Franck Pommereau

added test options

...@@ -8,3 +8,4 @@ __pycache__ ...@@ -8,3 +8,4 @@ __pycache__
8 .#* 8 .#*
9 #* 9 #*
10 cctlib/parser.out 10 cctlib/parser.out
11 +cct-test
......
1 + * cparse.py: add lineno to nodes
2 + * cttc.py & cx86.py: output lineno as comments
3 + * make a cleaner parser
4 + * use preprocessor
5 + * make stdlib
6 + * load extern symbols from stdlib (declared in .h)
1 -import io 1 +import io, os.path
2 2
3 from . import cparse 3 from . import cparse
4 from .cvisitors import Visitor 4 from .cvisitors import Visitor
...@@ -120,9 +120,10 @@ class CodeGenVisitor (Visitor) : ...@@ -120,9 +120,10 @@ class CodeGenVisitor (Visitor) :
120 __label = 0 120 __label = 0
121 __str_literal_label = 0 121 __str_literal_label = 0
122 122
123 - def __init__(self, path): 123 + def __init__(self, path, test=None):
124 Visitor.__init__(self) 124 Visitor.__init__(self)
125 self.path = path 125 self.path = path
126 + self.test = test
126 self.str_literal_str = io.StringIO() 127 self.str_literal_str = io.StringIO()
127 self.str_literal_dict = {} 128 self.str_literal_dict = {}
128 129
...@@ -180,17 +181,17 @@ class CodeGenVisitor (Visitor) : ...@@ -180,17 +181,17 @@ class CodeGenVisitor (Visitor) :
180 for c in chunks : 181 for c in chunks :
181 s = c.curr_str.getvalue() 182 s = c.curr_str.getvalue()
182 if s.strip() : 183 if s.strip() :
183 - outfile.write("\n###\n### code from file %r\n###\n" % c.path) 184 + outfile.write("\n#\n# code from file %r\n#\n" % c.path)
184 outfile.write(s) 185 outfile.write(s)
185 for c in chunks : 186 for c in chunks :
186 s = c.globals_str.getvalue() 187 s = c.globals_str.getvalue()
187 if s.strip() : 188 if s.strip() :
188 - outfile.write("\n###\n### globals from file %r\n###\n\n" % c.path) 189 + outfile.write("\n#\n# globals from file %r\n#\n\n" % c.path)
189 outfile.write(s) 190 outfile.write(s)
190 for c in chunks : 191 for c in chunks :
191 s = c.str_literal_str.getvalue() 192 s = c.str_literal_str.getvalue()
192 if s.strip() : 193 if s.strip() :
193 - outfile.write("\n###\n### string literals from file %r\n###\n\n" 194 + outfile.write("\n#\n# string literals from file %r\n#\n\n"
194 % c.path) 195 % c.path)
195 outfile.write(s) 196 outfile.write(s)
196 197
...@@ -396,6 +397,13 @@ class CodeGenVisitor (Visitor) : ...@@ -396,6 +397,13 @@ class CodeGenVisitor (Visitor) :
396 self.o(" ld %s %s" % (reg_to, reg_to), "Load array value") 397 self.o(" ld %s %s" % (reg_to, reg_to), "Load array value")
397 398
398 def vFunctionExpression(self, node): 399 def vFunctionExpression(self, node):
400 + if self.test and node.function.symbol.name == "TTCTEST" :
401 + call = node.arglist.nodes[0].get_str()
402 + expect = self.test[call]
403 + ret = self._accept_and_pop(node.arglist.nodes[1])
404 + self.o(" ### %s == %s # == %s" % (ret, expect, call))
405 + self.stack.done()
406 + return
399 self.c("FUNCTION CALL to %s() - begin" % 407 self.c("FUNCTION CALL to %s() - begin" %
400 node.function.symbol.name) 408 node.function.symbol.name)
401 self.stack.save_caller_saves() 409 self.stack.save_caller_saves()
...@@ -536,3 +544,13 @@ class CodeGenVisitor (Visitor) : ...@@ -536,3 +544,13 @@ class CodeGenVisitor (Visitor) :
536 def vAddrOf(self, node): 544 def vAddrOf(self, node):
537 node.expr.accept(self) 545 node.expr.accept(self)
538 self.o("", "(Address-of operator '&' used here)") 546 self.o("", "(Address-of operator '&' used here)")
547 +
548 +def compile (path) :
549 + tgt = os.path.splitext(path)[0] + ".bios"
550 + tgt, ["ttc", "asm", path, tgt]
551 +
552 +def cpp (args, path) :
553 + if args.test :
554 + return ["cpp", "-P", "-D", "TTC", path]
555 + else :
556 + return ["cpp", "-P", path]
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
8 # $Id: cx86.py,v 1.3 2004/06/02 21:05:23 varmaa Exp $ 8 # $Id: cx86.py,v 1.3 2004/06/02 21:05:23 varmaa Exp $
9 # --------------------------------------------------------------- 9 # ---------------------------------------------------------------
10 10
11 -import io 11 +import io, os.path
12 12
13 from . import cparse 13 from . import cparse
14 from .cvisitors import Visitor 14 from .cvisitors import Visitor
...@@ -405,7 +405,7 @@ class CodeGenVisitor(Visitor): ...@@ -405,7 +405,7 @@ class CodeGenVisitor(Visitor):
405 # Current label number for generating string literal labels. 405 # Current label number for generating string literal labels.
406 __str_literal_label = 0 406 __str_literal_label = 0
407 407
408 - def __init__(self, path): 408 + def __init__(self, path, test=None):
409 """Constructor. 'file' is the file object to output the 409 """Constructor. 'file' is the file object to output the
410 resulting code to.""" 410 resulting code to."""
411 411
...@@ -1087,3 +1087,13 @@ class CodeGenVisitor(Visitor): ...@@ -1087,3 +1087,13 @@ class CodeGenVisitor(Visitor):
1087 # --------------------------------------------------------------- 1087 # ---------------------------------------------------------------
1088 # End of cx86.py 1088 # End of cx86.py
1089 # --------------------------------------------------------------- 1089 # ---------------------------------------------------------------
1090 +
1091 +def compile (path) :
1092 + tgt = os.path.splitext(path)[0]
1093 + return tgt, ["gcc", "-m32", "-o", tgt, path]
1094 +
1095 +def cpp (args, path) :
1096 + if args.test :
1097 + return ["cpp", "-P", "-D", "CC", path]
1098 + else :
1099 + return ["cpp", "-P", path]
......
1 -import argparse, sys, os.path 1 +import argparse, sys, os, os.path, subprocess
2 2
3 import ply.yacc as yacc 3 import ply.yacc as yacc
4 from . import cparse, cvisitors, cx86, cttc 4 from . import cparse, cvisitors, cx86, cttc
...@@ -19,9 +19,10 @@ class Compiler (object) : ...@@ -19,9 +19,10 @@ class Compiler (object) :
19 """This object encapsulates the front-end for the compiler and 19 """This object encapsulates the front-end for the compiler and
20 serves as a facade interface to the 'meat' of the compiler 20 serves as a facade interface to the 'meat' of the compiler
21 underneath.""" 21 underneath."""
22 - def __init__ (self, arch, path) : 22 + def __init__ (self, arch, path, test) :
23 self.arch = arch 23 self.arch = arch
24 self.path = path 24 self.path = path
25 + self.test = test
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) :
...@@ -41,7 +42,7 @@ class Compiler (object) : ...@@ -41,7 +42,7 @@ class Compiler (object) :
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 - comp = self.arch.CodeGenVisitor(self.path) 45 + comp = self.arch.CodeGenVisitor(self.path, self.test)
45 self._compile_phase(comp) 46 self._compile_phase(comp)
46 if ast_file is not None: 47 if ast_file is not None:
47 self._compile_phase(cvisitors.ASTPrinterVisitor(ast_file)) 48 self._compile_phase(cvisitors.ASTPrinterVisitor(ast_file))
...@@ -58,14 +59,14 @@ class Compiler (object) : ...@@ -58,14 +59,14 @@ class Compiler (object) :
58 try: 59 try:
59 chunk = self._do_compile(show_ast) 60 chunk = self._do_compile(show_ast)
60 except cparse.ParseError: 61 except cparse.ParseError:
61 - print("Errors encountered, bailing.") 62 + print("... errors encountered, bailing")
62 return 63 return
63 except CompileError: 64 except CompileError:
64 self._print_stats() 65 self._print_stats()
65 - print("Errors encountered, bailing.") 66 + print("... errors encountered, bailing")
66 return 67 return
67 self._print_stats() 68 self._print_stats()
68 - print("Compile successful.") 69 + print("... compile successful")
69 return chunk 70 return chunk
70 71
71 def main (args=None) : 72 def main (args=None) :
...@@ -77,28 +78,53 @@ def main (args=None) : ...@@ -77,28 +78,53 @@ def main (args=None) :
77 help="write output to PATH") 78 help="write output to PATH")
78 parser.add_argument("--ast", action="store_true", default=False, 79 parser.add_argument("--ast", action="store_true", default=False,
79 help="dump AST for each C file") 80 help="dump AST for each C file")
80 - parser.add_argument("--arch", action="store", choices=list(ARCH), 81 + parser.add_argument("--cpp", "-p", action="store_true", default=False,
81 - default="ttc", 82 + help="process input file through cpp")
82 - help="output assembly for specified architecture (default 'ttc')") 83 + parser.add_argument("--arch", action="store", choices=list(ARCH), default="ttc",
83 - parser.add_argument("-t", "--ttc", action="store_const", const="ttc", 84 + help="output assembly for specified architecture"
84 - dest="arch", help="output TTC assembly") 85 + " (default 'ttc')")
86 + parser.add_argument("--compile", "-c", action="store_true", default=False,
87 + help="compile generated ASM")
88 + parser.add_argument("--test", "-t", action="store_true", default=False,
89 + help="test compiler")
85 parser.add_argument("source", nargs="+", metavar="PATH", 90 parser.add_argument("source", nargs="+", metavar="PATH",
86 help="C source files(s) to compile") 91 help="C source files(s) to compile")
87 args = parser.parse_args(args) 92 args = parser.parse_args(args)
88 chunks = [] 93 chunks = []
94 + if args.test :
95 + print("Generating tests")
96 + print("..$ gcc -o cct-test -D CC %s" % " ".join(args.source))
97 + subprocess.run(["gcc", "-o", "cct-test", "-D", "CC"] + args.source)
98 + print("..$ cct-test")
99 + testdata = subprocess.check_output("cct-test").decode()
100 + args.test = dict(line.rsplit(" => ", 1) for line in testdata.splitlines())
89 for src in args.source : 101 for src in args.source :
90 - print("Compiling %r" % src)
91 if args.ast : 102 if args.ast :
92 ast_path = os.path.splitext(src)[0] + ".ast" 103 ast_path = os.path.splitext(src)[0] + ".ast"
93 print("Dumping AST to %r" % ast_path) 104 print("Dumping AST to %r" % ast_path)
94 ast_file = open(ast_path, "w") 105 ast_file = open(ast_path, "w")
95 else : 106 else :
96 ast_file = None 107 ast_file = None
97 - code = "\n".join(l.rstrip() for l in open(src).readlines()) 108 + if args.cpp :
98 - ret = Compiler(ARCH[args.arch], src).compile(code, ast_file) 109 + print("Preprocessing %r" % src)
110 + cpp = ARCH[args.arch].cpp(args, src)
111 + print("..$ %s" % " ".join(cpp))
112 + code = subprocess.check_output(cpp).decode()
113 + print("Compiling preprocessed %r (line numbers may have changed)" % src)
114 + else :
115 + code = "\n".join(l.rstrip() for l in open(src).readlines())
116 + print("Compiling %r" % src)
117 + ret = Compiler(ARCH[args.arch], src, args.test).compile(code, ast_file)
99 if ast_file is not None : 118 if ast_file is not None :
100 ast_file.close() 119 ast_file.close()
101 if ret is None : 120 if ret is None :
102 sys.exit(1) 121 sys.exit(1)
103 chunks.append(ret) 122 chunks.append(ret)
104 ARCH[args.arch].CodeGenVisitor.concat(args.o, chunks) 123 ARCH[args.arch].CodeGenVisitor.concat(args.o, chunks)
124 + args.o.flush()
125 + if args.compile :
126 + tgt, cmd = ARCH[args.arch].compile(args.o.name)
127 + print("Building %r" % tgt)
128 + print(".. $ %s" % " ".join(cmd))
129 + ret = subprocess.run(cmd)
130 + print("... exited with status %s" % ret.returncode)
......