205 lines
5.6 KiB
Python
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
|