git @ Cat's Eye Technologies SixtyPical / 6744ad2
Beginnings of modularity. Chris Pressey 3 years ago
5 changed file(s) with 99 addition(s) and 38 deletion(s). Raw diff Collapse all Expand all
8383 * Tests, and implementation, ensuring a routine can be assigned to a vector of "wider" type
8484 * Related: can we simply view a (small) part of a buffer as a byte table? If not, why not?
8585 * Related: add constant to buffer to get new buffer. (Or to table, but... well, maybe.)
86 * Check that the buffer being read or written to through pointer, appears in approporiate inputs or outputs set.
86 * Check that the buffer being read or written to through pointer, appears in appropriate inputs or outputs set.
8787 (Associate each pointer with the buffer it points into.)
8888 * `static` pointers -- currently not possible because pointers must be zero-page, thus `@`, thus uninitialized.
8989 * Question the value of the "consistent initialization" principle for `if` statement analysis.
9393 * Possibly `ld x, [ptr] + y`, possibly `st x, [ptr] + y`.
9494 * Maybe even `copy [ptra] + y, [ptrb] + y`, which can be compiled to indirect LDA then indirect STA!
9595 * Optimize `ld a, z` and `st a, z` to zero-page operations if address of z < 256.
96 * Include files?
9796
9897 [VICE]: http://vice-emu.sourceforge.net/
1717 import sys
1818 import traceback
1919
20 from sixtypical.parser import Parser
20 from sixtypical.parser import Parser, ParsingContext
2121 from sixtypical.analyzer import Analyzer
2222 from sixtypical.emitter import Emitter, Byte, Word
2323 from sixtypical.compiler import Compiler
2424
2525
26 def merge_programs(programs):
27 """Assumes that the programs do not have any conflicts."""
28
29 from sixtypical.ast import Program
30
31 full = Program(1, defns=[], routines=[])
32 for p in programs:
33 full.defns.extend(p.defns)
34 full.routines.extend(p.routines)
35
36 return full
37
38
2639 def process_input_files(filenames, options):
40 context = ParsingContext()
41
2742 programs = []
2843
2944 for filename in options.filenames:
3045 text = open(filename).read()
31 parser = Parser(text, filename)
46 parser = Parser(context, text, filename)
47 if options.debug:
48 print(context)
3249 program = parser.program()
3350 programs.append(program)
3451
3552 if options.parse_only:
3653 return
3754
38 #program = merge_programs(programs)
39 program = programs[0]
55 program = merge_programs(programs)
4056
4157 analyzer = Analyzer(debug=options.debug)
4258 analyzer.analyze_program(program)
0 routine chrout
1 inputs a
2 trashes a
3 @ 65490
4
5 routine printa
6 trashes a, z, n
7 {
8 ld a, 65
9 call chrout
10 }
11
12 routine printb
13 trashes a, z, n
14 {
15 ld a, 66
16 call chrout
17 }
0 vector routine
1 trashes a, z, n
2 print
3
4 // routine printb
5 // trashes a, z, n
6 // {
7 // ld a, 66
8 // call chrout
9 // }
10
11 routine main
12 trashes print, a, z, n
13 {
14 copy printa, print
15 call print
16 copy printb, print
17 call print
18 }
1717 return "%s(%r, %r)" % (self.__class__.__name__, self.ast_node, self.model)
1818
1919
20 class Parser(object):
21 def __init__(self, text, filename):
22 self.scanner = Scanner(text, filename)
20 class ParsingContext(object):
21 def __init__(self):
2322 self.symbols = {} # token -> SymEntry
24 self.current_statics = {} # token -> SymEntry
23 self.statics = {} # token -> SymEntry
2524 self.typedefs = {} # token -> Type AST
2625 self.consts = {} # token -> Loc
26
2727 for token in ('a', 'x', 'y'):
2828 self.symbols[token] = SymEntry(None, LocationRef(TYPE_BYTE, token))
2929 for token in ('c', 'z', 'n', 'v'):
3030 self.symbols[token] = SymEntry(None, LocationRef(TYPE_BIT, token))
31
32 def __str__(self):
33 return "Symbols: {}\nStatics: {}\nTypedefs: {}\nConsts: {}".format(self.symbols, self.statics, self.typedefs, self.consts)
34
35
36 class Parser(object):
37 def __init__(self, context, text, filename):
38 self.context = context
39 self.scanner = Scanner(text, filename)
3140 self.backpatch_instrs = []
3241
3342 def syntax_error(self, msg):
3443 self.scanner.syntax_error(msg)
3544
3645 def soft_lookup(self, name):
37 if name in self.current_statics:
38 return self.current_statics[name].model
39 if name in self.symbols:
40 return self.symbols[name].model
46 if name in self.context.statics:
47 return self.context.statics[name].model
48 if name in self.context.symbols:
49 return self.context.symbols[name].model
4150 return None
4251
4352 def lookup(self, name):
5766 if self.scanner.on('const'):
5867 self.defn_const()
5968 typenames = ['byte', 'word', 'table', 'vector', 'buffer', 'pointer'] # 'routine',
60 typenames.extend(self.typedefs.keys())
69 typenames.extend(self.context.typedefs.keys())
6170 while self.scanner.on(*typenames):
6271 defn = self.defn()
6372 name = defn.name
64 if name in self.symbols:
73 if name in self.context.symbols:
6574 self.syntax_error('Symbol "%s" already declared' % name)
66 self.symbols[name] = SymEntry(defn, defn.location)
75 self.context.symbols[name] = SymEntry(defn, defn.location)
6776 defns.append(defn)
6877 while self.scanner.on('define', 'routine'):
6978 if self.scanner.consume('define'):
7382 else:
7483 routine = self.legacy_routine()
7584 name = routine.name
76 if name in self.symbols:
85 if name in self.context.symbols:
7786 self.syntax_error('Symbol "%s" already declared' % name)
78 self.symbols[name] = SymEntry(routine, routine.location)
87 self.context.symbols[name] = SymEntry(routine, routine.location)
7988 routines.append(routine)
8089 self.scanner.check_type('EOF')
8190
8291 # now backpatch the executable types.
83 #for type_name, type_ in self.typedefs.iteritems():
92 #for type_name, type_ in self.context.typedefs.iteritems():
8493 # type_.backpatch_constraint_labels(lambda w: self.lookup(w))
8594 for defn in defns:
8695 defn.location.type.backpatch_constraint_labels(lambda w: self.lookup(w))
8998 for instr in self.backpatch_instrs:
9099 if instr.opcode in ('call', 'goto'):
91100 name = instr.location
92 if name not in self.symbols:
101 if name not in self.context.symbols:
93102 self.syntax_error('Undefined routine "%s"' % name)
94 if not isinstance(self.symbols[name].model.type, (RoutineType, VectorType)):
103 if not isinstance(self.context.symbols[name].model.type, (RoutineType, VectorType)):
95104 self.syntax_error('Illegal call of non-executable "%s"' % name)
96 instr.location = self.symbols[name].model
105 instr.location = self.context.symbols[name].model
97106 if instr.opcode in ('copy',) and isinstance(instr.src, basestring):
98107 name = instr.src
99 if name not in self.symbols:
108 if name not in self.context.symbols:
100109 self.syntax_error('Undefined routine "%s"' % name)
101 if not isinstance(self.symbols[name].model.type, (RoutineType, VectorType)):
110 if not isinstance(self.context.symbols[name].model.type, (RoutineType, VectorType)):
102111 self.syntax_error('Illegal copy of non-executable "%s"' % name)
103 instr.src = self.symbols[name].model
112 instr.src = self.context.symbols[name].model
104113
105114 return Program(self.scanner.line_number, defns=defns, routines=routines)
106115
108117 self.scanner.expect('typedef')
109118 type_ = self.defn_type()
110119 name = self.defn_name()
111 if name in self.typedefs:
120 if name in self.context.typedefs:
112121 self.syntax_error('Type "%s" already declared' % name)
113 self.typedefs[name] = type_
122 self.context.typedefs[name] = type_
114123 return type_
115124
116125 def defn_const(self):
117126 self.scanner.expect('const')
118127 name = self.defn_name()
119 if name in self.consts:
128 if name in self.context.consts:
120129 self.syntax_error('Const "%s" already declared' % name)
121130 loc = self.const()
122 self.consts[name] = loc
131 self.context.consts[name] = loc
123132 return loc
124133
125134 def defn(self):
162171 loc = ConstantRef(TYPE_WORD, int(self.scanner.token))
163172 self.scanner.scan()
164173 return loc
165 elif self.scanner.token in self.consts:
166 loc = self.consts[self.scanner.token]
174 elif self.scanner.token in self.context.consts:
175 loc = self.context.consts[self.scanner.token]
167176 self.scanner.scan()
168177 return loc
169178 else:
214223 else:
215224 type_name = self.scanner.token
216225 self.scanner.scan()
217 if type_name not in self.typedefs:
226 if type_name not in self.context.typedefs:
218227 self.syntax_error("Undefined type '%s'" % type_name)
219 type_ = self.typedefs[type_name]
228 type_ = self.context.typedefs[type_name]
220229
221230 return type_
222231
272281 else:
273282 statics = self.statics()
274283
275 self.current_statics = self.compose_statics_dict(statics)
284 self.context.statics = self.compose_statics_dict(statics)
276285 block = self.block()
277 self.current_statics = {}
286 self.context.statics = {}
278287
279288 addr = None
280289 location = LocationRef(type_, name)
288297 c = {}
289298 for defn in statics:
290299 name = defn.name
291 if name in self.symbols or name in self.current_statics:
300 if name in self.context.symbols or name in self.context.statics:
292301 self.syntax_error('Symbol "%s" already declared' % name)
293302 c[name] = SymEntry(defn, defn.location)
294303 return c
315324 return accum
316325
317326 def locexpr(self, forward=False):
318 if self.scanner.token in ('on', 'off', 'word') or self.scanner.token in self.consts or self.scanner.on_type('integer literal'):
327 if self.scanner.token in ('on', 'off', 'word') or self.scanner.token in self.context.consts or self.scanner.on_type('integer literal'):
319328 return self.const()
320329 elif forward:
321330 name = self.scanner.token