mirror of
https://github.com/catseye/SixtyPical.git
synced 2024-11-25 23:49:17 +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:
|
For 0.3:
|
||||||
|
|
||||||
* extern routines.
|
|
||||||
* generate 6502 code for all SixtyPical instructions.
|
* generate 6502 code for all SixtyPical instructions.
|
||||||
* a little demo that actually compiles and does something on a C64 emulator.
|
|
||||||
|
|
||||||
For 0.4:
|
For 0.4:
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ from sixtypical.parser import Parser
|
|||||||
from sixtypical.evaluator import eval_program
|
from sixtypical.evaluator import eval_program
|
||||||
from sixtypical.analyzer import analyze_program
|
from sixtypical.analyzer import analyze_program
|
||||||
from sixtypical.emitter import Emitter, Byte, Word
|
from sixtypical.emitter import Emitter, Byte, Word
|
||||||
from sixtypical.compiler import compile_program
|
from sixtypical.compiler import Compiler
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
@ -75,7 +75,8 @@ if __name__ == '__main__':
|
|||||||
emitter.emit(Word(start_addr))
|
emitter.emit(Word(start_addr))
|
||||||
for byte in header:
|
for byte in header:
|
||||||
emitter.emit(Byte(byte))
|
emitter.emit(Byte(byte))
|
||||||
compile_program(program, emitter)
|
compiler = Compiler(emitter)
|
||||||
|
compiler.compile_program(program)
|
||||||
if options.debug:
|
if options.debug:
|
||||||
print repr(emitter.accum)
|
print repr(emitter.accum)
|
||||||
else:
|
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,
|
ConstantRef, LocationRef,
|
||||||
REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C
|
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 (
|
from sixtypical.gen6502 import (
|
||||||
Immediate, Absolute,
|
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
|
pass
|
||||||
|
|
||||||
|
|
||||||
def compile_program(program, emitter):
|
class Compiler(object):
|
||||||
assert isinstance(program, Program)
|
def __init__(self, emitter):
|
||||||
routines = {r.name: r for r in program.routines}
|
self.emitter = emitter
|
||||||
for routine in program.routines:
|
self.routines = {}
|
||||||
compile_routine(routine, emitter, 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):
|
def compile_routine(self, routine):
|
||||||
assert isinstance(routine, Routine)
|
assert isinstance(routine, Routine)
|
||||||
label = emitter.make_label(routine.name)
|
if routine.block:
|
||||||
if routine.block:
|
self.compile_block(routine.block)
|
||||||
compile_block(routine.block, emitter, routines)
|
self.emitter.emit(RTS())
|
||||||
emitter.emit(RTS())
|
|
||||||
return label
|
|
||||||
|
|
||||||
|
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):
|
def compile_instr(self, instr):
|
||||||
assert isinstance(block, Block)
|
assert isinstance(instr, Instr)
|
||||||
label = emitter.make_label()
|
opcode = instr.opcode
|
||||||
for instr in block.instrs:
|
dest = instr.dest
|
||||||
compile_instr(instr, emitter, routines)
|
src = instr.src
|
||||||
return label
|
|
||||||
|
if opcode == 'ld':
|
||||||
|
if dest == REG_A:
|
||||||
def compile_instr(instr, emitter, routines):
|
if isinstance(src, ConstantRef):
|
||||||
assert isinstance(instr, Instr)
|
self.emitter.emit(LDA(Immediate(Byte(src.value))))
|
||||||
opcode = instr.opcode
|
else:
|
||||||
dest = instr.dest
|
self.emitter.emit(LDA(Absolute(src.label)))
|
||||||
src = instr.src
|
elif dest == REG_X:
|
||||||
|
pass
|
||||||
if opcode == 'ld':
|
elif dest == REG_Y:
|
||||||
if dest == REG_A:
|
pass
|
||||||
if isinstance(src, ConstantRef):
|
|
||||||
emitter.emit(LDA(Immediate(Byte(src.value))))
|
|
||||||
else:
|
else:
|
||||||
emitter.emit(LDA(Absolute(src.label)))
|
raise UnsupportedOpcodeError(instr)
|
||||||
elif dest == REG_X:
|
elif opcode == 'st':
|
||||||
pass
|
if dest == FLAG_C and src == ConstantRef(0):
|
||||||
elif dest == REG_Y:
|
self.emitter.emit(CLC())
|
||||||
pass
|
elif dest == FLAG_C and src == ConstantRef(1):
|
||||||
else:
|
self.emitter.emit(SEC())
|
||||||
raise UnsupportedOpcodeError(instr)
|
elif src == REG_A:
|
||||||
elif opcode == 'st':
|
self.emitter.emit(STA(Absolute(dest.label)))
|
||||||
if dest == FLAG_C and src == ConstantRef(0):
|
elif src == REG_X:
|
||||||
emitter.emit(CLC())
|
self.emitter.emit(STX(Absolute(dest.label)))
|
||||||
elif dest == FLAG_C and src == ConstantRef(1):
|
elif src == REG_Y:
|
||||||
emitter.emit(SEC())
|
self.emitter.emit(STY(Absolute(dest.label)))
|
||||||
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))))
|
|
||||||
else:
|
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:
|
else:
|
||||||
raise UnsupportedOpcodeError(instr)
|
raise NotImplementedError
|
||||||
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
|
|
||||||
|
@ -58,6 +58,10 @@ class Label(Emittable):
|
|||||||
assert self.addr is not None, "unresolved label: %s" % self.name
|
assert self.addr is not None, "unresolved label: %s" % self.name
|
||||||
return Word(self.addr).serialize()
|
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):
|
class Emitter(object):
|
||||||
def __init__(self, addr):
|
def __init__(self, addr):
|
||||||
|
@ -123,6 +123,12 @@ class INY(Opcode):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class JSR(Opcode):
|
||||||
|
opcodes = {
|
||||||
|
Absolute: 0x20,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class LDA(Opcode):
|
class LDA(Opcode):
|
||||||
opcodes = {
|
opcodes = {
|
||||||
Immediate: 0xa9,
|
Immediate: 0xa9,
|
||||||
|
@ -44,4 +44,4 @@ Call extern.
|
|||||||
| ld a, 65
|
| ld a, 65
|
||||||
| call chrout
|
| call chrout
|
||||||
| }
|
| }
|
||||||
= 00c018690460
|
= 00c0a94120d2ff60
|
||||||
|
Loading…
Reference in New Issue
Block a user