# HG changeset patch # User Mario de Sousa # Date 1550067386 0 # Node ID ee66a14e38f7beaecd97b0d6d2e158792c4fe6d0 # Parent 9766936990db94b0d90276a0e02fc779cc6447db# Parent 24ef30a9bcee1e65b027be2c7f7a8d52c41a7479 merge diff -r 24ef30a9bcee -r ee66a14e38f7 lib/C/iec_std_functions.h --- a/lib/C/iec_std_functions.h Sun Oct 14 20:14:13 2018 +0300 +++ b/lib/C/iec_std_functions.h Wed Feb 13 14:16:26 2019 +0000 @@ -1481,46 +1481,100 @@ return __time_add(IN1, IN2); } +/* overloaded version of ADD(TIME, TIME) */ +static inline TIME ADD__TIME__TIME__TIME(EN_ENO_PARAMS TIME IN1, TIME IN2){ + TEST_EN(TIME) + return __time_add(IN1, IN2); +} + static inline TOD ADD_TOD_TIME(EN_ENO_PARAMS TOD IN1, TIME IN2){ TEST_EN(TOD) return __time_add(IN1, IN2); } +/* overloaded version of ADD(TOD, TIME) */ +static inline TOD ADD__TOD__TOD__TIME(EN_ENO_PARAMS TOD IN1, TIME IN2){ + TEST_EN(TIME) + return __time_add(IN1, IN2); +} + static inline DT ADD_DT_TIME(EN_ENO_PARAMS DT IN1, TIME IN2){ TEST_EN(DT) return __time_add(IN1, IN2); } +/* overloaded version of ADD(DT, TIME) */ +static inline DT ADD__DT__DT__TIME(EN_ENO_PARAMS DT IN1, TIME IN2){ + TEST_EN(TIME) + return __time_add(IN1, IN2); +} + static inline TIME SUB_TIME(EN_ENO_PARAMS TIME IN1, TIME IN2){ TEST_EN(TIME) return __time_sub(IN1, IN2); } +/* overloaded version of SUB(TIME, TIME) */ +static inline TIME SUB__TIME__TIME__TIME(EN_ENO_PARAMS TIME IN1, TIME IN2){ + TEST_EN(TIME) + return __time_sub(IN1, IN2); +} + static inline TIME SUB_DATE_DATE(EN_ENO_PARAMS DATE IN1, DATE IN2){ TEST_EN(TIME) return __time_sub(IN1, IN2); } +/* overloaded version of SUB(DATE, DATE) */ +static inline TIME SUB__TIME__DATE__DATE(EN_ENO_PARAMS DATE IN1, DATE IN2){ + TEST_EN(TIME) + return __time_sub(IN1, IN2); +} + static inline TOD SUB_TOD_TIME(EN_ENO_PARAMS TOD IN1, TIME IN2){ TEST_EN(TOD) return __time_sub(IN1, IN2); } +/* overloaded version of SUB(TOD, TIME) */ +static inline TOD SUB__TOD__TOD__TIME(EN_ENO_PARAMS TOD IN1, TIME IN2){ + TEST_EN(TOD) + return __time_sub(IN1, IN2); +} + static inline TIME SUB_TOD_TOD(EN_ENO_PARAMS TOD IN1, TOD IN2){ TEST_EN(TIME) return __time_sub(IN1, IN2); } +/* overloaded version of SUB(TOD, TOD) */ +static inline TIME SUB__TIME__TOD__TOD(EN_ENO_PARAMS TOD IN1, TOD IN2){ + TEST_EN(TIME) + return __time_sub(IN1, IN2); +} + static inline DT SUB_DT_TIME(EN_ENO_PARAMS DT IN1, TIME IN2){ TEST_EN(DT) return __time_sub(IN1, IN2); } +/* overloaded version of SUB(DT, TIME) */ +static inline DT SUB__DT__DT__TIME(EN_ENO_PARAMS DT IN1, TIME IN2){ + TEST_EN(DT) + return __time_sub(IN1, IN2); +} + static inline TIME SUB_DT_DT(EN_ENO_PARAMS DT IN1, DT IN2){ TEST_EN(TIME) return __time_sub(IN1, IN2); } +/* overloaded version of SUB(DT, DT) */ +static inline TIME SUB__TIME__DT__DT(EN_ENO_PARAMS DT IN1, DT IN2){ + TEST_EN(TIME) + return __time_sub(IN1, IN2); +} + /*** MULTIME ***/ #define __iec_(TYPENAME)\ @@ -1531,6 +1585,15 @@ __ANY_NUM(__iec_) #undef __iec_ +/*** MULTIME_TYPENAME ***/ +#define __iec_(TYPENAME)\ +static inline TIME MULTIME_##TYPENAME(EN_ENO_PARAMS TIME IN1, TYPENAME IN2){\ + TEST_EN(TIME)\ + return __time_mul(IN1, (LREAL)IN2);\ +} +__ANY_NUM(__iec_) +#undef __iec_ + /*** MUL ***/ #define __iec_(TYPENAME)\ static inline TIME MUL__TIME__TIME__##TYPENAME(EN_ENO_PARAMS TIME IN1, TYPENAME IN2){\ @@ -1549,6 +1612,15 @@ __ANY_NUM(__iec_) #undef __iec_ +/*** DIVTIME_TYPENAME ***/ +#define __iec_(TYPENAME)\ +static inline TIME DIVTIME_##TYPENAME(EN_ENO_PARAMS TIME IN1, TYPENAME IN2){\ + TEST_EN(TIME)\ + return __time_div(IN1, (LREAL)IN2);\ +} +__ANY_NUM(__iec_) +#undef __iec_ + /*** DIV ***/ #define __iec_(TYPENAME)\ static inline TIME DIV__TIME__TIME__##TYPENAME(EN_ENO_PARAMS TIME IN1, TYPENAME IN2){\ diff -r 24ef30a9bcee -r ee66a14e38f7 lib/create_standard_function_txt.sh --- a/lib/create_standard_function_txt.sh Sun Oct 14 20:14:13 2018 +0300 +++ b/lib/create_standard_function_txt.sh Wed Feb 13 14:16:26 2019 +0000 @@ -836,16 +836,25 @@ /*** Functions of time data types ***/ /**************************************/ -__function_2p(ADD_TIME, TIME, IN1, TIME, IN2, TIME) -__function_2p(ADD_TOD_TIME, TOD, IN1, TOD, IN2, TIME) -__function_2p(ADD_DT_TIME, DT, IN1, DT, IN2, TIME) - -__function_2p(SUB_TIME, TIME, IN1, TIME, IN2, TIME) +__function_2p(ADD_TIME, TIME, IN1, TIME, IN2, TIME) +__function_2p(ADD, TIME, IN1, TIME, IN2, TIME) /* overloaded function */ +__function_2p(ADD_TOD_TIME, TOD, IN1, TOD, IN2, TIME) +__function_2p(ADD, TOD, IN1, TOD, IN2, TIME) /* overloaded function */ +__function_2p(ADD_DT_TIME, DT, IN1, DT, IN2, TIME) +__function_2p(ADD, DT, IN1, DT, IN2, TIME) /* overloaded function */ + +__function_2p(SUB_TIME, TIME, IN1, TIME, IN2, TIME) +__function_2p(SUB, TIME, IN1, TIME, IN2, TIME) /* overloaded function */ __function_2p(SUB_DATE_DATE, TIME, IN1, DATE, IN2, DATE) -__function_2p(SUB_TOD_TIME, TOD, IN1, TOD, IN2, TIME) -__function_2p(SUB_TOD_TOD, TIME, IN1, TOD, IN2, TOD) -__function_2p(SUB_DT_TIME, DT, IN1, DT, IN2, TIME) -__function_2p(SUB_DT_DT, TIME, IN1, DT, IN2, DT) +__function_2p(SUB, TIME, IN1, DATE, IN2, DATE) /* overloaded function */ +__function_2p(SUB_TOD_TIME, TOD, IN1, TOD, IN2, TIME) +__function_2p(SUB, TOD, IN1, TOD, IN2, TIME) /* overloaded function */ +__function_2p(SUB_TOD_TOD, TIME, IN1, TOD, IN2, TOD ) +__function_2p(SUB, TIME, IN1, TOD, IN2, TOD ) /* overloaded function */ +__function_2p(SUB_DT_TIME, DT, IN1, DT, IN2, TIME) +__function_2p(SUB, DT, IN1, DT, IN2, TIME) /* overloaded function */ +__function_2p(SUB_DT_DT, TIME, IN1, DT, IN2, DT ) +__function_2p(SUB, TIME, IN1, DT, IN2, DT ) /* overloaded function */ /*** MULTIME ***/ diff -r 24ef30a9bcee -r ee66a14e38f7 lib/standard_functions.txt --- a/lib/standard_functions.txt Sun Oct 14 20:14:13 2018 +0300 +++ b/lib/standard_functions.txt Wed Feb 13 14:16:26 2019 +0000 @@ -1763,15 +1763,24 @@ FUNCTION FIND : UDINT VAR_INPUT IN1 : STRING; IN2 : STRING; END_VAR RETURN; END_FUNCTION FUNCTION FIND : ULINT VAR_INPUT IN1 : STRING; IN2 : STRING; END_VAR RETURN; END_FUNCTION FUNCTION ADD_TIME : TIME VAR_INPUT IN1 : TIME; IN2 : TIME; END_VAR RETURN; END_FUNCTION +FUNCTION ADD : TIME VAR_INPUT IN1 : TIME; IN2 : TIME; END_VAR RETURN; END_FUNCTION FUNCTION ADD_TOD_TIME : TOD VAR_INPUT IN1 : TOD; IN2 : TIME; END_VAR RETURN; END_FUNCTION +FUNCTION ADD : TOD VAR_INPUT IN1 : TOD; IN2 : TIME; END_VAR RETURN; END_FUNCTION FUNCTION ADD_DT_TIME : DT VAR_INPUT IN1 : DT; IN2 : TIME; END_VAR RETURN; END_FUNCTION +FUNCTION ADD : DT VAR_INPUT IN1 : DT; IN2 : TIME; END_VAR RETURN; END_FUNCTION FUNCTION SUB_TIME : TIME VAR_INPUT IN1 : TIME; IN2 : TIME; END_VAR RETURN; END_FUNCTION +FUNCTION SUB : TIME VAR_INPUT IN1 : TIME; IN2 : TIME; END_VAR RETURN; END_FUNCTION FUNCTION SUB_DATE_DATE : TIME VAR_INPUT IN1 : DATE; IN2 : DATE; END_VAR RETURN; END_FUNCTION +FUNCTION SUB : TIME VAR_INPUT IN1 : DATE; IN2 : DATE; END_VAR RETURN; END_FUNCTION FUNCTION SUB_TOD_TIME : TOD VAR_INPUT IN1 : TOD; IN2 : TIME; END_VAR RETURN; END_FUNCTION +FUNCTION SUB : TOD VAR_INPUT IN1 : TOD; IN2 : TIME; END_VAR RETURN; END_FUNCTION FUNCTION SUB_TOD_TOD : TIME VAR_INPUT IN1 : TOD; IN2 : TOD; END_VAR RETURN; END_FUNCTION +FUNCTION SUB : TIME VAR_INPUT IN1 : TOD; IN2 : TOD; END_VAR RETURN; END_FUNCTION FUNCTION SUB_DT_TIME : DT VAR_INPUT IN1 : DT; IN2 : TIME; END_VAR RETURN; END_FUNCTION +FUNCTION SUB : DT VAR_INPUT IN1 : DT; IN2 : TIME; END_VAR RETURN; END_FUNCTION FUNCTION SUB_DT_DT : TIME VAR_INPUT IN1 : DT; IN2 : DT; END_VAR RETURN; END_FUNCTION +FUNCTION SUB : TIME VAR_INPUT IN1 : DT; IN2 : DT; END_VAR RETURN; END_FUNCTION diff -r 24ef30a9bcee -r ee66a14e38f7 stage1_2/iec_flex.ll --- a/stage1_2/iec_flex.ll Sun Oct 14 20:14:13 2018 +0300 +++ b/stage1_2/iec_flex.ll Wed Feb 13 14:16:26 2019 +0000 @@ -247,6 +247,8 @@ void append_bodystate_buffer(const char *text, int is_whitespace = 0); void unput_bodystate_buffer(void); int isempty_bodystate_buffer(void); +void del_bodystate_buffer(void); + int GetNextChar(char *b, int maxBuffer); %} @@ -1231,12 +1233,12 @@ append_bodystate_buffer(yytext, 1 /* is whitespace */); } /* 'INITIAL_STEP' always used in beginning of SFCs !! */ -INITIAL_STEP { if (isempty_bodystate_buffer()) {unput_text(0); BEGIN(sfc_state);} +INITIAL_STEP { if (isempty_bodystate_buffer()) {unput_text(0); del_bodystate_buffer(); BEGIN(sfc_state);} else {append_bodystate_buffer(yytext);} } /* ':=', at the very beginning of a 'body', occurs only in transitions and not Function, FB, or Program bodies! */ -:= { if (isempty_bodystate_buffer()) {unput_text(0); BEGIN(st_state);} /* We do _not_ return a start_ST_body_token here, as bison does not expect it! */ +:= { if (isempty_bodystate_buffer()) {unput_text(0); del_bodystate_buffer(); BEGIN(st_state);} /* We do _not_ return a start_ST_body_token here, as bison does not expect it! */ else {append_bodystate_buffer(yytext);} } @@ -1257,7 +1259,7 @@ FOR | WHILE | EXIT | -REPEAT { if (isempty_bodystate_buffer()) {unput_text(0); BEGIN(st_state); return start_ST_body_token;} +REPEAT { if (isempty_bodystate_buffer()) {unput_text(0); del_bodystate_buffer(); BEGIN(st_state); return start_ST_body_token;} else {append_bodystate_buffer(yytext);} } @@ -2183,6 +2185,16 @@ } +/* Delete all data in bodystate. */ +/* Will be used to delete ST whitespace when not needed. If not deleted this whitespace + * will be prepended to the next text block of code being appended to bodystate_buffer, + * which may cause trouble if it is IL code + */ +void del_bodystate_buffer(void) { + free(bodystate_buffer); + bodystate_buffer = NULL; + bodystate_is_whitespace = 1; +} /* Called by flex when it reaches the end-of-file */ diff -r 24ef30a9bcee -r ee66a14e38f7 stage3/fill_candidate_datatypes.cc --- a/stage3/fill_candidate_datatypes.cc Sun Oct 14 20:14:13 2018 +0300 +++ b/stage3/fill_candidate_datatypes.cc Wed Feb 13 14:16:26 2019 +0000 @@ -2011,7 +2011,7 @@ * We do not need to generate an error message. This error will be caught somewhere else! */ if (NULL == prev_il_instruction) return NULL; - if (NULL == il_operand) return NULL; + if (NULL != il_operand) return NULL; for (unsigned int i = 0; i < prev_il_instruction->candidate_datatypes.size(); i++) { if (get_datatype_info_c::is_ANY_BIT_compatible(prev_il_instruction->candidate_datatypes[i])) add_datatype_to_candidate_list(symbol, prev_il_instruction->candidate_datatypes[i]); diff -r 24ef30a9bcee -r ee66a14e38f7 stage4/generate_c/generate_c.cc --- a/stage4/generate_c/generate_c.cc Sun Oct 14 20:14:13 2018 +0300 +++ b/stage4/generate_c/generate_c.cc Wed Feb 13 14:16:26 2019 +0000 @@ -544,9 +544,27 @@ /***********************************************************************/ /***********************************************************************/ -#define MILLISECOND 1000000 +#define MILLISECOND ((unsigned long long)1000000) #define SECOND 1000 * MILLISECOND +#define ULL_MAX std::numeric_limits::max() + +/* unsigned long long -> multiply and add : time_var += interval * multiplier */ +/* note: multiplier must be <> 0 due to overflow test */ +#define ULL_MUL_ADD(time_var, interval, multiplier, overflow_flag) { \ + /* Test overflow on MUL by pre-condition: If (ULL_MAX / a) < b => overflow! */ \ + overflow_flag |= ((ULL_MAX / (multiplier)) < GET_CVALUE(uint64, interval)); \ + /* Test overflow on ADD by pre-condition: If (ULL_MAX - a) < b => overflow! */ \ + overflow_flag |= ((ULL_MAX - (GET_CVALUE(uint64, interval) * multiplier)) < time_var); \ + time_var += GET_CVALUE(uint64, interval) * (multiplier); \ +} + +/* long double -> multiply and add : time_var += interval * multiplier */ +#define LDB_MUL_ADD(time_var, interval, multiplier) { \ + time_var += GET_CVALUE(real64, interval) * (multiplier); \ +} + + unsigned long long calculate_time(symbol_c *symbol) { if (NULL == symbol) return 0; @@ -567,52 +585,54 @@ /* SYM_REF5(interval_c, days, hours, minutes, seconds, milliseconds) */ unsigned long long int time_ull = 0; long double time_ld = 0; - /* - const unsigned long long int MILLISECOND = 1000000; - const unsigned long long int SECOND = 1000 * MILLISECOND - */ + bool ovflow = false; if (NULL != interval->milliseconds) { if (VALID_CVALUE( int64, interval->milliseconds) && GET_CVALUE( int64, interval->milliseconds) < 0) ERROR; // interval elements should always be positive! - if (VALID_CVALUE( int64, interval->milliseconds)) time_ull += GET_CVALUE( int64, interval->milliseconds) * MILLISECOND; - else if (VALID_CVALUE(uint64, interval->milliseconds)) time_ull += GET_CVALUE(uint64, interval->milliseconds) * MILLISECOND; - else if (VALID_CVALUE(real64, interval->milliseconds)) time_ld += GET_CVALUE(real64, interval->milliseconds) * MILLISECOND; + if (VALID_CVALUE(uint64, interval->milliseconds)) ULL_MUL_ADD(time_ull, interval->milliseconds, MILLISECOND, ovflow) + else if (VALID_CVALUE(real64, interval->milliseconds)) LDB_MUL_ADD(time_ld , interval->milliseconds, MILLISECOND) else ERROR; // if (NULL != interval->milliseconds) is true, then it must have a valid constant value! } if (NULL != interval->seconds ) { if (VALID_CVALUE( int64, interval->seconds ) && GET_CVALUE( int64, interval->seconds ) < 0) ERROR; // interval elements should always be positive! - if (VALID_CVALUE( int64, interval->seconds )) time_ull += GET_CVALUE( int64, interval->seconds ) * SECOND; - else if (VALID_CVALUE(uint64, interval->seconds )) time_ull += GET_CVALUE(uint64, interval->seconds ) * SECOND; - else if (VALID_CVALUE(real64, interval->seconds )) time_ld += GET_CVALUE(real64, interval->seconds ) * SECOND; + if (VALID_CVALUE(uint64, interval->seconds )) ULL_MUL_ADD(time_ull, interval->seconds, SECOND, ovflow) + else if (VALID_CVALUE(real64, interval->seconds )) LDB_MUL_ADD(time_ld , interval->seconds, SECOND) else ERROR; // if (NULL != interval->seconds) is true, then it must have a valid constant value! } if (NULL != interval->minutes ) { if (VALID_CVALUE( int64, interval->minutes ) && GET_CVALUE( int64, interval->minutes ) < 0) ERROR; // interval elements should always be positive! - if (VALID_CVALUE( int64, interval->minutes )) time_ull += GET_CVALUE( int64, interval->minutes ) * SECOND * 60; - else if (VALID_CVALUE(uint64, interval->minutes )) time_ull += GET_CVALUE(uint64, interval->minutes ) * SECOND * 60; - else if (VALID_CVALUE(real64, interval->minutes )) time_ld += GET_CVALUE(real64, interval->minutes ) * SECOND * 60; + if (VALID_CVALUE(uint64, interval->minutes )) ULL_MUL_ADD(time_ull, interval->minutes, SECOND * 60, ovflow) + else if (VALID_CVALUE(real64, interval->minutes )) LDB_MUL_ADD(time_ld , interval->minutes, SECOND * 60) else ERROR; // if (NULL != interval->minutes) is true, then it must have a valid constant value! } if (NULL != interval->hours ) { if (VALID_CVALUE( int64, interval->hours ) && GET_CVALUE( int64, interval->hours ) < 0) ERROR; // interval elements should always be positive! - if (VALID_CVALUE( int64, interval->hours )) time_ull += GET_CVALUE( int64, interval->hours ) * SECOND * 60 * 60; - else if (VALID_CVALUE(uint64, interval->hours )) time_ull += GET_CVALUE(uint64, interval->hours ) * SECOND * 60 * 60; - else if (VALID_CVALUE(real64, interval->hours )) time_ld += GET_CVALUE(real64, interval->hours ) * SECOND * 60 * 60; + if (VALID_CVALUE(uint64, interval->hours )) ULL_MUL_ADD(time_ull, interval->hours, SECOND * 60 * 60, ovflow) + else if (VALID_CVALUE(real64, interval->hours )) LDB_MUL_ADD(time_ld , interval->hours, SECOND * 60 * 60) else ERROR; // if (NULL != interval->hours) is true, then it must have a valid constant value! } if (NULL != interval->days ) { if (VALID_CVALUE( int64, interval->days ) && GET_CVALUE( int64, interval->days ) < 0) ERROR; // interval elements should always be positive! - if (VALID_CVALUE( int64, interval->days )) time_ull += GET_CVALUE( int64, interval->days ) * SECOND * 60 * 60 * 24; - else if (VALID_CVALUE(uint64, interval->days )) time_ull += GET_CVALUE(uint64, interval->days ) * SECOND * 60 * 60 * 24; - else if (VALID_CVALUE(real64, interval->days )) time_ld += GET_CVALUE(real64, interval->days ) * SECOND * 60 * 60 * 24; + if (VALID_CVALUE(uint64, interval->days )) ULL_MUL_ADD(time_ull, interval->days, SECOND * 60 * 60 * 24, ovflow) + else if (VALID_CVALUE(real64, interval->days )) LDB_MUL_ADD(time_ld , interval->days, SECOND * 60 * 60 * 24) else ERROR; // if (NULL != interval->days) is true, then it must have a valid constant value! } + /* Test overflow on ADD by pre-condition: If (ULL_MAX - a) < b => overflow! */ + ovflow |= ((ULL_MAX - time_ull) < (unsigned long long)time_ld); time_ull += time_ld; + + if (ovflow) { + /* time is being stored in ns resolution (MILLISECOND #define is set to 1000000) */ + /* time is being stored in unsigned long long (ISO C99 guarantees at least 64 bits) */ + /* 2⁶64ns works out to around 584.5 years, assuming 365.25 days per year */ + STAGE4_ERROR(symbol, symbol, "Internal overflow calculating task interval (must be < 584 years)."); + } + return time_ull; }; ERROR; // should never reach this point! @@ -642,8 +662,10 @@ else return euclide(b, c); } - - void update_ticktime(unsigned long long time) { + + bool update_ticktime(unsigned long long time) { + bool overflow = false; + if (common_ticktime == 0) common_ticktime = time; else if (time > common_ticktime) @@ -652,10 +674,14 @@ common_ticktime = euclide(common_ticktime, time); if (least_common_ticktime == 0) least_common_ticktime = time; - else - least_common_ticktime = (least_common_ticktime * time) / common_ticktime; - } - + else { + /* Test overflow on MUL by pre-condition: If (ULL_MAX / a) < b => overflow! */ + overflow = ((ULL_MAX / least_common_ticktime) < (time / common_ticktime)); + least_common_ticktime = least_common_ticktime * (time / common_ticktime); + } + return !overflow; + } + unsigned long long get_common_ticktime(void) { return common_ticktime; } @@ -671,9 +697,12 @@ //SYM_REF2(task_configuration_c, task_name, task_initialization) void *visit(task_initialization_c *symbol) { if (symbol->interval_data_source != NULL) { - unsigned long long time = calculate_time(symbol->interval_data_source); - if (time < 0) ERROR; - else update_ticktime(time); + unsigned long long time = calculate_time(symbol->interval_data_source); + if (!update_ticktime(time)) + /* time is being stored in ns resolution (MILLISECOND #define is set to 1000000) */ + /* time is being stored in unsigned long long (ISO C99 guarantees at least 64 bits) */ + /* 2⁶64ns works out to around 584.5 years, assuming 365.25 days per year */ + STAGE4_ERROR(symbol, symbol, "Internal overflow calculating least common multiple of task intervals (must be < 584 years)."); } return NULL; } @@ -2670,6 +2699,8 @@ config_s4o.print("unsigned long long common_ticktime__ = "); config_s4o.print_long_long_integer(common_ticktime); + config_s4o.print(" * "); + config_s4o.print_long_long_integer(1000000 / MILLISECOND); config_s4o.print("; /*ns*/\n"); config_s4o.print("unsigned long greatest_tick_count__ = (unsigned long)"); config_s4o.print_long_integer(calculate_common_ticktime.get_greatest_tick_count()); diff -r 24ef30a9bcee -r ee66a14e38f7 stage4/generate_c/generate_c_st.cc --- a/stage4/generate_c/generate_c_st.cc Sun Oct 14 20:14:13 2018 +0300 +++ b/stage4/generate_c/generate_c_st.cc Wed Feb 13 14:16:26 2019 +0000 @@ -937,7 +937,7 @@ /* B 3.2.1 Assignment Statements */ /*********************************/ void *visit(assignment_statement_c *symbol) { - symbol_c *left_type = search_varfb_instance_type->get_type_id(symbol->l_exp); + symbol_c *left_type = symbol->l_exp->datatype; if (this->is_variable_prefix_null()) { symbol->l_exp->accept(*this);