Changeset 4339764 in sasmodels for sasmodels/py2c.py


Ignore:
Timestamp:
Jan 5, 2018 11:54:32 AM (6 years ago)
Author:
Omer Eisenberg <omereis@…>
Children:
0bd0877
Parents:
2694cb8
Message:

printing warnings

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/py2c.py

    r7b1dcf9 r4339764  
    1  
    21""" 
    3     codegen 
    4     ~~~~~~~ 
    5  
    6     Extension to ast that allow ast -> python code generation. 
    7  
    8     :copyright: Copyright 2008 by Armin Ronacher. 
    9     :license: BSD. 
    10 """ 
    11 """ 
     2    py2c 
     3    ~~~~ 
     4 
     5    Convert simple numeric python code into C code. 
     6 
     7    The translate() function works on 
     8 
    129    Variables definition in C 
    1310    ------------------------- 
    14     Defining variables within the Translate function is a bit of a guess work, 
    15     using following rules. 
     11    Defining variables within the translate function is a bit of a guess work, 
     12    using following rules: 
    1613    *   By default, a variable is a 'double'. 
    1714    *   Variable in a for loop is an int. 
     
    1916        variable within the brackets is integer. For example, in the 
    2017        reference 'var1[var2]', var1 is a double array, and var2 is an integer. 
    21     *   Assignment to an argument makes that argument an array, and the index in 
    22         that assignment is 0. 
    23         For example, the following python code 
     18    *   Assignment to an argument makes that argument an array, and the index 
     19        in that assignment is 0. 
     20        For example, the following python code:: 
    2421            def func(arg1, arg2): 
    2522                arg2 = 17. 
    26         is translated to the following C code 
     23        is translated to the following C code:: 
    2724            double func(double arg1) 
    2825            { 
    2926                arg2[0] = 17.0; 
    3027            } 
    31         For example, the following python code is translated to the following C code 
     28        For example, the following python code is translated to the 
     29        following C code:: 
     30 
    3231            def func(arg1, arg2):          double func(double arg1) { 
    3332                arg2 = 17.                      arg2[0] = 17.0; 
    3433                                            } 
    35     *   All functions are defined as double, even if there is no return statement. 
    36  
    37  
     34    *   All functions are defined as double, even if there is no 
     35        return statement. 
     36 
     37Based on codegen.py: 
     38 
     39    :copyright: Copyright 2008 by Armin Ronacher. 
     40    :license: BSD. 
     41""" 
     42""" 
    3843Update Notes 
    3944============ 
    40 11/22 14:15, O.E.   Each 'visit_*' method is to build a C statement string. It 
     4511/22/2017, O.E.   Each 'visit_*' method is to build a C statement string. It 
    4146                    shold insert 4 blanks per indentation level. 
    4247                    The 'body' method will combine all the strings, by adding 
     
    525712/07/2017, OE: Translation of integer division, '\\' in python, implemented 
    5358                in translate_integer_divide, called from visit_BinOp 
    54 12/07/2017, OE: C variable definition handled in 'define_C_Vars' 
     5912/07/2017, OE: C variable definition handled in 'define_c_vars' 
    5560              : Python integer division, '//', translated to C in 
    5661                'translate_integer_divide' 
     
    596412/18/2017, OE: Added call to 'add_current_line()' at the beginning 
    6065                of visit_Return 
     6601/4/2018, O.E. Added functions 'get_files_names()', , 'print_usage()'. The get_files_names() 
     67                function retrieves the in/out file names form the command line, and returns 
     68                true/false if the number of parameters is valid. In case of no input 
     69                parameters, usage is prompt and the program terminates. 
     7001/4/2018, O.E. 'translate(functions, constants=None)' returns string, instaed of a list 
     7101/04/2017 O.E. Fixed bug in 'visit_If': visiting node.orelse in case else exists. 
     7201/05/2018 O.E. New class C_Vector defined. It holds name, type, size and initial values. 
     73                Assignment to that class in 'sequence_visit'. 
     74                Reading and inserting declaration in 'insert_c_vars' 
     75 
    6176 
    6277""" 
     
    102117 
    103118 
    104 def to_source(node, func_name, constants=None): 
    105     """This function can convert a node tree back into python sourcecode. 
    106     This is useful for debugging purposes, especially if you're dealing with 
    107     custom asts not generated by python itself. 
    108  
    109     It could be that the sourcecode is evaluable when the AST itself is not 
    110     compilable / evaluable.  The reason for this is that the AST contains some 
    111     more data than regular sourcecode does, which is dropped during 
    112     conversion. 
    113  
    114     Each level of indentation is replaced with `indent_with`.  Per default this 
    115     parameter is equal to four spaces as suggested by PEP 8, but it might be 
    116     adjusted to match the application's styleguide. 
    117  
    118     If `add_line_information` is set to `True` comments for the line numbers 
    119     of the nodes are added to the output.  This can be used to spot wrong line 
    120     number information of statement nodes. 
     119def to_source(tree, constants=None, fname=None, lineno=0): 
    121120    """ 
    122     generator = SourceGenerator(' ' * 4, False, constants) 
    123     generator.visit(node) 
    124  
    125     return ''.join(generator.c_proc) 
     121    This function can convert a syntax tree into C sourcecode. 
     122    """ 
     123    generator = SourceGenerator(constants=constants, fname=fname, lineno=lineno) 
     124    generator.visit(tree) 
     125    c_code = "\n".join(generator.c_proc) 
     126    c_code = "".join(generator.c_proc) 
     127    return (c_code, generator.warnings) 
    126128 
    127129def isevaluable(s): 
     
    129131        eval(s) 
    130132        return True 
    131     except: 
     133    except Exception: 
    132134        return False 
     135 
     136class C_Vector(): 
     137    def __init__(self): 
     138        self.size = 0 
     139        self.type = "double" 
     140        self.values = [] 
     141        self.assign_line = -1 
     142        self.name = "" 
     143 
     144    def get_leading_space(self, indent_with="    ", indent_level = 1): 
     145        leading_space = "" 
     146        for n in range(indent_level): 
     147            leading_space += indent_with 
     148        return leading_space 
     149         
     150    def item_declare_string(self, indent_with="    ", indent_level = 1): 
     151        declare_string = self.name + "[" + str(len(self.values)) + "]" 
     152        return declare_string 
     153     
     154    def declare_string(self, indent_with="    ", indent_level = 1): 
     155        declare_string = self.get_leading_space(indent_with, indent_level) 
     156        declare_string += self.type + " " + item_declare_string(indent_with, indent_level) 
     157#        self.name + "[" + str(len(self.values)) + "];\n" 
     158        return declare_string 
     159     
     160    def get_assign(self, indent_with="    ", indent_level = 1): 
     161        assign_loop = [] 
     162        c_string = self.get_leading_space(indent_with, indent_level - 1) 
     163        c_string += "for (n=0 ; n < " + str(len(self.values)) + " ; n++) {" 
     164        assign_loop.append(c_string) 
     165        for n,value in enumerate(self.values): 
     166            c_string = self.get_leading_space(indent_with, indent_level) 
     167            c_string += self.name + "[" + str(n) + "] = " + str(value) + ";" 
     168            assign_loop.append(c_string) 
     169        c_string = self.get_leading_space(indent_with, indent_level - 1) + "}" 
     170        assign_loop.append(c_string) 
     171        return (assign_loop) 
    133172 
    134173class SourceGenerator(NodeVisitor): 
     
    138177    """ 
    139178 
    140     def __init__(self, indent_with, add_line_information=False, constants=None): 
     179    def __init__(self, indent_with="    ", add_line_information=False, 
     180                 constants=None, fname=None, lineno=0): 
    141181        self.result = [] 
    142182        self.indent_with = indent_with 
     
    144184        self.indentation = 0 
    145185        self.new_lines = 0 
     186 
     187        # for C 
    146188        self.c_proc = [] 
    147         # for C 
    148189        self.signature_line = 0 
    149190        self.arguments = [] 
    150         self.name = "" 
     191        self.current_function = "" 
     192        self.fname = fname 
     193        self.lineno_offset = lineno 
    151194        self.warnings = [] 
    152         self.Statements = [] 
     195        self.statements = [] 
    153196        self.current_statement = "" 
    154         self.strMethodSignature = "" 
    155         self.C_Vars = [] 
    156         self.C_IntVars = [] 
    157         self.MathIncludeed = False 
    158         self.C_Pointers = [] 
    159         self.C_DclPointers = [] 
    160         self.C_Functions = [] 
    161         self.C_Vectors = [] 
    162         self.C_Constants = constants 
    163         self.SubRef = False 
    164         self.InSubscript = False 
    165         self.Tuples = [] 
     197        # TODO: use set rather than list for c_vars, ... 
     198        self.c_vars = [] 
     199        self.c_int_vars = [] 
     200        self.c_pointers = [] 
     201        self.c_dcl_pointers = [] 
     202        self.c_functions = [] 
     203        self.c_vectors = [] 
     204        self.c_constants = constants if constants is not None else {} 
     205        self.in_subref = False 
     206        self.in_subscript = False 
     207        self.tuples = [] 
    166208        self.required_functions = [] 
    167209        self.is_sequence = False 
    168210        self.visited_args = False 
     211        self.inside_if = False 
     212        self.C_Vectors = [] 
     213        self.assign_target = "" 
     214        self.assign_c_vector = [] 
    169215 
    170216    def write_python(self, x): 
     
    176222        self.result.append(x) 
    177223 
    178     def write_c(self, x): 
    179         self.current_statement += x 
    180  
    181     def add_c_line(self, x): 
    182         string = '' 
    183         for _ in range(self.indentation): 
    184             string += ("    ") 
    185         string += str(x) 
    186         self.c_proc.append(str(string + "\n")) 
    187         x = '' 
     224    def write_c(self, statement): 
     225        # TODO: build up as a list rather than adding to string 
     226        self.current_statement += statement 
     227 
     228    def add_c_line(self, line): 
     229        indentation = self.indent_with * self.indentation 
     230        self.c_proc.append("".join((indentation, line, "\n"))) 
    188231 
    189232    def add_current_line(self): 
     
    192235            self.current_statement = '' 
    193236 
    194     def AddUniqueVar(self, new_var): 
    195         if new_var not in self.C_Vars: 
    196             self.C_Vars.append(str(new_var)) 
    197  
    198     def WriteSincos(self, node): 
     237    def add_unique_var(self, new_var): 
     238        if new_var not in self.c_vars: 
     239            self.c_vars.append(str(new_var)) 
     240 
     241    def write_sincos(self, node): 
    199242        angle = str(node.args[0].id) 
    200243        self.write_c(node.args[1].id + " = sin(" + angle + ");") 
     
    203246        self.add_current_line() 
    204247        for arg in node.args: 
    205             self.AddUniqueVar(arg.id) 
     248            self.add_unique_var(arg.id) 
     249 
     250    def write_print(self, node): 
     251        self.write_c ("printf (") 
     252        c_str = self.current_statement 
     253        self.current_statement = "" 
     254        self.visit(node.args[0]) 
     255        print_params = self.current_statement # save print agruments 
     256        self.current_statement = c_str 
     257        print_params = print_params[1:(len(print_params) - 1)] # remove parentheses 
     258        prcnt = print_params.rfind('%') 
     259        if prcnt >= 0: 
     260            format_string = print_params[0:prcnt-1].strip() 
     261            format_string = format_string[1:len(format_string) - 1] 
     262            var_string = print_params[prcnt+1:len(print_params)].strip() 
     263        else: 
     264            format_string = print_params 
     265            var_string = "" 
     266        format_string= format_string[:len(format_string)] 
     267        self.write_c('"' + format_string + '\\n"') 
     268        if (len(var_string) > 0): 
     269            self.write_c(', ' + var_string) 
     270        self.write_c(");") 
     271        self.add_current_line() 
     272 
     273 
    206274 
    207275    def newline(self, node=None, extra=0): 
     
    211279            self.new_lines = 1 
    212280        if self.current_statement: 
    213             self.Statements.append(self.current_statement) 
     281            self.statements.append(self.current_statement) 
    214282            self.current_statement = '' 
    215283 
     
    258326                except AttributeError: 
    259327                    arg_name = arg.id 
    260                 w_str = ("Default Parameters are unknown to C: '%s = %s" 
    261                          % arg_name, str(default.n)) 
     328                w_str = ("Default Parameters are unknown to C: '%s = %s" \ 
     329                        % (arg_name, str(default.n))) 
    262330                self.warnings.append(w_str) 
    263331 
     
    278346            self.visit(node.msg) 
    279347 
    280     def define_C_Vars(self, target): 
     348    def define_c_vars(self, target): 
    281349        if hasattr(target, 'id'): 
    282350        # a variable is considered an array if it apears in the agrument list 
     
    287355        #  return 
    288356        # 
    289             if target.id not in self.C_Vars: 
     357            if target.id not in self.c_vars: 
    290358                if target.id in self.arguments: 
    291359                    idx = self.arguments.index(target.id) 
    292360                    new_target = self.arguments[idx] + "[0]" 
    293                     if new_target not in self.C_Pointers: 
     361                    if new_target not in self.c_pointers: 
    294362                        target.id = new_target 
    295                         self.C_Pointers.append(self.arguments[idx]) 
     363                        self.c_pointers.append(self.arguments[idx]) 
    296364                else: 
    297                     self.C_Vars.append(target.id) 
     365                    self.c_vars.append(target.id) 
    298366 
    299367    def add_semi_colon(self): 
     
    308376            if idx: 
    309377                self.write_c(' = ') 
    310             self.define_C_Vars(target) 
     378            self.define_c_vars(target) 
    311379            self.visit(target) 
    312         if self.Tuples: 
    313             tplTargets = list(self.Tuples) 
    314             del self.Tuples[:] 
     380            if hasattr(target,'id'): 
     381                self.assign_target = target.id 
     382        # Capture assigned tuple names, if any 
     383        targets = self.tuples[:] 
     384        del self.tuples[:] 
    315385        self.write_c(' = ') 
    316386        self.is_sequence = False 
    317387        self.visited_args = False 
    318388        self.visit(node.value) 
    319         self.add_semi_colon() 
    320         self.add_current_line() 
    321         for n, item in enumerate(self.Tuples): 
    322             self.visit(tplTargets[n]) 
    323             self.write_c(' = ') 
    324             self.visit(item) 
     389        if len(self.assign_c_vector): 
     390            for c_statement in self.assign_c_vector: 
     391                self.add_c_line (c_statement) 
     392#                self.c_proc.append(c_statement) 
     393            self.assign_c_vector.clear() 
     394        else: 
    325395            self.add_semi_colon() 
    326396            self.add_current_line() 
    327         if self.is_sequence and not self.visited_args: 
    328             for target in node.targets: 
    329                 if hasattr(target, 'id'): 
    330                     if target.id in self.C_Vars and target.id not in self.C_DclPointers: 
    331                         if target.id not in self.C_DclPointers: 
    332                             self.C_DclPointers.append(target.id) 
    333                             if target.id in self.C_Vars: 
    334                                 self.C_Vars.remove(target.id) 
     397        # Assign tuples to tuples, if any 
     398        # TODO: doesn't handle swap:  a,b = b,a 
     399            for target, item in zip(targets, self.tuples): 
     400                self.visit(target) 
     401                self.write_c(' = ') 
     402                self.visit(item) 
     403                self.add_semi_colon() 
     404                self.add_current_line() 
     405            if self.is_sequence and not self.visited_args: 
     406                for target in node.targets: 
     407                    if hasattr(target, 'id'): 
     408                        if target.id in self.c_vars and target.id not in self.c_dcl_pointers: 
     409                            if target.id not in self.c_dcl_pointers: 
     410                                self.c_dcl_pointers.append(target.id) 
     411                                if target.id in self.c_vars: 
     412                                    self.c_vars.remove(target.id) 
    335413        self.current_statement = '' 
     414        self.assign_target = '' 
    336415 
    337416    def visit_AugAssign(self, node): 
    338         if node.target.id not in self.C_Vars: 
     417        if node.target.id not in self.c_vars: 
    339418            if node.target.id not in self.arguments: 
    340                 self.C_Vars.append(node.target.id) 
     419                self.c_vars.append(node.target.id) 
    341420        self.visit(node.target) 
    342421        self.write_c(' ' + BINOP_SYMBOLS[type(node.op)] + '= ') 
     
    346425 
    347426    def visit_ImportFrom(self, node): 
     427        return  # import ignored 
    348428        self.newline(node) 
    349429        self.write_python('from %s%s import ' %('.' * node.level, node.module)) 
     
    354434 
    355435    def visit_Import(self, node): 
     436        return  # import ignored 
    356437        self.newline(node) 
    357438        for item in node.names: 
     
    363444        self.generic_visit(node) 
    364445 
    365     def listToDeclare(self, vars): 
    366         return ", ".join(vars) 
    367  
    368     def write_C_Pointers(self, start_var): 
    369         if self.C_DclPointers: 
     446    def write_c_pointers(self, start_var): 
     447        if self.c_dcl_pointers: 
    370448            var_list = [] 
    371             for c_ptr in self.C_DclPointers: 
    372                 if(len(vars) > 0): 
    373                     vars += ", " 
     449            for c_ptr in self.c_dcl_pointers: 
    374450                if c_ptr not in self.arguments: 
    375451                    var_list.append("*" + c_ptr) 
    376                 if c_ptr in self.C_Vars: 
    377                     self.C_Vars.remove(c_ptr) 
     452                if c_ptr in self.c_vars: 
     453                    self.c_vars.remove(c_ptr) 
    378454            if var_list: 
    379455                c_dcl = "    double " + ", ".join(var_list) + ";\n" 
     
    382458        return start_var 
    383459 
    384     def insert_C_Vars(self, start_var): 
    385         fLine = False 
    386         start_var = self.write_C_Pointers(start_var) 
    387         if self.C_IntVars: 
    388             for var in self.C_IntVars: 
    389                 if var in self.C_Vars: 
    390                     self.C_Vars.remove(var) 
    391             s = self.listToDeclare(self.C_IntVars) 
    392             self.c_proc.insert(start_var, "    int " + s + ";\n") 
    393             fLine = True 
     460    def insert_c_vars(self, start_var): 
     461        have_decls = False 
     462        start_var = self.write_c_pointers(start_var) 
     463        if self.c_int_vars: 
     464            for var in self.c_int_vars: 
     465                if var in self.c_vars: 
     466                    self.c_vars.remove(var) 
     467            decls = ", ".join(self.c_int_vars) 
     468            self.c_proc.insert(start_var, "    int " + decls + ";\n") 
     469            have_decls = True 
    394470            start_var += 1 
    395  
    396         if self.C_Vars: 
    397             s = self.listToDeclare(self.C_Vars) 
    398             self.c_proc.insert(start_var, "    double " + s + ";\n") 
    399             fLine = True 
     471        if len(self.C_Vectors) > 0: 
     472            vec_declare = [] 
     473            for c_vec in self.C_Vectors: 
     474                item_declare = c_vec.item_declare_string() 
     475                if item_declare not in vec_declare: 
     476                    vec_declare.append (item_declare) 
     477                if c_vec.name in self.c_vars: 
     478                    self.c_vars.remove(c_vec.name) 
     479            all_declare = "    double " + ", ".join (vec_declare) + ";\n" 
     480            self.c_proc.insert(start_var, all_declare) 
    400481            start_var += 1 
    401482 
    402         if self.C_Vectors: 
    403             s = self.listToDeclare(self.C_Vectors) 
    404             for n in range(len(self.C_Vectors)): 
    405                 name = "vec" + str(n+1) 
    406                 c_dcl = "    double " + name + "[] = {" + self.C_Vectors[n] + "};" 
    407                 self.c_proc.insert(start_var, c_dcl + "\n") 
     483        if self.c_vars: 
     484            decls = ", ".join(self.c_vars) 
     485            self.c_proc.insert(start_var, "    double " + decls + ";\n") 
     486            have_decls = True 
     487            start_var += 1 
     488 
     489        if self.c_vectors: 
     490            for vec_number, vec_value  in enumerate(self.c_vectors): 
     491                name = "vec" + str(vec_number + 1) 
     492                decl = "    double " + name + "[] = {" + vec_value + "};" 
     493                self.c_proc.insert(start_var, decl + "\n") 
    408494                start_var += 1 
    409495 
    410         del self.C_Vars[:] 
    411         del self.C_IntVars[:] 
    412         del self.C_Vectors[:] 
    413         del self.C_Pointers[:] 
    414         self.C_DclPointers 
    415         if fLine: 
     496        del self.c_vars[:] 
     497        del self.c_int_vars[:] 
     498        del self.c_vectors[:] 
     499        del self.c_pointers[:] 
     500        del self.c_dcl_pointers[:] 
     501        if have_decls: 
    416502            self.c_proc.insert(start_var, "\n") 
    417503 
    418     def InsertSignature(self): 
     504    def insert_signature(self): 
    419505        arg_decls = [] 
    420506        for arg in self.arguments: 
    421507            decl = "double " + arg 
    422             if arg in self.C_Pointers: 
     508            if arg in self.c_pointers: 
    423509                decl += "[]" 
    424510            arg_decls.append(decl) 
    425511        args_str = ", ".join(arg_decls) 
    426         self.strMethodSignature = 'double ' + self.name + '(' + args_str + ")" 
     512        method_sig = 'double ' + self.current_function + '(' + args_str + ")" 
    427513        if self.signature_line >= 0: 
    428             self.c_proc.insert(self.signature_line, self.strMethodSignature) 
     514            self.c_proc.insert(self.signature_line, method_sig) 
    429515 
    430516    def visit_FunctionDef(self, node): 
     517        if self.current_function: 
     518            self.unsupported(node, "function within a function") 
     519        self.current_function = node.name 
     520 
     521        warning_index = len(self.warnings) 
    431522        self.newline(extra=1) 
    432523        self.decorators(node) 
    433524        self.newline(node) 
    434525        self.arguments = [] 
    435         self.name = node.name 
    436         #if self.name not in self.required_functions[0]: 
    437         #   return 
    438         #print("Parsing '" + self.name + "'") 
    439  
    440526        self.visit(node.args) 
    441527        # for C 
    442528        self.signature_line = len(self.c_proc) 
    443         #self.add_c_line(self.strMethodSignature) 
    444529        self.add_c_line("\n{") 
    445530        start_vars = len(self.c_proc) + 1 
    446531        self.body(node.body) 
    447532        self.add_c_line("}\n") 
    448         self.InsertSignature() 
    449         self.insert_C_Vars(start_vars) 
    450         self.C_Pointers = [] 
     533        self.insert_signature() 
     534        self.insert_c_vars(start_vars) 
     535#        self.c_pointers = [] 
     536        self.c_pointers.clear() 
     537        self.C_Vectors.clear() 
     538        self.current_function = "" 
     539        if (warning_index != len(self.warnings)): 
     540            self.warnings.insert(warning_index, "Warning in function '" + node.name + "':") 
     541            self.warnings.append("Note: C compilation will fail") 
     542 
    451543 
    452544    def visit_ClassDef(self, node): 
     
    484576 
    485577    def visit_If(self, node): 
     578        self.add_current_line() 
     579        self.inside_if = True 
    486580        self.write_c('if ') 
    487581        self.visit(node.test) 
     
    507601                self.newline() 
    508602                self.write_c('else {') 
    509                 self.body(node.body) 
     603                self.body(node.orelse) 
    510604                self.add_c_line('}') 
    511605                break 
    512  
    513     def getNodeLineNo(self, node): 
    514         line_number = -1 
    515         if hasattr(node, 'value'): 
    516             line_number = node.value.lineno 
    517         elif hasattr(node, 'iter'): 
    518             if hasattr(node.iter, 'lineno'): 
    519                 line_number = node.iter.lineno 
    520         return line_number 
    521  
    522     def GetNodeAsString(self, node): 
    523         res = '' 
    524         if hasattr(node, 'n'): 
    525             res = str(node.n) 
    526         elif hasattr(node, 'id'): 
    527             res = node.id 
    528         return res 
    529  
    530     def GetForRange(self, node): 
     606        self.inside_if = False 
     607 
     608    def get_for_range(self, node): 
    531609        stop = "" 
    532610        start = '0' 
     
    553631        return start, stop, step 
    554632 
     633    def add_c_int_var (self, iterator): 
     634        if iterator not in self.c_int_vars: 
     635            self.c_int_vars.append(iterator) 
     636 
    555637    def visit_For(self, node): 
    556638        # node: for iterator is stored in node.target. 
     
    565647                    iterator = self.current_statement 
    566648                    self.current_statement = '' 
    567                     if iterator not in self.C_IntVars: 
    568                         self.C_IntVars.append(iterator) 
    569                     start, stop, step = self.GetForRange(node) 
     649                    self.add_c_int_var (iterator) 
     650                    start, stop, step = self.get_for_range(node) 
    570651                    self.write_c("for(" + iterator + "=" + str(start) + 
    571652                                 " ; " + iterator + " < " + str(stop) + 
     
    575656                    fForDone = True 
    576657        if not fForDone: 
    577             line_number = self.getNodeLineNo(node) 
     658            # Generate the statement that is causing the error 
    578659            self.current_statement = '' 
    579660            self.write_c('for ') 
     
    582663            self.visit(node.iter) 
    583664            self.write_c(':') 
    584             errStr = "Conversion Error in function " + self.name + ", Line #" + str(line_number) 
    585             errStr += "\nPython for expression not supported: '" + self.current_statement + "'" 
    586             raise Exception(errStr) 
     665            # report the error 
     666            self.unsupported("unsupported " + self.current_statement) 
    587667 
    588668    def visit_While(self, node): 
     
    590670        self.write_c('while ') 
    591671        self.visit(node.test) 
    592         self.write_c(':') 
     672        self.write_c(' { ') 
    593673        self.body_or_else(node) 
     674        self.write_c('}') 
     675        self.add_current_line() 
    594676 
    595677    def visit_With(self, node): 
     678        self.unsupported(node) 
    596679        self.newline(node) 
    597680        self.write_python('with ') 
     
    605688    def visit_Pass(self, node): 
    606689        self.newline(node) 
    607         self.write_python('pass') 
     690        #self.write_python('pass') 
    608691 
    609692    def visit_Print(self, node): 
     693        # TODO: print support would be nice, though hard to do 
     694        self.unsupported(node) 
    610695        # CRUFT: python 2.6 only 
    611696        self.newline(node) 
     
    625710 
    626711    def visit_Delete(self, node): 
     712        self.unsupported(node) 
    627713        self.newline(node) 
    628714        self.write_python('del ') 
     
    633719 
    634720    def visit_TryExcept(self, node): 
     721        self.unsupported(node) 
    635722        self.newline(node) 
    636723        self.write_python('try:') 
     
    640727 
    641728    def visit_TryFinally(self, node): 
     729        self.unsupported(node) 
    642730        self.newline(node) 
    643731        self.write_python('try:') 
     
    648736 
    649737    def visit_Global(self, node): 
     738        self.unsupported(node) 
    650739        self.newline(node) 
    651740        self.write_python('global ' + ', '.join(node.names)) 
     
    676765 
    677766    def visit_Raise(self, node): 
     767        self.unsupported(node) 
    678768        # CRUFT: Python 2.6 / 3.0 compatibility 
    679769        self.newline(node) 
     
    697787 
    698788    def visit_Attribute(self, node): 
    699         errStr = "Conversion Error in function " + self.name + ", Line #" + str(node.value.lineno) 
    700         errStr += "\nPython expression not supported: '" + node.value.id + "." + node.attr + "'" 
    701         raise Exception(errStr) 
     789        self.unsupported(node, "attribute reference a.b not supported") 
    702790        self.visit(node.value) 
    703791        self.write_python('.' + node.attr) 
     
    711799                want_comma.append(True) 
    712800        if hasattr(node.func, 'id'): 
    713             if node.func.id not in self.C_Functions: 
    714                 self.C_Functions.append(node.func.id) 
     801            if node.func.id not in self.c_functions: 
     802                self.c_functions.append(node.func.id) 
    715803            if node.func.id == 'abs': 
    716804                self.write_c("fabs ") 
     
    718806                self.write_c('(int) ') 
    719807            elif node.func.id == "SINCOS": 
    720                 self.WriteSincos(node) 
     808                self.write_sincos(node) 
     809                return 
     810            elif node.func.id == "print": 
     811                self.write_print(node) 
    721812                return 
    722813            else: 
     
    724815        else: 
    725816            self.visit(node.func) 
    726 #self.C_Functions 
    727817        self.write_c('(') 
    728818        for arg in node.args: 
     
    744834                self.write_c('**') 
    745835                self.visit(node.kwargs) 
    746         self.write_c(');') 
     836        self.write_c(')') 
     837        if (self.inside_if == False): 
     838            self.write_c(';') 
    747839 
    748840    def visit_Name(self, node): 
    749841        self.write_c(node.id) 
    750         if node.id in self.C_Pointers and not self.SubRef: 
     842        if node.id in self.c_pointers and not self.in_subref: 
    751843            self.write_c("[0]") 
    752844        name = "" 
     
    756848        else: 
    757849            name = node.id 
    758         # add variable to C_Vars if it ins't there yet, not an argument and not a number 
    759         if (name not in self.C_Functions and name not in self.C_Vars and 
    760                 name not in self.C_IntVars and name not in self.arguments and 
    761                 name not in self.C_Constants and not name.isdigit()): 
    762             if self.InSubscript: 
    763                 self.C_IntVars.append(node.id) 
     850        # add variable to c_vars if it ins't there yet, not an argument and not a number 
     851        if (name not in self.c_functions and name not in self.c_vars and 
     852                name not in self.c_int_vars and name not in self.arguments and 
     853                name not in self.c_constants and not name.isdigit()): 
     854            if self.in_subscript: 
     855                self.add_c_int_var (self, node.id) 
    764856            else: 
    765                 self.C_Vars.append(node.id) 
     857                self.c_vars.append(node.id) 
    766858 
    767859    def visit_Str(self, node): 
     
    777869        for idx, item in enumerate(node.elts): 
    778870            if idx: 
    779                 self.Tuples.append(item) 
     871                self.tuples.append(item) 
    780872            else: 
    781873                self.visit(item) 
     
    784876        def visit(self, node): 
    785877            self.is_sequence = True 
     878            c_vec = C_Vector() 
    786879            s = "" 
    787880            for idx, item in enumerate(node.elts): 
     
    789882                    s += ', ' 
    790883                if hasattr(item, 'id'): 
    791                     s += item.id 
     884                    c_vec.values.append(item.id) 
     885#                    s += item.id 
    792886                elif hasattr(item, 'n'): 
    793                     s += str(item.n) 
    794             if s: 
    795                 self.C_Vectors.append(s) 
    796                 vec_name = "vec"  + str(len(self.C_Vectors)) 
    797                 self.write_c(vec_name) 
     887                    c_vec.values.append(item.n) 
     888#                    s += str(item.n) 
     889                else: 
     890                    temp = self.current_statement 
     891                    self.current_statement = "" 
     892                    self.visit(item) 
     893                    c_vec.values.append(self.current_statement) 
     894#                    s += self.current_statement 
     895                    self.current_statement = temp 
     896            if (self.assign_target): 
     897                self.add_c_int_var ('n') 
     898                c_vec.name = self.assign_target 
     899                self.C_Vectors.append(c_vec) 
     900                assign_strings = c_vec.get_assign() 
     901                for assign_str in assign_strings: 
     902                    self.assign_c_vector.append(assign_str) 
     903#                    self.add_c_line(assign_str) 
     904#            if s: 
     905#                self.c_vectors.append(s) 
     906#                vec_name = "vec"  + str(len(self.c_vectors)) 
     907#                self.write_c(vec_name) 
    798908        return visit 
    799909 
     
    803913 
    804914    def visit_Dict(self, node): 
     915        self.unsupported(node) 
    805916        self.write_python('{') 
    806917        for idx, (key, value) in enumerate(zip(node.keys, node.values)): 
     
    9011012 
    9021013    def visit_Subscript(self, node): 
    903         if node.value.id not in self.C_Constants: 
    904             if node.value.id not in self.C_Pointers: 
    905                 self.C_Pointers.append(node.value.id) 
    906         self.SubRef = True 
     1014        if node.value.id not in self.c_constants: 
     1015            if node.value.id not in self.c_pointers: 
     1016                self.c_pointers.append(node.value.id) 
     1017        self.in_subref = True 
    9071018        self.visit(node.value) 
    908         self.SubRef = False 
     1019        self.in_subref = False 
    9091020        self.write_c('[') 
    910         self.InSubscript = True 
     1021        self.in_subscript = True 
    9111022        self.visit(node.slice) 
    912         self.InSubscript = False 
     1023        self.in_subscript = False 
    9131024        self.write_c(']') 
    9141025 
     
    9311042 
    9321043    def visit_Yield(self, node): 
     1044        self.unsupported(node) 
    9331045        self.write_python('yield ') 
    9341046        self.visit(node.value) 
    9351047 
    9361048    def visit_Lambda(self, node): 
     1049        self.unsupported(node) 
    9371050        self.write_python('lambda ') 
    9381051        self.visit(node.args) 
     
    9411054 
    9421055    def visit_Ellipsis(self, node): 
     1056        self.unsupported(node) 
    9431057        self.write_python('Ellipsis') 
    9441058 
     
    9601074 
    9611075    def visit_DictComp(self, node): 
     1076        self.unsupported(node) 
    9621077        self.write_python('{') 
    9631078        self.visit(node.key) 
     
    9681083        self.write_python('}') 
    9691084 
     1085    def visit_NameConstant (self, node): 
     1086        if (hasattr (node, "value")): 
     1087            if (node.value == True): 
     1088                val = "1" 
     1089            elif node.value == False: 
     1090                val = "0" 
     1091            else: 
     1092                val = "" 
     1093            if (len(val) > 0): 
     1094                self.write_c("(" + val + ")") 
     1095 
    9701096    def visit_IfExp(self, node): 
     1097        self.write_c('(') 
     1098        self.visit(node.test) 
     1099        self.write_c(' ? ') 
    9711100        self.visit(node.body) 
    972         self.write_c(' if ') 
    973         self.visit(node.test) 
    974         self.write_c(' else ') 
     1101        self.write_c(' : ') 
    9751102        self.visit(node.orelse) 
     1103        self.write_c(');') 
    9761104 
    9771105    def visit_Starred(self, node): 
     
    9881116 
    9891117    def visit_alias(self, node): 
     1118        self.unsupported(node) 
    9901119        self.write_python(node.name) 
    9911120        if node.asname is not None: 
     
    10051134    def visit_arguments(self, node): 
    10061135        self.signature(node) 
     1136 
     1137    def unsupported(self, node, message=None): 
     1138        if hasattr(node, "value"): 
     1139            lineno = node.value.lineno 
     1140        elif hasattr(node, "iter"): 
     1141            lineno = node.iter.lineno 
     1142        else: 
     1143            #print(dir(node)) 
     1144            lineno = 0 
     1145 
     1146        lineno += self.lineno_offset 
     1147        if self.fname: 
     1148            location = "%s(%d)" % (self.fname, lineno) 
     1149        else: 
     1150            location = "%d" % (self.fname, lineno) 
     1151        if self.current_function: 
     1152            location += ", function %s" % self.current_function 
     1153        if message is None: 
     1154            message = node.__class__.__name__ + " syntax not supported" 
     1155        raise SyntaxError("[%s] %s" % (location, message)) 
    10071156 
    10081157def print_function(f=None): 
     
    10181167        print(tree_source) 
    10191168 
    1020 def translate(functions, constants=0): 
     1169def define_constant(name, value, block_size=1): 
     1170    # type: (str, any, int) -> str 
     1171    """ 
     1172    Convert a python constant into a C constant of the same name. 
     1173 
     1174    Returns the C declaration of the constant as a string, possibly containing 
     1175    line feeds.  The string will not be indented. 
     1176 
     1177    Supports int, double and sequences of double. 
     1178    """ 
     1179    const = "constant "  # OpenCL needs globals to be constant 
     1180    if isinstance(value, int): 
     1181        parts = [const + "int ", name, " = ", "%d"%value, ";"] 
     1182    elif isinstance(value, float): 
     1183        parts = [const + "double ", name, " = ", "%.15g"%value, ";"] 
     1184    else: 
     1185        try: 
     1186            len(value) 
     1187        except TypeError: 
     1188            raise TypeError("constant %s must be int, float or [float, ...]"%name) 
     1189        # extend constant arrays to a multiple of 4; not sure if this 
     1190        # is necessary, but some OpenCL targets broke if the number 
     1191        # of parameters in the parameter table was not a multiple of 4, 
     1192        # so do it for all constant arrays to be safe. 
     1193        if len(value)%block_size != 0: 
     1194            value = list(value) + [0.]*(block_size - len(value)%block_size) 
     1195        elements = ["%.15g"%v for v in value] 
     1196        parts = [const + "double ", name, "[]", " = ", 
     1197                 "{\n   ", ", ".join(elements), "\n};"] 
     1198 
     1199    return "".join(parts) 
     1200 
     1201 
     1202# Modified from the following: 
     1203# 
     1204#    http://code.activestate.com/recipes/578272-topological-sort/ 
     1205#    Copyright (C) 2012 Sam Denton 
     1206#    License: MIT 
     1207def ordered_dag(dag): 
     1208    # type: (Dict[T, Set[T]]) -> Iterator[T] 
     1209    """ 
     1210    Given a dag defined by a dictionary of {k1: [k2, ...]} yield keys 
     1211    in order such that every key occurs after the keys it depends upon. 
     1212 
     1213    This is an iterator not a sequence.  To reverse it use:: 
     1214 
     1215        reversed(tuple(ordered_dag(dag))) 
     1216 
     1217    Raise an error if there are any cycles. 
     1218 
     1219    Keys are arbitrary hashable values. 
     1220    """ 
     1221    # Local import to make the function stand-alone, and easier to borrow 
     1222    from functools import reduce 
     1223 
     1224    dag = dag.copy() 
     1225 
     1226    # make leaves depend on the empty set 
     1227    leaves = reduce(set.union, dag.values()) - set(dag.keys()) 
     1228    dag.update({node: set() for node in leaves}) 
     1229    while True: 
     1230        leaves = set(node for node, links in dag.items() if not links) 
     1231        if not leaves: 
     1232            break 
     1233        for node in leaves: 
     1234            yield node 
     1235        dag = {node: (links-leaves) 
     1236               for node, links in dag.items() if node not in leaves} 
     1237    if dag: 
     1238        raise ValueError("Cyclic dependes exists amongst these items:\n%s" 
     1239                         % ", ".join(str(node) for node in dag.keys())) 
     1240 
     1241def translate(functions, constants=None): 
     1242    # type: (List[(str, str, int)], Dict[str, any]) -> List[str] 
     1243    """ 
     1244    Convert a set of functions 
     1245    """ 
    10211246    snippets = [] 
    1022     #snippets.append("#include <math.h>") 
    1023     #snippets.append("") 
    1024     for source, fname, line_no in functions: 
    1025         line_directive = '#line %d "%s"'%(line_no, fname.replace('\\', '\\\\')) 
     1247    snippets.append("#include <math.h>") 
     1248    snippets.append("") 
     1249    warnings = [] 
     1250    for source, fname, lineno in functions: 
     1251        line_directive = '#line %d "%s"'%(lineno, fname.replace('\\', '\\\\')) 
    10261252        snippets.append(line_directive) 
    10271253        tree = ast.parse(source) 
    1028         # in the future add filename, offset, constants 
    1029         c_code = to_source(tree, functions, constants) 
     1254        c_code,w = to_source(tree, constants=constants, fname=fname, lineno=lineno) 
     1255        if w: 
     1256            warnings.append ("\n".join(w)) 
    10301257        snippets.append(c_code) 
    1031     return snippets 
     1258    return "\n".join(snippets),warnings 
     1259#    return snippets 
     1260 
     1261def print_usage (): 
     1262        print("""\ 
     1263            Usage: python py2c.py <infile> [<outfile>] 
     1264            if outfile is omitted, output file is '<infile>.c' 
     1265        """) 
     1266 
     1267def get_files_names (): 
     1268    import os 
     1269    fname_in = fname_out = "" 
     1270    valid_params =  len(sys.argv) > 1 
     1271    if (valid_params == False): 
     1272        print_usage() 
     1273    else: 
     1274        fname_in = sys.argv[1] 
     1275        if len(sys.argv) == 2: 
     1276            fname_base = os.path.splitext(fname_in)[0] 
     1277            fname_out = str(fname_base) + '.c' 
     1278        else: 
     1279            fname_out = sys.argv[2] 
     1280    return valid_params, fname_in,fname_out 
    10321281 
    10331282def main(): 
    1034     import os 
    10351283    print("Parsing...using Python" + sys.version) 
    1036     if len(sys.argv) == 1: 
    1037         print("""\ 
    1038 Usage: python py2c.py <infile> [<outfile>] 
    1039  
    1040 if outfile is omitted, output file is '<infile>.c' 
    1041 """) 
     1284    valid_params, fname_in, fname_out = get_files_names () 
     1285    if (valid_params == False): 
     1286        print("Input parameters error.\nExiting") 
    10421287        return 
    10431288 
    1044     fname_in = sys.argv[1] 
    1045     if len(sys.argv) == 2: 
    1046         fname_base = os.path.splitext(fname_in)[0] 
    1047         fname_out = str(fname_base) + '.c' 
    1048     else: 
    1049         fname_out = sys.argv[2] 
    1050  
    10511289    with open(fname_in, "r") as python_file: 
    1052         code = python_file.read() 
    1053  
    1054     translation = translate([code, fname_in, 1])[0] 
     1290            code = python_file.read() 
     1291    name = "gauss" 
     1292    code = (code 
     1293            .replace(name+'.n', 'GAUSS_N') 
     1294            .replace(name+'.z', 'GAUSS_Z') 
     1295            .replace(name+'.w', 'GAUSS_W')) 
     1296 
     1297    translation,warnings = translate([(code, fname_in, 1)]) 
    10551298 
    10561299    with open(fname_out, "w") as file_out: 
    1057         file_out.write(translation) 
     1300        file_out.write(str(translation)) 
     1301    if warnings: 
     1302        print("".join(str(warnings[0]))) 
    10581303    print("...Done") 
    10591304 
    10601305if __name__ == "__main__": 
    1061     main() 
     1306    try: 
     1307        main() 
     1308    except Exception as excp: 
     1309        print ("Error:\n" + str(excp.args)) 
Note: See TracChangeset for help on using the changeset viewer.