stage4/generate_c/generate_c_inlinefcall.cc
changeset 219 9bb38736f126
child 221 c6aed7e5f070
equal deleted inserted replaced
218:413842f6152f 219:9bb38736f126
       
     1 /*
       
     2  * (c) 2007 Mario de Sousa and Laurent Bessard
       
     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  * This is one of the versions available for the 4th stage.
       
    27  *
       
    28  * This 4th stage generates a c++ source program equivalent
       
    29  * to the IL and ST code.
       
    30  */
       
    31 
       
    32 
       
    33 #define INLINE_RESULT_TEMP_VAR "__res"
       
    34 
       
    35 class generate_c_inline_c: public generate_c_typedecl_c {
       
    36 
       
    37   private:
       
    38 
       
    39     /* The name of the IL default variable... */
       
    40 	#define IL_DEFVAR   VAR_LEADER "IL_DEFVAR"
       
    41 	/* The name of the variable used to pass the result of a
       
    42 	 * parenthesised instruction list to the immediately preceding
       
    43 	 * scope ...
       
    44 	 */
       
    45 	il_default_variable_c default_variable_name;
       
    46 
       
    47 	int fcall_number;
       
    48 	symbol_c *fbname;
       
    49 
       
    50     search_expression_type_c *search_expression_type;
       
    51 
       
    52     search_varfb_instance_type_c *search_varfb_instance_type;
       
    53 
       
    54     search_base_type_c search_base_type;
       
    55 
       
    56   public:
       
    57     generate_c_inline_c(stage4out_c *s4o_ptr, symbol_c *name, symbol_c *scope, const char *variable_prefix = NULL)
       
    58     : generate_c_typedecl_c(s4o_ptr),
       
    59       default_variable_name(IL_DEFVAR, NULL)
       
    60     {
       
    61       search_expression_type = new search_expression_type_c(scope);
       
    62       search_varfb_instance_type = new search_varfb_instance_type_c(scope);
       
    63       this->set_variable_prefix(variable_prefix);
       
    64       fcall_number = 0;
       
    65       fbname = name;
       
    66     }
       
    67 
       
    68     virtual ~generate_c_inline_c(void) {
       
    69       delete search_varfb_instance_type;
       
    70     }
       
    71 
       
    72     void *generate_inline(symbol_c *function_name,
       
    73     		symbol_c *return_data_type,
       
    74     		std::list<FUNCTION_PARAM*> param_list) {
       
    75       std::list<FUNCTION_PARAM*>::iterator pt;
       
    76 
       
    77       fcall_number++;
       
    78 
       
    79       s4o.print(s4o.indent_spaces);
       
    80       s4o.print("inline ");
       
    81       return_data_type->accept(*this);
       
    82       s4o.print(" __");
       
    83       fbname->accept(*this);
       
    84       s4o.print("_");
       
    85       function_name->accept(*this);
       
    86       s4o.print_integer(fcall_number);
       
    87       s4o.print("(");
       
    88       s4o.indent_right();
       
    89 
       
    90       PARAM_LIST_ITERATOR() {
       
    91         if (PARAM_DIRECTION == function_param_iterator_c::direction_in) {
       
    92           PARAM_TYPE->accept(*this);
       
    93           s4o.print(" ");
       
    94           PARAM_NAME->accept(*this);
       
    95           s4o.print(",\n" + s4o.indent_spaces);
       
    96         }
       
    97       }
       
    98       fbname->accept(*this);
       
    99 	  s4o.print(" *");
       
   100 	  s4o.print(FB_FUNCTION_PARAM);
       
   101 	  s4o.indent_left();
       
   102 	  s4o.print(")\n" + s4o.indent_spaces);
       
   103 	  s4o.print("{\n");
       
   104       s4o.indent_right();
       
   105 
       
   106       s4o.print(s4o.indent_spaces);
       
   107       return_data_type->accept(*this);
       
   108       s4o.print(" "),
       
   109       s4o.print(INLINE_RESULT_TEMP_VAR);
       
   110       s4o.print(";\n");
       
   111 
       
   112 	  PARAM_LIST_ITERATOR() {
       
   113 		if ((PARAM_DIRECTION == function_param_iterator_c::direction_out ||
       
   114 		     PARAM_DIRECTION == function_param_iterator_c::direction_inout) &&
       
   115 		    PARAM_VALUE != NULL) {
       
   116 		  s4o.print(s4o.indent_spaces);
       
   117 		  PARAM_TYPE->accept(*this);
       
   118           s4o.print(" ");
       
   119           s4o.print(TEMP_VAR);
       
   120           PARAM_NAME->accept(*this);
       
   121           s4o.print(" = ");
       
   122           print_check_function(PARAM_TYPE, PARAM_VALUE);
       
   123           s4o.print(";\n");
       
   124 		}
       
   125 	  }
       
   126 
       
   127 	  s4o.print(s4o.indent_spaces + INLINE_RESULT_TEMP_VAR),
       
   128 			  s4o.print(" = ");
       
   129 	  function_name->accept(*this);
       
   130 	  s4o.print("(");
       
   131 	  s4o.indent_right();
       
   132 
       
   133 	  PARAM_LIST_ITERATOR() {
       
   134 		if (pt != param_list.begin())
       
   135 		  s4o.print(",\n" + s4o.indent_spaces);
       
   136 		if (PARAM_DIRECTION == function_param_iterator_c::direction_in)
       
   137 		  PARAM_NAME->accept(*this);
       
   138 		else if (PARAM_VALUE != NULL){
       
   139           s4o.print("&");
       
   140           s4o.print(TEMP_VAR);
       
   141           PARAM_NAME->accept(*this);
       
   142         }
       
   143 		else {
       
   144 		  s4o.print("NULL");
       
   145 		}
       
   146 	  }
       
   147 	  s4o.print(");\n");
       
   148 	  s4o.indent_left();
       
   149 
       
   150 	  PARAM_LIST_ITERATOR() {
       
   151         if ((PARAM_DIRECTION == function_param_iterator_c::direction_out ||
       
   152         	 PARAM_DIRECTION == function_param_iterator_c::direction_inout) &&
       
   153         	PARAM_VALUE != NULL) {
       
   154 
       
   155           s4o.print(s4o.indent_spaces);
       
   156 
       
   157           unsigned int vartype = search_varfb_instance_type->get_vartype(PARAM_VALUE);
       
   158           if (vartype == search_var_instance_decl_c::external_vt)
       
   159             s4o.print(SET_EXTERNAL);
       
   160           else if (vartype == search_var_instance_decl_c::located_vt)
       
   161             s4o.print(SET_LOCATED);
       
   162           else
       
   163             s4o.print(SET_VAR);
       
   164           s4o.print("(");
       
   165 
       
   166           PARAM_VALUE->accept(*this);
       
   167           s4o.print(", ");
       
   168           print_check_function(PARAM_TYPE, PARAM_NAME, NULL, true);
       
   169           s4o.print(");\n");
       
   170 		}
       
   171 	  }
       
   172 	  s4o.print(s4o.indent_spaces + "return ");
       
   173 	  s4o.print(INLINE_RESULT_TEMP_VAR);
       
   174 	  s4o.print(";\n");
       
   175 
       
   176       s4o.indent_left();
       
   177       s4o.print(s4o.indent_spaces + "}\n\n");
       
   178 
       
   179       return NULL;
       
   180     }
       
   181 
       
   182   private:
       
   183 
       
   184     /*********************/
       
   185     /* B 1.4 - Variables */
       
   186     /*********************/
       
   187     void *visit(symbolic_variable_c *symbol) {
       
   188       unsigned int vartype = search_varfb_instance_type->get_vartype(symbol);
       
   189       if (vartype == search_var_instance_decl_c::external_vt) {
       
   190         s4o.print(GET_EXTERNAL);
       
   191         s4o.print("(");
       
   192         symbol->var_name->accept(*this);
       
   193       }
       
   194       else {
       
   195         if (vartype == search_var_instance_decl_c::located_vt)
       
   196           s4o.print(GET_LOCATED);
       
   197         else
       
   198           s4o.print(GET_VAR);
       
   199         s4o.print("(");
       
   200         generate_c_base_c::visit(symbol);
       
   201       }
       
   202       s4o.print(")");
       
   203       return NULL;
       
   204     }
       
   205 
       
   206     /********************************************/
       
   207     /* B.1.4.1   Directly Represented Variables */
       
   208     /********************************************/
       
   209     // direct_variable: direct_variable_token   {$$ = new direct_variable_c($1);};
       
   210     void *visit(direct_variable_c *symbol) {
       
   211       TRACE("direct_variable_c");
       
   212       /* Do not use print_token() as it will change everything into uppercase */
       
   213       if (strlen(symbol->value) == 0) ERROR;
       
   214       s4o.print(GET_LOCATED);
       
   215       s4o.print("(");
       
   216       this->print_variable_prefix();
       
   217       s4o.printlocation(symbol->value + 1);
       
   218       s4o.print(")");
       
   219       return NULL;
       
   220     }
       
   221 
       
   222     /****************************************/
       
   223     /* B.2 - Language IL (Instruction List) */
       
   224     /****************************************/
       
   225 
       
   226     /***********************************/
       
   227     /* B 2.1 Instructions and Operands */
       
   228     /***********************************/
       
   229 
       
   230     void *visit(il_function_call_c *symbol) {
       
   231 	  function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name);
       
   232 
       
   233 	  if (f_decl != function_symtable.end_value()) {
       
   234 		DECLARE_PARAM_LIST()
       
   235 		bool has_output_params = false;
       
   236 
       
   237 		/* determine the base data type returned by the function being called... */
       
   238 		search_base_type_c search_base_type;
       
   239 		symbol_c *return_data_type = (symbol_c *)f_decl->type_name->accept(search_base_type);
       
   240 		if (NULL == return_data_type) ERROR;
       
   241 
       
   242 		/* loop through each function parameter, find the value we should pass
       
   243 		 * to it, and then output the c equivalent...
       
   244 		 */
       
   245 
       
   246 		function_param_iterator_c fp_iterator(f_decl);
       
   247 		identifier_c *param_name;
       
   248 		function_call_param_iterator_c function_call_param_iterator(symbol);
       
   249 		for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) {
       
   250 		  symbol_c *param_type = fp_iterator.param_type();
       
   251 		  if (param_type == NULL) ERROR;
       
   252 
       
   253 		  function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction();
       
   254 
       
   255 		  symbol_c *param_value = NULL;
       
   256 
       
   257 		  /* if it is the first parameter, semantics specifies that we should
       
   258 		   * get the value off the IL default variable!
       
   259 		   */
       
   260 		 if (1 == i)
       
   261 		   param_value = &this->default_variable_name;
       
   262 
       
   263 		  /* Get the value from a foo(<param_name> = <param_value>) style call */
       
   264 		  /* NOTE: the following line of code is not required in this case, but it doesn't
       
   265 		   * harm to leave it in, as in the case of a non-formal syntax function call,
       
   266 		   * it will always return NULL.
       
   267 		   * We leave it in in case we later decide to merge this part of the code together
       
   268 		   * with the function calling code in generate_c_st_c, which does require
       
   269 		   * the following line...
       
   270 		   */
       
   271 		  if (param_value == NULL)
       
   272 			param_value = function_call_param_iterator.search_f(param_name);
       
   273 
       
   274 		  /* Get the value from a foo(<param_value>) style call */
       
   275 		  if (param_value == NULL)
       
   276 			param_value = function_call_param_iterator.next_nf();
       
   277 
       
   278 		  if (param_value == NULL && param_direction == function_param_iterator_c::direction_in) {
       
   279 			/* No value given for parameter, so we must use the default... */
       
   280 			/* First check whether default value specified in function declaration...*/
       
   281 			param_value = fp_iterator.default_value();
       
   282 		  }
       
   283 
       
   284 		  ADD_PARAM_LIST(param_name, param_value, param_type, fp_iterator.param_direction())
       
   285 		} /* for(...) */
       
   286 
       
   287 		PARAM_LIST_ITERATOR() {
       
   288 			if ((PARAM_DIRECTION == function_param_iterator_c::direction_out ||
       
   289 				 PARAM_DIRECTION == function_param_iterator_c::direction_inout) &&
       
   290 				PARAM_VALUE != NULL) {
       
   291 			  has_output_params = true;
       
   292 			}
       
   293 		}
       
   294 
       
   295 	    if (has_output_params)
       
   296 	      generate_inline(symbol->function_name, return_data_type, param_list);
       
   297 
       
   298 	    CLEAR_PARAM_LIST()
       
   299 	  }
       
   300 	  return NULL;
       
   301     }
       
   302 
       
   303     void *visit(il_formal_funct_call_c *symbol) {
       
   304 	  function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name);
       
   305 
       
   306 	  if (f_decl != function_symtable.end_value()) {
       
   307 		DECLARE_PARAM_LIST()
       
   308 		bool has_output_params = false;
       
   309 
       
   310 		/* determine the base data type returned by the function being called... */
       
   311 		search_base_type_c search_base_type;
       
   312 		symbol_c *return_data_type = (symbol_c *)f_decl->type_name->accept(search_base_type);
       
   313 		if (NULL == return_data_type) ERROR;
       
   314 
       
   315 		/* loop through each function parameter, find the value we should pass
       
   316 		 * to it, and then output the c equivalent...
       
   317 		 */
       
   318 
       
   319 		function_param_iterator_c fp_iterator(f_decl);
       
   320 		identifier_c *param_name;
       
   321 		function_call_param_iterator_c function_call_param_iterator(symbol);
       
   322 		for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) {
       
   323 		  symbol_c *param_type = fp_iterator.param_type();
       
   324 		  if (param_type == NULL) ERROR;
       
   325 
       
   326 		  function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction();
       
   327 
       
   328 
       
   329 		  symbol_c *param_value = NULL;
       
   330 
       
   331 		  /* Get the value from a foo(<param_name> = <param_value>) style call */
       
   332 		  if (param_value == NULL)
       
   333 			param_value = function_call_param_iterator.search_f(param_name);
       
   334 
       
   335 		  /* Get the value from a foo(<param_value>) style call */
       
   336 		  /* NOTE: the following line of code is not required in this case, but it doesn't
       
   337 		   * harm to leave it in, as in the case of a formal syntax function call,
       
   338 		   * it will always return NULL.
       
   339 		   * We leave it in in case we later decide to merge this part of the code together
       
   340 		   * with the function calling code in generate_c_st_c, which does require
       
   341 		   * the following line...
       
   342 		   */
       
   343 		  if (param_value == NULL)
       
   344 			param_value = function_call_param_iterator.next_nf();
       
   345 
       
   346 		  if (param_value == NULL) {
       
   347 			/* No value given for parameter, so we must use the default... */
       
   348 			/* First check whether default value specified in function declaration...*/
       
   349 			param_value = fp_iterator.default_value();
       
   350 		  }
       
   351 
       
   352 		  ADD_PARAM_LIST(param_name, param_value, param_type, fp_iterator.param_direction())
       
   353 		}
       
   354 
       
   355 		PARAM_LIST_ITERATOR() {
       
   356       	  if ((PARAM_DIRECTION == function_param_iterator_c::direction_out ||
       
   357       		   PARAM_DIRECTION == function_param_iterator_c::direction_inout) &&
       
   358       	      PARAM_VALUE != NULL) {
       
   359       	    has_output_params = true;
       
   360       	  }
       
   361         }
       
   362 
       
   363         if (has_output_params)
       
   364 	      generate_inline(symbol->function_name, return_data_type, param_list);
       
   365 
       
   366         CLEAR_PARAM_LIST()
       
   367 	  }
       
   368       return NULL;
       
   369     }
       
   370 
       
   371     /***************************************/
       
   372     /* B.3 - Language ST (Structured Text) */
       
   373     /***************************************/
       
   374     /***********************/
       
   375     /* B 3.1 - Expressions */
       
   376     /***********************/
       
   377 
       
   378     void *visit(function_invocation_c *symbol) {
       
   379       function_declaration_c *f_decl = function_symtable.find_value(symbol->function_name);
       
   380 
       
   381       if (f_decl != function_symtable.end_value()) {
       
   382     	DECLARE_PARAM_LIST()
       
   383     	bool has_output_params = false;
       
   384 
       
   385     	symbol_c *parameter_assignment_list = NULL;
       
   386 	    if (NULL != symbol->   formal_param_list) parameter_assignment_list = symbol->   formal_param_list;
       
   387 	    if (NULL != symbol->nonformal_param_list) parameter_assignment_list = symbol->nonformal_param_list;
       
   388 	    if (NULL == parameter_assignment_list) ERROR;
       
   389 
       
   390 	    /* determine the base data type returned by the function being called... */
       
   391 		search_base_type_c search_base_type;
       
   392 		symbol_c *return_data_type = (symbol_c *)f_decl->type_name->accept(search_base_type);
       
   393 		if (NULL == return_data_type) ERROR;
       
   394 
       
   395     	/* loop through each function parameter, find the value we should pass
       
   396          * to it, and then output the c equivalent...
       
   397          */
       
   398         function_param_iterator_c fp_iterator(f_decl);
       
   399         identifier_c *param_name;
       
   400         function_call_param_iterator_c function_call_param_iterator(symbol);
       
   401         for(int i = 1; (param_name = fp_iterator.next()) != NULL; i++) {
       
   402 
       
   403           function_param_iterator_c::param_direction_t param_direction = fp_iterator.param_direction();
       
   404 
       
   405           /* Get the value from a foo(<param_name> = <param_value>) style call */
       
   406           symbol_c *param_value = function_call_param_iterator.search_f(param_name);
       
   407 
       
   408           /* Get the value from a foo(<param_value>) style call */
       
   409           if (param_value == NULL)
       
   410             param_value = function_call_param_iterator.next_nf();
       
   411 
       
   412           if (param_value == NULL && param_direction == function_param_iterator_c::direction_in) {
       
   413             /* No value given for parameter, so we must use the default... */
       
   414             /* First check whether default value specified in function declaration...*/
       
   415             param_value = fp_iterator.default_value();
       
   416           }
       
   417 
       
   418           symbol_c *param_type = fp_iterator.param_type();
       
   419           if (param_type == NULL) ERROR;
       
   420 
       
   421           ADD_PARAM_LIST(param_name, param_value, param_type, param_direction)
       
   422         } /* for(...) */
       
   423         // symbol->parameter_assignment->accept(*this);
       
   424 
       
   425         PARAM_LIST_ITERATOR() {
       
   426       	  if ((PARAM_DIRECTION == function_param_iterator_c::direction_out ||
       
   427       			PARAM_DIRECTION == function_param_iterator_c::direction_inout) &&
       
   428               PARAM_VALUE != NULL) {
       
   429       	    has_output_params = true;
       
   430       	  }
       
   431         }
       
   432 
       
   433         if (has_output_params)
       
   434 	      generate_inline(symbol->function_name, return_data_type, param_list);
       
   435 
       
   436         CLEAR_PARAM_LIST()
       
   437       }
       
   438 	  return NULL;
       
   439     }
       
   440 
       
   441 };  /* generate_c_inline_c */
       
   442 
       
   443 
       
   444 /***********************************************************************/
       
   445 /***********************************************************************/
       
   446 /***********************************************************************/
       
   447 /***********************************************************************/
       
   448 
       
   449 
       
   450 class generate_c_inlinefcall_c: public iterator_visitor_c {
       
   451 
       
   452   private:
       
   453 	generate_c_inline_c *generate_c_inline;
       
   454 
       
   455   public:
       
   456 	generate_c_inlinefcall_c(stage4out_c *s4o_ptr, symbol_c *name, symbol_c *scope, const char *variable_prefix = NULL) {
       
   457 	  generate_c_inline = new generate_c_inline_c(s4o_ptr, name, scope, variable_prefix);
       
   458 	}
       
   459 
       
   460 	virtual ~generate_c_inlinefcall_c(void) {
       
   461 	  delete generate_c_inline;
       
   462 	}
       
   463 
       
   464   private:
       
   465 
       
   466 	void *visit(function_invocation_c *symbol) {
       
   467 	  return symbol->accept(*generate_c_inline);
       
   468 	}
       
   469 
       
   470 	void *visit(il_function_call_c *symbol) {
       
   471 	  return symbol->accept(*generate_c_inline);
       
   472 	}
       
   473 
       
   474 	void *visit(il_formal_funct_call_c *symbol) {
       
   475 	  return symbol->accept(*generate_c_inline);
       
   476 	}
       
   477 }; /* generate_c_inlinefcall_c */
       
   478 
       
   479 
       
   480