"""Ophis Intermediate Representation Classes for representing the Intermediate nodes upon which the assembler passes operate.""" # Copyright 2002-2014 Michael C. Martin and additional contributors. # You may use, modify, and distribute this file under the MIT # license: See README for details. import Ophis.Errors as Err class Node(object): """The default IR Node Instances of Node always have the three fields ppt(Program Point), nodetype(a string), and data (a list).""" def __init__(self, ppt, nodetype, *data): self.ppt = ppt self.nodetype = nodetype self.data = list(data) def accept(self, asmpass, env=None): """Implements the Visitor pattern for an assembler pass. Calls the routine 'asmpass.visitTYPE(self, env)' where TYPE is the value of self.nodetype.""" Err.currentpoint = self.ppt routine = getattr(asmpass, "visit" + self.nodetype, asmpass.visitUnknown) routine(self, env) def __str__(self): if self.nodetype != "SEQUENCE": return str(self.ppt) + ": " + self.nodetype + " - " + \ " ".join(map(str, self.data)) else: return "\n".join(map(str, self.data)) def __repr__(self): args = [self.ppt, self.nodetype] + self.data return "Node(" + ", ".join(map(repr, args)) + ")" NullNode = Node("", "None") def SequenceNode(ppt, nodelist): return Node(ppt, "SEQUENCE", *nodelist) class Expr(object): """Base class for Ophis expressions All expressions have a field called "data" and a boolean field called "hardcoded". An expression is hardcoded if it has no symbolic values in it.""" def __init__(self, data): self.data = data self.hardcoded = False def __str__(self): return "" def valid(self, env=None, PCvalid=False): """Returns true if the the expression can be successfully evaluated in the specified environment.""" return False def value(self, env=None): "Evaluates this expression in the given environment." return None class ConstantExpr(Expr): "Represents a numeric constant" def __init__(self, data): self.data = data self.hardcoded = True def __str__(self): return str(self.data) def valid(self, env=None, PCvalid=False): return True def value(self, env=None): return self.data class LabelExpr(Expr): "Represents a symbolic constant" def __init__(self, data): self.data = data self.hardcoded = False def __str__(self): return self.data def valid(self, env=None, PCvalid=False): return (env is not None) and self.data in env def value(self, env=None): return env[self.data] class PCExpr(Expr): "Represents the current program counter: ^" def __init__(self): self.hardcoded = False def __str__(self): return "^" def valid(self, env=None, PCvalid=False): return env is not None and PCvalid def value(self, env=None): return env.getPC() class HighByteExpr(Expr): "Represents the expression >{data}" def __init__(self, data): self.data = data self.hardcoded = data.hardcoded def __str__(self): return ">" + str(self.data) def valid(self, env=None, PCvalid=False): return self.data.valid(env, PCvalid) def value(self, env=None): val = self.data.value(env) return (val >> 8) & 0xff class LowByteExpr(Expr): "Represents the expression <{data}" def __init__(self, data): self.data = data self.hardcoded = data.hardcoded def __str__(self): return "<" + str(self.data) def valid(self, env=None, PCvalid=False): return self.data.valid(env, PCvalid) def value(self, env=None): val = self.data.value(env) return val & 0xff class SequenceExpr(Expr): """Represents an interleaving of operands (of type Expr) and operators (of type String). Subclasses must provide a routine operate(self, firstarg, op, secondarg) that evaluates the operator.""" def __init__(self, data): """Constructor for Sequence Expressions. Results will be screwy if the data inpot isn't a list with types [Expr, str, Expr, str, Expr, str, ... Expr, str, Expr].""" self.data = data self.operands = [x for x in data if isinstance(x, Expr)] self.operators = [x for x in data if type(x) == str] for i in self.operands: if not i.hardcoded: self.hardcoded = False break else: self.hardcoded = True def __str__(self): return "[" + " ".join(map(str, self.data)) + "]" def valid(self, env=None, PCvalid=False): for i in self.operands: if not i.valid(env, PCvalid): return False return True def value(self, env=None): subs = list(map((lambda x: x.value(env)), self.operands)) result = subs[0] index = 1 for op in self.operators: result = self.operate(result, op, subs[index]) index += 1 return result def operate(self, start, op, other): if op == "*": return start * other if op == "/": return start // other if op == "+": return start + other if op == "-": return start - other if op == "&": return start & other if op == "|": return start | other if op == "^": return start ^ other