Add a pre-parsing phase to stage1_2 (allows source code that references POUs and datatypes before they are declared)
authormjsousa
Sat, 29 Nov 2014 13:43:20 +0000
changeset 952 e984cfdf3b10
parent 951 f53ea4c8621c
child 953 66697c05a147
Add a pre-parsing phase to stage1_2 (allows source code that references POUs and datatypes before they are declared)
stage1_2/iec_bison.yy
stage1_2/iec_flex.ll
stage1_2/stage1_2.cc
stage1_2/stage1_2_priv.hh
util/symtable.cc
--- 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  <leaf>	prev_declared_resource_name
 %token  <ID>	prev_declared_resource_name_token
 
+%type  <leaf>	prev_declared_configuration_name
 %token  <ID>	prev_declared_configuration_name_token
 
 // %type  <leaf>	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;
 
--- 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 <vardecl_state> 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;
+}
+
+<get_pou_name_state>{
+{identifier}			BEGIN(ignore_pou_state); yylval.ID=strdup(yytext); return identifier_token;
+.				BEGIN(ignore_pou_state); unput_text(0);
+}
+
+<ignore_pou_state>{
+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_state>{il_whitespace}		/* Eat any whitespace */
 
 	/* The comments */
-<body_state,vardecl_list_state>{comment_beg}		yy_push_state(comment_state);
+<get_pou_name_state,ignore_pou_state,body_state,vardecl_list_state>{comment_beg}		yy_push_state(comment_state);
 {comment_beg}						yy_push_state(comment_state);
 <comment_state>{
 {comment_beg}						{if (get_opt_nested_comments()) yy_push_state(comment_state);}
--- 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. */
--- 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. */
--- 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<const char *, value_t> new_element(identifier_str, new_value);
   std::pair<iterator, bool> 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<typename value_type, value_type null_value>