mirror of
https://github.com/catseye/SixtyPical.git
synced 2024-11-22 01:32:13 +00:00
Compiler object, labels, compile 'call'... It prints 'A'!
This commit is contained in:
parent
2ffff3bbdb
commit
643a48a2c5
@ -33,9 +33,7 @@ TODO
|
||||
|
||||
For 0.3:
|
||||
|
||||
* extern routines.
|
||||
* generate 6502 code for all SixtyPical instructions.
|
||||
* a little demo that actually compiles and does something on a C64 emulator.
|
||||
|
||||
For 0.4:
|
||||
|
||||
|
@ -21,7 +21,7 @@ from sixtypical.parser import Parser
|
||||
from sixtypical.evaluator import eval_program
|
||||
from sixtypical.analyzer import analyze_program
|
||||
from sixtypical.emitter import Emitter, Byte, Word
|
||||
from sixtypical.compiler import compile_program
|
||||
from sixtypical.compiler import Compiler
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
@ -75,7 +75,8 @@ if __name__ == '__main__':
|
||||
emitter.emit(Word(start_addr))
|
||||
for byte in header:
|
||||
emitter.emit(Byte(byte))
|
||||
compile_program(program, emitter)
|
||||
compiler = Compiler(emitter)
|
||||
compiler.compile_program(program)
|
||||
if options.debug:
|
||||
print repr(emitter.accum)
|
||||
else:
|
||||
|
12
eg/print.60p
Normal file
12
eg/print.60p
Normal file
@ -0,0 +1,12 @@
|
||||
routine chrout
|
||||
inputs a
|
||||
trashes a
|
||||
@ 65490
|
||||
|
||||
routine main
|
||||
inputs a
|
||||
trashes a, z, n
|
||||
{
|
||||
ld a, 65
|
||||
call chrout
|
||||
}
|
@ -5,10 +5,10 @@ from sixtypical.model import (
|
||||
ConstantRef, LocationRef,
|
||||
REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C
|
||||
)
|
||||
from sixtypical.emitter import Byte
|
||||
from sixtypical.emitter import Label, Byte
|
||||
from sixtypical.gen6502 import (
|
||||
Immediate, Absolute,
|
||||
LDA, LDX, LDY, STA, STX, STY, CLC, SEC, ADC, RTS
|
||||
LDA, LDX, LDY, STA, STX, STY, CLC, SEC, ADC, RTS, JSR
|
||||
)
|
||||
|
||||
|
||||
@ -16,90 +16,97 @@ class UnsupportedOpcodeError(KeyError):
|
||||
pass
|
||||
|
||||
|
||||
def compile_program(program, emitter):
|
||||
assert isinstance(program, Program)
|
||||
routines = {r.name: r for r in program.routines}
|
||||
for routine in program.routines:
|
||||
compile_routine(routine, emitter, routines)
|
||||
class Compiler(object):
|
||||
def __init__(self, emitter):
|
||||
self.emitter = emitter
|
||||
self.routines = {}
|
||||
self.labels = {}
|
||||
|
||||
def compile_program(self, program):
|
||||
assert isinstance(program, Program)
|
||||
for routine in program.routines:
|
||||
self.routines[routine.name] = routine
|
||||
label = Label(routine.name)
|
||||
if routine.addr is not None:
|
||||
label.set_addr(routine.addr)
|
||||
self.labels[routine.name] = label
|
||||
for routine in program.routines:
|
||||
self.compile_routine(routine)
|
||||
|
||||
def compile_routine(routine, emitter, routines):
|
||||
assert isinstance(routine, Routine)
|
||||
label = emitter.make_label(routine.name)
|
||||
if routine.block:
|
||||
compile_block(routine.block, emitter, routines)
|
||||
emitter.emit(RTS())
|
||||
return label
|
||||
def compile_routine(self, routine):
|
||||
assert isinstance(routine, Routine)
|
||||
if routine.block:
|
||||
self.compile_block(routine.block)
|
||||
self.emitter.emit(RTS())
|
||||
|
||||
def compile_block(self, block):
|
||||
assert isinstance(block, Block)
|
||||
label = self.emitter.make_label()
|
||||
for instr in block.instrs:
|
||||
self.compile_instr(instr)
|
||||
return label
|
||||
|
||||
def compile_block(block, emitter, routines):
|
||||
assert isinstance(block, Block)
|
||||
label = emitter.make_label()
|
||||
for instr in block.instrs:
|
||||
compile_instr(instr, emitter, routines)
|
||||
return label
|
||||
|
||||
|
||||
def compile_instr(instr, emitter, routines):
|
||||
assert isinstance(instr, Instr)
|
||||
opcode = instr.opcode
|
||||
dest = instr.dest
|
||||
src = instr.src
|
||||
|
||||
if opcode == 'ld':
|
||||
if dest == REG_A:
|
||||
if isinstance(src, ConstantRef):
|
||||
emitter.emit(LDA(Immediate(Byte(src.value))))
|
||||
def compile_instr(self, instr):
|
||||
assert isinstance(instr, Instr)
|
||||
opcode = instr.opcode
|
||||
dest = instr.dest
|
||||
src = instr.src
|
||||
|
||||
if opcode == 'ld':
|
||||
if dest == REG_A:
|
||||
if isinstance(src, ConstantRef):
|
||||
self.emitter.emit(LDA(Immediate(Byte(src.value))))
|
||||
else:
|
||||
self.emitter.emit(LDA(Absolute(src.label)))
|
||||
elif dest == REG_X:
|
||||
pass
|
||||
elif dest == REG_Y:
|
||||
pass
|
||||
else:
|
||||
emitter.emit(LDA(Absolute(src.label)))
|
||||
elif dest == REG_X:
|
||||
pass
|
||||
elif dest == REG_Y:
|
||||
pass
|
||||
else:
|
||||
raise UnsupportedOpcodeError(instr)
|
||||
elif opcode == 'st':
|
||||
if dest == FLAG_C and src == ConstantRef(0):
|
||||
emitter.emit(CLC())
|
||||
elif dest == FLAG_C and src == ConstantRef(1):
|
||||
emitter.emit(SEC())
|
||||
elif src == REG_A:
|
||||
emitter.emit(STA(Absolute(dest.label)))
|
||||
elif src == REG_X:
|
||||
emitter.emit(STX(Absolute(dest.label)))
|
||||
elif src == REG_Y:
|
||||
emitter.emit(STY(Absolute(dest.label)))
|
||||
else:
|
||||
raise UnsupportedOpcodeError(instr)
|
||||
elif opcode == 'add':
|
||||
if dest == REG_A:
|
||||
if isinstance(src, ConstantRef):
|
||||
emitter.emit(ADC(Immediate(Byte(src.value))))
|
||||
raise UnsupportedOpcodeError(instr)
|
||||
elif opcode == 'st':
|
||||
if dest == FLAG_C and src == ConstantRef(0):
|
||||
self.emitter.emit(CLC())
|
||||
elif dest == FLAG_C and src == ConstantRef(1):
|
||||
self.emitter.emit(SEC())
|
||||
elif src == REG_A:
|
||||
self.emitter.emit(STA(Absolute(dest.label)))
|
||||
elif src == REG_X:
|
||||
self.emitter.emit(STX(Absolute(dest.label)))
|
||||
elif src == REG_Y:
|
||||
self.emitter.emit(STY(Absolute(dest.label)))
|
||||
else:
|
||||
emitter.emit(ADC(Absolute(src.label)))
|
||||
raise UnsupportedOpcodeError(instr)
|
||||
elif opcode == 'add':
|
||||
if dest == REG_A:
|
||||
if isinstance(src, ConstantRef):
|
||||
self.emitter.emit(ADC(Immediate(Byte(src.value))))
|
||||
else:
|
||||
self.emitter.emit(ADC(Absolute(src.label)))
|
||||
else:
|
||||
raise UnsupportedOpcodeError(instr)
|
||||
elif opcode == 'sub':
|
||||
raise NotImplementedError
|
||||
elif opcode == 'inc':
|
||||
raise NotImplementedError
|
||||
elif opcode == 'dec':
|
||||
raise NotImplementedError
|
||||
elif opcode == 'cmp':
|
||||
raise NotImplementedError
|
||||
elif opcode == 'and':
|
||||
raise NotImplementedError
|
||||
elif opcode == 'or':
|
||||
raise NotImplementedError
|
||||
elif opcode == 'xor':
|
||||
raise NotImplementedError
|
||||
elif opcode == 'shl':
|
||||
raise NotImplementedError
|
||||
elif opcode == 'shr':
|
||||
raise NotImplementedError
|
||||
elif opcode == 'call':
|
||||
label = self.labels[instr.name]
|
||||
self.emitter.emit(JSR(Absolute(label)))
|
||||
elif opcode == 'if':
|
||||
raise NotImplementedError
|
||||
else:
|
||||
raise UnsupportedOpcodeError(instr)
|
||||
elif opcode == 'sub':
|
||||
raise NotImplementedError
|
||||
elif opcode == 'inc':
|
||||
raise NotImplementedError
|
||||
elif opcode == 'dec':
|
||||
raise NotImplementedError
|
||||
elif opcode == 'cmp':
|
||||
raise NotImplementedError
|
||||
elif opcode == 'and':
|
||||
raise NotImplementedError
|
||||
elif opcode == 'or':
|
||||
raise NotImplementedError
|
||||
elif opcode == 'xor':
|
||||
raise NotImplementedError
|
||||
elif opcode == 'shl':
|
||||
raise NotImplementedError
|
||||
elif opcode == 'shr':
|
||||
raise NotImplementedError
|
||||
elif opcode == 'call':
|
||||
raise NotImplementedError(instr.name)
|
||||
elif opcode == 'if':
|
||||
raise NotImplementedError
|
||||
else:
|
||||
raise NotImplementedError
|
||||
raise NotImplementedError
|
||||
|
@ -58,6 +58,10 @@ class Label(Emittable):
|
||||
assert self.addr is not None, "unresolved label: %s" % self.name
|
||||
return Word(self.addr).serialize()
|
||||
|
||||
def __repr__(self):
|
||||
addrs = ', addr=%r' % self.addr if self.addr is not None else ''
|
||||
return "%s(%r%s)" % (self.__class__.__name__, self.name, addrs)
|
||||
|
||||
|
||||
class Emitter(object):
|
||||
def __init__(self, addr):
|
||||
|
@ -123,6 +123,12 @@ class INY(Opcode):
|
||||
}
|
||||
|
||||
|
||||
class JSR(Opcode):
|
||||
opcodes = {
|
||||
Absolute: 0x20,
|
||||
}
|
||||
|
||||
|
||||
class LDA(Opcode):
|
||||
opcodes = {
|
||||
Immediate: 0xa9,
|
||||
|
@ -44,4 +44,4 @@ Call extern.
|
||||
| ld a, 65
|
||||
| call chrout
|
||||
| }
|
||||
= 00c018690460
|
||||
= 00c0a94120d2ff60
|
||||
|
Loading…
Reference in New Issue
Block a user