Franck Pommereau

correct line numbers, added stdio

...@@ -28,8 +28,14 @@ def _get_calculated(node): ...@@ -28,8 +28,14 @@ def _get_calculated(node):
28 return node 28 return node
29 29
30 inputfile = None 30 inputfile = None
31 +linenomap = {}
31 32
32 def _get_pos(prod) : 33 def _get_pos(prod) :
34 + if isinstance(prod, ply.lex.LexToken) :
35 + line_start = prod.lexer.lexdata.rfind('\n', 0, prod.lexpos) + 1
36 + return {"lineno" : linenomap.get(prod.lineno, prod.lineno),
37 + "colno" : prod.lexpos - line_start + 1,
38 + "filename" : inputfile}
33 for p in prod.slice[1:] : 39 for p in prod.slice[1:] :
34 if isinstance(p, Node) and p.lineno : 40 if isinstance(p, Node) and p.lineno :
35 return p.getpos() 41 return p.getpos()
...@@ -38,7 +44,7 @@ def _get_pos(prod) : ...@@ -38,7 +44,7 @@ def _get_pos(prod) :
38 if isinstance(child, Node) and child.lineno : 44 if isinstance(child, Node) and child.lineno :
39 return child.getpos() 45 return child.getpos()
40 line_start = prod.lexer.lexdata.rfind('\n', 0, prod.lexpos(1)) + 1 46 line_start = prod.lexer.lexdata.rfind('\n', 0, prod.lexpos(1)) + 1
41 - return {"lineno" : prod.lineno(1), 47 + return {"lineno" : linenomap.get(prod.lineno(1), prod.lineno(1)),
42 "colno" : prod.lexpos(1) - line_start + 1, 48 "colno" : prod.lexpos(1) - line_start + 1,
43 "filename" : inputfile} 49 "filename" : inputfile}
44 50
...@@ -366,7 +372,7 @@ def p_empty(t): ...@@ -366,7 +372,7 @@ def p_empty(t):
366 pass 372 pass
367 373
368 def p_error(t): 374 def p_error(t):
369 - print("[%(filename):%(lineno)s:%(colno)s] syntax error:" % _get_pos(t)) 375 + print("[%(filename)s:%(lineno)s:%(colno)s] syntax error:" % _get_pos(t))
370 start = t.lexer.lexdata.rfind("\n", 0, t.lexpos) 376 start = t.lexer.lexdata.rfind("\n", 0, t.lexpos)
371 if start == -1 : 377 if start == -1 :
372 start = 0 378 start = 0
......
1 +import subprocess
2 +
3 +def _lnomap (line) :
4 + if line.startswith("#") :
5 + try :
6 + return int(line.split(None, 2)[1])
7 + except :
8 + pass
9 +
10 +def cpp (path, arch, args) :
11 + lmap = {}
12 + code = []
13 + args = ["cpp", "-D__CCT__=%s" % arch] + args + [path]
14 + pos = 1
15 + out = subprocess.check_output(args)
16 + for line in (l.rstrip() for l in out.decode().splitlines()) :
17 + num = _lnomap(line)
18 + if num is not None :
19 + pos = num
20 + else :
21 + code.append(line)
22 + lmap[len(code)] = pos
23 + pos += 1
24 + return "\n".join(code), lmap
25 +
26 +def test (path) :
27 + old = [l.rstrip() for l in open(path)]
28 + new, lno = cpp(path, "x86", [])
29 + new = [l.rstrip() for l in new.splitlines()]
30 + for i, l in enumerate(new) :
31 + s = old[lno.get(i+1, i+1) - 1]
32 + if s != l :
33 + print("@%s -> %s" % (i+1, lno.get(i+1, i+1) - 1))
34 + print("<", s)
35 + print(">", l)
36 + return old, new, lno
...@@ -581,8 +581,8 @@ def compile (path) : ...@@ -581,8 +581,8 @@ def compile (path) :
581 tgt = os.path.splitext(path)[0] + ".bios" 581 tgt = os.path.splitext(path)[0] + ".bios"
582 tgt, ["ttc", "asm", path, tgt] 582 tgt, ["ttc", "asm", path, tgt]
583 583
584 -def cpp (args, path) : 584 +def cpp (args) :
585 if args.test : 585 if args.test :
586 - return ["cpp", "-D", "TTC", path] 586 + return ["-DTTC"]
587 else : 587 else :
588 - return ["cpp", path] 588 + return []
......
...@@ -450,7 +450,7 @@ class TypeCheckVisitor(Visitor): ...@@ -450,7 +450,7 @@ class TypeCheckVisitor(Visitor):
450 elif type_str == 'int': 450 elif type_str == 'int':
451 pass 451 pass
452 452
453 - def _compare_types(self, name_str, from_type, to_type, raise_errors=1): 453 + def _compare_types(self, name_str, from_type, to_type, raise_errors=1, node=None):
454 """Compares the two types to see if it's possible to perform a 454 """Compares the two types to see if it's possible to perform a
455 binary operation on them. If it is not, then the appropriate 455 binary operation on them. If it is not, then the appropriate
456 errors/warnings are raised, unless raise_errors is set to 456 errors/warnings are raised, unless raise_errors is set to
...@@ -472,14 +472,20 @@ class TypeCheckVisitor(Visitor): ...@@ -472,14 +472,20 @@ class TypeCheckVisitor(Visitor):
472 conflict = WARNING 472 conflict = WARNING
473 else: 473 else:
474 conflict = ERROR 474 conflict = ERROR
475 + elif from_str.startswith("pointer(") and to_str.startswith("pointer(") :
476 + conflict = WARNING
475 else: 477 else:
476 conflict = ERROR 478 conflict = ERROR
477 if not raise_errors: 479 if not raise_errors:
478 return conflict 480 return conflict
479 if conflict == WARNING: 481 if conflict == WARNING:
480 - self.warning("%s: Conversion from %s to %s may result in data loss." % (name_str, from_str, to_str)) 482 + self.warning("%s%s: Conversion from %s to %s may result in data loss."
483 + % ("[%s] " % node.loc() if node else "",
484 + name_str, from_str, to_str))
481 elif conflict == ERROR: 485 elif conflict == ERROR:
482 - self.error("%s: Cannot convert from %s to %s." % (name_str, from_str, to_str)) 486 + self.error("%s%s: Cannot convert from %s to %s."
487 + % ("[%s] " % node.loc() if node else "",
488 + name_str, from_str, to_str))
483 489
484 def vNode(self, node): 490 def vNode(self, node):
485 pass 491 pass
...@@ -519,7 +525,7 @@ class TypeCheckVisitor(Visitor): ...@@ -519,7 +525,7 @@ class TypeCheckVisitor(Visitor):
519 # TODO: re-implement this! 525 # TODO: re-implement this!
520 # elif node.left.symbol.is_constant: 526 # elif node.left.symbol.is_constant:
521 # self.error("Invalid lvalue: lvalue is constant!") 527 # self.error("Invalid lvalue: lvalue is constant!")
522 - self._compare_types("Assignment", node.right.type, node.left.type) 528 + self._compare_types("Assignment", node.right.type, node.left.type, node=node)
523 node.right.coerce_to_type = node.left.type 529 node.right.coerce_to_type = node.left.type
524 node.type = node.left.type 530 node.type = node.left.type
525 else: 531 else:
...@@ -527,15 +533,18 @@ class TypeCheckVisitor(Visitor): ...@@ -527,15 +533,18 @@ class TypeCheckVisitor(Visitor):
527 # specification for binary operand type coercion. 533 # specification for binary operand type coercion.
528 534
529 self._coerce_consts(node.left, node.right) 535 self._coerce_consts(node.left, node.right)
530 - left_conflicts = self._compare_types("", node.right.type, node.left.type, raise_errors=0) 536 + left_conflicts = self._compare_types("", node.right.type, node.left.type,
531 - right_conflicts = self._compare_types("", node.left.type, node.right.type, raise_errors=0) 537 + raise_errors=0, node=node)
538 + right_conflicts = self._compare_types("", node.left.type, node.right.type,
539 + raise_errors=0, node=node)
532 if left_conflicts < right_conflicts: 540 if left_conflicts < right_conflicts:
533 from_node = node.right 541 from_node = node.right
534 to_node = node.left 542 to_node = node.left
535 else: 543 else:
536 from_node = node.left 544 from_node = node.left
537 to_node = node.right 545 to_node = node.right
538 - self._compare_types("Binop '%s'" % node.op, from_node.type, to_node.type) 546 + self._compare_types("Binop '%s'" % node.op, from_node.type, to_node.type,
547 + node=node)
539 from_node.coerce_to_type = to_node.type 548 from_node.coerce_to_type = to_node.type
540 to_node.coerce_to_type = to_node.type 549 to_node.coerce_to_type = to_node.type
541 node.type = to_node.type 550 node.type = to_node.type
...@@ -550,7 +559,7 @@ class TypeCheckVisitor(Visitor): ...@@ -550,7 +559,7 @@ class TypeCheckVisitor(Visitor):
550 node.expr.accept(self) 559 node.expr.accept(self)
551 return_type = self.curr_func.type.get_return_type() 560 return_type = self.curr_func.type.get_return_type()
552 self._coerce_const(node.expr, return_type) 561 self._coerce_const(node.expr, return_type)
553 - self._compare_types("Return expression", node.expr.type, return_type) 562 + self._compare_types("Return expression", node.expr.type, return_type, node=node)
554 node.expr.coerce_to_type = return_type 563 node.expr.coerce_to_type = return_type
555 564
556 def vArrayExpression(self, node): 565 def vArrayExpression(self, node):
...@@ -579,7 +588,8 @@ class TypeCheckVisitor(Visitor): ...@@ -579,7 +588,8 @@ class TypeCheckVisitor(Visitor):
579 self.error("Too few arguments passed to function.") 588 self.error("Too few arguments passed to function.")
580 for arg, param in zip(node.arglist.nodes, params.nodes): 589 for arg, param in zip(node.arglist.nodes, params.nodes):
581 self._coerce_const(arg, param.type) 590 self._coerce_const(arg, param.type)
582 - self._compare_types("Function call argument", arg.type, param.type) 591 + self._compare_types("Function call argument", arg.type, param.type,
592 + node=node)
583 arg.coerce_to_type = param.type 593 arg.coerce_to_type = param.type
584 # If this function takes a variable number of args and 594 # If this function takes a variable number of args and
585 # we've got more args than required parameters, we need 595 # we've got more args than required parameters, we need
......
...@@ -1118,8 +1118,8 @@ def compile (path) : ...@@ -1118,8 +1118,8 @@ def compile (path) :
1118 tgt = os.path.splitext(path)[0] 1118 tgt = os.path.splitext(path)[0]
1119 return tgt, ["gcc", "-m32", "-o", tgt, path] 1119 return tgt, ["gcc", "-m32", "-o", tgt, path]
1120 1120
1121 -def cpp (args, path) : 1121 +def cpp (args) :
1122 if args.test : 1122 if args.test :
1123 - return ["cpp", "-D", "CC", path] 1123 + return ["-DCC"]
1124 else : 1124 else :
1125 - return ["cpp", path] 1125 + return []
......
1 import argparse, sys, os, os.path, subprocess 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, cpp
5 5
6 ARCH = {"x86" : cx86, 6 ARCH = {"x86" : cx86,
7 "ttc" : cttc} 7 "ttc" : cttc}
...@@ -19,15 +19,17 @@ class Compiler (object) : ...@@ -19,15 +19,17 @@ 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, test) : 22 + def __init__ (self, arch, path, lmap, test) :
23 self.arch = arch 23 self.arch = arch
24 self.path = path 24 self.path = path
25 + self.lmap = lmap
25 self.test = test 26 self.test = test
26 self.total_errors = 0 27 self.total_errors = 0
27 self.total_warnings = 0 28 self.total_warnings = 0
28 def _parse (self) : 29 def _parse (self) :
29 "Parses the source code." 30 "Parses the source code."
30 cparse.inputfile = self.path 31 cparse.inputfile = self.path
32 + cparse.linenomap = self.lmap
31 self.ast = yacc.parse(self.code) 33 self.ast = yacc.parse(self.code)
32 def _compile_phase (self, visitor) : 34 def _compile_phase (self, visitor) :
33 "Applies a visitor to the abstract syntax tree." 35 "Applies a visitor to the abstract syntax tree."
...@@ -108,16 +110,14 @@ def main (args=None) : ...@@ -108,16 +110,14 @@ def main (args=None) :
108 ast_file = None 110 ast_file = None
109 if args.cpp : 111 if args.cpp :
110 print("Preprocessing %r" % src) 112 print("Preprocessing %r" % src)
111 - cpp = ARCH[args.arch].cpp(args, src) 113 + cppargs = ARCH[args.arch].cpp(args)
112 - print("..$ %s" % " ".join(cpp)) 114 + print("..$ cpp %s %s" % (" ".join(cppargs), src))
113 - code = "\n".join(l.rstrip() 115 + code, lmap = cpp.cpp(src, args.arch, cppargs)
114 - for l in subprocess.check_output(cpp).decode().splitlines()
115 - if not l.startswith("#"))
116 print("Compiling preprocessed %r" % src) 116 print("Compiling preprocessed %r" % src)
117 else : 117 else :
118 code = "\n".join(l.rstrip() for l in open(src).readlines()) 118 code = "\n".join(l.rstrip() for l in open(src).readlines())
119 print("Compiling %r" % src) 119 print("Compiling %r" % src)
120 - ret = Compiler(ARCH[args.arch], src, args.test).compile(code, ast_file) 120 + ret = Compiler(ARCH[args.arch], src, lmap, args.test).compile(code, ast_file)
121 if ast_file is not None : 121 if ast_file is not None :
122 ast_file.close() 122 ast_file.close()
123 if ret is None : 123 if ret is None :
......
1 +putc:
2 + set R8 3 # Point R8 towards argument c
3 + add R8 SP R8 # ... located as SP+3
4 + ld R8 R8 # Load argument c
5 + set R9 1012 # Put command for screen
6 + bus R9 R8 R8 # Write char to screen
7 + set R0 1 # Set return value
8 + ret
1 +#ifdef __CCT__
2 +extern int putc(char c);
3 +#define neg(i) -i
4 +#define UINT(i) i
5 +#define _DIGITS "0123456789ABCDEF"
6 +#define _STR "65536"
7 +#else
8 +extern int putchar(int c);
9 +#define putc(c) putchar(c)
10 +#define neg(i) ~i + 1
11 +#define UINT(i) (unsigned int)(i)
12 +#define _DIGITS _digits
13 +char _digits[17] = "0123456789ABCDEF";
14 +#define _STR _str
15 +char _str[6] = "65536";
16 +#endif
17 +
18 +int puts(char *s) {
19 + int n;
20 + int i;
21 + n = 0;
22 + i = 0;
23 + while (1) {
24 + if (s[i]) {
25 + n += putc(s[i]);
26 + i += 1;
27 + } else {
28 + break;
29 + }
30 + }
31 + return n;
32 +}
33 +
34 +#define ICHAR 105
35 +#define SCHAR 115
36 +#define UCHAR 117
37 +#define XCHAR 120
38 +#define PERCENT 37
39 +#define MINUS 45
40 +
41 +int putu(int u, char f) {
42 + char *DIGITS;
43 + char *str;
44 + int div;
45 + int r;
46 + int n;
47 + int p;
48 + DIGITS = _DIGITS;
49 + str = _STR;
50 + n = 0;
51 + p = 0;
52 + if (f == XCHAR) {
53 + div = 16;
54 + } else {
55 + div = 10;
56 + }
57 + while (u) {
58 + r = u % div;
59 + str[p] = DIGITS[r];
60 + p += 1;
61 + u = u / div;
62 + }
63 + p -= 1;
64 + while (p >= 0) {
65 + n += putc(str[p]);
66 + p -= 1;
67 + }
68 + return n;
69 +}
70 +
71 +int puti(int i) {
72 + int n;
73 + int s;
74 + int r;
75 + n = 0;
76 + if (UINT(i) > 32767) {
77 + n += putc(MINUS);
78 + n += putu(neg(i), UCHAR);
79 + return n;
80 + } else {
81 + return putu(i, UCHAR);
82 + }
83 +}
84 +
85 +int printf(char *str, ...) {
86 + int n;
87 + int i;
88 + int a;
89 + int *iargs;
90 + char **cargs;
91 + iargs = &str;
92 + cargs = &str;
93 + a = 1;
94 + n = 0;
95 + i = 0;
96 + while (1) {
97 + if (str[i] == 0) {
98 + break;
99 + } else if (str[i] == PERCENT) {
100 + i += 1;
101 + if (str[i] == ICHAR) {
102 + n += puti(iargs[a]);
103 + } else if (str[i] == UCHAR) {
104 + n += putu(iargs[a], UCHAR);
105 + } else if (str[i] == SCHAR) {
106 + n += puts(cargs[a]);
107 + } else if (str[i] == XCHAR) {
108 + n += putu(iargs[a], XCHAR);
109 + } else if (str[i] == PERCENT) {
110 + n += putc(PERCENT);
111 + i += 1;
112 + continue;
113 + } else {
114 + n += putc(PERCENT);
115 + n += putc(str[i]);
116 + }
117 + a += 1;
118 + } else {
119 + n += putc(str[i]);
120 + }
121 + i += 1;
122 + }
123 + return n;
124 +}
125 +
126 +int main() {
127 + puts("hello world\n");
128 + puti(42);
129 + puts(" => 42\n");
130 + puti(-42);
131 + puts(" => -42\n");
132 + putu(42, XCHAR);
133 + puts(" => 2A\n");
134 + putu(42, UCHAR);
135 + puts(" => 42\n");
136 + printf("hello %s I'm %u (%x)\n", "stdio", 42, 42);
137 + return 0;
138 +}
1 +extern int printf(char *str, ...);
2 +extern int puts(char *s);
3 +extern int putc(char c);
4 +extern int puti(int i);