Franck Pommereau

added source filename:lineno in output

* cparse.py: add lineno to nodes
* cttc.py & cx86.py: output lineno as comments
General:
* make a cleaner parser
* use preprocessor
TTC:
* make stdlib
* load extern symbols from stdlib (declared in .h)
x86:
......
......@@ -20,9 +20,16 @@ class Node:
self.colno = colno
self.filename = filename
def loc (self) :
return "%s:%s:%s" % (self.filename, self.lineno, self.colno)
def loc (self, col=False) :
if col :
return "%s:%s:%s" % (self.filename, self.lineno, self.colno)
else :
return "%s:%s" % (self.filename, self.lineno)
def getpos (self) :
return {"lineno" : self.lineno,
"colno" : self.colno,
"filename" : self.filename}
def is_null(self):
"""Returns whether the node represents a null node."""
......
......@@ -250,11 +250,11 @@ def t_WHITESPACE(t):
def t_NEWLINE(t):
r'\n+'
t.lineno += len(t.value)
t.lexer.lineno += len(t.value)
def t_COMMENT(t):
r'/\*[\w\W]*?\*/'
t.lineno += t.value.count('\n')
t.lexer.lineno += t.value.count('\n')
pass
# ---------------------------------------------------------------
......
This diff is collapsed. Click to expand it.
......@@ -142,6 +142,11 @@ class CodeGenVisitor (Visitor) :
def c(self, str, indent_amt=2):
self.curr_str.write("\n # %s\n\n" % str)
def _loc(self, node, comment="") :
if node.lineno != self._last_lineno or comment :
self._last_lineno = node.lineno
self.curr_str.write("# %s %s\n" % (node.loc(), comment))
def vNodeList(self, node):
self._visitList(node.nodes)
......@@ -158,6 +163,7 @@ class CodeGenVisitor (Visitor) :
def vStatementList(self, node):
for n in node.nodes:
self._loc(n)
self._accept_and_empty_stack(n)
def _generate_global_variable_definitions(self, node):
......@@ -169,6 +175,7 @@ class CodeGenVisitor (Visitor) :
return globals_str
def vTranslationUnit(self, node):
self._last_lineno = None
self.curr_str = io.StringIO()
self.globals_str = self._generate_global_variable_definitions(node)
self._visitList(node.nodes)
......@@ -239,6 +246,7 @@ class CodeGenVisitor (Visitor) :
stack_frame_size = self._calc_function_var_addrs(node.symtab, 0)
line = self._fill_line("BEGIN FUNCTION: %s()" % node.name)
self.c("%s\n #\n # Function type: %s" % (line, node.type.get_string()), 0)
self._loc(node, "(enter function)")
self.o("%s:" % node.compile_loc)
self.o(" push BP", "Save old frame pointer")
self.o(" mov SP BP", "Set new frame pointer")
......@@ -255,6 +263,7 @@ class CodeGenVisitor (Visitor) :
self.o(" sub R9 SP SP", "... shift SP")
self.stack.save_callee_saves()
self.curr_str.write(function_str.getvalue())
self._loc(node, "(exit function)")
self.o("%s:" % self.curr_func_end_label)
self.stack.load_callee_saves()
self.o(" mov BP SP", "Deallocate local+temp vars")
......@@ -264,9 +273,11 @@ class CodeGenVisitor (Visitor) :
self.c(line, 0)
def vCompoundStatement(self, node):
self._loc(node)
node.statement_list.accept(self)
def vIfStatement(self, node):
self._loc(node)
done_label = self.new_label() + "_done"
if not node.else_stmt.is_null():
else_label = self.new_label() + "_else"
......@@ -300,6 +311,7 @@ class CodeGenVisitor (Visitor) :
self.continue_labels.pop()
def vWhileLoop(self, node):
self._loc(node)
test_label = self.new_label() + "_test"
done_label = self.new_label() + "_done"
self._push_loop_labels(break_label=done_label,
......@@ -319,6 +331,7 @@ class CodeGenVisitor (Visitor) :
self._pop_loop_labels()
def vForLoop(self, node):
self._loc(node)
test_label = self.new_label() + "_test"
done_label = self.new_label() + "_done"
self._push_loop_labels(break_label=done_label,
......@@ -340,10 +353,12 @@ class CodeGenVisitor (Visitor) :
self._pop_loop_labels()
def vBreakStatement(self, node):
self._loc(node)
self.o(" set R9 @%s" % self.break_labels[-1], "Loop: break statement")
self.o(" jmp R9", "... jump to loop exit")
def vContinueStatement(self, node):
self._loc(node)
self.o(" set R9 @%s" % self.continue_labels[-1], "Loop: continue statement")
self.o(" jmp R9", "... jump to loop start")
......@@ -359,6 +374,7 @@ class CodeGenVisitor (Visitor) :
return label_str
def vStringLiteral(self, node):
self._loc(node)
label_str = self._get_new_str_literal_label(node.get_str())
COMMENT_CHARS = 7
comment_label = node.get_sanitized_str()
......@@ -368,10 +384,12 @@ class CodeGenVisitor (Visitor) :
"Get addr of string literal '%s'" % comment_label)
def vConst(self, node):
self._loc(node)
self.o(" set %s %X" % (self.stack.push(), node.value),
"Load numeric constant %d" % node.value)
def vId(self, node):
self._loc(node)
if node.output_addr:
if isinstance(node.symbol.compile_loc, int) :
self.o(" set R9 %X" % node.symbol.compile_loc,
......@@ -392,6 +410,7 @@ class CodeGenVisitor (Visitor) :
self.o(" ld %s %s" % (reg, reg), "Get value of %s" % node.symbol.name)
def vArrayExpression(self, node):
self._loc(node)
node.expr.accept(self)
node.index.accept(self)
reg_index = self.stack.pop()
......@@ -404,6 +423,7 @@ class CodeGenVisitor (Visitor) :
self.o(" ld %s %s" % (reg_to, reg_to), "Load array value")
def vFunctionExpression(self, node):
self._loc(node)
if self.test and node.function.symbol.name == "TTCTEST" :
call = node.arglist.nodes[0].get_str()
expect = self.test[call]
......@@ -433,6 +453,7 @@ class CodeGenVisitor (Visitor) :
self.c("FUNCTION CALL to %s() - end" % node.function.symbol.name)
def vReturnStatement(self, node):
self._loc(node)
return_reg = self._accept_and_pop(node.expr)
self.o(" mov %s R0" % return_reg, "Set return value")
self.o(" set R9 @%s" % self.curr_func_end_label,
......@@ -526,6 +547,7 @@ class CodeGenVisitor (Visitor) :
raise Exception("unsupported comparison %r" % node.op)
def vBinop(self, node):
self._loc(node)
if node.op in cparse.Binop.ASSIGN_OPS:
self._binop_assign(node)
elif node.op in ['+','-','*']:
......@@ -534,11 +556,13 @@ class CodeGenVisitor (Visitor) :
self._binop_compare(node)
def vNegative(self, node):
self._loc(node)
node.expr.accept(self)
reg = self.stack.peek()
self.o(" neg %s %s" % (reg, reg), "Perform unary negation")
def vPointer(self, node):
self._loc(node)
node.expr.accept(self)
if node.output_addr:
self.o("", "(Getting pointer target addr via '*')")
......@@ -549,6 +573,7 @@ class CodeGenVisitor (Visitor) :
self.stack.done()
def vAddrOf(self, node):
self._loc(node)
node.expr.accept(self)
self.o("", "(Address-of operator '&' used here)")
......@@ -558,6 +583,6 @@ def compile (path) :
def cpp (args, path) :
if args.test :
return ["cpp", "-P", "-D", "TTC", path]
return ["cpp", "-D", "TTC", path]
else :
return ["cpp", "-P", path]
return ["cpp", path]
......
......@@ -478,7 +478,13 @@ class CodeGenVisitor(Visitor):
self.o("\n%s# %s\n" % (indent, str))
def _loc(self, node, comment="") :
if node.lineno != self._last_lineno or comment :
self._last_lineno = node.lineno
self.curr_str.write("# %s %s\n" % (node.loc(), comment))
def vNodeList(self, node):
self._loc(node)
self._visitList(node.nodes)
def _empty_stack(self, node):
......@@ -506,6 +512,7 @@ class CodeGenVisitor(Visitor):
def vStatementList(self, node):
for n in node.nodes:
self._loc(n)
self._accept_and_empty_stack(n)
def _generate_global_variable_definitions(self, node):
......@@ -524,6 +531,7 @@ class CodeGenVisitor(Visitor):
def vTranslationUnit(self, node):
"""Outputs the entire assembly source file."""
self._last_lineno = None
self.curr_str = io.StringIO()
self.globals_str = self._generate_global_variable_definitions(node)
......@@ -665,6 +673,7 @@ class CodeGenVisitor(Visitor):
"# Function type: %s" %
(line, node.type.get_string()), 0)
self._loc(node, "(enter function)")
if not node.static:
self.o(" .global %s" % node.compile_loc)
self.o("%s:" % node.compile_loc)
......@@ -700,6 +709,7 @@ class CodeGenVisitor(Visitor):
# Add the previously-generated assembly code for the function.
self.curr_str.write(function_str.getvalue())
self._loc(node, "(exit function)")
self.o("%s:" % self.curr_func_end_label)
# Restore any callee-save registers that may have been used.
......@@ -712,9 +722,11 @@ class CodeGenVisitor(Visitor):
self.c(line, 0)
def vCompoundStatement(self, node):
self._loc(node)
node.statement_list.accept(self)
def vIfStatement(self, node):
self._loc(node)
done_label = self.new_label() + "_done"
if not node.else_stmt.is_null():
else_label = self.new_label() + "_else"
......@@ -757,6 +769,7 @@ class CodeGenVisitor(Visitor):
self.continue_labels.pop()
def vWhileLoop(self, node):
self._loc(node)
test_label = self.new_label() + "_test"
done_label = self.new_label() + "_done"
......@@ -782,6 +795,7 @@ class CodeGenVisitor(Visitor):
self._pop_loop_labels()
def vForLoop(self, node):
self._loc(node)
test_label = self.new_label() + "_test"
done_label = self.new_label() + "_done"
......@@ -810,10 +824,12 @@ class CodeGenVisitor(Visitor):
self._pop_loop_labels()
def vBreakStatement(self, node):
self._loc(node)
self.o(" jmp %s" % self.break_labels[-1],
"Loop: break statement")
def vContinueStatement(self, node):
self._loc(node)
self.o(" jmp %s" % self.continue_labels[-1],
"Loop: continue statement")
......@@ -833,6 +849,7 @@ class CodeGenVisitor(Visitor):
return label_str
def vStringLiteral(self, node):
self._loc(node)
label_str = self._get_new_str_literal_label(node.get_str())
# Make a little preview of the literal in the annotated
......@@ -847,11 +864,13 @@ class CodeGenVisitor(Visitor):
"Get addr of string literal '%s'" % comment_label)
def vConst(self, node):
self._loc(node)
self.o(" movl $%d, %s" % (node.value,
self.stack.push(node.type)),
"Load numeric constant %d" % node.value)
def vId(self, node):
self._loc(node)
# If we're only supposed to push our address on the stack, not
# our actual value, then do that and exit.
if node.output_addr:
......@@ -869,6 +888,7 @@ class CodeGenVisitor(Visitor):
"Get value of %s" % node.symbol.name)
def vArrayExpression(self, node):
self._loc(node)
node.expr.accept(self)
node.index.accept(self)
reg_index = self.stack.pop(node.index.type)
......@@ -891,6 +911,7 @@ class CodeGenVisitor(Visitor):
def vFunctionExpression(self, node):
"""Generates assembly for calling a function."""
self._loc(node)
self.c("FUNCTION CALL to %s() - begin" %
node.function.symbol.name)
......@@ -936,6 +957,7 @@ class CodeGenVisitor(Visitor):
node.function.symbol.name)
def vReturnStatement(self, node):
self._loc(node)
return_reg = self._accept_and_pop(node.expr)
self.o(" movl %s, %%eax" % return_reg, "Set return value")
self.o(" jmp %s" % self.curr_func_end_label, "Exit function")
......@@ -1051,6 +1073,7 @@ class CodeGenVisitor(Visitor):
"Zero-extend the boolean result")
def vBinop(self, node):
self._loc(node)
if node.op in cparse.Binop.ASSIGN_OPS:
self._binop_assign(node)
elif node.op in ['+','-','*']:
......@@ -1059,11 +1082,13 @@ class CodeGenVisitor(Visitor):
self._binop_compare(node)
def vNegative(self, node):
self._loc(node)
node.expr.accept(self)
self.o(" negl %s" % self.stack.peek(),
"Perform unary negation")
def vPointer(self, node):
self._loc(node)
node.expr.accept(self)
if node.output_addr:
self.o("", "(Getting pointer target addr via '*')")
......@@ -1080,6 +1105,7 @@ class CodeGenVisitor(Visitor):
self.stack.done()
def vAddrOf(self, node):
self._loc(node)
node.expr.accept(self)
self.stack.force_type_change(node.type)
self.o("", "(Address-of operator '&' used here)")
......@@ -1094,6 +1120,6 @@ def compile (path) :
def cpp (args, path) :
if args.test :
return ["cpp", "-P", "-D", "CC", path]
return ["cpp", "-D", "CC", path]
else :
return ["cpp", "-P", path]
return ["cpp", path]
......
......@@ -27,6 +27,7 @@ class Compiler (object) :
self.total_warnings = 0
def _parse (self) :
"Parses the source code."
cparse.inputfile = self.path
self.ast = yacc.parse(self.code)
def _compile_phase (self, visitor) :
"Applies a visitor to the abstract syntax tree."
......@@ -109,8 +110,10 @@ def main (args=None) :
print("Preprocessing %r" % src)
cpp = ARCH[args.arch].cpp(args, src)
print("..$ %s" % " ".join(cpp))
code = subprocess.check_output(cpp).decode()
print("Compiling preprocessed %r (line numbers may have changed)" % src)
code = "\n".join(l.rstrip()
for l in subprocess.check_output(cpp).decode().splitlines()
if not l.startswith("#"))
print("Compiling preprocessed %r" % src)
else :
code = "\n".join(l.rstrip() for l in open(src).readlines())
print("Compiling %r" % src)
......