mirror of
https://github.com/michaelcmartin/Ophis.git
synced 2024-05-29 00:41:29 +00:00
41bf01d035
Most of the work is handled by 2to3, but there's a few extra tricks needed to finish the job, mostly about picking the right bits to be Unicode and the right bits to be bytes.
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
|