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:
@@ -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())
|
||||
|
||||
|
@@ -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):
|
||||
|
@@ -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"""
|
||||
|
@@ -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
|
||||
|
Reference in New Issue
Block a user