Franck Pommereau

generate a single output file

......@@ -6,6 +6,8 @@
# $Id: cx86.py,v 1.3 2004/06/02 21:05:23 varmaa Exp $
# ---------------------------------------------------------------
import io
from . import cparse
from .cvisitors import Visitor
......@@ -394,28 +396,25 @@ class CodeGenVisitor(Visitor):
"""Visitor that generates x86 assembly code for the abstract
syntax tree."""
def __init__(self, file, show_comments=0):
# The current label number we're on, for generating
# jump labels in the assembly code (e.g., 'LO', 'L1', etc).
__label = 0
# Current label number for generating string literal labels.
__str_literal_label = 0
def __init__(self, path):
"""Constructor. 'file' is the file object to output the
resulting code to. If 'show_comments' is true, then annotated
comments are produced for the generated assembly code."""
resulting code to."""
Visitor.__init__(self)
# The current label number we're on, for generating
# jump labels in the assembly code (e.g., 'LO', 'L1', etc).
self.__label = 0
# Current label number for generating string literal labels.
self.__str_literal_label = 0
# path of compiled C source
self.path = path
# Current assembly code for string literals.
self.__str_literal_str = ""
# Whether we should show comments or not.
self.show_comments = show_comments
# The file we're outputting the generated code to.
self.file = file
self.str_literal_str = io.StringIO()
self.str_literal_dict = {}
# A hashtable of binary operators and the assembly
# instructions corresponding to them. Certain instructions
......@@ -454,7 +453,7 @@ class CodeGenVisitor(Visitor):
"""Generate a new jump label and return it."""
label = ".L%d" % self.__label
self.__label += 1
self.__class__.__label += 1
return label
def o(self, str, comment=None):
......@@ -462,22 +461,20 @@ class CodeGenVisitor(Visitor):
with an optional annotated comment (if comments are
enabled)."""
if self.show_comments and comment != None:
if comment != None:
comment = "# %s" % comment
self.curr_str += "%-35s %s\n" % (str, comment)
self.curr_str.write("%-35s %s\n" % (str, comment))
else:
if str == "":
return
self.curr_str += str + "\n"
self.curr_str.write(str + "\n")
def c(self, str, indent_amt=2):
"""Output a single-line comment to the output file, if
comments are enabled."""
"Output a single-line comment to the output file."
indent = " " * indent_amt
if self.show_comments:
self.o("\n%s# %s\n" % (indent, str))
self.o("\n%s# %s\n" % (indent, str))
def vNodeList(self, node):
self._visitList(node.nodes)
......@@ -513,36 +510,43 @@ class CodeGenVisitor(Visitor):
"""Generate and return a list of global variable
definitions."""
globals_str = ".global_vars:\n"
globals_str = io.StringIO()
for symbol in node.symtab.entries.values():
symbol.compile_loc = self.symbol_prepend + symbol.name
if not symbol.type.is_function() and not symbol.extern:
globals_str += " .comm %s,%d\n" % \
(symbol.compile_loc, \
self._calc_var_size(symbol.type)*WEIRD_MULTIPLIER)
globals_str.write(" .comm %s,%d\n"
% (symbol.compile_loc,
self._calc_var_size(symbol.type)*WEIRD_MULTIPLIER))
return globals_str
def vTranslationUnit(self, node):
"""Outputs the entire assembly source file."""
self.curr_str = ""
self.o("# Generated by c.py")
self.o("# Atul Varma (Spring 2004)\n")
self.o(" .text")
self.curr_str = io.StringIO()
globals_str = self._generate_global_variable_definitions(node)
self.globals_str = self._generate_global_variable_definitions(node)
# Generate the main code.
self._visitList(node.nodes)
# Append global variable definitions.
self.o(globals_str)
# Append string literal definitions.
self.o(self.__str_literal_str)
# Output the entire file.
self.file.write(self.curr_str)
@classmethod
def concat (cls, outfile, chunks) :
outfile.write("# Generated by cct\n"
"# Franck Pommereau (2018)\n"
"# Adapted from Atul Varma's c.py (Spring 2004)\n\n")
#
outfile.write(".text\n\n")
for c in chunks :
outfile.write("# code from file %r\n" % c.path)
outfile.write(c.curr_str.getvalue())
#
outfile.write(".global_vars:\n\n")
for c in chunks :
outfile.write("\n# globals from file %r\n\n" % c.path)
outfile.write(c.globals_str.getvalue())
for c in chunks :
outfile.write("\n# string literals from file %r\n\n" % c.path)
outfile.write(c.str_literal_str.getvalue())
def _calc_var_size(self, type):
"""Calculate and return the size of the given type, in
......@@ -674,7 +678,7 @@ class CodeGenVisitor(Visitor):
# insert it into our code later on.
old_str = self.curr_str
self.curr_str = ""
self.curr_str = io.StringIO()
node.body.accept(self)
......@@ -692,7 +696,7 @@ class CodeGenVisitor(Visitor):
self.stack.save_callee_saves()
# Add the previously-generated assembly code for the function.
self.curr_str += function_str
self.curr_str.write(function_str.getvalue())
self.o("%s:" % self.curr_func_end_label)
......@@ -816,10 +820,14 @@ class CodeGenVisitor(Visitor):
generate (but do not yet emit) the assembly for it, and return
the name of the new label."""
if str in self.str_literal_dict :
return self.str_literal_dict[str]
label_str = "LC%d" % self.__str_literal_label
self.str_literal_dict[str] = label_str
str = str.replace('\n', '\\12')
self.__str_literal_str += """%s:\n .ascii "%s\\0"\n""" % (label_str, str)
self.__str_literal_label += 1
self.str_literal_str.write("""%s:\n .ascii "%s\\0"\n""" % (label_str, str))
self.__class__.__str_literal_label += 1
return label_str
def vStringLiteral(self, node):
......
......@@ -20,8 +20,9 @@ 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, arch) :
def __init__ (self, arch, path) :
self.arch = arch
self.path = path
self.total_errors = 0
self.total_warnings = 0
def _parse (self) :
......@@ -34,37 +35,39 @@ class Compiler (object) :
self.total_warnings += visitor.warnings
if visitor.has_errors():
raise CompileError()
def _do_compile (self, outfile, ast_file) :
def _do_compile (self, 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(self.arch.CodeGenVisitor(outfile))
comp = self.arch.CodeGenVisitor(self.path)
self._compile_phase(comp)
if ast_file is not None:
self._compile_phase(cvisitors.ASTPrinterVisitor(ast_file))
return comp
def _print_stats (self) :
"Prints the total number of errors/warnings from compilation."
if self.total_errors :
print("%d errors" % self.total_errors)
if self.total_warnings :
print("%s warnings" % self.total_warnings)
def compile (self, code, outfile, show_ast) :
def compile (self, code, show_ast) :
"Compiles the given code string to the given file object."
self.code = code
try:
self._do_compile(outfile, show_ast)
chunk = self._do_compile(show_ast)
except cparse.ParseError:
print("Errors encountered, bailing.")
return 1
return
except CompileError:
self._print_stats()
print("Errors encountered, bailing.")
return 1
return
self._print_stats()
print("Compile successful.")
return 0
return chunk
def main (args=None) :
parser = argparse.ArgumentParser(prog="cct",
......@@ -83,6 +86,7 @@ def main (args=None) :
parser.add_argument("source", nargs="+", metavar="PATH",
help="C source files(s) to compile")
args = parser.parse_args(args)
chunks = []
for src in args.source :
print("Compiling %r" % src)
if args.ast :
......@@ -92,8 +96,10 @@ def main (args=None) :
else :
ast_file = None
code = "\n".join(open(src).readlines())
retval = Compiler(ARCH[args.arch]).compile(code, args.o, ast_file)
ret = Compiler(ARCH[args.arch], src).compile(code, ast_file)
if ast_file is not None :
ast_file.close()
if retval != 0 :
sys.exit(retval)
if ret is None :
sys.exit(1)
chunks.append(ret)
ARCH[args.arch].CodeGenVisitor.concat(args.o, chunks)
......
......@@ -149,5 +149,11 @@ int main(int argc, char **argv) {
printf("array-built string is: %s\n", c);
free(c);
}
/* multiple defined strings */
printf("this string is defined twice\n");
printf("this string is defined twice\n");
return 0;
}
......
......@@ -11,16 +11,8 @@
/* Test global variable. */
int stuff_count;
/* Test of static function definition, to make sure it
doesn't conflict with fib() defined in foo.c. */
static int fib()
{
return stuff_count += 1;
}
/* Increment global variable. */
int increment_stuff_count()
{
fib();
return 0;
return stuff_count += 1;
}
......