This commit is contained in:
Irmen de Jong 2018-01-07 14:36:12 +01:00
parent 18526469ed
commit 9b68722df3
2 changed files with 161 additions and 136 deletions

View File

@ -6,170 +6,187 @@ Written by Irmen de Jong (irmen@razorvine.net)
License: GNU GPL 3.0, see LICENSE
"""
from typing import List, Set
import attr
from ply.yacc import yacc
from .symbols import SourceRef, AstNode
from typing import Union
from .symbols import SourceRef
from .lexer import tokens, lexer, find_tok_column # get the lexer tokens. required.
start = "start"
@attr.s(cmp=False, slots=True, frozen=False)
class AstNode:
sourceref = attr.ib(type=SourceRef)
@property
def lineref(self) -> str:
return "src l. " + str(self.sourceref.line)
def print_tree(self) -> None:
def tostr(node: AstNode, level: int) -> None:
if not isinstance(node, AstNode):
return
indent = " " * level
name = getattr(node, "name", "")
print(indent, node.__class__.__name__, repr(name))
try:
variables = vars(node).items()
except TypeError:
return
for name, value in variables:
if isinstance(value, AstNode):
tostr(value, level + 1)
if isinstance(value, (list, tuple, set)):
if len(value) > 0:
elt = list(value)[0]
if isinstance(elt, AstNode) or name == "nodes":
print(indent, " >", name, "=")
for elt in value:
tostr(elt, level + 2)
tostr(self, 0)
@attr.s(cmp=False)
class Module(AstNode):
def __init__(self, nodes: List[AstNode], sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.nodes = nodes or []
nodes = attr.ib(type=list)
@attr.s(cmp=False)
class Directive(AstNode):
def __init__(self, name: str, args, sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.name = name
self.args = args or []
class Block(AstNode):
def __init__(self, name: str, address, scope, sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.name = name
self.address = address
self.scope = scope
name = attr.ib(type=str)
args = attr.ib(type=list, default=attr.Factory(list))
@attr.s(cmp=False)
class Scope(AstNode):
def __init__(self, nodes: List[AstNode], sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.nodes = nodes
nodes = attr.ib(type=list)
@attr.s(cmp=False)
class Block(AstNode):
scope = attr.ib(type=Scope)
name = attr.ib(type=str, default=None)
address = attr.ib(type=int, default=None)
@attr.s(cmp=False)
class Label(AstNode):
def __init__(self, name: str, sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.name = name
name = attr.ib(type=str)
@attr.s(cmp=False)
class Register(AstNode):
def __init__(self, name: str, sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.name = name
name = attr.ib(type=str)
@attr.s(cmp=False)
class PreserveRegs(AstNode):
def __init__(self, registers, sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.registers = registers
registers = attr.ib(type=str)
@attr.s(cmp=False)
class Assignment(AstNode):
def __init__(self, lhs, rhs, sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.lhs = lhs
self.rhs = rhs
left = attr.ib() # type: Union[str, TargetRegisters, Dereference]
right = attr.ib()
@attr.s(cmp=False)
class AugAssignment(Assignment):
def __init__(self, lhs, operator: str, rhs, sourceref: SourceRef) -> None:
super().__init__(lhs, rhs, sourceref)
self.operator = operator
operator = attr.ib(type=str)
@attr.s(cmp=False)
class SubCall(AstNode):
def __init__(self, target, preserveregs, arguments, sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.target = target
self.preserveregs = preserveregs
self.arguments = arguments
target = attr.ib()
preserve_regs = attr.ib()
arguments = attr.ib()
@attr.s(cmp=False)
class Return(AstNode):
def __init__(self, valueA, valueX, valueY, sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.valueA = valueA
self.valueX = valueX
self.valueY = valueY
value_A = attr.ib(default=None)
value_X = attr.ib(default=None)
value_Y = attr.ib(default=None)
@attr.s(cmp=False)
class TargetRegisters(AstNode):
def __init__(self, registers: List[str], sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.registers = registers
registers = attr.ib(type=list)
def add_register(self, register) -> None:
def add(self, register: str) -> None:
self.registers.append(register)
@attr.s(cmp=False)
class InlineAssembly(AstNode):
def __init__(self, assembly: str, sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.assembly = assembly
assembly = attr.ib(type=str)
@attr.s(cmp=False)
class VarDef(AstNode):
def __init__(self, name: str, vartype, datatype, value, sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.name = name
self.vartype = vartype
self.datatype = datatype
self.value = value
name = attr.ib(type=str)
vartype = attr.ib()
datatype = attr.ib()
value = attr.ib(default=None)
@attr.s(cmp=False, slots=True)
class Datatype(AstNode):
def __init__(self, name: str, dimension, sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.name = name
self.dimension = dimension
name = attr.ib(type=str)
dimension = attr.ib(type=list, default=None)
@attr.s(cmp=False)
class Subroutine(AstNode):
def __init__(self, name: str, paramspec, resultspec, code, sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.name = name
self.paramspec = paramspec
self.resultspec = resultspec
self.code = code
name = attr.ib(type=str)
param_spec = attr.ib()
result_spec = attr.ib()
scope = attr.ib(type=Scope, default=None)
address = attr.ib(type=int, default=None)
def __attrs_post_init__(self):
if self.scope is not None and self.address is not None:
raise ValueError("subroutine must have either a scope or an address, not both")
@attr.s(cmp=False)
class Goto(AstNode):
def __init__(self, target, ifstmt, condition, sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.target = target
self.ifstmt = ifstmt
self.condition = condition
target = attr.ib()
if_stmt = attr.ib(default=None)
condition = attr.ib(default=None)
@attr.s(cmp=False)
class Dereference(AstNode):
def __init__(self, location, datatype, sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.location = location
self.datatype = datatype
location = attr.ib()
datatype = attr.ib()
@attr.s(cmp=False, slots=True)
class CallTarget(AstNode):
def __init__(self, target, address_of: bool, sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.target = target
self.address_of = address_of
target = attr.ib()
address_of = attr.ib(type=bool)
@attr.s(cmp=False, slots=True)
class CallArgument(AstNode):
def __init__(self, name: str, value, sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.name = name
self.value = value
value = attr.ib()
name = attr.ib(type=str, default=None)
@attr.s(cmp=False)
class UnaryOp(AstNode):
def __init__(self, operator, operand, sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.operator = operator
self.operand = operand
operator = attr.ib(type=str)
operand = attr.ib()
@attr.s(cmp=False, slots=True)
class Expression(AstNode):
def __init__(self, lhs, operator, rhs, sourceref: SourceRef) -> None:
super().__init__(sourceref)
self.lhs = lhs
self.operator = operator
self.rhs = rhs
left = attr.ib()
operator = attr.ib(type=str)
right = attr.ib()
def p_start(p):
@ -178,7 +195,7 @@ def p_start(p):
| module_elements
"""
if p[1]:
p[0] = Module(p[1], _token_sref(p, 1))
p[0] = Module(nodes=p[1], sourceref=_token_sref(p, 1))
def p_module(p):
@ -207,9 +224,9 @@ def p_directive(p):
| DIRECTIVE directive_args ENDL
"""
if len(p) == 2:
p[0] = Directive(p[1], None, _token_sref(p, 1))
p[0] = Directive(name=p[1], sourceref=_token_sref(p, 1))
else:
p[0] = Directive(p[1], p[2], _token_sref(p, 1))
p[0] = Directive(name=p[1], args=p[2], sourceref=_token_sref(p, 1))
def p_directive_args(p):
@ -236,21 +253,21 @@ def p_block_name_addr(p):
"""
block : BITINVERT NAME INTEGER endl_opt scope
"""
p[0] = Block(p[2], p[3], p[5], _token_sref(p, 1))
p[0] = Block(name=p[2], address=p[3], scope=p[5], sourceref=_token_sref(p, 1))
def p_block_name(p):
"""
block : BITINVERT NAME endl_opt scope
"""
p[0] = Block(p[2], None, p[4], _token_sref(p, 1))
p[0] = Block(name=p[2], scope=p[4], sourceref=_token_sref(p, 1))
def p_block(p):
"""
block : BITINVERT endl_opt scope
"""
p[0] = Block(None, None, p[3], _token_sref(p, 1))
p[0] = Block(scope=p[3], sourceref=_token_sref(p, 1))
def p_endl_opt(p):
@ -265,7 +282,7 @@ def p_scope(p):
"""
scope : '{' scope_elements_opt '}'
"""
p[0] = Scope(p[2], _token_sref(p, 1))
p[0] = Scope(nodes=p[2], sourceref=_token_sref(p, 1))
def p_scope_elements_opt(p):
@ -304,28 +321,28 @@ def p_label(p):
"""
label : LABEL
"""
p[0] = Label(p[1], _token_sref(p, 1))
p[0] = Label(name=p[1], sourceref=_token_sref(p, 1))
def p_inlineasm(p):
"""
inlineasm : INLINEASM ENDL
"""
p[0] = InlineAssembly(p[1], _token_sref(p, 1))
p[0] = InlineAssembly(assembly=p[1], sourceref=_token_sref(p, 1))
def p_vardef(p):
"""
vardef : VARTYPE type_opt NAME ENDL
"""
p[0] = VarDef(p[3], p[1], p[2], None, _token_sref(p, 1))
p[0] = VarDef(name=p[3], vartype=p[1], datatype=p[2], sourceref=_token_sref(p, 1))
def p_vardef_value(p):
"""
vardef : VARTYPE type_opt NAME IS expression
"""
p[0] = VarDef(p[3], p[1], p[2], p[5], _token_sref(p, 1))
p[0] = VarDef(name=p[3], vartype=p[1], datatype=p[2], value=p[5], sourceref=_token_sref(p, 1))
def p_type_opt(p):
@ -335,9 +352,9 @@ def p_type_opt(p):
| empty
"""
if len(p) == 5:
p[0] = Datatype(p[1], p[3], _token_sref(p, 1))
p[0] = Datatype(name=p[1], dimension=p[3], sourceref=_token_sref(p, 1))
elif len(p) == 2:
p[0] = Datatype(p[1], None, _token_sref(p, 1))
p[0] = Datatype(name=p[1], sourceref=_token_sref(p, 1))
def p_dimensions(p):
@ -364,7 +381,13 @@ def p_subroutine(p):
"""
subroutine : SUB NAME '(' sub_param_spec ')' RARROW '(' sub_result_spec ')' subroutine_body ENDL
"""
p[0] = Subroutine(p[1], p[3], p[7], p[9], _token_sref(p, 1))
body = p[10]
if isinstance(body, Scope):
p[0] = Subroutine(name=p[2], param_spec=p[4], result_spec=p[8], scope=body, sourceref=_token_sref(p, 1))
elif isinstance(body, int):
p[0] = Subroutine(name=p[2], param_spec=p[4], result_spec=p[8], address=body, sourceref=_token_sref(p, 1))
else:
raise TypeError("subroutine_body", p.slice)
def p_sub_param_spec(p):
@ -457,14 +480,14 @@ def p_incrdecr(p):
incrdecr : assignment_target INCR
| assignment_target DECR
"""
p[0] = UnaryOp(p[2], p[1], _token_sref(p, 1))
p[0] = UnaryOp(operator=p[2], operand=p[1], sourceref=_token_sref(p, 1))
def p_call_subroutine(p):
"""
subroutine_call : calltarget preserveregs_opt '(' call_arguments_opt ')'
"""
p[0] = SubCall(p[1], p[2], p[4], _token_sref(p, 1))
p[0] = SubCall(target=p[1], preserve_regs=p[2], arguments=p[4], sourceref=_token_sref(p, 1))
def p_preserveregs_opt(p):
@ -479,7 +502,7 @@ def p_preserveregs(p):
"""
preserveregs : PRESERVEREGS
"""
p[0] = PreserveRegs(p[1], _token_sref(p, 1))
p[0] = PreserveRegs(registers=p[1], sourceref=_token_sref(p, 1))
def p_call_arguments_opt(p):
@ -508,9 +531,9 @@ def p_call_argument(p):
| NAME IS expression
"""
if len(p) == 2:
p[0] = CallArgument(None, p[1], _token_sref(p, 1))
p[0] = CallArgument(value=p[1], sourceref=_token_sref(p, 1))
elif len(p) == 4:
p[0] = CallArgument(p[1], p[3], _token_sref(p, 1))
p[0] = CallArgument(name=p[1], value=p[3], sourceref=_token_sref(p, 1))
def p_return(p):
@ -521,41 +544,41 @@ def p_return(p):
| RETURN expression ',' expression ',' expression
"""
if len(p) == 2:
p[0] = Return(None, None, None, _token_sref(p, 1))
p[0] = Return(sourceref=_token_sref(p, 1))
elif len(p) == 3:
p[0] = Return(p[2], None, None, _token_sref(p, 1))
p[0] = Return(value_A=p[2], sourceref=_token_sref(p, 1))
elif len(p) == 5:
p[0] = Return(p[2], p[4], None, _token_sref(p, 1))
p[0] = Return(value_A=p[2], value_X=p[4], sourceref=_token_sref(p, 1))
elif len(p) == 7:
p[0] = Return(p[2], p[4], p[6], _token_sref(p, 1))
p[0] = Return(value_A=p[2], value_X=p[4], value_Y=p[6], sourceref=_token_sref(p, 1))
def p_register(p):
"""
register : REGISTER
"""
p[0] = Register(p[1], _token_sref(p, 1))
p[0] = Register(name=p[1], sourceref=_token_sref(p, 1))
def p_goto(p):
"""
goto : GOTO calltarget
"""
p[0] = Goto(p[2], None, None, _token_sref(p, 1))
p[0] = Goto(target=p[2], sourceref=_token_sref(p, 1))
def p_conditional_goto_plain(p):
"""
conditional_goto : IF GOTO calltarget
"""
p[0] = Goto(p[3], p[1], None, _token_sref(p, 1))
p[0] = Goto(target=p[3], if_stmt=p[1], sourceref=_token_sref(p, 1))
def p_conditional_goto_expr(p):
"""
conditional_goto : IF expression GOTO calltarget
"""
p[0] = Goto(p[4], p[1], p[2], _token_sref(p, 1))
p[0] = Goto(target=p[4], if_stmt=p[1], condition=p[2], sourceref=_token_sref(p, 1))
def p_calltarget(p):
@ -566,16 +589,16 @@ def p_calltarget(p):
| dereference
"""
if len(p) == 2:
p[0] = CallTarget(p[1], False, _token_sref(p, 1))
p[0] = CallTarget(target=p[1], address_of=False, sourceref=_token_sref(p, 1))
elif len(p) == 3:
p[0] = CallTarget(p[2], True, _token_sref(p, 1))
p[0] = CallTarget(target=p[2], address_of=True, sourceref=_token_sref(p, 1))
def p_dereference(p):
"""
dereference : '[' dereference_operand ']'
"""
p[0] = Dereference(p[2][0], p[2][1], _token_sref(p, 1))
p[0] = Dereference(location=p[2][0], datatype=p[2][1], sourceref=_token_sref(p, 1))
def p_dereference_operand(p):
@ -600,14 +623,14 @@ def p_assignment(p):
assignment : assignment_target IS expression
| assignment_target IS assignment
"""
p[0] = Assignment(p[1], p[3], _token_sref(p, 1))
p[0] = Assignment(left=p[1], right=p[3], sourceref=_token_sref(p, 1))
def p_aug_assignment(p):
"""
aug_assignment : assignment_target AUGASSIGN expression
"""
p[0] = AugAssignment(p[1], p[2], p[3], _token_sref(p, 1))
p[0] = AugAssignment(left=p[1], operator=p[2], right=p[3], sourceref=_token_sref(p, 1))
precedence = (
@ -632,28 +655,28 @@ def p_expression(p):
| expression EQUALS expression
| expression NOTEQUALS expression
"""
p[0] = Expression(p[1], p[2], p[3], _token_sref(p, 1))
p[0] = Expression(left=p[1], operator=p[2], right=p[3], sourceref=_token_sref(p, 1))
def p_expression_uminus(p):
"""
expression : '-' expression %prec UNARY_MINUS
"""
p[0] = UnaryOp(p[1], p[2], _token_sref(p, 1))
p[0] = UnaryOp(operator=p[1], operand=p[2], sourceref=_token_sref(p, 1))
def p_expression_addressof(p):
"""
expression : BITAND symbolname %prec UNARY_ADDRESSOF
"""
p[0] = UnaryOp(p[1], p[2], _token_sref(p, 1))
p[0] = UnaryOp(operator=p[1], operand=p[2], sourceref=_token_sref(p, 1))
def p_unary_expression_bitinvert(p):
"""
expression : BITINVERT expression
"""
p[0] = UnaryOp(p[1], p[2], _token_sref(p, 1))
p[0] = UnaryOp(operator=p[1], operand=p[2], sourceref=_token_sref(p, 1))
def p_expression_group(p):
@ -663,7 +686,7 @@ def p_expression_group(p):
p[0] = p[2]
def p_expression_ass_rhs(p):
def p_expression_expr_value(p):
"""expression : expression_value"""
p[0] = p[1]
@ -694,13 +717,12 @@ def p_target_registers(p):
| target_registers ',' register
"""
if len(p) == 2:
p[0] = TargetRegisters([p[1]], _token_sref(p, 1))
p[0] = TargetRegisters(registers=[p[1]], sourceref=_token_sref(p, 1))
else:
p[1].add_register(p[3])
p[1].add(p[3])
p[0] = p[1]
def p_empty(p):
"""empty :"""
pass

View File

@ -5,3 +5,6 @@ incremental = True
[mypy-il65/parsetab.*]
ignore_errors = True
[mypy-il65/plyparser.*]
ignore_errors = True