mirror of
https://github.com/michaelcmartin/Ophis.git
synced 2025-01-13 10:29:47 +00:00
Convert Ophis to Python 3.
Most of the work is handled by 2to3, but there's a few extra tricks needed to finish the job, mostly about picking the right bits to be Unicode and the right bits to be bytes.
This commit is contained in:
parent
971fafd918
commit
41bf01d035
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
from os.path import realpath, dirname, join
|
from os.path import realpath, dirname, join
|
||||||
from sys import argv, exit, path
|
from sys import argv, exit, path
|
||||||
|
@ -10,7 +10,8 @@ import Ophis.CmdLine
|
|||||||
import Ophis.IR as IR
|
import Ophis.IR as IR
|
||||||
import Ophis.Frontend as FE
|
import Ophis.Frontend as FE
|
||||||
import Ophis.Errors as Err
|
import Ophis.Errors as Err
|
||||||
import math, os.path
|
import math
|
||||||
|
import os.path
|
||||||
|
|
||||||
basecharmap = "".join([chr(x) for x in range(256)])
|
basecharmap = "".join([chr(x) for x in range(256)])
|
||||||
currentcharmap = basecharmap
|
currentcharmap = basecharmap
|
||||||
@ -68,7 +69,7 @@ def pragmaIncbin(ppt, line, result):
|
|||||||
line.expect("EOL")
|
line.expect("EOL")
|
||||||
if type(filename) == str:
|
if type(filename) == str:
|
||||||
try:
|
try:
|
||||||
f = file(os.path.join(FE.context_directory, filename), "rb")
|
f = open(os.path.join(FE.context_directory, filename), "rb")
|
||||||
if offset.hardcoded and (size is None or size.hardcoded):
|
if offset.hardcoded and (size is None or size.hardcoded):
|
||||||
# We know how big it will be, we can just use the values.
|
# We know how big it will be, we can just use the values.
|
||||||
# First check to make sure they're sane
|
# First check to make sure they're sane
|
||||||
@ -94,7 +95,7 @@ def pragmaIncbin(ppt, line, result):
|
|||||||
size = IR.ConstantExpr(-1)
|
size = IR.ConstantExpr(-1)
|
||||||
f.seek(offset.value())
|
f.seek(offset.value())
|
||||||
bytes = f.read(size.value())
|
bytes = f.read(size.value())
|
||||||
bytes = [IR.ConstantExpr(ord(x)) for x in bytes]
|
bytes = [IR.ConstantExpr(x) for x in bytes]
|
||||||
result.append(IR.Node(ppt, "Byte", *bytes))
|
result.append(IR.Node(ppt, "Byte", *bytes))
|
||||||
else:
|
else:
|
||||||
# offset or length could change based on label placement.
|
# offset or length could change based on label placement.
|
||||||
@ -103,7 +104,7 @@ def pragmaIncbin(ppt, line, result):
|
|||||||
# alias. Don't use symbolic aliases when extracting tiny
|
# alias. Don't use symbolic aliases when extracting tiny
|
||||||
# pieces out of humongous files, I guess.
|
# pieces out of humongous files, I guess.
|
||||||
bytes = f.read()
|
bytes = f.read()
|
||||||
bytes = [IR.ConstantExpr(ord(x)) for x in bytes]
|
bytes = [IR.ConstantExpr(x) for x in bytes]
|
||||||
if size is None:
|
if size is None:
|
||||||
size = IR.SequenceExpr([IR.ConstantExpr(len(bytes)),
|
size = IR.SequenceExpr([IR.ConstantExpr(len(bytes)),
|
||||||
"-",
|
"-",
|
||||||
@ -141,7 +142,7 @@ def pragmaCharmapbin(ppt, line, result):
|
|||||||
line.expect("EOL")
|
line.expect("EOL")
|
||||||
if type(filename) == str:
|
if type(filename) == str:
|
||||||
try:
|
try:
|
||||||
f = file(os.path.join(FE.context_directory, filename), "rb")
|
f = open(os.path.join(FE.context_directory, filename), "rb")
|
||||||
bytes = f.read()
|
bytes = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
except IOError:
|
except IOError:
|
||||||
|
@ -18,14 +18,14 @@ def log(err):
|
|||||||
the global error count."""
|
the global error count."""
|
||||||
global count
|
global count
|
||||||
count = count + 1
|
count = count + 1
|
||||||
print>>sys.stderr, currentpoint + ": " + err
|
print(currentpoint + ": " + err, file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
def report():
|
def report():
|
||||||
"Print out the number of errors."
|
"Print out the number of errors."
|
||||||
if count == 0:
|
if count == 0:
|
||||||
print>>sys.stderr, "No errors"
|
print("No errors", file=sys.stderr)
|
||||||
elif count == 1:
|
elif count == 1:
|
||||||
print>>sys.stderr, "1 error"
|
print("1 error", file=sys.stderr)
|
||||||
else:
|
else:
|
||||||
print>>sys.stderr, str(count) + " errors"
|
print(str(count) + " errors", file=sys.stderr)
|
||||||
|
@ -70,7 +70,7 @@ def lex(point, line):
|
|||||||
return
|
return
|
||||||
elif firstchar in bases:
|
elif firstchar in bases:
|
||||||
try:
|
try:
|
||||||
result.append(Lexeme("NUM", long(rest, bases[firstchar][1])))
|
result.append(Lexeme("NUM", int(rest, bases[firstchar][1])))
|
||||||
return
|
return
|
||||||
except ValueError:
|
except ValueError:
|
||||||
Err.log('Invalid ' + bases[firstchar][0] + ' constant: ' +
|
Err.log('Invalid ' + bases[firstchar][0] + ' constant: ' +
|
||||||
@ -79,7 +79,7 @@ def lex(point, line):
|
|||||||
return
|
return
|
||||||
elif firstchar.isdigit():
|
elif firstchar.isdigit():
|
||||||
try:
|
try:
|
||||||
result.append(Lexeme("NUM", long(token)))
|
result.append(Lexeme("NUM", int(token)))
|
||||||
except ValueError:
|
except ValueError:
|
||||||
Err.log('Identifiers may not begin with a number')
|
Err.log('Identifiers may not begin with a number')
|
||||||
result.append(Lexeme("LABEL", "ERROR"))
|
result.append(Lexeme("LABEL", "ERROR"))
|
||||||
@ -403,19 +403,19 @@ def parse_file(ppt, filename, load_once=False):
|
|||||||
filename))
|
filename))
|
||||||
if load_once and filename in loadedfiles:
|
if load_once and filename in loadedfiles:
|
||||||
if Cmd.print_loaded_files:
|
if Cmd.print_loaded_files:
|
||||||
print>>sys.stderr, "Skipping " + filename
|
print("Skipping " + filename, file=sys.stderr)
|
||||||
return IR.NullNode
|
return IR.NullNode
|
||||||
loadedfiles[filename] = True
|
loadedfiles[filename] = True
|
||||||
if Cmd.print_loaded_files:
|
if Cmd.print_loaded_files:
|
||||||
if filename != '-':
|
if filename != '-':
|
||||||
print>>sys.stderr, "Loading " + filename
|
print("Loading " + filename, file=sys.stderr)
|
||||||
else:
|
else:
|
||||||
print>>sys.stderr, "Loading from standard input"
|
print("Loading from standard input", file=sys.stderr)
|
||||||
try:
|
try:
|
||||||
if filename != '-':
|
if filename != '-':
|
||||||
if context_directory is not None:
|
if context_directory is not None:
|
||||||
filename = os.path.join(context_directory, filename)
|
filename = os.path.join(context_directory, filename)
|
||||||
f = file(filename)
|
f = open(filename, "rt")
|
||||||
linelist = f.readlines()
|
linelist = f.readlines()
|
||||||
f.close()
|
f.close()
|
||||||
context_directory = os.path.abspath(os.path.dirname(filename))
|
context_directory = os.path.abspath(os.path.dirname(filename))
|
||||||
@ -423,8 +423,8 @@ def parse_file(ppt, filename, load_once=False):
|
|||||||
context_directory = os.getcwd()
|
context_directory = os.getcwd()
|
||||||
linelist = sys.stdin.readlines()
|
linelist = sys.stdin.readlines()
|
||||||
pptlist = ["%s:%d" % (filename, i + 1) for i in range(len(linelist))]
|
pptlist = ["%s:%d" % (filename, i + 1) for i in range(len(linelist))]
|
||||||
lexlist = map(lex, pptlist, linelist)
|
lexlist = list(map(lex, pptlist, linelist))
|
||||||
IRlist = map(parse_line, pptlist, lexlist)
|
IRlist = list(map(parse_line, pptlist, lexlist))
|
||||||
IRlist = [node for node in IRlist if node is not IR.NullNode]
|
IRlist = [node for node in IRlist if node is not IR.NullNode]
|
||||||
context_directory = old_context
|
context_directory = old_context
|
||||||
return IR.SequenceNode(ppt, IRlist)
|
return IR.SequenceNode(ppt, IRlist)
|
||||||
|
@ -179,7 +179,7 @@ class SequenceExpr(Expr):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def value(self, env=None):
|
def value(self, env=None):
|
||||||
subs = map((lambda x: x.value(env)), self.operands)
|
subs = list(map((lambda x: x.value(env)), self.operands))
|
||||||
result = subs[0]
|
result = subs[0]
|
||||||
index = 1
|
index = 1
|
||||||
for op in self.operators:
|
for op in self.operators:
|
||||||
|
@ -43,7 +43,7 @@ class Listing(object):
|
|||||||
out = file(self.filename, "w")
|
out = file(self.filename, "w")
|
||||||
for x in self.listing:
|
for x in self.listing:
|
||||||
if type(x) is str:
|
if type(x) is str:
|
||||||
print>>out, x
|
print(x, file=out)
|
||||||
elif type(x) is tuple:
|
elif type(x) is tuple:
|
||||||
i = 0
|
i = 0
|
||||||
pc = x[0]
|
pc = x[0]
|
||||||
@ -59,7 +59,7 @@ class Listing(object):
|
|||||||
charline += "."
|
charline += "."
|
||||||
else:
|
else:
|
||||||
charline += chr(c)
|
charline += chr(c)
|
||||||
print>>out, "%-54s |%-16s|" % (dataline, charline)
|
print("%-54s |%-16s|" % (dataline, charline), file=out)
|
||||||
i += 16
|
i += 16
|
||||||
if self.filename != "-":
|
if self.filename != "-":
|
||||||
out.close()
|
out.close()
|
||||||
|
@ -55,7 +55,7 @@ def expandMacro(ppt, name, arglist):
|
|||||||
Err.log("Undefined macro '%s'" % name)
|
Err.log("Undefined macro '%s'" % name)
|
||||||
return IR.NullNode
|
return IR.NullNode
|
||||||
argexprs = [IR.Node(ppt, "Label", "_*%d" % i, arg)
|
argexprs = [IR.Node(ppt, "Label", "_*%d" % i, arg)
|
||||||
for (i, arg) in zip(xrange(1, sys.maxint), arglist)]
|
for (i, arg) in zip(range(1, sys.maxsize), arglist)]
|
||||||
bindexprs = [IR.Node(ppt, "Label", "_%d" % i, IR.LabelExpr("_*%d" % i))
|
bindexprs = [IR.Node(ppt, "Label", "_%d" % i, IR.LabelExpr("_*%d" % i))
|
||||||
for i in range(1, len(arglist) + 1)]
|
for i in range(1, len(arglist) + 1)]
|
||||||
body = [IR.Node("%s->%s" % (ppt, node.ppt), node.nodetype, *node.data)
|
body = [IR.Node("%s->%s" % (ppt, node.ppt), node.nodetype, *node.data)
|
||||||
@ -70,7 +70,7 @@ def dump():
|
|||||||
global macros
|
global macros
|
||||||
for mac in macros:
|
for mac in macros:
|
||||||
body = macros[mac]
|
body = macros[mac]
|
||||||
print>>sys.stderr, "Macro: " + mac
|
print("Macro: " + mac, file=sys.stderr)
|
||||||
for node in body:
|
for node in body:
|
||||||
print>>sys.stderr, node
|
print(node, file=sys.stderr)
|
||||||
print>>sys.stderr, ""
|
print("", file=sys.stderr)
|
||||||
|
@ -72,7 +72,7 @@ def run_all():
|
|||||||
try:
|
try:
|
||||||
outfile = Ophis.CmdLine.outfile
|
outfile = Ophis.CmdLine.outfile
|
||||||
if outfile == '-':
|
if outfile == '-':
|
||||||
output = sys.stdout
|
output = sys.stdout.buffer
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
# We can't dump our binary in text mode; that would be
|
# We can't dump our binary in text mode; that would be
|
||||||
# disastrous. So, we'll do some platform-specific
|
# disastrous. So, we'll do some platform-specific
|
||||||
@ -80,16 +80,16 @@ def run_all():
|
|||||||
import msvcrt
|
import msvcrt
|
||||||
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
|
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
|
||||||
elif outfile is None:
|
elif outfile is None:
|
||||||
output = file('ophis.bin', 'wb')
|
output = open('ophis.bin', 'wb')
|
||||||
else:
|
else:
|
||||||
output = file(outfile, 'wb')
|
output = open(outfile, 'wb')
|
||||||
output.write("".join(map(chr, a.output)))
|
output.write(bytes(a.output))
|
||||||
output.flush()
|
output.flush()
|
||||||
if outfile != '-':
|
if outfile != '-':
|
||||||
output.close()
|
output.close()
|
||||||
return 0
|
return 0
|
||||||
except IOError:
|
except IOError:
|
||||||
print>>sys.stderr, "Could not write to " + outfile
|
print("Could not write to " + outfile, file=sys.stderr)
|
||||||
return 1
|
return 1
|
||||||
else:
|
else:
|
||||||
Err.report()
|
Err.report()
|
||||||
|
@ -67,18 +67,18 @@ class Pass(object):
|
|||||||
printing debugging information."""
|
printing debugging information."""
|
||||||
if Err.count == 0:
|
if Err.count == 0:
|
||||||
if Cmd.print_pass:
|
if Cmd.print_pass:
|
||||||
print>>sys.stderr, "Running: " + self.name
|
print("Running: " + self.name, file=sys.stderr)
|
||||||
env.reset()
|
env.reset()
|
||||||
self.prePass()
|
self.prePass()
|
||||||
node.accept(self, env)
|
node.accept(self, env)
|
||||||
self.postPass()
|
self.postPass()
|
||||||
env.reset()
|
env.reset()
|
||||||
if Cmd.print_labels:
|
if Cmd.print_labels:
|
||||||
print>>sys.stderr, "Current labels:"
|
print("Current labels:", file=sys.stderr)
|
||||||
print>>sys.stderr, env
|
print(env, file=sys.stderr)
|
||||||
if Cmd.print_ir:
|
if Cmd.print_ir:
|
||||||
print>>sys.stderr, "Current IR:"
|
print("Current IR:", file=sys.stderr)
|
||||||
print>>sys.stderr, node
|
print(node, file=sys.stderr)
|
||||||
|
|
||||||
|
|
||||||
class FixPoint(object):
|
class FixPoint(object):
|
||||||
@ -92,7 +92,7 @@ class FixPoint(object):
|
|||||||
def go(self, node, env):
|
def go(self, node, env):
|
||||||
"""Runs this FixPoint's passes, in order, until the fixpoint
|
"""Runs this FixPoint's passes, in order, until the fixpoint
|
||||||
is true. Always runs the passes at least once."""
|
is true. Always runs the passes at least once."""
|
||||||
for i in xrange(100):
|
for i in range(100):
|
||||||
if Err.count != 0:
|
if Err.count != 0:
|
||||||
break
|
break
|
||||||
for p in self.passes:
|
for p in self.passes:
|
||||||
@ -102,7 +102,7 @@ class FixPoint(object):
|
|||||||
if self.fixpoint():
|
if self.fixpoint():
|
||||||
break
|
break
|
||||||
if Cmd.print_pass:
|
if Cmd.print_pass:
|
||||||
print>>sys.stderr, "Fixpoint failed, looping back"
|
print("Fixpoint failed, looping back", file=sys.stderr)
|
||||||
else:
|
else:
|
||||||
Err.log("Can't make %s converge! Maybe there's a recursive "
|
Err.log("Can't make %s converge! Maybe there's a recursive "
|
||||||
"dependency somewhere?" % self.name)
|
"dependency somewhere?" % self.name)
|
||||||
@ -120,7 +120,7 @@ class DefineMacros(Pass):
|
|||||||
if self.inDef:
|
if self.inDef:
|
||||||
Err.log("Unmatched .macro")
|
Err.log("Unmatched .macro")
|
||||||
elif Cmd.print_ir:
|
elif Cmd.print_ir:
|
||||||
print>>sys.stderr, "Macro definitions:"
|
print("Macro definitions:", file=sys.stderr)
|
||||||
Macro.dump()
|
Macro.dump()
|
||||||
|
|
||||||
def visitMacroBegin(self, node, env):
|
def visitMacroBegin(self, node, env):
|
||||||
@ -197,11 +197,11 @@ class InitLabels(Pass):
|
|||||||
env[label] = 0
|
env[label] = 0
|
||||||
self.changed = True
|
self.changed = True
|
||||||
if label in ['a', 'x', 'y'] and self.runcount == 1:
|
if label in ['a', 'x', 'y'] and self.runcount == 1:
|
||||||
print>>sys.stderr, str(node.ppt) + ": WARNING: " \
|
print(str(node.ppt) + ": WARNING: " \
|
||||||
"using register name as label"
|
"using register name as label", file=sys.stderr)
|
||||||
if label in Ops.opcodes and self.runcount == 1:
|
if label in Ops.opcodes and self.runcount == 1:
|
||||||
print>>sys.stderr, str(node.ppt) + ": WARNING: " \
|
print(str(node.ppt) + ": WARNING: " \
|
||||||
"using opcode name as label"
|
"using opcode name as label", file=sys.stderr)
|
||||||
|
|
||||||
def visitUnknown(self, node, env):
|
def visitUnknown(self, node, env):
|
||||||
pass
|
pass
|
||||||
@ -636,16 +636,16 @@ class ExtendBranches(PCTracker):
|
|||||||
if Cmd.enable_4502_exts:
|
if Cmd.enable_4502_exts:
|
||||||
node.nodetype = "RelativeLong"
|
node.nodetype = "RelativeLong"
|
||||||
if Cmd.warn_on_branch_extend:
|
if Cmd.warn_on_branch_extend:
|
||||||
print>>sys.stderr, str(node.ppt) + ": WARNING: " \
|
print(str(node.ppt) + ": WARNING: " \
|
||||||
"branch out of range, replacing with 16-bit relative branch"
|
"branch out of range, replacing with 16-bit relative branch", file=sys.stderr)
|
||||||
else:
|
else:
|
||||||
if opcode == 'bra':
|
if opcode == 'bra':
|
||||||
# If BRA - BRanch Always - is out of range, it's a JMP.
|
# If BRA - BRanch Always - is out of range, it's a JMP.
|
||||||
node.data = ('jmp', expr, None)
|
node.data = ('jmp', expr, None)
|
||||||
node.nodetype = "Absolute"
|
node.nodetype = "Absolute"
|
||||||
if Cmd.warn_on_branch_extend:
|
if Cmd.warn_on_branch_extend:
|
||||||
print>>sys.stderr, str(node.ppt) + ": WARNING: " \
|
print(str(node.ppt) + ": WARNING: " \
|
||||||
"bra out of range, replacing with jmp"
|
"bra out of range, replacing with jmp", file=sys.stderr)
|
||||||
else:
|
else:
|
||||||
# Otherwise, we replace it with a 'macro' of sorts by hand:
|
# Otherwise, we replace it with a 'macro' of sorts by hand:
|
||||||
# $branch LOC -> $reversed_branch ^+5; JMP LOC
|
# $branch LOC -> $reversed_branch ^+5; JMP LOC
|
||||||
@ -661,11 +661,11 @@ class ExtendBranches(PCTracker):
|
|||||||
node.nodetype = 'SEQUENCE'
|
node.nodetype = 'SEQUENCE'
|
||||||
node.data = expansion
|
node.data = expansion
|
||||||
if Cmd.warn_on_branch_extend:
|
if Cmd.warn_on_branch_extend:
|
||||||
print>>sys.stderr, str(node.ppt) + ": WARNING: " + \
|
print(str(node.ppt) + ": WARNING: " + \
|
||||||
opcode + " out of range, " \
|
opcode + " out of range, " \
|
||||||
"replacing with " + \
|
"replacing with " + \
|
||||||
ExtendBranches.reversed[opcode] + \
|
ExtendBranches.reversed[opcode] + \
|
||||||
"/jmp combo"
|
"/jmp combo", file=sys.stderr)
|
||||||
self.changed = True
|
self.changed = True
|
||||||
node.accept(self, env)
|
node.accept(self, env)
|
||||||
else:
|
else:
|
||||||
@ -690,11 +690,11 @@ class ExtendBranches(PCTracker):
|
|||||||
node.nodetype = 'SEQUENCE'
|
node.nodetype = 'SEQUENCE'
|
||||||
node.data = expansion
|
node.data = expansion
|
||||||
if Cmd.warn_on_branch_extend:
|
if Cmd.warn_on_branch_extend:
|
||||||
print>>sys.stderr, str(node.ppt) + ": WARNING: " + \
|
print(str(node.ppt) + ": WARNING: " + \
|
||||||
opcode + " out of range, " \
|
opcode + " out of range, " \
|
||||||
"replacing with " + \
|
"replacing with " + \
|
||||||
ExtendBranches.reversed[opcode] + \
|
ExtendBranches.reversed[opcode] + \
|
||||||
"/jmp combo"
|
"/jmp combo", file=sys.stderr)
|
||||||
self.changed = True
|
self.changed = True
|
||||||
node.accept(self, env)
|
node.accept(self, env)
|
||||||
else:
|
else:
|
||||||
@ -763,10 +763,10 @@ class Assembler(Pass):
|
|||||||
self.listing.dump()
|
self.listing.dump()
|
||||||
self.mapper.dump()
|
self.mapper.dump()
|
||||||
if Cmd.print_summary and Err.count == 0:
|
if Cmd.print_summary and Err.count == 0:
|
||||||
print>>sys.stderr, "Assembly complete: %s bytes output " \
|
print("Assembly complete: %s bytes output " \
|
||||||
"(%s code, %s data, %s filler)" \
|
"(%s code, %s data, %s filler)" \
|
||||||
% (len(self.output),
|
% (len(self.output),
|
||||||
self.code, self.data, self.filler)
|
self.code, self.data, self.filler), file=sys.stderr)
|
||||||
|
|
||||||
def outputbyte(self, expr, env, tee=None):
|
def outputbyte(self, expr, env, tee=None):
|
||||||
'Outputs a byte, with range checking'
|
'Outputs a byte, with range checking'
|
||||||
@ -799,7 +799,7 @@ class Assembler(Pass):
|
|||||||
'Outputs a little-endian dword, with range checking'
|
'Outputs a little-endian dword, with range checking'
|
||||||
if self.writeOK:
|
if self.writeOK:
|
||||||
val = expr.value(env)
|
val = expr.value(env)
|
||||||
if val < 0x00000000 or val > 0xFFFFFFFFL:
|
if val < 0x00000000 or val > 0xFFFFFFFF:
|
||||||
Err.log("DWord constant " + str(expr) + " out of range")
|
Err.log("DWord constant " + str(expr) + " out of range")
|
||||||
val = 0
|
val = 0
|
||||||
self.output.append(int(val & 0xFF))
|
self.output.append(int(val & 0xFF))
|
||||||
@ -829,7 +829,7 @@ class Assembler(Pass):
|
|||||||
'Outputs a big-endian dword, with range checking'
|
'Outputs a big-endian dword, with range checking'
|
||||||
if self.writeOK:
|
if self.writeOK:
|
||||||
val = expr.value(env)
|
val = expr.value(env)
|
||||||
if val < 0x00000000 or val > 0xFFFFFFFFL:
|
if val < 0x00000000 or val > 0xFFFFFFFF:
|
||||||
Err.log("DWord constant " + str(expr) + " out of range")
|
Err.log("DWord constant " + str(expr) + " out of range")
|
||||||
val = 0
|
val = 0
|
||||||
self.output.append(int((val >> 24) & 0xFF))
|
self.output.append(int((val >> 24) & 0xFF))
|
||||||
@ -1083,7 +1083,7 @@ class Assembler(Pass):
|
|||||||
(pc, target))
|
(pc, target))
|
||||||
else:
|
else:
|
||||||
created = []
|
created = []
|
||||||
for i in xrange(target - pc):
|
for i in range(target - pc):
|
||||||
self.outputbyte(node.data[1], env, created)
|
self.outputbyte(node.data[1], env, created)
|
||||||
self.filler += target - pc
|
self.filler += target - pc
|
||||||
self.registerData(created, env.getPC())
|
self.registerData(created, env.getPC())
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
x = ''.join([chr(x) for x in range(256)])
|
x = bytes(list(range(256)))
|
||||||
bits = struct.unpack("32s32s32s32s32s32s32s32s", x)
|
bits = struct.unpack("32s32s32s32s32s32s32s32s", x)
|
||||||
norm = [4, 5, 6, 7, 0, 1, 2, 3]
|
norm = [4, 5, 6, 7, 0, 1, 2, 3]
|
||||||
ivrs = [4, 1, 0, 7, 6, 5, 2, 3]
|
ivrs = [4, 1, 0, 7, 6, 5, 2, 3]
|
||||||
blnk = [4, 3, 2, 7, 0, 1, 6, 5]
|
blnk = [4, 3, 2, 7, 0, 1, 6, 5]
|
||||||
normmap = ''.join([bits[x] for x in norm])
|
normmap = b''.join([bits[x] for x in norm])
|
||||||
ivrsmap = ''.join([bits[x] for x in ivrs])
|
ivrsmap = b''.join([bits[x] for x in ivrs])
|
||||||
blnkmap = ''.join([bits[x] for x in blnk])
|
blnkmap = b''.join([bits[x] for x in blnk])
|
||||||
|
|
||||||
|
|
||||||
def dumpfile(n, m):
|
def dumpfile(n, m):
|
||||||
f = file(n, 'wb')
|
f = open(n, 'wb')
|
||||||
f.write(m)
|
f.write(m)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
verbose = 0
|
verbose = 0
|
||||||
@ -80,7 +80,7 @@ def decomment(l):
|
|||||||
|
|
||||||
|
|
||||||
def decomment_readlines(fname):
|
def decomment_readlines(fname):
|
||||||
result = [decomment(x) for x in file(fname).readlines()]
|
result = [decomment(x) for x in open(fname, "rt").readlines()]
|
||||||
return [x for x in result if len(x) > 0]
|
return [x for x in result if len(x) > 0]
|
||||||
|
|
||||||
|
|
||||||
@ -103,22 +103,22 @@ def parse_chipset_file(fname):
|
|||||||
result[op] = []
|
result[op] = []
|
||||||
result[op].append((mnem, flatmodes.index(mode)))
|
result[op].append((mnem, flatmodes.index(mode)))
|
||||||
else:
|
else:
|
||||||
print "Unknown mode '%s'" % s_p[1]
|
print("Unknown mode '%s'" % s_p[1])
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print "Illegal opcode '%s'" % l[0]
|
print("Illegal opcode '%s'" % l[0])
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def collate_chipset_map(cs_list, base):
|
def collate_chipset_map(cs_list, base):
|
||||||
result = {}
|
result = {}
|
||||||
for (opcode, insts) in zip(range(256), cs_list):
|
for (opcode, insts) in zip(list(range(256)), cs_list):
|
||||||
if insts is not None:
|
if insts is not None:
|
||||||
for inst in insts:
|
for inst in insts:
|
||||||
(mnem, mode) = inst
|
(mnem, mode) = inst
|
||||||
if mnem not in result:
|
if mnem not in result:
|
||||||
result[mnem] = [None] * len(modes)
|
result[mnem] = [None] * len(modes)
|
||||||
if result[mnem][mode] is not None:
|
if result[mnem][mode] is not None:
|
||||||
print "Warning: Reassigning %s - %s" % (mnem, modes[mode])
|
print("Warning: Reassigning %s - %s" % (mnem, modes[mode]))
|
||||||
result[mnem][mode] = opcode
|
result[mnem][mode] = opcode
|
||||||
if base is not None:
|
if base is not None:
|
||||||
todel = []
|
todel = []
|
||||||
@ -127,9 +127,9 @@ def collate_chipset_map(cs_list, base):
|
|||||||
if result[x] == base[x]:
|
if result[x] == base[x]:
|
||||||
todel.append(x)
|
todel.append(x)
|
||||||
elif verbose != 0:
|
elif verbose != 0:
|
||||||
print "# Opcode %s changed" % x
|
print("# Opcode %s changed" % x)
|
||||||
elif verbose != 0:
|
elif verbose != 0:
|
||||||
print "# Opcode %s added" % x
|
print("# Opcode %s added" % x)
|
||||||
for x in todel:
|
for x in todel:
|
||||||
del result[x]
|
del result[x]
|
||||||
return result
|
return result
|
||||||
@ -143,14 +143,14 @@ def mapval(x):
|
|||||||
|
|
||||||
|
|
||||||
def dump_map(m, prologue=''):
|
def dump_map(m, prologue=''):
|
||||||
mnems = m.keys()
|
mnems = list(m.keys())
|
||||||
mnems.sort()
|
mnems.sort()
|
||||||
for mnem in mnems:
|
for mnem in mnems:
|
||||||
codes = [mapval(x) for x in m[mnem]]
|
codes = [mapval(x) for x in m[mnem]]
|
||||||
print "%s'%s': [%s,\n%s %s]," % (prologue, mnem,
|
print("%s'%s': [%s,\n%s %s]," % (prologue, mnem,
|
||||||
', '.join(codes[:8]),
|
', '.join(codes[:8]),
|
||||||
prologue + " " * len(mnem),
|
prologue + " " * len(mnem),
|
||||||
', '.join(codes[8:]))
|
', '.join(codes[8:])))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
@ -165,18 +165,18 @@ if __name__ == '__main__':
|
|||||||
for y in [z.split(':', 1) for z in decomment_readlines(x)]]
|
for y in [z.split(':', 1) for z in decomment_readlines(x)]]
|
||||||
for l in ls:
|
for l in ls:
|
||||||
if len(l) != 2:
|
if len(l) != 2:
|
||||||
print "Could not parse the chipset line '%s'" % ":".join(l)
|
print("Could not parse the chipset line '%s'" % ":".join(l))
|
||||||
else:
|
else:
|
||||||
archs.append((l[0], l[1]))
|
archs.append((l[0], l[1]))
|
||||||
except IOError:
|
except IOError:
|
||||||
print "Could not read file %s" % x
|
print("Could not read file %s" % x)
|
||||||
print prologue
|
print(prologue)
|
||||||
baseset = None
|
baseset = None
|
||||||
for (field, fname) in archs:
|
for (field, fname) in archs:
|
||||||
chipset_list = parse_chipset_file(fname)
|
chipset_list = parse_chipset_file(fname)
|
||||||
instruction_map = collate_chipset_map(chipset_list, baseset)
|
instruction_map = collate_chipset_map(chipset_list, baseset)
|
||||||
if baseset is None:
|
if baseset is None:
|
||||||
baseset = instruction_map
|
baseset = instruction_map
|
||||||
print "%s = {" % field
|
print("%s = {" % field)
|
||||||
dump_map(instruction_map, ' ' * (len(field) + 4))
|
dump_map(instruction_map, ' ' * (len(field) + 4))
|
||||||
print "%s}" % (' ' * (len(field) + 3))
|
print("%s}" % (' ' * (len(field) + 3)))
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import subprocess
|
import subprocess
|
||||||
@ -20,14 +20,14 @@ failed = 0
|
|||||||
|
|
||||||
|
|
||||||
def assembled(raw):
|
def assembled(raw):
|
||||||
return ' '.join(["%02X" % ord(c) for c in raw])
|
return ' '.join(["%02X" % c for c in raw])
|
||||||
|
|
||||||
|
|
||||||
def assemble_raw(asm="", options=[]):
|
def assemble_raw(asm="", options=[]):
|
||||||
p = subprocess.Popen([pythonpath, ophispath] + options,
|
p = subprocess.Popen([pythonpath, ophispath] + options,
|
||||||
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE)
|
stderr=subprocess.PIPE)
|
||||||
return p.communicate(asm)
|
return p.communicate(asm.encode("UTF-8"))
|
||||||
|
|
||||||
|
|
||||||
def assemble_string(asm, options=[]):
|
def assemble_string(asm, options=[]):
|
||||||
@ -37,15 +37,15 @@ def assemble_string(asm, options=[]):
|
|||||||
def test_string(test_name, asm, expected, options=[]):
|
def test_string(test_name, asm, expected, options=[]):
|
||||||
(out, err) = assemble_string(asm, options)
|
(out, err) = assemble_string(asm, options)
|
||||||
if out == expected:
|
if out == expected:
|
||||||
print "%s: SUCCESS" % test_name
|
print("%s: SUCCESS" % test_name)
|
||||||
else:
|
else:
|
||||||
global failed
|
global failed
|
||||||
failed += 1
|
failed += 1
|
||||||
print "%s: FAILED" % test_name
|
print("%s: FAILED" % test_name)
|
||||||
print "Assembled code: ", assembled(out)
|
print("Assembled code: ", assembled(out))
|
||||||
print "Expected code: ", assembled(expected)
|
print("Expected code: ", assembled(expected))
|
||||||
if err != '':
|
if err != '':
|
||||||
print "Error output:\n%s" % err
|
print("Error output:\n%s" % err.decode(sys.stderr.encoding))
|
||||||
|
|
||||||
|
|
||||||
def test_file(test_name, fname, ename, options=[]):
|
def test_file(test_name, fname, ename, options=[]):
|
||||||
@ -57,7 +57,7 @@ def test_file(test_name, fname, ename, options=[]):
|
|||||||
expected = f.read()
|
expected = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
else: # a test where we expect failure
|
else: # a test where we expect failure
|
||||||
expected = ''
|
expected = b''
|
||||||
test_string(test_name, asm, expected, options)
|
test_string(test_name, asm, expected, options)
|
||||||
|
|
||||||
|
|
||||||
@ -66,16 +66,16 @@ def test_file(test_name, fname, ename, options=[]):
|
|||||||
# on, then we start running through the features.
|
# on, then we start running through the features.
|
||||||
|
|
||||||
def test_basic():
|
def test_basic():
|
||||||
print
|
print()
|
||||||
print "==== BASIC OPERATION ===="
|
print("==== BASIC OPERATION ====")
|
||||||
test_string('Basic Ophis operation', '.byte "Hello, world!"',
|
test_string('Basic Ophis operation', '.byte "Hello, world!"',
|
||||||
'Hello, world!')
|
b'Hello, world!')
|
||||||
test_string('Newline/EOF passthrough', '.byte 10,26,13,4,0,"Hi",13,10',
|
test_string('Newline/EOF passthrough', '.byte 10,26,13,4,0,"Hi",13,10',
|
||||||
'\n\x1a\r\x04\x00Hi\r\n')
|
b'\n\x1a\r\x04\x00Hi\r\n')
|
||||||
# Normally these would go in Expressions but we need them to run the
|
# Normally these would go in Expressions but we need them to run the
|
||||||
# tests for relative instructions.
|
# tests for relative instructions.
|
||||||
test_string('Program counter recognition', '.org $41\nlda #^\n', '\xa9A')
|
test_string('Program counter recognition', '.org $41\nlda #^\n', b'\xa9A')
|
||||||
test_string('Program counter math', '.org $41\nlda #^+3\n', '\xa9D')
|
test_string('Program counter math', '.org $41\nlda #^+3\n', b'\xa9D')
|
||||||
if failed == 0:
|
if failed == 0:
|
||||||
test_file('Basic instructions', 'testbase.oph', 'testbase.bin')
|
test_file('Basic instructions', 'testbase.oph', 'testbase.bin')
|
||||||
test_file('Basic data pragmas', 'testdata.oph', 'testdata.bin')
|
test_file('Basic data pragmas', 'testdata.oph', 'testdata.bin')
|
||||||
@ -100,13 +100,13 @@ def test_basic():
|
|||||||
|
|
||||||
def test_outfile():
|
def test_outfile():
|
||||||
global failed
|
global failed
|
||||||
print "\n==== INPUT AND OUTPUT ===="
|
print("\n==== INPUT AND OUTPUT ====")
|
||||||
if os.path.exists("ophis.bin"):
|
if os.path.exists("ophis.bin"):
|
||||||
print "TEST SUITE FAILED: unclean test environment (ophis.bin exists)"
|
print("TEST SUITE FAILED: unclean test environment (ophis.bin exists)")
|
||||||
failed += 1
|
failed += 1
|
||||||
return
|
return
|
||||||
elif os.path.exists("custom.bin"):
|
elif os.path.exists("custom.bin"):
|
||||||
print "TEST SUITE FAILED: unclean test environment (custom.bin exists)"
|
print("TEST SUITE FAILED: unclean test environment (custom.bin exists)")
|
||||||
failed += 1
|
failed += 1
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -114,45 +114,46 @@ def test_outfile():
|
|||||||
try:
|
try:
|
||||||
assemble_raw('.byte "Hello, world!", 10', ['-'])
|
assemble_raw('.byte "Hello, world!", 10', ['-'])
|
||||||
f = open('ophis.bin', 'rb')
|
f = open('ophis.bin', 'rb')
|
||||||
if f.read() != 'Hello, world!\n':
|
if f.read() != b'Hello, world!\n':
|
||||||
print "Default output filename: FAILED (bad output)"
|
print("Default output filename: FAILED (bad output)")
|
||||||
failed += 1
|
failed += 1
|
||||||
else:
|
else:
|
||||||
print "Default output filename: SUCCESS"
|
print("Default output filename: SUCCESS")
|
||||||
f.close()
|
f.close()
|
||||||
os.unlink('ophis.bin')
|
os.unlink('ophis.bin')
|
||||||
except:
|
except:
|
||||||
print "Default output filename: FAILED (exception)"
|
print("Default output filename: FAILED (exception)")
|
||||||
failed += 1
|
failed += 1
|
||||||
|
raise
|
||||||
|
|
||||||
# Test 2: Command line override
|
# Test 2: Command line override
|
||||||
try:
|
try:
|
||||||
assemble_raw('.byte "Hello, world!", 10', ['-', '-o', 'custom.bin'])
|
assemble_raw('.byte "Hello, world!", 10', ['-', '-o', 'custom.bin'])
|
||||||
f = open('custom.bin', 'rb')
|
f = open('custom.bin', 'rb')
|
||||||
if f.read() != 'Hello, world!\n':
|
if f.read() != b'Hello, world!\n':
|
||||||
print "Commandline output filename: FAILED (bad output)"
|
print("Commandline output filename: FAILED (bad output)")
|
||||||
failed += 1
|
failed += 1
|
||||||
else:
|
else:
|
||||||
print "Commandline output filename: SUCCESS"
|
print("Commandline output filename: SUCCESS")
|
||||||
f.close()
|
f.close()
|
||||||
os.unlink('custom.bin')
|
os.unlink('custom.bin')
|
||||||
except:
|
except:
|
||||||
print "Commandline output filename: FAILED (exception)"
|
print("Commandline output filename: FAILED (exception)")
|
||||||
failed += 1
|
failed += 1
|
||||||
|
|
||||||
# Test 3: Pragma override
|
# Test 3: Pragma override
|
||||||
try:
|
try:
|
||||||
assemble_raw('.outfile "custom.bin"\n.byte "Hello, world!", 10', ['-'])
|
assemble_raw('.outfile "custom.bin"\n.byte "Hello, world!", 10', ['-'])
|
||||||
f = open('custom.bin', 'rb')
|
f = open('custom.bin', 'rb')
|
||||||
if f.read() != 'Hello, world!\n':
|
if f.read() != b'Hello, world!\n':
|
||||||
print "Commandline output filename: FAILED (bad output)"
|
print("Commandline output filename: FAILED (bad output)")
|
||||||
failed += 1
|
failed += 1
|
||||||
else:
|
else:
|
||||||
print "Commandline output filename: SUCCESS"
|
print("Commandline output filename: SUCCESS")
|
||||||
f.close()
|
f.close()
|
||||||
os.unlink('custom.bin')
|
os.unlink('custom.bin')
|
||||||
except:
|
except:
|
||||||
print "Commandline output filename: FAILED (exception)"
|
print("Commandline output filename: FAILED (exception)")
|
||||||
failed += 1
|
failed += 1
|
||||||
|
|
||||||
# Test 4: Command line override of .outfile
|
# Test 4: Command line override of .outfile
|
||||||
@ -160,15 +161,15 @@ def test_outfile():
|
|||||||
assemble_raw('.outfile "custom2.bin"\n'
|
assemble_raw('.outfile "custom2.bin"\n'
|
||||||
'.byte "Hello, world!", 10', ['-', '-o', 'custom.bin'])
|
'.byte "Hello, world!", 10', ['-', '-o', 'custom.bin'])
|
||||||
f = open('custom.bin', 'rb')
|
f = open('custom.bin', 'rb')
|
||||||
if f.read() != 'Hello, world!\n':
|
if f.read() != b'Hello, world!\n':
|
||||||
print "Commandline override of pragma: FAILED (bad output)"
|
print("Commandline override of pragma: FAILED (bad output)")
|
||||||
failed += 1
|
failed += 1
|
||||||
else:
|
else:
|
||||||
print "Commandline override of pragma: SUCCESS"
|
print("Commandline override of pragma: SUCCESS")
|
||||||
f.close()
|
f.close()
|
||||||
os.unlink('custom.bin')
|
os.unlink('custom.bin')
|
||||||
except:
|
except:
|
||||||
print "Commandline override of pragma: FAILED (exception)"
|
print("Commandline override of pragma: FAILED (exception)")
|
||||||
failed += 1
|
failed += 1
|
||||||
|
|
||||||
# Test 5: Pragma repetition priority
|
# Test 5: Pragma repetition priority
|
||||||
@ -177,15 +178,15 @@ def test_outfile():
|
|||||||
'.outfile "custom2.bin"\n'
|
'.outfile "custom2.bin"\n'
|
||||||
'.byte "Hello, world!", 10', ['-'])
|
'.byte "Hello, world!", 10', ['-'])
|
||||||
f = open('custom.bin', 'rb')
|
f = open('custom.bin', 'rb')
|
||||||
if f.read() != 'Hello, world!\n':
|
if f.read() != b'Hello, world!\n':
|
||||||
print "Pragma repetition: FAILED (bad output)"
|
print("Pragma repetition: FAILED (bad output)")
|
||||||
failed += 1
|
failed += 1
|
||||||
else:
|
else:
|
||||||
print "Pragma repetition: SUCCESS"
|
print("Pragma repetition: SUCCESS")
|
||||||
f.close()
|
f.close()
|
||||||
os.unlink('custom.bin')
|
os.unlink('custom.bin')
|
||||||
except:
|
except:
|
||||||
print "Pragma repetition: FAILED (exception)"
|
print("Pragma repetition: FAILED (exception)")
|
||||||
failed += 1
|
failed += 1
|
||||||
|
|
||||||
# Test 6: multiple input files
|
# Test 6: multiple input files
|
||||||
@ -200,73 +201,73 @@ def test_outfile():
|
|||||||
s += f.read()
|
s += f.read()
|
||||||
f.close()
|
f.close()
|
||||||
if out != s:
|
if out != s:
|
||||||
print "Multiple input files: FAILED (bad output)"
|
print("Multiple input files: FAILED (bad output)")
|
||||||
failed += 1
|
failed += 1
|
||||||
else:
|
else:
|
||||||
print "Multiple input files: SUCCESS"
|
print("Multiple input files: SUCCESS")
|
||||||
except:
|
except:
|
||||||
print "Multiple input files: FAILED (exception)"
|
print("Multiple input files: FAILED (exception)")
|
||||||
failed += 1
|
failed += 1
|
||||||
|
|
||||||
|
|
||||||
def test_transforms():
|
def test_transforms():
|
||||||
print "\n==== BINARY TRANSFORM PASSES ===="
|
print("\n==== BINARY TRANSFORM PASSES ====")
|
||||||
print "Simple zero page selection: SUCCESS (covered in basic tests)"
|
print("Simple zero page selection: SUCCESS (covered in basic tests)")
|
||||||
test_string('Chained collapse', '.org $fa \n lda + \n lda ^ \n * rts \n',
|
test_string('Chained collapse', '.org $fa \n lda + \n lda ^ \n * rts \n',
|
||||||
'\xa5\xfe\xa5\xfc\x60')
|
b'\xa5\xfe\xa5\xfc\x60')
|
||||||
test_string('Reversible collapse', '.org $fb \n bne ^+200 \n lda ^ \n',
|
test_string('Reversible collapse', '.org $fb \n bne ^+200 \n lda ^ \n',
|
||||||
'\xf0\x03\x4c\xc5\x01\xad\x00\x01')
|
b'\xf0\x03\x4c\xc5\x01\xad\x00\x01')
|
||||||
|
|
||||||
|
|
||||||
def test_expressions():
|
def test_expressions():
|
||||||
print "\n==== EXPRESSIONS AND LABELS ===="
|
print("\n==== EXPRESSIONS AND LABELS ====")
|
||||||
test_string('Basic addition', '.byte 3+2', '\x05')
|
test_string('Basic addition', '.byte 3+2', b'\x05')
|
||||||
test_string('Basic subtraction', '.byte 3-2', '\x01')
|
test_string('Basic subtraction', '.byte 3-2', b'\x01')
|
||||||
test_string('Basic multiplication', '.byte 3*2', '\x06')
|
test_string('Basic multiplication', '.byte 3*2', b'\x06')
|
||||||
test_string('Basic division', '.byte 6/2', '\x03')
|
test_string('Basic division', '.byte 6/2', b'\x03')
|
||||||
test_string('Basic bit-union', '.byte 5|9', '\x0d')
|
test_string('Basic bit-union', '.byte 5|9', b'\x0d')
|
||||||
test_string('Basic bit-intersection', '.byte 5&9', '\x01')
|
test_string('Basic bit-intersection', '.byte 5&9', b'\x01')
|
||||||
test_string('Basic bit-toggle', '.byte 5^9', '\x0c')
|
test_string('Basic bit-toggle', '.byte 5^9', b'\x0c')
|
||||||
test_string('Division truncation', '.byte 5/2', '\x02')
|
test_string('Division truncation', '.byte 5/2', b'\x02')
|
||||||
test_string('Overflow', '.byte $FF*$10', '')
|
test_string('Overflow', '.byte $FF*$10', b'')
|
||||||
test_string('Multibyte overflow', '.word $FF*$10', '\xf0\x0f')
|
test_string('Multibyte overflow', '.word $FF*$10', b'\xf0\x0f')
|
||||||
test_string('Masked overflow', '.byte $FF*$10&$FF', '\xf0')
|
test_string('Masked overflow', '.byte $FF*$10&$FF', b'\xf0')
|
||||||
test_string('Underflow', '.byte 2-3', '')
|
test_string('Underflow', '.byte 2-3', b'')
|
||||||
test_string('Masked underflow', '.byte 2-3&$FF', '\xff')
|
test_string('Masked underflow', '.byte 2-3&$FF', b'\xff')
|
||||||
test_string('Arithmetic precedence', '.byte 2+3*4-6/2', '\x0b')
|
test_string('Arithmetic precedence', '.byte 2+3*4-6/2', b'\x0b')
|
||||||
test_string('Parentheses', '.byte [2+3]*[4-6/2]', '\x05')
|
test_string('Parentheses', '.byte [2+3]*[4-6/2]', b'\x05')
|
||||||
test_string('String escapes',
|
test_string('String escapes',
|
||||||
'.byte "The man said, \\"The \\\\ is Windowsy.\\""',
|
'.byte "The man said, \\"The \\\\ is Windowsy.\\""',
|
||||||
'The man said, "The \\ is Windowsy."')
|
b'The man said, "The \\ is Windowsy."')
|
||||||
test_string('Byte selector precedence',
|
test_string('Byte selector precedence',
|
||||||
'.byte >$d000+32,>[$d000+32],<[$D000-275]',
|
'.byte >$d000+32,>[$d000+32],<[$D000-275]',
|
||||||
'\xf0\xd0\xed')
|
b'\xf0\xd0\xed')
|
||||||
test_string('Named labels', '.org $6948\nl: .word l', 'Hi')
|
test_string('Named labels', '.org $6948\nl: .word l', b'Hi')
|
||||||
test_string('.alias directive (basic)', '.alias hi $6948\n.word hi', 'Hi')
|
test_string('.alias directive (basic)', '.alias hi $6948\n.word hi', b'Hi')
|
||||||
test_string('.alias directive (derived)',
|
test_string('.alias directive (derived)',
|
||||||
'.alias hi $6948\n.alias ho hi+$600\n.word hi,ho', 'HiHo')
|
'.alias hi $6948\n.alias ho hi+$600\n.word hi,ho', b'HiHo')
|
||||||
test_string('.alias directive (circular)',
|
test_string('.alias directive (circular)',
|
||||||
'.alias a c+1\n.alias b a+3\n.alias c b-4\n.word a, b, c',
|
'.alias a c+1\n.alias b a+3\n.alias c b-4\n.word a, b, c',
|
||||||
'')
|
b'')
|
||||||
test_string('.advance directive (basic)',
|
test_string('.advance directive (basic)',
|
||||||
'lda #$05\n.advance $05\n.byte ^',
|
'lda #$05\n.advance $05\n.byte ^',
|
||||||
'\xa9\x05\x00\x00\x00\x05')
|
b'\xa9\x05\x00\x00\x00\x05')
|
||||||
test_string('.advance directive (filler)',
|
test_string('.advance directive (filler)',
|
||||||
'lda #$05\nf: .advance $05,f+3\n.byte ^',
|
'lda #$05\nf: .advance $05,f+3\n.byte ^',
|
||||||
'\xa9\x05\x05\x05\x05\x05')
|
b'\xa9\x05\x05\x05\x05\x05')
|
||||||
test_string('.advance no-op', 'lda #$05\n.advance $02\n.byte ^',
|
test_string('.advance no-op', 'lda #$05\n.advance $02\n.byte ^',
|
||||||
'\xa9\x05\x02')
|
b'\xa9\x05\x02')
|
||||||
test_string('.advance failure', 'lda #$05\n.advance $01\n.byte ^', '')
|
test_string('.advance failure', 'lda #$05\n.advance $01\n.byte ^', b'')
|
||||||
test_string('.checkpc, space > 0', 'lda #$05\n.checkpc $10', '\xa9\x05')
|
test_string('.checkpc, space > 0', 'lda #$05\n.checkpc $10', b'\xa9\x05')
|
||||||
test_string('.checkpc, space = 0', 'lda #$05\n.checkpc 2', '\xa9\x05')
|
test_string('.checkpc, space = 0', 'lda #$05\n.checkpc 2', b'\xa9\x05')
|
||||||
test_string('.checkpc, space < 0', 'lda $05\n.checkpc 1', '')
|
test_string('.checkpc, space < 0', 'lda $05\n.checkpc 1', b'')
|
||||||
test_string('A X Y usable as labels',
|
test_string('A X Y usable as labels',
|
||||||
'.alias a 1\n.alias x 2\n.alias y 3\n'
|
'.alias a 1\n.alias x 2\n.alias y 3\n'
|
||||||
'lda (a+x+y),y\nlda (x+y,x)',
|
'lda (a+x+y),y\nlda (x+y,x)',
|
||||||
'\xb1\x06\xa1\x05')
|
b'\xb1\x06\xa1\x05')
|
||||||
test_string('Opcodes usable as labels',
|
test_string('Opcodes usable as labels',
|
||||||
'ldy #$00\n dey: dey\n bne dey',
|
'ldy #$00\n dey: dey\n bne dey',
|
||||||
'\xa0\x00\x88\xd0\xfd')
|
b'\xa0\x00\x88\xd0\xfd')
|
||||||
|
|
||||||
|
|
||||||
def test_segments():
|
def test_segments():
|
||||||
@ -277,18 +278,18 @@ def test_segments():
|
|||||||
'.org $61\n'
|
'.org $61\n'
|
||||||
'd:\n'
|
'd:\n'
|
||||||
'.text\n'
|
'.text\n'
|
||||||
'l: .byte l, d', 'Aa')
|
'l: .byte l, d', b'Aa')
|
||||||
test_string('Data cleanliness', '.byte 65\n.data\n.byte 65', '')
|
test_string('Data cleanliness', '.byte 65\n.data\n.byte 65', b'')
|
||||||
test_string('.space directive',
|
test_string('.space directive',
|
||||||
'.data\n.org $41\n.space a 2\n.space b 1\n.space c 1\n'
|
'.data\n.org $41\n.space a 2\n.space b 1\n.space c 1\n'
|
||||||
'.text\n.byte a, b, c\n', 'ACD')
|
'.text\n.byte a, b, c\n', b'ACD')
|
||||||
test_string('Multiple named segments',
|
test_string('Multiple named segments',
|
||||||
'.data\n.org $41\n.data a\n.org $61\n.data b\n.org $4a\n'
|
'.data\n.org $41\n.data a\n.org $61\n.data b\n.org $4a\n'
|
||||||
'.data\n.space q 1\n.data a\n.space r 1\n.data b\n.space s 1\n'
|
'.data\n.space q 1\n.data a\n.space r 1\n.data b\n.space s 1\n'
|
||||||
'.text\n.org $10\n.text a\n.org $20\n'
|
'.text\n.org $10\n.text a\n.org $20\n'
|
||||||
'.text\n.byte ^,q,r,s\n'
|
'.text\n.byte ^,q,r,s\n'
|
||||||
'.text a\n.byte ^,q,r,s\n',
|
'.text a\n.byte ^,q,r,s\n',
|
||||||
'\x10AaJ\x20AaJ')
|
b'\x10AaJ\x20AaJ')
|
||||||
|
|
||||||
|
|
||||||
def test_scopes():
|
def test_scopes():
|
||||||
@ -300,13 +301,13 @@ def test_scopes():
|
|||||||
'.scend\n'
|
'.scend\n'
|
||||||
'.scope\n'
|
'.scope\n'
|
||||||
'_l: .byte _l\n'
|
'_l: .byte _l\n'
|
||||||
'.scend\n', 'AB')
|
'.scend\n', b'AB')
|
||||||
test_string('Data hiding outside of scope',
|
test_string('Data hiding outside of scope',
|
||||||
'.org $41\n'
|
'.org $41\n'
|
||||||
'.scope\n'
|
'.scope\n'
|
||||||
'_l: .byte _l\n'
|
'_l: .byte _l\n'
|
||||||
'.scend\n'
|
'.scend\n'
|
||||||
' .byte _l\n', '')
|
' .byte _l\n', b'')
|
||||||
test_string('Repeated labels, nested scopes',
|
test_string('Repeated labels, nested scopes',
|
||||||
'.org $41\n'
|
'.org $41\n'
|
||||||
'.scope\n'
|
'.scope\n'
|
||||||
@ -315,17 +316,17 @@ def test_scopes():
|
|||||||
'_l: .byte _l\n'
|
'_l: .byte _l\n'
|
||||||
'.scend\n'
|
'.scend\n'
|
||||||
' .byte _l\n'
|
' .byte _l\n'
|
||||||
'.scend\n', 'ABA')
|
'.scend\n', b'ABA')
|
||||||
test_string('Anonymous labels (basic)',
|
test_string('Anonymous labels (basic)',
|
||||||
'.org $41\n'
|
'.org $41\n'
|
||||||
'* .byte -, +\n'
|
'* .byte -, +\n'
|
||||||
'* .byte -, --\n', 'ACCA')
|
'* .byte -, --\n', b'ACCA')
|
||||||
test_string('Anonymous labels (across scopes)',
|
test_string('Anonymous labels (across scopes)',
|
||||||
'.org $41\n'
|
'.org $41\n'
|
||||||
'* .byte -, +\n'
|
'* .byte -, +\n'
|
||||||
'.scope\n'
|
'.scope\n'
|
||||||
'* .byte -, --\n'
|
'* .byte -, --\n'
|
||||||
'.scend\n', 'ACCA')
|
'.scend\n', b'ACCA')
|
||||||
|
|
||||||
|
|
||||||
def test_macros():
|
def test_macros():
|
||||||
@ -334,12 +335,12 @@ def test_macros():
|
|||||||
'.macro greet\n'
|
'.macro greet\n'
|
||||||
' .byte "hi"\n'
|
' .byte "hi"\n'
|
||||||
'.macend\n'
|
'.macend\n'
|
||||||
'`greet\n.invoke greet', "hihi")
|
'`greet\n.invoke greet', b"hihi")
|
||||||
test_string('Macros with arguments',
|
test_string('Macros with arguments',
|
||||||
'.macro greet\n'
|
'.macro greet\n'
|
||||||
' .byte "hi",_1\n'
|
' .byte "hi",_1\n'
|
||||||
'.macend\n'
|
'.macend\n'
|
||||||
"`greet 'A\n.invoke greet 'B", "hiAhiB")
|
"`greet 'A\n.invoke greet 'B", b"hiAhiB")
|
||||||
test_string('Macros invoking macros',
|
test_string('Macros invoking macros',
|
||||||
'.macro inner\n'
|
'.macro inner\n'
|
||||||
' .byte " there"\n'
|
' .byte " there"\n'
|
||||||
@ -348,7 +349,7 @@ def test_macros():
|
|||||||
' .byte "hi"\n'
|
' .byte "hi"\n'
|
||||||
' `inner\n'
|
' `inner\n'
|
||||||
'.macend\n'
|
'.macend\n'
|
||||||
"`greet", "hi there")
|
"`greet", b"hi there")
|
||||||
test_string('Macros defining macros (illegal)',
|
test_string('Macros defining macros (illegal)',
|
||||||
'.macro greet\n'
|
'.macro greet\n'
|
||||||
'.macro inner\n'
|
'.macro inner\n'
|
||||||
@ -357,7 +358,7 @@ def test_macros():
|
|||||||
' .byte "hi"\n'
|
' .byte "hi"\n'
|
||||||
' `inner\n'
|
' `inner\n'
|
||||||
'.macend\n'
|
'.macend\n'
|
||||||
"`greet", "")
|
"`greet", b"")
|
||||||
test_string('Fail on infinite recursion',
|
test_string('Fail on infinite recursion',
|
||||||
'.macro inner\n'
|
'.macro inner\n'
|
||||||
' .byte " there"\n'
|
' .byte " there"\n'
|
||||||
@ -367,75 +368,75 @@ def test_macros():
|
|||||||
' .byte "hi"\n'
|
' .byte "hi"\n'
|
||||||
' `inner\n'
|
' `inner\n'
|
||||||
'.macend\n'
|
'.macend\n'
|
||||||
"`greet", "")
|
"`greet", b"")
|
||||||
|
|
||||||
|
|
||||||
def test_subfiles():
|
def test_subfiles():
|
||||||
print("\n==== COMPILATION UNITS ====")
|
print("\n==== COMPILATION UNITS ====")
|
||||||
test_string(".include pragma", '.include "baseinc.oph"', 'BASIC\n')
|
test_string(".include pragma", '.include "baseinc.oph"', b'BASIC\n')
|
||||||
test_string(".include repeated",
|
test_string(".include repeated",
|
||||||
'.include "baseinc.oph"\n.include "baseinc.oph"',
|
'.include "baseinc.oph"\n.include "baseinc.oph"',
|
||||||
'BASIC\nBASIC\n')
|
b'BASIC\nBASIC\n')
|
||||||
test_string(".require pragma", '.require "baseinc.oph"', 'BASIC\n')
|
test_string(".require pragma", '.require "baseinc.oph"', b'BASIC\n')
|
||||||
test_string(".include before .require",
|
test_string(".include before .require",
|
||||||
'.include "baseinc.oph"\n.require "baseinc.oph"',
|
'.include "baseinc.oph"\n.require "baseinc.oph"',
|
||||||
'BASIC\n')
|
b'BASIC\n')
|
||||||
test_string(".require before .include",
|
test_string(".require before .include",
|
||||||
'.require "baseinc.oph"\n.include "baseinc.oph"',
|
'.require "baseinc.oph"\n.include "baseinc.oph"',
|
||||||
'BASIC\nBASIC\n')
|
b'BASIC\nBASIC\n')
|
||||||
test_string(".require same file twice with different paths",
|
test_string(".require same file twice with different paths",
|
||||||
'.include "baseinc.oph"\n.include "sub/baseinc.oph"',
|
'.include "baseinc.oph"\n.include "sub/baseinc.oph"',
|
||||||
'BASIC\nSUB 1 START\nSUB 1 END\n')
|
b'BASIC\nSUB 1 START\nSUB 1 END\n')
|
||||||
test_string(".require different files with identical paths",
|
test_string(".require different files with identical paths",
|
||||||
'.include "sub/sub/sub.oph"',
|
'.include "sub/sub/sub.oph"',
|
||||||
'SUB 2 START\nSUB 1 START\nBASIC\nSUB 1 END\nSUB 2 END\n')
|
b'SUB 2 START\nSUB 1 START\nBASIC\nSUB 1 END\nSUB 2 END\n')
|
||||||
test_string(".charmap (basic)",
|
test_string(".charmap (basic)",
|
||||||
'.charmap \'A, "abcdefghijklmnopqrstuvwxyz"\n'
|
'.charmap \'A, "abcdefghijklmnopqrstuvwxyz"\n'
|
||||||
'.charmap \'a, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"\n'
|
'.charmap \'a, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"\n'
|
||||||
'.byte "hELLO, wORLD!"', "Hello, World!")
|
'.byte "hELLO, wORLD!"', b"Hello, World!")
|
||||||
test_string(".charmap (reset)",
|
test_string(".charmap (reset)",
|
||||||
'.charmap \'A, "abcdefghijklmnopqrstuvwxyz"\n'
|
'.charmap \'A, "abcdefghijklmnopqrstuvwxyz"\n'
|
||||||
'.charmap \'a, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"\n'
|
'.charmap \'a, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"\n'
|
||||||
'.byte "hELLO, wORLD!",10\n'
|
'.byte "hELLO, wORLD!",10\n'
|
||||||
'.charmap\n'
|
'.charmap\n'
|
||||||
'.byte "hELLO, wORLD!",10\n',
|
'.byte "hELLO, wORLD!",10\n',
|
||||||
"Hello, World!\nhELLO, wORLD!\n")
|
b"Hello, World!\nhELLO, wORLD!\n")
|
||||||
test_string(".charmap (out of range)",
|
test_string(".charmap (out of range)",
|
||||||
'.charmap 250, "ABCDEFGHIJKLM"\n.byte 250,251',
|
'.charmap 250, "ABCDEFGHIJKLM"\n.byte 250,251',
|
||||||
'')
|
b'')
|
||||||
test_string(".charmapbin (basic)",
|
test_string(".charmapbin (basic)",
|
||||||
'.charmapbin "../examples/petscii.map"\n.byte "hELLO, wORLD!"',
|
'.charmapbin "../examples/petscii.map"\n.byte "hELLO, wORLD!"',
|
||||||
"Hello, World!")
|
b"Hello, World!")
|
||||||
test_string(".charmapbin (illegal)",
|
test_string(".charmapbin (illegal)",
|
||||||
'.charmapbin "baseinc.bin"\n.byte "hELLO, wORLD!"', '')
|
'.charmapbin "baseinc.bin"\n.byte "hELLO, wORLD!"', b'')
|
||||||
test_string(".incbin (basic)", '.incbin "baseinc.bin"', "BASIC\n")
|
test_string(".incbin (basic)", '.incbin "baseinc.bin"', b"BASIC\n")
|
||||||
test_string(".incbin (hardcoded offset)",
|
test_string(".incbin (hardcoded offset)",
|
||||||
'.incbin "baseinc.bin",3', "IC\n")
|
'.incbin "baseinc.bin",3', b"IC\n")
|
||||||
test_string(".incbin (hardcoded offset and length)",
|
test_string(".incbin (hardcoded offset and length)",
|
||||||
'.incbin "baseinc.bin",3,2', "IC")
|
'.incbin "baseinc.bin",3,2', b"IC")
|
||||||
test_string(".incbin (softcoded offset and length)",
|
test_string(".incbin (softcoded offset and length)",
|
||||||
'.alias off len+1\n.alias len 2\n'
|
'.alias off len+1\n.alias len 2\n'
|
||||||
'.incbin "baseinc.bin",off,len', "IC")
|
'.incbin "baseinc.bin",off,len', b"IC")
|
||||||
test_string(".incbin (length too long)",
|
test_string(".incbin (length too long)",
|
||||||
'.byte 65\n.incbin "baseinc.bin",3,4', "")
|
'.byte 65\n.incbin "baseinc.bin",3,4', b"")
|
||||||
test_string(".incbin (negative offset)",
|
test_string(".incbin (negative offset)",
|
||||||
'.byte 65\n.incbin "baseinc.bin",1-5,4', "")
|
'.byte 65\n.incbin "baseinc.bin",1-5,4', b"")
|
||||||
test_string(".incbin (offset = size)",
|
test_string(".incbin (offset = size)",
|
||||||
'.byte 65\n.incbin "baseinc.bin",6', "A")
|
'.byte 65\n.incbin "baseinc.bin",6', b"A")
|
||||||
test_string(".incbin (offset > size)",
|
test_string(".incbin (offset > size)",
|
||||||
'.byte 65\n.incbin "baseinc.bin",7', "")
|
'.byte 65\n.incbin "baseinc.bin",7', b"")
|
||||||
test_string(".incbin (softcoded length too long)",
|
test_string(".incbin (softcoded length too long)",
|
||||||
'.alias off len\n.alias len 4\n'
|
'.alias off len\n.alias len 4\n'
|
||||||
'.byte 65\n.incbin "baseinc.bin",off,len', "")
|
'.byte 65\n.incbin "baseinc.bin",off,len', b"")
|
||||||
test_string(".incbin (softcoded negative offset)",
|
test_string(".incbin (softcoded negative offset)",
|
||||||
'.alias off 1-5\n'
|
'.alias off 1-5\n'
|
||||||
'.byte 65\n.incbin "baseinc.bin",off,4', "")
|
'.byte 65\n.incbin "baseinc.bin",off,4', b"")
|
||||||
test_string(".incbin (softcoded offset = size)",
|
test_string(".incbin (softcoded offset = size)",
|
||||||
'.alias off 6\n'
|
'.alias off 6\n'
|
||||||
'.byte 65\n.incbin "baseinc.bin",off', "A")
|
'.byte 65\n.incbin "baseinc.bin",off', b"A")
|
||||||
test_string(".incbin (softcoded offset > size)",
|
test_string(".incbin (softcoded offset > size)",
|
||||||
'.alias off 7\n'
|
'.alias off 7\n'
|
||||||
'.byte 65\n.incbin "baseinc.bin",off', "")
|
'.byte 65\n.incbin "baseinc.bin",off', b"")
|
||||||
|
|
||||||
|
|
||||||
def test_systematic():
|
def test_systematic():
|
||||||
@ -449,18 +450,18 @@ def test_systematic():
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
print "Using Python interpreter:", pythonpath
|
print("Using Python interpreter:", pythonpath)
|
||||||
|
|
||||||
test_basic()
|
test_basic()
|
||||||
os.chdir(os.path.dirname(os.path.realpath(sys.argv[0])))
|
os.chdir(os.path.dirname(os.path.realpath(sys.argv[0])))
|
||||||
if failed == 0:
|
if failed == 0:
|
||||||
test_systematic()
|
test_systematic()
|
||||||
else:
|
else:
|
||||||
print "\nBasic test cases failed, aborting test."
|
print("\nBasic test cases failed, aborting test.")
|
||||||
|
|
||||||
if failed > 0:
|
if failed > 0:
|
||||||
print "\nTotal test case failures: %d" % failed
|
print("\nTotal test case failures: %d" % failed)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
else:
|
else:
|
||||||
print "\nAll test cases succeeded"
|
print("\nAll test cases succeeded")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user