stage4/generate_cc/generate_cc_st.cc
changeset 0 fb772792efd1
child 16 e8b99f896416
equal deleted inserted replaced
-1:000000000000 0:fb772792efd1
       
     1 /*
       
     2  * (c) 2003 Mario de Sousa
       
     3  *
       
     4  * Offered to the public under the terms of the GNU General Public License
       
     5  * as published by the Free Software Foundation; either version 2 of the
       
     6  * License, or (at your option) any later version.
       
     7  *
       
     8  * This program is distributed in the hope that it will be useful, but
       
     9  * WITHOUT ANY WARRANTY; without even the implied warranty of
       
    10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
       
    11  * Public License for more details.
       
    12  *
       
    13  * This code is made available on the understanding that it will not be
       
    14  * used in safety-critical situations without a full and competent review.
       
    15  */
       
    16 
       
    17 /*
       
    18  * An IEC 61131-3 IL and ST compiler.
       
    19  *
       
    20  * Based on the
       
    21  * FINAL DRAFT - IEC 61131-3, 2nd Ed. (2001-12-10)
       
    22  *
       
    23  */
       
    24 
       
    25 
       
    26 /*
       
    27  * Conversion of st statements (i.e. ST code).
       
    28  *
       
    29  * This is part of the 4th stage that generates
       
    30  * a c++ source program equivalent to the IL and ST
       
    31  * code.
       
    32  */
       
    33 
       
    34 
       
    35 
       
    36 
       
    37 
       
    38 class generate_cc_st_c: public generate_cc_typedecl_c {
       
    39 
       
    40   private:
       
    41     /* When calling a function block, we must first find it's type,
       
    42      * by searching through the declarations of the variables currently
       
    43      * in scope.
       
    44      * This class does just that...
       
    45      * A new class is instantiated whenever we begin generating the code
       
    46      * for a function block type declaration, or a program declaration.
       
    47      * This object instance will then later be called while the
       
    48      * function block's or the program's body is being handled.
       
    49      *
       
    50      * Note that functions cannot contain calls to function blocks,
       
    51      * so we do not create an object instance when handling
       
    52      * a function declaration.
       
    53      */
       
    54     search_fb_instance_decl_c *search_fb_instance_decl;
       
    55 
       
    56 
       
    57   public:
       
    58     generate_cc_st_c(stage4out_c *s4o_ptr, symbol_c *scope, const char *variable_prefix = NULL)
       
    59     : generate_cc_typedecl_c(s4o_ptr) {
       
    60       search_fb_instance_decl = new search_fb_instance_decl_c(scope);
       
    61       this->set_variable_prefix(variable_prefix);
       
    62     }
       
    63 
       
    64     virtual ~generate_cc_st_c(void) {
       
    65       delete search_fb_instance_decl;
       
    66     }
       
    67 
       
    68 
       
    69   private:
       
    70     /* Some function calls in the body of functions or function blocks
       
    71      * may leave some parameters to their default values, and
       
    72      * ignore some output parameters of the function being called.
       
    73      * Our conversion of ST functions to C++ does not contemplate that,
       
    74      * i.e. each called function must get all it's input and output
       
    75      * parameters set correctly.
       
    76      * For input parameters we merely need to call the function with
       
    77      * the apropriate default value, but for output parameters
       
    78      * we must create temporary variables to hold the output value.
       
    79      *
       
    80      * We declare all the temporary output variables at the begining of
       
    81      * the body of each function or function block, and use them as
       
    82      * in function calls later on as they become necessary...
       
    83      * Note that we cannot create these variables just before a function
       
    84      * call, as the function call itself may be integrated within an
       
    85      * expression, or another function call!
       
    86      *
       
    87      * The variables are declared in the exact same order in which they
       
    88      * will be used later on during the function calls, which allows us
       
    89      * to simply re-create the name that was used for the temporary variable
       
    90      * instead of keeping it in some list.
       
    91      * The names are recreated by the temp_var_name_factory, after reset()
       
    92      * has been called!
       
    93      *
       
    94      * This function will genertae code similar to...
       
    95      *
       
    96      *     INT __TMP_0 = 23;
       
    97      *     REAL __TMP_1 = 45.5;
       
    98      *     ...
       
    99      */
       
   100     temp_var_name_c temp_var_name_factory;
       
   101 
       
   102   public:
       
   103     void generate(statement_list_c *stl) {
       
   104       generate_cc_tempvardecl_c generate_cc_tempvardecl(&s4o);
       
   105       generate_cc_tempvardecl.generate(stl, &temp_var_name_factory);
       
   106       stl->accept(*this);
       
   107     }
       
   108 
       
   109   private:
       
   110 /***************************************/
       
   111 /* B.3 - Language ST (Structured Text) */
       
   112 /***************************************/
       
   113 /***********************/
       
   114 /* B 3.1 - Expressions */
       
   115 /***********************/
       
   116 void *visit(or_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " || ");}
       
   117 /* TODO ...  XOR expression... */
       
   118 void *visit(xor_expression_c *symbol) {ERROR; return print_binary_expression(symbol->l_exp, symbol->r_exp, " XOR ");}
       
   119 void *visit(and_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " && ");}
       
   120 void *visit(equ_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " == ");}
       
   121 void *visit(notequ_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " != ");}
       
   122 void *visit(lt_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " < ");}
       
   123 void *visit(gt_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " > ");}
       
   124 void *visit(le_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " <= ");}
       
   125 void *visit(ge_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " >= ");}
       
   126 void *visit(add_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " + ");}
       
   127 void *visit(sub_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " - ");}
       
   128 void *visit(mul_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " * ");}
       
   129 void *visit(div_expression_c *symbol) {return print_binary_expression(symbol->l_exp, symbol->r_exp, " / ");}
       
   130 void *visit(mod_expression_c *symbol) {
       
   131   s4o.print("((");
       
   132   symbol->r_exp->accept(*this);
       
   133   s4o.print(" == 0)?0:");
       
   134   print_binary_expression(symbol->l_exp, symbol->r_exp, " % ");
       
   135   s4o.print(")");
       
   136   return NULL;
       
   137 }
       
   138 
       
   139 /* TODO: power expression... */
       
   140 void *visit(power_expression_c *symbol) {ERROR; return print_binary_expression(symbol->l_exp, symbol->r_exp, " ** ");}
       
   141 void *visit(neg_expression_c *symbol) {return print_unary_expression(symbol->exp, " -");}
       
   142 void *visit(not_expression_c *symbol) {return print_unary_expression(symbol->exp, "!");}
       
   143 
       
   144 void *visit(function_invocation_c *symbol) {
       
   145   function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name);
       
   146 
       
   147   if (f_decl == function_symtable.end_value())
       
   148     /* should never occur. The function being called MUST be in the symtable... */
       
   149     ERROR;
       
   150 
       
   151   symbol->function_name->accept(*this);
       
   152   s4o.print("(");
       
   153 
       
   154   /* loop through each function parameter, find the value we should pass
       
   155    * to it, and then output the c equivalent...
       
   156    */
       
   157 
       
   158   function_param_iterator_c fp_iterator(f_decl);
       
   159   identifier_c *param_name;
       
   160   function_call_param_iterator_c function_call_param_iterator(symbol);
       
   161   for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) {
       
   162     if (i != 1)
       
   163       s4o.print(", ");
       
   164 
       
   165     symbol_c *param_type = fp_iterator.param_type();
       
   166     if (param_type == NULL) ERROR;
       
   167 
       
   168     function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction();
       
   169 
       
   170     /* Get the value from a foo(<param_name> = <param_value>) style call */
       
   171     symbol_c *param_value = function_call_param_iterator.search(param_name);
       
   172 
       
   173     /* Get the value from a foo(<param_value>) style call */
       
   174     if (param_value == NULL)
       
   175       param_value = function_call_param_iterator.next();
       
   176 
       
   177     switch (param_direction) {
       
   178       case function_param_iterator_c::direction_in:
       
   179         if (param_value == NULL) {
       
   180           /* No value given for parameter, so we must use the default... */
       
   181           /* First check whether default value specified in function declaration...*/
       
   182           param_value = fp_iterator.default_value();
       
   183         }
       
   184         if (param_value == NULL) {
       
   185           /* If not, get the default value of this variable's type */
       
   186           param_value = (symbol_c *)param_type->accept(*type_initial_value_c::instance());
       
   187         }
       
   188         if (param_value == NULL) ERROR;
       
   189         param_value->accept(*this);
       
   190 	break;
       
   191       case function_param_iterator_c::direction_out:
       
   192       case function_param_iterator_c::direction_inout:
       
   193         if (param_value == NULL) {
       
   194 	  /* no parameter value given, so we pass a previously declared temporary variable. */
       
   195           std::string *temp_var_name = temp_var_name_factory.new_name();
       
   196           s4o.print(*temp_var_name);
       
   197           delete temp_var_name;
       
   198 	} else {
       
   199           param_value->accept(*this);
       
   200 	}
       
   201 	break;
       
   202       case function_param_iterator_c::direction_extref:
       
   203         /* TODO! */
       
   204         ERROR;
       
   205         break;
       
   206     } /* switch */
       
   207   } /* for(...) */
       
   208 
       
   209   // symbol->parameter_assignment->accept(*this);
       
   210   s4o.print(")");
       
   211   return NULL;
       
   212 }
       
   213 
       
   214 /********************/
       
   215 /* B 3.2 Statements */
       
   216 /********************/
       
   217 void *visit(statement_list_c *symbol) {
       
   218   return print_list(symbol, s4o.indent_spaces, ";\n" + s4o.indent_spaces, ";\n");
       
   219 }
       
   220 
       
   221 /*********************************/
       
   222 /* B 3.2.1 Assignment Statements */
       
   223 /*********************************/
       
   224 void *visit(assignment_statement_c *symbol) {
       
   225   symbol->l_exp->accept(*this);
       
   226   s4o.print(" = ");
       
   227   symbol->r_exp->accept(*this);
       
   228   return NULL;
       
   229 }
       
   230 
       
   231 /*****************************************/
       
   232 /* B 3.2.2 Subprogram Control Statements */
       
   233 /*****************************************/
       
   234 
       
   235 /* fb_name '(' [param_assignment_list] ')' */
       
   236 /* param_assignment_list -> may be NULL ! */
       
   237 //SYM_REF2(fb_invocation_c, fb_name, param_assignment_list)
       
   238 void *visit(fb_invocation_c *symbol) {
       
   239   TRACE("fb_invocation_c");
       
   240   /* first figure out what is the name of the function block type of the function block being called... */
       
   241   symbol_c *function_block_type_name = this->search_fb_instance_decl->get_type_name(symbol->fb_name);
       
   242     /* should never occur. The function block instance MUST have been declared... */
       
   243   if (function_block_type_name == NULL) ERROR;
       
   244 
       
   245   /* Now find the declaration of the function block type being called... */
       
   246   function_block_declaration_c *fb_decl = function_block_type_symtable.find_value(function_block_type_name);
       
   247     /* should never occur. The function block type being called MUST be in the symtable... */
       
   248   if (fb_decl == function_block_type_symtable.end_value()) ERROR;
       
   249 
       
   250   /* loop through each function block parameter, find the value we should pass
       
   251    * to it, and then output the c equivalent...
       
   252    */
       
   253   function_param_iterator_c fp_iterator(fb_decl);
       
   254   identifier_c *param_name;
       
   255   function_call_param_iterator_c function_call_param_iterator(symbol);
       
   256   for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) {
       
   257     function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction();
       
   258 
       
   259     /* Get the value from a foo(<param_name> = <param_value>) style call */
       
   260     symbol_c *param_value = function_call_param_iterator.search(param_name);
       
   261 
       
   262     /* Get the value from a foo(<param_value>) style call */
       
   263     if (param_value == NULL)
       
   264       param_value = function_call_param_iterator.next();
       
   265 
       
   266     /* now output the value assignment */
       
   267     if (param_value != NULL)
       
   268       if ((param_direction == function_param_iterator_c::direction_in) ||
       
   269           (param_direction == function_param_iterator_c::direction_inout)) {
       
   270         symbol->fb_name->accept(*this);
       
   271         s4o.print(".");
       
   272         param_name->accept(*this);
       
   273         s4o.print(" = ");
       
   274         param_value->accept(*this);
       
   275         s4o.print(";\n" + s4o.indent_spaces);
       
   276       }
       
   277   } /* for(...) */
       
   278 
       
   279   /* now call the function... */
       
   280   function_block_type_name->accept(*this);
       
   281   s4o.print(FB_FUNCTION_SUFFIX);
       
   282   s4o.print("(&");
       
   283   symbol->fb_name->accept(*this);
       
   284   s4o.print(")");
       
   285 
       
   286   /* loop through each function parameter, find the variable to which
       
   287    * we should atribute the value of all output or inoutput parameters.
       
   288    */
       
   289   fp_iterator.reset();
       
   290   function_call_param_iterator.reset();
       
   291   for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) {
       
   292     function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction();
       
   293 
       
   294     /* Get the value from a foo(<param_name> = <param_value>) style call */
       
   295     symbol_c *param_value = function_call_param_iterator.search(param_name);
       
   296 
       
   297     /* Get the value from a foo(<param_value>) style call */
       
   298     if (param_value == NULL)
       
   299       param_value = function_call_param_iterator.next();
       
   300 
       
   301     /* now output the value assignment */
       
   302     if (param_value != NULL)
       
   303       if ((param_direction == function_param_iterator_c::direction_out) ||
       
   304           (param_direction == function_param_iterator_c::direction_inout)) {
       
   305         s4o.print(";\n"+ s4o.indent_spaces);
       
   306         param_value->accept(*this);
       
   307         s4o.print(" = ");
       
   308         symbol->fb_name->accept(*this);
       
   309         s4o.print(".");
       
   310         param_name->accept(*this);
       
   311       }
       
   312   } /* for(...) */
       
   313 
       
   314   return NULL;
       
   315 }
       
   316 
       
   317 
       
   318 
       
   319 
       
   320 /* helper symbol for fb_invocation */
       
   321 /* param_assignment_list ',' param_assignment */
       
   322 void *visit(param_assignment_list_c *symbol) {
       
   323   TRACE("param_assignment_list_c");
       
   324   /* this should never be called... */
       
   325   ERROR;
       
   326   return NULL;
       
   327 //  return print_list(symbol, "", ", ");
       
   328 }
       
   329 
       
   330 
       
   331 void *visit(input_variable_param_assignment_c *symbol) {
       
   332   TRACE("input_variable_param_assignment_c");
       
   333   /* this should never be called... */
       
   334   ERROR;
       
   335   return NULL;
       
   336 /*
       
   337   symbol->variable_name->accept(*this);
       
   338   s4o.print(" = ");
       
   339   symbol->expression->accept(*this);
       
   340   return NULL;
       
   341 */
       
   342 }
       
   343 
       
   344 void *visit(output_variable_param_assignment_c *symbol) {
       
   345   TRACE("output_variable_param_assignment_c");
       
   346   /* this should never be called... */
       
   347   ERROR;
       
   348   return NULL;
       
   349 /*
       
   350   s4o.print(s4o.indent_spaces);
       
   351   if (symbol->not_param != NULL)
       
   352     symbol->not_param->accept(*this);
       
   353   symbol->variable_name->accept(*this);
       
   354   s4o.print(" => ");
       
   355   symbol->variable->accept(*this);
       
   356   return NULL;
       
   357 */
       
   358 }
       
   359 
       
   360 // TODO: the NOT symbol in function (block) calls...
       
   361 void *visit(not_paramassign_c *symbol) {
       
   362   TRACE("not_paramassign_c");
       
   363   /* this should never be called... */
       
   364   ERROR;
       
   365   return NULL;
       
   366 /*
       
   367   s4o.print("NOT ");
       
   368   return NULL;
       
   369 */
       
   370 }
       
   371 
       
   372 
       
   373 /********************************/
       
   374 /* B 3.2.3 Selection Statements */
       
   375 /********************************/
       
   376 void *visit(if_statement_c *symbol) {
       
   377   s4o.print("if (");
       
   378   symbol->expression->accept(*this);
       
   379   s4o.print(") {\n");
       
   380   s4o.indent_right();
       
   381   symbol->statement_list->accept(*this);
       
   382   s4o.indent_left();
       
   383   symbol->elseif_statement_list->accept(*this);
       
   384 
       
   385   if (symbol->else_statement_list != NULL) {
       
   386     s4o.print(s4o.indent_spaces); s4o.print("} else {\n");
       
   387     s4o.indent_right();
       
   388     symbol->else_statement_list->accept(*this);
       
   389     s4o.indent_left();
       
   390   }
       
   391   s4o.print(s4o.indent_spaces); s4o.print("}");
       
   392   return NULL;
       
   393 }
       
   394 
       
   395 /* helper symbol for if_statement */
       
   396 void *visit(elseif_statement_list_c *symbol) {return print_list(symbol);}
       
   397 
       
   398 /* helper symbol for elseif_statement_list */
       
   399 void *visit(elseif_statement_c *symbol) {
       
   400   s4o.print(s4o.indent_spaces); s4o.print("} else if (");
       
   401   symbol->expression->accept(*this);
       
   402   s4o.print(") {\n");
       
   403   s4o.indent_right();
       
   404   symbol->statement_list->accept(*this);
       
   405   s4o.indent_left();
       
   406   return NULL;
       
   407 }
       
   408 
       
   409 void *visit(case_statement_c *symbol) {
       
   410   s4o.print("switch(");
       
   411   symbol->expression->accept(*this);
       
   412   s4o.print(") {\n");
       
   413   s4o.indent_right();
       
   414   symbol->case_element_list->accept(*this);
       
   415   if (symbol->statement_list != NULL) {
       
   416     s4o.print(s4o.indent_spaces + "default:\n");
       
   417     s4o.indent_right();
       
   418     symbol->statement_list->accept(*this);
       
   419     s4o.print(s4o.indent_spaces + "break;\n");
       
   420     s4o.indent_left();
       
   421   }
       
   422   s4o.indent_left();
       
   423   s4o.print(s4o.indent_spaces + "}");
       
   424   return NULL;
       
   425 }
       
   426 
       
   427 /* helper symbol for case_statement */
       
   428 void *visit(case_element_list_c *symbol) {return print_list(symbol);}
       
   429 
       
   430 void *visit(case_element_c *symbol) {
       
   431   s4o.print(s4o.indent_spaces + "case ");
       
   432   symbol->case_list->accept(*this);
       
   433   s4o.print(" :\n");
       
   434   s4o.indent_right();
       
   435   symbol->statement_list->accept(*this);
       
   436   s4o.print(s4o.indent_spaces + "break;\n");
       
   437   s4o.indent_left();
       
   438   return NULL;
       
   439 }
       
   440 
       
   441 void *visit(case_list_c *symbol) {return print_list(symbol, "", ", ");}
       
   442 
       
   443 /********************************/
       
   444 /* B 3.2.4 Iteration Statements */
       
   445 /********************************/
       
   446 void *visit(for_statement_c *symbol) {
       
   447   s4o.print("for(");
       
   448   symbol->control_variable->accept(*this);
       
   449   s4o.print(" = ");
       
   450   symbol->beg_expression->accept(*this);
       
   451   s4o.print("; ");
       
   452   symbol->control_variable->accept(*this);
       
   453   s4o.print(" != ");
       
   454   symbol->end_expression->accept(*this);
       
   455   s4o.print("; ");
       
   456   symbol->control_variable->accept(*this);
       
   457   if (symbol->by_expression != NULL) {
       
   458     s4o.print(" += ");
       
   459     symbol->by_expression->accept(*this);
       
   460   } else {
       
   461     s4o.print("++");
       
   462   }
       
   463   s4o.print(") {\n");
       
   464   s4o.indent_right();
       
   465   symbol->statement_list->accept(*this);
       
   466   s4o.indent_left();
       
   467   s4o.print(s4o.indent_spaces); s4o.print("}");
       
   468   return NULL;
       
   469 }
       
   470 void *visit(while_statement_c *symbol) {
       
   471   s4o.print("while (");
       
   472   symbol->expression->accept(*this);
       
   473   s4o.print(") {\n");
       
   474   s4o.indent_right();
       
   475   symbol->statement_list->accept(*this);
       
   476   s4o.indent_left();
       
   477   s4o.print(s4o.indent_spaces); s4o.print("}");
       
   478   return NULL;
       
   479 }
       
   480 void *visit(repeat_statement_c *symbol) {
       
   481   s4o.print("do {\n");
       
   482   s4o.indent_right();
       
   483   symbol->statement_list->accept(*this);
       
   484   s4o.indent_left();
       
   485   s4o.print(s4o.indent_spaces); s4o.print("} while(");
       
   486   symbol->expression->accept(*this);
       
   487   s4o.print(")");
       
   488   return NULL;
       
   489 }
       
   490 void *visit(exit_statement_c *symbol) {
       
   491   s4o.print("exit(0)");
       
   492   return NULL;
       
   493 }
       
   494 
       
   495 
       
   496 
       
   497 }; /* generate_cc_st_c */
       
   498 
       
   499 
       
   500 
       
   501 
       
   502 
       
   503 
       
   504 
       
   505 
       
   506