stage1_2/iec_bison.yy
changeset 1021 21a97cdb317d
parent 1019 1e3cefbbdee2
child 1031 ce026aee03e0
--- a/stage1_2/iec_bison.yy	Fri May 06 11:48:02 2016 +0300
+++ b/stage1_2/iec_bison.yy	Tue Jun 28 16:35:47 2016 +0300
@@ -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  <leaf>	prev_declared_derived_function_block_name
 %type  <leaf>	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<poutype_identifier_c*>($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<poutype_identifier_c*>($1)) ERROR;} // $1 should be a poutype_identifier_c
+| function_name_no_NOT_clashes '(' ')'
+	{if (NULL == dynamic_cast<poutype_identifier_c*>($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;