main.py
2.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import argparse, sys, os.path
import ply.yacc as yacc
from . import cparse, cvisitors, cx86
class CompileError (Exception) :
"Exception raised when there's been a compilation error."
pass
class Compiler (object) :
"""This object encapsulates the front-end for the compiler and
serves as a facade interface to the 'meat' of the compiler
underneath."""
def __init__ (self) :
self.total_errors = 0
self.total_warnings = 0
def _parse (self) :
"Parses the source code."
self.ast = yacc.parse(self.code)
def _compile_phase (self, visitor) :
"Applies a visitor to the abstract syntax tree."
visitor.visit(self.ast)
self.total_errors += visitor.errors
self.total_warnings += visitor.warnings
if visitor.has_errors():
raise CompileError()
def _do_compile (self, outfile, ast_file) :
"""Compiles the code to the given file object. Enabling
show_ast prints out the abstract syntax tree."""
self._parse()
self._compile_phase(cvisitors.SymtabVisitor())
self._compile_phase(cvisitors.TypeCheckVisitor())
self._compile_phase(cvisitors.FlowControlVisitor())
self._compile_phase(cx86.CodeGenVisitor(outfile))
if ast_file is not None:
self._compile_phase(cvisitors.ASTPrinterVisitor(ast_file))
def _print_stats (self) :
"Prints the total number of errors/warnings from compilation."
print("%d errors, %d warnings." % (self.total_errors, self.total_warnings))
def compile (self, code, outfile, show_ast) :
"Compiles the given code string to the given file object."
self.code = code
try:
self._do_compile(outfile, show_ast)
except cparse.ParseError:
print("Errors encountered, bailing.")
return 1
except CompileError:
self._print_stats()
print("Errors encountered, bailing.")
return 1
self._print_stats()
print("Compile successful.")
return 0
def main (args=None) :
parser = argparse.ArgumentParser(prog="cct")
parser.add_argument("-o", action="store", metavar="PATH",
type=argparse.FileType('w'), default=sys.stdout,
help="write output to PATH")
parser.add_argument("--ast", action="store_true", default=False,
help="dump AST for each C file")
parser.add_argument("source", nargs="+", metavar="PATH",
help="C source files(s) to compile")
args = parser.parse_args(args)
for src in args.source :
if args.ast :
ast_file = open(os.path.splitext(src)[0] + ".ast", "w")
else :
ast_file = None
retval = Compiler().compile(open(src).read(), args.o, ast_file)
if ast_file is not None :
ast_file.close()
if retval != 0 :
sys.exit(retval)