git @ Cat's Eye Technologies SixtyPical / e44c802
Syntax errors have line numbers in them now. Chris Pressey 3 years ago
5 changed file(s) with 57 addition(s) and 39 deletion(s). Raw diff Collapse all Expand all
00 word one
1 word table many
1 word table[256] many
22
33 routine main
44 inputs one, many
44 child_attrs = ()
55 value_attrs = ()
66
7 def __init__(self, **kwargs):
7 def __init__(self, line_number, **kwargs):
8 self.line_number = line_number
89 self.attrs = {}
910 for attr in self.children_attrs:
1011 self.attrs[attr] = kwargs.pop(attr, [])
55 RoutineType, VectorType, TableType, BufferType, PointerType,
66 LocationRef, ConstantRef, IndirectRef, IndexedRef, AddressRef,
77 )
8 from sixtypical.scanner import Scanner
8 from sixtypical.scanner import Scanner, SixtyPicalSyntaxError
99
1010
1111 class SymEntry(object):
2929 self.symbols[token] = SymEntry(None, LocationRef(TYPE_BIT, token))
3030 self.backpatch_instrs = []
3131
32 def syntax_error(self, msg):
33 raise SixtyPicalSyntaxError(self.scanner.line_number, msg)
34
3235 def soft_lookup(self, name):
3336 if name in self.current_statics:
3437 return self.current_statics[name].model
3942 def lookup(self, name):
4043 model = self.soft_lookup(name)
4144 if model is None:
42 raise SyntaxError('Undefined symbol "%s"' % name)
45 self.syntax_error('Undefined symbol "{}"'.format(name))
4346 return model
4447
4548 # --- grammar productions
5558 defn = self.defn()
5659 name = defn.name
5760 if name in self.symbols:
58 raise SyntaxError('Symbol "%s" already declared' % name)
61 self.syntax_error('Symbol "%s" already declared' % name)
5962 self.symbols[name] = SymEntry(defn, defn.location)
6063 defns.append(defn)
6164 while self.scanner.on('define', 'routine'):
6770 routine = self.legacy_routine()
6871 name = routine.name
6972 if name in self.symbols:
70 raise SyntaxError('Symbol "%s" already declared' % name)
73 self.syntax_error('Symbol "%s" already declared' % name)
7174 self.symbols[name] = SymEntry(routine, routine.location)
7275 routines.append(routine)
7376 self.scanner.check_type('EOF')
8386 if instr.opcode in ('call', 'goto'):
8487 name = instr.location
8588 if name not in self.symbols:
86 raise SyntaxError('Undefined routine "%s"' % name)
89 self.syntax_error('Undefined routine "%s"' % name)
8790 if not isinstance(self.symbols[name].model.type, (RoutineType, VectorType)):
88 raise SyntaxError('Illegal call of non-executable "%s"' % name)
91 self.syntax_error('Illegal call of non-executable "%s"' % name)
8992 instr.location = self.symbols[name].model
9093 if instr.opcode in ('copy',) and isinstance(instr.src, basestring):
9194 name = instr.src
9295 if name not in self.symbols:
93 raise SyntaxError('Undefined routine "%s"' % name)
96 self.syntax_error('Undefined routine "%s"' % name)
9497 if not isinstance(self.symbols[name].model.type, (RoutineType, VectorType)):
95 raise SyntaxError('Illegal copy of non-executable "%s"' % name)
98 self.syntax_error('Illegal copy of non-executable "%s"' % name)
9699 instr.src = self.symbols[name].model
97100
98 return Program(defns=defns, routines=routines)
101 return Program(self.scanner.line_number, defns=defns, routines=routines)
99102
100103 def typedef(self):
101104 self.scanner.expect('typedef')
102105 type_ = self.defn_type()
103106 name = self.defn_name()
104107 if name in self.typedefs:
105 raise SyntaxError('Type "%s" already declared' % name)
108 self.syntax_error('Type "%s" already declared' % name)
106109 self.typedefs[name] = type_
107110 return type_
108111
126129 self.scanner.scan()
127130
128131 if initial is not None and addr is not None:
129 raise SyntaxError("Definition cannot have both initial value and explicit address")
132 self.syntax_error("Definition cannot have both initial value and explicit address")
130133
131134 location = LocationRef(type_, name)
132135
133 return Defn(name=name, addr=addr, initial=initial, location=location)
136 return Defn(self.scanner.line_number, name=name, addr=addr, initial=initial, location=location)
134137
135138 def defn_size(self):
136139 self.scanner.expect('[')
146149 if self.scanner.consume('table'):
147150 size = self.defn_size()
148151 if size <= 0 or size > 256:
149 raise SyntaxError("Table size must be > 0 and <= 256")
152 self.syntax_error("Table size must be > 0 and <= 256")
150153 type_ = TableType(type_, size)
151154
152155 return type_
166169 elif self.scanner.consume('vector'):
167170 type_ = self.defn_type_term()
168171 if not isinstance(type_, RoutineType):
169 raise SyntaxError("Vectors can only be of a routine, not %r" % type_)
172 self.syntax_error("Vectors can only be of a routine, not %r" % type_)
170173 type_ = VectorType(type_)
171174 elif self.scanner.consume('routine'):
172175 (inputs, outputs, trashes) = self.constraints()
180183 type_name = self.scanner.token
181184 self.scanner.scan()
182185 if type_name not in self.typedefs:
183 raise SyntaxError("Undefined type '%s'" % type_name)
186 self.syntax_error("Undefined type '%s'" % type_name)
184187 type_ = self.typedefs[type_name]
185188
186189 return type_
219222 addr = None
220223 location = LocationRef(type_, name)
221224 return Routine(
225 self.scanner.line_number,
222226 name=name, block=block, addr=addr,
223227 location=location
224228 )
226230 def routine(self, name):
227231 type_ = self.defn_type()
228232 if not isinstance(type_, RoutineType):
229 raise SyntaxError("Can only define a routine, not %r" % type_)
233 self.syntax_error("Can only define a routine, not %r" % type_)
230234 statics = []
231235 if self.scanner.consume('@'):
232236 self.scanner.check_type('integer literal')
243247 addr = None
244248 location = LocationRef(type_, name)
245249 return Routine(
250 self.scanner.line_number,
246251 name=name, block=block, addr=addr,
247252 location=location, statics=statics
248253 )
252257 for defn in statics:
253258 name = defn.name
254259 if name in self.symbols or name in self.current_statics:
255 raise SyntaxError('Symbol "%s" already declared' % name)
260 self.syntax_error('Symbol "%s" already declared' % name)
256261 c[name] = SymEntry(defn, defn.location)
257262 return c
258263
332337 while self.scanner.consume('static'):
333338 defn = self.defn()
334339 if defn.initial is None:
335 raise SyntaxError("Static definition {} must have initial value".format(defn))
340 self.syntax_error("Static definition {} must have initial value".format(defn))
336341 defns.append(defn)
337342 return defns
338343
342347 while not self.scanner.on('}'):
343348 instrs.append(self.instr())
344349 self.scanner.expect('}')
345 return Block(instrs=instrs)
350 return Block(self.scanner.line_number, instrs=instrs)
346351
347352 def instr(self):
348353 if self.scanner.consume('if'):
354359 block2 = None
355360 if self.scanner.consume('else'):
356361 block2 = self.block()
357 return If(src=src, block1=block1, block2=block2, inverted=inverted)
362 return If(self.scanner.line_number, src=src, block1=block1, block2=block2, inverted=inverted)
358363 elif self.scanner.consume('repeat'):
359364 inverted = False
360365 src = None
365370 src = self.locexpr()
366371 else:
367372 self.scanner.expect('forever')
368 return Repeat(src=src, block=block, inverted=inverted)
373 return Repeat(self.scanner.line_number, src=src, block=block, inverted=inverted)
369374 elif self.scanner.token in ("ld",):
370375 # the same as add, sub, cmp etc below, except supports an indlocexpr for the src
371376 opcode = self.scanner.token
373378 dest = self.locexpr()
374379 self.scanner.expect(',')
375380 src = self.indlocexpr()
376 return SingleOp(opcode=opcode, dest=dest, src=src)
381 return SingleOp(self.scanner.line_number, opcode=opcode, dest=dest, src=src)
377382 elif self.scanner.token in ("add", "sub", "cmp", "and", "or", "xor"):
378383 opcode = self.scanner.token
379384 self.scanner.scan()
380385 dest = self.locexpr()
381386 self.scanner.expect(',')
382387 src = self.indexed_locexpr()
383 return SingleOp(opcode=opcode, dest=dest, src=src)
388 return SingleOp(self.scanner.line_number, opcode=opcode, dest=dest, src=src)
384389 elif self.scanner.token in ("st",):
385390 opcode = self.scanner.token
386391 self.scanner.scan()
387392 src = self.locexpr()
388393 self.scanner.expect(',')
389394 dest = self.indlocexpr()
390 return SingleOp(opcode=opcode, dest=dest, src=src)
395 return SingleOp(self.scanner.line_number, opcode=opcode, dest=dest, src=src)
391396 elif self.scanner.token in ("shl", "shr", "inc", "dec"):
392397 opcode = self.scanner.token
393398 self.scanner.scan()
394399 dest = self.locexpr()
395 return SingleOp(opcode=opcode, dest=dest, src=None)
400 return SingleOp(self.scanner.line_number, opcode=opcode, dest=dest, src=None)
396401 elif self.scanner.token in ("call", "goto"):
397402 opcode = self.scanner.token
398403 self.scanner.scan()
399404 name = self.scanner.token
400405 self.scanner.scan()
401 instr = SingleOp(opcode=opcode, location=name, dest=None, src=None)
406 instr = SingleOp(self.scanner.line_number, opcode=opcode, location=name, dest=None, src=None)
402407 self.backpatch_instrs.append(instr)
403408 return instr
404409 elif self.scanner.token in ("copy",):
407412 src = self.indlocexpr(forward=True)
408413 self.scanner.expect(',')
409414 dest = self.indlocexpr()
410 instr = SingleOp(opcode=opcode, dest=dest, src=src)
415 instr = SingleOp(self.scanner.line_number, opcode=opcode, dest=dest, src=src)
411416 self.backpatch_instrs.append(instr)
412417 return instr
413418 elif self.scanner.consume("with"):
414419 self.scanner.expect("interrupts")
415420 self.scanner.expect("off")
416421 block = self.block()
417 return WithInterruptsOff(block=block)
422 return WithInterruptsOff(self.scanner.line_number, block=block)
418423 elif self.scanner.consume("trash"):
419424 dest = self.locexpr()
420 return SingleOp(opcode='trash', src=None, dest=dest)
421 else:
422 raise ValueError('bad opcode "%s"' % self.scanner.token)
425 return SingleOp(self.scanner.line_number, opcode='trash', src=None, dest=dest)
426 else:
427 self.syntax_error('bad opcode "%s"' % self.scanner.token)
00 # encoding: UTF-8
11
22 import re
3
4
5 class SixtyPicalSyntaxError(ValueError):
6 def __init__(self, line_number, message):
7 super(SixtyPicalSyntaxError, self).__init__(line_number, message)
8
9 def __str__(self):
10 return "Line {}: {}".format(self.args[0], self.args[1])
311
412
513 class Scanner(object):
715 self.text = text
816 self.token = None
917 self.type = None
18 self.line_number = 1
1019 self.scan()
1120
1221 def scan_pattern(self, pattern, type, token_group=1, rest_group=2):
1827 self.type = type
1928 self.token = match.group(token_group)
2029 self.text = match.group(rest_group)
30 self.line_number += self.token.count('\n')
2131 return True
2232
2333 def scan(self):
4555 if self.scan_pattern(r'.', 'unknown character'):
4656 return
4757 else:
48 raise AssertionError("this should never happen, self.text=(%s)" % self.text)
58 raise AssertionError("this should never happen, self.text=({})".format(self.text))
4959
5060 def expect(self, token):
5161 if self.token == token:
5262 self.scan()
5363 else:
54 raise SyntaxError("Expected '%s', but found '%s'" %
55 (token, self.token))
64 raise SixtyPicalSyntaxError(self.scanner.line_number, "Expected '{}', but found '{}'".format(
65 token, self.token
66 ))
5667
5768 def on(self, *tokens):
5869 return self.token in tokens
6273
6374 def check_type(self, type):
6475 if not self.type == type:
65 raise SyntaxError("Expected %s, but found %s ('%s')" %
66 (type, self.type, self.token))
76 raise SixtyPicalSyntaxError(self.scanner.line_number, "Expected {}, but found '{}'".format(
77 self.type, self.token
78 ))
6779
6880 def consume(self, token):
6981 if self.token == token:
23222322 | copy bar, many + x
23232323 | call many + x
23242324 | }
2325 ? ValueError
2325 ? SyntaxError
23262326
23272327 ### typedef ###
23282328