# HG changeset patch # User mjsousa # Date 1417268600 0 # Node ID e984cfdf3b10080ec131858966bca326fa187c40 # Parent f53ea4c8621ccb2c5f5dbd81faea54757552a9c3 Add a pre-parsing phase to stage1_2 (allows source code that references POUs and datatypes before they are declared) diff -r f53ea4c8621c -r e984cfdf3b10 stage1_2/iec_bison.yy --- a/stage1_2/iec_bison.yy Sat Nov 29 12:10:34 2014 +0000 +++ b/stage1_2/iec_bison.yy Sat Nov 29 13:43:20 2014 +0000 @@ -1141,6 +1141,7 @@ %type prev_declared_resource_name %token prev_declared_resource_name_token +%type prev_declared_configuration_name %token prev_declared_configuration_name_token // %type prev_declared_task_name @@ -1605,20 +1606,20 @@ ; -prev_declared_variable_name : prev_declared_variable_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_fb_name : prev_declared_fb_name_token {$$ = new identifier_c($1, locloc(@$));}; - -prev_declared_simple_type_name : prev_declared_simple_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; -prev_declared_subrange_type_name : prev_declared_subrange_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; +prev_declared_variable_name: prev_declared_variable_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_fb_name: prev_declared_fb_name_token {$$ = new identifier_c($1, locloc(@$));}; + +prev_declared_simple_type_name: prev_declared_simple_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; +prev_declared_subrange_type_name: prev_declared_subrange_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; prev_declared_enumerated_type_name: prev_declared_enumerated_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; -prev_declared_array_type_name : prev_declared_array_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; -prev_declared_structure_type_name : prev_declared_structure_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; -prev_declared_string_type_name : prev_declared_string_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; -prev_declared_ref_type_name : prev_declared_ref_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; /* defined in IEC 61131-3 v3 */ - -prev_declared_derived_function_name : prev_declared_derived_function_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_array_type_name: prev_declared_array_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; +prev_declared_structure_type_name: prev_declared_structure_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; +prev_declared_string_type_name: prev_declared_string_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; +prev_declared_ref_type_name: prev_declared_ref_type_name_token {$$ = new derived_datatype_identifier_c($1, locloc(@$));}; /* defined in IEC 61131-3 v3 */ + +prev_declared_derived_function_name: prev_declared_derived_function_name_token {$$ = new identifier_c($1, locloc(@$));}; prev_declared_derived_function_block_name: prev_declared_derived_function_block_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_program_type_name : prev_declared_program_type_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_program_type_name: prev_declared_program_type_name_token {$$ = new identifier_c($1, locloc(@$));}; @@ -2605,12 +2606,25 @@ simple_type_declaration: /* simple_type_name ':' simple_spec_init */ /* To understand why simple_spec_init was brocken up into its consituent components in the following rules, please see note in the definition of 'enumerated_type_declaration'. */ +/* PRE_PARSING: The rules expected to be applied by the preparser. */ identifier ':' simple_specification {library_element_symtable.insert($1, prev_declared_simple_type_name_token);} + {if (!get_preparse_state()) ERROR;} +| identifier ':' elementary_type_name {library_element_symtable.insert($1, prev_declared_simple_type_name_token);} ASSIGN constant + {if (!get_preparse_state()) ERROR;} +| identifier ':' prev_declared_simple_type_name {library_element_symtable.insert($1, prev_declared_simple_type_name_token);} ASSIGN constant + {if (!get_preparse_state()) ERROR;} +/* STANDARD_PARSING: The rules expected to be applied after the preparser has finished. */ +| prev_declared_simple_type_name ':' simple_spec_init {$$ = new simple_type_declaration_c($1, $3, locloc(@$));} -| identifier ':' elementary_type_name {library_element_symtable.insert($1, prev_declared_simple_type_name_token);} ASSIGN constant - {$$ = new simple_type_declaration_c($1, new simple_spec_init_c($3, $6, locf(@3), locl(@6)), locloc(@$));} -| identifier ':' prev_declared_simple_type_name {library_element_symtable.insert($1, prev_declared_simple_type_name_token);} ASSIGN constant - {$$ = new simple_type_declaration_c($1, new simple_spec_init_c($3, $6, locf(@3), locl(@6)), locloc(@$));} +/* These three rules can now be safely replaced by the original rule abvoe!! */ +/* +| prev_declared_simple_type_name ':' simple_specification + {$$ = new simple_type_declaration_c($1, $3, locloc(@$));} +| prev_declared_simple_type_name ':' elementary_type_name ASSIGN constant + {$$ = new simple_type_declaration_c($1, new simple_spec_init_c($3, $5, locf(@3), locl(@5)), locloc(@$));} +| prev_declared_simple_type_name ':' prev_declared_simple_type_name ASSIGN constant + {$$ = new simple_type_declaration_c($1, new simple_spec_init_c($3, $5, locf(@3), locl(@5)), locloc(@$));} +*/ /* ERROR_CHECK_BEGIN */ | error ':' simple_spec_init {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid name defined for data type declaration.");yyerrok;} @@ -2683,10 +2697,12 @@ subrange_type_declaration: /* subrange_type_name ':' subrange_spec_init */ - identifier ':' subrange_spec_init - {$$ = new subrange_type_declaration_c($1, $3, locloc(@$)); - library_element_symtable.insert($1, prev_declared_subrange_type_name_token); - } +/* PRE_PARSING: The rules expected to be applied by the preparser. */ + identifier ':' subrange_spec_init {library_element_symtable.insert($1, prev_declared_subrange_type_name_token);} + {if (!get_preparse_state()) ERROR;} +/* STANDARD_PARSING: The rules expected to be applied after the preparser has finished. */ +| prev_declared_subrange_type_name ':' subrange_spec_init + {$$ = new subrange_type_declaration_c($1, $3, locloc(@$));} /* ERROR_CHECK_BEGIN */ | error ':' subrange_spec_init {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid name defined for subrange type declaration."); yyerrok;} @@ -2758,10 +2774,22 @@ * identifier ':' enumerated_spec_init * and include the library_element_symtable.insert(...) code in the rule actions! */ +/* PRE_PARSING: The rules expected to be applied by the preparser. */ identifier ':' enumerated_specification {library_element_symtable.insert($1, prev_declared_enumerated_type_name_token);} + {if (!get_preparse_state()) ERROR;} +| identifier ':' enumerated_specification {library_element_symtable.insert($1, prev_declared_enumerated_type_name_token);} ASSIGN enumerated_value + {if (!get_preparse_state()) ERROR;} +/* STANDARD_PARSING: The rules expected to be applied after the preparser has finished. */ +/* Since the enumerated type name is placed in the library_element_symtable during preparsing, we can now safely use the single rule: */ +| prev_declared_enumerated_type_name ':' enumerated_spec_init + {$$ = new enumerated_type_declaration_c($1, $3, locloc(@$));} + /* These two rules are equivalent to the above rule */ +/* +| prev_declared_enumerated_type_name ':' enumerated_specification {library_element_symtable.insert($1, prev_declared_enumerated_type_name_token);} {$$ = new enumerated_type_declaration_c($1, new enumerated_spec_init_c($3, NULL, locloc(@3)), locloc(@$));} -| identifier ':' enumerated_specification {library_element_symtable.insert($1, prev_declared_enumerated_type_name_token);} ASSIGN enumerated_value +| prev_declared_enumerated_type_name ':' enumerated_specification {library_element_symtable.insert($1, prev_declared_enumerated_type_name_token);} ASSIGN enumerated_value {$$ = new enumerated_type_declaration_c($1, new enumerated_spec_init_c($3, $6, locf(@3), locl(@6)), locloc(@$));} +*/ /* ERROR_CHECK_BEGIN */ | error ':' enumerated_spec_init {$$ = NULL; print_err_msg(locf(@1), locl(@1), "invalid name defined for enumerated type declaration."); yyerrok;} @@ -2849,10 +2877,12 @@ array_type_declaration: /* array_type_name ':' array_spec_init */ - identifier ':' array_spec_init - {$$ = new array_type_declaration_c($1, $3, locloc(@$)); - library_element_symtable.insert($1, prev_declared_array_type_name_token); - } +/* PRE_PARSING: The rules expected to be applied by the preparser. */ + identifier ':' array_spec_init {library_element_symtable.insert($1, prev_declared_array_type_name_token);} + {if (!get_preparse_state()) ERROR;} +/* STANDARD_PARSING: The rules expected to be applied after the preparser has finished. */ +| prev_declared_array_type_name ':' array_spec_init + {$$ = new array_type_declaration_c($1, $3, locloc(@$));} /* ERROR_CHECK_BEGIN */ | identifier array_spec_init {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in array type declaration."); yynerrs++;} @@ -3003,10 +3033,12 @@ structure_type_declaration: /* structure_type_name ':' structure_specification */ - identifier ':' structure_specification - {$$ = new structure_type_declaration_c($1, $3, locloc(@$)); - library_element_symtable.insert($1, prev_declared_structure_type_name_token); - } +/* PRE_PARSING: The rules expected to be applied by the preparser. */ + identifier ':' structure_specification {library_element_symtable.insert($1, prev_declared_structure_type_name_token);} + {if (!get_preparse_state()) ERROR;} +/* STANDARD_PARSING: The rules expected to be applied after the preparser has finished. */ +| prev_declared_structure_type_name ':' structure_specification + {$$ = new structure_type_declaration_c($1, $3, locloc(@$));} /* ERROR_CHECK_BEGIN */ | identifier structure_specification {$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between data type name and specification in structure type declaration."); yynerrs++;} @@ -3188,10 +3220,12 @@ string_type_declaration: /* string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init */ - identifier ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init - {$$ = new string_type_declaration_c($1, $3, $4, $5, locloc(@$)); - library_element_symtable.insert($1, prev_declared_string_type_name_token); - } +/* PRE_PARSING: The rules expected to be applied by the preparser. */ + identifier ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init {library_element_symtable.insert($1, prev_declared_string_type_name_token);} + {if (!get_preparse_state()) ERROR;} +/* STANDARD_PARSING: The rules expected to be applied after the preparser has finished. */ +| prev_declared_string_type_name ':' elementary_string_type_name string_type_declaration_size string_type_declaration_init + {$$ = new string_type_declaration_c($1, $3, $4, $5, locloc(@$));} ; @@ -3316,10 +3350,12 @@ ; ref_type_decl: /* defined in IEC 61131-3 v3 */ - identifier ':' ref_spec_init - {$$ = new ref_type_decl_c($1, $3, locloc(@$)); - library_element_symtable.insert($1, prev_declared_ref_type_name_token); - } +/* PRE_PARSING: The rules expected to be applied by the preparser. */ + identifier ':' ref_spec_init {library_element_symtable.insert($1, prev_declared_ref_type_name_token);} + {if (!get_preparse_state()) ERROR;} +/* STANDARD_PARSING: The rules expected to be applied after the preparser has finished. */ +| prev_declared_ref_type_name ':' ref_spec_init + {$$ = new ref_type_decl_c($1, $3, locloc(@$));} ; @@ -4820,60 +4856,48 @@ derived_function_name: - identifier + identifier /* will never occur during normal parsing, only needed for preparsing to change it to a prev_declared_derived_function_name! */ | prev_declared_derived_function_name {$$ = $1; - if (!allow_function_overloading) { - fprintf(stderr, "Function overloading not allowed. Invalid identifier %s\n", ((token_c *)($1))->value); - ERROR; - } + if (get_preparse_state() && !allow_function_overloading) {print_err_msg(locloc(@$), "Function overloading not allowed. Invalid identifier.\n"); yynerrs++;} } | AND {$$ = new identifier_c("AND", locloc(@$)); - if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"AND\" not allowed. Invalid identifier\n"); + if (!allow_function_overloading) {print_err_msg(locloc(@$), "Function overloading not allowed. Invalid identifier.\n"); yynerrs++;} } | OR {$$ = new identifier_c("OR", locloc(@$)); - if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"OR\" not allowed. Invalid identifier\n"); + if (!allow_function_overloading) {print_err_msg(locloc(@$), "Function overloading not allowed. Invalid identifier.\n"); yynerrs++;} } | XOR {$$ = new identifier_c("XOR", locloc(@$)); - if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"XOR\" not allowed. Invalid identifier\n"); + if (!allow_function_overloading) {print_err_msg(locloc(@$), "Function overloading not allowed. Invalid identifier.\n"); yynerrs++;} } | NOT {$$ = new identifier_c("NOT", locloc(@$)); - if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"NOT\" not allowed. Invalid identifier\n"); + if (!allow_function_overloading) {print_err_msg(locloc(@$), "Function overloading not allowed. Invalid identifier.\n"); yynerrs++;} } | MOD {$$ = new identifier_c("MOD", locloc(@$)); - if (!allow_function_overloading) print_err_msg(locloc(@1), "Function overloading \"MOD\" not allowed. Invalid identifier\n"); + if (!allow_function_overloading) {print_err_msg(locloc(@$), "Function overloading not allowed. Invalid identifier.\n"); yynerrs++;} } ; function_declaration: /* FUNCTION derived_function_name ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ - function_name_declaration ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION +/* PRE_PARSING: The rules expected to be applied by the preparser. */ + FUNCTION derived_function_name END_FUNCTION /* rule that is only expected to be used during preparse state => MUST print an error if used outside preparse() state!! */ + {$$ = NULL; + if (get_preparse_state()) {library_element_symtable.insert($2, prev_declared_derived_function_name_token);} + else {print_err_msg(locl(@1), locf(@3), "FUNCTION with no variable declarations and no body."); yynerrs++;} + } +/* STANDARD_PARSING: The rules expected to be applied after the preparser has finished. */ +| function_name_declaration ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION {$$ = new function_declaration_c($1, $3, $4, $5, locloc(@$)); add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ variable_name_symtable.pop(); direct_variable_symtable.pop(); - if (allow_function_overloading) { - switch (library_element_symtable.find_value($1)) { - case prev_declared_derived_function_name_token: - /* do nothing, already in map. */ - break; - case BOGUS_TOKEN_ID: - /* Not yet in map. Must insert...*/ - library_element_symtable.insert($1, prev_declared_derived_function_name_token); - break; - default: - /* Already in map but associated with something else other than a funtion name! */ - ERROR; - } - } else { - library_element_symtable.insert($1, prev_declared_derived_function_name_token); - } } /* | FUNCTION derived_function_name ':' derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ | function_name_declaration ':' derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION @@ -4881,15 +4905,6 @@ add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ variable_name_symtable.pop(); direct_variable_symtable.pop(); - if (allow_function_overloading) { - switch (library_element_symtable.find_value($1)) { - case prev_declared_derived_function_name_token: /* do nothing, already in map. */ break; - case BOGUS_TOKEN_ID: library_element_symtable.insert($1, prev_declared_derived_function_name_token); break; - default: ERROR; - } - } else { - library_element_symtable.insert($1, prev_declared_derived_function_name_token); - } } /* ERROR_CHECK_BEGIN */ | function_name_declaration elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION @@ -4954,6 +4969,7 @@ * the parser to reduce it, before parsing the function body! */ function_name_declaration: + /* FUNCTION derived_function_name */ FUNCTION derived_function_name {$$ = $2; /* the function name functions as a @@ -5087,10 +5103,16 @@ function_block_declaration: - FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK +/* PRE_PARSING: The rules expected to be applied by the preparser. */ + FUNCTION_BLOCK derived_function_block_name END_FUNCTION_BLOCK /* rule that is only expected to be used during preparse state => MUST print an error if used outside preparse() state!! */ + {$$ = NULL; + if (get_preparse_state()) {library_element_symtable.insert($2, prev_declared_derived_function_block_name_token);} + else {print_err_msg(locl(@1), locf(@3), "FUNCTION_BLOCK with no variable declarations and no body."); yynerrs++;} + } +/* STANDARD_PARSING: The rules expected to be applied after the preparser has finished. */ +| FUNCTION_BLOCK prev_declared_derived_function_block_name io_OR_other_var_declarations_list function_block_body END_FUNCTION_BLOCK {$$ = new function_block_declaration_c($2, $3, $4, locloc(@$)); add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ - library_element_symtable.insert($2, prev_declared_derived_function_block_name_token); /* Clear the variable_name_symtable. Since * we have finished parsing the function block, * the variable names are now out of scope, so @@ -5108,8 +5130,10 @@ {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared in function declaration."); yynerrs++;} | FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list END_FUNCTION_BLOCK {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no body defined in function block declaration."); yynerrs++;} +/* Rule already covered by the rule to handle the preparse state! | FUNCTION_BLOCK derived_function_block_name END_FUNCTION_BLOCK {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared and body defined in function block declaration."); yynerrs++;} +*/ | FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations_list function_block_body END_OF_INPUT {$$ = NULL; print_err_msg(locf(@1), locl(@2), "no variable(s) declared and body defined in function block declaration."); yynerrs++;} | FUNCTION_BLOCK error END_FUNCTION_BLOCK @@ -5240,9 +5264,15 @@ program_declaration: - PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM +/* PRE_PARSING: The rules expected to be applied by the preparser. */ + PROGRAM program_type_name END_PROGRAM /* rule that is only expected to be used during preparse state => MUST print an error if used outside preparse() state!! */ + {$$ = NULL; + if (get_preparse_state()) {library_element_symtable.insert($2, prev_declared_program_type_name_token);} + else {print_err_msg(locl(@1), locf(@3), "PROGRAM with no variable declarations and no body."); yynerrs++;} + } +/* STANDARD_PARSING: The rules expected to be applied after the preparser has finished. */ +| PROGRAM prev_declared_program_type_name program_var_declarations_list function_block_body END_PROGRAM {$$ = new program_declaration_c($2, $3, $4, locloc(@$)); - library_element_symtable.insert($2, prev_declared_program_type_name_token); /* Clear the variable_name_symtable. Since * we have finished parsing the program declaration, * the variable names are now out of scope, so @@ -5256,13 +5286,15 @@ {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no program name defined in program declaration.");} | PROGRAM error program_var_declarations_list function_block_body END_PROGRAM {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid program name in program declaration."); yyerrok;} -| PROGRAM program_type_name function_block_body END_PROGRAM +| PROGRAM prev_declared_program_type_name function_block_body END_PROGRAM {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared in program declaration."); yynerrs++;} -| PROGRAM program_type_name program_var_declarations_list END_PROGRAM +| PROGRAM prev_declared_program_type_name program_var_declarations_list END_PROGRAM {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no body defined in program declaration."); yynerrs++;} -| PROGRAM program_type_name END_PROGRAM +/* Rule already covered by the rule to handle the preparse state! +| PROGRAM prev_declared_program_type_name END_PROGRAM {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no variable(s) declared and body defined in program declaration."); yynerrs++;} -| PROGRAM program_type_name program_var_declarations_list function_block_body END_OF_INPUT +*/ +| PROGRAM prev_declared_program_type_name program_var_declarations_list function_block_body END_OF_INPUT {$$ = NULL; print_err_msg(locf(@1), locl(@2), "unclosed program declaration."); yynerrs++;} | PROGRAM error END_PROGRAM {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in program declaration."); yyerrok;} @@ -5741,10 +5773,11 @@ * If it ever becomes necessary to change this interpretation of * the syntax, then this section of the syntax parser must be updated! */ -prev_declared_global_var_name: prev_declared_global_var_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_resource_name: prev_declared_resource_name_token {$$ = new identifier_c($1, locloc(@$));}; -prev_declared_program_name: prev_declared_program_name_token {$$ = new identifier_c($1, locloc(@$));}; -// prev_declared_task_name: prev_declared_task_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_global_var_name: prev_declared_global_var_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_resource_name: prev_declared_resource_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_program_name: prev_declared_program_name_token {$$ = new identifier_c($1, locloc(@$));}; +prev_declared_configuration_name: prev_declared_configuration_name_token {$$ = new identifier_c($1, locloc(@$));}; +// prev_declared_task_name: prev_declared_task_name_token {$$ = new identifier_c($1, locloc(@$));}; @@ -5768,7 +5801,14 @@ resource_type_name: any_identifier; configuration_declaration: - CONFIGURATION configuration_name +/* PRE_PARSING: The rules expected to be applied by the preparser. */ + CONFIGURATION configuration_name END_CONFIGURATION /* rule that is only expected to be used during preparse state */ + {$$ = NULL; + if (get_preparse_state()) {library_element_symtable.insert($2, prev_declared_configuration_name_token);} + else {print_err_msg(locl(@1), locf(@3), "no resource(s) nor program(s) defined in configuration declaration."); yynerrs++;} + } +/* STANDARD_PARSING: The rules expected to be applied after the preparser has finished. */ +| CONFIGURATION prev_declared_configuration_name global_var_declarations_list single_resource_declaration {variable_name_symtable.pop(); @@ -5777,18 +5817,16 @@ optional_instance_specific_initializations END_CONFIGURATION {$$ = new configuration_declaration_c($2, $3, $4, $6, $7, locloc(@$)); - library_element_symtable.insert($2, prev_declared_configuration_name_token); variable_name_symtable.pop(); direct_variable_symtable.pop(); } -| CONFIGURATION configuration_name +| CONFIGURATION prev_declared_configuration_name global_var_declarations_list resource_declaration_list optional_access_declarations optional_instance_specific_initializations END_CONFIGURATION {$$ = new configuration_declaration_c($2, $3, $4, $5, $6, locloc(@$)); - library_element_symtable.insert($2, prev_declared_configuration_name_token); variable_name_symtable.pop(); direct_variable_symtable.pop(); } @@ -5825,12 +5863,14 @@ optional_instance_specific_initializations END_CONFIGURATION {$$ = NULL; print_err_msg(locf(@2), locl(@2), "invalid configuration name defined in configuration declaration."); yyerrok;} +/* Rule already covered by the rule to handle the preparse state! | CONFIGURATION configuration_name global_var_declarations_list optional_access_declarations optional_instance_specific_initializations END_CONFIGURATION {$$ = NULL; print_err_msg(locl(@3), locf(@4), "no resource(s) defined in configuration declaration."); yynerrs++;} +*/ | CONFIGURATION configuration_name global_var_declarations_list error @@ -8486,28 +8526,13 @@ extern const char *INCLUDE_DIRECTORIES[]; -int stage2__(const char *filename, - symbol_c **tree_root_ref - ) { - char *libfilename = NULL; - - if (runtime_options.includedir != NULL) { - INCLUDE_DIRECTORIES[0] = runtime_options.includedir; - } - - /* first parse the standard library file... */ - /* Do not debug the standard library, even if debug flag is set! */ - /* +static int parse_files(const char *libfilename, const char *filename) { + /* first parse the standard library file... */ + /* Do not debug the standard library, even if debug flag is set! #if YYDEBUG yydebug = 1; #endif */ - - if ((libfilename = strdup3(INCLUDE_DIRECTORIES[0], "/", LIBFILE)) == NULL) { - fprintf (stderr, "Out of memory. Bailing out!\n"); - return -1; - } - FILE *libfile = NULL; if((libfile = parse_file(libfilename)) == NULL) { char *errmsg = strdup2("Error opening library file ", libfilename); @@ -8524,19 +8549,16 @@ allow_ref_dereferencing = runtime_options.ref_standard_extensions; allow_ref_to_any = runtime_options.ref_nonstand_extensions; allow_ref_to_in_derived_datatypes = runtime_options.ref_nonstand_extensions; - if (yyparse() != 0) - ERROR; + if (yyparse() != 0) ERROR; fclose(libfile); - if (yynerrs > 0) { - fprintf (stderr, "\n%d error(s) found in %s. Bailing out!\n", yynerrs /* global variable */, libfilename); - ERROR; + if (yynerrs > 0) { /* NOTE: yynerrs is a global variable */ + /* Hopefully the libraries do not contain any errors, so this should not occur! */ + fprintf (stderr, "\n%d error(s) found in %s. Bailing out!\n", yynerrs, libfilename); + return -2; } - free(libfilename); - - /* if by any chance the library is not complete, we - * now add the missing reserved keywords to the list!!! - */ + + /* if by any chance the library is not complete, we now add the missing reserved keywords to the list!!! */ for(int i = 0; standard_function_block_names[i] != NULL; i++) if (library_element_symtable.find_value(standard_function_block_names[i]) == library_element_symtable.end_value()) @@ -8551,7 +8573,7 @@ char *errmsg = strdup2("Error opening main file ", filename); perror(errmsg); free(errmsg); - return -1; + return -3; } allow_function_overloading = false; @@ -8573,7 +8595,79 @@ fprintf (stderr, "\n%d error(s) found. Bailing out!\n", yynerrs /* global variable */); exit(EXIT_FAILURE); } + + return 0; +} + + + + + +/* We parse the input source code twice!! + * 1st pass --> Pre-parsing + * ------------------------- + * The intention of the first pass is to fill up the library_element_symtable with the names of all + * the POUs (Functions, FBs, Programs and Configurations), as well as all the Derived Datatypes. + * + * During this pass POUs are only parsed until their name is obtained, and the remaining source + * code (variable declarations and body) is completely thrown away by flex. Datatype declarations + * however are parsed normally! + * + * At the end of the pre-parsing, the AST will contain only the derived datatype declarations, + * and this tree will be trown away (by simply resetting tree_root = NULL). + * More importantly, the library_element_symtable will contain the names of all the POUs and + * derived datatypes. + * + * 2st pass --> Normal parsing + * ---------------------------- + * In this second parse the whole source code is parsed correctly, and the AST is generated + * completely. + * + * However, if the pre-parsing has been done before this normal parsing, the POUs may appear + * in the source code in any order, as calling a POU (e.g. calling a function) that has not yet + * been declared will no longer generate a parsing error because the name of the function being + * called is already in the library_element_symtable. + * + * Declaring variables of datatypes that have not yet been declared will also be possible, as the + * datatypes will also already be in the library_element_symtable! + */ + +int stage2__(const char *filename, + symbol_c **tree_root_ref + ) { + char *libfilename = NULL; + + /* Determine the full path name of the standard library file... */ + if (runtime_options.includedir != NULL) + INCLUDE_DIRECTORIES[0] = runtime_options.includedir; + + if ((libfilename = strdup3(INCLUDE_DIRECTORIES[0], "/", LIBFILE)) == NULL) { + fprintf (stderr, "Out of memory. Bailing out!\n"); + exit(EXIT_FAILURE); + } + + /*******************************/ + /* Do the PRE parsing run...! */ + /*******************************/ + // fprintf (stderr, "----> Starting pre-parsing!\n"); + tree_root = NULL; + set_preparse_state(); + if (parse_files(libfilename, filename) < 0) + exit(EXIT_FAILURE); + // TODO: delete the current AST. For the moment, we leave all the objects in memory (not much of an issue in a program that always runs to completion). + + /*******************************/ + /* Do the main parsing run...! */ + /*******************************/ + // fprintf (stderr, "----> Starting normal parsing!\n"); + tree_root = NULL; + rst_preparse_state(); + if (parse_files(libfilename, filename) < 0) + exit(EXIT_FAILURE); + + /* Final clean-up... */ + free(libfilename); if (tree_root_ref != NULL) *tree_root_ref = tree_root; diff -r f53ea4c8621c -r e984cfdf3b10 stage1_2/iec_flex.ll --- a/stage1_2/iec_flex.ll Sat Nov 29 12:10:34 2014 +0000 +++ b/stage1_2/iec_flex.ll Sat Nov 29 13:43:20 2014 +0000 @@ -347,8 +347,31 @@ * Unfortunately, flex will join '_' and '4h' to create a legal {identifier} '_4h', * and return that identifier instead! So, we added this state! * - * There is a main state machine... + * The ignore_pou_state state is only used when bison says it is doing the pre-parsing. + * During pre-parsing, the main state machine will only transition between + * INITIAL and ignore_pou_state, and from here back to INITIAL. All other + * transitions are inhibited. This inhibition is actually just enforced by making + * sure that the INITIAL ---> ignore_pou_state transition is tested before all other + * transitions coming out of INITIAL state. All other transitions are unaffected, as they + * never get a chance to be evaluated when bison is doing pre-parsing. + * Pre-parsing is a first quick scan through the whole input source code simply + * to determine the list of POUs and datatypes that will be defined in that + * code. Basically, the objective is to fill up the previously_declared_xxxxx + * maps, without processing the code itself. Once these maps have been filled up, + * bison will throw away the AST (abstract syntax tree) created up to that point, + * and scan through the same source code again, but this time creating a correct AST. + * This pre-scan allows the source code to reference POUs and datatypes that are + * only declared after they are used! * + * + * Here is a main state machine... + * --+ + * | these states are + * +------------> get_pou_name_state ----> ignore_pou_state | only active + * | | | when bison is + * | ------------------------------------------+ | doing the + * | | | pre-parsing!! + * | v --+ * +---> INITIAL <-------> config * | \ * | V @@ -379,11 +402,17 @@ * * * Possible state changes are: + * INITIAL -> goto(ignore_pou_state) + * (This transition state is only used when bison says it is doing the pre-parsing.) + * (This transition takes precedence over all other transitions!) + * (when a FUNCTION, FUNCTION_BLOCK, PROGRAM or CONFIGURATION is found) + * * INITIAL -> goto(config_state) * (when a CONFIGURATION is found) * * INITIAL -> goto(header_state) * (when a FUNCTION, FUNCTION_BLOCK, or PROGRAM is found) + * * header_state -> goto(vardecl_list_state) * (When the first VAR token is found, i.e. at begining of first VAR .. END_VAR declaration) * @@ -410,10 +439,12 @@ * sfc_state -> pop() to vardecl_list_state * (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found) * + * ignore_pou_state -> goto(INITIAL) + * (when a END_FUNCTION, END_FUNCTION_BLOCK, END_PROGRAM or END_CONFIGURATION is found) * vardecl_list_state -> goto(INITIAL) - * (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found) - * config_state -> goto(INITIAL) - * (when a END_CONFIGURATION is found) + * (when a END_FUNCTION, END_FUNCTION_BLOCK, or END_PROGRAM is found) + * config_state -> goto(INITIAL) + * (when a END_CONFIGURATION is found) * * * sfc_state -> push current state(sfc_state); goto(body_state) @@ -434,6 +465,10 @@ */ +/* Bison is in the pre-parsing stage, and we are parsing a POU. Ignore everything up to the end of the POU! */ +%x ignore_pou_state +%x get_pou_name_state + /* we are parsing a configuration. */ %s config_state @@ -1052,10 +1087,24 @@ * continue in the state, untill the end of the FUNCTION, FUNCTION_BLOCK * or PROGAM. */ -FUNCTION BEGIN(header_state); return FUNCTION; -FUNCTION_BLOCK BEGIN(header_state); return FUNCTION_BLOCK; -PROGRAM BEGIN(header_state); return PROGRAM; -CONFIGURATION BEGIN(config_state); return CONFIGURATION; + +FUNCTION{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return FUNCTION; +FUNCTION_BLOCK{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return FUNCTION_BLOCK; +PROGRAM{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(header_state); return PROGRAM; +CONFIGURATION{st_whitespace} if (get_preparse_state()) BEGIN(get_pou_name_state); else BEGIN(config_state); return CONFIGURATION; +} + +{ +{identifier} BEGIN(ignore_pou_state); yylval.ID=strdup(yytext); return identifier_token; +. BEGIN(ignore_pou_state); unput_text(0); +} + +{ +END_FUNCTION unput_text(0); BEGIN(INITIAL); +END_FUNCTION_BLOCK unput_text(0); BEGIN(INITIAL); +END_PROGRAM unput_text(0); BEGIN(INITIAL); +END_CONFIGURATION unput_text(0); BEGIN(INITIAL); +.|\n {}/* Ignore text inside POU! (including the '\n' character!)) */ } /* INITIAL -> body_state */ @@ -1180,7 +1229,7 @@ {il_whitespace} /* Eat any whitespace */ /* The comments */ -{comment_beg} yy_push_state(comment_state); +{comment_beg} yy_push_state(comment_state); {comment_beg} yy_push_state(comment_state); { {comment_beg} {if (get_opt_nested_comments()) yy_push_state(comment_state);} diff -r f53ea4c8621c -r e984cfdf3b10 stage1_2/stage1_2.cc --- a/stage1_2/stage1_2.cc Sat Nov 29 12:10:34 2014 +0000 +++ b/stage1_2/stage1_2.cc Sat Nov 29 13:43:20 2014 +0000 @@ -73,6 +73,15 @@ bool get_opt_ref_standard_extensions() {return runtime_options.ref_standard_extensions;} +/**********************************************************************************************/ +/* whether bison is doing the pre-parsing, where POU bodies and var declarations are ignored! */ +/**********************************************************************************************/ +static bool preparse_state__ = false; + +void set_preparse_state(void) {preparse_state__ = true; } +void rst_preparse_state(void) {preparse_state__ = false;} +bool get_preparse_state(void) {return preparse_state__;} // returns true if bison is in preparse state + /****************************************************/ /* Controlling the entry to the body_state in flex. */ diff -r f53ea4c8621c -r e984cfdf3b10 stage1_2/stage1_2_priv.hh --- a/stage1_2/stage1_2_priv.hh Sat Nov 29 12:10:34 2014 +0000 +++ b/stage1_2/stage1_2_priv.hh Sat Nov 29 13:43:20 2014 +0000 @@ -142,6 +142,12 @@ FILE *parse_file(const char *filename); +/**********************************************************************************************/ +/* whether bison is doing the pre-parsing, where POU bodies and var declarations are ignored! */ +/**********************************************************************************************/ +void set_preparse_state(void); +void rst_preparse_state(void); +bool get_preparse_state(); // returns true if bison is in preparse state /****************************************************/ /* Controlling the entry to the body_state in flex. */ diff -r f53ea4c8621c -r e984cfdf3b10 util/symtable.cc --- a/util/symtable.cc Sat Nov 29 12:10:34 2014 +0000 +++ b/util/symtable.cc Sat Nov 29 13:43:20 2014 +0000 @@ -116,12 +116,13 @@ } // std::cout << "store_identifier(" << identifier_str << "): \n"; + iterator i = _base.find(identifier_str); + if ((i != _base.end()) && (i->second != new_value)) {ERROR;} /* error inserting new identifier: identifier already in map associated to a different value */ + if ((i != _base.end()) && (i->second == new_value)) {return;} /* identifier already in map associated with the same value */ + std::pair new_element(identifier_str, new_value); std::pair res = _base.insert(new_element); - if (!res.second) - /* error inserting new identifier... */ - /* identifier already in map? */ - ERROR; + if (!res.second) {ERROR;} /* unknown error inserting new identifier */ } template