Add support for REF_TO inside arrays and structs (a non-standard feature!)
authormjsousa
Sat, 27 Sep 2014 20:09:19 +0100
changeset 932 061824c45a5b
parent 931 c0c245197b5a
child 933 76324f461aed
Add support for REF_TO inside arrays and structs (a non-standard feature!)
lib/C/iec_types_all.h
main.cc
stage1_2/iec_bison.yy
stage4/generate_c/generate_c_typedecl.cc
--- a/lib/C/iec_types_all.h	Mon Aug 11 08:07:12 2014 +0100
+++ b/lib/C/iec_types_all.h	Sat Sep 27 20:09:19 2014 +0100
@@ -124,7 +124,7 @@
 __DECLARE_COMPLEX_STRUCT(type)
 
 #define __DECLARE_REFTO_TYPE(type, name)\
-typedef name * type;\
+typedef name type;\
 __DECLARE_COMPLEX_STRUCT(type)
 
 
--- a/main.cc	Mon Aug 11 08:07:12 2014 +0100
+++ b/main.cc	Sat Sep 27 20:09:19 2014 +0100
@@ -123,7 +123,8 @@
   printf(" -s : allow use of safe datatypes (SAFEBOOL, etc.)   (defined in PLCOpen Safety)\n");
   printf(" -n : allow use of nested comments                   (an IEC 61131-3 v3 feature)\n");
   printf(" -r : allow use of references (REF_TO, REF, NULL)    (an IEC 61131-3 v3 feature)\n");
-  printf(" -R : allow use of REF_TO ANY datatypes (implies -r) (a non-standard extension!)\n");
+  printf(" -R : allow use of REF_TO ANY datatypes              (a non-standard extension!)\n");
+  printf("        as well as REF_TO in ARRAYs and STRUCTs      (a non-standard extension!)\n");
   printf(" -c : create conversion functions for enumerated data types\n");
   printf(" -O : options for output (code generation) stage. Available options for %s are...\n", cmd);
   stage4_print_options();
--- a/stage1_2/iec_bison.yy	Mon Aug 11 08:07:12 2014 +0100
+++ b/stage1_2/iec_bison.yy	Sat Sep 27 20:09:19 2014 +0100
@@ -198,22 +198,19 @@
  */
 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...
- */
+/* 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.
- */
+/* 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 REF_TO ANY datatypes (non-standard extension) */
 extern bool allow_ref_to_any;
 
-/* A pointer to the root of the parsing tree that will be generated 
- * by bison.
- */
+/* A global flag used to tell the parser whether to allow use of REF_TO as a struct or array element (non-standard extension) */
+extern bool allow_ref_to_in_derived_datatypes;
+
+/* A pointer to the root of the parsing tree that will be generated  by bison. */
 extern symbol_c *tree_root;
 
 
@@ -785,9 +782,10 @@
 %token END_STRUCT
 
 
-%type  <leaf>	ref_spec      /* defined in IEC 61131-3 v3 */
-%type  <leaf>	ref_spec_init /* defined in IEC 61131-3 v3 */
-%type  <leaf>	ref_type_decl /* defined in IEC 61131-3 v3 */
+%type  <leaf>	ref_spec                 /* defined in IEC 61131-3 v3 */
+%type  <leaf>	ref_spec_non_recursive   /* helper symbol */
+%type  <leaf>	ref_spec_init            /* defined in IEC 61131-3 v3 */
+%type  <leaf>	ref_type_decl            /* defined in IEC 61131-3 v3 */
 
 
 
@@ -2878,6 +2876,23 @@
   prev_declared_array_type_name
 | ARRAY '[' array_subrange_list ']' OF non_generic_type_name
 	{$$ = new array_specification_c($3, $6, locloc(@$));}
+| ARRAY '[' array_subrange_list ']' OF ref_spec_non_recursive
+	/* non standard extension: Allow use of arrays storing REF_TO datatypes that are declared as 'ARRAY [1..3] OF REF_TO INT' */
+	/*                                                                                                            ^^^^^^      */
+	/* NOTE: We use ref_spec and not ref_spec_init as for the moment I do not want to allow direct specification of initial value.
+	 *       I (MJS) am not too sure whether this is currently supported in code generation, so leave it out for now.
+	 *       It also does not seem to be a very good idea to allow initial value specification when declaring the array,
+	 *       since the standard syntax does not allow it either for any other datatype!
+	 * NOTE: We use ref_spec_non_recursive instead of ref_spec in order to remove a reduce/reduce conflict.
+	 *       Note that non_generic_type_name that is used in the previous rule already include the prev_declared_ref_type_name.
+	 *       which leads to the reduce/reduce conflict, as it is also included in ref_spec.
+	 */
+	{$$ = new array_specification_c($3, $6, locloc(@$));
+	 if (!allow_ref_to_in_derived_datatypes) {
+	   print_err_msg(locf(@$), locl(@$), "REF_TO may not be used in an ARRAY specification (use -R option to activate support for this non-standard syntax)."); 
+	   yynerrs++;
+	 }
+	}
 /* ERROR_CHECK_BEGIN */
 | ARRAY array_subrange_list ']' OF non_generic_type_name
 	{$$ = NULL; print_err_msg(locl(@1), locf(@2), "'[' missing before subrange list in array specification."); yynerrs++;}
@@ -3065,6 +3080,13 @@
 	{$$ = new structure_element_declaration_c($1, $3, locloc(@$));}
 | structure_element_name ':' initialized_structure
 	{$$ = new structure_element_declaration_c($1, $3, locloc(@$));}
+| structure_element_name ':' ref_spec_init                              /* non standard extension: Allow use of struct elements storing REF_TO datatypes (either using REF_TO or a previosuly declared ref type) */
+	{ $$ = new structure_element_declaration_c($1, $3, locloc(@$));
+	  if (!allow_ref_to_in_derived_datatypes) {
+	    print_err_msg(locf(@$), locl(@$), "REF_TO and reference datatypes may not be used in a STRUCT element (use -R option to activate support for this non-standard syntax)."); 
+	    yynerrs++;
+	  }
+	}
 /* ERROR_CHECK_BEGIN */
 | structure_element_name simple_spec_init
 	{$$ = NULL; print_err_msg(locl(@1), locf(@2), "':' missing between structure element name and simple specification."); yynerrs++;}
@@ -3220,7 +3242,7 @@
  *       We have therefore explicitly added the "REF_TO function_block_type_name" to this rule!
  * NOTE: the REF_TO ANY is a non-standard extension to the standard. This is basically equivalent to a (void *)
  */
-ref_spec: /* defined in IEC 61131-3 v3 */
+ref_spec_non_recursive: /* helper symbol, used to remove a reduce/reduce conflict in a non-standard syntax I (Mario) have added!! */
   REF_TO non_generic_type_name
 	{$$ = new ref_spec_c($2, locloc(@$));}
 | REF_TO function_block_type_name
@@ -3232,20 +3254,51 @@
 	   yynerrs++;
 	 }
 	}
-/* The following line is actually not included in IEC 61131-3, but we add it anyway otherwise it will not be possible to
- * define a REF_TO datatype as an alias to an already previously declared REF_TO datatype.
+;
+
+ref_spec: /* defined in IEC 61131-3 v3 */
+  ref_spec_non_recursive
+| prev_declared_ref_type_name 
+;
+
+
+/* The IEC 61131-3 v3 standard actually only defines the following syntax:
+ * 
+ *  Ref_Type_Decl: Ref_Type_Name ':' Ref_Spec_Init;
+ *  Ref_Spec_Init: Ref_Spec ( ':=' Ref_Value )?;
+ *  Ref_Spec     : 'REF_TO' + Data_Type_Access;
+ *
+ * Note that the above syntax it is not possible to define a REF_TO datatype as 
+ * an alias to an already previously declared REF_TO datatype.
+ *
+ * I (Mario) believe that this is probably a bug in the IEC 61131-3 syntax, and I have therefore
+ * changed that standard definition to...
+ *
+ *  Ref_Type_Decl: Ref_Type_Name ':' Ref_Spec_Init;
+ *  Ref_Spec_Init: Ref_Spec ( ':=' Ref_Value )?;
+ *  Ref_Spec     : ('REF_TO' + Data_Type_Access) | Ref_Type_Name;
+ *  
  * For example:
  *       TYPE
- *          ref1: REF_TO INT;
- *          ref2: ref1;    <-- without the following rule, this would not be allowed!!
+ *          ref1_t: REF_TO INT;
+ *          ref2_t: ref1_t;    <-- without the above changes, this would not be allowed!!
  *       END_TYPE
  *
- * This extra rule also makes it possible to declare variables using a previously declared REF_TO datatype
+ * This change also makes it possible to declare variables using a previously declared REF_TO datatype
  *  For example:
- *     VAR  refvar: ref1; END_VAR
- */
-| prev_declared_ref_type_name 
-;
+ *     VAR  refvar: ref1_t; END_VAR
+ *
+ * This change also makes it possible to declare arrays containing a previously declared ref type.
+ *  For example:
+ *     VAR  refvar: ARRAY [1..3] OF ref1_t;     END_VAR   <--- becomes OK
+ *     VAR  refvar: ARRAY [1..3] OF REF_TO INT; END_VAR   <--- still not OK. (Only becomes OK with other non-standard rules in another location of this file!)
+ *
+ * Interestingly, this change does NOT make it possible to declare structure elements of a previously declared ref type.
+ *  For example:
+ *     TYPE struct_t: STRUCT elem1: ref1_t;     END_STRUCT; END_TYPE;    <--- still not OK. (Only becomes OK with other non-standard rules in another location of this file!)
+ *     TYPE struct_t: STRUCT elem1: REF_TO INT; END_STRUCT; END_TYPE;    <--- still not OK. (Only becomes OK with other non-standard rules in another location of this file!)
+ */
+
 
 
 ref_spec_init: /* defined in IEC 61131-3 v3 */
@@ -3267,6 +3320,9 @@
 
 
 
+
+
+
 /*********************/
 /* B 1.4 - Variables */
 /*********************/
@@ -8159,17 +8215,14 @@
  */
 bool allow_extensible_function_parameters = false;
 
-/* A global flag used to tell the parser whether to include the full variable location
- * when printing out error messages...
- */
+/* 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 allow use of REF_TO ANY datatypes (non-standard extension) */
 bool allow_ref_to_any = false;
-
-/* A pointer to the root of the parsing tree that will be generated 
- * by bison.
- */
+/* A global flag used to tell the parser whether to allow use of REF_TO as a struct or array element (non-standard extension) */
+bool allow_ref_to_in_derived_datatypes = false;
+
+/* A pointer to the root of the parsing tree that will be generated by bison. */
 symbol_c *tree_root;
 
 
@@ -8392,10 +8445,10 @@
 
 
 int stage2__(const char *filename, 
-             const char *includedir,     /* Include directory, where included files will be searched for... */
+             const char *includedir,   /* Include directory, where included files will be searched for... */
              symbol_c **tree_root_ref,
-             bool full_token_loc_,       /* error messages specify full token location */
-             bool ref_to_any_            /* allow use of non-standard REF_TO ANY datatypes */
+             bool full_token_loc_,                     /* error messages specify full token location */
+             bool allow_ref_to_nonstandard_extensions_ /* allow use of non-standard REF_TO ANY datatypes, and REF_TO inside structs and arrays */
             ) {
   char *libfilename = NULL;
 
@@ -8427,8 +8480,9 @@
 
   allow_function_overloading           = true;
   allow_extensible_function_parameters = true;
-  full_token_loc   = full_token_loc_;
-  allow_ref_to_any = ref_to_any_;
+  full_token_loc                       = full_token_loc_;
+  allow_ref_to_any                     = allow_ref_to_nonstandard_extensions_;
+  allow_ref_to_in_derived_datatypes    = allow_ref_to_nonstandard_extensions_;
   if (yyparse() != 0)
       ERROR;
   fclose(libfile);
@@ -8461,8 +8515,9 @@
 
   allow_function_overloading           = false;
   allow_extensible_function_parameters = false;
-  full_token_loc   = full_token_loc_;
-  allow_ref_to_any = ref_to_any_;
+  full_token_loc                       = full_token_loc_;
+  allow_ref_to_any                     = allow_ref_to_nonstandard_extensions_;
+  allow_ref_to_in_derived_datatypes    = allow_ref_to_nonstandard_extensions_;  
   //allow_ref_to_any = false;    /* we only allow REF_TO ANY in library functions/FBs, no matter what the user asks for in the command line */
 
   if (yyparse() != 0) {
--- a/stage4/generate_c/generate_c_typedecl.cc	Mon Aug 11 08:07:12 2014 +0100
+++ b/stage4/generate_c/generate_c_typedecl.cc	Sat Sep 27 20:09:19 2014 +0100
@@ -641,7 +641,9 @@
   /* This is NOT part of an implicitly declared datatype (i.e. we are being called from an visit(ref_type_decl_c *),
    * through the visit(ref_spec_init_c*)), so we need to simply print out the name of the datatype we reference to.
    */
-  return symbol->type_name->accept(*this);
+  symbol->type_name->accept(*this);
+  s4o_incl.print("*");
+  return NULL;
 }
 
 /* For the moment, we do not support initialising reference data types */