mirror of
https://github.com/michaelcmartin/Ophis.git
synced 2024-10-12 15:23:38 +00:00
Improve .incbin to let its arguments be arbitrary expressions
This introduces a new IR node for mutable-during-assembly ranges. In the common case, where offset and range are hardcoded or missing, it continues with the older, more efficient behavior.
This commit is contained in:
parent
9ea0962e52
commit
9323067e91
@ -53,26 +53,43 @@ def pragmaRequire(ppt, line, result):
|
||||
def pragmaIncbin(ppt, line, result):
|
||||
"Includes a binary file"
|
||||
filename = line.expect("STRING").value
|
||||
offset = 0
|
||||
size = -1
|
||||
offset = IR.ConstantExpr(0)
|
||||
size = None
|
||||
if str(line.lookahead(0)) == ",":
|
||||
line.pop()
|
||||
offset = line.expect("NUM").value
|
||||
offset = FE.parse_expr(line)
|
||||
if str(line.lookahead(0)) == ",":
|
||||
line.pop()
|
||||
size = line.expect("NUM").value
|
||||
size = FE.parse_expr(line)
|
||||
line.expect("EOL")
|
||||
if type(filename) == str:
|
||||
try:
|
||||
f = file(os.path.join(FE.context_directory, filename), "rb")
|
||||
f.seek(offset)
|
||||
bytes = f.read(size)
|
||||
if offset.hardcoded and (size is None or size.hardcoded):
|
||||
# We know how big it will be, we can just use the values.
|
||||
if size is None:
|
||||
size = IR.ConstantExpr(-1)
|
||||
f.seek(offset.value())
|
||||
bytes = f.read(size.value())
|
||||
bytes = [IR.ConstantExpr(ord(x)) for x in bytes]
|
||||
result.append(IR.Node(ppt, "Byte", *bytes))
|
||||
else:
|
||||
# offset or length could change based on label placement.
|
||||
# This seems like an unbelievably bad idea, but since we
|
||||
# don't have constant prop it will happen for any symbolic
|
||||
# alias. Don't use symbolic aliases when extracting tiny
|
||||
# pieces out of humongous files, I guess.
|
||||
bytes = f.read()
|
||||
bytes = [IR.ConstantExpr(ord(x)) for x in bytes]
|
||||
if size is None:
|
||||
size = IR.SequenceExpr([IR.ConstantExpr(len(bytes)),
|
||||
"-",
|
||||
offset])
|
||||
result.append(IR.Node(ppt, "ByteRange", offset, size, *bytes))
|
||||
f.close()
|
||||
except IOError:
|
||||
Err.log("Could not read " + filename)
|
||||
return
|
||||
bytes = [IR.ConstantExpr(ord(x)) for x in bytes]
|
||||
result.append(IR.Node(ppt, "Byte", *bytes))
|
||||
|
||||
|
||||
def pragmaCharmap(ppt, line, result):
|
||||
|
@ -366,6 +366,10 @@ class PCTracker(Pass):
|
||||
def visitByte(self, node, env):
|
||||
env.incPC(len(node.data))
|
||||
|
||||
def visitByteRange(self, node, env):
|
||||
if node.data[1].valid(env):
|
||||
env.incPC(node.data[1].value(env))
|
||||
|
||||
def visitWord(self, node, env):
|
||||
env.incPC(len(node.data) * 2)
|
||||
|
||||
@ -744,6 +748,19 @@ class Assembler(Pass):
|
||||
env.incPC(len(node.data))
|
||||
self.data += len(node.data)
|
||||
|
||||
def visitByteRange(self, node, env):
|
||||
offset = node.data[0].value(env) + 2
|
||||
length = node.data[1].value(env)
|
||||
if offset < 2:
|
||||
Err.log("Negative offset in .incbin")
|
||||
elif offset + length > len(node.data):
|
||||
Err.log("File too small for .incbin subrange")
|
||||
else:
|
||||
for expr in node.data[offset:(offset + length)]:
|
||||
self.outputbyte(expr, env)
|
||||
env.incPC(length)
|
||||
self.data += length
|
||||
|
||||
def visitWord(self, node, env):
|
||||
for expr in node.data:
|
||||
self.outputword(expr, env)
|
||||
|
Loading…
Reference in New Issue
Block a user