diff -r 000000000000 -r fb772792efd1 stage4/generate_cc/generate_cc_vardecl.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/stage4/generate_cc/generate_cc_vardecl.cc Wed Jan 31 15:32:38 2007 +0100 @@ -0,0 +1,1661 @@ +/* + * (c) 2003 Mario de Sousa + * + * Offered to the public under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * This code is made available on the understanding that it will not be + * used in safety-critical situations without a full and competent review. + */ + +/* + * An IEC 61131-3 IL and ST compiler. + * + * Based on the + * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) + * + */ + + +/* + * Conversion of variable declaration constructs. + * + * This is part of the 4th stage that generates + * a c++ source program equivalent to the IL and ST + * code. + */ + + + + +//#include /* required for NULL */ +//#include +//#include + +//#include "../../util/symtable.hh" + + + + + + + + + +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ +/***********************************************************************/ + + + + +class generate_cc_vardecl_c: protected generate_cc_typedecl_c { + + /* A Helper class to the main class... */ + /* print a string, except the first time it is called */ + /* used to print the separator "," before each variable + * declaration, except the first... + * + * Needs to be done in a seperate class because this is called + * from within various locations within the code. + */ + class next_var_c { + private: + bool print_flag; + std::string str1, str2; + + next_var_c *embedded_scope; + + public: + next_var_c(std::string s1, std::string s2) { + str1 = s1; + str2 = s2; + print_flag = false; + embedded_scope = NULL; + } + + std::string get(void) { + if (NULL != embedded_scope) + return embedded_scope->get(); + + bool old_print_flag = print_flag; + print_flag = true; + if (!old_print_flag) + return str1; + else + return str2; + } + + /* Create a new next_var_c for an embedded scope. + * From now on, every call to get() will return the + * inner-most scope...! + */ + void push(std::string s1, std::string s2) { + if (NULL != embedded_scope) + return embedded_scope->push(s1, s2); + + embedded_scope = new next_var_c(s1, s2); + if (NULL == embedded_scope) + ERROR; + return; + } + + /* Remove the inner-most scope... */ + void pop(void) { + if (NULL != embedded_scope) + return embedded_scope->pop(); + + delete embedded_scope; + embedded_scope = NULL; + } + }; + + private: + /* used to generate the ',' separating the parameters in a function call */ + next_var_c *nv; + + + public: + /* the types of variables that need to be processed... */ + static const unsigned int none_vt = 0x0000; + static const unsigned int input_vt = 0x0001; // VAR_INPUT + static const unsigned int output_vt = 0x0002; // VAR_OUTPUT + static const unsigned int inoutput_vt = 0x0004; // VAR_IN_OUT + static const unsigned int private_vt = 0x0008; // VAR + static const unsigned int temp_vt = 0x0010; // VAR_TEMP + static const unsigned int external_vt = 0x0020; // VAR_EXTERNAL + static const unsigned int global_vt = 0x0040; // VAR_GLOBAL + // Globals declared inside a resource will not be declared + // unless global_vt is acompanied by resource_vt + static const unsigned int located_vt = 0x0080; // VAR AT + static const unsigned int program_vt = 0x0100; // PROGRAM (inside a configuration!) + // Programs declared inside a resource will not be declared + // unless program_vt is acompanied by resource_vt + + static const unsigned int resource_vt = 0x8000; // RESOURCE (inside a configuration!) + // This, just of itself, will not print out any declarations!! + // It must be acompanied by either program_vt and/or global_vt + + /* How variables should be declared: as local variables or + * variables within a function call interface. + * + * This will define the format of the output generated + * by this class. + * + * finterface_vf: function interface parameters + * e.g. f( int a, long b, real c ); + * --------------------- + * This class/function will produce the + * underlined code of the above examples, + * and no more!! + * + * localinit_vf: local declaration. Will include variable + * initialisation if it is not a located variable. + * e.g. + * int a = 9; + * long b = 99; + * real c = 99.9; + * + * local_vf: local declaration. Will NOT include variable + * initialisation. + * e.g. + * int a; + * long b; + * real c; + * + * init_vf: local initialisation without declaration. + * e.g. + * a = 9; + * b = 99; + * c = 99.9; + * + * constructorinit_vf: initialising of member variables... + * e.g. for a constructor... + * class_name_c(void) + * : a(9), b(99), c(99.9) { // code... } + * -------------------- + * This class/function will produce the + * underlined code of the above examples, + * and no more!! + * + * globalinit_vf: initialising of static c++ variables. These + * variables may have been declared as static inside + * a class, in which case the scope within which they were + * previously delcared must be passed as the second parameter + * to the print() function. + * + * e.g. + * __plc_pt_c START_P::loc = __plc_pt_c("I2"); + */ + typedef enum {finterface_vf, + local_vf, + localinit_vf, + init_vf, + constructorinit_vf, + globalinit_vf + } varformat_t; + + + private: + /* variable used to store the types of variables that need to be processed... */ + /* Only set in the constructor...! */ + /* Will contain a set of values of generate_cc_vardecl_c::XXXX_vt */ + unsigned int wanted_vartype; + /* variable used to store the type of variable currently being processed... */ + /* Will contain a single value of generate_cc_vardecl_c::XXXX_vt */ + unsigned int current_vartype; + + /* How variables should be declared: as local variables or + * variables within a function interface... + */ + /* Only set in the constructor...! */ + varformat_t wanted_varformat; + + /* The number of variables already declared. */ + /* Used to declare 'void' in case no variables are declared in a function interface... */ + int finterface_var_count; + + + + /* Holds the references to the type and initial value + * of the variables currently being declared. + * Please read the comment under var1_init_decl_c for further + * details... + * + * We make an effort to keep these pointers pointing to NULL + * whenever we are outside the scope of variable declaration + * (i.e. when we are traversing a part of the parse tree which + * is not part of variable declaration) in order tio try to catch + * any bugs as soon as possible. + */ + symbol_c *current_var_type_symbol; + symbol_c *current_var_init_symbol; + void update_type_init(symbol_c *symbol /* a spec_init_c, subrange_spec_init_c, etc... */ ) { + this->current_var_type_symbol = spec_init_sperator_c::get_spec(symbol); + this->current_var_init_symbol = spec_init_sperator_c::get_init(symbol); + if (NULL == this->current_var_type_symbol) + ERROR; + if (NULL == this->current_var_init_symbol) { + /* We try to find the data type's default value... */ + this->current_var_init_symbol = (symbol_c *)this->current_var_type_symbol->accept(*type_initial_value_c::instance()); + /* Note that Function Block 'data types' do not have a default value, so we cannot abort if no default value is found! */ + /* + if (NULL == this->current_var_init_symbol) + ERROR; + */ + } + } + + void void_type_init(void) { + this->current_var_type_symbol = NULL; + this->current_var_init_symbol = NULL; + } + + /* Only used when wanted_varformat == globalinit_vf + * Holds a pointer to an identifier_c, which in turns contains + * the identifier of the scope within which the static member was + * declared. + */ + symbol_c *globalnamespace; + + /* Actually produce the output where variables are declared... */ + /* Note that located variables are the exception, they + * being declared in the located_var_decl_c visitor... + */ + void *declare_variables(symbol_c *symbol) { + list_c *list = dynamic_cast(symbol); + /* should NEVER EVER occur!! */ + if (list == NULL) ERROR; + + /* now to produce the c equivalent... */ + if ((wanted_varformat == local_vf) || + (wanted_varformat == init_vf) || + (wanted_varformat == localinit_vf)) { + for(int i = 0; i < list->n; i++) { + s4o.print(s4o.indent_spaces); + if (wanted_varformat != init_vf) { + this->current_var_type_symbol->accept(*this); + s4o.print(" "); + } + this->print_variable_prefix(); + list->elements[i]->accept(*this); + if (wanted_varformat != local_vf) { + if (this->current_var_init_symbol != NULL) { + s4o.print(" = "); + this->current_var_init_symbol->accept(*this); + } + } + s4o.print(";\n"); + } + } + + if (wanted_varformat == finterface_vf) { + for(int i = 0; i < list->n; i++) { + finterface_var_count++; + s4o.print(nv->get()); + s4o.print("\n" + s4o.indent_spaces); + this->current_var_type_symbol->accept(*this); + if ((current_vartype & (output_vt | inoutput_vt)) != 0) + s4o.print(" &"); + else + s4o.print(" "); + list->elements[i]->accept(*this); + /* We do not print the initial value at function declaration! + * It is up to the caller to pass the correct default value + * if none is specified in the ST source code + */ + /* if (this->current_var_init_symbol != NULL) { + s4o.print(" = "); this->current_var_init_symbol->accept(*this);} + */ + } + } + + if (wanted_varformat == constructorinit_vf) { + for(int i = 0; i < list->n; i++) { + if (this->current_var_init_symbol != NULL) { + s4o.print(nv->get()); + list->elements[i]->accept(*this); + s4o.print("("); + this->current_var_init_symbol->accept(*this); + s4o.print(")"); + } + } + } + + return NULL; + } + + + + + public: + generate_cc_vardecl_c(stage4out_c *s4o_ptr, varformat_t varformat, unsigned int vartype) + : generate_cc_typedecl_c(s4o_ptr) { + wanted_varformat = varformat; + wanted_vartype = vartype; + current_vartype = none_vt; + current_var_type_symbol = NULL; + current_var_init_symbol = NULL; + globalnamespace = NULL; + nv = NULL; + } + + ~generate_cc_vardecl_c(void) {} + + + void print(symbol_c *symbol, symbol_c *scope = NULL, const char *variable_prefix = NULL) { + this->set_variable_prefix(variable_prefix); + if (globalinit_vf == wanted_varformat) + globalnamespace = scope; + + finterface_var_count = 0; + + switch (wanted_varformat) { + case constructorinit_vf: nv = new next_var_c(": ", ", "); break; + case finterface_vf: /* fall through... */ + case localinit_vf: /* fall through... */ + case local_vf: nv = new next_var_c("", ", "); break; + default: nv = NULL; + } /* switch() */ + + symbol->accept(*this); + + /* special case... */ + if (wanted_varformat == finterface_vf) + if (finterface_var_count == 0) + s4o.print("void"); + + delete nv; + nv = NULL; + globalnamespace = NULL; + } + + + protected: +/***************************/ +/* B 0 - Programming Model */ +/***************************/ + /* leave for derived classes... */ + +/*************************/ +/* B.1 - Common elements */ +/*************************/ +/*******************************************/ +/* B 1.1 - Letters, digits and identifiers */ +/*******************************************/ + /* done in base class(es) */ + +/*********************/ +/* B 1.2 - Constants */ +/*********************/ + /* originally empty... */ + +/******************************/ +/* B 1.2.1 - Numeric Literals */ +/******************************/ + /* done in base class(es) */ + +/*******************************/ +/* B.1.2.2 Character Strings */ +/*******************************/ + /* done in base class(es) */ + +/***************************/ +/* B 1.2.3 - Time Literals */ +/***************************/ +/************************/ +/* B 1.2.3.1 - Duration */ +/************************/ + /* done in base class(es) */ + +/************************************/ +/* B 1.2.3.2 - Time of day and Date */ +/************************************/ + /* done in base class(es) */ + +/**********************/ +/* B.1.3 - Data types */ +/**********************/ +/***********************************/ +/* B 1.3.1 - Elementary Data Types */ +/***********************************/ + /* done in base class(es) */ + +/********************************/ +/* B.1.3.2 - Generic data types */ +/********************************/ + /* originally empty... */ + +/********************************/ +/* B 1.3.3 - Derived data types */ +/********************************/ + /* done in base class(es) */ + +/*********************/ +/* B 1.4 - Variables */ +/*********************/ + /* done in base class(es) */ + +/********************************************/ +/* B.1.4.1 Directly Represented Variables */ +/********************************************/ + /* done in base class(es) */ + +/*************************************/ +/* B.1.4.2 Multi-element Variables */ +/*************************************/ + /* done in base class(es) */ + +/******************************************/ +/* B 1.4.3 - Declaration & Initialisation */ +/******************************************/ +void *visit(constant_option_c *symbol) {s4o.print("CONSTANT"); return NULL;} +void *visit(retain_option_c *symbol) {s4o.print("RETAIN"); return NULL;} +void *visit(non_retain_option_c *symbol) {s4o.print("NON_RETAIN"); return NULL;} + +void *visit(input_declarations_c *symbol) { + TRACE("input_declarations_c"); + if ((wanted_vartype & input_vt) != 0) { +/* + // TO DO ... + if (symbol->option != NULL) + symbol->option->accept(*this); +*/ + //s4o.indent_right(); + current_vartype = input_vt; + symbol->input_declaration_list->accept(*this); + current_vartype = none_vt; + //s4o.indent_left(); + } + return NULL; +} + +/* helper symbol for input_declarations */ +void *visit(input_declaration_list_c *symbol) { + TRACE("input_declaration_list_c"); + print_list(symbol); + return NULL; +} + +void *visit(edge_declaration_c *symbol) { + TRACE("edge_declaration_c"); + // TO DO ... + symbol->var1_list->accept(*this); + s4o.print(" : BOOL "); + symbol->edge->accept(*this); + return NULL; +} + +void *visit(raising_edge_option_c *symbol) { + // TO DO ... + s4o.print("R_EDGE"); + return NULL; +} + + +#if 0 +/* var1_list ':' array_spec_init */ +SYM_REF2(array_var_init_decl_c, var1_list, array_spec_init) +#endif + +/* var1_list ':' initialized_structure */ +// SYM_REF2(structured_var_init_decl_c, var1_list, initialized_structure) +void *visit(structured_var_init_decl_c *symbol) { + TRACE("structured_var_init_decl_c"); + /* Please read the comments inside the var1_init_decl_c + * visitor, as they apply here too. + */ + + /* Start off by setting the current_var_type_symbol and + * current_var_init_symbol private variables... + */ + update_type_init(symbol->initialized_structure); + + /* now to produce the c equivalent... */ + symbol->var1_list->accept(*this); + + /* Values no longer in scope, and therefore no longer used. + * Make an effort to keep them set to NULL when not in use + * in order to catch bugs as soon as possible... + */ + void_type_init(); + + return NULL; +} + +/* fb_name_list ':' function_block_type_name ASSIGN structure_initialization */ +/* structure_initialization -> may be NULL ! */ +void *visit(fb_name_decl_c *symbol) { + TRACE("fb_name_decl_c"); + /* Please read the comments inside the var1_init_decl_c + * visitor, as they apply here too. + */ + + /* Start off by setting the current_var_type_symbol and + * current_var_init_symbol private variables... + */ + update_type_init(symbol); + + /* now to produce the c equivalent... */ + symbol->fb_name_list->accept(*this); + + /* Values no longer in scope, and therefore no longer used. + * Make an effort to keep them set to NULL when not in use + * in order to catch bugs as soon as possible... + */ + void_type_init(); + + return NULL; +} + +/* fb_name_list ',' fb_name */ +void *visit(fb_name_list_c *symbol) { + TRACE("fb_name_list_c"); + declare_variables(symbol); + return NULL; +} + + +/* VAR_OUTPUT [RETAIN | NON_RETAIN] var_init_decl_list END_VAR */ +/* option -> may be NULL ! */ +void *visit(output_declarations_c *symbol) { + TRACE("output_declarations_c"); + if ((wanted_vartype & output_vt) != 0) { +/* + // TO DO ... + if (symbol->option != NULL) + symbol->option->accept(*this); +*/ + //s4o.indent_right(); + current_vartype = output_vt; + symbol->var_init_decl_list->accept(*this); + current_vartype = none_vt; + //s4o.indent_left(); + } + return NULL; +} + +/* VAR_IN_OUT var_declaration_list END_VAR */ +void *visit(input_output_declarations_c *symbol) { + TRACE("input_output_declarations_c"); + if ((wanted_vartype & inoutput_vt) != 0) { + //s4o.indent_right(); + current_vartype = inoutput_vt; + symbol->var_declaration_list->accept(*this); + current_vartype = none_vt; + //s4o.indent_left(); + } + return NULL; +} + +/* helper symbol for input_output_declarations */ +/* var_declaration_list var_declaration ';' */ +void *visit(var_declaration_list_c *symbol) { + TRACE("var_declaration_list_c"); + print_list(symbol); + return NULL; +} + +#if 0 +/* var1_list ':' array_specification */ +SYM_REF2(array_var_declaration_c, var1_list, array_specification) +#endif + +/* var1_list ':' structure_type_name */ +//SYM_REF2(structured_var_declaration_c, var1_list, structure_type_name) +void *visit(structured_var_declaration_c *symbol) { + TRACE("structured_var_declaration_c"); + /* Please read the comments inside the var1_init_decl_c + * visitor, as they apply here too. + */ + + /* Start off by setting the current_var_type_symbol and + * current_var_init_symbol private variables... + */ + update_type_init(symbol->structure_type_name); + + /* now to produce the c equivalent... */ + symbol->var1_list->accept(*this); + + /* Values no longer in scope, and therefore no longer used. + * Make an effort to keep them set to NULL when not in use + * in order to catch bugs as soon as possible... + */ + void_type_init(); + + return NULL; +} + + +/* VAR [CONSTANT] var_init_decl_list END_VAR */ +/* option -> may be NULL ! */ +/* helper symbol for input_declarations */ +void *visit(var_declarations_c *symbol) { + TRACE("var_declarations_c"); + if ((wanted_vartype & private_vt) != 0) { +/* + // TO DO ... + if (symbol->option != NULL) + symbol->option->accept(*this); +*/ + current_vartype = private_vt; + symbol->var_init_decl_list->accept(*this); + current_vartype = none_vt; + } + return NULL; +} + +/* VAR RETAIN var_init_decl_list END_VAR */ +void *visit(retentive_var_declarations_c *symbol) { + TRACE("retentive_var_declarations_c"); + if ((wanted_vartype & private_vt) != 0) { + current_vartype = private_vt; + symbol->var_init_decl_list->accept(*this); + current_vartype = none_vt; + } + return NULL; +} + +/* VAR [CONSTANT|RETAIN|NON_RETAIN] located_var_decl_list END_VAR */ +/* option -> may be NULL ! */ +//SYM_REF2(located_var_declarations_c, option, located_var_decl_list) +void *visit(located_var_declarations_c *symbol) { + TRACE("located_var_declarations_c"); + if ((wanted_vartype & located_vt) != 0) { +/* + // TO DO ... + if (symbol->option != NULL) + symbol->option->accept(*this); +*/ + current_vartype = located_vt; + symbol->located_var_decl_list->accept(*this); + current_vartype = none_vt; + } + return NULL; +} + +/* helper symbol for located_var_declarations */ +/* located_var_decl_list located_var_decl ';' */ +//SYM_LIST(located_var_decl_list_c) +void *visit(located_var_decl_list_c *symbol) { + TRACE("located_var_decl_list_c"); + print_list(symbol); + return NULL; +} + + +/* [variable_name] location ':' located_var_spec_init */ +/* variable_name -> may be NULL ! */ +//SYM_REF4(located_var_decl_c, variable_name, location, located_var_spec_init, unused) +void *visit(located_var_decl_c *symbol) { + TRACE("located_var_decl_c"); + /* Please read the comments inside the var1_init_decl_c + * visitor, as they apply here too. + */ + + /* Start off by setting the current_var_type_symbol and + * current_var_init_symbol private variables... + */ + update_type_init(symbol->located_var_spec_init); + + /* now to produce the c equivalent... */ + switch(wanted_varformat) { + case local_vf: + /* NOTE: located variables must be declared static, as the connection to the + * MatPLC point must be initialised at program startup, and not whenever + * a new function block is instantiated! + * Since they always refer to the same MatPLC point, it is OK to let several + * function block instances share the same located variable! + * If the IEC compiler maps IEC tasks to Linux threads, with tasks/threads + * running simultaneously, then we must make sure the MatPLC IO library + * is thread safe! + */ + s4o.print(s4o.indent_spaces + "static __plc_pt_c<"); + this->current_var_type_symbol->accept(*this); + s4o.print(", 8*sizeof("); + this->current_var_type_symbol->accept(*this); + s4o.print(")> "); + if (symbol->variable_name != NULL) + symbol->variable_name->accept(*this); + else + symbol->location->accept(*this); + s4o.print(";\n"); + break; + + case globalinit_vf: + s4o.print(s4o.indent_spaces + "__plc_pt_c<"); + this->current_var_type_symbol->accept(*this); + s4o.print(", 8*sizeof("); + this->current_var_type_symbol->accept(*this); + s4o.print(")> "); + if (this->globalnamespace != NULL) { + this->globalnamespace->accept(*this); + s4o.print("::"); + } + if (symbol->variable_name != NULL) + symbol->variable_name->accept(*this); + else + symbol->location->accept(*this); + + s4o.print(" = "); + + s4o.print(s4o.indent_spaces + "__plc_pt_c<"); + this->current_var_type_symbol->accept(*this); + s4o.print(", 8*sizeof("); + this->current_var_type_symbol->accept(*this); + s4o.print(")>(\""); + symbol->location->accept(*this); + s4o.print("\""); + if (this->current_var_init_symbol != NULL) { + s4o.print(", "); + this->current_var_init_symbol->accept(*this); + } + s4o.print(");\n"); + break; + + default: + ERROR; + } /* switch() */ + + /* Values no longer in scope, and therefore no longer used. + * Make an effort to keep them set to NULL when not in use + * in order to catch bugs as soon as possible... + */ + void_type_init(); + + return NULL; +} + + + + +/*| VAR_EXTERNAL [CONSTANT] external_declaration_list END_VAR */ +/* option -> may be NULL ! */ +//SYM_REF2(external_var_declarations_c, option, external_declaration_list) +void *visit(external_var_declarations_c *symbol) { + TRACE("external_var_declarations_c"); + if ((wanted_vartype & external_vt) != 0) { +/* + // TODO ... + if (symbol->option != NULL) + symbol->option->accept(*this); +*/ + //s4o.indent_right(); + current_vartype = external_vt; + symbol->external_declaration_list->accept(*this); + current_vartype = none_vt; + //s4o.indent_left(); + } + return NULL; +} + +/* helper symbol for external_var_declarations */ +/*| external_declaration_list external_declaration';' */ +//SYM_LIST(external_declaration_list_c) +/* helper symbol for input_declarations */ +void *visit(external_declaration_list_c *symbol) { + TRACE("external_declaration_list_c"); + print_list(symbol); + return NULL; +} + + +/* global_var_name ':' (simple_specification|subrange_specification|enumerated_specification|array_specification|prev_declared_structure_type_name|function_block_type_name */ +//SYM_REF2(external_declaration_c, global_var_name, specification) +void *visit(external_declaration_c *symbol) { + TRACE("external_declaration_c"); + /* Please read the comments inside the var1_init_decl_c + * visitor, as they apply here too. + */ + + /* Start off by setting the current_var_type_symbol and + * current_var_init_symbol private variables... + */ + this->current_var_type_symbol = symbol->specification; + this->current_var_init_symbol = NULL; + + /* now to produce the c equivalent... */ + switch (wanted_varformat) { + case local_vf: + case localinit_vf: + s4o.print(s4o.indent_spaces); + s4o.print("__ext_ref_c<"); + this->current_var_type_symbol->accept(*this); + s4o.print("> &"); + symbol->global_var_name->accept(*this); + if ((wanted_varformat == localinit_vf) && + (this->current_var_init_symbol != NULL)) { + s4o.print(" = "); + this->current_var_init_symbol->accept(*this); + } + s4o.print(";\n"); + break; + + case constructorinit_vf: + s4o.print(nv->get()); + symbol->global_var_name->accept(*this); + s4o.print("(*"); + symbol->global_var_name->accept(*this); + s4o.print(")"); + break; + + case finterface_vf: + finterface_var_count++; + s4o.print(nv->get()); + s4o.print("__ext_ref_c<"); + this->current_var_type_symbol->accept(*this); + s4o.print("> *"); + symbol->global_var_name->accept(*this); + break; + + default: + ERROR; + } + + /* Values no longer in scope, and therefore no longer used. + * Make an effort to keep them set to NULL when not in use + * in order to catch bugs as soon as possible... + */ + void_type_init(); + + return NULL; +} + + + +/*| VAR_GLOBAL [CONSTANT|RETAIN] global_var_decl_list END_VAR */ +/* option -> may be NULL ! */ +// SYM_REF2(global_var_declarations_c, option, global_var_decl_list) +void *visit(global_var_declarations_c *symbol) { + TRACE("global_var_declarations_c"); + if ((wanted_vartype & global_vt) != 0) { +/* + // TODO ... + if (symbol->option != NULL) + symbol->option->accept(*this); +*/ + //s4o.indent_right(); + unsigned int previous_vartype = current_vartype; + // previous_vartype will be either none_vt, or resource_vt + current_vartype = global_vt; + symbol->global_var_decl_list->accept(*this); + current_vartype = previous_vartype; + //s4o.indent_left(); + } + return NULL; +} + +/* helper symbol for global_var_declarations */ +/*| global_var_decl_list global_var_decl ';' */ +//SYM_LIST(global_var_decl_list_c) +void *visit(global_var_decl_list_c *symbol) { + TRACE("global_var_decl_list_c"); + print_list(symbol); + return NULL; +} + + + +/*| global_var_spec ':' [located_var_spec_init|function_block_type_name] */ +/* type_specification ->may be NULL ! */ +// SYM_REF2(global_var_decl_c, global_var_spec, type_specification) +void *visit(global_var_decl_c *symbol) { + TRACE("global_var_decl_c"); + /* Please read the comments inside the var1_init_decl_c + * visitor, as they apply here too. + */ + + /* Start off by setting the current_var_type_symbol and + * current_var_init_symbol private variables... + */ + update_type_init(symbol->type_specification); + + /* now to produce the c equivalent... */ + symbol->global_var_spec->accept(*this); + + /* Values no longer in scope, and therefore no longer used. + * Make an effort to keep them set to NULL when not in use + * in order to catch bugs as soon as possible... + */ + void_type_init(); + + return NULL; +} + + +/*| global_var_name location */ +// SYM_REF2(global_var_spec_c, global_var_name, location) +void *visit(global_var_spec_c *symbol) { + TRACE("global_var_spec_c"); + + /* now to produce the c equivalent... */ + switch(wanted_varformat) { + case local_vf: + /* NOTE: located variables must be declared static, as the connection to the + * MatPLC point must be initialised at program startup, and not whenever + * a new function block is instantiated! + * Nevertheless, this construct never occurs inside a Function Block, but + * only inside a configuration. In this case, only a single instance will + * be created, directly at startup, so it is not necessary that the variables + * be declared static. + */ + s4o.print(s4o.indent_spaces + "__plc_pt_c<"); + this->current_var_type_symbol->accept(*this); + s4o.print(", 8*sizeof("); + this->current_var_type_symbol->accept(*this); + s4o.print(")> "); + if (symbol->global_var_name != NULL) + symbol->global_var_name->accept(*this); + else + symbol->location->accept(*this); + s4o.print(";\n"); + break; + + case constructorinit_vf: + s4o.print(nv->get()); + if (symbol->global_var_name != NULL) + symbol->global_var_name->accept(*this); + else + symbol->location->accept(*this); + s4o.print("(\""); + symbol->location->accept(*this); + s4o.print("\""); + if (this->current_var_init_symbol != NULL) { + s4o.print(", "); + this->current_var_init_symbol->accept(*this); + } + s4o.print(")"); + break; + + default: + ERROR; + } /* switch() */ + + return NULL; +} + + + +/* AT direct_variable */ +// SYM_REF2(location_c, direct_variable, unused) +void *visit(location_c *symbol) { + TRACE("location_c"); + return symbol->direct_variable->accept(*this); +} + + +/*| global_var_list ',' global_var_name */ +//SYM_LIST(global_var_list_c) +void *visit(global_var_list_c *symbol) { + TRACE("global_var_list_c"); + list_c *list = dynamic_cast(symbol); + /* should NEVER EVER occur!! */ + if (list == NULL) ERROR; + + /* now to produce the c equivalent... */ + switch (wanted_varformat) { + case local_vf: + case localinit_vf: + for(int i = 0; i < list->n; i++) { + s4o.print(s4o.indent_spaces); + s4o.print("__ext_element_c<"); + this->current_var_type_symbol->accept(*this); + s4o.print("> "); + list->elements[i]->accept(*this); + if (wanted_varformat == localinit_vf) { + if (this->current_var_init_symbol != NULL) { + s4o.print(" = "); + this->current_var_init_symbol->accept(*this); + } + } + s4o.print(";\n"); + } + break; + + case constructorinit_vf: + if (this->current_var_init_symbol != NULL) { + for(int i = 0; i < list->n; i++) { + s4o.print(nv->get()); + + list->elements[i]->accept(*this); + s4o.print("("); + this->current_var_init_symbol->accept(*this); + s4o.print(")"); +#if 0 + /* The following code would be for globalinit_vf !! + * But it is not currently required... + */ + s4o.print(s4o.indent_spaces + "__ext_element_c<"); + this->current_var_type_symbol->accept(*this); + s4o.print("> "); + if (this->globalnamespace != NULL) { + this->globalnamespace->accept(*this); + s4o.print("::"); + } + list->elements[i]->accept(*this); + + if (this->current_var_init_symbol != NULL) { + s4o.print(" = "); + s4o.print("__ext_element_c<"); + this->current_var_type_symbol->accept(*this); + s4o.print(">("); + this->current_var_init_symbol->accept(*this); + s4o.print(")"); + } + s4o.print(";\n"); +#endif + } + } + break; + + default: + ERROR; /* not supported, and not needed either... */ + } + + return NULL; +} + + +#if 0 +/* var1_list ':' single_byte_string_spec */ +SYM_REF2(single_byte_string_var_declaration_c, var1_list, single_byte_string_spec) + +/* STRING ['[' integer ']'] [ASSIGN single_byte_character_string] */ +/* integer ->may be NULL ! */ +/* single_byte_character_string ->may be NULL ! */ +SYM_REF2(single_byte_string_spec_c, integer, single_byte_character_string) + +/* var1_list ':' double_byte_string_spec */ +SYM_REF2(double_byte_string_var_declaration_c, var1_list, double_byte_string_spec) + +/* WSTRING ['[' integer ']'] [ASSIGN double_byte_character_string] */ +/* integer ->may be NULL ! */ +/* double_byte_character_string ->may be NULL ! */ +SYM_REF2(double_byte_string_spec_c, integer, double_byte_character_string) + +/*| VAR [RETAIN|NON_RETAIN] incompl_located_var_decl_list END_VAR */ +/* option ->may be NULL ! */ +SYM_REF2(incompl_located_var_declarations_c, option, incompl_located_var_decl_list) + +/* helper symbol for incompl_located_var_declarations */ +/*| incompl_located_var_decl_list incompl_located_var_decl ';' */ +SYM_LIST(incompl_located_var_decl_list_c) + +/* variable_name incompl_location ':' var_spec */ +SYM_REF4(incompl_located_var_decl_c, variable_name, incompl_location, var_spec, unused) + +/* AT incompl_location_token */ +SYM_TOKEN(incompl_location_c) +#endif + + +void *visit(falling_edge_option_c *symbol) { + // TO DO ... + s4o.print("F_EDGE"); + return NULL; +} + + +void *visit(var1_init_decl_c *symbol) { + TRACE("var1_init_decl_c"); + /* We have several implementation alternatives here... + * + * The issue is that generation of c code + * based on the abstract syntax tree requires the reversal + * of the symbol order compared to st. For e.g.: + * (ST) a, b, c: INT := 98; + * (C ) int a=98, b=98, c=98; + * The spec_init contains the references to 'INT' and '98'. + * The var1_list contains the references to 'a', 'b', and 'c'. + * The var1_init_decl_c contains the references to spec_init and var1_list. + * + * For c code generation, the var1_init_decl_c visitor + * would need to access the internals of other classes + * (e.g. the simple_spec_init_c). + * + * We can do this using one of three methods: + * 1) Create the abstract syntax tree differently; + * 2) Access other classes from within the var1_init_decl_c; + * 3) Pass info between the visitors using global variables + * only acessible by this class (private vars) + * + * In 1), the abstract syntax tree would be built so that + * var1_init_decl_c would contain direct references to + * var1_list_c, to the var type 'INT' and to the initialiser '98' + * (as per the example above). + * + * 2) would have several sub-options to obtain the references + * to 'INT' and '98' from within var1_init_decl_c. + * In 2a), the var1_init_decl_c would use dynamic casts to determine + * the class of spec_init (simple_spec_init_c, subrange_spec_init_c or + * enumerated_spec_init_c), and from there obtain the 'INT' and '98' + * In 2b) var1_init_decl_c would have one reference for each + * simple_spec_init_c, subrange_spec_init_c and enumerated_spec_init_c, + * the apropriate one being initialised by the var1_init_decl_c constructor. + * Note that the constructor would use dynamic casts. In essence, we + * would merely be changing the location of the code with the + * dynamic casts. + * In 2c) we would use three overloaded constructors for var1_init_decl_c + * one each for simple_spec_init_c, etc... This implies + * use type specific pointers to each symbol in the bison + * parser, instead of simply using a symbol_c * for all symbols; + * + * In 3), we use two global but private variables with references to + * 'INT' and '98', that would be initiliased by the visitors to + * simple_spec_init_c, subrange_spec_init_c and enumerated_spec_init_c. + * The visitor to var1_list_c would then use the references in the global + * variables. + * + * I (Mario) have chosen to use 3). + */ + + /* Start off by setting the current_var_type_symbol and + * current_var_init_symbol private variables... + */ + update_type_init(symbol->spec_init); + + /* now to produce the c equivalent... */ + symbol->var1_list->accept(*this); + + /* Values no longer in scope, and therefore no longer used. + * Make an effort to keep them set to NULL when not in use + * in order to catch bugs as soon as possible... + */ + void_type_init(); + + return NULL; +} + + + +void *visit(var1_list_c *symbol) { + TRACE("var1_list_c"); + declare_variables(symbol); + return NULL; +} + + + + +/* intermediate helper symbol for: + * - non_retentive_var_decls + * - output_declarations + */ +void *visit(var_init_decl_list_c *symbol) { + TRACE("var_init_decl_list_c"); + return print_list(symbol); + return NULL; +} + + +/**************************************/ +/* B.1.5 - Program organization units */ +/**************************************/ +/***********************/ +/* B 1.5.1 - Functions */ +/***********************/ +/* The missing function_declaration_c + * is handled in derived classes + */ + + + +/* intermediate helper symbol for function_declaration */ +void *visit(var_declarations_list_c *symbol) { + TRACE("var_declarations_list_c"); + return print_list(symbol); +} + + +void *visit(function_var_decls_c *symbol) { + TRACE("function_var_decls_c"); + + if ((wanted_vartype & private_vt) != 0) { +/* + // TO DO ... + if (symbol->option != NULL) + symbol->option->accept(*this); +*/ + current_vartype = private_vt; + symbol->decl_list->accept(*this); + current_vartype = none_vt; + } + return NULL; +} + + +/* intermediate helper symbol for function_var_decls */ +void *visit(var2_init_decl_list_c *symbol) { + TRACE("var2_init_decl_list_c"); + print_list(symbol); + return NULL; +} + + +/*****************************/ +/* B 1.5.2 - Function Blocks */ +/*****************************/ + +/* The missing function_block_declaration_c + * is handled in derived classes + */ + + +/* VAR_TEMP temp_var_decl_list END_VAR */ +void *visit(temp_var_decls_c *symbol) { + TRACE("temp_var_decls_c"); + if ((wanted_vartype & temp_vt) != 0) { + current_vartype = temp_vt; + symbol->var_decl_list->accept(*this); + current_vartype = none_vt; + } + return NULL; +} + +/* intermediate helper symbol for temp_var_decls */ +void *visit(temp_var_decls_list_c *symbol) { + TRACE("temp_var_decls_list_c"); + return print_list(symbol); +} + +/* VAR NON_RETAIN var_init_decl_list END_VAR */ +void *visit(non_retentive_var_decls_c *symbol) { + TRACE("non_retentive_var_decls_c"); + // TODO ... guarantee the non-retain semantics! + if ((wanted_vartype & private_vt) != 0) { + current_vartype = private_vt; + symbol->var_decl_list->accept(*this); + current_vartype = none_vt; + } + return NULL; +} + + + +/**********************/ +/* B 1.5.3 - Programs */ +/**********************/ + /* leave for derived classes... */ + +/*********************************************/ +/* B.1.6 Sequential function chart elements */ +/*********************************************/ + +/********************************/ +/* B 1.7 Configuration elements */ +/********************************/ + /* Programs instantiated inside configurations are declared as variables!! */ + +/* +CONFIGURATION configuration_name + optional_global_var_declarations + (resource_declaration_list | single_resource_declaration) + optional_access_declarations + optional_instance_specific_initializations +END_CONFIGURATION +*/ +/* +SYM_REF6(configuration_declaration_c, configuration_name, global_var_declarations, resource_declarations, access_declarations, instance_specific_initializations, unused) +*/ +void *visit(configuration_declaration_c *symbol) { + TRACE("configuration_declaration_c"); + + symbol->global_var_declarations->accept(*this); // will contain VAR_GLOBAL declarations!! + symbol->resource_declarations->accept(*this); // will contain PROGRAM declarations!! + return NULL; +} + + +/* helper symbol for configuration_declaration */ +// SYM_LIST(resource_declaration_list_c) +void *visit(resource_declaration_list_c *symbol) { + TRACE("resource_declaration_list_c"); + + return print_list(symbol); +} + +/* +RESOURCE resource_name ON resource_type_name + optional_global_var_declarations + single_resource_declaration +END_RESOURCE +*/ +// SYM_REF4(resource_declaration_c, resource_name, resource_type_name, global_var_declarations, resource_declaration) +void *visit(resource_declaration_c *symbol) { + TRACE("resource_declaration_c"); + + if ((wanted_vartype & resource_vt) != 0) { + s4o.print(s4o.indent_spaces + "struct {\n"); + s4o.indent_right(); + + current_vartype = resource_vt; + if (NULL != symbol->global_var_declarations) + symbol->global_var_declarations->accept(*this); // will contain VAR_GLOBAL declarations!! + if (NULL != symbol->resource_declaration) + symbol->resource_declaration->accept(*this); // will contain PROGRAM declarations!! + current_vartype = none_vt; + + s4o.indent_left(); + s4o.print(s4o.indent_spaces + "} "); + symbol->resource_name->accept(*this); + s4o.print(";\n"); + } + return NULL; +} + +/* task_configuration_list program_configuration_list */ +// SYM_REF2(single_resource_declaration_c, task_configuration_list, program_configuration_list) +void *visit(single_resource_declaration_c *symbol) { + TRACE("single_resource_declaration_c"); + + if ((wanted_vartype & program_vt) != 0) { + unsigned int previous_vartype = current_vartype; + // previous_vartype will be resource_vt + current_vartype = program_vt; + symbol->program_configuration_list->accept(*this); + current_vartype = previous_vartype; + } + return NULL; +} + + +/* helper symbol for single_resource_declaration */ +// SYM_LIST(task_configuration_list_c) + + +/* helper symbol for single_resource_declaration */ +/* | program_configuration_list program_configuration ';' */ +// SYM_LIST(program_configuration_list_c) +void *visit(program_configuration_list_c *symbol) { + TRACE("program_configuration_list_c"); + + return print_list(symbol); +} + +/* helper symbol for + * - access_path + * - instance_specific_init + */ +// SYM_LIST(any_fb_name_list_c) + +/* [resource_name '.'] global_var_name ['.' structure_element_name] */ +// SYM_REF4(global_var_reference_c, resource_name, global_var_name, structure_element_name, unused) + +/* prev_declared_program_name '.' symbolic_variable */ +// SYM_REF2(program_output_reference_c, program_name, symbolic_variable) + +/* TASK task_name task_initialization */ +// SYM_REF2(task_configuration_c, task_name, task_initialization) + +/* '(' [SINGLE ASSIGN data_source ','] [INTERVAL ASSIGN data_source ','] PRIORITY ASSIGN integer ')' */ +// SYM_REF4(task_initialization_c, single_data_source, interval_data_source, priority_data_source, unused) + +/* PROGRAM [RETAIN | NON_RETAIN] program_name [WITH task_name] ':' program_type_name ['(' prog_conf_elements ')'] */ +// SYM_REF6(program_configuration_c, retain_option, program_name, task_name, program_type_name, prog_conf_elements, unused) +private: + /* a helper function to the program_configuration_c visitor... */ + void program_constructor_call(program_configuration_c *symbol) { + program_declaration_c *p_decl = program_type_symtable.find_value(symbol->program_type_name); + + if (p_decl == program_type_symtable.end_value()) + /* should never occur. The program being called MUST be in the symtable... */ + ERROR; + + symbol->program_name->accept(*this); + s4o.print("("); + + /* loop through each function parameter, find the value we should pass + * to it, and then output the c equivalent... + */ + function_param_iterator_c fp_iterator(p_decl); + function_call_param_iterator_c function_call_param_iterator(symbol); + identifier_c *param_name; + nv->push("", ", "); + for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) { + + symbol_c *param_type = fp_iterator.param_type(); + if (param_type == NULL) ERROR; + + function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction(); + + /* Get the value from a foo( = ) style call */ + symbol_c *param_value = function_call_param_iterator.search(param_name); + + switch (param_direction) { + case function_param_iterator_c::direction_in: + case function_param_iterator_c::direction_out: + case function_param_iterator_c::direction_inout: + /* ignore them all!! */ + break; + + case function_param_iterator_c::direction_extref: + if (param_value == NULL) + /* This is illegal in ST and IL languages. + * All variables declared in a VAR_EXTERNAL __must__ + * be initialised to reference a specific VAR_GLOBAL variable!! + * + * The semantic checker should have caught this, we check again just the + * same (especially since the semantic checker has not yet been written!). + */ + ERROR; + s4o.print(nv->get()); + s4o.print("&"); + param_value->accept(*this); + break; +#if 0 + if (param_value == NULL) { + /* no parameter value given, so we pass a previously declared temporary variable. */ + std::string *temp_var_name = temp_var_name_factory.new_name(); + s4o.print(*temp_var_name); + delete temp_var_name; + } else { + param_value->accept(*this); + } +#endif + break; + } /* switch */ + } /* for(...) */ + + // symbol->parameter_assignment->accept(*this); + s4o.print(")"); + nv->pop(); + return; +} + + +public: +void *visit(program_configuration_c *symbol) { + TRACE("program_configuration_c"); + + /* now to produce the c equivalent... */ + switch (wanted_varformat) { + case local_vf: + case localinit_vf: + s4o.print(s4o.indent_spaces); + symbol->program_type_name->accept(*this); + s4o.print(" "); + symbol->program_name->accept(*this); + if (wanted_varformat == localinit_vf) { + // TODO... + // program_call(symbol); + } + s4o.print(";\n"); + break; + + case constructorinit_vf: + s4o.print(nv->get()); + program_constructor_call(symbol); +/* + symbol->program_name->accept(*this); + s4o.print("("); + symbol->prog_conf_elements->accept(*this); + nv->pop(); + s4o.print(")"); +*/ + break; + + default: + ERROR; /* not supported, and not needed either... */ + } + + return NULL; +} + + + +/* prog_conf_elements ',' prog_conf_element */ +//SYM_LIST(prog_conf_elements_c) +void *visit(prog_conf_elements_c *symbol) { + TRACE("prog_conf_elements_c"); + + return print_list(symbol); +} + +/* fb_name WITH task_name */ +//SYM_REF2(fb_task_c, fb_name, task_name) +void *visit(fb_task_c *symbol) { + TRACE("fb_task_c"); + + /* TODO... + * + * NOTE: Not yet supported... + * We do not support allocating specific function blocks declared + * inside a program to be executed by a different task from the one + * already executing the program itself. + * This is mostly because I (Mario) simply do not understand the + * semantics the standard expects us to implement in this case. It is all + * very confusing, and very poorly defined in the standard! + */ + ERROR; + return NULL; +} + + + + + + + + + + + + + + + + + + + + + + + + + + + +/* any_symbolic_variable ASSIGN prog_data_source */ +// SYM_REF2(prog_cnxn_assign_c, symbolic_variable, prog_data_source) +void *visit(prog_cnxn_assign_c *symbol) { + TRACE("prog_cnxn_assign_c"); + + /* TODO... */ + return NULL; +} + +/* any_symbolic_variable SENDTO data_sink */ +// SYM_REF2(prog_cnxn_sendto_c, symbolic_variable, prog_data_source) +void *visit(prog_cnxn_sendto_c *symbol) { + TRACE("prog_cnxn_sendto_c"); + + /* TODO... */ + return NULL; +} + +#if 0 +/* VAR_CONFIG instance_specific_init_list END_VAR_BOGUS */ +SYM_REF2(instance_specific_initializations_c, instance_specific_init_list, unused) + +/* helper symbol for instance_specific_initializations */ +SYM_LIST(instance_specific_init_list_c) + +/* resource_name '.' program_name '.' {fb_name '.'} + ((variable_name [location] ':' located_var_spec_init) | (fb_name ':' fb_initialization)) +*/ +SYM_REF6(instance_specific_init_c, resource_name, program_name, any_fb_name_list, variable_name, location, initialization) + +/* helper symbol for instance_specific_init */ +/* function_block_type_name ':=' structure_initialization */ +SYM_REF2(fb_initialization_c, function_block_type_name, structure_initialization) + +#endif + + + + +/****************************************/ +/* B.2 - Language IL (Instruction List) */ +/****************************************/ +/***********************************/ +/* B 2.1 Instructions and Operands */ +/***********************************/ + /* leave for derived classes... */ + +/*******************/ +/* B 2.2 Operators */ +/*******************/ + /* leave for derived classes... */ + + +/***************************************/ +/* B.3 - Language ST (Structured Text) */ +/***************************************/ +/***********************/ +/* B 3.1 - Expressions */ +/***********************/ + /* leave for derived classes... */ + +/********************/ +/* B 3.2 Statements */ +/********************/ + /* leave for derived classes... */ + +/*********************************/ +/* B 3.2.1 Assignment Statements */ +/*********************************/ + /* leave for derived classes... */ + +/*****************************************/ +/* B 3.2.2 Subprogram Control Statements */ +/*****************************************/ + /* leave for derived classes... */ + +/********************************/ +/* B 3.2.3 Selection Statements */ +/********************************/ + /* leave for derived classes... */ + +/********************************/ +/* B 3.2.4 Iteration Statements */ +/********************************/ + /* leave for derived classes... */ + + + +}; /* generate_cc_vardecl_c */ + + +