Fix bug: Add support for de-referencing pointers to struct (struct_ptr^.elem1) when used inside FB.
Note that multiple de-referencing of structs (struct_ptr_ptr^^.elem) is not supported inside FB code (this would need BIG changes to the compiler!)
--- a/absyntax/absyntax.cc Sun Sep 28 17:48:42 2014 +0100
+++ b/absyntax/absyntax.cc Sun Oct 19 08:36:49 2014 +0100
@@ -56,6 +56,7 @@
this->last_line = last_line;
this->last_column = last_column;
this->last_order = last_order;
+ this->parent = NULL;
this->datatype = NULL;
this->scope = NULL;
this->const_value._real64.status = cs_undefined;
@@ -110,6 +111,12 @@
elements[n++] = elem;
if (NULL == elem) return;
+ /* Sometimes add_element() is called in stage3 or stage4 to temporarily add an AST symbol to the list.
+ * Since this symbol already belongs in some other place in the aST, it will have the 'parent' pointer set,
+ * and so we must not overwrite it. We only set the 'parent' pointer on new symbols that have the 'parent'
+ * pointer still set to NULL.
+ */
+ if (NULL == elem->parent) elem->parent = this;
/* adjust the location parameters, taking into account the new element. */
if (NULL == first_file) {
@@ -199,6 +206,7 @@
int ll, int lc, const char *lfile, long int lorder) \
:symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder) { \
this->ref1 = ref1; \
+ if (NULL != ref1) ref1->parent = this; \
} \
void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);}
@@ -211,6 +219,8 @@
:symbol_c(fl, fc, ffile, forder, ll, lc, lfile, lorder) { \
this->ref1 = ref1; \
this->ref2 = ref2; \
+ if (NULL != ref1) ref1->parent = this; \
+ if (NULL != ref2) ref2->parent = this; \
} \
void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);}
@@ -225,6 +235,9 @@
this->ref1 = ref1; \
this->ref2 = ref2; \
this->ref3 = ref3; \
+ if (NULL != ref1) ref1->parent = this; \
+ if (NULL != ref2) ref2->parent = this; \
+ if (NULL != ref3) ref3->parent = this; \
} \
void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);}
@@ -241,6 +254,10 @@
this->ref2 = ref2; \
this->ref3 = ref3; \
this->ref4 = ref4; \
+ if (NULL != ref1) ref1->parent = this; \
+ if (NULL != ref2) ref2->parent = this; \
+ if (NULL != ref3) ref3->parent = this; \
+ if (NULL != ref4) ref4->parent = this; \
} \
void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);}
@@ -259,6 +276,11 @@
this->ref3 = ref3; \
this->ref4 = ref4; \
this->ref5 = ref5; \
+ if (NULL != ref1) ref1->parent = this; \
+ if (NULL != ref2) ref2->parent = this; \
+ if (NULL != ref3) ref3->parent = this; \
+ if (NULL != ref4) ref4->parent = this; \
+ if (NULL != ref5) ref5->parent = this; \
} \
void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);}
@@ -280,6 +302,12 @@
this->ref4 = ref4; \
this->ref5 = ref5; \
this->ref6 = ref6; \
+ if (NULL != ref1) ref1->parent = this; \
+ if (NULL != ref2) ref2->parent = this; \
+ if (NULL != ref3) ref3->parent = this; \
+ if (NULL != ref4) ref4->parent = this; \
+ if (NULL != ref5) ref5->parent = this; \
+ if (NULL != ref6) ref6->parent = this; \
} \
void *class_name_c::accept(visitor_c &visitor) {return visitor.visit(this);}
--- a/absyntax/absyntax.def Sun Sep 28 17:48:42 2014 +0100
+++ b/absyntax/absyntax.def Sun Oct 19 08:36:49 2014 +0100
@@ -1139,8 +1139,9 @@
/***********************/
/* B 3.1 - Expressions */
/***********************/
-SYM_REF1( ref_expression_c, exp) /* an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. Returns address of the varible! */
-SYM_REF1(deref_expression_c, exp) /* an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. Dereferences an address! */
+SYM_REF1( ref_expression_c, exp) /* an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. REF() -> returns address of the varible! */
+SYM_REF1(deref_expression_c, exp) /* an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. DREF() -> dereferences an address! */
+SYM_REF1(deref_operator_c, exp) /* an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. ^ -> dereferences an address! */
SYM_REF2( or_expression_c, l_exp, r_exp)
SYM_REF2(xor_expression_c, l_exp, r_exp)
SYM_REF2(and_expression_c, l_exp, r_exp)
--- a/absyntax/absyntax.hh Sun Sep 28 17:48:42 2014 +0100
+++ b/absyntax/absyntax.hh Sun Oct 19 08:36:49 2014 +0100
@@ -109,6 +109,9 @@
/*
* Annotations produced during stage 1_2
*/
+ /* Points to the parent symbol in the AST, i.e. the symbol in the AST that will contain the current symbol */
+ symbol_c *parent;
+
/* Line number for the purposes of error checking. */
int first_line;
int first_column;
--- a/absyntax_utils/search_varfb_instance_type.cc Sun Sep 28 17:48:42 2014 +0100
+++ b/absyntax_utils/search_varfb_instance_type.cc Sun Oct 19 08:36:49 2014 +0100
@@ -405,3 +405,61 @@
initial_step_c initial_step(NULL, NULL);
return initial_step.accept(*this);
}
+
+
+/***************************************/
+/* B.3 - Language ST (Structured Text) */
+/***************************************/
+/***********************/
+/* B 3.1 - Expressions */
+/***********************/
+/* SYM_REF1(deref_expression_c, exp) --> an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. Returns address of the varible! */
+void *search_varfb_instance_type_c::visit(deref_expression_c *symbol) {
+ symbol->exp->accept(*this);
+ symbol_c *basetype_decl = current_basetype_decl;
+ this->init(); /* set all current_*** pointers to NULL ! */
+
+ /* Check whether the expression if a REF_TO datatype, and if so, set the new datatype to the datatype it references! */
+ /* Determine whether the datatype is a ref_spec_c, as this is the class used as the */
+ /* canonical/base datatype of REF_TO types (see search_base_type_c ...) */
+ ref_spec_c * ref_spec = dynamic_cast<ref_spec_c *>(basetype_decl);
+ if (NULL != ref_spec) {
+ current_basetype_decl = search_base_type_c::get_basetype_decl(ref_spec->type_name);
+ current_basetype_id = search_base_type_c::get_basetype_id (ref_spec->type_name);
+ }
+
+/* ########### WARNING ########################################################## */
+/* The following two lines DO NOT belong here. It is just a temporary measure until I get the chance
+ * to clean this up, and move it to fill/narrow candidate datatypes in stage 3
+ */
+ symbol->datatype = current_basetype_decl;
+ symbol->exp->datatype = ref_spec;
+
+ return NULL;
+}
+
+
+/* SYM_REF1(deref_operator_c, exp) --> an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. Returns address of the varible! */
+void *search_varfb_instance_type_c::visit(deref_operator_c *symbol) {
+ symbol->exp->accept(*this);
+ symbol_c *basetype_decl = current_basetype_decl;
+ this->init(); /* set all current_*** pointers to NULL ! */
+
+ /* Check whether the expression if a REF_TO datatype, and if so, set the new datatype to the datatype it references! */
+ /* Determine whether the datatype is a ref_spec_c, as this is the class used as the */
+ /* canonical/base datatype of REF_TO types (see search_base_type_c ...) */
+ ref_spec_c * ref_spec = dynamic_cast<ref_spec_c *>(basetype_decl);
+ if (NULL != ref_spec) {
+ current_basetype_decl = search_base_type_c::get_basetype_decl(ref_spec->type_name);
+ current_basetype_id = search_base_type_c::get_basetype_id (ref_spec->type_name);
+ }
+
+/* ########### WARNING ########################################################## */
+/* The following two lines DO NOT belong here. It is just a temporary measure until I get the chance
+ * to clean this up, and move it to fill/narrow candidate datatypes in stage 3
+ */
+ symbol->datatype = current_basetype_decl;
+ symbol->exp->datatype = ref_spec;
+
+ return NULL;
+}
--- a/absyntax_utils/search_varfb_instance_type.hh Sun Sep 28 17:48:42 2014 +0100
+++ b/absyntax_utils/search_varfb_instance_type.hh Sun Oct 19 08:36:49 2014 +0100
@@ -197,7 +197,17 @@
/* STEP step_name ':' action_association_list END_STEP */
// SYM_REF2(step_c, step_name, action_association_list)
void *visit(step_c *symbol);
-
+
+ /***************************************/
+ /* B.3 - Language ST (Structured Text) */
+ /***************************************/
+ /***********************/
+ /* B 3.1 - Expressions */
+ /***********************/
+ /* SYM_REF1(deref_expression_c, exp) --> an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. Returns address of the varible! */
+ void *visit(deref_operator_c *symbol);
+ void *visit(deref_expression_c *symbol);
+
}; // search_varfb_instance_type_c
--- a/stage1_2/iec_bison.yy Sun Sep 28 17:48:42 2014 +0100
+++ b/stage1_2/iec_bison.yy Sun Oct 19 08:36:49 2014 +0100
@@ -3406,7 +3406,7 @@
*/
| symbolic_variable '^'
/* Dereferencing operator defined in IEC 61131-3 v3. However, implemented here differently then how it is defined in the standard! See following note for explanation! */
- {$$ = new deref_expression_c($1, locloc(@$));
+ {$$ = new deref_operator_c($1, locloc(@$));
if (!allow_ref_dereferencing) {
print_err_msg(locf(@$), locl(@$), "Derefencing REF_TO datatypes with '^' is not allowed (use -r option to activate support for this IEC 61131-3 v3 feature).");
yynerrs++;
--- a/stage3/fill_candidate_datatypes.cc Sun Sep 28 17:48:42 2014 +0100
+++ b/stage3/fill_candidate_datatypes.cc Sun Oct 19 08:36:49 2014 +0100
@@ -1906,6 +1906,23 @@
}
+/* SYM_REF1(deref_operator_c, exp) --> an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. Returns address of the varible! */
+void *fill_candidate_datatypes_c::visit(deref_operator_c *symbol) {
+ symbol->exp->accept(*this);
+
+ for (unsigned int i = 0; i < symbol->exp->candidate_datatypes.size(); i++) {
+ /* Determine whether the datatype is a ref_spec_c, as this is the class used as the */
+ /* canonical/base datatype of REF_TO types (see search_base_type_c ...) */
+ ref_spec_c *ref_spec = dynamic_cast<ref_spec_c *>(symbol->exp->candidate_datatypes[i]);
+
+ if (NULL != ref_spec)
+ add_datatype_to_candidate_list(symbol, search_base_type_c::get_basetype_decl(ref_spec->type_name));
+ }
+
+ return NULL;
+}
+
+
/* SYM_REF1(ref_expression_c, exp) --> an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. Returns address of the varible! */
void *fill_candidate_datatypes_c::visit( ref_expression_c *symbol) {
/* We must first determine the datatype of the expression passed to the REF() operator, with no ambiguities!
--- a/stage3/fill_candidate_datatypes.hh Sun Sep 28 17:48:42 2014 +0100
+++ b/stage3/fill_candidate_datatypes.hh Sun Oct 19 08:36:49 2014 +0100
@@ -337,6 +337,7 @@
/***********************/
/* B 3.1 - Expressions */
/***********************/
+ void *visit( deref_operator_c *symbol);
void *visit( deref_expression_c *symbol);
void *visit( ref_expression_c *symbol);
void *visit( or_expression_c *symbol);
--- a/stage3/narrow_candidate_datatypes.cc Sun Sep 28 17:48:42 2014 +0100
+++ b/stage3/narrow_candidate_datatypes.cc Sun Oct 19 08:36:49 2014 +0100
@@ -1395,6 +1395,23 @@
}
+/* SYM_REF1(deref_operator_c, exp) --> an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. Returns address of the varible! */
+void *narrow_candidate_datatypes_c::visit(deref_operator_c *symbol) {
+ for (unsigned int i = 0; i < symbol->exp->candidate_datatypes.size(); i++) {
+ /* Determine whether the datatype is a ref_spec_c, as this is the class used as the */
+ /* canonical/base datatype of REF_TO types (see search_base_type_c ...) */
+ ref_spec_c *ref_spec = dynamic_cast<ref_spec_c *>(symbol->exp->candidate_datatypes[i]);
+
+ if ((NULL != ref_spec) && get_datatype_info_c::is_type_equal(ref_spec->type_name, symbol->datatype))
+ /* if it points to the required datatype for symbol, then that is the required datatype for symbol->exp */
+ symbol->exp->datatype = ref_spec;
+ }
+
+ symbol->exp->accept(*this);
+ return NULL;
+}
+
+
/* SYM_REF1(ref_expression_c, exp) --> an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. Returns address of the varible! */
void *narrow_candidate_datatypes_c::visit( ref_expression_c *symbol) {
if (symbol->exp->candidate_datatypes.size() > 0) {
--- a/stage3/narrow_candidate_datatypes.hh Sun Sep 28 17:48:42 2014 +0100
+++ b/stage3/narrow_candidate_datatypes.hh Sun Oct 19 08:36:49 2014 +0100
@@ -308,6 +308,7 @@
/***********************/
/* B 3.1 - Expressions */
/***********************/
+ void *visit( deref_operator_c *symbol);
void *visit( deref_expression_c *symbol);
void *visit( ref_expression_c *symbol);
void *visit( or_expression_c *symbol);
--- a/stage3/print_datatypes_error.cc Sun Sep 28 17:48:42 2014 +0100
+++ b/stage3/print_datatypes_error.cc Sun Oct 19 08:36:49 2014 +0100
@@ -1044,6 +1044,15 @@
/***********************/
/* B 3.1 - Expressions */
/***********************/
+/* SYM_REF1(deref_operator_c, exp) --> an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. Returns address of the varible! */
+void *print_datatypes_error_c::visit(deref_operator_c *symbol) {
+ symbol->exp->accept(*this);
+ /* we should really check whether the expression is merely a variable. For now, leave it for the future! */
+ if ((symbol->candidate_datatypes.size() == 0) && (symbol->exp->candidate_datatypes.size() > 0))
+ STAGE3_ERROR(0, symbol, symbol, "^ operator must be preceded by a value of type REF_TO.");
+ return NULL;
+}
+
/* SYM_REF1(deref_expression_c, exp) --> an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. Returns address of the varible! */
void *print_datatypes_error_c::visit(deref_expression_c *symbol) {
symbol->exp->accept(*this);
--- a/stage3/print_datatypes_error.hh Sun Sep 28 17:48:42 2014 +0100
+++ b/stage3/print_datatypes_error.hh Sun Oct 19 08:36:49 2014 +0100
@@ -288,6 +288,7 @@
/***********************/
/* B 3.1 - Expressions */
/***********************/
+ void *visit( deref_operator_c *symbol);
void *visit( deref_expression_c *symbol);
void *visit( ref_expression_c *symbol);
void *visit( or_expression_c *symbol);
--- a/stage4/generate_c/generate_c_base.cc Sun Sep 28 17:48:42 2014 +0100
+++ b/stage4/generate_c/generate_c_base.cc Sun Oct 19 08:36:49 2014 +0100
@@ -747,9 +747,10 @@
* this into account!
*/
// SYM_REF2(structured_variable_c, record_variable, field_selector)
+// TODO: It seems to me this code no longer gets to execute, since the function is overloaded in generate_c_st_c and generate_c_il_c
+// I will have to check this later, and delete this code if the above is really true!
void *visit(structured_variable_c *symbol) {
TRACE("structured_variable_c");
-
symbol->record_variable->accept(*this);
s4o.print(".");
symbol->field_selector->accept(*this);
--- a/stage4/generate_c/generate_c_st.cc Sun Sep 28 17:48:42 2014 +0100
+++ b/stage4/generate_c/generate_c_st.cc Sun Oct 19 08:36:49 2014 +0100
@@ -348,8 +348,10 @@
|| get_datatype_info_c::is_sfc_step (symbol->record_variable->datatype)) {
if (NULL == symbol->record_variable->scope) ERROR;
search_var_instance_decl_c search_var_instance_decl(symbol->record_variable->scope);
- if (search_var_instance_decl_c::external_vt == search_var_instance_decl.get_vartype(get_var_name_c::get_last_field(symbol->record_variable)))
- s4o.print("->");
+ if (search_var_instance_decl_c::external_vt == search_var_instance_decl.get_vartype(get_var_name_c::get_last_field(symbol->record_variable)))
+ s4o.print("->"); /* please read the comment in visit(deref_operator_c *) tio understand what this line is doing! */
+ else if (dynamic_cast<deref_operator_c *>(symbol->record_variable) != NULL)
+ s4o.print("->"); /* please read the comment in visit(deref_operator_c *) tio understand what this line is doing! */
else
s4o.print(".");
symbol->field_selector->accept(*this);
@@ -360,12 +362,22 @@
// the following condition MUST be a negation of the above condition used in the 'case complextype_base_vg:'
if (!( get_datatype_info_c::is_function_block(symbol->record_variable->datatype) // if the record variable is not a FB...
|| get_datatype_info_c::is_sfc_step (symbol->record_variable->datatype))) { // ...nor an SFC step name, then it will certainly be a structure!
- s4o.print(".");
+ if (dynamic_cast<deref_operator_c *>(symbol->record_variable) != NULL)
+ s4o.print("->"); /* please read the comment in visit(deref_operator_c *) tio understand what this line is doing! */
+ else
+ s4o.print(".");
symbol->field_selector->accept(*this);
}
break;
default:
if (this->is_variable_prefix_null()) {
+ /* We are writing code for a FUNCTION. In this case, deref_operator_c are not transformed into the C pointer derefence syntax '->' (e.g. ptr->elem).
+ * We use instead the '*' syntax (e.g. (*ptr).elem)
+ * While in FB the '->' is generated by this structured_variable_c visitor, in Functions the '*' syntax is generated by the deref_operator_c visitor
+ * This is why here we do NOT have --> {if (dynamic_cast<deref_operator_c *>(symbol->record_variable) != NULL) ..}
+ *
+ * please read the comment in visit(deref_operator_c *) for more information!
+ */
symbol->record_variable->accept(*this);
s4o.print(".");
symbol->field_selector->accept(*this);
@@ -463,6 +475,45 @@
/***********************/
/* B 3.1 - Expressions */
/***********************/
+void *visit(deref_operator_c *symbol) {
+ /* When producing C code for FUNCTION_BLOCKS, we use the '*' syntax (e.g. (*ptr).elem)
+ * When producing C code for a FUNCTION_BLOCK, the deref_operator_c are transformed in two ways, depending on where they occur.
+ * - deref_operator between a struct and its elem (e.g. struct_ref^.elem1)
+ * are transformed into C using the C pointer derefence syntax '->' (e.g. struct_ref->elem1).
+ * (In this case, '->' is generated by this structured_variable_c visitor)
+ * - deref_operator at the end of a struct variable (e.g. struct.elem_ptr^)
+ * are transformed using the '*' syntax for C pointer dereferencing (e.g. *(struct.elem_ptr) )
+ *
+ * NOTE: Ideally, we should always use the '*' C pointer dereferencing syntax. However, due to the
+ * was the GET_VAR and SET_VAR are transformed into C, this does not work for '^' between a struct and its
+ * element (e.g. struct_ref^.elem), which is whey in this case only we use the '->' syntax.
+ * NOTE: The use of the -> syntax means that pointers to pointers are not supported betweem a struct and its elem
+ * (e.g. . struct_ref_ref^^.elem) as this would be transformed into the invalid C code struct_ref_ref->->elem.
+ * This is why we add a test for this case, and bug out with an error if we encounter it!!
+ */
+ if (this->is_variable_prefix_null()) {
+ /* For code in FUNCTIONs */
+ s4o.print("(*");
+ symbol->exp->accept(*this);
+ s4o.print(")");
+ } else {
+ /* For code in FBs, and PROGRAMS... */
+ if (NULL == dynamic_cast<structured_variable_c *>(symbol->parent)) {
+ s4o.print("(*");
+ symbol->exp->accept(*this);
+ s4o.print(")");
+ } else {
+ /* We are in a structured variable - the structured_variable_c itself will already have printed out the '->' !! */
+ if (NULL != dynamic_cast<deref_operator_c *>(symbol->exp))
+ STAGE4_ERROR(symbol, symbol->exp, "The use of consecutive derefencing operators between a struct and its elem (ex: struct_ref_ref^^.elem) is currently not supported for code inside a Function_Block.");
+ symbol->exp->accept(*this);
+ }
+ }
+
+ return NULL;
+}
+
+
void *visit(deref_expression_c *symbol) {
s4o.print("(");
if (this->is_variable_prefix_null()) {
@@ -472,7 +523,6 @@
s4o.print("");
} else {
/* For code in FBs, and PROGRAMS... */
- s4o.print("(");
unsigned int vartype = analyse_variable_c::first_nonfb_vardecltype(symbol->exp, scope_);
if (vartype == search_var_instance_decl_c::external_vt) {
if (!get_datatype_info_c::is_type_valid (symbol->exp->datatype)) ERROR;
@@ -496,8 +546,6 @@
symbol->exp->accept(*this);
s4o.print(")");
wanted_variablegeneration = old_wanted_variablegeneration;
-
- s4o.print(")");
}
s4o.print(")");
--- a/stage4/generate_iec/generate_iec.cc Sun Sep 28 17:48:42 2014 +0100
+++ b/stage4/generate_iec/generate_iec.cc Sun Oct 19 08:36:49 2014 +0100
@@ -1917,8 +1917,9 @@
/***********************/
/* B 3.1 - Expressions */
/***********************/
-void *visit( ref_expression_c *symbol) {return s4o.print( "REF("); symbol->exp->accept(*this); s4o.print(")");} /* an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. Returns address of the varible! */
-void *visit( deref_expression_c *symbol) {return s4o.print("DREF("); symbol->exp->accept(*this); s4o.print(")");} /* an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. Returns address of the varible! */
+void *visit( deref_operator_c *symbol) {return symbol->exp->accept(*this); s4o.print("^");} /* an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. ^ -> dereferences an address into a variable! */
+void *visit( deref_expression_c *symbol) {return s4o.print("DREF("); symbol->exp->accept(*this); s4o.print(")");} /* an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. DREF() -> dereferences an address into a variable! */
+void *visit( ref_expression_c *symbol) {return s4o.print( "REF("); symbol->exp->accept(*this); s4o.print(")");} /* an extension to the IEC 61131-3 standard - based on the IEC 61131-3 v3 standard. REF() -> returns address of the varible! */
void *visit( or_expression_c *symbol) {return print_binary_expression(symbol, symbol->l_exp, symbol->r_exp, " OR ");}
void *visit( xor_expression_c *symbol) {return print_binary_expression(symbol, symbol->l_exp, symbol->r_exp, " XOR ");}
void *visit( and_expression_c *symbol) {return print_binary_expression(symbol, symbol->l_exp, symbol->r_exp, " AND ");}