mirror of
https://github.com/catseye/SixtyPical.git
synced 2025-02-19 20:30:45 +00:00
Clean up driver code, add filename to error messages.
This commit is contained in:
parent
3f0e36a67c
commit
d9e625db30
@ -1,7 +1,7 @@
|
||||
SixtyPical
|
||||
==========
|
||||
|
||||
_Version 0.14. Work-in-progress, everything is subject to change._
|
||||
_Version 0.15. Work-in-progress, everything is subject to change._
|
||||
|
||||
**SixtyPical** is a 6502-like programming language with advanced
|
||||
static analysis.
|
||||
|
132
bin/sixtypical
132
bin/sixtypical
@ -24,6 +24,66 @@ from sixtypical.emitter import Emitter, Byte, Word
|
||||
from sixtypical.compiler import Compiler
|
||||
|
||||
|
||||
def process_input_files(filenames, options):
|
||||
programs = []
|
||||
|
||||
for filename in options.filenames:
|
||||
text = open(filename).read()
|
||||
parser = Parser(text, filename)
|
||||
program = parser.program()
|
||||
programs.append(program)
|
||||
|
||||
if options.parse_only:
|
||||
return
|
||||
|
||||
#program = merge_programs(programs)
|
||||
program = programs[0]
|
||||
|
||||
analyzer = Analyzer(debug=options.debug)
|
||||
analyzer.analyze_program(program)
|
||||
|
||||
if options.analyze_only:
|
||||
return
|
||||
|
||||
fh = sys.stdout
|
||||
|
||||
if options.origin.startswith('0x'):
|
||||
start_addr = int(options.origin, 16)
|
||||
else:
|
||||
start_addr = int(options.origin, 10)
|
||||
|
||||
output_format = options.output_format
|
||||
|
||||
prelude = []
|
||||
if options.prelude == 'c64':
|
||||
output_format = 'prg'
|
||||
start_addr = 0x0801
|
||||
prelude = [0x10, 0x08, 0xc9, 0x07, 0x9e, 0x32,
|
||||
0x30, 0x36, 0x31, 0x00, 0x00, 0x00]
|
||||
elif options.prelude == 'vic20':
|
||||
output_format = 'prg'
|
||||
start_addr = 0x1001
|
||||
prelude = [0x0b, 0x10, 0xc9, 0x07, 0x9e, 0x34,
|
||||
0x31, 0x30, 0x39, 0x00, 0x00, 0x00]
|
||||
elif options.prelude:
|
||||
raise NotImplementedError("Unknown prelude: {}".format(options.prelude))
|
||||
|
||||
# If we are outputting a .PRG, we output the load address first.
|
||||
# We don't use the Emitter for this b/c not part of addr space.
|
||||
if output_format == 'prg':
|
||||
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)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
argparser = ArgumentParser(__doc__.strip())
|
||||
|
||||
@ -72,69 +132,11 @@ if __name__ == '__main__':
|
||||
options, unknown = argparser.parse_known_args(sys.argv[1:])
|
||||
remainder = ' '.join(unknown)
|
||||
|
||||
for filename in options.filenames:
|
||||
text = open(filename).read()
|
||||
|
||||
try:
|
||||
parser = Parser(text)
|
||||
program = parser.program()
|
||||
except Exception as e:
|
||||
if options.traceback:
|
||||
raise
|
||||
else:
|
||||
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
|
||||
|
||||
if options.origin.startswith('0x'):
|
||||
start_addr = int(options.origin, 16)
|
||||
try:
|
||||
process_input_files(options.filenames, options)
|
||||
except Exception as e:
|
||||
if options.traceback:
|
||||
raise
|
||||
else:
|
||||
start_addr = int(options.origin, 10)
|
||||
|
||||
output_format = options.output_format
|
||||
|
||||
prelude = []
|
||||
if options.prelude == 'c64':
|
||||
output_format = 'prg'
|
||||
start_addr = 0x0801
|
||||
prelude = [0x10, 0x08, 0xc9, 0x07, 0x9e, 0x32,
|
||||
0x30, 0x36, 0x31, 0x00, 0x00, 0x00]
|
||||
elif options.prelude == 'vic20':
|
||||
output_format = 'prg'
|
||||
start_addr = 0x1001
|
||||
prelude = [0x0b, 0x10, 0xc9, 0x07, 0x9e, 0x34,
|
||||
0x31, 0x30, 0x39, 0x00, 0x00, 0x00]
|
||||
elif options.prelude:
|
||||
raise NotImplementedError("Unknown prelude: {}".format(options.prelude))
|
||||
|
||||
# If we are outputting a .PRG, we output the load address first.
|
||||
# We don't use the Emitter for this b/c not part of addr space.
|
||||
if output_format == 'prg':
|
||||
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)
|
||||
traceback.print_exception(e.__class__, e, None)
|
||||
sys.exit(1)
|
||||
|
@ -6,7 +6,7 @@ from sixtypical.model import (
|
||||
RoutineType, VectorType, TableType, BufferType, PointerType,
|
||||
LocationRef, ConstantRef, IndirectRef, IndexedRef, AddressRef,
|
||||
)
|
||||
from sixtypical.scanner import Scanner, SixtyPicalSyntaxError
|
||||
from sixtypical.scanner import Scanner
|
||||
|
||||
|
||||
class SymEntry(object):
|
||||
@ -19,8 +19,8 @@ class SymEntry(object):
|
||||
|
||||
|
||||
class Parser(object):
|
||||
def __init__(self, text):
|
||||
self.scanner = Scanner(text)
|
||||
def __init__(self, text, filename):
|
||||
self.scanner = Scanner(text, filename)
|
||||
self.symbols = {} # token -> SymEntry
|
||||
self.current_statics = {} # token -> SymEntry
|
||||
self.typedefs = {} # token -> Type AST
|
||||
@ -32,7 +32,7 @@ class Parser(object):
|
||||
self.backpatch_instrs = []
|
||||
|
||||
def syntax_error(self, msg):
|
||||
raise SixtyPicalSyntaxError(self.scanner.line_number, msg)
|
||||
self.scanner.syntax_error(msg)
|
||||
|
||||
def soft_lookup(self, name):
|
||||
if name in self.current_statics:
|
||||
|
@ -4,16 +4,17 @@ import re
|
||||
|
||||
|
||||
class SixtyPicalSyntaxError(ValueError):
|
||||
def __init__(self, line_number, message):
|
||||
super(SixtyPicalSyntaxError, self).__init__(line_number, message)
|
||||
def __init__(self, filename, line_number, message):
|
||||
super(SixtyPicalSyntaxError, self).__init__(filename, line_number, message)
|
||||
|
||||
def __str__(self):
|
||||
return "Line {}: {}".format(self.args[0], self.args[1])
|
||||
return "{}, line {}: {}".format(self.args[0], self.args[1], self.args[2])
|
||||
|
||||
|
||||
class Scanner(object):
|
||||
def __init__(self, text):
|
||||
def __init__(self, text, filename):
|
||||
self.text = text
|
||||
self.filename = filename
|
||||
self.token = None
|
||||
self.type = None
|
||||
self.line_number = 1
|
||||
@ -62,9 +63,7 @@ class Scanner(object):
|
||||
if self.token == token:
|
||||
self.scan()
|
||||
else:
|
||||
raise SixtyPicalSyntaxError(self.line_number, "Expected '{}', but found '{}'".format(
|
||||
token, self.token
|
||||
))
|
||||
self.syntax_error("Expected '{}', but found '{}'".format(token, self.token))
|
||||
|
||||
def on(self, *tokens):
|
||||
return self.token in tokens
|
||||
@ -74,9 +73,7 @@ class Scanner(object):
|
||||
|
||||
def check_type(self, type):
|
||||
if not self.type == type:
|
||||
raise SixtyPicalSyntaxError(self.line_number, "Expected {}, but found '{}'".format(
|
||||
self.type, self.token
|
||||
))
|
||||
self.syntax_error("Expected {}, but found '{}'".format(self.type, self.token))
|
||||
|
||||
def consume(self, token):
|
||||
if self.token == token:
|
||||
@ -84,3 +81,6 @@ class Scanner(object):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def syntax_error(self, msg):
|
||||
raise SixtyPicalSyntaxError(self.filename, self.line_number, msg)
|
||||
|
Loading…
x
Reference in New Issue
Block a user