mirror of
https://github.com/catseye/SixtyPical.git
synced 2025-01-23 10:30:16 +00:00
Always analyze before compiling.
This commit is contained in:
parent
43b3a088b0
commit
ed1ed3eb5d
@ -85,7 +85,6 @@ If one branch trashes {`a`} and the other branch trashes {`b`} then the whole
|
||||
### And at some point...
|
||||
|
||||
* Check that the buffer being read or written to through pointer, appears in approporiate inputs or outputs set.
|
||||
* always analyze before executing or compiling, unless told not to
|
||||
* `interrupt` routines -- to indicate that "the supervisor" has stored values on the stack, so we can trash them.
|
||||
* error messages that include the line number of the source code
|
||||
* add absolute addressing in shl/shr, absolute-indexed for add, sub, etc.
|
||||
|
@ -27,60 +27,73 @@ from sixtypical.compiler import Compiler
|
||||
if __name__ == '__main__':
|
||||
optparser = OptionParser(__doc__.strip())
|
||||
|
||||
optparser.add_option("--analyze",
|
||||
optparser.add_option("--analyze-only",
|
||||
action="store_true",
|
||||
help="")
|
||||
help="Only parse and analyze the program; do not compile it.")
|
||||
optparser.add_option("--basic-prelude",
|
||||
action="store_true",
|
||||
help="")
|
||||
optparser.add_option("--compile",
|
||||
action="store_true",
|
||||
help="")
|
||||
help="Insert a Commodore BASIC 2.0 snippet before the program "
|
||||
"so that it can be LOADed and RUN on Commodore platforms.")
|
||||
optparser.add_option("--debug",
|
||||
action="store_true",
|
||||
help="")
|
||||
help="Display debugging information when analyzing and compiling.")
|
||||
optparser.add_option("--parse-only",
|
||||
action="store_true",
|
||||
help="Only parse the program; do not analyze or compile it.")
|
||||
optparser.add_option("--traceback",
|
||||
action="store_true",
|
||||
help="")
|
||||
help="When an error occurs, display a full Python traceback.")
|
||||
|
||||
(options, args) = optparser.parse_args(sys.argv[1:])
|
||||
|
||||
for filename in args:
|
||||
text = open(filename).read()
|
||||
parser = Parser(text)
|
||||
program = parser.program()
|
||||
|
||||
if options.analyze:
|
||||
try:
|
||||
analyzer = Analyzer(debug=options.debug)
|
||||
analyzer.analyze_program(program)
|
||||
except Exception as e:
|
||||
if options.traceback:
|
||||
raise
|
||||
else:
|
||||
traceback.print_exception(e.__class__, e, None)
|
||||
sys.exit(1)
|
||||
|
||||
if options.compile:
|
||||
fh = sys.stdout
|
||||
start_addr = 0xc000
|
||||
prelude = []
|
||||
if options.basic_prelude:
|
||||
start_addr = 0x0801
|
||||
prelude = [0x10, 0x08, 0xc9, 0x07, 0x9e, 0x32,
|
||||
0x30, 0x36, 0x31, 0x00, 0x00, 0x00]
|
||||
|
||||
# we are outputting a .PRG, so we output the load address first
|
||||
# we don't use the Emitter for this b/c not part of addr space
|
||||
if not options.debug:
|
||||
fh.write(Word(start_addr).serialize(0))
|
||||
|
||||
emitter = Emitter(start_addr)
|
||||
for byte in prelude:
|
||||
emitter.emit(Byte(byte))
|
||||
compiler = Compiler(emitter)
|
||||
compiler.compile_program(program)
|
||||
if options.debug:
|
||||
pprint(emitter.accum)
|
||||
try:
|
||||
parser = Parser(text)
|
||||
program = parser.program()
|
||||
except Exception as e:
|
||||
if options.traceback:
|
||||
raise
|
||||
else:
|
||||
emitter.serialize(fh)
|
||||
traceback.print_exception(e.__class__, e, None)
|
||||
sys.exit(1)
|
||||
|
||||
if options.parse_only:
|
||||
sys.exit(0)
|
||||
|
||||
try:
|
||||
analyzer = Analyzer(debug=options.debug)
|
||||
analyzer.analyze_program(program)
|
||||
except Exception as e:
|
||||
if options.traceback:
|
||||
raise
|
||||
else:
|
||||
traceback.print_exception(e.__class__, e, None)
|
||||
sys.exit(1)
|
||||
|
||||
if options.analyze_only:
|
||||
sys.exit(0)
|
||||
|
||||
fh = sys.stdout
|
||||
start_addr = 0xc000
|
||||
prelude = []
|
||||
if options.basic_prelude:
|
||||
start_addr = 0x0801
|
||||
prelude = [0x10, 0x08, 0xc9, 0x07, 0x9e, 0x32,
|
||||
0x30, 0x36, 0x31, 0x00, 0x00, 0x00]
|
||||
|
||||
# we are outputting a .PRG, so we output the load address first
|
||||
# we don't use the Emitter for this b/c not part of addr space
|
||||
if not options.debug:
|
||||
fh.write(Word(start_addr).serialize(0))
|
||||
|
||||
emitter = Emitter(start_addr)
|
||||
for byte in prelude:
|
||||
emitter.emit(Byte(byte))
|
||||
compiler = Compiler(emitter)
|
||||
compiler.compile_program(program)
|
||||
if options.debug:
|
||||
pprint(emitter.accum)
|
||||
else:
|
||||
emitter.serialize(fh)
|
||||
|
@ -258,8 +258,8 @@ class Analyzer(object):
|
||||
raise TypeMismatchError((src, dest))
|
||||
context.assert_meaningful(instr.index)
|
||||
elif src.type != dest.type:
|
||||
raise TypeMismatchError('%s and %s in %s' %
|
||||
(src.name, dest.name, self.current_routine.name)
|
||||
raise TypeMismatchError('%r and %r in %s' %
|
||||
(src, dest, self.current_routine.name)
|
||||
)
|
||||
context.assert_meaningful(src)
|
||||
context.set_written(dest)
|
||||
|
@ -7,7 +7,7 @@ static analysis rules.
|
||||
[Falderal]: http://catseye.tc/node/Falderal
|
||||
|
||||
-> Functionality "Analyze SixtyPical program" is implemented by
|
||||
-> shell command "bin/sixtypical --analyze --traceback %(test-body-file) && echo ok"
|
||||
-> shell command "bin/sixtypical --analyze-only --traceback %(test-body-file) && echo ok"
|
||||
|
||||
-> Tests for functionality "Analyze SixtyPical program"
|
||||
|
||||
@ -236,7 +236,7 @@ Can't `st` a `word` type.
|
||||
| ld a, 0
|
||||
| st a, foo
|
||||
| }
|
||||
? TypeMismatchError: a and foo in main
|
||||
? TypeMismatchError
|
||||
|
||||
### tables ###
|
||||
|
||||
|
@ -7,7 +7,7 @@ SixtyPical to 6502 machine code.
|
||||
[Falderal]: http://catseye.tc/node/Falderal
|
||||
|
||||
-> Functionality "Compile SixtyPical program" is implemented by
|
||||
-> shell command "bin/sixtypical --basic-prelude --compile %(test-body-file) | tests/appliances/bin/dcc6502-adapter"
|
||||
-> shell command "bin/sixtypical --basic-prelude --traceback %(test-body-file) >/tmp/foo && tests/appliances/bin/dcc6502-adapter </tmp/foo"
|
||||
|
||||
-> Tests for functionality "Compile SixtyPical program"
|
||||
|
||||
@ -277,14 +277,16 @@ Compiling `if` without `else`.
|
||||
| trashes a, x, y, z, n, c, v
|
||||
| {
|
||||
| ld a, 0
|
||||
| ld y, 0
|
||||
| if z {
|
||||
| ld y, 1
|
||||
| }
|
||||
| }
|
||||
= $080D LDA #$00
|
||||
= $080F BNE $0813
|
||||
= $0811 LDY #$01
|
||||
= $0813 RTS
|
||||
= $080F LDY #$00
|
||||
= $0811 BNE $0815
|
||||
= $0813 LDY #$01
|
||||
= $0815 RTS
|
||||
|
||||
Compiling `repeat`.
|
||||
|
||||
@ -495,7 +497,11 @@ Copy vector to vector.
|
||||
|
||||
Copy routine to vector, inside an `interrupts off` block.
|
||||
|
||||
| vector routine bar
|
||||
| vector routine
|
||||
| inputs x
|
||||
| outputs x
|
||||
| trashes z, n
|
||||
| bar
|
||||
|
|
||||
| routine foo
|
||||
| inputs x
|
||||
@ -506,7 +512,6 @@ Copy routine to vector, inside an `interrupts off` block.
|
||||
| }
|
||||
|
|
||||
| routine main
|
||||
| inputs foo
|
||||
| outputs bar
|
||||
| trashes a, n, z
|
||||
| {
|
||||
@ -568,13 +573,22 @@ Copy word to word table and back, with both `x` and `y` as indexes.
|
||||
|
||||
Indirect call.
|
||||
|
||||
| vector routine outputs x trashes z, n foo
|
||||
| vector routine
|
||||
| outputs x
|
||||
| trashes z, n
|
||||
| foo
|
||||
|
|
||||
| routine bar outputs x trashes z, n {
|
||||
| routine bar
|
||||
| outputs x
|
||||
| trashes z, n
|
||||
| {
|
||||
| ld x, 200
|
||||
| }
|
||||
|
|
||||
| routine main inputs bar outputs x, foo trashes a, z, n {
|
||||
| routine main
|
||||
| outputs x, foo
|
||||
| trashes a, z, n
|
||||
| {
|
||||
| copy bar, foo
|
||||
| call foo
|
||||
| }
|
||||
@ -590,11 +604,18 @@ Indirect call.
|
||||
|
||||
goto.
|
||||
|
||||
| routine bar outputs x trashes z, n {
|
||||
| routine bar
|
||||
| inputs y
|
||||
| outputs x, y
|
||||
| trashes z, n
|
||||
| {
|
||||
| ld x, 200
|
||||
| }
|
||||
|
|
||||
| routine main outputs x trashes a, z, n {
|
||||
| routine main
|
||||
| outputs x, y
|
||||
| trashes a, z, n
|
||||
| {
|
||||
| ld y, 200
|
||||
| goto bar
|
||||
| }
|
||||
@ -841,39 +862,41 @@ Note that this is *not* range-checked. (Yet.)
|
||||
| routine main
|
||||
| inputs buf
|
||||
| outputs y, foo, delta
|
||||
| trashes a, z, n, ptr
|
||||
| trashes a, c, v, z, n, ptr
|
||||
| {
|
||||
| copy 619, delta
|
||||
| ld y, 0
|
||||
| st off, c
|
||||
| copy ^buf, ptr
|
||||
| add ptr, delta
|
||||
| add ptr, word 1
|
||||
| copy [ptr] + y, foo
|
||||
| }
|
||||
= $080D LDA #$6B
|
||||
= $080F STA $1042
|
||||
= $080F STA $1043
|
||||
= $0812 LDA #$02
|
||||
= $0814 STA $1043
|
||||
= $0814 STA $1044
|
||||
= $0817 LDY #$00
|
||||
= $0819 LDA #$41
|
||||
= $081B STA $FE
|
||||
= $081D LDA #$08
|
||||
= $081F STA $FF
|
||||
= $0821 LDA $FE
|
||||
= $0823 ADC $1042
|
||||
= $0826 STA $FE
|
||||
= $0828 LDA $FF
|
||||
= $082A ADC $1043
|
||||
= $082D STA $FF
|
||||
= $082F LDA $FE
|
||||
= $0831 ADC #$01
|
||||
= $0833 STA $FE
|
||||
= $0835 LDA $FF
|
||||
= $0837 ADC #$00
|
||||
= $0839 STA $FF
|
||||
= $083B LDA ($FE),Y
|
||||
= $083D STA $1041
|
||||
= $0840 RTS
|
||||
= $0819 CLC
|
||||
= $081A LDA #$42
|
||||
= $081C STA $FE
|
||||
= $081E LDA #$08
|
||||
= $0820 STA $FF
|
||||
= $0822 LDA $FE
|
||||
= $0824 ADC $1043
|
||||
= $0827 STA $FE
|
||||
= $0829 LDA $FF
|
||||
= $082B ADC $1044
|
||||
= $082E STA $FF
|
||||
= $0830 LDA $FE
|
||||
= $0832 ADC #$01
|
||||
= $0834 STA $FE
|
||||
= $0836 LDA $FF
|
||||
= $0838 ADC #$00
|
||||
= $083A STA $FF
|
||||
= $083C LDA ($FE),Y
|
||||
= $083E STA $1042
|
||||
= $0841 RTS
|
||||
|
||||
### Trash
|
||||
|
||||
|
@ -10,7 +10,7 @@ but not necessarily sensible programs.
|
||||
[Falderal]: http://catseye.tc/node/Falderal
|
||||
|
||||
-> Functionality "Check syntax of SixtyPical program" is implemented by
|
||||
-> shell command "bin/sixtypical %(test-body-file) && echo ok"
|
||||
-> shell command "bin/sixtypical --parse-only --traceback %(test-body-file) && echo ok"
|
||||
|
||||
-> Tests for functionality "Check syntax of SixtyPical program"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user