# HG changeset patch # User mjsousa # Date 1413704209 -3600 # Node ID 0f7bcc1605680d1a1f2a676e8138b6b881b0e683 # Parent be4373d07201a51e5c3313de00160da3857104ba 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!) diff -r be4373d07201 -r 0f7bcc160568 absyntax/absyntax.cc --- 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);} diff -r be4373d07201 -r 0f7bcc160568 absyntax/absyntax.def --- 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) diff -r be4373d07201 -r 0f7bcc160568 absyntax/absyntax.hh --- 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; diff -r be4373d07201 -r 0f7bcc160568 absyntax_utils/search_varfb_instance_type.cc --- 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(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(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; +} diff -r be4373d07201 -r 0f7bcc160568 absyntax_utils/search_varfb_instance_type.hh --- 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 diff -r be4373d07201 -r 0f7bcc160568 stage1_2/iec_bison.yy --- 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++; diff -r be4373d07201 -r 0f7bcc160568 stage3/fill_candidate_datatypes.cc --- 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(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! diff -r be4373d07201 -r 0f7bcc160568 stage3/fill_candidate_datatypes.hh --- 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); diff -r be4373d07201 -r 0f7bcc160568 stage3/narrow_candidate_datatypes.cc --- 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(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) { diff -r be4373d07201 -r 0f7bcc160568 stage3/narrow_candidate_datatypes.hh --- 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); diff -r be4373d07201 -r 0f7bcc160568 stage3/print_datatypes_error.cc --- 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); diff -r be4373d07201 -r 0f7bcc160568 stage3/print_datatypes_error.hh --- 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); diff -r be4373d07201 -r 0f7bcc160568 stage4/generate_c/generate_c_base.cc --- 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); diff -r be4373d07201 -r 0f7bcc160568 stage4/generate_c/generate_c_st.cc --- 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(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(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(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(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(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(")"); diff -r be4373d07201 -r 0f7bcc160568 stage4/generate_iec/generate_iec.cc --- 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 ");}