1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2025-08-09 15:25:01 +00:00

Distinct AST nodes for call and goto instructions.

This commit is contained in:
Chris Pressey
2019-04-08 16:26:51 +01:00
parent bd462d6d8b
commit 4615d8d054
4 changed files with 126 additions and 101 deletions

View File

@@ -1,7 +1,7 @@
# encoding: UTF-8
from sixtypical.ast import (
Program, Routine, Block, SingleOp, If, Repeat, For, WithInterruptsOff, Save, PointInto
Program, Routine, Block, SingleOp, Call, GoTo, If, Repeat, For, WithInterruptsOff, Save, PointInto
)
from sixtypical.model import (
TYPE_BYTE, TYPE_WORD,
@@ -493,6 +493,10 @@ class Analyzer(object):
def analyze_instr(self, instr, context):
if isinstance(instr, SingleOp):
self.analyze_single_op(instr, context)
elif isinstance(instr, Call):
self.analyze_call(instr, context)
elif isinstance(instr, GoTo):
self.analyze_goto(instr, context)
elif isinstance(instr, If):
self.analyze_if(instr, context)
elif isinstance(instr, Repeat):
@@ -667,20 +671,6 @@ class Analyzer(object):
self.assert_type(TYPE_BYTE, dest)
context.set_written(dest, FLAG_Z, FLAG_N, FLAG_C)
context.invalidate_range(dest)
elif opcode == 'call':
type = instr.location.type
if not isinstance(type, (RoutineType, VectorType)):
raise TypeMismatchError(instr, instr.location)
if isinstance(type, VectorType):
type = type.of_type
for ref in type.inputs:
context.assert_meaningful(ref)
for ref in type.outputs:
context.set_written(ref)
for ref in type.trashes:
context.assert_writeable(ref)
context.set_touched(ref)
context.set_unmeaningful(ref)
elif opcode == 'copy':
if dest == REG_A:
raise ForbiddenWriteError(instr, "{} cannot be used as destination for copy".format(dest))
@@ -789,7 +779,31 @@ class Analyzer(object):
context.set_touched(REG_A, FLAG_Z, FLAG_N)
context.set_unmeaningful(REG_A, FLAG_Z, FLAG_N)
elif opcode == 'goto':
elif opcode == 'trash':
context.set_touched(instr.dest)
context.set_unmeaningful(instr.dest)
elif opcode == 'nop':
pass
else:
raise NotImplementedError(opcode)
def analyze_call(self, instr, context):
type = instr.location.type
if not isinstance(type, (RoutineType, VectorType)):
raise TypeMismatchError(instr, instr.location)
if isinstance(type, VectorType):
type = type.of_type
for ref in type.inputs:
context.assert_meaningful(ref)
for ref in type.outputs:
context.set_written(ref)
for ref in type.trashes:
context.assert_writeable(ref)
context.set_touched(ref)
context.set_unmeaningful(ref)
def analyze_goto(self, instr, context):
location = instr.location
type_ = location.type
@@ -843,14 +857,6 @@ class Analyzer(object):
context.set_terminated()
elif opcode == 'trash':
context.set_touched(instr.dest)
context.set_unmeaningful(instr.dest)
elif opcode == 'nop':
pass
else:
raise NotImplementedError(opcode)
def analyze_if(self, instr, context):
incoming_meaningful = set(context.each_meaningful())

View File

@@ -72,7 +72,15 @@ class Instr(AST):
class SingleOp(Instr):
value_attrs = ('opcode', 'dest', 'src', 'location',)
value_attrs = ('opcode', 'dest', 'src',)
class Call(Instr):
value_attrs = ('location',)
class GoTo(Instr):
value_attrs = ('location',)
class If(Instr):

View File

@@ -1,7 +1,7 @@
# encoding: UTF-8
from sixtypical.ast import (
Program, Routine, Block, SingleOp, If, Repeat, For, WithInterruptsOff, Save, PointInto
Program, Routine, Block, SingleOp, Call, GoTo, If, Repeat, For, WithInterruptsOff, Save, PointInto
)
from sixtypical.model import (
ConstantRef, LocationRef, IndexedRef, IndirectRef,
@@ -162,6 +162,10 @@ class Compiler(object):
def compile_instr(self, instr):
if isinstance(instr, SingleOp):
return self.compile_single_op(instr)
elif isinstance(instr, Call):
return self.compile_call(instr)
elif isinstance(instr, GoTo):
return self.compile_goto(instr)
elif isinstance(instr, If):
return self.compile_if(instr)
elif isinstance(instr, Repeat):
@@ -393,7 +397,16 @@ class Compiler(object):
self.emitter.emit(cls(mode(Offset(self.get_label(dest.ref.name), dest.offset.value))))
else:
self.emitter.emit(cls(self.absolute_or_zero_page(self.get_label(dest.name))))
elif opcode == 'call':
elif opcode == 'copy':
self.compile_copy(instr, instr.src, instr.dest)
elif opcode == 'trash':
pass
elif opcode == 'nop':
self.emitter.emit(NOP())
else:
raise NotImplementedError(opcode)
def compile_call(self, instr):
location = instr.location
label = self.get_label(instr.location.name)
if isinstance(location.type, RoutineType):
@@ -405,7 +418,8 @@ class Compiler(object):
self.emitter.emit(JSR(Absolute(trampoline)))
else:
raise NotImplementedError
elif opcode == 'goto':
def compile_goto(self, instr):
self.final_goto_seen = True
if self.skip_final_goto:
pass
@@ -418,14 +432,6 @@ class Compiler(object):
self.emitter.emit(JMP(Indirect(label)))
else:
raise NotImplementedError
elif opcode == 'copy':
self.compile_copy(instr, instr.src, instr.dest)
elif opcode == 'trash':
pass
elif opcode == 'nop':
self.emitter.emit(NOP())
else:
raise NotImplementedError(opcode)
def compile_cmp(self, instr, src, dest):
"""`instr` is only for reporting purposes"""

View File

@@ -1,7 +1,7 @@
# encoding: UTF-8
from sixtypical.ast import (
Program, Defn, Routine, Block, SingleOp, If, Repeat, For, WithInterruptsOff, Save, PointInto
Program, Defn, Routine, Block, SingleOp, Call, GoTo, If, Repeat, For, WithInterruptsOff, Save, PointInto
)
from sixtypical.model import (
TYPE_BIT, TYPE_BYTE, TYPE_WORD,
@@ -113,6 +113,8 @@ class Parser(object):
resolve_fwd_reference(node, 'location')
resolve_fwd_reference(node, 'src')
resolve_fwd_reference(node, 'dest')
if isinstance(node, (Call, GoTo)):
resolve_fwd_reference(node, 'location')
# --- grammar productions
@@ -380,7 +382,7 @@ class Parser(object):
self.scanner.expect('{')
while not self.scanner.on('}'):
instrs.append(self.instr())
if isinstance(instrs[-1], SingleOp) and instrs[-1].opcode == 'goto':
if isinstance(instrs[-1], GoTo):
break
self.scanner.expect('}')
return Block(self.scanner.line_number, instrs=instrs)
@@ -450,12 +452,15 @@ class Parser(object):
opcode = self.scanner.token
self.scanner.scan()
return SingleOp(self.scanner.line_number, opcode=opcode, dest=None, src=None)
elif self.scanner.token in ("call", "goto"):
opcode = self.scanner.token
self.scanner.scan()
elif self.scanner.consume("call"):
name = self.scanner.token
self.scanner.scan()
instr = SingleOp(self.scanner.line_number, opcode=opcode, location=ForwardReference(name), dest=None, src=None)
instr = Call(self.scanner.line_number, location=ForwardReference(name))
return instr
elif self.scanner.consume("goto"):
name = self.scanner.token
self.scanner.scan()
instr = GoTo(self.scanner.line_number, location=ForwardReference(name))
return instr
elif self.scanner.token in ("copy",):
opcode = self.scanner.token