diff -r 59435d4c5e0c -r 0d4d3a502d82 stage1_2/iec_bison.yy --- a/stage1_2/iec_bison.yy Fri May 06 11:48:02 2016 +0300 +++ b/stage1_2/iec_bison.yy Thu Sep 08 17:44:44 2016 +0100 @@ -198,12 +198,6 @@ */ extern bool allow_extensible_function_parameters; -/* A global flag used to tell the parser whether to include the full variable location when printing out error messages... */ -extern bool full_token_loc; - -/* A global flag used to tell the parser whether to generate conversion function for enumerated data types. */ -extern bool conversion_functions; - /* A global flag used to tell the parser whether to allow use of DREF and '^' operators (defined in IEC 61131-3 v3) */ extern bool allow_ref_dereferencing; @@ -379,6 +373,32 @@ %type prev_declared_derived_function_block_name %type prev_declared_program_type_name +/* Tokens used to help resolve a reduce/reduce conflict */ +/* The mentioned conflict only arises due to a non-standard feature added to matiec. + * Namely, the permission to call functions returning VOID as an ST statement. + * e.g.: FUNCTION foo: VOID + * VAR_INPUT i: INT; END_VAR; + * ... + * END_FUNCTION + * + * FUNCTION BAR: BOOL + * VAR b: bool; END_VAR + * foo(i:=42); <--- Calling foo outside an expression. Function invocation is considered an ST statement!! + * END_FUNCTION + * + * The above function invocation may also be reduced to a formal IL function invocation, so we get a + * reduce/reduce conflict to st_statement_list/instruction_list (or something equivalent). + * + * We solve this by having flex determine if it is ST or IL invocation (ST ends with a ';' !!). + * At the start of a function/FB/program body, flex will tell bison whether to expect ST or IL code! + * This is why we need the following two tokens! + * + * NOTE: flex was already determing whther it was parsing ST or IL code as it can only send + * EOL tokens when parsing IL. However, did this silently without telling bison about this. + * Now, it does + */ +%token start_ST_body_token +%token start_IL_body_token @@ -656,6 +676,9 @@ %token TIME_OF_DAY %token TOD +/* A non-standard extension! */ +%token VOID + /******************************************************/ /* Symbols defined in */ /* "Safety Software Technical Specification, */ @@ -2573,7 +2596,7 @@ data_type_declaration: TYPE type_declaration_list END_TYPE - {$$ = new data_type_declaration_c($2, locloc(@$)); if (conversion_functions) include_string((create_enumtype_conversion_functions_c::get_declaration($$)).c_str());} + {$$ = new data_type_declaration_c($2, locloc(@$)); if (runtime_options.conversion_functions) include_string((create_enumtype_conversion_functions_c::get_declaration($$)).c_str());} /* ERROR_CHECK_BEGIN */ | TYPE END_TYPE {$$ = NULL; print_err_msg(locl(@1), locf(@2), "no data type declared in data type(s) declaration."); yynerrs++;} @@ -5001,7 +5024,7 @@ /* POST_PARSING and 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 */ + if (!runtime_options.disable_implicit_en_eno) 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(); library_element_symtable.insert($1, prev_declared_derived_function_name_token); @@ -5009,7 +5032,15 @@ /* | 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 {$$ = 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 */ + if (!runtime_options.disable_implicit_en_eno) 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(); + library_element_symtable.insert($1, prev_declared_derived_function_name_token); + } +/* | FUNCTION derived_function_name ':' VOID io_OR_function_var_declarations_list function_body END_FUNCTION */ +| function_name_declaration ':' VOID io_OR_function_var_declarations_list function_body END_FUNCTION + {$$ = new function_declaration_c($1, new void_type_name_c(locloc(@3)), $4, $5, locloc(@$)); + if (!runtime_options.disable_implicit_en_eno) 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(); library_element_symtable.insert($1, prev_declared_derived_function_name_token); @@ -5178,8 +5209,8 @@ function_body: - statement_list {$$ = $1;} /* if we leave it for the default action we get a type clash! */ -| instruction_list {$$ = $1;} /* if we leave it for the default action we get a type clash! */ + start_ST_body_token statement_list {$$ = $2;} +| start_IL_body_token instruction_list {$$ = $2;} /* | ladder_diagram | function_block_diagram @@ -5220,7 +5251,7 @@ /* POST_PARSING: The rules expected to be applied after the preparser runs. Will only run if pre-parsing command line option is ON. */ | 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 */ + if (!runtime_options.disable_implicit_en_eno) add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ /* Clear the variable_name_symtable. Since we have finished parsing the function block, * the variable names are now out of scope, so are no longer valid! */ @@ -5231,7 +5262,7 @@ | FUNCTION_BLOCK 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(@$)); library_element_symtable.insert($2, prev_declared_derived_function_block_name_token); - add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ + if (!runtime_options.disable_implicit_en_eno) add_en_eno_param_decl_c::add_to($$); /* add EN and ENO declarations, if not already there */ /* Clear the variable_name_symtable. Since we have finished parsing the function block, * the variable names are now out of scope, so are no longer valid! */ @@ -5252,7 +5283,7 @@ {$$ = 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++;} + {$$ = NULL; print_err_msg(locf(@1), locl(@2), "expecting END_FUNCTION_BLOCK before end of file."); yynerrs++;} | FUNCTION_BLOCK error END_FUNCTION_BLOCK {$$ = NULL; print_err_msg(locf(@2), locl(@2), "unknown error in function block declaration."); yyerrok;} /* ERROR_CHECK_END */ @@ -5361,9 +5392,21 @@ function_block_body: - statement_list {$$ = $1;} -| instruction_list {$$ = $1;} -| sequential_function_chart {$$ = $1;} + /* NOTE: start_ST_body_token is a dummy token generated by flex when it determines it is starting to parse a POU body in ST + * start_IL_body_token is a dummy token generated by flex when it determines it is starting to parse a POU body in IL + * These tokens help remove a reduce/reduce conflict in bison, between a formal function invocation in IL, and a + * function invocation used as a statement (a non-standard extension added to matiec) + * e.g: FUNCTION_BLOCK foo + * VAR ... END_VAR + * func_returning_void(in1 := 3 + * ); --> only the presence or absence of ';' will determine whether this is a IL or ST + * function invocation. (In standard ST this would be ilegal, in matiec we allow it + * when activated by a command line option) + * END_FUNCTION + */ + start_ST_body_token statement_list {$$ = $2;} +| start_IL_body_token instruction_list {$$ = $2;} +| sequential_function_chart {$$ = $1;} /* | ladder_diagram | function_block_diagram @@ -7812,11 +7855,16 @@ {$$ = new function_invocation_c($1, $3, NULL, locloc(@$)); if (NULL == dynamic_cast($1)) ERROR;} // $1 should be a poutype_identifier_c | function_name_no_NOT_clashes '(' param_assignment_nonformal_list ')' {$$ = new function_invocation_c($1, NULL, $3, locloc(@$)); if (NULL == dynamic_cast($1)) ERROR;} // $1 should be a poutype_identifier_c +| function_name_no_NOT_clashes '(' ')' + {if (NULL == dynamic_cast($1)) ERROR; // $1 should be a poutype_identifier_c + if (runtime_options.allow_missing_var_in) + {$$ = new function_invocation_c($1, NULL, NULL, locloc(@$));} + else + {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no parameter defined in function invocation of ST expression."); yynerrs++;} + } /* ERROR_CHECK_BEGIN */ | function_name_no_NOT_clashes param_assignment_formal_list ')' {$$ = NULL; print_err_msg(locl(@1), locf(@2), "'(' missing after function name in ST expression."); yynerrs++;} -| function_name_no_NOT_clashes '(' ')' - {$$ = NULL; print_err_msg(locl(@2), locf(@3), "no parameter defined in function invocation of ST expression."); yynerrs++;} | function_name_no_NOT_clashes '(' error ')' {$$ = NULL; print_err_msg(locf(@3), locl(@3), "invalid parameter(s) defined in function invocation of ST expression."); yyerrok;} | function_name_no_NOT_clashes '(' param_assignment_formal_list error @@ -7857,6 +7905,15 @@ | subprogram_control_statement | selection_statement | iteration_statement +| function_invocation + { /* This is a non-standard extension (calling a function outside an ST expression!) */ + /* Only allow this if command line option has been selected... */ + $$ = $1; + if (!runtime_options.allow_void_datatype) { + print_err_msg(locf(@1), locl(@1), "Function invocation in ST code is not allowed outside an expression. To allow this non-standard syntax, activate the apropriate command line option."); + yynerrs++; + } + } ; @@ -8443,10 +8500,6 @@ */ bool allow_extensible_function_parameters = false; -/* A global flag indicating whether to include the full variable location when printing out error messages... */ -bool full_token_loc; -/* A global flag used to tell the parser whether to generate conversion function for enumerated data types. */ -bool conversion_functions = false; /* A global flag used to tell the parser whether to allow use of DREF and '^' operators (defined in IEC 61131-3 v3) */ bool allow_ref_dereferencing; /* A global flag used to tell the parser whether to allow use of REF_TO ANY datatypes (non-standard extension) */ @@ -8522,7 +8575,7 @@ if (first_filename == NULL) first_filename = unknown_file; if ( last_filename == NULL) last_filename = unknown_file; - if (full_token_loc) { + if (runtime_options.full_token_loc) { if (first_filename == last_filename) fprintf(stderr, "%s:%d-%d..%d-%d: error: %s\n", first_filename, first_line, first_column, last_line, last_column, additional_error_msg); else @@ -8708,8 +8761,6 @@ allow_function_overloading = true; allow_extensible_function_parameters = true; - full_token_loc = runtime_options.full_token_loc; - conversion_functions = runtime_options.conversion_functions; 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; @@ -8745,8 +8796,6 @@ allow_function_overloading = false; allow_extensible_function_parameters = false; - full_token_loc = runtime_options.full_token_loc; - conversion_functions = runtime_options.conversion_functions; 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;