345 * e.g.: TIME#55d_4h_56m |
345 * e.g.: TIME#55d_4h_56m |
346 * We would like to return to bison the tokens 'TIME' '#' '55d' '_' '4h' '_' '56m' |
346 * We would like to return to bison the tokens 'TIME' '#' '55d' '_' '4h' '_' '56m' |
347 * Unfortunately, flex will join '_' and '4h' to create a legal {identifier} '_4h', |
347 * Unfortunately, flex will join '_' and '4h' to create a legal {identifier} '_4h', |
348 * and return that identifier instead! So, we added this state! |
348 * and return that identifier instead! So, we added this state! |
349 * |
349 * |
350 * There is a main state machine... |
350 * The ignore_pou_state state is only used when bison says it is doing the pre-parsing. |
|
351 * During pre-parsing, the main state machine will only transition between |
|
352 * INITIAL and ignore_pou_state, and from here back to INITIAL. All other |
|
353 * transitions are inhibited. This inhibition is actually just enforced by making |
|
354 * sure that the INITIAL ---> ignore_pou_state transition is tested before all other |
|
355 * transitions coming out of INITIAL state. All other transitions are unaffected, as they |
|
356 * never get a chance to be evaluated when bison is doing pre-parsing. |
|
357 * Pre-parsing is a first quick scan through the whole input source code simply |
|
358 * to determine the list of POUs and datatypes that will be defined in that |
|
359 * code. Basically, the objective is to fill up the previously_declared_xxxxx |
|
360 * maps, without processing the code itself. Once these maps have been filled up, |
|
361 * bison will throw away the AST (abstract syntax tree) created up to that point, |
|
362 * and scan through the same source code again, but this time creating a correct AST. |
|
363 * This pre-scan allows the source code to reference POUs and datatypes that are |
|
364 * only declared after they are used! |
351 * |
365 * |
|
366 * |
|
367 * Here is a main state machine... |
|
368 * --+ |
|
369 * | these states are |
|
370 * +------------> get_pou_name_state ----> ignore_pou_state | only active |
|
371 * | | | when bison is |
|
372 * | ------------------------------------------+ | doing the |
|
373 * | | | pre-parsing!! |
|
374 * | v --+ |
352 * +---> INITIAL <-------> config |
375 * +---> INITIAL <-------> config |
353 * | \ |
376 * | \ |
354 * | V |
377 * | V |
355 * | header_state |
378 * | header_state |
356 * | | |
379 * | | |
377 * - The transitions form sfc to body will be decided by bison, which will |
400 * - The transitions form sfc to body will be decided by bison, which will |
378 * tell flex to do the transition by calling cmd_goto_body_state(). |
401 * tell flex to do the transition by calling cmd_goto_body_state(). |
379 * |
402 * |
380 * |
403 * |
381 * Possible state changes are: |
404 * Possible state changes are: |
|
405 * INITIAL -> goto(ignore_pou_state) |
|
406 * (This transition state is only used when bison says it is doing the pre-parsing.) |
|
407 * (This transition takes precedence over all other transitions!) |
|
408 * (when a FUNCTION, FUNCTION_BLOCK, PROGRAM or CONFIGURATION is found) |
|
409 * |
382 * INITIAL -> goto(config_state) |
410 * INITIAL -> goto(config_state) |
383 * (when a CONFIGURATION is found) |
411 * (when a CONFIGURATION is found) |
384 * |
412 * |
385 * INITIAL -> goto(header_state) |
413 * INITIAL -> goto(header_state) |
386 * (when a FUNCTION, FUNCTION_BLOCK, or PROGRAM is found) |
414 * (when a FUNCTION, FUNCTION_BLOCK, or PROGRAM is found) |
|
415 * |
387 * header_state -> goto(vardecl_list_state) |
416 * header_state -> goto(vardecl_list_state) |
388 * (When the first VAR token is found, i.e. at begining of first VAR .. END_VAR declaration) |
417 * (When the first VAR token is found, i.e. at begining of first VAR .. END_VAR declaration) |
389 * |
418 * |
390 * vardecl_list_state -> push current state (vardecl_list_state), and goto(vardecl_state) |
419 * vardecl_list_state -> push current state (vardecl_list_state), and goto(vardecl_state) |
391 * (when a VAR token is found) |
420 * (when a VAR token is found) |
408 * (when a END_FUNCTION, END_FUNCTION_BLOCK, END_PROGRAM, |
437 * (when a END_FUNCTION, END_FUNCTION_BLOCK, END_PROGRAM, |
409 * END_ACTION or END_TRANSITION is found) |
438 * END_ACTION or END_TRANSITION is found) |
410 * sfc_state -> pop() to vardecl_list_state |
439 * sfc_state -> pop() to vardecl_list_state |
411 * (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found) |
440 * (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found) |
412 * |
441 * |
|
442 * ignore_pou_state -> goto(INITIAL) |
|
443 * (when a END_FUNCTION, END_FUNCTION_BLOCK, END_PROGRAM or END_CONFIGURATION is found) |
413 * vardecl_list_state -> goto(INITIAL) |
444 * vardecl_list_state -> goto(INITIAL) |
414 * (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found) |
445 * (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found) |
415 * config_state -> goto(INITIAL) |
446 * config_state -> goto(INITIAL) |
416 * (when a END_CONFIGURATION is found) |
447 * (when a END_CONFIGURATION is found) |
417 * |
448 * |
418 * |
449 * |
419 * sfc_state -> push current state(sfc_state); goto(body_state) |
450 * sfc_state -> push current state(sfc_state); goto(body_state) |
420 * (when parsing an action. This transition is requested by bison) |
451 * (when parsing an action. This transition is requested by bison) |
421 * sfc_state -> push current state(sfc_state); goto(sfc_qualifier_state) |
452 * sfc_state -> push current state(sfc_state); goto(sfc_qualifier_state) |
431 * |
462 * |
432 * There is another secondary state machine for parsing comments, another for file_includes, |
463 * There is another secondary state machine for parsing comments, another for file_includes, |
433 * and yet another for time literals. |
464 * and yet another for time literals. |
434 */ |
465 */ |
435 |
466 |
|
467 |
|
468 /* Bison is in the pre-parsing stage, and we are parsing a POU. Ignore everything up to the end of the POU! */ |
|
469 %x ignore_pou_state |
|
470 %x get_pou_name_state |
436 |
471 |
437 /* we are parsing a configuration. */ |
472 /* we are parsing a configuration. */ |
438 %s config_state |
473 %s config_state |
439 |
474 |
440 /* Inside a configuration, we are parsing a task initialisation parameters */ |
475 /* Inside a configuration, we are parsing a task initialisation parameters */ |
1050 * FUNCTION_BLOCKs that do not have at least one VAR_END before the body_state. |
1085 * FUNCTION_BLOCKs that do not have at least one VAR_END before the body_state. |
1051 * If the code has an error, and no VAR_END before the body, we will simply |
1086 * If the code has an error, and no VAR_END before the body, we will simply |
1052 * continue in the <vardecl_state> state, untill the end of the FUNCTION, FUNCTION_BLOCK |
1087 * continue in the <vardecl_state> state, untill the end of the FUNCTION, FUNCTION_BLOCK |
1053 * or PROGAM. |
1088 * or PROGAM. |
1054 */ |
1089 */ |
1055 FUNCTION BEGIN(header_state); return FUNCTION; |
1090 |
1056 FUNCTION_BLOCK BEGIN(header_state); return FUNCTION_BLOCK; |
1091 FUNCTION{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return FUNCTION; |
1057 PROGRAM BEGIN(header_state); return PROGRAM; |
1092 FUNCTION_BLOCK{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return FUNCTION_BLOCK; |
1058 CONFIGURATION BEGIN(config_state); return CONFIGURATION; |
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!)) */ |
1059 } |
1108 } |
1060 |
1109 |
1061 /* INITIAL -> body_state */ |
1110 /* INITIAL -> body_state */ |
1062 /* required if the function, program, etc.. has no VAR block! */ |
1111 /* required if the function, program, etc.. has no VAR block! */ |
1063 /* We comment it out since the standard does not allow this. */ |
1112 /* We comment it out since the standard does not allow this. */ |
1178 /* The whitespace */ |
1227 /* The whitespace */ |
1179 <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 */ |
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 */ |
1180 <il_state>{il_whitespace} /* Eat any whitespace */ |
1229 <il_state>{il_whitespace} /* Eat any whitespace */ |
1181 |
1230 |
1182 /* The comments */ |
1231 /* The comments */ |
1183 <body_state,vardecl_list_state>{comment_beg} yy_push_state(comment_state); |
1232 <get_pou_name_state,ignore_pou_state,body_state,vardecl_list_state>{comment_beg} yy_push_state(comment_state); |
1184 {comment_beg} yy_push_state(comment_state); |
1233 {comment_beg} yy_push_state(comment_state); |
1185 <comment_state>{ |
1234 <comment_state>{ |
1186 {comment_beg} {if (get_opt_nested_comments()) yy_push_state(comment_state);} |
1235 {comment_beg} {if (get_opt_nested_comments()) yy_push_state(comment_state);} |
1187 {comment_end} yy_pop_state(); |
1236 {comment_end} yy_pop_state(); |
1188 . /* Ignore text inside comment! */ |
1237 . /* Ignore text inside comment! */ |