mirror of
https://github.com/catseye/SixtyPical.git
synced 2025-08-10 06:24:56 +00:00
Make AST more structured (borrowed from ALPACA.)
This commit is contained in:
@@ -1,8 +1,29 @@
|
|||||||
# encoding: UTF-8
|
# encoding: UTF-8
|
||||||
|
|
||||||
class AST(object):
|
class AST(object):
|
||||||
|
children_attrs = ()
|
||||||
|
child_attrs = ()
|
||||||
|
value_attrs = ()
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
self.attrs = kwargs
|
self.attrs = {}
|
||||||
|
for attr in self.children_attrs:
|
||||||
|
self.attrs[attr] = kwargs.pop(attr, [])
|
||||||
|
for child in self.attrs[attr]:
|
||||||
|
assert child is None or isinstance(child, AST), \
|
||||||
|
"child %s=%r of %r is not an AST node" % (attr, child, self)
|
||||||
|
for attr in self.child_attrs:
|
||||||
|
self.attrs[attr] = kwargs.pop(attr, None)
|
||||||
|
child = self.attrs[attr]
|
||||||
|
assert child is None or isinstance(child, AST), \
|
||||||
|
"child %s=%r of %r is not an AST node" % (attr, child, self)
|
||||||
|
for attr in self.value_attrs:
|
||||||
|
self.attrs[attr] = kwargs.pop(attr, None)
|
||||||
|
assert (not kwargs), "extra arguments supplied to {} node: {}".format(self.type, kwargs)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self):
|
||||||
|
return self.__class__.__name__
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(%r)" % (self.__class__.__name__, self.attrs)
|
return "%s(%r)" % (self.__class__.__name__, self.attrs)
|
||||||
@@ -12,22 +33,50 @@ class AST(object):
|
|||||||
return self.attrs[name]
|
return self.attrs[name]
|
||||||
raise AttributeError(name)
|
raise AttributeError(name)
|
||||||
|
|
||||||
|
def all_children(self):
|
||||||
|
for attr in self.children_attrs:
|
||||||
|
for child in self.attrs[attr]:
|
||||||
|
yield child
|
||||||
|
for subchild in child.all_children():
|
||||||
|
yield subchild
|
||||||
|
for attr in self.child_attrs:
|
||||||
|
child = self.attrs[attr]
|
||||||
|
yield child
|
||||||
|
for subchild in child.all_children():
|
||||||
|
yield subchild
|
||||||
|
|
||||||
|
|
||||||
class Program(AST):
|
class Program(AST):
|
||||||
pass
|
children_attrs = ('defns', 'routines',)
|
||||||
|
|
||||||
|
|
||||||
class Defn(AST):
|
class Defn(AST):
|
||||||
pass
|
value_attrs = ('name', 'addr', 'initial', 'location',)
|
||||||
|
|
||||||
|
|
||||||
class Routine(AST):
|
class Routine(AST):
|
||||||
pass
|
value_attrs = ('name', 'addr', 'initial', 'location',)
|
||||||
|
children_attrs = ('statics',)
|
||||||
|
child_attrs = ('block',)
|
||||||
|
|
||||||
|
|
||||||
class Block(AST):
|
class Block(AST):
|
||||||
pass
|
children_attrs = ('instrs',)
|
||||||
|
|
||||||
|
|
||||||
class Instr(AST):
|
class Instr(AST):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class SingleOp(Instr):
|
||||||
|
value_attrs = ('opcode', 'dest', 'src', 'index', 'location',)
|
||||||
|
|
||||||
|
|
||||||
|
class BlockOp(Instr):
|
||||||
|
value_attrs = ('opcode', 'dest', 'src', 'inverted')
|
||||||
|
child_attrs = ('block',)
|
||||||
|
|
||||||
|
|
||||||
|
class IfOp(Instr):
|
||||||
|
value_attrs = ('opcode', 'dest', 'src', 'inverted')
|
||||||
|
child_attrs = ('block1', 'block2',)
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# encoding: UTF-8
|
# encoding: UTF-8
|
||||||
|
|
||||||
from sixtypical.ast import Program, Defn, Routine, Block, Instr
|
from sixtypical.ast import Program, Defn, Routine, Block, SingleOp, BlockOp, IfOp
|
||||||
from sixtypical.model import (
|
from sixtypical.model import (
|
||||||
TYPE_BIT, TYPE_BYTE, TYPE_WORD,
|
TYPE_BIT, TYPE_BYTE, TYPE_WORD,
|
||||||
RoutineType, VectorType, TableType, BufferType, PointerType,
|
RoutineType, VectorType, TableType, BufferType, PointerType,
|
||||||
@@ -352,8 +352,8 @@ class Parser(object):
|
|||||||
block2 = None
|
block2 = None
|
||||||
if self.scanner.consume('else'):
|
if self.scanner.consume('else'):
|
||||||
block2 = self.block()
|
block2 = self.block()
|
||||||
return Instr(opcode='if', dest=None, src=src,
|
return IfOp(opcode='if', dest=None, src=src,
|
||||||
block1=block1, block2=block2, inverted=inverted)
|
block1=block1, block2=block2, inverted=inverted)
|
||||||
elif self.scanner.consume('repeat'):
|
elif self.scanner.consume('repeat'):
|
||||||
inverted = False
|
inverted = False
|
||||||
src = None
|
src = None
|
||||||
@@ -364,7 +364,7 @@ class Parser(object):
|
|||||||
src = self.locexpr()
|
src = self.locexpr()
|
||||||
else:
|
else:
|
||||||
self.scanner.expect('forever')
|
self.scanner.expect('forever')
|
||||||
return Instr(opcode='repeat', dest=None, src=src,
|
return BlockOp(opcode='repeat', dest=None, src=src,
|
||||||
block=block, inverted=inverted)
|
block=block, inverted=inverted)
|
||||||
elif self.scanner.token in ("ld",):
|
elif self.scanner.token in ("ld",):
|
||||||
# the same as add, sub, cmp etc below, except supports an indlocexpr for the src
|
# the same as add, sub, cmp etc below, except supports an indlocexpr for the src
|
||||||
@@ -373,7 +373,7 @@ class Parser(object):
|
|||||||
dest = self.locexpr()
|
dest = self.locexpr()
|
||||||
self.scanner.expect(',')
|
self.scanner.expect(',')
|
||||||
src = self.indlocexpr()
|
src = self.indlocexpr()
|
||||||
return Instr(opcode=opcode, dest=dest, src=src, index=None)
|
return SingleOp(opcode=opcode, dest=dest, src=src, index=None)
|
||||||
elif self.scanner.token in ("add", "sub", "cmp", "and", "or", "xor"):
|
elif self.scanner.token in ("add", "sub", "cmp", "and", "or", "xor"):
|
||||||
opcode = self.scanner.token
|
opcode = self.scanner.token
|
||||||
self.scanner.scan()
|
self.scanner.scan()
|
||||||
@@ -383,25 +383,25 @@ class Parser(object):
|
|||||||
index = None
|
index = None
|
||||||
if self.scanner.consume('+'):
|
if self.scanner.consume('+'):
|
||||||
index = self.locexpr()
|
index = self.locexpr()
|
||||||
return Instr(opcode=opcode, dest=dest, src=src, index=index)
|
return SingleOp(opcode=opcode, dest=dest, src=src, index=index)
|
||||||
elif self.scanner.token in ("st",):
|
elif self.scanner.token in ("st",):
|
||||||
opcode = self.scanner.token
|
opcode = self.scanner.token
|
||||||
self.scanner.scan()
|
self.scanner.scan()
|
||||||
src = self.locexpr()
|
src = self.locexpr()
|
||||||
self.scanner.expect(',')
|
self.scanner.expect(',')
|
||||||
dest = self.indlocexpr()
|
dest = self.indlocexpr()
|
||||||
return Instr(opcode=opcode, dest=dest, src=src, index=None)
|
return SingleOp(opcode=opcode, dest=dest, src=src, index=None)
|
||||||
elif self.scanner.token in ("shl", "shr", "inc", "dec"):
|
elif self.scanner.token in ("shl", "shr", "inc", "dec"):
|
||||||
opcode = self.scanner.token
|
opcode = self.scanner.token
|
||||||
self.scanner.scan()
|
self.scanner.scan()
|
||||||
dest = self.locexpr()
|
dest = self.locexpr()
|
||||||
return Instr(opcode=opcode, dest=dest, src=None)
|
return SingleOp(opcode=opcode, dest=dest, src=None)
|
||||||
elif self.scanner.token in ("call", "goto"):
|
elif self.scanner.token in ("call", "goto"):
|
||||||
opcode = self.scanner.token
|
opcode = self.scanner.token
|
||||||
self.scanner.scan()
|
self.scanner.scan()
|
||||||
name = self.scanner.token
|
name = self.scanner.token
|
||||||
self.scanner.scan()
|
self.scanner.scan()
|
||||||
instr = Instr(opcode=opcode, location=name, dest=None, src=None)
|
instr = SingleOp(opcode=opcode, location=name, dest=None, src=None)
|
||||||
self.backpatch_instrs.append(instr)
|
self.backpatch_instrs.append(instr)
|
||||||
return instr
|
return instr
|
||||||
elif self.scanner.token in ("copy",):
|
elif self.scanner.token in ("copy",):
|
||||||
@@ -410,16 +410,16 @@ class Parser(object):
|
|||||||
src = self.indlocexpr(forward=True)
|
src = self.indlocexpr(forward=True)
|
||||||
self.scanner.expect(',')
|
self.scanner.expect(',')
|
||||||
dest = self.indlocexpr()
|
dest = self.indlocexpr()
|
||||||
instr = Instr(opcode=opcode, dest=dest, src=src)
|
instr = SingleOp(opcode=opcode, dest=dest, src=src)
|
||||||
self.backpatch_instrs.append(instr)
|
self.backpatch_instrs.append(instr)
|
||||||
return instr
|
return instr
|
||||||
elif self.scanner.consume("with"):
|
elif self.scanner.consume("with"):
|
||||||
self.scanner.expect("interrupts")
|
self.scanner.expect("interrupts")
|
||||||
self.scanner.expect("off")
|
self.scanner.expect("off")
|
||||||
block = self.block()
|
block = self.block()
|
||||||
return Instr(opcode='with-sei', dest=None, src=None, block=block)
|
return BlockOp(opcode='with-sei', dest=None, src=None, block=block)
|
||||||
elif self.scanner.consume("trash"):
|
elif self.scanner.consume("trash"):
|
||||||
dest = self.locexpr()
|
dest = self.locexpr()
|
||||||
return Instr(opcode='trash', src=None, dest=dest)
|
return SingleOp(opcode='trash', src=None, dest=dest)
|
||||||
else:
|
else:
|
||||||
raise ValueError('bad opcode "%s"' % self.scanner.token)
|
raise ValueError('bad opcode "%s"' % self.scanner.token)
|
||||||
|
Reference in New Issue
Block a user