etisserant@0: /* etisserant@0: * (c) 2003 Mario de Sousa etisserant@0: * etisserant@0: * Offered to the public under the terms of the GNU General Public License etisserant@0: * as published by the Free Software Foundation; either version 2 of the etisserant@0: * License, or (at your option) any later version. etisserant@0: * etisserant@0: * This program is distributed in the hope that it will be useful, but etisserant@0: * WITHOUT ANY WARRANTY; without even the implied warranty of etisserant@0: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General etisserant@0: * Public License for more details. etisserant@0: * etisserant@0: * This code is made available on the understanding that it will not be etisserant@0: * used in safety-critical situations without a full and competent review. etisserant@0: */ etisserant@0: etisserant@0: /* etisserant@0: * An IEC 61131-3 IL and ST compiler. etisserant@0: * etisserant@0: * Based on the etisserant@0: * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) etisserant@0: * etisserant@0: */ etisserant@0: etisserant@0: etisserant@0: /* etisserant@0: * This is one of the versions available for the 4th stage. etisserant@0: * etisserant@0: * This 4th stage generates a c++ source program equivalent etisserant@0: * to the IL and ST code. etisserant@0: */ etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: // #include /* required for NULL */ etisserant@0: #include etisserant@0: #include lbessard@16: #include etisserant@0: etisserant@0: #include "../../util/symtable.hh" etisserant@0: #include "../../util/dsymtable.hh" etisserant@0: #include "../../absyntax/visitor.hh" etisserant@0: etisserant@0: #include "../stage4.hh" etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: //#define DEBUG etisserant@0: #ifdef DEBUG etisserant@0: #define TRACE(classname) printf("\n____%s____\n",classname); etisserant@0: #else etisserant@0: #define TRACE(classname) etisserant@0: #endif etisserant@0: etisserant@0: etisserant@0: etisserant@0: #define ERROR error_exit(__FILE__,__LINE__) etisserant@0: /* function defined in main.cc */ etisserant@0: extern void error_exit(const char *file_name, int line_no); etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /* A symbol table with all globally declared functions... */ etisserant@0: function_declaration_c null_symbol1(NULL,NULL,NULL,NULL); etisserant@0: dsymtable_c function_symtable; etisserant@0: etisserant@0: /* A symbol table with all globally declared functions block types... */ etisserant@0: function_block_declaration_c null_symbol2(NULL,NULL,NULL,NULL); etisserant@0: symtable_c function_block_type_symtable; etisserant@0: etisserant@0: /* A symbol table with all globally declared program types... */ etisserant@0: program_declaration_c null_symbol3(NULL,NULL,NULL,NULL); etisserant@0: symtable_c program_type_symtable; etisserant@0: etisserant@0: /* A symbol table with all user declared type definitions... */ etisserant@0: /* Note that function block types and program types have their etisserant@0: * own symbol tables, so do not get placed in this symbol table! etisserant@0: */ etisserant@0: symbol_c null_symbol4; etisserant@0: symtable_c type_symtable; etisserant@0: etisserant@0: etisserant@0: etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: etisserant@0: etisserant@0: /* returns 0 if the names are equal!! */ etisserant@0: /* NOTE: it must ignore case!! */ etisserant@0: static int compare_identifiers(symbol_c *ident1, symbol_c *ident2) { etisserant@0: etisserant@0: identifier_c *name1 = dynamic_cast(ident1); etisserant@0: identifier_c *name2 = dynamic_cast(ident2); etisserant@0: etisserant@0: if ((name1 == NULL) || (name2 == NULL)) etisserant@0: /* invalid identifiers... */ etisserant@0: return -1; etisserant@0: etisserant@0: if (strcasecmp(name1->value, name2->value) == 0) etisserant@0: return 0; etisserant@0: etisserant@0: /* identifiers do not match! */ etisserant@0: return 1; etisserant@0: } etisserant@0: etisserant@0: etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: etisserant@0: /* Unlike Programs and Configurations which get mapped onto C++ classes, etisserant@0: * Function Blocks are mapped onto a C structure containing the variables, and etisserant@0: * a C function containing the code in the FB's body. This is to allow direct allocation etisserant@0: * of a FB variable (which is really an instance of the C data structure) to etisserant@0: * a member of a union variable (note that classes with constructors cannot etisserant@0: * be mebers of a union), which is done in IL when loading a FB onto IL's etisserant@0: * default variable. etisserant@0: * etisserant@0: * So as not to clash the names of the C data structure and the C function, etisserant@0: * the C structure is given a name identical to that of the FB name, whereas etisserant@0: * the name of the function is the FB name with a constant string appended. etisserant@0: * The value of that constant string which is appended is defined in the following etisserant@0: * constant. etisserant@0: * In order not to clash with any variable in the IL and ST source codem the etisserant@0: * following constant should contain a double underscore, which is not allowed etisserant@0: * in IL and ST. etisserant@0: * etisserant@0: * e.g.: FUNTION_BLOCK TEST etisserant@0: * is mapped onto a TEST data structure, and a TEST_body__ function. etisserant@0: */ etisserant@0: etisserant@0: #define FB_FUNCTION_SUFFIX "_body__" etisserant@0: etisserant@0: /* The FB body function is passed as the only parameter a pointer to the FB data lbessard@18: * structure instance. The name of this parameter is given by the following constant. etisserant@0: * In order not to clash with any variable in the IL and ST source codem the etisserant@0: * following constant should contain a double underscore, which is not allowed etisserant@0: * in IL and ST. etisserant@0: * etisserant@0: * e.g.: the body of FUNTION_BLOCK TEST etisserant@0: * is mapped onto the C function etisserant@0: * TEST_body__(TEST *data__) etisserant@0: */ etisserant@0: etisserant@0: #define FB_FUNCTION_PARAM "data__" etisserant@0: etisserant@0: lbessard@18: #define SFC_STEP_ACTION_PREFIX "__SFC_" lbessard@18: lbessard@18: etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: etisserant@0: etisserant@0: #include "spec_init_separator.cc" etisserant@0: #include "function_param_iterator.cc" etisserant@0: #include "function_call_iterator.cc" etisserant@0: #include "function_call_param_iterator.cc" etisserant@0: #include "type_initial_value.cc" etisserant@0: #include "search_fb_instance_decl.cc" etisserant@0: #include "search_base_type.cc" etisserant@0: #include "search_var_instance_decl.cc" etisserant@0: #include "decompose_var_instance_name.cc" etisserant@0: #include "search_varfb_instance_type.cc" etisserant@0: #include "search_constant_type.cc" lbessard@16: #include "search_expression_type.cc" etisserant@0: etisserant@0: #include "generate_cc_base.cc" lbessard@17: #include "generate_cc_sfcdecl.cc" etisserant@0: #include "generate_cc_typedecl.cc" etisserant@0: #include "generate_cc_vardecl.cc" etisserant@0: #include "generate_cc_configbody.cc" etisserant@0: etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: etisserant@0: /* Generate a name for a temporary variable. etisserant@0: * Each new name generated is appended a different number, etisserant@0: * starting off from 0. etisserant@0: * After calling reset(), the names will start off again from 0. etisserant@0: */ etisserant@0: #define VAR_LEADER "__" etisserant@0: #define TEMP_VAR VAR_LEADER "TMP_" etisserant@0: #define SOURCE_VAR VAR_LEADER "SRC_" etisserant@0: etisserant@0: #include "generate_cc_tempvardecl.cc" etisserant@0: etisserant@0: #include "generate_cc_st.cc" etisserant@0: #include "generate_cc_il.cc" etisserant@0: etisserant@0: #include "generate_cc.hh" etisserant@0: etisserant@0: etisserant@0: etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: etisserant@0: /* A helper class that knows how to generate code for both the IL and ST languages... */ lbessard@17: class generate_cc_SFC_IL_ST_c: public null_visitor_c { etisserant@0: private: etisserant@0: stage4out_c *s4o_ptr; etisserant@0: symbol_c *scope; etisserant@0: const char *variable_prefix; etisserant@0: etisserant@0: public: lbessard@17: generate_cc_SFC_IL_ST_c(stage4out_c *s4o_ptr, symbol_c *scope, const char *variable_prefix = NULL); lbessard@17: /*********************************************/ lbessard@17: /* B.1.6 Sequential function chart elements */ lbessard@17: /*********************************************/ lbessard@17: lbessard@17: /*| sequential_function_chart sfc_network*/ lbessard@17: void *visit(sequential_function_chart_c * symbol); lbessard@17: lbessard@17: /****************************************/ lbessard@17: /* B.2 - Language IL (Instruction List) */ lbessard@17: /****************************************/ lbessard@17: lbessard@17: /***********************************/ lbessard@17: /* B 2.1 Instructions and Operands */ lbessard@17: /***********************************/ lbessard@17: /*| instruction_list il_instruction */ lbessard@17: void *visit(instruction_list_c *symbol); lbessard@17: lbessard@17: /* Remainder implemented in generate_cc_il_c... */ lbessard@17: lbessard@17: /***************************************/ lbessard@17: /* B.3 - Language ST (Structured Text) */ lbessard@17: /***************************************/ lbessard@17: /***********************/ lbessard@17: /* B 3.1 - Expressions */ lbessard@17: /***********************/ lbessard@17: /* Implemented in generate_cc_st_c */ lbessard@17: lbessard@17: /********************/ lbessard@17: /* B 3.2 Statements */ lbessard@17: /********************/ lbessard@17: void *visit(statement_list_c *symbol); lbessard@17: lbessard@17: /* Remainder implemented in generate_cc_st_c... */ lbessard@17: }; lbessard@17: lbessard@17: #include "generate_cc_sfc.cc" lbessard@17: lbessard@17: generate_cc_SFC_IL_ST_c::generate_cc_SFC_IL_ST_c(stage4out_c *s4o_ptr, symbol_c *scope, const char *variable_prefix) { lbessard@17: if (NULL == scope) ERROR; lbessard@17: this->s4o_ptr = s4o_ptr; lbessard@17: this->scope = scope; lbessard@17: this->variable_prefix = variable_prefix; lbessard@17: } lbessard@17: lbessard@17: void *generate_cc_SFC_IL_ST_c::visit(sequential_function_chart_c * symbol) { lbessard@17: generate_cc_sfc_c generate_cc_sfc(s4o_ptr, scope, variable_prefix); lbessard@17: generate_cc_sfc.generate(symbol); lbessard@17: return NULL; lbessard@17: } lbessard@17: lbessard@17: void *generate_cc_SFC_IL_ST_c::visit(instruction_list_c *symbol) { etisserant@0: generate_cc_il_c generate_cc_il(s4o_ptr, scope, variable_prefix); etisserant@0: generate_cc_il.generate(symbol); etisserant@0: return NULL; etisserant@0: } etisserant@0: lbessard@17: void *generate_cc_SFC_IL_ST_c::visit(statement_list_c *symbol) { etisserant@0: generate_cc_st_c generate_cc_st(s4o_ptr, scope, variable_prefix); etisserant@0: generate_cc_st.generate(symbol); etisserant@0: return NULL; etisserant@0: } etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: etisserant@0: etisserant@0: class generate_cc_c: public generate_cc_typedecl_c { etisserant@0: etisserant@0: public: etisserant@0: generate_cc_c(stage4out_c *s4o_ptr) etisserant@0: : generate_cc_typedecl_c(s4o_ptr) {}; etisserant@0: virtual ~generate_cc_c(void) {} etisserant@0: etisserant@0: etisserant@0: public: etisserant@0: /***************************/ etisserant@0: /* B 0 - Programming Model */ etisserant@0: /***************************/ etisserant@0: void *visit(library_c *symbol) { etisserant@0: TRACE("library_c"); etisserant@0: etisserant@0: /* Insert the header... */ etisserant@0: s4o.print("/*******************************************/\n"); etisserant@0: s4o.print("/* FILE GENERATED BY iec2cc */\n"); etisserant@0: s4o.print("/* Editing this file is not recommended... */\n"); etisserant@0: s4o.print("/*******************************************/\n"); etisserant@0: s4o.print("\n\n\n\n\n"); etisserant@0: s4o.print("#include \"plciec.h\"\n"); etisserant@0: s4o.print("\n\n\n\n\n"); etisserant@0: etisserant@0: /* now do the actual code... */ etisserant@0: print_list(symbol); etisserant@0: s4o.print("\n\n"); etisserant@0: etisserant@0: /* Finish off with the main() */ etisserant@0: s4o.print("#include \"plciec.cc\"\n"); etisserant@0: s4o.print("\n\n"); etisserant@0: etisserant@0: // function_symtable.print(); etisserant@0: return NULL; etisserant@0: } etisserant@0: etisserant@0: /*************************/ etisserant@0: /* B.1 - Common elements */ etisserant@0: /*************************/ etisserant@0: /*******************************************/ etisserant@0: /* B 1.1 - Letters, digits and identifiers */ etisserant@0: /*******************************************/ etisserant@0: /* done in base class(es) */ etisserant@0: etisserant@0: /*********************/ etisserant@0: /* B 1.2 - Constants */ etisserant@0: /*********************/ etisserant@0: /* originally empty... */ etisserant@0: etisserant@0: /******************************/ etisserant@0: /* B 1.2.1 - Numeric Literals */ etisserant@0: /******************************/ etisserant@0: /* done in base class(es) */ etisserant@0: etisserant@0: /*******************************/ etisserant@0: /* B.1.2.2 Character Strings */ etisserant@0: /*******************************/ etisserant@0: /* done in base class(es) */ etisserant@0: etisserant@0: /***************************/ etisserant@0: /* B 1.2.3 - Time Literals */ etisserant@0: /***************************/ etisserant@0: /************************/ etisserant@0: /* B 1.2.3.1 - Duration */ etisserant@0: /************************/ etisserant@0: /* done in base class(es) */ etisserant@0: etisserant@0: /************************************/ etisserant@0: /* B 1.2.3.2 - Time of day and Date */ etisserant@0: /************************************/ etisserant@0: /* done in base class(es) */ etisserant@0: etisserant@0: /**********************/ etisserant@0: /* B.1.3 - Data types */ etisserant@0: /**********************/ etisserant@0: /***********************************/ etisserant@0: /* B 1.3.1 - Elementary Data Types */ etisserant@0: /***********************************/ etisserant@0: /* done in base class(es) */ etisserant@0: etisserant@0: /********************************/ etisserant@0: /* B.1.3.2 - Generic data types */ etisserant@0: /********************************/ etisserant@0: /* originally empty... */ etisserant@0: etisserant@0: /********************************/ etisserant@0: /* B 1.3.3 - Derived data types */ etisserant@0: /********************************/ etisserant@0: /* done in base class(es) */ etisserant@0: etisserant@0: /*********************/ etisserant@0: /* B 1.4 - Variables */ etisserant@0: /*********************/ etisserant@0: /* done in base class(es) */ etisserant@0: etisserant@0: /********************************************/ etisserant@0: /* B.1.4.1 Directly Represented Variables */ etisserant@0: /********************************************/ etisserant@0: /* done in base class(es) */ etisserant@0: etisserant@0: /*************************************/ etisserant@0: /* B.1.4.2 Multi-element Variables */ etisserant@0: /*************************************/ etisserant@0: /* done in base class(es) */ etisserant@0: etisserant@0: /******************************************/ etisserant@0: /* B 1.4.3 - Declaration & Initialisation */ etisserant@0: /******************************************/ etisserant@0: /* done in base class(es) */ etisserant@0: etisserant@0: /**************************************/ etisserant@0: /* B.1.5 - Program organization units */ etisserant@0: /**************************************/ etisserant@0: /***********************/ etisserant@0: /* B 1.5.1 - Functions */ etisserant@0: /***********************/ etisserant@0: etisserant@0: public: etisserant@0: /* FUNCTION derived_function_name ':' elementary_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ etisserant@0: /* | FUNCTION derived_function_name ':' derived_type_name io_OR_function_var_declarations_list function_body END_FUNCTION */ etisserant@0: void *visit(function_declaration_c *symbol) { etisserant@0: generate_cc_vardecl_c *vardecl; etisserant@0: TRACE("function_declaration_c"); etisserant@0: etisserant@0: /* start off by adding this declaration to the global etisserant@0: * function declaration symbol table... etisserant@0: */ etisserant@0: function_symtable.insert(symbol->derived_function_name, symbol); etisserant@0: etisserant@0: /* (A) Function declaration... */ etisserant@0: /* (A.1) Function return type */ etisserant@0: s4o.print("// FUNCTION\n"); etisserant@0: symbol->type_name->accept(*this); /* return type */ etisserant@0: s4o.print(" "); etisserant@0: /* (A.2) Function name */ etisserant@0: symbol->derived_function_name->accept(*this); etisserant@0: s4o.print("("); etisserant@0: etisserant@0: /* (A.3) Function parameters */ etisserant@0: s4o.indent_right(); etisserant@0: vardecl = new generate_cc_vardecl_c(&s4o, etisserant@0: generate_cc_vardecl_c::finterface_vf, etisserant@0: generate_cc_vardecl_c::input_vt | etisserant@0: generate_cc_vardecl_c::output_vt | etisserant@0: generate_cc_vardecl_c::inoutput_vt); etisserant@0: vardecl->print(symbol->var_declarations_list); etisserant@0: delete vardecl; etisserant@0: s4o.indent_left(); etisserant@0: etisserant@0: s4o.print(")\n" + s4o.indent_spaces + "{\n"); etisserant@0: etisserant@0: /* (B) Function local variable declaration */ etisserant@0: /* (B.1) Variables declared in ST source code */ etisserant@0: s4o.indent_right(); etisserant@0: vardecl = new generate_cc_vardecl_c(&s4o, generate_cc_vardecl_c::localinit_vf, generate_cc_vardecl_c::private_vt); etisserant@0: vardecl->print(symbol->var_declarations_list); etisserant@0: delete vardecl; etisserant@0: etisserant@0: /* (B.2) Temporary variable for function's return value */ etisserant@0: /* It will have the same name as the function itself! */ etisserant@0: s4o.print(s4o.indent_spaces); etisserant@0: symbol->type_name->accept(*this); /* return type */ etisserant@0: s4o.print(" "); etisserant@0: symbol->derived_function_name->accept(*this); etisserant@0: s4o.print(" = "); etisserant@0: { etisserant@0: /* get the default value of this variable's type */ etisserant@0: symbol_c *default_value = (symbol_c *)symbol->type_name->accept(*type_initial_value_c::instance()); etisserant@0: if (default_value == NULL) ERROR; etisserant@0: default_value->accept(*this); etisserant@0: } etisserant@0: s4o.print(";\n\n"); etisserant@0: etisserant@0: /* (C) Function body */ lbessard@17: generate_cc_SFC_IL_ST_c generate_cc_code(&s4o, symbol); etisserant@0: symbol->function_body->accept(generate_cc_code); etisserant@0: s4o.print(s4o.indent_spaces + "return "); etisserant@0: symbol->derived_function_name->accept(*this); etisserant@0: s4o.print(";\n"); etisserant@0: s4o.indent_left(); etisserant@0: s4o.print(s4o.indent_spaces + "}\n\n\n"); etisserant@0: etisserant@0: return NULL; etisserant@0: } etisserant@0: etisserant@0: etisserant@0: /* The remaining var_declarations_list_c, function_var_decls_c etisserant@0: * and var2_init_decl_list_c are handled in the generate_cc_vardecl_c class etisserant@0: */ etisserant@0: etisserant@0: etisserant@0: /*****************************/ etisserant@0: /* B 1.5.2 - Function Blocks */ etisserant@0: /*****************************/ etisserant@0: public: etisserant@0: /* FUNCTION_BLOCK derived_function_block_name io_OR_other_var_declarations function_block_body END_FUNCTION_BLOCK */ etisserant@0: //SYM_REF4(function_block_declaration_c, fblock_name, var_declarations, fblock_body, unused) etisserant@0: void *visit(function_block_declaration_c *symbol) { etisserant@0: generate_cc_vardecl_c *vardecl; etisserant@0: TRACE("function_block_declaration_c"); etisserant@0: etisserant@0: /* start off by adding this declaration to the global etisserant@0: * function block declaration symbol table... etisserant@0: */ etisserant@0: function_block_type_symtable.insert(symbol->fblock_name, symbol); etisserant@0: etisserant@0: /* (A) Function Block data structure declaration... */ etisserant@0: /* (A.1) Data structure declaration */ etisserant@0: s4o.print("// FUNCTION_BLOCK "); etisserant@0: symbol->fblock_name->accept(*this); etisserant@0: s4o.print("\n// Data part\n"); etisserant@0: s4o.print("typedef struct {\n"); etisserant@0: s4o.indent_right(); etisserant@0: /* (A.2) Public variables: i.e. the function parameters... */ etisserant@0: s4o.print(s4o.indent_spaces + "// FB Interface - IN, OUT, IN_OUT variables\n"); etisserant@0: vardecl = new generate_cc_vardecl_c(&s4o, etisserant@0: generate_cc_vardecl_c::local_vf, etisserant@0: generate_cc_vardecl_c::input_vt | etisserant@0: generate_cc_vardecl_c::output_vt | etisserant@0: generate_cc_vardecl_c::inoutput_vt); etisserant@0: vardecl->print(symbol->var_declarations); etisserant@0: delete vardecl; etisserant@0: s4o.print("\n"); etisserant@0: /* (A.3) Private internal variables */ etisserant@0: s4o.print(s4o.indent_spaces + "// FB private variables - TEMP, private and located variables\n"); etisserant@0: vardecl = new generate_cc_vardecl_c(&s4o, etisserant@0: generate_cc_vardecl_c::local_vf, lbessard@18: generate_cc_vardecl_c::temp_vt | etisserant@0: generate_cc_vardecl_c::private_vt | etisserant@0: generate_cc_vardecl_c::located_vt); etisserant@0: vardecl->print(symbol->var_declarations); etisserant@0: delete vardecl; etisserant@0: s4o.print("\n"); etisserant@0: etisserant@0: /* (A.4) Function Block data structure type name. */ etisserant@0: s4o.indent_left(); etisserant@0: s4o.print("} "); etisserant@0: symbol->fblock_name->accept(*this); etisserant@0: s4o.print(";\n\n"); etisserant@0: etisserant@0: etisserant@0: /* (B) Function with FB body */ etisserant@0: /* (B.1) Function declaration */ etisserant@0: s4o.print("// Code part\n"); etisserant@0: /* function interface */ etisserant@0: s4o.print("void "); etisserant@0: symbol->fblock_name->accept(*this); etisserant@0: s4o.print(FB_FUNCTION_SUFFIX); etisserant@0: s4o.print("("); lbessard@16: /* first and only parameter is a pointer to the data */ etisserant@0: symbol->fblock_name->accept(*this); etisserant@0: s4o.print(" *"); etisserant@0: s4o.print(FB_FUNCTION_PARAM); etisserant@0: s4o.print(") {\n"); etisserant@0: s4o.indent_right(); etisserant@0: etisserant@0: /* (B.2) Initialize TEMP variables */ etisserant@0: /* function body */ etisserant@0: s4o.print(s4o.indent_spaces + "// Initialise TEMP variables\n"); etisserant@0: vardecl = new generate_cc_vardecl_c(&s4o, etisserant@0: generate_cc_vardecl_c::init_vf, etisserant@0: generate_cc_vardecl_c::temp_vt); etisserant@0: vardecl->print(symbol->var_declarations, NULL, FB_FUNCTION_PARAM"->"); etisserant@0: delete vardecl; etisserant@0: s4o.print("\n"); etisserant@0: etisserant@0: /* (B.3) Function code */ lbessard@17: generate_cc_SFC_IL_ST_c generate_cc_code(&s4o, symbol, FB_FUNCTION_PARAM"->"); etisserant@0: symbol->fblock_body->accept(generate_cc_code); etisserant@0: s4o.indent_left(); etisserant@0: s4o.print(s4o.indent_spaces + "} // "); etisserant@0: symbol->fblock_name->accept(*this); etisserant@0: s4o.print(FB_FUNCTION_SUFFIX); etisserant@0: s4o.print(s4o.indent_spaces + "() \n\n"); etisserant@0: lbessard@16: s4o.indent_left(); lbessard@16: s4o.print("\n\n\n\n"); lbessard@16: lbessard@16: return NULL; lbessard@16: } lbessard@16: lbessard@16: lbessard@16: /* The remaining temp_var_decls_c, temp_var_decls_list_c lbessard@16: * and non_retentive_var_decls_c are handled in the generate_cc_vardecl_c class lbessard@16: */ lbessard@16: lbessard@16: lbessard@16: /**********************/ lbessard@16: /* B 1.5.3 - Programs */ lbessard@16: /**********************/ lbessard@16: lbessard@16: lbessard@16: lbessard@16: public: lbessard@16: /* PROGRAM program_type_name program_var_declarations_list function_block_body END_PROGRAM */ lbessard@16: //SYM_REF4(program_declaration_c, program_type_name, var_declarations, function_block_body, unused) lbessard@16: void *visit(program_declaration_c *symbol) { lbessard@16: generate_cc_vardecl_c *vardecl; lbessard@16: TRACE("program_declaration_c"); lbessard@16: lbessard@16: /* start off by adding this declaration to the global lbessard@16: * program declaration symbol table... lbessard@16: */ lbessard@16: program_type_symtable.insert(symbol->program_type_name, symbol); lbessard@16: lbessard@16: /* (A) Program data structure declaration... */ lbessard@16: /* (A.1) Data structure declaration */ lbessard@16: s4o.print("// PROGRAM "); lbessard@16: symbol->program_type_name->accept(*this); lbessard@16: s4o.print("\n// Data part\n"); lbessard@16: s4o.print("typedef struct {\n"); lbessard@16: s4o.indent_right(); lbessard@16: lbessard@16: /* (A.2) Public variables: i.e. the program parameters... */ lbessard@16: s4o.print(s4o.indent_spaces + "// PROGRAM Interface - IN, OUT, IN_OUT variables\n"); etisserant@0: vardecl = new generate_cc_vardecl_c(&s4o, etisserant@0: generate_cc_vardecl_c::local_vf, etisserant@0: generate_cc_vardecl_c::input_vt | etisserant@0: generate_cc_vardecl_c::output_vt | etisserant@0: generate_cc_vardecl_c::inoutput_vt); etisserant@0: vardecl->print(symbol->var_declarations); etisserant@0: delete vardecl; etisserant@0: s4o.print("\n"); etisserant@0: /* (A.3) Private internal variables */ lbessard@16: s4o.print(s4o.indent_spaces + "// PROGRAM private variables - TEMP, private and located variables\n"); etisserant@0: vardecl = new generate_cc_vardecl_c(&s4o, lbessard@17: generate_cc_vardecl_c::local_vf, lbessard@17: generate_cc_vardecl_c::temp_vt | lbessard@17: generate_cc_vardecl_c::private_vt | lbessard@17: generate_cc_vardecl_c::located_vt | lbessard@17: generate_cc_vardecl_c::external_vt); etisserant@0: vardecl->print(symbol->var_declarations); etisserant@0: delete vardecl; lbessard@18: /* (A.4) Generate private internal variables for SFC */ lbessard@18: generate_cc_sfctables_c generate_cc_sfctables(&s4o); lbessard@18: symbol->function_block_body->accept(generate_cc_sfctables); lbessard@16: s4o.print("\n"); lbessard@16: lbessard@17: /* (A.5) Program data structure type name. */ tib@12: s4o.indent_left(); tib@12: s4o.print("} "); tib@12: symbol->program_type_name->accept(*this); lbessard@16: s4o.print(";\n\n"); lbessard@16: lbessard@16: /* (B) Function with PROGRAM body */ lbessard@18: /* (B.1) Step and Action definitions */ lbessard@18: generate_cc_sfcdecl_c generate_cc_sfcdecl(&s4o); lbessard@18: symbol->function_block_body->accept(generate_cc_sfcdecl); lbessard@18: lbessard@18: /* (B.2) Function declaration */ lbessard@16: s4o.print("// Code part\n"); lbessard@16: /* function interface */ tib@12: s4o.print("void "); etisserant@0: symbol->program_type_name->accept(*this); tib@12: s4o.print(FB_FUNCTION_SUFFIX); etisserant@0: s4o.print("("); lbessard@16: /* first and only parameter is a pointer to the data */ tib@12: symbol->program_type_name->accept(*this); lbessard@16: s4o.print(" *"); lbessard@16: s4o.print(FB_FUNCTION_PARAM); lbessard@16: s4o.print(") {\n"); lbessard@16: s4o.indent_right(); lbessard@16: lbessard@18: /* (B.3) Initialize TEMP variables */ lbessard@16: /* function body */ lbessard@16: s4o.print(s4o.indent_spaces + "// Initialise TEMP variables\n"); etisserant@0: vardecl = new generate_cc_vardecl_c(&s4o, lbessard@16: generate_cc_vardecl_c::init_vf, lbessard@16: generate_cc_vardecl_c::temp_vt); lbessard@16: vardecl->print(symbol->var_declarations, NULL, FB_FUNCTION_PARAM"->"); lbessard@16: delete vardecl; etisserant@0: s4o.print("\n"); etisserant@0: lbessard@18: /* (B.4) Function code */ lbessard@17: generate_cc_SFC_IL_ST_c generate_cc_code(&s4o, symbol, FB_FUNCTION_PARAM"->"); etisserant@0: symbol->function_block_body->accept(generate_cc_code); etisserant@0: s4o.indent_left(); lbessard@16: s4o.print(s4o.indent_spaces + "} // "); tib@12: symbol->program_type_name->accept(*this); tib@12: s4o.print(FB_FUNCTION_SUFFIX); lbessard@16: s4o.print(s4o.indent_spaces + "() \n\n"); lbessard@16: lbessard@18: /* (B.5) Step and Action undefinitions */ lbessard@18: generate_cc_sfcundecl_c generate_cc_sfcundecl(&s4o); lbessard@18: symbol->function_block_body->accept(generate_cc_sfcundecl); lbessard@18: lbessard@16: s4o.indent_left(); etisserant@0: s4o.print("\n\n\n\n"); etisserant@0: etisserant@0: return NULL; etisserant@0: } etisserant@0: etisserant@0: etisserant@0: /* intermediate helper symbol for program_declaration_c */ etisserant@0: /* { io_var_declarations | other_var_declarations } */ etisserant@0: /* etisserant@0: * NOTE: we re-use the var_declarations_list_c etisserant@0: */ etisserant@0: etisserant@0: /*********************************************/ etisserant@0: /* B.1.6 Sequential function chart elements */ etisserant@0: /*********************************************/ etisserant@0: etisserant@0: /********************************/ etisserant@0: /* B 1.7 Configuration elements */ etisserant@0: /********************************/ etisserant@0: etisserant@0: etisserant@0: public: etisserant@0: /* etisserant@0: CONFIGURATION configuration_name etisserant@0: optional_global_var_declarations etisserant@0: (resource_declaration_list | single_resource_declaration) etisserant@0: optional_access_declarations etisserant@0: optional_instance_specific_initializations etisserant@0: END_CONFIGURATION etisserant@0: */ etisserant@0: /* etisserant@0: SYM_REF6(configuration_declaration_c, configuration_name, global_var_declarations, resource_declarations, access_declarations, instance_specific_initializations, unused) etisserant@0: */ etisserant@0: void *visit(configuration_declaration_c *symbol) { etisserant@0: static int configuration_count = 0; etisserant@0: generate_cc_vardecl_c *vardecl; etisserant@0: TRACE("configuration_declaration_c"); etisserant@0: etisserant@0: configuration_count++; etisserant@0: if (configuration_count == 1) { etisserant@0: /* the first configuration is the one we will use!! */ etisserant@0: s4o.print("#define __configuration_c "); etisserant@0: symbol->configuration_name->accept(*this); etisserant@0: s4o.print("\n" + s4o.indent_spaces); etisserant@0: } etisserant@0: etisserant@0: /* (A) Class (__configuration) declaration... */ etisserant@0: /* (A.1) configuration name in comment */ etisserant@0: s4o.print("// CONFIGURATION\n" + s4o.indent_spaces); etisserant@0: s4o.print("class "); etisserant@0: symbol->configuration_name->accept(*this); etisserant@0: s4o.print(" {\n"); etisserant@0: s4o.indent_right(); etisserant@0: etisserant@0: /* (A.2) Global variables etisserant@0: * AND etisserant@0: * (A.3) Programs in the Configuration etisserant@0: */ etisserant@0: /* Programs types are mapped onto classes, etisserant@0: * and programs are then instantiated inside the configuration etisserant@0: * as objects of the appropriate class! etisserant@0: */ etisserant@0: s4o.print(s4o.indent_spaces + "private:\n"); etisserant@0: s4o.indent_right(); etisserant@0: vardecl = new generate_cc_vardecl_c(&s4o, etisserant@0: generate_cc_vardecl_c::local_vf, etisserant@0: generate_cc_vardecl_c::global_vt | etisserant@0: generate_cc_vardecl_c::program_vt | etisserant@0: generate_cc_vardecl_c::resource_vt); etisserant@0: vardecl->print(symbol); etisserant@0: delete vardecl; etisserant@0: s4o.indent_left(); etisserant@0: s4o.print("\n"); etisserant@0: etisserant@0: etisserant@0: etisserant@0: /* (B) Constructor */ etisserant@0: /* (B.1) Constructor name... */ etisserant@0: s4o.print(s4o.indent_spaces + "public:\n"); etisserant@0: s4o.indent_right(); etisserant@0: s4o.print(s4o.indent_spaces); etisserant@0: symbol->configuration_name->accept(*this); etisserant@0: s4o.print("(void)\n"); etisserant@0: etisserant@0: /* (B.2) Member initializations... */ etisserant@0: s4o.indent_right(); etisserant@0: s4o.print(s4o.indent_spaces); etisserant@0: vardecl = new generate_cc_vardecl_c(&s4o, etisserant@0: generate_cc_vardecl_c::constructorinit_vf, etisserant@0: generate_cc_vardecl_c::program_vt | etisserant@0: generate_cc_vardecl_c::global_vt | etisserant@0: generate_cc_vardecl_c::resource_vt); etisserant@0: vardecl->print(symbol); etisserant@0: delete vardecl; etisserant@0: etisserant@0: /* (B.3) Constructor Body... */ etisserant@0: s4o.print("\n" + s4o.indent_spaces + "{}\n\n"); etisserant@0: s4o.indent_left(); etisserant@0: s4o.indent_left(); etisserant@0: etisserant@0: /* (C) Public Function*/ etisserant@0: /* (C.1) Public Function declaration */ etisserant@0: s4o.print(s4o.indent_spaces + "public:\n"); etisserant@0: s4o.indent_right(); etisserant@0: s4o.print(s4o.indent_spaces + "void run(void) {\n"); etisserant@0: etisserant@0: /* (C.2) Public Function body */ etisserant@0: /* Invoke each program in the configuration */ etisserant@0: s4o.indent_right(); etisserant@0: generate_cc_configbody_c *configbody = new generate_cc_configbody_c(&s4o); etisserant@0: symbol->accept(*configbody); etisserant@0: delete configbody; etisserant@0: s4o.indent_left(); etisserant@0: etisserant@0: /* (C.3) Close Public Function body */ etisserant@0: s4o.print(s4o.indent_spaces + "} /* f() */\n\n"); etisserant@0: s4o.indent_left(); etisserant@0: etisserant@0: /* (D) Close the class declaration... */ etisserant@0: s4o.indent_left(); etisserant@0: s4o.print(s4o.indent_spaces + "}; /* class "); etisserant@0: symbol->configuration_name->accept(*this); etisserant@0: s4o.print(" */\n\n\n"); etisserant@0: etisserant@0: return NULL; etisserant@0: } etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: #if 0 etisserant@0: etisserant@0: /* helper symbol for configuration_declaration */ etisserant@0: SYM_LIST(resource_declaration_list_c) etisserant@0: etisserant@0: /* etisserant@0: RESOURCE resource_name ON resource_type_name etisserant@0: optional_global_var_declarations etisserant@0: single_resource_declaration etisserant@0: END_RESOURCE etisserant@0: */ etisserant@0: SYM_REF4(resource_declaration_c, resource_name, resource_type_name, global_var_declarations, resource_declaration) etisserant@0: etisserant@0: /* task_configuration_list program_configuration_list */ etisserant@0: SYM_REF2(single_resource_declaration_c, task_configuration_list, program_configuration_list) etisserant@0: etisserant@0: /* helper symbol for single_resource_declaration */ etisserant@0: SYM_LIST(task_configuration_list_c) etisserant@0: etisserant@0: /* helper symbol for single_resource_declaration */ etisserant@0: SYM_LIST(program_configuration_list_c) etisserant@0: etisserant@0: /* helper symbol for etisserant@0: * - access_path etisserant@0: * - instance_specific_init etisserant@0: */ etisserant@0: SYM_LIST(any_fb_name_list_c) etisserant@0: etisserant@0: /* [resource_name '.'] global_var_name ['.' structure_element_name] */ etisserant@0: SYM_REF4(global_var_reference_c, resource_name, global_var_name, structure_element_name, unused) etisserant@0: etisserant@0: /* prev_declared_program_name '.' symbolic_variable */ etisserant@0: SYM_REF2(program_output_reference_c, program_name, symbolic_variable) etisserant@0: etisserant@0: /* TASK task_name task_initialization */ etisserant@0: SYM_REF2(task_configuration_c, task_name, task_initialization) etisserant@0: etisserant@0: /* '(' [SINGLE ASSIGN data_source ','] [INTERVAL ASSIGN data_source ','] PRIORITY ASSIGN integer ')' */ etisserant@0: SYM_REF4(task_initialization_c, single_data_source, interval_data_source, priority_data_source, unused) etisserant@0: etisserant@0: /* PROGRAM [RETAIN | NON_RETAIN] program_name [WITH task_name] ':' program_type_name ['(' prog_conf_elements ')'] */ etisserant@0: SYM_REF6(program_configuration_c, retain_option, program_name, task_name, program_type_name, prog_conf_elements, unused) etisserant@0: etisserant@0: /* prog_conf_elements ',' prog_conf_element */ etisserant@0: SYM_LIST(prog_conf_elements_c) etisserant@0: etisserant@0: /* fb_name WITH task_name */ etisserant@0: SYM_REF2(fb_task_c, fb_name, task_name) etisserant@0: etisserant@0: /* any_symbolic_variable ASSIGN prog_data_source */ etisserant@0: SYM_REF2(prog_cnxn_assign_c, symbolic_variable, prog_data_source) etisserant@0: etisserant@0: /* any_symbolic_variable SENDTO data_sink */ etisserant@0: SYM_REF2(prog_cnxn_sendto_c, symbolic_variable, prog_data_source) etisserant@0: etisserant@0: /* VAR_CONFIG instance_specific_init_list END_VAR_BOGUS */ etisserant@0: SYM_REF2(instance_specific_initializations_c, instance_specific_init_list, unused) etisserant@0: etisserant@0: /* helper symbol for instance_specific_initializations */ etisserant@0: SYM_LIST(instance_specific_init_list_c) etisserant@0: etisserant@0: /* resource_name '.' program_name '.' {fb_name '.'} etisserant@0: ((variable_name [location] ':' located_var_spec_init) | (fb_name ':' fb_initialization)) etisserant@0: */ etisserant@0: SYM_REF6(instance_specific_init_c, resource_name, program_name, any_fb_name_list, variable_name, location, initialization) etisserant@0: etisserant@0: /* helper symbol for instance_specific_init */ etisserant@0: /* function_block_type_name ':=' structure_initialization */ etisserant@0: SYM_REF2(fb_initialization_c, function_block_type_name, structure_initialization) etisserant@0: etisserant@0: #endif etisserant@0: etisserant@0: etisserant@0: }; /* generate_cc_c */ etisserant@0: etisserant@0: etisserant@0: etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: /***********************************************************************/ etisserant@0: etisserant@0: etisserant@0: etisserant@0: etisserant@0: visitor_c *new_code_generator(stage4out_c *s4o) {return new generate_cc_c(s4o);} etisserant@0: void delete_code_generator(visitor_c *code_generator) {delete code_generator;} etisserant@0: etisserant@0: