From 9323067e91d8b26db1755bf9b72ccee9cf293464 Mon Sep 17 00:00:00 2001 From: Michael Martin Date: Sun, 3 Jun 2012 23:50:29 -0700 Subject: [PATCH] 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. --- src/Ophis/CorePragmas.py | 33 +++++++++++++++++++++++++-------- src/Ophis/Passes.py | 17 +++++++++++++++++ 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/Ophis/CorePragmas.py b/src/Ophis/CorePragmas.py index a6373eb..f6b25a1 100644 --- a/src/Ophis/CorePragmas.py +++ b/src/Ophis/CorePragmas.py @@ -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): diff --git a/src/Ophis/Passes.py b/src/Ophis/Passes.py index ae8139e..67429b2 100644 --- a/src/Ophis/Passes.py +++ b/src/Ophis/Passes.py @@ -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)