mirror of
https://github.com/michaelcmartin/Ophis.git
synced 2024-12-30 10:30:47 +00:00
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:
parent
10c3b46996
commit
7f650e787d
@ -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:]])
|
||||
|
@ -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
|
||||
|
@ -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')
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user