Franck Pommereau

correct line numbers, added stdio

......@@ -28,8 +28,14 @@ def _get_calculated(node):
return node
inputfile = None
linenomap = {}
def _get_pos(prod) :
if isinstance(prod, ply.lex.LexToken) :
line_start = prod.lexer.lexdata.rfind('\n', 0, prod.lexpos) + 1
return {"lineno" : linenomap.get(prod.lineno, prod.lineno),
"colno" : prod.lexpos - line_start + 1,
"filename" : inputfile}
for p in prod.slice[1:] :
if isinstance(p, Node) and p.lineno :
return p.getpos()
......@@ -38,7 +44,7 @@ def _get_pos(prod) :
if isinstance(child, Node) and child.lineno :
return child.getpos()
line_start = prod.lexer.lexdata.rfind('\n', 0, prod.lexpos(1)) + 1
return {"lineno" : prod.lineno(1),
return {"lineno" : linenomap.get(prod.lineno(1), prod.lineno(1)),
"colno" : prod.lexpos(1) - line_start + 1,
"filename" : inputfile}
......@@ -366,7 +372,7 @@ def p_empty(t):
pass
def p_error(t):
print("[%(filename):%(lineno)s:%(colno)s] syntax error:" % _get_pos(t))
print("[%(filename)s:%(lineno)s:%(colno)s] syntax error:" % _get_pos(t))
start = t.lexer.lexdata.rfind("\n", 0, t.lexpos)
if start == -1 :
start = 0
......
import subprocess
def _lnomap (line) :
if line.startswith("#") :
try :
return int(line.split(None, 2)[1])
except :
pass
def cpp (path, arch, args) :
lmap = {}
code = []
args = ["cpp", "-D__CCT__=%s" % arch] + args + [path]
pos = 1
out = subprocess.check_output(args)
for line in (l.rstrip() for l in out.decode().splitlines()) :
num = _lnomap(line)
if num is not None :
pos = num
else :
code.append(line)
lmap[len(code)] = pos
pos += 1
return "\n".join(code), lmap
def test (path) :
old = [l.rstrip() for l in open(path)]
new, lno = cpp(path, "x86", [])
new = [l.rstrip() for l in new.splitlines()]
for i, l in enumerate(new) :
s = old[lno.get(i+1, i+1) - 1]
if s != l :
print("@%s -> %s" % (i+1, lno.get(i+1, i+1) - 1))
print("<", s)
print(">", l)
return old, new, lno
......@@ -581,8 +581,8 @@ def compile (path) :
tgt = os.path.splitext(path)[0] + ".bios"
tgt, ["ttc", "asm", path, tgt]
def cpp (args, path) :
def cpp (args) :
if args.test :
return ["cpp", "-D", "TTC", path]
return ["-DTTC"]
else :
return ["cpp", path]
return []
......
......@@ -450,7 +450,7 @@ class TypeCheckVisitor(Visitor):
elif type_str == 'int':
pass
def _compare_types(self, name_str, from_type, to_type, raise_errors=1):
def _compare_types(self, name_str, from_type, to_type, raise_errors=1, node=None):
"""Compares the two types to see if it's possible to perform a
binary operation on them. If it is not, then the appropriate
errors/warnings are raised, unless raise_errors is set to
......@@ -472,14 +472,20 @@ class TypeCheckVisitor(Visitor):
conflict = WARNING
else:
conflict = ERROR
elif from_str.startswith("pointer(") and to_str.startswith("pointer(") :
conflict = WARNING
else:
conflict = ERROR
if not raise_errors:
return conflict
if conflict == WARNING:
self.warning("%s: Conversion from %s to %s may result in data loss." % (name_str, from_str, to_str))
self.warning("%s%s: Conversion from %s to %s may result in data loss."
% ("[%s] " % node.loc() if node else "",
name_str, from_str, to_str))
elif conflict == ERROR:
self.error("%s: Cannot convert from %s to %s." % (name_str, from_str, to_str))
self.error("%s%s: Cannot convert from %s to %s."
% ("[%s] " % node.loc() if node else "",
name_str, from_str, to_str))
def vNode(self, node):
pass
......@@ -519,7 +525,7 @@ class TypeCheckVisitor(Visitor):
# TODO: re-implement this!
# elif node.left.symbol.is_constant:
# self.error("Invalid lvalue: lvalue is constant!")
self._compare_types("Assignment", node.right.type, node.left.type)
self._compare_types("Assignment", node.right.type, node.left.type, node=node)
node.right.coerce_to_type = node.left.type
node.type = node.left.type
else:
......@@ -527,15 +533,18 @@ class TypeCheckVisitor(Visitor):
# specification for binary operand type coercion.
self._coerce_consts(node.left, node.right)
left_conflicts = self._compare_types("", node.right.type, node.left.type, raise_errors=0)
right_conflicts = self._compare_types("", node.left.type, node.right.type, raise_errors=0)
left_conflicts = self._compare_types("", node.right.type, node.left.type,
raise_errors=0, node=node)
right_conflicts = self._compare_types("", node.left.type, node.right.type,
raise_errors=0, node=node)
if left_conflicts < right_conflicts:
from_node = node.right
to_node = node.left
else:
from_node = node.left
to_node = node.right
self._compare_types("Binop '%s'" % node.op, from_node.type, to_node.type)
self._compare_types("Binop '%s'" % node.op, from_node.type, to_node.type,
node=node)
from_node.coerce_to_type = to_node.type
to_node.coerce_to_type = to_node.type
node.type = to_node.type
......@@ -550,7 +559,7 @@ class TypeCheckVisitor(Visitor):
node.expr.accept(self)
return_type = self.curr_func.type.get_return_type()
self._coerce_const(node.expr, return_type)
self._compare_types("Return expression", node.expr.type, return_type)
self._compare_types("Return expression", node.expr.type, return_type, node=node)
node.expr.coerce_to_type = return_type
def vArrayExpression(self, node):
......@@ -579,7 +588,8 @@ class TypeCheckVisitor(Visitor):
self.error("Too few arguments passed to function.")
for arg, param in zip(node.arglist.nodes, params.nodes):
self._coerce_const(arg, param.type)
self._compare_types("Function call argument", arg.type, param.type)
self._compare_types("Function call argument", arg.type, param.type,
node=node)
arg.coerce_to_type = param.type
# If this function takes a variable number of args and
# we've got more args than required parameters, we need
......
......@@ -1118,8 +1118,8 @@ def compile (path) :
tgt = os.path.splitext(path)[0]
return tgt, ["gcc", "-m32", "-o", tgt, path]
def cpp (args, path) :
def cpp (args) :
if args.test :
return ["cpp", "-D", "CC", path]
return ["-DCC"]
else :
return ["cpp", path]
return []
......
import argparse, sys, os, os.path, subprocess
import ply.yacc as yacc
from . import cparse, cvisitors, cx86, cttc
from . import cparse, cvisitors, cx86, cttc, cpp
ARCH = {"x86" : cx86,
"ttc" : cttc}
......@@ -19,15 +19,17 @@ 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, path, test) :
def __init__ (self, arch, path, lmap, test) :
self.arch = arch
self.path = path
self.lmap = lmap
self.test = test
self.total_errors = 0
self.total_warnings = 0
def _parse (self) :
"Parses the source code."
cparse.inputfile = self.path
cparse.linenomap = self.lmap
self.ast = yacc.parse(self.code)
def _compile_phase (self, visitor) :
"Applies a visitor to the abstract syntax tree."
......@@ -108,16 +110,14 @@ def main (args=None) :
ast_file = None
if args.cpp :
print("Preprocessing %r" % src)
cpp = ARCH[args.arch].cpp(args, src)
print("..$ %s" % " ".join(cpp))
code = "\n".join(l.rstrip()
for l in subprocess.check_output(cpp).decode().splitlines()
if not l.startswith("#"))
cppargs = ARCH[args.arch].cpp(args)
print("..$ cpp %s %s" % (" ".join(cppargs), src))
code, lmap = cpp.cpp(src, args.arch, cppargs)
print("Compiling preprocessed %r" % src)
else :
code = "\n".join(l.rstrip() for l in open(src).readlines())
print("Compiling %r" % src)
ret = Compiler(ARCH[args.arch], src, args.test).compile(code, ast_file)
ret = Compiler(ARCH[args.arch], src, lmap, args.test).compile(code, ast_file)
if ast_file is not None :
ast_file.close()
if ret is None :
......
putc:
set R8 3 # Point R8 towards argument c
add R8 SP R8 # ... located as SP+3
ld R8 R8 # Load argument c
set R9 1012 # Put command for screen
bus R9 R8 R8 # Write char to screen
set R0 1 # Set return value
ret
#ifdef __CCT__
extern int putc(char c);
#define neg(i) -i
#define UINT(i) i
#define _DIGITS "0123456789ABCDEF"
#define _STR "65536"
#else
extern int putchar(int c);
#define putc(c) putchar(c)
#define neg(i) ~i + 1
#define UINT(i) (unsigned int)(i)
#define _DIGITS _digits
char _digits[17] = "0123456789ABCDEF";
#define _STR _str
char _str[6] = "65536";
#endif
int puts(char *s) {
int n;
int i;
n = 0;
i = 0;
while (1) {
if (s[i]) {
n += putc(s[i]);
i += 1;
} else {
break;
}
}
return n;
}
#define ICHAR 105
#define SCHAR 115
#define UCHAR 117
#define XCHAR 120
#define PERCENT 37
#define MINUS 45
int putu(int u, char f) {
char *DIGITS;
char *str;
int div;
int r;
int n;
int p;
DIGITS = _DIGITS;
str = _STR;
n = 0;
p = 0;
if (f == XCHAR) {
div = 16;
} else {
div = 10;
}
while (u) {
r = u % div;
str[p] = DIGITS[r];
p += 1;
u = u / div;
}
p -= 1;
while (p >= 0) {
n += putc(str[p]);
p -= 1;
}
return n;
}
int puti(int i) {
int n;
int s;
int r;
n = 0;
if (UINT(i) > 32767) {
n += putc(MINUS);
n += putu(neg(i), UCHAR);
return n;
} else {
return putu(i, UCHAR);
}
}
int printf(char *str, ...) {
int n;
int i;
int a;
int *iargs;
char **cargs;
iargs = &str;
cargs = &str;
a = 1;
n = 0;
i = 0;
while (1) {
if (str[i] == 0) {
break;
} else if (str[i] == PERCENT) {
i += 1;
if (str[i] == ICHAR) {
n += puti(iargs[a]);
} else if (str[i] == UCHAR) {
n += putu(iargs[a], UCHAR);
} else if (str[i] == SCHAR) {
n += puts(cargs[a]);
} else if (str[i] == XCHAR) {
n += putu(iargs[a], XCHAR);
} else if (str[i] == PERCENT) {
n += putc(PERCENT);
i += 1;
continue;
} else {
n += putc(PERCENT);
n += putc(str[i]);
}
a += 1;
} else {
n += putc(str[i]);
}
i += 1;
}
return n;
}
int main() {
puts("hello world\n");
puti(42);
puts(" => 42\n");
puti(-42);
puts(" => -42\n");
putu(42, XCHAR);
puts(" => 2A\n");
putu(42, UCHAR);
puts(" => 42\n");
printf("hello %s I'm %u (%x)\n", "stdio", 42, 42);
return 0;
}
extern int printf(char *str, ...);
extern int puts(char *s);
extern int putc(char c);
extern int puti(int i);