Ophis/src/Ophis/IR.py

205 lines
5.6 KiB
Python

"""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>", "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 "<UNKNOWN: " + repr(self.data) + ">"
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