generate_IEC_std.py
changeset 25 8dc68e669d99
child 26 36d378bd852e
equal deleted inserted replaced
24:364320323b4d 25:8dc68e669d99
       
     1 # Get definitions
       
     2 from plcopen.structures import *
       
     3 
       
     4 #import pprint
       
     5 #pp = pprint.PrettyPrinter(indent=4)
       
     6 
       
     7 def ANY_to_compiler_test_type_GEN(typename, paramname):
       
     8     """
       
     9     Convert ANY_XXX IEC type declaration into IEC2CC's generated type test.
       
    10     This tests are defined in search_expression_type.cc 
       
    11     """
       
    12     return {"ANY" : "",
       
    13     "ANY_BIT" : "if(search_expression_type->is_binary_type(%(paramname)s_type_symbol))",
       
    14     "ANY_NUM" : "if(search_expression_type->is_num_type(%(paramname)s_type_symbol))",
       
    15     "ANY_REAL" : "if(search_expression_type->is_real_type(%(paramname)s_type_symbol))",
       
    16     "ANY_INT" : "if(search_expression_type->is_integer_type(%(paramname)s_type_symbol))"
       
    17     }.get(typename,
       
    18         "if (typeid(*last_type_symbol) == typeid(%(typename)s_type_name_c))")%{
       
    19                 "paramname" : paramname, "typename": typename.lower()}
       
    20 
       
    21 def recurse_and_indent(fdecls, indent, do_type_search_only = False, do_il = False):
       
    22     """
       
    23     This function generate visit(function_invocation) code for 
       
    24         - ST code generator
       
    25         - IL code generator
       
    26         - search_expression_type class for ST
       
    27         - search_expression_type class for IL
       
    28         
       
    29     Input data is a 
       
    30     "{fname : {IN[0]paramname : {IN[0]paramtype : {IN[1]paraname : {IN[1]paramtype : {... : {IN[N]paraname : {IN[N]paramtype : (fdecl,)}}}}}}"
       
    31     nested dictionary structure.
       
    32     """
       
    33     if type(fdecls) != type(tuple()):
       
    34         res = ""
       
    35         for Paramname, ParamTypes in fdecls.iteritems():
       
    36             if do_il:
       
    37                 res += """
       
    38 {"""
       
    39                 if not do_type_search_only:
       
    40                     res += """
       
    41     /* Get the value from a foo(<param_name> = <param_value>) style call */
       
    42     symbol_c *%(input_name)s_param_value = &this->default_variable_name;
       
    43 """%{"input_name":Paramname}
       
    44                 res += """
       
    45     symbol_c *%(input_name)s_type_symbol = param_data_type;
       
    46     last_type_symbol = param_data_type;
       
    47 """%{"input_name":Paramname}
       
    48             else:
       
    49                 res += """
       
    50 {
       
    51     identifier_c param_name("%(input_name)s");
       
    52     /* Get the value from a foo(<param_name> = <param_value>) style call */
       
    53     symbol_c *%(input_name)s_param_value = function_call_param_iterator.search(&param_name);
       
    54     
       
    55     /* Get the value from a foo(<param_value>) style call */
       
    56     if (%(input_name)s_param_value == NULL)
       
    57       %(input_name)s_param_value = function_call_param_iterator.next();
       
    58     symbol_c *%(input_name)s_type_symbol = search_expression_type->get_type(%(input_name)s_param_value);
       
    59     last_type_symbol = last_type_symbol && search_expression_type->is_same_type(%(input_name)s_type_symbol, last_type_symbol) ? search_expression_type->common_type(%(input_name)s_type_symbol, last_type_symbol) : %(input_name)s_type_symbol ;
       
    60 """%{"input_name":Paramname}
       
    61             
       
    62             for ParamType,NextParamDecl in ParamTypes.iteritems():
       
    63             
       
    64                 res += """    
       
    65     %(type_test)s
       
    66     {
       
    67 %(if_good_type_code)s
       
    68     }
       
    69 """%{
       
    70     "type_test":ANY_to_compiler_test_type_GEN(ParamType,Paramname), 
       
    71     "if_good_type_code":recurse_and_indent(NextParamDecl,indent,do_type_search_only).replace('\n','\n    ')}
       
    72 
       
    73             res += """    
       
    74     ERROR;
       
    75 }
       
    76 """
       
    77         
       
    78         return res.replace('\n','\n'+indent)
       
    79     else:
       
    80         res = "\n"
       
    81         fdecl=fdecls[0]
       
    82         
       
    83         result_type_rule = fdecl["return_type_rule"]
       
    84         res += {
       
    85             "copy_input" : "symbol_c * return_type_symbol = last_type_symbol;\n",
       
    86             "defined" : "symbol_c * return_type_symbol = &search_constant_type_c::%s_type_name;\n"%fdecl["outputs"][0][1].lower(),
       
    87             }.get(result_type_rule, "symbol_c * return_type_symbol = %s;\n"%result_type_rule)
       
    88         
       
    89         if not do_type_search_only:
       
    90             code_gen = eval(fdecl["python_eval_c_code_format"])
       
    91 
       
    92             code_gen_dic_decl = {}
       
    93             for paramname,paramtype,unused in fdecl["inputs"]:
       
    94                 code_gen_dic_decl[paramname+"_value"] = '");\n%s_param_value->accept(*this);\ns4o.print("'%(paramname)
       
    95                 code_gen_dic_decl[paramname+"_type"] = '");\n%s_type_symbol->accept(*this);\ns4o.print("'%(paramname)
       
    96             code_gen_dic_decl["return_type"] = '");\nreturn_type_symbol->accept(*this);\ns4o.print("'
       
    97             code_gen_dic_decl["param_count"] = '");\ns4o.print_integer(nb_param);\ns4o.print("'
       
    98             code_gen_dic_decl["start_bool_filter"] = '");\nif (search_expression_type->is_bool_type(last_type_symbol))\n  s4o.print("('
       
    99             code_gen_dic_decl["end_bool_filter"] = '");\nif (search_expression_type->is_bool_type(last_type_symbol)) {\n  s4o.print("&1");\n  s4o.print(")");\n}\ns4o.print("'
       
   100             
       
   101             if type(code_gen) == type(tuple()):
       
   102                 res += 's4o.print("%s");\n'%(code_gen[0]%code_gen_dic_decl)
       
   103                 static_param_accept_list = []
       
   104                 for paramname,paramtype,unused in fdecl["inputs"]:
       
   105                     static_param_accept_list.append("%s_param_value->accept(*this);\n"%(paramname))
       
   106                 res += ('s4o.print("%s");\n'%(code_gen[1])).join(static_param_accept_list)
       
   107                 code = 's4o.print("%s");\nparam_value->accept(*this);\n'%(code_gen[1])
       
   108                 end_code = 's4o.print("%s");\nreturn NULL;\n'%(code_gen[2]%code_gen_dic_decl)
       
   109             else:
       
   110                 code = ''
       
   111                 end_code = ('s4o.print("' + code_gen%code_gen_dic_decl + '");\nreturn NULL;\n').replace('s4o.print("");\n','')
       
   112 
       
   113             if fdecl["extensible"]:
       
   114                 res += ("""
       
   115 int base_num = %d;
       
   116 symbol_c *param_value = NULL;
       
   117 do{
       
   118     char my_name[10];
       
   119     sprintf(my_name, "IN%%d", base_num++);
       
   120     identifier_c param_name(my_name);
       
   121     
       
   122     /* Get the value from a foo(<param_name> = <param_value>) style call */
       
   123     param_value = function_call_param_iterator.search(&param_name);
       
   124     
       
   125     /* Get the value from a foo(<param_value>) style call */
       
   126     if (param_value == NULL)
       
   127       param_value = function_call_param_iterator.next();
       
   128     if (param_value != NULL){
       
   129         symbol_c *current_type_symbol = search_expression_type->get_type(param_value);
       
   130         last_type_symbol = last_type_symbol && search_expression_type->is_same_type(current_type_symbol, last_type_symbol) ? search_expression_type->common_type(current_type_symbol, last_type_symbol) : current_type_symbol ;
       
   131     
       
   132         /*Function specific CODE */
       
   133         %s
       
   134     }
       
   135     
       
   136 }while(param_value != NULL);
       
   137 %s
       
   138 """%(fdecl["baseinputnumber"]+2, code.replace('\n','\n        '), end_code))
       
   139             else:
       
   140                 #res += code + end_code
       
   141                 res += end_code
       
   142         else:
       
   143             res += "return return_type_symbol;\n"
       
   144         
       
   145                 
       
   146         return res.replace('\n','\n'+indent)
       
   147 
       
   148 ###################################################################
       
   149 ###                                                             ###
       
   150 ###                           MAIN                              ###
       
   151 ###                                                             ###
       
   152 ###################################################################
       
   153 
       
   154 """
       
   155 Reorganize std_decl from structure.py
       
   156 into a nested dictionnary structure (i.e. a tree):
       
   157 "{fname : {IN[0]paramname : {IN[0]paramtype : {IN[1]paraname : {IN[1]paramtype : {... : {IN[N]paraname : {IN[N]paramtype : (fdecl,)}}}}}}"
       
   158 Keep ptrack of original declaration order in a 
       
   159 separated list called official_order
       
   160 """
       
   161 std_fdecls = {}
       
   162 official_order = []
       
   163 for section in std_decl:
       
   164     for fdecl in section["list"]:
       
   165         if len(official_order)==0 or official_order[-1] != fdecl["name"]:
       
   166             official_order.append(fdecl["name"])
       
   167         # store all func by name in a dict
       
   168         std_fdecls_fdecl_name = std_fdecls.get(fdecl["name"], {})
       
   169         current = std_fdecls_fdecl_name
       
   170         for i in fdecl["inputs"]:
       
   171             current[i[0]] = current.get(i[0], {})
       
   172             current = current[i[0]]
       
   173             last = current
       
   174             current[i[1]] = current.get(i[1], {})
       
   175             current = current[i[1]]
       
   176         last[i[1]]=(fdecl,)
       
   177         std_fdecls[fdecl["name"]] = std_fdecls_fdecl_name
       
   178 
       
   179 ###################################################################
       
   180 
       
   181 """
       
   182 Generate the long enumeration of std function types
       
   183 """
       
   184 function_type_decl =  """
       
   185 /****
       
   186  * IEC 61131-3 standard function lib
       
   187  * generated code, do not edit by hand
       
   188  */
       
   189 typedef enum {
       
   190 """
       
   191 for fname, fdecls in [ (fname,std_fdecls[fname]) for fname in official_order ]:
       
   192     function_type_decl += "    function_"+fname.lower()+",\n"
       
   193 
       
   194 function_type_decl += """    function_none
       
   195 } function_type_t;
       
   196 """
       
   197 ###################################################################
       
   198 """
       
   199 Generate the funct that return enumerated according function name
       
   200 """
       
   201 get_function_type_decl = """
       
   202 /****
       
   203  * IEC 61131-3 standard function lib
       
   204  * generated code, do not edit by hand
       
   205  */
       
   206 function_type_t get_function_type(identifier_c *function_name) {
       
   207 """
       
   208 for fname, fdecls in [ (fname,std_fdecls[fname]) for fname in official_order ]:
       
   209     get_function_type_decl += """
       
   210 if (!strcasecmp(function_name->value, "%s"))
       
   211     return function_%s;
       
   212 """%(fname,fname.lower())
       
   213 
       
   214 get_function_type_decl += """
       
   215     else return function_none;
       
   216 }
       
   217 
       
   218 """
       
   219 ###################################################################
       
   220 """
       
   221 Generate the part of generate_cc_st_c::visit(function_invocation)
       
   222 that is responsible to generate C code for std lib calls.
       
   223 """
       
   224 st_code_gen = """
       
   225 /****
       
   226  * IEC 61131-3 standard function lib
       
   227  * generated code, do not edit by hand
       
   228  */
       
   229 switch(current_function_type){
       
   230 """
       
   231 
       
   232 for fname, fdecls in [ (fname,std_fdecls[fname]) for fname in official_order ]:
       
   233     st_code_gen += """
       
   234 /****
       
   235  *%s
       
   236  */
       
   237     case function_%s :
       
   238     {
       
   239         symbol_c *last_type_symbol = NULL;
       
   240 """    %(fname, fname.lower())
       
   241     indent =  "    "
       
   242 
       
   243     st_code_gen += recurse_and_indent(fdecls, indent).replace('\n','\n    ')
       
   244     
       
   245     st_code_gen += """
       
   246     }/*function_%s*/
       
   247     break;
       
   248 """    %(fname.lower())
       
   249 st_code_gen +=  """
       
   250     case function_none :
       
   251     ERROR;
       
   252 }
       
   253 return NULL;
       
   254 """
       
   255 
       
   256 ###################################################################
       
   257 """
       
   258 Generate the part of generate_cc_il_c::visit(il_function_call)
       
   259 that is responsible to generate C code for std lib calls.
       
   260 """
       
   261 il_code_gen = """
       
   262 /****
       
   263  * IEC 61131-3 standard function lib
       
   264  * generated code, do not edit by hand
       
   265  */
       
   266 switch(current_function_type){
       
   267 """
       
   268 
       
   269 for fname, fdecls in [ (fname,std_fdecls[fname]) for fname in official_order ]:
       
   270     il_code_gen += """
       
   271 /****
       
   272  *%s
       
   273  */
       
   274     case function_%s :
       
   275     {
       
   276         symbol_c *last_type_symbol = NULL;
       
   277 """    %(fname, fname.lower())
       
   278     indent =  "    "
       
   279 
       
   280     il_code_gen += recurse_and_indent(fdecls, indent, do_il=True).replace('\n','\n    ')
       
   281     
       
   282     il_code_gen += """
       
   283     }/*function_%s*/
       
   284     break;
       
   285 """    %(fname.lower())
       
   286 il_code_gen +=  """
       
   287     case function_none :
       
   288     ERROR;
       
   289 }
       
   290 return NULL;
       
   291 """
       
   292 
       
   293 ###################################################################
       
   294 """
       
   295 Generate the part of search_expression_type_c::visit(function_invocation)
       
   296 that is responsible of returning type symbol for function invocation.
       
   297 """
       
   298 search_type_code =  """
       
   299 /****
       
   300  * IEC 61131-3 standard function lib
       
   301  * generated code, do not edit by hand
       
   302  */
       
   303 
       
   304 void *compute_standard_function_st(function_invocation_c *symbol) {
       
   305 
       
   306   function_type_t current_function_type = get_function_type((identifier_c *)symbol->function_name);
       
   307   function_call_param_iterator_c function_call_param_iterator(symbol);
       
   308   search_expression_type_c* search_expression_type = this;
       
   309 
       
   310   switch(current_function_type){
       
   311 """
       
   312 
       
   313 for fname, fdecls in [ (fname,std_fdecls[fname]) for fname in official_order ]:
       
   314     search_type_code += """
       
   315 /****
       
   316  *%s
       
   317  */
       
   318     case function_%s :
       
   319     {
       
   320         symbol_c *last_type_symbol = NULL;
       
   321 """    %(fname, fname.lower())
       
   322     indent =  "    "
       
   323 
       
   324     search_type_code += recurse_and_indent(fdecls, indent, True).replace('\n','\n    ')
       
   325     
       
   326     search_type_code += """
       
   327     }/*function_%s*/
       
   328     break;
       
   329 """    %(fname.lower())
       
   330 search_type_code += """
       
   331     case function_none :
       
   332     ERROR;
       
   333   }
       
   334   return NULL;
       
   335 }
       
   336 
       
   337 void *compute_standard_function_il(il_function_call_c *symbol, symbol_c *param_data_type) {
       
   338   
       
   339   function_type_t current_function_type = get_function_type((identifier_c *)symbol->function_name);
       
   340   function_call_param_iterator_c function_call_param_iterator(symbol);  
       
   341   search_expression_type_c* search_expression_type = this;
       
   342 
       
   343   switch(current_function_type){
       
   344 """
       
   345 
       
   346 for fname, fdecls in [ (fname,std_fdecls[fname]) for fname in official_order ]:
       
   347     search_type_code += """
       
   348 /****
       
   349  *%s
       
   350  */
       
   351     case function_%s :
       
   352     {
       
   353         symbol_c *last_type_symbol = NULL;
       
   354 """    %(fname, fname.lower())
       
   355     indent =  "    "
       
   356 
       
   357     search_type_code += recurse_and_indent(fdecls, indent, True, True).replace('\n','\n    ')
       
   358     
       
   359     search_type_code += """
       
   360     }/*function_%s*/
       
   361     break;
       
   362 """    %(fname.lower())
       
   363 search_type_code += """
       
   364     case function_none :
       
   365     ERROR;
       
   366   }
       
   367   return NULL;
       
   368 }
       
   369 """
       
   370 
       
   371 ###################################################################
       
   372 ###################################################################
       
   373 ###################################################################
       
   374 """
       
   375 Generate the C implementation of the IEC standard function library.
       
   376 """
       
   377 iec_std_lib_generated =  """
       
   378 /****
       
   379  * IEC 61131-3 standard function lib
       
   380  * generated code, do not edit by hand
       
   381  */
       
   382 
       
   383 /* Macro that expand to subtypes */
       
   384 """
       
   385 for typename, parenttypename in TypeHierarchy_list:
       
   386     if (typename.startswith("ANY")):
       
   387         iec_std_lib_generated += "#define " + typename + "(DO)"
       
   388         for typename2, parenttypename2 in TypeHierarchy_list:
       
   389             if(parenttypename2 == typename):
       
   390                 if(typename2.startswith("ANY")):
       
   391                     iec_std_lib_generated +=  " " + typename2 + "(DO)"
       
   392                 else:
       
   393                     iec_std_lib_generated +=  " DO(" + typename2 + ")"
       
   394         iec_std_lib_generated +=  "\n"
       
   395     else:
       
   396         break
       
   397 
       
   398 if len(sys.argv) != 2 :
       
   399     print "Usage: " + sys.argv[0] + "path_name\n -> create files in path_name"
       
   400     sys.exit(0)
       
   401 
       
   402 # Now, print that out, or write to files from sys.argv
       
   403 for name, ext in [
       
   404         ('function_type_decl','h'),
       
   405         ('get_function_type_decl','c'),
       
   406         ('st_code_gen','c'),
       
   407         ('il_code_gen','c'),
       
   408         ('search_type_code','c'),
       
   409         ('iec_std_lib_generated','h')]:
       
   410     fd = open(os.path.join(sys.argv[1],name+'.'+ext),'w')
       
   411     fd.write(eval(name))
       
   412     fd.close()