Fix the bugs the test suite found

- .require now tracks absolute paths of loaded files
 - stricter checking of .incbin arguments
 - fix charmap reset directive
 - Allow register names (a, x, y) as labels, with warning
 - Allow opcode names as labels, with warning
This commit is contained in:
Michael Martin 2012-06-12 06:27:11 -07:00
parent 10c3b46996
commit 7f650e787d
4 changed files with 64 additions and 17 deletions

View File

@ -12,14 +12,13 @@ import Ophis.Frontend as FE
import Ophis.Errors as Err
import os.path
loadedfiles = {}
basecharmap = "".join([chr(x) for x in range(256)])
currentcharmap = basecharmap
def reset():
global loadedfiles, currentcharmap, basecharmap
loadedfiles = {}
global currentcharmap, basecharmap
FE.loadedfiles = {}
currentcharmap = basecharmap
@ -36,8 +35,6 @@ def pragmaInclude(ppt, line, result):
filename = line.expect("STRING").value
line.expect("EOL")
if type(filename) == str:
global loadedfiles
loadedfiles[filename] = True
result.append(FE.parse_file(ppt, filename))
@ -46,10 +43,7 @@ def pragmaRequire(ppt, line, result):
filename = line.expect("STRING").value
line.expect("EOL")
if type(filename) == str:
global loadedfiles
if filename not in loadedfiles:
loadedfiles[filename] = True
result.append(FE.parse_file(ppt, filename))
result.append(FE.parse_file(ppt, filename, True))
def pragmaIncbin(ppt, line, result):
@ -69,6 +63,25 @@ def pragmaIncbin(ppt, line, result):
f = file(os.path.join(FE.context_directory, filename), "rb")
if offset.hardcoded and (size is None or size.hardcoded):
# We know how big it will be, we can just use the values.
# First check to make sure they're sane
if offset.value() < 0:
Err.log("Offset may not be negative")
f.close()
return
f.seek(0, 2) # Seek to end of file
if offset.value() > f.tell():
Err.log("Offset runs past end of file")
f.close()
return
if size is not None:
if size.value() < 0:
Err.log("Length may not be negative")
f.close()
return
if offset.value() + size.value() > f.tell():
Err.log(".incbin length too long")
f.close()
return
if size is None:
size = IR.ConstantExpr(-1)
f.seek(offset.value())
@ -97,10 +110,10 @@ def pragmaIncbin(ppt, line, result):
def pragmaCharmap(ppt, line, result):
"Modify the character map."
global currentcharmap, basecharmap
bytes = readData(line)
if len(bytes) == 0:
if str(line.lookahead(0)) == "EOL":
currentcharmap = basecharmap
else:
bytes = readData(line)
try:
base = bytes[0].data
newsubstr = "".join([chr(x.data) for x in bytes[1:]])

View File

@ -15,6 +15,9 @@ import os.path
# license: See README for details.
loadedfiles = {}
class Lexeme(object):
"Class for lexer tokens. Used by lexer and parser."
def __init__(self, type="UNKNOWN", value=None):
@ -180,8 +183,17 @@ class ParseLine(object):
"""Reads a token from the ParseLine line and returns it if it's of a
type in the sequence tokens. Otherwise, it logs an error."""
token = self.pop()
if token.type not in tokens:
Err.log('Expected: "' + '", "'.join(tokens) + '"')
if token.type in tokens:
return token
if 'LABEL' in tokens:
if token.type in ['X', 'Y']:
token.value = token.type.lower()
token.type = 'LABEL'
return token
elif token.type == 'OPCODE':
token.type = 'LABEL'
return token
Err.log('Expected: "' + '", "'.join(tokens) + '"')
return token
@ -196,7 +208,7 @@ def parse_expr(line):
next = line.lookahead(0).type
if next == "NUM":
return IR.ConstantExpr(line.expect("NUM").value)
elif next == "LABEL":
elif next in ["LABEL", "X", "Y", "OPCODE"]:
return IR.LabelExpr(line.expect("LABEL").value)
elif next == "^":
line.expect("^")
@ -352,11 +364,20 @@ def parse_line(ppt, lexemelist):
context_directory = None
def parse_file(ppt, filename):
def parse_file(ppt, filename, load_once=False):
"Loads an Ophis source file, and returns an IR list."
global context_directory
global context_directory, loadedfiles
Err.currentpoint = ppt
old_context = context_directory
if filename != '-':
if context_directory is not None:
filename = os.path.abspath(os.path.join(context_directory,
filename))
if load_once and filename in loadedfiles:
if Cmd.print_loaded_files:
print>>sys.stderr, "Skipping " + filename
return IR.NullNode
loadedfiles[filename] = True
if Cmd.print_loaded_files:
if filename != '-':
print>>sys.stderr, "Loading " + filename

View File

@ -8,6 +8,7 @@
# license: See README for details.
import sys
import os
import Ophis.Frontend
import Ophis.IR
import Ophis.CorePragmas
@ -71,7 +72,7 @@ def run_all():
# We can't dump our binary in test mode; that would be
# disastrous. So, we'll do some platform-specific
# things here to force our stdout to binary mode.
import os, msvcrt
import msvcrt
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
elif outfile is None:
output = file('ophis.bin', 'wb')

View File

@ -174,10 +174,12 @@ class InitLabels(Pass):
def __init__(self):
Pass.__init__(self)
self.labelmap = {}
self.runcount = 0
def prePass(self):
self.changed = False
self.PCvalid = True
self.runcount += 1
def visitAdvance(self, node, env):
self.PCvalid = node.data[0].valid(env, self.PCvalid)
@ -195,6 +197,12 @@ class InitLabels(Pass):
if val.valid(env, self.PCvalid) and label not in env:
env[label] = 0
self.changed = True
if label in ['a', 'x', 'y'] and self.runcount == 1:
print>>sys.stderr, str(node.ppt) + ": WARNING: " \
"using register name as label"
if label in Ops.opcodes and self.runcount == 1:
print>>sys.stderr, str(node.ppt) + ": WARNING: " \
"using opcode name as label"
def visitUnknown(self, node, env):
pass
@ -787,6 +795,10 @@ class Assembler(Pass):
length = node.data[1].value(env)
if offset < 2:
Err.log("Negative offset in .incbin")
elif offset > len(node.data):
Err.log("Offset extends past end of file")
elif length < 0:
Err.log("Negative length")
elif offset + length > len(node.data):
Err.log("File too small for .incbin subrange")
else: