148 * apropriately whenever it comes across an (*#include <filename> *) directive... |
148 * apropriately whenever it comes across an (*#include <filename> *) directive... |
149 */ |
149 */ |
150 const char *current_filename = NULL; |
150 const char *current_filename = NULL; |
151 |
151 |
152 |
152 |
153 |
|
154 /* We will not be using unput() in our flex code... */ |
|
155 /* NOTE: it seems that this #define is no longer needed, It has been |
|
156 * replaced by %option nounput. |
|
157 * Should we simply delete it? |
|
158 * For now leave it in, in case someone is using an old version of flex. |
|
159 * In any case, the most harm that can result in a warning message |
|
160 * when compiling iec.flex.c: |
|
161 * warning: ‘void yyunput(int, char*)’ defined but not used |
|
162 */ |
|
163 #define YY_NO_UNPUT |
|
164 |
153 |
165 /* Variable defined by the bison parser. |
154 /* Variable defined by the bison parser. |
166 * It must be initialised with the location |
155 * It must be initialised with the location |
167 * of the token being parsed. |
156 * of the token being parsed. |
168 * This is only needed if we want to keep |
157 * This is only needed if we want to keep |
234 * 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. |
235 */ |
224 */ |
236 void unput_and_mark(const char c); |
225 void unput_and_mark(const char c); |
237 |
226 |
238 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); |
239 |
238 |
240 int GetNextChar(char *b, int maxBuffer); |
239 int GetNextChar(char *b, int maxBuffer); |
241 %} |
240 %} |
242 |
241 |
243 |
242 |
967 |
966 |
968 /* 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. */ |
969 <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); |
970 |
969 |
971 /* Pragmas sent to syntax analyser (bison) */ |
970 /* Pragmas sent to syntax analyser (bison) */ |
972 {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. |
973 {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. |
974 <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), |
975 <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. |
976 |
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! */ |
977 /* 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... */ |
978 /* 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! */ |
979 {pragma} {/* return the pragmma without the enclosing '{' and '}' */ |
987 {pragma} {/* return the pragmma without the enclosing '{' and '}' */ |
980 int cut = yytext[1]=='{'?2:1; |
988 int cut = yytext[1]=='{'?2:1; |
981 yytext[strlen(yytext)-cut] = '\0'; |
989 yytext[strlen(yytext)-cut] = '\0'; |
982 yylval.ID=strdup(yytext+cut); |
990 yylval.ID=strdup(yytext+cut); |
983 return pragma_token; |
991 return pragma_token; |
984 } |
992 } |
985 <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 '}' */ |
986 int cut = yytext[1]=='{'?2:1; |
994 int cut = yytext[1]=='{'?2:1; |
987 yytext[strlen(yytext)-cut] = '\0'; |
995 yytext[strlen(yytext)-cut] = '\0'; |
988 yylval.ID=strdup(yytext+cut); |
996 yylval.ID=strdup(yytext+cut); |
989 return pragma_token; |
997 return pragma_token; |
990 } |
998 } |
1068 /* Handle all the state changes! */ |
1076 /* Handle all the state changes! */ |
1069 /*********************************/ |
1077 /*********************************/ |
1070 |
1078 |
1071 /* INITIAL -> header_state */ |
1079 /* INITIAL -> header_state */ |
1072 <INITIAL>{ |
1080 <INITIAL>{ |
1073 /* 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??? |
1074 * - 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 |
1075 * 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 |
1076 * one VAR_INPUT ... VAR_END construct! |
1107 * one VAR_INPUT ... VAR_END construct! |
1077 * - 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 |
1078 * 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 |
1082 * construct! |
1113 * construct! |
1083 * |
1114 * |
1084 * 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 |
1085 * 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. |
1086 * 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 |
1087 * 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 |
1088 * 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!! |
1089 */ |
1133 */ |
1090 |
|
1091 FUNCTION{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return FUNCTION; |
|
1092 FUNCTION_BLOCK{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return FUNCTION_BLOCK; |
|
1093 PROGRAM{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return PROGRAM; |
|
1094 CONFIGURATION{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(config_state); return CONFIGURATION; |
|
1095 } |
|
1096 |
|
1097 <get_pou_name_state>{ |
|
1098 {identifier} BEGIN(ignore_pou_state); yylval.ID=strdup(yytext); return identifier_token; |
|
1099 . BEGIN(ignore_pou_state); unput_text(0); |
|
1100 } |
|
1101 |
|
1102 <ignore_pou_state>{ |
|
1103 END_FUNCTION unput_text(0); BEGIN(INITIAL); |
|
1104 END_FUNCTION_BLOCK unput_text(0); BEGIN(INITIAL); |
|
1105 END_PROGRAM unput_text(0); BEGIN(INITIAL); |
|
1106 END_CONFIGURATION unput_text(0); BEGIN(INITIAL); |
|
1107 .|\n {}/* Ignore text inside POU! (including the '\n' character!)) */ |
|
1108 } |
|
1109 |
|
1110 /* INITIAL -> body_state */ |
|
1111 /* required if the function, program, etc.. has no VAR block! */ |
|
1112 /* We comment it out since the standard does not allow this. */ |
|
1113 /* NOTE: Even if we were to include the following code, it */ |
|
1114 /* would have no effect whatsoever since the above */ |
|
1115 /* rules will take precendence! */ |
|
1116 /* |
|
1117 <INITIAL>{ |
|
1118 FUNCTION BEGIN(body_state); return FUNCTION; |
|
1119 FUNCTION_BLOCK BEGIN(body_state); return FUNCTION_BLOCK; |
|
1120 PROGRAM BEGIN(body_state); return PROGRAM; |
|
1121 } |
|
1122 */ |
|
1123 |
|
1124 /* header_state -> (vardecl_list_state) */ |
|
1125 <header_state>{ |
1134 <header_state>{ |
1126 VAR | /* execute the next rule's action, i.e. fall-through! */ |
1135 VAR | /* execute the next rule's action, i.e. fall-through! */ |
1127 VAR_INPUT | |
1136 VAR_INPUT | |
1128 VAR_OUTPUT | |
1137 VAR_OUTPUT | |
1129 VAR_IN_OUT | |
1138 VAR_IN_OUT | |
1130 VAR_EXTERNAL | |
1139 VAR_EXTERNAL | |
1131 VAR_GLOBAL | |
1140 VAR_GLOBAL | |
1132 VAR_TEMP | |
1141 VAR_TEMP | |
1133 VAR_CONFIG | |
1142 VAR_CONFIG | |
1134 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); |
1135 } |
1144 } |
1136 |
1145 |
1137 |
1146 |
1138 /* vardecl_list_state -> (vardecl_state | body_state | INITIAL) */ |
1147 /* vardecl_list_state -> (vardecl_state | body_state | INITIAL) */ |
1139 <vardecl_list_state>{ |
1148 <vardecl_list_state>{ |
1161 } |
1170 } |
1162 |
1171 |
1163 |
1172 |
1164 /* body_state -> (il_state | st_state | sfc_state) */ |
1173 /* body_state -> (il_state | st_state | sfc_state) */ |
1165 <body_state>{ |
1174 <body_state>{ |
1166 INITIAL_STEP unput_text(0); BEGIN(sfc_state); |
1175 {st_whitespace} {/* In body state we do not process any tokens, |
1167 |
1176 * we simply store them for later processing! |
1168 {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 * NOTE: all whitespace in the begining |
1169 {direct_variable_standard} unput_text(0); BEGIN(st_state); /* will always be followed by ':=' as the left hand of an assignment statement */ |
1178 * of body_state must be removed so we can |
1170 |
1179 * detect ':=' in the beginning of TRANSACTION |
1171 RETURN unput_text(0); BEGIN(st_state); |
1180 * conditions preceded by whitespace. |
1172 IF unput_text(0); BEGIN(st_state); |
1181 * => only add to bodystate_buffer when not in beginning. |
1173 CASE unput_text(0); BEGIN(st_state); |
1182 */ |
1174 FOR unput_text(0); BEGIN(st_state); |
1183 if (!isempty_bodystate_buffer()) |
1175 WHILE unput_text(0); BEGIN(st_state); |
1184 append_bodystate_buffer(yytext); |
1176 EXIT unput_text(0); BEGIN(st_state); |
1185 } |
1177 REPEAT unput_text(0); BEGIN(st_state); |
1186 /* 'INITIAL_STEP' always used in beginning of SFCs !! */ |
1178 |
1187 INITIAL_STEP { if (isempty_bodystate_buffer()) {unput_text(0); BEGIN(sfc_state);} |
1179 /* ':=' occurs only in transitions, and not Function or FB bodies! */ |
1188 else {append_bodystate_buffer(yytext);} |
1180 := unput_text(0); BEGIN(st_state); |
1189 } |
1181 |
1190 |
1182 {identifier} {int token = get_identifier_token(yytext); |
1191 /* ':=', at the very beginning of a 'body', occurs only in transitions and not Function, FB, or Program bodies! */ |
1183 if ((token == prev_declared_fb_name_token) || (token == prev_declared_variable_name_token)) { |
1192 := { 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! */ |
1184 /* the code has a call to a function block OR has an assingment with a variable as the lvalue */ |
1193 else {append_bodystate_buffer(yytext);} |
1185 unput_text(0); BEGIN(st_state); |
1194 } |
1186 } else |
1195 |
1187 if (token == prev_declared_derived_function_name_token) { |
1196 /* 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). */ |
1188 /* the code has a call to a function - must be IL */ |
1197 END_ACTION | /* execute the next rule's action, i.e. fall-through! */ |
1189 unput_text(0); BEGIN(il_state); |
1198 END_FUNCTION | |
1190 } else { |
1199 END_FUNCTION_BLOCK | |
1191 /* Might be a lable in IL, or a bug in ST/IL code. We jump to IL */ |
1200 END_PROGRAM { append_bodystate_buffer(yytext); unput_bodystate_buffer(); BEGIN(il_state); /*printf("returning start_IL_body_token\n");*/ return start_IL_body_token;} |
1192 unput_text(0); BEGIN(il_state); |
1201 .|\n { append_bodystate_buffer(yytext); |
1193 } |
1202 if (strcmp(yytext, ";") == 0) |
1194 } |
1203 {unput_bodystate_buffer(); BEGIN(st_state); /*printf("returning start_ST_body_token\n");*/ return start_ST_body_token;} |
1195 |
1204 } |
1196 . 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... */ |
1205 /* The following rules are not really necessary. They just make compilation faster in case the ST Statement List starts with one fot he following... */ |
|
1206 RETURN | /* execute the next rule's action, i.e. fall-through! */ |
|
1207 IF | |
|
1208 CASE | |
|
1209 FOR | |
|
1210 WHILE | |
|
1211 EXIT | |
|
1212 REPEAT { if (isempty_bodystate_buffer()) {unput_text(0); BEGIN(st_state); return start_ST_body_token;} |
|
1213 else {append_bodystate_buffer(yytext);} |
|
1214 } |
|
1215 |
1197 } /* end of body_state lexical parser */ |
1216 } /* end of body_state lexical parser */ |
1198 |
|
1199 |
1217 |
1200 |
1218 |
1201 /* (il_state | st_state) -> pop to $previous_state (vardecl_list_state or sfc_state) */ |
1219 /* (il_state | st_state) -> pop to $previous_state (vardecl_list_state or sfc_state) */ |
1202 <il_state,st_state>{ |
1220 <il_state,st_state>{ |
1203 END_FUNCTION yy_pop_state(); unput_text(0); |
1221 END_FUNCTION yy_pop_state(); unput_text(0); |
1223 /* Next is to to remove all whitespace */ |
1241 /* Next is to to remove all whitespace */ |
1224 /***************************************/ |
1242 /***************************************/ |
1225 /* NOTE: pragmas are handled right at the beginning... */ |
1243 /* NOTE: pragmas are handled right at the beginning... */ |
1226 |
1244 |
1227 /* The whitespace */ |
1245 /* The whitespace */ |
1228 <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 */ |
1246 <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 */ |
1229 <il_state>{il_whitespace} /* Eat any whitespace */ |
1247 <il_state>{il_whitespace} /* Eat any whitespace */ |
|
1248 /* NOTE: Due to the need of having the following rule have higher priority, |
|
1249 * the following rule was moved to an earlier position in this file. |
|
1250 <body_state>{st_whitespace} {...} |
|
1251 */ |
1230 |
1252 |
1231 /* The comments */ |
1253 /* The comments */ |
1232 <get_pou_name_state,ignore_pou_state,body_state,vardecl_list_state>{comment_beg} yy_push_state(comment_state); |
1254 <get_pou_name_state,ignore_pou_state,body_state,vardecl_list_state>{comment_beg} yy_push_state(comment_state); |
1233 {comment_beg} yy_push_state(comment_state); |
1255 {comment_beg} yy_push_state(comment_state); |
1234 <comment_state>{ |
1256 <comment_state>{ |
1263 * If we don't, then even it will not be possible to use 'MOD' |
1285 * If we don't, then even it will not be possible to use 'MOD' |
1264 * as a funtion as in 'X := MOD(Y, Z);' |
1286 * as a funtion as in 'X := MOD(Y, Z);' |
1265 * We solve this by NOT testing for function names here, and |
1287 * We solve this by NOT testing for function names here, and |
1266 * handling this function and keyword clash in bison! |
1288 * handling this function and keyword clash in bison! |
1267 */ |
1289 */ |
|
1290 /* NOTE: The following code has been commented out as most users do not want matiec |
|
1291 * to allow the use of 'R1', 'IN' ... IL operators as identifiers, |
|
1292 * even though a literal reading of the standard allows this. |
|
1293 * We could add this as a commadnd line option, but it is not yet done. |
|
1294 * For now we just comment out the code, but leave it the commented code |
|
1295 * in so we can re-activate quickly (without having to go through old commits |
|
1296 * in the mercurial repository to figure out the missing code! |
|
1297 */ |
1268 /* |
1298 /* |
1269 {identifier} {int token = get_identifier_token(yytext); |
1299 {identifier} {int token = get_identifier_token(yytext); |
1270 // fprintf(stderr, "flex: analysing identifier '%s'...", yytext); |
1300 // fprintf(stderr, "flex: analysing identifier '%s'...", yytext); |
1271 if ((token == prev_declared_variable_name_token) || |
1301 if ((token == prev_declared_variable_name_token) || |
1272 // (token == prev_declared_derived_function_name_token) || // DO NOT add this condition! |
1302 // (token == prev_declared_derived_function_name_token) || // DO NOT add this condition! |
1376 DT return DT; /* Keyword (Data Type) */ |
1406 DT return DT; /* Keyword (Data Type) */ |
1377 TOD return TOD; /* Keyword (Data Type) */ |
1407 TOD return TOD; /* Keyword (Data Type) */ |
1378 DATE_AND_TIME return DATE_AND_TIME; /* Keyword (Data Type) */ |
1408 DATE_AND_TIME return DATE_AND_TIME; /* Keyword (Data Type) */ |
1379 TIME_OF_DAY return TIME_OF_DAY; /* Keyword (Data Type) */ |
1409 TIME_OF_DAY return TIME_OF_DAY; /* Keyword (Data Type) */ |
1380 |
1410 |
|
1411 /* A non-standard extension! */ |
|
1412 VOID {if (runtime_options.allow_void_datatype) {return VOID;} else {REJECT;}} |
|
1413 |
|
1414 |
1381 /*****************************************************************/ |
1415 /*****************************************************************/ |
1382 /* Keywords defined in "Safety Software Technical Specification" */ |
1416 /* Keywords defined in "Safety Software Technical Specification" */ |
1383 /*****************************************************************/ |
1417 /*****************************************************************/ |
1384 /* |
1418 /* |
1385 * NOTE: The following keywords are define in |
1419 * NOTE: The following keywords are define in |
1478 |
1512 |
1479 |
1513 |
1480 /***********************/ |
1514 /***********************/ |
1481 /* B 1.5.1 - Functions */ |
1515 /* B 1.5.1 - Functions */ |
1482 /***********************/ |
1516 /***********************/ |
1483 FUNCTION return FUNCTION; /* Keyword */ |
1517 /* Note: The following END_FUNCTION rule includes a BEGIN(INITIAL); command. |
1484 END_FUNCTION return END_FUNCTION; /* Keyword */ |
1518 * This is necessary in case the input program being parsed has syntax errors that force |
1485 VAR return VAR; /* Keyword */ |
1519 * flex's main state machine to never change to the il_state or the st_state |
1486 CONSTANT return CONSTANT; /* Keyword */ |
1520 * after changing to the body_state. |
|
1521 * Ths BEGIN(INITIAL) command forces the flex state machine to re-synchronise with |
|
1522 * the input stream even in the presence of buggy code! |
|
1523 */ |
|
1524 FUNCTION return FUNCTION; /* Keyword */ |
|
1525 END_FUNCTION BEGIN(INITIAL); return END_FUNCTION; /* Keyword */ /* see Note above */ |
|
1526 VAR return VAR; /* Keyword */ |
|
1527 CONSTANT return CONSTANT; /* Keyword */ |
1487 |
1528 |
1488 |
1529 |
1489 /*****************************/ |
1530 /*****************************/ |
1490 /* B 1.5.2 - Function Blocks */ |
1531 /* B 1.5.2 - Function Blocks */ |
1491 /*****************************/ |
1532 /*****************************/ |
1492 FUNCTION_BLOCK return FUNCTION_BLOCK; /* Keyword */ |
1533 /* Note: The following END_FUNCTION_BLOCK rule includes a BEGIN(INITIAL); command. |
1493 END_FUNCTION_BLOCK return END_FUNCTION_BLOCK; /* Keyword */ |
1534 * This is necessary in case the input program being parsed has syntax errors that force |
1494 VAR_TEMP return VAR_TEMP; /* Keyword */ |
1535 * flex's main state machine to never change to the il_state or the st_state |
1495 VAR return VAR; /* Keyword */ |
1536 * after changing to the body_state. |
1496 NON_RETAIN return NON_RETAIN; /* Keyword */ |
1537 * Ths BEGIN(INITIAL) command forces the flex state machine to re-synchronise with |
1497 END_VAR return END_VAR; /* Keyword */ |
1538 * the input stream even in the presence of buggy code! |
|
1539 */ |
|
1540 FUNCTION_BLOCK return FUNCTION_BLOCK; /* Keyword */ |
|
1541 END_FUNCTION_BLOCK BEGIN(INITIAL); return END_FUNCTION_BLOCK; /* Keyword */ /* see Note above */ |
|
1542 VAR_TEMP return VAR_TEMP; /* Keyword */ |
|
1543 VAR return VAR; /* Keyword */ |
|
1544 NON_RETAIN return NON_RETAIN; /* Keyword */ |
|
1545 END_VAR return END_VAR; /* Keyword */ |
1498 |
1546 |
1499 |
1547 |
1500 /**********************/ |
1548 /**********************/ |
1501 /* B 1.5.3 - Programs */ |
1549 /* B 1.5.3 - Programs */ |
1502 /**********************/ |
1550 /**********************/ |
1503 PROGRAM return PROGRAM; /* Keyword */ |
1551 /* Note: The following END_PROGRAM rule includes a BEGIN(INITIAL); command. |
1504 END_PROGRAM return END_PROGRAM; /* Keyword */ |
1552 * This is necessary in case the input program being parsed has syntax errors that force |
|
1553 * flex's main state machine to never change to the il_state or the st_state |
|
1554 * after changing to the body_state. |
|
1555 * Ths BEGIN(INITIAL) command forces the flex state machine to re-synchronise with |
|
1556 * the input stream even in the presence of buggy code! |
|
1557 */ |
|
1558 PROGRAM return PROGRAM; /* Keyword */ |
|
1559 END_PROGRAM BEGIN(INITIAL); return END_PROGRAM; /* Keyword */ /* see Note above */ |
1505 |
1560 |
1506 |
1561 |
1507 /********************************************/ |
1562 /********************************************/ |
1508 /* B 1.6 Sequential Function Chart elements */ |
1563 /* B 1.6 Sequential Function Chart elements */ |
1509 /********************************************/ |
1564 /********************************************/ |
1547 |
1602 |
1548 |
1603 |
1549 /********************************/ |
1604 /********************************/ |
1550 /* B 1.7 Configuration elements */ |
1605 /* B 1.7 Configuration elements */ |
1551 /********************************/ |
1606 /********************************/ |
1552 CONFIGURATION return CONFIGURATION; /* Keyword */ |
1607 /* Note: The following END_CONFIGURATION rule will never get to be used, as we have |
1553 END_CONFIGURATION return END_CONFIGURATION; /* Keyword */ |
1608 * another identical rule above (closer to the rules handling the transitions |
1554 TASK return TASK; /* Keyword */ |
1609 * of the main state machine) that will always execute before this one. |
1555 RESOURCE return RESOURCE; /* Keyword */ |
1610 * Note: The following END_CONFIGURATION rule includes a BEGIN(INITIAL); command. |
1556 ON return ON; /* Keyword */ |
1611 * This is nt strictly necessary, but I place it here so it follwos the same |
1557 END_RESOURCE return END_RESOURCE; /* Keyword */ |
1612 * pattern used in END_FUNCTION, END_PROGRAM, and END_FUNCTION_BLOCK |
1558 VAR_CONFIG return VAR_CONFIG; /* Keyword */ |
1613 */ |
1559 VAR_ACCESS return VAR_ACCESS; /* Keyword */ |
1614 CONFIGURATION return CONFIGURATION; /* Keyword */ |
1560 END_VAR return END_VAR; /* Keyword */ |
1615 END_CONFIGURATION BEGIN(INITIAL); return END_CONFIGURATION; /* Keyword */ /* see 2 Notes above! */ |
1561 WITH return WITH; /* Keyword */ |
1616 TASK return TASK; /* Keyword */ |
1562 PROGRAM return PROGRAM; /* Keyword */ |
1617 RESOURCE return RESOURCE; /* Keyword */ |
1563 RETAIN return RETAIN; /* Keyword */ |
1618 ON return ON; /* Keyword */ |
1564 NON_RETAIN return NON_RETAIN; /* Keyword */ |
1619 END_RESOURCE return END_RESOURCE; /* Keyword */ |
1565 READ_WRITE return READ_WRITE; /* Keyword */ |
1620 VAR_CONFIG return VAR_CONFIG; /* Keyword */ |
1566 READ_ONLY return READ_ONLY; /* Keyword */ |
1621 VAR_ACCESS return VAR_ACCESS; /* Keyword */ |
|
1622 END_VAR return END_VAR; /* Keyword */ |
|
1623 WITH return WITH; /* Keyword */ |
|
1624 PROGRAM return PROGRAM; /* Keyword */ |
|
1625 RETAIN return RETAIN; /* Keyword */ |
|
1626 NON_RETAIN return NON_RETAIN; /* Keyword */ |
|
1627 READ_WRITE return READ_WRITE; /* Keyword */ |
|
1628 READ_ONLY return READ_ONLY; /* Keyword */ |
1567 |
1629 |
1568 /* PRIORITY, SINGLE and INTERVAL are not a keywords, so we only return them when |
1630 /* PRIORITY, SINGLE and INTERVAL are not a keywords, so we only return them when |
1569 * it is explicitly required and we are not expecting any identifiers |
1631 * it is explicitly required and we are not expecting any identifiers |
1570 * that could also use the same letter sequence (i.e. an identifier: piority, ...) |
1632 * that could also use the same letter sequence (i.e. an identifier: piority, ...) |
1571 */ |
1633 */ |
2011 free(yycopy); |
2073 free(yycopy); |
2012 } |
2074 } |
2013 |
2075 |
2014 |
2076 |
2015 |
2077 |
|
2078 /* The body_state tries to find a ';' before a END_PROGRAM, END_FUNCTION or END_FUNCTION_BLOCK or END_ACTION |
|
2079 * To do so, it must ignore comments and pragmas. This means that we cannot do this in a signle lex rule. |
|
2080 * However, we must store any text we consume in every rule, so we can push it back into the buffer |
|
2081 * once we have decided if we are parsing ST or IL code. The following functions manage that buffer used by |
|
2082 * the body_state. |
|
2083 */ |
|
2084 /* The buffer used by the body_state state */ |
|
2085 char *bodystate_buffer = NULL; |
|
2086 |
|
2087 /* append text to bodystate_buffer */ |
|
2088 void append_bodystate_buffer(const char *text) { |
|
2089 //printf("<<<append_bodystate_buffer>>> %d <%s><%s>\n", bodystate_buffer, text, (NULL != bodystate_buffer)?bodystate_buffer:"NULL"); |
|
2090 long int old_len = 0; |
|
2091 if (NULL != bodystate_buffer) old_len = strlen(bodystate_buffer); |
|
2092 bodystate_buffer = (char *)realloc(bodystate_buffer, old_len + strlen(text) + 1); |
|
2093 if (NULL == bodystate_buffer) ERROR; |
|
2094 strcpy(bodystate_buffer + old_len, text); |
|
2095 //printf("=<%s> %d %d\n", (NULL != bodystate_buffer)?bodystate_buffer:NULL, old_len + strlen(text) + 1, bodystate_buffer); |
|
2096 } |
|
2097 |
|
2098 /* Return all data in bodystate_buffer back to flex, and empty bodystate_buffer. */ |
|
2099 void unput_bodystate_buffer(void) { |
|
2100 if (NULL == bodystate_buffer) ERROR; |
|
2101 //printf("<<<unput_bodystate_buffer>>>\n%s\n", bodystate_buffer); |
|
2102 |
|
2103 for (long int i = strlen(bodystate_buffer)-1; i >= 0; i--) |
|
2104 unput(bodystate_buffer[i]); |
|
2105 |
|
2106 free(bodystate_buffer); |
|
2107 bodystate_buffer = NULL; |
|
2108 } |
|
2109 |
|
2110 |
|
2111 /* Return true if bodystate_buffer is empty */ |
|
2112 int isempty_bodystate_buffer(void) { |
|
2113 return (NULL == bodystate_buffer); |
|
2114 } |
|
2115 |
|
2116 |
|
2117 |
|
2118 |
2016 /* Called by flex when it reaches the end-of-file */ |
2119 /* Called by flex when it reaches the end-of-file */ |
2017 int yywrap(void) |
2120 int yywrap(void) |
2018 { |
2121 { |
2019 /* We reached the end of the input file... */ |
2122 /* We reached the end of the input file... */ |
2020 |
2123 |