1 #!/usr/bin/env python 2 3 """ 4 Generate C code from object layouts and other deduced information. 5 6 Copyright (C) 2015, 2016 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 """ 21 22 from common import CommonOutput 23 from encoders import encode_bound_reference, encode_function_pointer, \ 24 encode_instantiator_pointer, \ 25 encode_literal_constant, encode_literal_constant_member, \ 26 encode_literal_constant_value, \ 27 encode_literal_instantiator, encode_literal_reference, \ 28 encode_path, \ 29 encode_predefined_reference, encode_size, \ 30 encode_symbol, encode_tablename, \ 31 encode_type_attribute 32 from os import listdir 33 from os.path import isdir, join, split 34 from referencing import Reference 35 36 def copy(source, target): 37 38 "Copy a text file from 'source' to 'target'." 39 40 if isdir(target): 41 target = join(target, split(source)[-1]) 42 infile = open(source) 43 outfile = open(target, "w") 44 try: 45 outfile.write(infile.read()) 46 finally: 47 outfile.close() 48 infile.close() 49 50 class Generator(CommonOutput): 51 52 "A code generator." 53 54 function_type = "__builtins__.core.function" 55 56 # NOTE: These must be synchronised with the library. 57 58 predefined_constant_members = ( 59 ("__builtins__.boolean", "False"), 60 ("__builtins__.boolean", "True"), 61 ("__builtins__.none", "None"), 62 ("__builtins__.notimplemented", "NotImplemented"), 63 ) 64 65 literal_instantiator_types = ( 66 "__builtins__.dict.dict", 67 "__builtins__.list.list", 68 "__builtins__.tuple.tuple", 69 ) 70 71 def __init__(self, importer, optimiser, output): 72 self.importer = importer 73 self.optimiser = optimiser 74 self.output = output 75 76 def to_output(self): 77 78 "Write the generated code." 79 80 self.check_output() 81 self.write_structures() 82 self.copy_templates() 83 84 def copy_templates(self): 85 86 "Copy template files to the generated output directory." 87 88 templates = join(split(__file__)[0], "templates") 89 90 for filename in listdir(templates): 91 copy(join(templates, filename), self.output) 92 93 def write_structures(self): 94 95 "Write structures used by the program." 96 97 f_consts = open(join(self.output, "progconsts.h"), "w") 98 f_defs = open(join(self.output, "progtypes.c"), "w") 99 f_decls = open(join(self.output, "progtypes.h"), "w") 100 f_signatures = open(join(self.output, "main.h"), "w") 101 f_code = open(join(self.output, "main.c"), "w") 102 103 try: 104 # Output boilerplate. 105 106 print >>f_consts, """\ 107 #ifndef __PROGCONSTS_H__ 108 #define __PROGCONSTS_H__ 109 """ 110 print >>f_decls, """\ 111 #ifndef __PROGTYPES_H__ 112 #define __PROGTYPES_H__ 113 114 #include "progconsts.h" 115 #include "types.h" 116 """ 117 print >>f_defs, """\ 118 #include "progtypes.h" 119 #include "progops.h" 120 #include "main.h" 121 """ 122 print >>f_signatures, """\ 123 #ifndef __MAIN_H__ 124 #define __MAIN_H__ 125 126 #include "types.h" 127 """ 128 print >>f_code, """\ 129 #include <string.h> 130 #include <stdio.h> 131 #include "types.h" 132 #include "exceptions.h" 133 #include "ops.h" 134 #include "progconsts.h" 135 #include "progtypes.h" 136 #include "progops.h" 137 #include "main.h" 138 """ 139 140 # Generate structure size data. 141 142 size_tables = {} 143 144 for kind in ["<class>", "<module>", "<instance>"]: 145 size_tables[kind] = {} 146 147 for ref, structure in self.optimiser.structures.items(): 148 size_tables[ref.get_kind()][ref.get_origin()] = len(structure) 149 150 size_tables = size_tables.items() 151 size_tables.sort() 152 153 for kind, sizes in size_tables: 154 self.write_size_constants(f_consts, kind, sizes, 0) 155 156 # Generate parameter table size data. 157 158 min_sizes = {} 159 max_sizes = {} 160 161 for path, parameters in self.optimiser.parameters.items(): 162 argmin, argmax = self.get_argument_limits(path) 163 min_sizes[path] = argmin 164 max_sizes[path] = argmax 165 166 # Record instantiator limits. 167 168 if path.endswith(".__init__"): 169 path = path[:-len(".__init__")] 170 171 self.write_size_constants(f_consts, "pmin", min_sizes, 0) 172 self.write_size_constants(f_consts, "pmax", max_sizes, 0) 173 174 # Generate parameter codes. 175 176 self.write_code_constants(f_consts, self.optimiser.all_paramnames, self.optimiser.arg_locations, "pcode", "ppos") 177 178 # Generate attribute codes. 179 180 self.write_code_constants(f_consts, self.optimiser.all_attrnames, self.optimiser.locations, "code", "pos") 181 182 # Generate table and structure data. 183 184 function_instance_attrs = None 185 objects = self.optimiser.attr_table.items() 186 objects.sort() 187 188 for ref, indexes in objects: 189 attrnames = self.get_attribute_names(indexes) 190 191 kind = ref.get_kind() 192 path = ref.get_origin() 193 table_name = encode_tablename(kind, path) 194 structure_size = encode_size(kind, path) 195 196 # Generate structures for classes and modules. 197 198 if kind != "<instance>": 199 structure = [] 200 attrs = self.get_static_attributes(kind, path, attrnames) 201 202 # Set a special instantiator on the class. 203 204 if kind == "<class>": 205 attrs["__fn__"] = path 206 attrs["__args__"] = encode_size("pmin", path) 207 208 # Write instantiator declarations based on the 209 # applicable initialiser. 210 211 init_ref = attrs["__init__"] 212 213 # Write instantiator definitions. 214 215 self.write_instantiator(f_code, f_signatures, path, init_ref) 216 217 # Write parameter table. 218 219 self.make_parameter_table(f_decls, f_defs, path, init_ref.get_origin()) 220 221 self.populate_structure(Reference(kind, path), attrs, kind, structure) 222 223 if kind == "<class>": 224 self.write_instance_structure(f_decls, path, structure_size) 225 226 self.write_structure(f_decls, f_defs, path, table_name, structure_size, structure, 227 kind == "<class>" and path) 228 229 # Record function instance details for function generation below. 230 231 else: 232 attrs = self.get_instance_attributes(path, attrnames) 233 if path == self.function_type: 234 function_instance_attrs = attrs 235 236 # Write a table for all objects. 237 238 table = [] 239 self.populate_table(Reference(kind, path), table) 240 self.write_table(f_decls, f_defs, table_name, structure_size, table) 241 242 # Generate function instances. 243 244 functions = set() 245 246 for ref in self.importer.objects.values(): 247 if ref.has_kind("<function>"): 248 functions.add(ref.get_origin()) 249 250 functions = list(functions) 251 functions.sort() 252 253 for path in functions: 254 cls = self.function_type 255 table_name = encode_tablename("<instance>", cls) 256 structure_size = encode_size("<instance>", cls) 257 258 # Set a special callable attribute on the instance. 259 260 function_instance_attrs["__fn__"] = path 261 function_instance_attrs["__args__"] = encode_size("pmin", path) 262 263 # Produce two structures where a method is involved. 264 265 ref = self.importer.get_object(path) 266 parent_ref = self.importer.get_object(ref.parent()) 267 parent_kind = parent_ref and parent_ref.get_kind() 268 269 # Populate and write each structure. 270 271 if parent_kind == "<class>": 272 273 # A bound version of a method. 274 275 structure = self.populate_function(path, function_instance_attrs, False) 276 self.write_structure(f_decls, f_defs, encode_bound_reference(path), table_name, structure_size, structure) 277 278 # An unbound version of a method. 279 280 structure = self.populate_function(path, function_instance_attrs, True) 281 self.write_structure(f_decls, f_defs, path, table_name, structure_size, structure) 282 283 else: 284 # A normal function. 285 286 structure = self.populate_function(path, function_instance_attrs, False) 287 self.write_structure(f_decls, f_defs, path, table_name, structure_size, structure) 288 289 # Functions with defaults need to declare instance structures. 290 291 if self.importer.function_defaults.get(path): 292 self.write_instance_structure(f_decls, path, structure_size) 293 294 # Write function declarations. 295 # Signature: __attr <name>(__attr[]); 296 297 print >>f_signatures, "__attr %s(__attr args[]);" % encode_function_pointer(path) 298 299 # Write parameter table. 300 301 self.make_parameter_table(f_decls, f_defs, path, path) 302 303 # Generate predefined constants. 304 305 for path, name in self.predefined_constant_members: 306 self.make_predefined_constant(f_decls, f_defs, path, name) 307 308 # Generate literal constants. 309 310 for value, n in self.optimiser.constants.items(): 311 self.make_literal_constant(f_decls, f_defs, n, value) 312 313 # Finish the main source file. 314 315 self.write_main_program(f_code, f_signatures) 316 317 # Output more boilerplate. 318 319 print >>f_consts, """\ 320 321 #endif /* __PROGCONSTS_H__ */""" 322 323 print >>f_decls, """\ 324 325 #define __FUNCTION_TYPE %s 326 #define __FUNCTION_INSTANCE_SIZE %s 327 328 #endif /* __PROGTYPES_H__ */""" % ( 329 encode_path(self.function_type), 330 encode_size("<instance>", self.function_type) 331 ) 332 333 print >>f_signatures, """\ 334 335 #endif /* __MAIN_H__ */""" 336 337 finally: 338 f_consts.close() 339 f_defs.close() 340 f_decls.close() 341 f_signatures.close() 342 f_code.close() 343 344 def make_literal_constant(self, f_decls, f_defs, n, value): 345 346 """ 347 Write literal constant details to 'f_decls' (to declare a structure) and 348 to 'f_defs' (to define the contents) for the constant with the number 349 'n' with the given literal 'value'. 350 """ 351 352 const_path = encode_literal_constant(n) 353 structure_name = encode_literal_reference(n) 354 355 # NOTE: This makes assumptions about the __builtins__ structure. 356 357 typename = value.__class__.__name__ 358 ref = Reference("<instance>", "__builtins__.%s.%s" % (typename, typename)) 359 360 self.make_constant(f_decls, f_defs, ref, const_path, structure_name, value) 361 362 def make_predefined_constant(self, f_decls, f_defs, path, name): 363 364 """ 365 Write predefined constant details to 'f_decls' (to declare a structure) 366 and to 'f_defs' (to define the contents) for the constant located in 367 'path' with the given 'name'. 368 """ 369 370 # Determine the details of the constant. 371 372 attr_path = "%s.%s" % (path, name) 373 structure_name = encode_predefined_reference(attr_path) 374 ref = self.importer.get_object(attr_path) 375 376 self.make_constant(f_decls, f_defs, ref, attr_path, structure_name) 377 378 def make_constant(self, f_decls, f_defs, ref, const_path, structure_name, data=None): 379 380 """ 381 Write constant details to 'f_decls' (to declare a structure) and to 382 'f_defs' (to define the contents) for the constant described by 'ref' 383 having the given 'path' and 'structure_name' (for the constant structure 384 itself). 385 """ 386 387 # Obtain the attributes. 388 389 cls = ref.get_origin() 390 indexes = self.optimiser.attr_table[ref] 391 attrnames = self.get_attribute_names(indexes) 392 attrs = self.get_instance_attributes(cls, attrnames) 393 394 # Set the data, if provided. 395 396 if data is not None: 397 attrs["__data__"] = data 398 399 # Define the structure details. An object is created for the constant, 400 # but an attribute is provided, referring to the object, for access to 401 # the constant in the program. 402 403 structure = [] 404 table_name = encode_tablename("<instance>", cls) 405 structure_size = encode_size("<instance>", cls) 406 self.populate_structure(ref, attrs, ref.get_kind(), structure) 407 self.write_structure(f_decls, f_defs, structure_name, table_name, structure_size, structure) 408 409 # Define a macro for the constant. 410 411 attr_name = encode_path(const_path) 412 print >>f_decls, "#define %s ((__attr) {&%s, &%s})" % (attr_name, structure_name, structure_name) 413 414 def make_parameter_table(self, f_decls, f_defs, path, function_path): 415 416 """ 417 Write parameter table details to 'f_decls' (to declare a table) and to 418 'f_defs' (to define the contents) for the function with the given 419 'path', using 'function_path' to obtain the parameter details. The 420 latter two arguments may differ when describing an instantiator using 421 the details of an initialiser. 422 """ 423 424 table = [] 425 table_name = encode_tablename("<function>", path) 426 structure_size = encode_size("pmax", path) 427 self.populate_parameter_table(function_path, table) 428 self.write_parameter_table(f_decls, f_defs, table_name, structure_size, table) 429 430 def write_size_constants(self, f_consts, size_prefix, sizes, padding): 431 432 """ 433 Write size constants to 'f_consts' for the given 'size_prefix', using 434 the 'sizes' dictionary to populate the definition, adding the given 435 'padding' to the basic sizes. 436 """ 437 438 print >>f_consts, "enum %s {" % encode_size(size_prefix) 439 first = True 440 for path, size in sizes.items(): 441 if not first: 442 print >>f_consts, "," 443 else: 444 first = False 445 f_consts.write(" %s = %d" % (encode_size(size_prefix, path), size + padding)) 446 print >>f_consts, "\n };" 447 448 def write_code_constants(self, f_consts, attrnames, locations, code_prefix, pos_prefix): 449 450 """ 451 Write code constants to 'f_consts' for the given 'attrnames' and 452 attribute 'locations'. 453 """ 454 455 print >>f_consts, "enum %s {" % encode_symbol(code_prefix) 456 first = True 457 for i, attrname in enumerate(attrnames): 458 if not first: 459 print >>f_consts, "," 460 else: 461 first = False 462 f_consts.write(" %s = %d" % (encode_symbol(code_prefix, attrname), i)) 463 print >>f_consts, "\n };" 464 465 print >>f_consts, "enum %s {" % encode_symbol(pos_prefix) 466 first = True 467 for i, attrnames in enumerate(locations): 468 for attrname in attrnames: 469 if not first: 470 print >>f_consts, "," 471 else: 472 first = False 473 f_consts.write(" %s = %d" % (encode_symbol(pos_prefix, attrname), i)) 474 print >>f_consts, "\n };" 475 476 def write_table(self, f_decls, f_defs, table_name, structure_size, table): 477 478 """ 479 Write the declarations to 'f_decls' and definitions to 'f_defs' for 480 the object having the given 'table_name' and the given 'structure_size', 481 with 'table' details used to populate the definition. 482 """ 483 484 print >>f_decls, "extern const __table %s;\n" % table_name 485 486 # Write the corresponding definition. 487 488 print >>f_defs, "const __table %s = {\n %s,\n {\n %s\n }\n };\n" % ( 489 table_name, structure_size, 490 ",\n ".join(table)) 491 492 def write_parameter_table(self, f_decls, f_defs, table_name, structure_size, table): 493 494 """ 495 Write the declarations to 'f_decls' and definitions to 'f_defs' for 496 the object having the given 'table_name' and the given 'structure_size', 497 with 'table' details used to populate the definition. 498 """ 499 500 print >>f_decls, "extern const __ptable %s;\n" % table_name 501 502 # Write the corresponding definition. 503 504 print >>f_defs, "const __ptable %s = {\n %s,\n {\n %s\n }\n };\n" % ( 505 table_name, structure_size, 506 ",\n ".join([("{%s, %s}" % t) for t in table])) 507 508 def write_instance_structure(self, f_decls, path, structure_size): 509 510 """ 511 Write a declaration to 'f_decls' for the object having the given 'path' 512 and the given 'structure_size'. 513 """ 514 515 # Write an instance-specific type definition for instances of classes. 516 # See: templates/types.h 517 518 print >>f_decls, """\ 519 typedef struct { 520 const __table * table; 521 unsigned int pos; 522 __attr attrs[%s]; 523 } %s; 524 """ % (structure_size, encode_symbol("obj", path)) 525 526 def write_structure(self, f_decls, f_defs, structure_name, table_name, structure_size, structure, path=None): 527 528 """ 529 Write the declarations to 'f_decls' and definitions to 'f_defs' for 530 the object having the given 'structure_name', the given 'table_name', 531 and the given 'structure_size', with 'structure' details used to 532 populate the definition. 533 """ 534 535 if f_decls: 536 print >>f_decls, "extern __obj %s;\n" % encode_path(structure_name) 537 538 is_class = path and self.importer.get_object(path).has_kind("<class>") 539 pos = is_class and encode_symbol("pos", encode_type_attribute(path)) or "0" 540 541 print >>f_defs, """\ 542 __obj %s = { 543 &%s, 544 %s, 545 { 546 %s 547 }}; 548 """ % ( 549 encode_path(structure_name), table_name, pos, 550 ",\n ".join(structure)) 551 552 def get_argument_limits(self, path): 553 554 """ 555 Return the argument minimum and maximum for the callable at 'path', 556 adding an argument position for a universal context. 557 """ 558 559 parameters = self.importer.function_parameters[path] 560 defaults = self.importer.function_defaults.get(path) 561 num_parameters = len(parameters) + 1 562 return num_parameters - (defaults and len(defaults) or 0), num_parameters 563 564 def get_attribute_names(self, indexes): 565 566 """ 567 Given a list of attribute table 'indexes', return a list of attribute 568 names. 569 """ 570 571 all_attrnames = self.optimiser.all_attrnames 572 attrnames = [] 573 for i in indexes: 574 if i is None: 575 attrnames.append(None) 576 else: 577 attrnames.append(all_attrnames[i]) 578 return attrnames 579 580 def get_static_attributes(self, kind, name, attrnames): 581 582 """ 583 Return a mapping of attribute names to paths for attributes belonging 584 to objects of the given 'kind' (being "<class>" or "<module>") with 585 the given 'name' and supporting the given 'attrnames'. 586 """ 587 588 attrs = {} 589 590 for attrname in attrnames: 591 if attrname is None: 592 continue 593 if kind == "<class>": 594 path = self.importer.all_class_attrs[name][attrname] 595 elif kind == "<module>": 596 path = "%s.%s" % (name, attrname) 597 else: 598 continue 599 600 # The module may be hidden. 601 602 attr = self.importer.get_object(path) 603 if not attr: 604 module = self.importer.hidden.get(path) 605 if module: 606 attr = Reference(module.name, "<module>") 607 attrs[attrname] = attr 608 609 return attrs 610 611 def get_instance_attributes(self, name, attrnames): 612 613 """ 614 Return a mapping of attribute names to references for attributes 615 belonging to instances of the class with the given 'name', where the 616 given 'attrnames' are supported. 617 """ 618 619 consts = self.importer.all_instance_attr_constants[name] 620 attrs = {} 621 for attrname in attrnames: 622 if attrname is None: 623 continue 624 const = consts.get(attrname) 625 attrs[attrname] = const or Reference("<var>", "%s.%s" % (name, attrname)) 626 return attrs 627 628 def populate_table(self, key, table): 629 630 """ 631 Traverse the attributes in the determined order for the structure having 632 the given 'key', adding entries to the attribute 'table'. 633 """ 634 635 for attrname in self.optimiser.structures[key]: 636 637 # Handle gaps in the structure. 638 639 if attrname is None: 640 table.append("0") 641 else: 642 table.append(encode_symbol("code", attrname)) 643 644 def populate_parameter_table(self, key, table): 645 646 """ 647 Traverse the parameters in the determined order for the structure having 648 the given 'key', adding entries to the attribute 'table'. 649 """ 650 651 for value in self.optimiser.parameters[key]: 652 653 # Handle gaps in the structure. 654 655 if value is None: 656 table.append(("0", "0")) 657 else: 658 name, pos = value 659 table.append((encode_symbol("pcode", name), pos)) 660 661 def populate_function(self, path, function_instance_attrs, unbound=False): 662 663 """ 664 Populate a structure for the function with the given 'path'. The given 665 'attrs' provide the instance attributes, and if 'unbound' is set to a 666 true value, an unbound method structure is produced (as opposed to a 667 callable bound method structure). 668 """ 669 670 cls = self.function_type 671 structure = [] 672 self.populate_structure(Reference("<instance>", cls), function_instance_attrs, "<instance>", structure, unbound) 673 674 # Append default members. 675 676 self.append_defaults(path, structure) 677 return structure 678 679 def populate_structure(self, ref, attrs, kind, structure, unbound=False): 680 681 """ 682 Traverse the attributes in the determined order for the structure having 683 the given 'ref' whose members are provided by the 'attrs' mapping, in a 684 structure of the given 'kind', adding entries to the object 'structure'. 685 If 'unbound' is set to a true value, an unbound method function pointer 686 will be employed, with a reference to the bound method incorporated into 687 the special __fn__ attribute. 688 """ 689 690 origin = ref.get_origin() 691 692 for attrname in self.optimiser.structures[ref]: 693 694 # Handle gaps in the structure. 695 696 if attrname is None: 697 structure.append("{0, 0}") 698 699 # Handle non-constant and constant members. 700 701 else: 702 attr = attrs[attrname] 703 704 # Special function pointer member. 705 706 if attrname == "__fn__": 707 708 # Provide bound method references and the unbound function 709 # pointer if populating methods in a class. 710 711 bound_attr = None 712 713 # Classes offer instantiators. 714 715 if kind == "<class>": 716 attr = encode_instantiator_pointer(attr) 717 718 # Methods offers references to bound versions and an unbound 719 # method function. 720 721 elif unbound: 722 bound_attr = encode_bound_reference(attr) 723 attr = "__unbound_method" 724 725 # Other functions just offer function pointers. 726 727 else: 728 attr = encode_function_pointer(attr) 729 730 structure.append("{%s, .fn=%s}" % (bound_attr and ".b=&%s" % bound_attr or "0", attr)) 731 continue 732 733 # Special argument specification member. 734 735 elif attrname == "__args__": 736 structure.append("{.min=%s, .ptable=&%s}" % (attr, encode_tablename("<function>", origin))) 737 continue 738 739 # Special internal data member. 740 741 elif attrname == "__data__": 742 structure.append("{0, .%s=%s}" % (encode_literal_constant_member(attr), 743 encode_literal_constant_value(attr))) 744 continue 745 746 structure.append(self.encode_member(origin, attrname, attr, kind)) 747 748 def encode_member(self, path, name, ref, structure_type): 749 750 """ 751 Encode within the structure provided by 'path', the member whose 'name' 752 provides 'ref', within the given 'structure_type'. 753 """ 754 755 kind = ref.get_kind() 756 origin = ref.get_origin() 757 758 # References to constant literals. 759 760 if kind == "<instance>": 761 attr_path = "%s.%s" % (path, name) 762 763 # Obtain a constant value directly assigned to the attribute. 764 765 if self.optimiser.constant_numbers.has_key(attr_path): 766 constant_number = self.optimiser.constant_numbers[attr_path] 767 constant_value = "const%d" % constant_number 768 return "{&%s, &%s} /* %s */" % (constant_value, constant_value, name) 769 770 # Predefined constant references. 771 772 if (path, name) in self.predefined_constant_members: 773 attr_path = encode_predefined_reference("%s.%s" % (path, name)) 774 return "{&%s, &%s} /* %s */" % (attr_path, attr_path, name) 775 776 # General undetermined members. 777 778 if kind in ("<var>", "<instance>"): 779 return "{0, 0} /* %s */" % name 780 781 # Set the context depending on the kind of attribute. 782 # For methods: {&<parent>, &<attr>} 783 # For other attributes: {&<attr>, &<attr>} 784 785 else: 786 if kind == "<function>" and structure_type == "<class>": 787 parent = origin.rsplit(".", 1)[0] 788 context = "&%s" % encode_path(parent) 789 elif kind == "<instance>": 790 context = "&%s" % encode_path(origin) 791 else: 792 context = "0" 793 return "{%s, &%s}" % (context, encode_path(origin)) 794 795 def append_defaults(self, path, structure): 796 797 """ 798 For the given 'path', append default parameter members to the given 799 'structure'. 800 """ 801 802 for name, default in self.importer.function_defaults.get(path): 803 structure.append(self.encode_member(path, name, default, "<instance>")) 804 805 def write_instantiator(self, f_code, f_signatures, path, init_ref): 806 807 """ 808 Write an instantiator to 'f_code', with a signature to 'f_signatures', 809 for instances of the class with the given 'path', with 'init_ref' as the 810 initialiser function reference. 811 812 NOTE: This also needs to initialise any __fn__ and __args__ members 813 NOTE: where __call__ is provided by the class. 814 """ 815 816 parameters = self.importer.function_parameters[init_ref.get_origin()] 817 818 print >>f_code, """\ 819 __attr %s(__attr __args[]) 820 { 821 /* Allocate the structure. */ 822 __args[0] = __new(&%s, &%s, sizeof(%s)); 823 824 /* Call the initialiser. */ 825 %s(__args); 826 827 /* Return the allocated object details. */ 828 return __args[0]; 829 } 830 """ % ( 831 encode_instantiator_pointer(path), 832 encode_tablename("<instance>", path), 833 encode_path(path), 834 encode_symbol("obj", path), 835 encode_function_pointer(init_ref.get_origin()) 836 ) 837 838 print >>f_signatures, "__attr %s(__attr[]);" % encode_instantiator_pointer(path) 839 840 # Write additional literal instantiators. These do not call the 841 # initialisers but instead populate the structures directly. 842 843 if path in self.literal_instantiator_types: 844 print >>f_code, """\ 845 __attr %s(__attr __args[], unsigned int number) 846 { 847 __attr data; 848 849 /* Allocate the structure. */ 850 __args[0] = __new(&%s, &%s, sizeof(%s)); 851 852 /* Allocate a structure for the data. */ 853 data = __newdata(__args, number); 854 855 /* Store a reference to the data in the object's __data__ attribute. */ 856 __store_via_object(__args[0].value, %s, data); 857 858 /* Return the allocated object details. */ 859 return __args[0]; 860 } 861 """ % ( 862 encode_literal_instantiator(path), 863 encode_tablename("<instance>", path), 864 encode_path(path), 865 encode_symbol("obj", path), 866 encode_symbol("pos", "__data__") 867 ) 868 869 print >>f_signatures, "__attr %s(__attr[], unsigned int);" % encode_literal_instantiator(path) 870 871 def write_main_program(self, f_code, f_signatures): 872 873 """ 874 Write the main program to 'f_code', invoking the program's modules. Also 875 write declarations for module main functions to 'f_signatures'. 876 """ 877 878 print >>f_code, """\ 879 int main(int argc, char *argv[]) 880 { 881 __Try 882 {""" 883 884 for name in self.importer.modules.keys(): 885 function_name = "__main_%s" % encode_path(name) 886 print >>f_signatures, "void %s();" % function_name 887 888 # Emit the main module's function last. 889 890 if name != "__main__": 891 print >>f_code, """\ 892 %s();""" % function_name 893 894 print >>f_code, """\ 895 __main___main__(); 896 return 0; 897 } 898 __Catch_anonymous 899 { 900 fprintf(stderr, "Program terminated due to exception.\\n"); 901 return 1; 902 } 903 } 904 """ 905 906 # vim: tabstop=4 expandtab shiftwidth=4