Showing
4 changed files
with
77 additions
and
65 deletions
... | @@ -6,6 +6,8 @@ | ... | @@ -6,6 +6,8 @@ |
6 | # $Id: cx86.py,v 1.3 2004/06/02 21:05:23 varmaa Exp $ | 6 | # $Id: cx86.py,v 1.3 2004/06/02 21:05:23 varmaa Exp $ |
7 | # --------------------------------------------------------------- | 7 | # --------------------------------------------------------------- |
8 | 8 | ||
9 | +import io | ||
10 | + | ||
9 | from . import cparse | 11 | from . import cparse |
10 | from .cvisitors import Visitor | 12 | from .cvisitors import Visitor |
11 | 13 | ||
... | @@ -394,28 +396,25 @@ class CodeGenVisitor(Visitor): | ... | @@ -394,28 +396,25 @@ class CodeGenVisitor(Visitor): |
394 | """Visitor that generates x86 assembly code for the abstract | 396 | """Visitor that generates x86 assembly code for the abstract |
395 | syntax tree.""" | 397 | syntax tree.""" |
396 | 398 | ||
397 | - def __init__(self, file, show_comments=0): | 399 | + # The current label number we're on, for generating |
400 | + # jump labels in the assembly code (e.g., 'LO', 'L1', etc). | ||
401 | + __label = 0 | ||
402 | + | ||
403 | + # Current label number for generating string literal labels. | ||
404 | + __str_literal_label = 0 | ||
405 | + | ||
406 | + def __init__(self, path): | ||
398 | """Constructor. 'file' is the file object to output the | 407 | """Constructor. 'file' is the file object to output the |
399 | - resulting code to. If 'show_comments' is true, then annotated | 408 | + resulting code to.""" |
400 | - comments are produced for the generated assembly code.""" | ||
401 | 409 | ||
402 | Visitor.__init__(self) | 410 | Visitor.__init__(self) |
403 | 411 | ||
404 | - # The current label number we're on, for generating | 412 | + # path of compiled C source |
405 | - # jump labels in the assembly code (e.g., 'LO', 'L1', etc). | 413 | + self.path = path |
406 | - self.__label = 0 | ||
407 | - | ||
408 | - # Current label number for generating string literal labels. | ||
409 | - self.__str_literal_label = 0 | ||
410 | 414 | ||
411 | # Current assembly code for string literals. | 415 | # Current assembly code for string literals. |
412 | - self.__str_literal_str = "" | 416 | + self.str_literal_str = io.StringIO() |
413 | - | 417 | + self.str_literal_dict = {} |
414 | - # Whether we should show comments or not. | ||
415 | - self.show_comments = show_comments | ||
416 | - | ||
417 | - # The file we're outputting the generated code to. | ||
418 | - self.file = file | ||
419 | 418 | ||
420 | # A hashtable of binary operators and the assembly | 419 | # A hashtable of binary operators and the assembly |
421 | # instructions corresponding to them. Certain instructions | 420 | # instructions corresponding to them. Certain instructions |
... | @@ -454,7 +453,7 @@ class CodeGenVisitor(Visitor): | ... | @@ -454,7 +453,7 @@ class CodeGenVisitor(Visitor): |
454 | """Generate a new jump label and return it.""" | 453 | """Generate a new jump label and return it.""" |
455 | 454 | ||
456 | label = ".L%d" % self.__label | 455 | label = ".L%d" % self.__label |
457 | - self.__label += 1 | 456 | + self.__class__.__label += 1 |
458 | return label | 457 | return label |
459 | 458 | ||
460 | def o(self, str, comment=None): | 459 | def o(self, str, comment=None): |
... | @@ -462,22 +461,20 @@ class CodeGenVisitor(Visitor): | ... | @@ -462,22 +461,20 @@ class CodeGenVisitor(Visitor): |
462 | with an optional annotated comment (if comments are | 461 | with an optional annotated comment (if comments are |
463 | enabled).""" | 462 | enabled).""" |
464 | 463 | ||
465 | - if self.show_comments and comment != None: | 464 | + if comment != None: |
466 | comment = "# %s" % comment | 465 | comment = "# %s" % comment |
467 | - self.curr_str += "%-35s %s\n" % (str, comment) | 466 | + self.curr_str.write("%-35s %s\n" % (str, comment)) |
468 | else: | 467 | else: |
469 | if str == "": | 468 | if str == "": |
470 | return | 469 | return |
471 | - self.curr_str += str + "\n" | 470 | + self.curr_str.write(str + "\n") |
472 | 471 | ||
473 | def c(self, str, indent_amt=2): | 472 | def c(self, str, indent_amt=2): |
474 | - """Output a single-line comment to the output file, if | 473 | + "Output a single-line comment to the output file." |
475 | - comments are enabled.""" | ||
476 | 474 | ||
477 | indent = " " * indent_amt | 475 | indent = " " * indent_amt |
478 | 476 | ||
479 | - if self.show_comments: | 477 | + self.o("\n%s# %s\n" % (indent, str)) |
480 | - self.o("\n%s# %s\n" % (indent, str)) | ||
481 | 478 | ||
482 | def vNodeList(self, node): | 479 | def vNodeList(self, node): |
483 | self._visitList(node.nodes) | 480 | self._visitList(node.nodes) |
... | @@ -513,36 +510,43 @@ class CodeGenVisitor(Visitor): | ... | @@ -513,36 +510,43 @@ class CodeGenVisitor(Visitor): |
513 | """Generate and return a list of global variable | 510 | """Generate and return a list of global variable |
514 | definitions.""" | 511 | definitions.""" |
515 | 512 | ||
516 | - globals_str = ".global_vars:\n" | 513 | + globals_str = io.StringIO() |
517 | for symbol in node.symtab.entries.values(): | 514 | for symbol in node.symtab.entries.values(): |
518 | symbol.compile_loc = self.symbol_prepend + symbol.name | 515 | symbol.compile_loc = self.symbol_prepend + symbol.name |
519 | if not symbol.type.is_function() and not symbol.extern: | 516 | if not symbol.type.is_function() and not symbol.extern: |
520 | - globals_str += " .comm %s,%d\n" % \ | 517 | + globals_str.write(" .comm %s,%d\n" |
521 | - (symbol.compile_loc, \ | 518 | + % (symbol.compile_loc, |
522 | - self._calc_var_size(symbol.type)*WEIRD_MULTIPLIER) | 519 | + self._calc_var_size(symbol.type)*WEIRD_MULTIPLIER)) |
523 | return globals_str | 520 | return globals_str |
524 | 521 | ||
525 | def vTranslationUnit(self, node): | 522 | def vTranslationUnit(self, node): |
526 | """Outputs the entire assembly source file.""" | 523 | """Outputs the entire assembly source file.""" |
527 | 524 | ||
528 | - self.curr_str = "" | 525 | + self.curr_str = io.StringIO() |
529 | - self.o("# Generated by c.py") | ||
530 | - self.o("# Atul Varma (Spring 2004)\n") | ||
531 | - self.o(" .text") | ||
532 | 526 | ||
533 | - globals_str = self._generate_global_variable_definitions(node) | 527 | + self.globals_str = self._generate_global_variable_definitions(node) |
534 | 528 | ||
535 | # Generate the main code. | 529 | # Generate the main code. |
536 | self._visitList(node.nodes) | 530 | self._visitList(node.nodes) |
537 | 531 | ||
538 | - # Append global variable definitions. | 532 | + @classmethod |
539 | - self.o(globals_str) | 533 | + def concat (cls, outfile, chunks) : |
540 | - | 534 | + outfile.write("# Generated by cct\n" |
541 | - # Append string literal definitions. | 535 | + "# Franck Pommereau (2018)\n" |
542 | - self.o(self.__str_literal_str) | 536 | + "# Adapted from Atul Varma's c.py (Spring 2004)\n\n") |
543 | - | 537 | + # |
544 | - # Output the entire file. | 538 | + outfile.write(".text\n\n") |
545 | - self.file.write(self.curr_str) | 539 | + for c in chunks : |
540 | + outfile.write("# code from file %r\n" % c.path) | ||
541 | + outfile.write(c.curr_str.getvalue()) | ||
542 | + # | ||
543 | + outfile.write(".global_vars:\n\n") | ||
544 | + for c in chunks : | ||
545 | + outfile.write("\n# globals from file %r\n\n" % c.path) | ||
546 | + outfile.write(c.globals_str.getvalue()) | ||
547 | + for c in chunks : | ||
548 | + outfile.write("\n# string literals from file %r\n\n" % c.path) | ||
549 | + outfile.write(c.str_literal_str.getvalue()) | ||
546 | 550 | ||
547 | def _calc_var_size(self, type): | 551 | def _calc_var_size(self, type): |
548 | """Calculate and return the size of the given type, in | 552 | """Calculate and return the size of the given type, in |
... | @@ -674,7 +678,7 @@ class CodeGenVisitor(Visitor): | ... | @@ -674,7 +678,7 @@ class CodeGenVisitor(Visitor): |
674 | # insert it into our code later on. | 678 | # insert it into our code later on. |
675 | 679 | ||
676 | old_str = self.curr_str | 680 | old_str = self.curr_str |
677 | - self.curr_str = "" | 681 | + self.curr_str = io.StringIO() |
678 | 682 | ||
679 | node.body.accept(self) | 683 | node.body.accept(self) |
680 | 684 | ||
... | @@ -692,7 +696,7 @@ class CodeGenVisitor(Visitor): | ... | @@ -692,7 +696,7 @@ class CodeGenVisitor(Visitor): |
692 | self.stack.save_callee_saves() | 696 | self.stack.save_callee_saves() |
693 | 697 | ||
694 | # Add the previously-generated assembly code for the function. | 698 | # Add the previously-generated assembly code for the function. |
695 | - self.curr_str += function_str | 699 | + self.curr_str.write(function_str.getvalue()) |
696 | 700 | ||
697 | self.o("%s:" % self.curr_func_end_label) | 701 | self.o("%s:" % self.curr_func_end_label) |
698 | 702 | ||
... | @@ -816,10 +820,14 @@ class CodeGenVisitor(Visitor): | ... | @@ -816,10 +820,14 @@ class CodeGenVisitor(Visitor): |
816 | generate (but do not yet emit) the assembly for it, and return | 820 | generate (but do not yet emit) the assembly for it, and return |
817 | the name of the new label.""" | 821 | the name of the new label.""" |
818 | 822 | ||
823 | + if str in self.str_literal_dict : | ||
824 | + return self.str_literal_dict[str] | ||
825 | + | ||
819 | label_str = "LC%d" % self.__str_literal_label | 826 | label_str = "LC%d" % self.__str_literal_label |
827 | + self.str_literal_dict[str] = label_str | ||
820 | str = str.replace('\n', '\\12') | 828 | str = str.replace('\n', '\\12') |
821 | - self.__str_literal_str += """%s:\n .ascii "%s\\0"\n""" % (label_str, str) | 829 | + self.str_literal_str.write("""%s:\n .ascii "%s\\0"\n""" % (label_str, str)) |
822 | - self.__str_literal_label += 1 | 830 | + self.__class__.__str_literal_label += 1 |
823 | return label_str | 831 | return label_str |
824 | 832 | ||
825 | def vStringLiteral(self, node): | 833 | def vStringLiteral(self, node): | ... | ... |
... | @@ -20,8 +20,9 @@ class Compiler (object) : | ... | @@ -20,8 +20,9 @@ class Compiler (object) : |
20 | """This object encapsulates the front-end for the compiler and | 20 | """This object encapsulates the front-end for the compiler and |
21 | serves as a facade interface to the 'meat' of the compiler | 21 | serves as a facade interface to the 'meat' of the compiler |
22 | underneath.""" | 22 | underneath.""" |
23 | - def __init__ (self, arch) : | 23 | + def __init__ (self, arch, path) : |
24 | self.arch = arch | 24 | self.arch = arch |
25 | + self.path = path | ||
25 | self.total_errors = 0 | 26 | self.total_errors = 0 |
26 | self.total_warnings = 0 | 27 | self.total_warnings = 0 |
27 | def _parse (self) : | 28 | def _parse (self) : |
... | @@ -34,37 +35,39 @@ class Compiler (object) : | ... | @@ -34,37 +35,39 @@ class Compiler (object) : |
34 | self.total_warnings += visitor.warnings | 35 | self.total_warnings += visitor.warnings |
35 | if visitor.has_errors(): | 36 | if visitor.has_errors(): |
36 | raise CompileError() | 37 | raise CompileError() |
37 | - def _do_compile (self, outfile, ast_file) : | 38 | + def _do_compile (self, ast_file) : |
38 | """Compiles the code to the given file object. Enabling | 39 | """Compiles the code to the given file object. Enabling |
39 | show_ast prints out the abstract syntax tree.""" | 40 | show_ast prints out the abstract syntax tree.""" |
40 | self._parse() | 41 | self._parse() |
41 | self._compile_phase(cvisitors.SymtabVisitor()) | 42 | self._compile_phase(cvisitors.SymtabVisitor()) |
42 | self._compile_phase(cvisitors.TypeCheckVisitor()) | 43 | self._compile_phase(cvisitors.TypeCheckVisitor()) |
43 | self._compile_phase(cvisitors.FlowControlVisitor()) | 44 | self._compile_phase(cvisitors.FlowControlVisitor()) |
44 | - self._compile_phase(self.arch.CodeGenVisitor(outfile)) | 45 | + comp = self.arch.CodeGenVisitor(self.path) |
46 | + self._compile_phase(comp) | ||
45 | if ast_file is not None: | 47 | if ast_file is not None: |
46 | self._compile_phase(cvisitors.ASTPrinterVisitor(ast_file)) | 48 | self._compile_phase(cvisitors.ASTPrinterVisitor(ast_file)) |
49 | + return comp | ||
47 | def _print_stats (self) : | 50 | def _print_stats (self) : |
48 | "Prints the total number of errors/warnings from compilation." | 51 | "Prints the total number of errors/warnings from compilation." |
49 | if self.total_errors : | 52 | if self.total_errors : |
50 | print("%d errors" % self.total_errors) | 53 | print("%d errors" % self.total_errors) |
51 | if self.total_warnings : | 54 | if self.total_warnings : |
52 | print("%s warnings" % self.total_warnings) | 55 | print("%s warnings" % self.total_warnings) |
53 | - def compile (self, code, outfile, show_ast) : | 56 | + def compile (self, code, show_ast) : |
54 | "Compiles the given code string to the given file object." | 57 | "Compiles the given code string to the given file object." |
55 | self.code = code | 58 | self.code = code |
56 | try: | 59 | try: |
57 | - self._do_compile(outfile, show_ast) | 60 | + chunk = self._do_compile(show_ast) |
58 | except cparse.ParseError: | 61 | except cparse.ParseError: |
59 | print("Errors encountered, bailing.") | 62 | print("Errors encountered, bailing.") |
60 | - return 1 | 63 | + return |
61 | except CompileError: | 64 | except CompileError: |
62 | self._print_stats() | 65 | self._print_stats() |
63 | print("Errors encountered, bailing.") | 66 | print("Errors encountered, bailing.") |
64 | - return 1 | 67 | + return |
65 | self._print_stats() | 68 | self._print_stats() |
66 | print("Compile successful.") | 69 | print("Compile successful.") |
67 | - return 0 | 70 | + return chunk |
68 | 71 | ||
69 | def main (args=None) : | 72 | def main (args=None) : |
70 | parser = argparse.ArgumentParser(prog="cct", | 73 | parser = argparse.ArgumentParser(prog="cct", |
... | @@ -83,6 +86,7 @@ def main (args=None) : | ... | @@ -83,6 +86,7 @@ def main (args=None) : |
83 | parser.add_argument("source", nargs="+", metavar="PATH", | 86 | parser.add_argument("source", nargs="+", metavar="PATH", |
84 | help="C source files(s) to compile") | 87 | help="C source files(s) to compile") |
85 | args = parser.parse_args(args) | 88 | args = parser.parse_args(args) |
89 | + chunks = [] | ||
86 | for src in args.source : | 90 | for src in args.source : |
87 | print("Compiling %r" % src) | 91 | print("Compiling %r" % src) |
88 | if args.ast : | 92 | if args.ast : |
... | @@ -92,8 +96,10 @@ def main (args=None) : | ... | @@ -92,8 +96,10 @@ def main (args=None) : |
92 | else : | 96 | else : |
93 | ast_file = None | 97 | ast_file = None |
94 | code = "\n".join(open(src).readlines()) | 98 | code = "\n".join(open(src).readlines()) |
95 | - retval = Compiler(ARCH[args.arch]).compile(code, args.o, ast_file) | 99 | + ret = Compiler(ARCH[args.arch], src).compile(code, ast_file) |
96 | if ast_file is not None : | 100 | if ast_file is not None : |
97 | ast_file.close() | 101 | ast_file.close() |
98 | - if retval != 0 : | 102 | + if ret is None : |
99 | - sys.exit(retval) | 103 | + sys.exit(1) |
104 | + chunks.append(ret) | ||
105 | + ARCH[args.arch].CodeGenVisitor.concat(args.o, chunks) | ... | ... |
... | @@ -149,5 +149,11 @@ int main(int argc, char **argv) { | ... | @@ -149,5 +149,11 @@ int main(int argc, char **argv) { |
149 | printf("array-built string is: %s\n", c); | 149 | printf("array-built string is: %s\n", c); |
150 | free(c); | 150 | free(c); |
151 | } | 151 | } |
152 | + | ||
153 | + /* multiple defined strings */ | ||
154 | + | ||
155 | + printf("this string is defined twice\n"); | ||
156 | + printf("this string is defined twice\n"); | ||
157 | + | ||
152 | return 0; | 158 | return 0; |
153 | } | 159 | } | ... | ... |
... | @@ -11,16 +11,8 @@ | ... | @@ -11,16 +11,8 @@ |
11 | /* Test global variable. */ | 11 | /* Test global variable. */ |
12 | int stuff_count; | 12 | int stuff_count; |
13 | 13 | ||
14 | -/* Test of static function definition, to make sure it | ||
15 | - doesn't conflict with fib() defined in foo.c. */ | ||
16 | -static int fib() | ||
17 | -{ | ||
18 | - return stuff_count += 1; | ||
19 | -} | ||
20 | - | ||
21 | /* Increment global variable. */ | 14 | /* Increment global variable. */ |
22 | int increment_stuff_count() | 15 | int increment_stuff_count() |
23 | { | 16 | { |
24 | - fib(); | 17 | + return stuff_count += 1; |
25 | - return 0; | ||
26 | } | 18 | } | ... | ... |
-
Please register or login to post a comment