lbessard@70: /* lbessard@70: * (c) 2003 Mario de Sousa lbessard@70: * lbessard@70: * Offered to the public under the terms of the GNU General Public License lbessard@70: * as published by the Free Software Foundation; either version 2 of the lbessard@70: * License, or (at your option) any later version. lbessard@70: * lbessard@70: * This program is distributed in the hope that it will be useful, but lbessard@70: * WITHOUT ANY WARRANTY; without even the implied warranty of lbessard@70: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General lbessard@70: * Public License for more details. lbessard@70: * lbessard@70: * This code is made available on the understanding that it will not be lbessard@70: * used in safety-critical situations without a full and competent review. lbessard@70: */ lbessard@70: lbessard@70: /* lbessard@70: * An IEC 61131-3 IL and ST compiler. lbessard@70: * lbessard@70: * Based on the lbessard@70: * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10) lbessard@70: * lbessard@70: */ lbessard@70: lbessard@70: lbessard@70: /* lbessard@70: * Declare temporary variables to be later used as output parameters lbessard@70: * in function calls for which not all output parameters were lbessard@70: * defined in the original (st or il) source code. lbessard@70: * lbessard@70: * This is part of the 4th stage that generates lbessard@70: * a c++ source program equivalent to the IL and ST lbessard@70: * code. lbessard@70: */ lbessard@70: lbessard@70: lbessard@70: lbessard@70: lbessard@70: class temp_var_name_c { lbessard@70: private: lbessard@70: int counter; lbessard@70: lbessard@70: public: lbessard@70: void reset(void) {counter = 0;} lbessard@70: temp_var_name_c(void) {reset();} lbessard@70: lbessard@70: public: lbessard@70: std::string *new_name(void) { lbessard@70: std::string *new_str = new std::string(TEMP_VAR); lbessard@70: /* yikes!!! How to convert an int to a string elegantly??? lbessard@70: * Right now I (Mario) can only think of snprintf() lbessard@70: * C++ must have a more elegant method! lbessard@70: */ lbessard@70: int int_str_size = snprintf(NULL, 0, "%d", counter); lbessard@70: if (int_str_size <= 0) ERROR; lbessard@70: char *int_str = (char *)malloc(int_str_size+1); lbessard@70: if (snprintf(int_str, int_str_size+1, "%d", counter++) >= int_str_size+1) ERROR; lbessard@70: *new_str += int_str; lbessard@70: free(int_str); lbessard@70: return new_str; lbessard@70: } lbessard@70: lbessard@70: }; lbessard@70: lbessard@70: lbessard@70: lbessard@70: /***********************************************************************/ lbessard@70: /***********************************************************************/ lbessard@70: /***********************************************************************/ lbessard@70: /***********************************************************************/ lbessard@70: lbessard@70: lbessard@70: lbessard@70: /* Some function calls in the body of functions or function blocks lbessard@70: * may leave some parameters to their default values, and lbessard@70: * ignore some output parameters of the function being called. lbessard@70: * Our conversion of ST functions to C++ does not contemplate that, lbessard@70: * i.e. each called function must get all it's input and output lbessard@70: * parameters set correctly. lbessard@70: * For input parameters we merely need to call the function with lbessard@70: * the apropriate default value, but for output parameters lbessard@70: * we must create temporary variables to hold the output value. lbessard@70: * lbessard@70: * We declare all the temporary output variables at the begining of lbessard@70: * the body of each function or function block, and use them as lbessard@70: * in function calls later on as they become necessary... lbessard@70: * Note that we cannot create these variables just before a function lbessard@70: * call, as the function call itself may be integrated within an lbessard@70: * expression, or another function call! lbessard@70: * lbessard@70: * The variables are declared in the exact same order in which they lbessard@70: * will be used later on during the function calls, which allows us lbessard@70: * to simply re-create the name that was used for the temporary variable lbessard@70: * instead of keeping it in some list. lbessard@70: * The names are recreated by the temp_var_name_factory, after reset() lbessard@70: * has been called! lbessard@70: * lbessard@70: * This function will genertae code similar to... lbessard@70: * lbessard@70: * INT __TMP_0 = 23; lbessard@70: * REAL __TMP_1 = 45.5; lbessard@70: * ... lbessard@70: */ lbessard@70: lbessard@70: class generate_c_tempvardecl_c: generate_c_typedecl_c { lbessard@70: public: lbessard@70: generate_c_tempvardecl_c(stage4out_c *s4o_ptr): generate_c_typedecl_c(s4o_ptr) {} lbessard@70: lbessard@70: void generate(symbol_c *body, temp_var_name_c *temp_var_name_factory) { lbessard@70: temp_var_name_factory->reset(); lbessard@70: function_call_iterator_c fcall_iterator(body); lbessard@70: for(symbol_c *finvocation = NULL; (finvocation = fcall_iterator.next()) != NULL;) { lbessard@70: /* get the name of the next function that gets called */ lbessard@70: identifier_c *fcalled_name = fcall_iterator.fname(); lbessard@70: /* get that function's declaration... */ lbessard@70: function_declaration_c *fdecl = function_symtable.find_value(fcalled_name); lbessard@70: if (fdecl == function_symtable.end_value()) { lbessard@70: function_type_t function_type = get_function_type(fcalled_name); lbessard@70: if (function_type == function_none) ERROR; lbessard@70: return; lbessard@70: } lbessard@70: /* create iterator to iterate through each of the called function's parameters... */ lbessard@70: function_param_iterator_c fp_iterator(fdecl); lbessard@70: lbessard@70: /* iterate through each of the called function's parameters... */ lbessard@70: identifier_c *param_name = NULL; lbessard@70: function_call_param_iterator_c function_call_param_iterator(finvocation); lbessard@70: for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) { lbessard@70: lbessard@70: function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction(); lbessard@70: if (param_direction == function_param_iterator_c::direction_in) lbessard@70: /* ignore input only parameters... lbessard@70: * we do not need to create temporary variables for these! lbessard@70: */ lbessard@70: continue; lbessard@70: lbessard@70: /* Get the value from a foo( = ) style call */ lbessard@70: symbol_c *param_value = function_call_param_iterator.search(param_name); lbessard@70: lbessard@70: /* Get the value from a foo() style call */ lbessard@70: if (param_value == NULL) lbessard@70: param_value = function_call_param_iterator.next(); lbessard@70: lbessard@70: if (param_value != NULL) lbessard@70: /* ignore output parameters to which a variable is passed... lbessard@70: * we do not need to create temporary variables for these! lbessard@70: */ lbessard@70: continue; lbessard@70: lbessard@70: symbol_c *param_type = fp_iterator.param_type(); lbessard@70: lbessard@70: /* get the parameter's default value */ lbessard@70: param_value = fp_iterator.default_value(); lbessard@70: lbessard@70: /* If no default value specified in function declaration, lbessard@70: * get the default value of this variable's type lbessard@70: */ lbessard@70: if (param_value == NULL) lbessard@70: param_value = (symbol_c *)param_type->accept(*type_initial_value_c::instance()); lbessard@70: if (param_value == NULL) ERROR; lbessard@70: lbessard@70: /* now declare a temporary variable, with the correct default value... */ lbessard@70: s4o.print(s4o.indent_spaces); lbessard@70: param_type->accept(*this); lbessard@70: s4o.print(" "); lbessard@70: lbessard@70: std::string *temp_var_name = temp_var_name_factory->new_name(); lbessard@70: s4o.print(*temp_var_name); lbessard@70: delete temp_var_name; lbessard@70: lbessard@70: s4o.print(" = "); lbessard@70: param_value->accept(*this); lbessard@70: s4o.print(";\n"); lbessard@70: } lbessard@70: } lbessard@70: temp_var_name_factory->reset(); lbessard@70: s4o.print("\n"); lbessard@70: } lbessard@70: };