Changeset 4339764 in sasmodels
- Timestamp:
- Jan 5, 2018 1:54:32 PM (7 years ago)
- Children:
- 0bd0877
- Parents:
- 2694cb8
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sasmodels/py2c.py
r7b1dcf9 r4339764 1 2 1 """ 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 12 9 Variables definition in C 13 10 ------------------------- 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: 16 13 * By default, a variable is a 'double'. 17 14 * Variable in a for loop is an int. … … 19 16 variable within the brackets is integer. For example, in the 20 17 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 in22 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:: 24 21 def func(arg1, arg2): 25 22 arg2 = 17. 26 is translated to the following C code 23 is translated to the following C code:: 27 24 double func(double arg1) 28 25 { 29 26 arg2[0] = 17.0; 30 27 } 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 32 31 def func(arg1, arg2): double func(double arg1) { 33 32 arg2 = 17. arg2[0] = 17.0; 34 33 } 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 37 Based on codegen.py: 38 39 :copyright: Copyright 2008 by Armin Ronacher. 40 :license: BSD. 41 """ 42 """ 38 43 Update Notes 39 44 ============ 40 11/22 14:15, O.E. Each 'visit_*' method is to build a C statement string. It45 11/22/2017, O.E. Each 'visit_*' method is to build a C statement string. It 41 46 shold insert 4 blanks per indentation level. 42 47 The 'body' method will combine all the strings, by adding … … 52 57 12/07/2017, OE: Translation of integer division, '\\' in python, implemented 53 58 in translate_integer_divide, called from visit_BinOp 54 12/07/2017, OE: C variable definition handled in 'define_ C_Vars'59 12/07/2017, OE: C variable definition handled in 'define_c_vars' 55 60 : Python integer division, '//', translated to C in 56 61 'translate_integer_divide' … … 59 64 12/18/2017, OE: Added call to 'add_current_line()' at the beginning 60 65 of visit_Return 66 01/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. 70 01/4/2018, O.E. 'translate(functions, constants=None)' returns string, instaed of a list 71 01/04/2017 O.E. Fixed bug in 'visit_If': visiting node.orelse in case else exists. 72 01/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 61 76 62 77 """ … … 102 117 103 118 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. 119 def to_source(tree, constants=None, fname=None, lineno=0): 121 120 """ 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) 126 128 127 129 def isevaluable(s): … … 129 131 eval(s) 130 132 return True 131 except :133 except Exception: 132 134 return False 135 136 class 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) 133 172 134 173 class SourceGenerator(NodeVisitor): … … 138 177 """ 139 178 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): 141 181 self.result = [] 142 182 self.indent_with = indent_with … … 144 184 self.indentation = 0 145 185 self.new_lines = 0 186 187 # for C 146 188 self.c_proc = [] 147 # for C148 189 self.signature_line = 0 149 190 self.arguments = [] 150 self.name = "" 191 self.current_function = "" 192 self.fname = fname 193 self.lineno_offset = lineno 151 194 self.warnings = [] 152 self. Statements = []195 self.statements = [] 153 196 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 = [] 166 208 self.required_functions = [] 167 209 self.is_sequence = False 168 210 self.visited_args = False 211 self.inside_if = False 212 self.C_Vectors = [] 213 self.assign_target = "" 214 self.assign_c_vector = [] 169 215 170 216 def write_python(self, x): … … 176 222 self.result.append(x) 177 223 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"))) 188 231 189 232 def add_current_line(self): … … 192 235 self.current_statement = '' 193 236 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): 199 242 angle = str(node.args[0].id) 200 243 self.write_c(node.args[1].id + " = sin(" + angle + ");") … … 203 246 self.add_current_line() 204 247 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 206 274 207 275 def newline(self, node=None, extra=0): … … 211 279 self.new_lines = 1 212 280 if self.current_statement: 213 self. Statements.append(self.current_statement)281 self.statements.append(self.current_statement) 214 282 self.current_statement = '' 215 283 … … 258 326 except AttributeError: 259 327 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))) 262 330 self.warnings.append(w_str) 263 331 … … 278 346 self.visit(node.msg) 279 347 280 def define_ C_Vars(self, target):348 def define_c_vars(self, target): 281 349 if hasattr(target, 'id'): 282 350 # a variable is considered an array if it apears in the agrument list … … 287 355 # return 288 356 # 289 if target.id not in self. C_Vars:357 if target.id not in self.c_vars: 290 358 if target.id in self.arguments: 291 359 idx = self.arguments.index(target.id) 292 360 new_target = self.arguments[idx] + "[0]" 293 if new_target not in self. C_Pointers:361 if new_target not in self.c_pointers: 294 362 target.id = new_target 295 self. C_Pointers.append(self.arguments[idx])363 self.c_pointers.append(self.arguments[idx]) 296 364 else: 297 self. C_Vars.append(target.id)365 self.c_vars.append(target.id) 298 366 299 367 def add_semi_colon(self): … … 308 376 if idx: 309 377 self.write_c(' = ') 310 self.define_ C_Vars(target)378 self.define_c_vars(target) 311 379 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[:] 315 385 self.write_c(' = ') 316 386 self.is_sequence = False 317 387 self.visited_args = False 318 388 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: 325 395 self.add_semi_colon() 326 396 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) 335 413 self.current_statement = '' 414 self.assign_target = '' 336 415 337 416 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: 339 418 if node.target.id not in self.arguments: 340 self. C_Vars.append(node.target.id)419 self.c_vars.append(node.target.id) 341 420 self.visit(node.target) 342 421 self.write_c(' ' + BINOP_SYMBOLS[type(node.op)] + '= ') … … 346 425 347 426 def visit_ImportFrom(self, node): 427 return # import ignored 348 428 self.newline(node) 349 429 self.write_python('from %s%s import ' %('.' * node.level, node.module)) … … 354 434 355 435 def visit_Import(self, node): 436 return # import ignored 356 437 self.newline(node) 357 438 for item in node.names: … … 363 444 self.generic_visit(node) 364 445 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: 370 448 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: 374 450 if c_ptr not in self.arguments: 375 451 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) 378 454 if var_list: 379 455 c_dcl = " double " + ", ".join(var_list) + ";\n" … … 382 458 return start_var 383 459 384 def insert_ C_Vars(self, start_var):385 fLine= False386 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= True460 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 394 470 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) 400 481 start_var += 1 401 482 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") 408 494 start_var += 1 409 495 410 del self. C_Vars[:]411 del self. C_IntVars[:]412 del self. C_Vectors[:]413 del self. C_Pointers[:]414 self.C_DclPointers415 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: 416 502 self.c_proc.insert(start_var, "\n") 417 503 418 def InsertSignature(self):504 def insert_signature(self): 419 505 arg_decls = [] 420 506 for arg in self.arguments: 421 507 decl = "double " + arg 422 if arg in self. C_Pointers:508 if arg in self.c_pointers: 423 509 decl += "[]" 424 510 arg_decls.append(decl) 425 511 args_str = ", ".join(arg_decls) 426 self.strMethodSignature = 'double ' + self.name+ '(' + args_str + ")"512 method_sig = 'double ' + self.current_function + '(' + args_str + ")" 427 513 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) 429 515 430 516 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) 431 522 self.newline(extra=1) 432 523 self.decorators(node) 433 524 self.newline(node) 434 525 self.arguments = [] 435 self.name = node.name436 #if self.name not in self.required_functions[0]:437 # return438 #print("Parsing '" + self.name + "'")439 440 526 self.visit(node.args) 441 527 # for C 442 528 self.signature_line = len(self.c_proc) 443 #self.add_c_line(self.strMethodSignature)444 529 self.add_c_line("\n{") 445 530 start_vars = len(self.c_proc) + 1 446 531 self.body(node.body) 447 532 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 451 543 452 544 def visit_ClassDef(self, node): … … 484 576 485 577 def visit_If(self, node): 578 self.add_current_line() 579 self.inside_if = True 486 580 self.write_c('if ') 487 581 self.visit(node.test) … … 507 601 self.newline() 508 602 self.write_c('else {') 509 self.body(node. body)603 self.body(node.orelse) 510 604 self.add_c_line('}') 511 605 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): 531 609 stop = "" 532 610 start = '0' … … 553 631 return start, stop, step 554 632 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 555 637 def visit_For(self, node): 556 638 # node: for iterator is stored in node.target. … … 565 647 iterator = self.current_statement 566 648 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) 570 651 self.write_c("for(" + iterator + "=" + str(start) + 571 652 " ; " + iterator + " < " + str(stop) + … … 575 656 fForDone = True 576 657 if not fForDone: 577 line_number = self.getNodeLineNo(node)658 # Generate the statement that is causing the error 578 659 self.current_statement = '' 579 660 self.write_c('for ') … … 582 663 self.visit(node.iter) 583 664 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) 587 667 588 668 def visit_While(self, node): … … 590 670 self.write_c('while ') 591 671 self.visit(node.test) 592 self.write_c(' :')672 self.write_c(' { ') 593 673 self.body_or_else(node) 674 self.write_c('}') 675 self.add_current_line() 594 676 595 677 def visit_With(self, node): 678 self.unsupported(node) 596 679 self.newline(node) 597 680 self.write_python('with ') … … 605 688 def visit_Pass(self, node): 606 689 self.newline(node) 607 self.write_python('pass')690 #self.write_python('pass') 608 691 609 692 def visit_Print(self, node): 693 # TODO: print support would be nice, though hard to do 694 self.unsupported(node) 610 695 # CRUFT: python 2.6 only 611 696 self.newline(node) … … 625 710 626 711 def visit_Delete(self, node): 712 self.unsupported(node) 627 713 self.newline(node) 628 714 self.write_python('del ') … … 633 719 634 720 def visit_TryExcept(self, node): 721 self.unsupported(node) 635 722 self.newline(node) 636 723 self.write_python('try:') … … 640 727 641 728 def visit_TryFinally(self, node): 729 self.unsupported(node) 642 730 self.newline(node) 643 731 self.write_python('try:') … … 648 736 649 737 def visit_Global(self, node): 738 self.unsupported(node) 650 739 self.newline(node) 651 740 self.write_python('global ' + ', '.join(node.names)) … … 676 765 677 766 def visit_Raise(self, node): 767 self.unsupported(node) 678 768 # CRUFT: Python 2.6 / 3.0 compatibility 679 769 self.newline(node) … … 697 787 698 788 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") 702 790 self.visit(node.value) 703 791 self.write_python('.' + node.attr) … … 711 799 want_comma.append(True) 712 800 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) 715 803 if node.func.id == 'abs': 716 804 self.write_c("fabs ") … … 718 806 self.write_c('(int) ') 719 807 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) 721 812 return 722 813 else: … … 724 815 else: 725 816 self.visit(node.func) 726 #self.C_Functions727 817 self.write_c('(') 728 818 for arg in node.args: … … 744 834 self.write_c('**') 745 835 self.visit(node.kwargs) 746 self.write_c(');') 836 self.write_c(')') 837 if (self.inside_if == False): 838 self.write_c(';') 747 839 748 840 def visit_Name(self, node): 749 841 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: 751 843 self.write_c("[0]") 752 844 name = "" … … 756 848 else: 757 849 name = node.id 758 # add variable to C_Vars if it ins't there yet, not an argument and not a number759 if (name not in self. C_Functions and name not in self.C_Vars and760 name not in self. C_IntVars and name not in self.arguments and761 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) 764 856 else: 765 self. C_Vars.append(node.id)857 self.c_vars.append(node.id) 766 858 767 859 def visit_Str(self, node): … … 777 869 for idx, item in enumerate(node.elts): 778 870 if idx: 779 self. Tuples.append(item)871 self.tuples.append(item) 780 872 else: 781 873 self.visit(item) … … 784 876 def visit(self, node): 785 877 self.is_sequence = True 878 c_vec = C_Vector() 786 879 s = "" 787 880 for idx, item in enumerate(node.elts): … … 789 882 s += ', ' 790 883 if hasattr(item, 'id'): 791 s += item.id 884 c_vec.values.append(item.id) 885 # s += item.id 792 886 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) 798 908 return visit 799 909 … … 803 913 804 914 def visit_Dict(self, node): 915 self.unsupported(node) 805 916 self.write_python('{') 806 917 for idx, (key, value) in enumerate(zip(node.keys, node.values)): … … 901 1012 902 1013 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 = True1014 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 907 1018 self.visit(node.value) 908 self. SubRef = False1019 self.in_subref = False 909 1020 self.write_c('[') 910 self. InSubscript = True1021 self.in_subscript = True 911 1022 self.visit(node.slice) 912 self. InSubscript = False1023 self.in_subscript = False 913 1024 self.write_c(']') 914 1025 … … 931 1042 932 1043 def visit_Yield(self, node): 1044 self.unsupported(node) 933 1045 self.write_python('yield ') 934 1046 self.visit(node.value) 935 1047 936 1048 def visit_Lambda(self, node): 1049 self.unsupported(node) 937 1050 self.write_python('lambda ') 938 1051 self.visit(node.args) … … 941 1054 942 1055 def visit_Ellipsis(self, node): 1056 self.unsupported(node) 943 1057 self.write_python('Ellipsis') 944 1058 … … 960 1074 961 1075 def visit_DictComp(self, node): 1076 self.unsupported(node) 962 1077 self.write_python('{') 963 1078 self.visit(node.key) … … 968 1083 self.write_python('}') 969 1084 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 970 1096 def visit_IfExp(self, node): 1097 self.write_c('(') 1098 self.visit(node.test) 1099 self.write_c(' ? ') 971 1100 self.visit(node.body) 972 self.write_c(' if ') 973 self.visit(node.test) 974 self.write_c(' else ') 1101 self.write_c(' : ') 975 1102 self.visit(node.orelse) 1103 self.write_c(');') 976 1104 977 1105 def visit_Starred(self, node): … … 988 1116 989 1117 def visit_alias(self, node): 1118 self.unsupported(node) 990 1119 self.write_python(node.name) 991 1120 if node.asname is not None: … … 1005 1134 def visit_arguments(self, node): 1006 1135 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)) 1007 1156 1008 1157 def print_function(f=None): … … 1018 1167 print(tree_source) 1019 1168 1020 def translate(functions, constants=0): 1169 def 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 1207 def 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 1241 def translate(functions, constants=None): 1242 # type: (List[(str, str, int)], Dict[str, any]) -> List[str] 1243 """ 1244 Convert a set of functions 1245 """ 1021 1246 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('\\', '\\\\')) 1026 1252 snippets.append(line_directive) 1027 1253 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)) 1030 1257 snippets.append(c_code) 1031 return snippets 1258 return "\n".join(snippets),warnings 1259 # return snippets 1260 1261 def print_usage (): 1262 print("""\ 1263 Usage: python py2c.py <infile> [<outfile>] 1264 if outfile is omitted, output file is '<infile>.c' 1265 """) 1266 1267 def 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 1032 1281 1033 1282 def main(): 1034 import os1035 1283 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") 1042 1287 return 1043 1288 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 1051 1289 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)]) 1055 1298 1056 1299 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]))) 1058 1303 print("...Done") 1059 1304 1060 1305 if __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.