223 * but first return to the stream an additional character to mark the end of the token. |
223 * but first return to the stream an additional character to mark the end of the token. |
224 */ |
224 */ |
225 void unput_and_mark(const char c); |
225 void unput_and_mark(const char c); |
226 |
226 |
227 void include_file(const char *include_filename); |
227 void include_file(const char *include_filename); |
|
228 |
|
229 /* The body_state tries to find a ';' before a END_PROGRAM, END_FUNCTION or END_FUNCTION_BLOCK or END_ACTION |
|
230 * To do so, it must ignore comments and pragmas. This means that we cannot do this in a signle lex rule. |
|
231 * However, we must store any text we consume in every rule, so we can push it back into the buffer |
|
232 * once we have decided if we are parsing ST or IL code. The following functions manage that buffer used by |
|
233 * the body_state. |
|
234 */ |
|
235 void append_bodystate_buffer(const char *yytext); |
|
236 void unput_bodystate_buffer(void); |
|
237 int isempty_bodystate_buffer(void); |
228 |
238 |
229 int GetNextChar(char *b, int maxBuffer); |
239 int GetNextChar(char *b, int maxBuffer); |
230 %} |
240 %} |
231 |
241 |
232 |
242 |
956 |
966 |
957 /* We start off by searching for the pragmas we handle in the lexical parser. */ |
967 /* We start off by searching for the pragmas we handle in the lexical parser. */ |
958 <INITIAL>{file_include_pragma} unput_text(0); yy_push_state(include_beg); |
968 <INITIAL>{file_include_pragma} unput_text(0); yy_push_state(include_beg); |
959 |
969 |
960 /* Pragmas sent to syntax analyser (bison) */ |
970 /* Pragmas sent to syntax analyser (bison) */ |
961 {disable_code_generation_pragma} return disable_code_generation_pragma_token; |
971 /* NOTE: In the vardecl_list_state we only process the pragmas between two consecutive VAR .. END_VAR blocks. |
962 {enable_code_generation_pragma} return enable_code_generation_pragma_token; |
972 * We do not process any pragmas trailing after the last END_VAR. We leave that to the body_state. |
963 <body_state,vardecl_list_state>{disable_code_generation_pragma} return disable_code_generation_pragma_token; |
973 * This is because the pragmas are stored in a statement_list or instruction_list (in bison), |
964 <body_state,vardecl_list_state>{enable_code_generation_pragma} return enable_code_generation_pragma_token; |
974 * but these lists must start with the special tokens start_IL_body_token/start_ST_body_token. |
965 |
975 * This means that these special tokens must be generated (by the body_state) before processing |
|
976 * the pragme => we cannot process the trailing pragmas in the vardecl_list_state state. |
|
977 */ |
|
978 {disable_code_generation_pragma} return disable_code_generation_pragma_token; |
|
979 {enable_code_generation_pragma} return enable_code_generation_pragma_token; |
|
980 <vardecl_list_state>{disable_code_generation_pragma}/(VAR) return disable_code_generation_pragma_token; |
|
981 <vardecl_list_state>{enable_code_generation_pragma}/(VAR) return enable_code_generation_pragma_token; |
|
982 <body_state>{disable_code_generation_pragma} append_bodystate_buffer(yytext); /* in body state we do not process any tokens, we simply store them for later processing! */ |
|
983 <body_state>{enable_code_generation_pragma} append_bodystate_buffer(yytext); /* in body state we do not process any tokens, we simply store them for later processing! */ |
966 /* Any other pragma we find, we just pass it up to the syntax parser... */ |
984 /* Any other pragma we find, we just pass it up to the syntax parser... */ |
967 /* Note that the <body_state> state is exclusive, so we have to include it here too. */ |
985 /* Note that the <body_state> state is exclusive, so we have to include it here too. */ |
|
986 <body_state>{pragma} append_bodystate_buffer(yytext); /* in body state we do not process any tokens, we simply store them for later processing! */ |
968 {pragma} {/* return the pragmma without the enclosing '{' and '}' */ |
987 {pragma} {/* return the pragmma without the enclosing '{' and '}' */ |
969 int cut = yytext[1]=='{'?2:1; |
988 int cut = yytext[1]=='{'?2:1; |
970 yytext[strlen(yytext)-cut] = '\0'; |
989 yytext[strlen(yytext)-cut] = '\0'; |
971 yylval.ID=strdup(yytext+cut); |
990 yylval.ID=strdup(yytext+cut); |
972 return pragma_token; |
991 return pragma_token; |
973 } |
992 } |
974 <body_state,vardecl_list_state>{pragma} {/* return the pragmma without the enclosing '{' and '}' */ |
993 <vardecl_list_state>{pragma}/(VAR) {/* return the pragmma without the enclosing '{' and '}' */ |
975 int cut = yytext[1]=='{'?2:1; |
994 int cut = yytext[1]=='{'?2:1; |
976 yytext[strlen(yytext)-cut] = '\0'; |
995 yytext[strlen(yytext)-cut] = '\0'; |
977 yylval.ID=strdup(yytext+cut); |
996 yylval.ID=strdup(yytext+cut); |
978 return pragma_token; |
997 return pragma_token; |
979 } |
998 } |
1057 /* Handle all the state changes! */ |
1076 /* Handle all the state changes! */ |
1058 /*********************************/ |
1077 /*********************************/ |
1059 |
1078 |
1060 /* INITIAL -> header_state */ |
1079 /* INITIAL -> header_state */ |
1061 <INITIAL>{ |
1080 <INITIAL>{ |
1062 /* NOTE: how about functions that do not declare variables, and go directly to the body_state??? |
1081 FUNCTION{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else {BEGIN(header_state);/* printf("\nChanging to header_state\n"); */} return FUNCTION; |
|
1082 FUNCTION_BLOCK{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else {BEGIN(header_state);/* printf("\nChanging to header_state\n"); */} return FUNCTION_BLOCK; |
|
1083 PROGRAM{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else {BEGIN(header_state);/* printf("\nChanging to header_state\n"); */} return PROGRAM; |
|
1084 CONFIGURATION{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else {BEGIN(config_state);/* printf("\nChanging to config_state\n"); */} return CONFIGURATION; |
|
1085 } |
|
1086 |
|
1087 <get_pou_name_state>{ |
|
1088 {identifier} BEGIN(ignore_pou_state); yylval.ID=strdup(yytext); return identifier_token; |
|
1089 . BEGIN(ignore_pou_state); unput_text(0); |
|
1090 } |
|
1091 |
|
1092 <ignore_pou_state>{ |
|
1093 END_FUNCTION unput_text(0); BEGIN(INITIAL); |
|
1094 END_FUNCTION_BLOCK unput_text(0); BEGIN(INITIAL); |
|
1095 END_PROGRAM unput_text(0); BEGIN(INITIAL); |
|
1096 END_CONFIGURATION unput_text(0); BEGIN(INITIAL); |
|
1097 .|\n {}/* Ignore text inside POU! (including the '\n' character!)) */ |
|
1098 } |
|
1099 |
|
1100 |
|
1101 /* header_state -> (vardecl_list_state) */ |
|
1102 /* NOTE: This transition assumes that all POUs with code (Function, FB, and Program) will always contain |
|
1103 * at least one VAR_XXX block. |
|
1104 * How about functions that do not declare variables, and go directly to the body_state??? |
1063 * - According to Section 2.5.1.3 (Function Declaration), item 2 in the list, a FUNCTION |
1105 * - According to Section 2.5.1.3 (Function Declaration), item 2 in the list, a FUNCTION |
1064 * must have at least one input argument, so a correct declaration will have at least |
1106 * must have at least one input argument, so a correct declaration will have at least |
1065 * one VAR_INPUT ... VAR_END construct! |
1107 * one VAR_INPUT ... VAR_END construct! |
1066 * - According to Section 2.5.2.2 (Function Block Declaration), a FUNCTION_BLOCK |
1108 * - According to Section 2.5.2.2 (Function Block Declaration), a FUNCTION_BLOCK |
1067 * must have at least one input argument, so a correct declaration will have at least |
1109 * must have at least one input argument, so a correct declaration will have at least |
1071 * construct! |
1113 * construct! |
1072 * |
1114 * |
1073 * All the above means that we needn't worry about PROGRAMs, FUNCTIONs or |
1115 * All the above means that we needn't worry about PROGRAMs, FUNCTIONs or |
1074 * FUNCTION_BLOCKs that do not have at least one VAR_END before the body_state. |
1116 * FUNCTION_BLOCKs that do not have at least one VAR_END before the body_state. |
1075 * If the code has an error, and no VAR_END before the body, we will simply |
1117 * If the code has an error, and no VAR_END before the body, we will simply |
1076 * continue in the <vardecl_state> state, untill the end of the FUNCTION, FUNCTION_BLOCK |
1118 * continue in the <vardecl_state> state, until the end of the FUNCTION, FUNCTION_BLOCK |
1077 * or PROGAM. |
1119 * or PROGAM. |
|
1120 * |
|
1121 * WARNING: From 2016-05 (May 2016) onwards, matiec supports a non-standard option in which a Function |
|
1122 * may be declared with no Input, Output or IN_OUT variables. This means that the above |
|
1123 * assumption is no longer valid. |
|
1124 * To make things simpler (i.e. so we do not need to change the transition conditions in the flex state machine), |
|
1125 * when using this non-standard extension matiec requires that Functions must include at least one |
|
1126 * VAR .. END_VAR block. This implies that the above assumption remains valid! |
|
1127 * This limitation of requiring a VAR .. END_VAR block is not really very limiting, as a function |
|
1128 * with no input and output parameters will probably need to do some 'work', and for that it will |
|
1129 * probably need some local variables declared in a VAR .. END_VAR block. |
|
1130 * Note however that in the extreme it might make sense to have a function with no variables whatsoever |
|
1131 * (e.g.: a function that only calls other functions that all return VOID - another non standard extension!). |
|
1132 * For now we do not consider this!! |
1078 */ |
1133 */ |
1079 |
|
1080 FUNCTION{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return FUNCTION; |
|
1081 FUNCTION_BLOCK{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return FUNCTION_BLOCK; |
|
1082 PROGRAM{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return PROGRAM; |
|
1083 CONFIGURATION{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(config_state); return CONFIGURATION; |
|
1084 } |
|
1085 |
|
1086 <get_pou_name_state>{ |
|
1087 {identifier} BEGIN(ignore_pou_state); yylval.ID=strdup(yytext); return identifier_token; |
|
1088 . BEGIN(ignore_pou_state); unput_text(0); |
|
1089 } |
|
1090 |
|
1091 <ignore_pou_state>{ |
|
1092 END_FUNCTION unput_text(0); BEGIN(INITIAL); |
|
1093 END_FUNCTION_BLOCK unput_text(0); BEGIN(INITIAL); |
|
1094 END_PROGRAM unput_text(0); BEGIN(INITIAL); |
|
1095 END_CONFIGURATION unput_text(0); BEGIN(INITIAL); |
|
1096 .|\n {}/* Ignore text inside POU! (including the '\n' character!)) */ |
|
1097 } |
|
1098 |
|
1099 /* INITIAL -> body_state */ |
|
1100 /* required if the function, program, etc.. has no VAR block! */ |
|
1101 /* We comment it out since the standard does not allow this. */ |
|
1102 /* NOTE: Even if we were to include the following code, it */ |
|
1103 /* would have no effect whatsoever since the above */ |
|
1104 /* rules will take precendence! */ |
|
1105 /* |
|
1106 <INITIAL>{ |
|
1107 FUNCTION BEGIN(body_state); return FUNCTION; |
|
1108 FUNCTION_BLOCK BEGIN(body_state); return FUNCTION_BLOCK; |
|
1109 PROGRAM BEGIN(body_state); return PROGRAM; |
|
1110 } |
|
1111 */ |
|
1112 |
|
1113 /* header_state -> (vardecl_list_state) */ |
|
1114 <header_state>{ |
1134 <header_state>{ |
1115 VAR | /* execute the next rule's action, i.e. fall-through! */ |
1135 VAR | /* execute the next rule's action, i.e. fall-through! */ |
1116 VAR_INPUT | |
1136 VAR_INPUT | |
1117 VAR_OUTPUT | |
1137 VAR_OUTPUT | |
1118 VAR_IN_OUT | |
1138 VAR_IN_OUT | |
1119 VAR_EXTERNAL | |
1139 VAR_EXTERNAL | |
1120 VAR_GLOBAL | |
1140 VAR_GLOBAL | |
1121 VAR_TEMP | |
1141 VAR_TEMP | |
1122 VAR_CONFIG | |
1142 VAR_CONFIG | |
1123 VAR_ACCESS unput_text(0); BEGIN(vardecl_list_state); |
1143 VAR_ACCESS unput_text(0); /* printf("\nChanging to vardecl_list_state\n") */; BEGIN(vardecl_list_state); |
1124 } |
1144 } |
1125 |
1145 |
1126 |
1146 |
1127 /* vardecl_list_state -> (vardecl_state | body_state | INITIAL) */ |
1147 /* vardecl_list_state -> (vardecl_state | body_state | INITIAL) */ |
1128 <vardecl_list_state>{ |
1148 <vardecl_list_state>{ |
1150 } |
1170 } |
1151 |
1171 |
1152 |
1172 |
1153 /* body_state -> (il_state | st_state | sfc_state) */ |
1173 /* body_state -> (il_state | st_state | sfc_state) */ |
1154 <body_state>{ |
1174 <body_state>{ |
1155 INITIAL_STEP unput_text(0); BEGIN(sfc_state); |
1175 /* 'INITIAL_STEP' always used in beginning of SFCs !! */ |
1156 |
1176 INITIAL_STEP { if (isempty_bodystate_buffer()) {unput_text(0); BEGIN(sfc_state);} |
1157 {qualified_identifier} unput_text(0); BEGIN(st_state); /* will always be followed by '[' for an array access, or ':=' as the left hand of an assignment statement */ |
1177 else {append_bodystate_buffer(yytext);} |
1158 {direct_variable_standard} unput_text(0); BEGIN(st_state); /* will always be followed by ':=' as the left hand of an assignment statement */ |
1178 } |
1159 |
1179 |
1160 RETURN unput_text(0); BEGIN(st_state); |
1180 /* ':=', at the very beginning of a 'body', occurs only in transitions and not Function, FB, or Program bodies! */ |
1161 IF unput_text(0); BEGIN(st_state); |
1181 := { 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! */ |
1162 CASE unput_text(0); BEGIN(st_state); |
1182 else {append_bodystate_buffer(yytext);} |
1163 FOR unput_text(0); BEGIN(st_state); |
1183 } |
1164 WHILE unput_text(0); BEGIN(st_state); |
1184 |
1165 EXIT unput_text(0); BEGIN(st_state); |
1185 /* check if ';' occurs before an END_FUNCTION, END_FUNCTION_BLOCK, END_PROGRAM or END_ACTION. (If true => we are parsing ST; If false => parsing IL). */ |
1166 REPEAT unput_text(0); BEGIN(st_state); |
1186 END_ACTION | /* execute the next rule's action, i.e. fall-through! */ |
1167 |
1187 END_FUNCTION | |
1168 /* ':=' occurs only in transitions, and not Function or FB bodies! */ |
1188 END_FUNCTION_BLOCK | |
1169 := unput_text(0); BEGIN(st_state); |
1189 END_PROGRAM { append_bodystate_buffer(yytext); unput_bodystate_buffer(); BEGIN(il_state); /*printf("returning start_IL_body_token\n");*/ return start_IL_body_token;} |
1170 |
1190 .|\n { append_bodystate_buffer(yytext); |
1171 {identifier} {int token = get_identifier_token(yytext); |
1191 if (strcmp(yytext, ";") == 0) |
1172 if ((token == prev_declared_fb_name_token) || (token == prev_declared_variable_name_token)) { |
1192 {unput_bodystate_buffer(); BEGIN(st_state); /*printf("returning start_ST_body_token\n");*/ return start_ST_body_token;} |
1173 /* the code has a call to a function block OR has an assingment with a variable as the lvalue */ |
1193 } |
1174 unput_text(0); BEGIN(st_state); |
1194 /* The following rules are not really necessary. They just make compilation faster in case the ST Statement List starts with one fot he following... */ |
1175 } else |
1195 RETURN | /* execute the next rule's action, i.e. fall-through! */ |
1176 if (token == prev_declared_derived_function_name_token) { |
1196 IF | |
1177 /* the code has a call to a function - must be IL */ |
1197 CASE | |
1178 unput_text(0); BEGIN(il_state); |
1198 FOR | |
1179 } else { |
1199 WHILE | |
1180 /* Might be a lable in IL, or a bug in ST/IL code. We jump to IL */ |
1200 EXIT | |
1181 unput_text(0); BEGIN(il_state); |
1201 REPEAT { if (isempty_bodystate_buffer()) {unput_text(0); BEGIN(st_state); return start_ST_body_token;} |
1182 } |
1202 else {append_bodystate_buffer(yytext);} |
1183 } |
1203 } |
1184 |
1204 |
1185 . unput_text(0); BEGIN(il_state); /* Don't know what it could be. This is most likely a bug. Let's just to a random state... */ |
|
1186 } /* end of body_state lexical parser */ |
1205 } /* end of body_state lexical parser */ |
1187 |
|
1188 |
1206 |
1189 |
1207 |
1190 /* (il_state | st_state) -> pop to $previous_state (vardecl_list_state or sfc_state) */ |
1208 /* (il_state | st_state) -> pop to $previous_state (vardecl_list_state or sfc_state) */ |
1191 <il_state,st_state>{ |
1209 <il_state,st_state>{ |
1192 END_FUNCTION yy_pop_state(); unput_text(0); |
1210 END_FUNCTION yy_pop_state(); unput_text(0); |
1212 /* Next is to to remove all whitespace */ |
1230 /* Next is to to remove all whitespace */ |
1213 /***************************************/ |
1231 /***************************************/ |
1214 /* NOTE: pragmas are handled right at the beginning... */ |
1232 /* NOTE: pragmas are handled right at the beginning... */ |
1215 |
1233 |
1216 /* The whitespace */ |
1234 /* The whitespace */ |
1217 <INITIAL,header_state,config_state,body_state,vardecl_list_state,vardecl_state,st_state,sfc_state,task_init_state,sfc_qualifier_state>{st_whitespace} /* Eat any whitespace */ |
1235 <INITIAL,header_state,config_state,vardecl_list_state,vardecl_state,st_state,sfc_state,task_init_state,sfc_qualifier_state>{st_whitespace} /* Eat any whitespace */ |
1218 <il_state>{il_whitespace} /* Eat any whitespace */ |
1236 <il_state>{il_whitespace} /* Eat any whitespace */ |
|
1237 <body_state>{st_whitespace} append_bodystate_buffer(yytext); /* in body state we do not process any tokens, we simply store them for later processing! */ |
1219 |
1238 |
1220 /* The comments */ |
1239 /* The comments */ |
1221 <get_pou_name_state,ignore_pou_state,body_state,vardecl_list_state>{comment_beg} yy_push_state(comment_state); |
1240 <get_pou_name_state,ignore_pou_state,body_state,vardecl_list_state>{comment_beg} yy_push_state(comment_state); |
1222 {comment_beg} yy_push_state(comment_state); |
1241 {comment_beg} yy_push_state(comment_state); |
1223 <comment_state>{ |
1242 <comment_state>{ |
1252 * If we don't, then even it will not be possible to use 'MOD' |
1271 * If we don't, then even it will not be possible to use 'MOD' |
1253 * as a funtion as in 'X := MOD(Y, Z);' |
1272 * as a funtion as in 'X := MOD(Y, Z);' |
1254 * We solve this by NOT testing for function names here, and |
1273 * We solve this by NOT testing for function names here, and |
1255 * handling this function and keyword clash in bison! |
1274 * handling this function and keyword clash in bison! |
1256 */ |
1275 */ |
|
1276 /* NOTE: The following code has been commented out as most users do not want matiec |
|
1277 * to allow the use of 'R1', 'IN' ... IL operators as identifiers, |
|
1278 * even though a literal reading of the standard allows this. |
|
1279 * We could add this as a commadnd line option, but it is not yet done. |
|
1280 * For now we just comment out the code, but leave it the commented code |
|
1281 * in so we can re-activate quickly (without having to go through old commits |
|
1282 * in the mercurial repository to figure out the missing code! |
|
1283 */ |
1257 /* |
1284 /* |
1258 {identifier} {int token = get_identifier_token(yytext); |
1285 {identifier} {int token = get_identifier_token(yytext); |
1259 // fprintf(stderr, "flex: analysing identifier '%s'...", yytext); |
1286 // fprintf(stderr, "flex: analysing identifier '%s'...", yytext); |
1260 if ((token == prev_declared_variable_name_token) || |
1287 if ((token == prev_declared_variable_name_token) || |
1261 // (token == prev_declared_derived_function_name_token) || // DO NOT add this condition! |
1288 // (token == prev_declared_derived_function_name_token) || // DO NOT add this condition! |
1472 |
1499 |
1473 /***********************/ |
1500 /***********************/ |
1474 /* B 1.5.1 - Functions */ |
1501 /* B 1.5.1 - Functions */ |
1475 /***********************/ |
1502 /***********************/ |
1476 /* Note: The following END_FUNCTION rule includes a BEGIN(INITIAL); command. |
1503 /* Note: The following END_FUNCTION rule includes a BEGIN(INITIAL); command. |
1477 * This is necessary in case the input program being pased has syntax errors that force |
1504 * This is necessary in case the input program being parsed has syntax errors that force |
1478 * flex's main state machine to never change to the il_state or the st_state |
1505 * flex's main state machine to never change to the il_state or the st_state |
1479 * after changing to the body_state. |
1506 * after changing to the body_state. |
1480 * Ths BEGIN(INITIAL) command forces the flex state machine to re-synchronise with |
1507 * Ths BEGIN(INITIAL) command forces the flex state machine to re-synchronise with |
1481 * the input stream even in the presence of buggy code! |
1508 * the input stream even in the presence of buggy code! |
1482 */ |
1509 */ |
1488 |
1515 |
1489 /*****************************/ |
1516 /*****************************/ |
1490 /* B 1.5.2 - Function Blocks */ |
1517 /* B 1.5.2 - Function Blocks */ |
1491 /*****************************/ |
1518 /*****************************/ |
1492 /* Note: The following END_FUNCTION_BLOCK rule includes a BEGIN(INITIAL); command. |
1519 /* Note: The following END_FUNCTION_BLOCK rule includes a BEGIN(INITIAL); command. |
1493 * This is necessary in case the input program being pased has syntax errors that force |
1520 * This is necessary in case the input program being parsed has syntax errors that force |
1494 * flex's main state machine to never change to the il_state or the st_state |
1521 * flex's main state machine to never change to the il_state or the st_state |
1495 * after changing to the body_state. |
1522 * after changing to the body_state. |
1496 * Ths BEGIN(INITIAL) command forces the flex state machine to re-synchronise with |
1523 * Ths BEGIN(INITIAL) command forces the flex state machine to re-synchronise with |
1497 * the input stream even in the presence of buggy code! |
1524 * the input stream even in the presence of buggy code! |
1498 */ |
1525 */ |
1506 |
1533 |
1507 /**********************/ |
1534 /**********************/ |
1508 /* B 1.5.3 - Programs */ |
1535 /* B 1.5.3 - Programs */ |
1509 /**********************/ |
1536 /**********************/ |
1510 /* Note: The following END_PROGRAM rule includes a BEGIN(INITIAL); command. |
1537 /* Note: The following END_PROGRAM rule includes a BEGIN(INITIAL); command. |
1511 * This is necessary in case the input program being pased has syntax errors that force |
1538 * This is necessary in case the input program being parsed has syntax errors that force |
1512 * flex's main state machine to never change to the il_state or the st_state |
1539 * flex's main state machine to never change to the il_state or the st_state |
1513 * after changing to the body_state. |
1540 * after changing to the body_state. |
1514 * Ths BEGIN(INITIAL) command forces the flex state machine to re-synchronise with |
1541 * Ths BEGIN(INITIAL) command forces the flex state machine to re-synchronise with |
1515 * the input stream even in the presence of buggy code! |
1542 * the input stream even in the presence of buggy code! |
1516 */ |
1543 */ |
2032 free(yycopy); |
2059 free(yycopy); |
2033 } |
2060 } |
2034 |
2061 |
2035 |
2062 |
2036 |
2063 |
|
2064 /* The body_state tries to find a ';' before a END_PROGRAM, END_FUNCTION or END_FUNCTION_BLOCK or END_ACTION |
|
2065 * To do so, it must ignore comments and pragmas. This means that we cannot do this in a signle lex rule. |
|
2066 * However, we must store any text we consume in every rule, so we can push it back into the buffer |
|
2067 * once we have decided if we are parsing ST or IL code. The following functions manage that buffer used by |
|
2068 * the body_state. |
|
2069 */ |
|
2070 /* The buffer used by the body_state state */ |
|
2071 char *bodystate_buffer = NULL; |
|
2072 |
|
2073 /* append text to bodystate_buffer */ |
|
2074 void append_bodystate_buffer(const char *text) { |
|
2075 //printf("<<<append_bodystate_buffer>>> %d <%s><%s>\n", bodystate_buffer, (NULL != bodystate_buffer)?bodystate_buffer:"NULL", text); |
|
2076 long int old_len = 0; |
|
2077 if (NULL != bodystate_buffer) old_len = strlen(bodystate_buffer); |
|
2078 bodystate_buffer = (char *)realloc(bodystate_buffer, old_len + strlen(text) + 1); |
|
2079 if (NULL == bodystate_buffer) ERROR; |
|
2080 strcpy(bodystate_buffer + old_len, text); |
|
2081 //printf("=<%s> %d %d\n", (NULL != bodystate_buffer)?bodystate_buffer:NULL, old_len + strlen(text) + 1, bodystate_buffer); |
|
2082 } |
|
2083 |
|
2084 /* Return all data in bodystate_buffer back to flex, and empty bodystate_buffer. */ |
|
2085 void unput_bodystate_buffer(void) { |
|
2086 if (NULL == bodystate_buffer) ERROR; |
|
2087 //printf("<<<unput_bodystate_buffer>>>\n%s\n", bodystate_buffer); |
|
2088 |
|
2089 for (long int i = strlen(bodystate_buffer)-1; i >= 0; i--) |
|
2090 unput(bodystate_buffer[i]); |
|
2091 |
|
2092 free(bodystate_buffer); |
|
2093 bodystate_buffer = NULL; |
|
2094 } |
|
2095 |
|
2096 |
|
2097 /* Return true if bodystate_buffer is empty */ |
|
2098 int isempty_bodystate_buffer(void) { |
|
2099 return (NULL == bodystate_buffer); |
|
2100 } |
|
2101 |
|
2102 |
|
2103 |
|
2104 |
2037 /* Called by flex when it reaches the end-of-file */ |
2105 /* Called by flex when it reaches the end-of-file */ |
2038 int yywrap(void) |
2106 int yywrap(void) |
2039 { |
2107 { |
2040 /* We reached the end of the input file... */ |
2108 /* We reached the end of the input file... */ |
2041 |
2109 |