mirror of
https://github.com/irmen/prog8.git
synced 2025-01-26 19:30:59 +00:00
first part of goto codegen
This commit is contained in:
parent
191978c8fb
commit
a171bb998d
@ -121,8 +121,10 @@ def generate_aug_assignment(ctx: Context) -> None:
|
||||
raise CodeError("invalid dereference operand type", rvalue)
|
||||
else:
|
||||
raise CodeError("invalid rvalue type", rvalue)
|
||||
elif isinstance(lvalue, SymbolName):
|
||||
raise NotImplementedError("symbolname augassign", lvalue) # XXX
|
||||
else:
|
||||
raise CodeError("aug. assignment only implemented for registers for now", stmt.sourceref) # XXX
|
||||
raise CodeError("aug. assignment only implemented for registers and symbols for now", lvalue, stmt.sourceref) # XXX
|
||||
|
||||
|
||||
def _generate_aug_reg_int(out: Callable, lvalue: Register, operator: str, rvalue: int, rname: str, scope: Scope) -> None:
|
||||
|
@ -5,17 +5,146 @@ This is the code generator for gotos and subroutine calls.
|
||||
Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
||||
"""
|
||||
|
||||
from ..plyparse import Goto, SubCall
|
||||
from . import Context
|
||||
from ..plyparse import Goto, SubCall, LiteralValue, SymbolName, Dereference, Register
|
||||
from . import Context, CodeError, to_hex
|
||||
|
||||
|
||||
def generate_goto(ctx: Context) -> None:
|
||||
stmt = ctx.stmt
|
||||
assert isinstance(stmt, Goto)
|
||||
pass # @todo
|
||||
ctx.out("\v\t\t\t; " + ctx.stmt.lineref)
|
||||
if stmt.condition:
|
||||
if stmt.if_stmt:
|
||||
_gen_goto_special_if_cond(ctx, stmt)
|
||||
else:
|
||||
_gen_goto_cond(ctx, stmt)
|
||||
else:
|
||||
if stmt.if_stmt:
|
||||
_gen_goto_special_if(ctx, stmt)
|
||||
else:
|
||||
_gen_goto_unconditional(ctx, stmt)
|
||||
|
||||
|
||||
def _gen_goto_special_if(ctx: Context, stmt: Goto) -> None:
|
||||
# a special if, but no conditional expression
|
||||
if isinstance(stmt.target, Dereference):
|
||||
# dereference is symbol, literal, or register (pair)
|
||||
if isinstance(stmt.target.operand, LiteralValue):
|
||||
targetstr = to_hex(stmt.target.operand.value)
|
||||
elif isinstance(stmt.target.operand, SymbolName):
|
||||
targetstr = stmt.target.operand.name
|
||||
else:
|
||||
# register pair
|
||||
ctx.out("\vst{:s} il65_lib.SCRATCH_ZPWORD1".format(stmt.target.operand.name[0]))
|
||||
ctx.out("\vst{:s} il65_lib.SCRATCH_ZPWORD1+1".format(stmt.target.operand.name[1]))
|
||||
targetstr = "il65_lib.SCRATCH_ZPWORD1"
|
||||
if stmt.if_cond == "true":
|
||||
ctx.out("\vbeq +")
|
||||
ctx.out("\vjmp ({:s})".format(targetstr))
|
||||
ctx.out("+")
|
||||
elif stmt.if_cond in ("not", "zero"):
|
||||
ctx.out("\vbne +")
|
||||
ctx.out("\vjmp ({:s})".format(targetstr))
|
||||
ctx.out("+")
|
||||
elif stmt.if_cond in ("cc", "cs", "vc", "vs", "eq", "ne"):
|
||||
if stmt.if_cond == "cc":
|
||||
ctx.out("\vbcs +")
|
||||
elif stmt.if_cond == "cs":
|
||||
ctx.out("\vbcc +")
|
||||
elif stmt.if_cond == "vc":
|
||||
ctx.out("\vbvs +")
|
||||
elif stmt.if_cond == "vs":
|
||||
ctx.out("\vbvc +")
|
||||
elif stmt.if_cond == "eq":
|
||||
ctx.out("\vbne +")
|
||||
elif stmt.if_cond == "ne":
|
||||
ctx.out("\vbeq +")
|
||||
ctx.out("\vjmp ({:s})".format(targetstr))
|
||||
ctx.out("+")
|
||||
elif stmt.if_cond == "lt":
|
||||
ctx.out("\vbcs +")
|
||||
ctx.out("\vjmp ({:s})".format(targetstr))
|
||||
ctx.out("+")
|
||||
elif stmt.if_cond == "gt":
|
||||
ctx.out("\vbcc +")
|
||||
ctx.out("\vbeq +")
|
||||
ctx.out("\vjmp ({:s})".format(targetstr))
|
||||
ctx.out("+")
|
||||
elif stmt.if_cond == "ge":
|
||||
ctx.out("\vbcc +")
|
||||
ctx.out("\vjmp ({:s})".format(targetstr))
|
||||
ctx.out("+")
|
||||
elif stmt.if_cond == "le":
|
||||
ctx.out("\vbeq +")
|
||||
ctx.out("\vbcs ++")
|
||||
ctx.out("+\t\tjmp ({:s})".format(targetstr))
|
||||
ctx.out("+")
|
||||
else:
|
||||
raise CodeError("invalid if status " + stmt.if_cond)
|
||||
else:
|
||||
if isinstance(stmt.target, LiteralValue) and type(stmt.target.value) is int:
|
||||
targetstr = to_hex(stmt.target.value)
|
||||
elif isinstance(stmt.target, SymbolName):
|
||||
targetstr = stmt.target.name
|
||||
else:
|
||||
raise CodeError("invalid goto target type", stmt)
|
||||
if stmt.if_cond == "true":
|
||||
ctx.out("\vbne " + targetstr)
|
||||
elif stmt.if_cond in ("not", "zero"):
|
||||
ctx.out("\vbeq " + targetstr)
|
||||
elif stmt.if_cond in ("cc", "cs", "vc", "vs", "eq", "ne"):
|
||||
ctx.out("\vb{:s} {:s}".format(stmt.if_cond, targetstr))
|
||||
elif stmt.if_cond == "pos":
|
||||
ctx.out("\vbpl " + targetstr)
|
||||
elif stmt.if_cond == "neg":
|
||||
ctx.out("\vbmi " + targetstr)
|
||||
elif stmt.if_cond == "lt":
|
||||
ctx.out("\vbcc " + targetstr)
|
||||
elif stmt.if_cond == "gt":
|
||||
ctx.out("\vbeq +")
|
||||
ctx.out("\vbcs " + targetstr)
|
||||
ctx.out("+")
|
||||
elif stmt.if_cond == "ge":
|
||||
ctx.out("\vbcs " + targetstr)
|
||||
elif stmt.if_cond == "le":
|
||||
ctx.out("\vbcc " + targetstr)
|
||||
ctx.out("\vbeq " + targetstr)
|
||||
else:
|
||||
raise CodeError("invalid if status " + stmt.if_cond)
|
||||
|
||||
|
||||
def _gen_goto_unconditional(ctx: Context, stmt: Goto) -> None:
|
||||
# unconditional jump to <target>
|
||||
if isinstance(stmt.target, LiteralValue) and type(stmt.target.value) is int:
|
||||
ctx.out("\vjmp " + to_hex(stmt.target.value))
|
||||
elif isinstance(stmt.target, SymbolName):
|
||||
ctx.out("\vjmp " + stmt.target.name)
|
||||
elif isinstance(stmt.target, Dereference):
|
||||
# dereference is symbol, literal, or register (pair)
|
||||
if isinstance(stmt.target.operand, LiteralValue):
|
||||
ctx.out("\vjmp ({:s})".format(to_hex(stmt.target.operand.value)))
|
||||
elif isinstance(stmt.target.operand, SymbolName):
|
||||
ctx.out("\vjmp ({:s})".format(stmt.target.operand.name))
|
||||
else:
|
||||
# register pair
|
||||
ctx.out("\vst{:s} il65_lib.SCRATCH_ZPWORD1".format(stmt.target.operand.name[0]))
|
||||
ctx.out("\vst{:s} il65_lib.SCRATCH_ZPWORD1+1".format(stmt.target.operand.name[1]))
|
||||
ctx.out("\vjmp (il65_lib.SCRATCH_ZPWORD1)")
|
||||
else:
|
||||
raise CodeError("invalid goto target type", stmt)
|
||||
|
||||
|
||||
def _gen_goto_special_if_cond(ctx: Context, stmt: Goto) -> None:
|
||||
pass # @todo special if WITH conditional expression
|
||||
|
||||
|
||||
def _gen_goto_cond(ctx: Context, stmt: Goto) -> None:
|
||||
pass # @todo regular if WITH conditional expression
|
||||
|
||||
|
||||
def generate_subcall(ctx: Context) -> None:
|
||||
stmt = ctx.stmt
|
||||
assert isinstance(stmt, SubCall)
|
||||
pass # @todo
|
||||
ctx.out("\v\t\t\t; " + ctx.stmt.lineref)
|
||||
ctx.out("\v; @todo sub call: {}".format(ctx.stmt.target))
|
||||
# @todo subcall
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
%asm {
|
||||
; ---- jmp (indirect) routines for register pairs containing the indirect address
|
||||
; @todo still needed??
|
||||
jsr_indirect_nozpuse_AX
|
||||
sta jsr_indirect_tmp
|
||||
stx jsr_indirect_tmp+1
|
||||
|
@ -2,105 +2,6 @@
|
||||
|
||||
|
||||
class CodeGenerator:
|
||||
def generate_call(self, stmt: CallStmt) -> None:
|
||||
self.p("\t\t\t\t\t; " + stmt.lineref)
|
||||
if stmt.condition:
|
||||
assert stmt.is_goto
|
||||
if stmt.condition.lvalue:
|
||||
if stmt.condition.comparison_op:
|
||||
self._generate_goto_conditional_comparison(stmt)
|
||||
else:
|
||||
self._generate_goto_conditional_truthvalue(stmt)
|
||||
else:
|
||||
self._generate_goto_conditional_if(stmt)
|
||||
else:
|
||||
# unconditional goto or subroutine call.
|
||||
def branch_emitter(targetstr: str, is_goto: bool, target_indirect: bool) -> None:
|
||||
if is_goto:
|
||||
if target_indirect:
|
||||
self.p("\t\tjmp ({:s})".format(targetstr))
|
||||
else:
|
||||
self.p("\t\tjmp {:s}".format(targetstr))
|
||||
else:
|
||||
assert not target_indirect
|
||||
self.p("\t\tjsr " + targetstr)
|
||||
self._generate_call_or_goto(stmt, branch_emitter)
|
||||
|
||||
def _generate_goto_conditional_if(self, stmt):
|
||||
# a goto with just an if-condition, no condition expression
|
||||
def branch_emitter(targetstr: str, is_goto: bool, target_indirect: bool) -> None:
|
||||
assert is_goto and not stmt.condition.comparison_op
|
||||
ifs = stmt.condition.ifstatus
|
||||
if target_indirect:
|
||||
if ifs == "true":
|
||||
self.p("\t\tbeq +")
|
||||
self.p("\t\tjmp ({:s})".format(targetstr))
|
||||
self.p("+")
|
||||
elif ifs in ("not", "zero"):
|
||||
self.p("\t\tbne +")
|
||||
self.p("\t\tjmp ({:s})".format(targetstr))
|
||||
self.p("+")
|
||||
elif ifs in ("cc", "cs", "vc", "vs", "eq", "ne"):
|
||||
if ifs == "cc":
|
||||
self.p("\t\tbcs +")
|
||||
elif ifs == "cs":
|
||||
self.p("\t\tbcc +")
|
||||
elif ifs == "vc":
|
||||
self.p("\t\tbvs +")
|
||||
elif ifs == "vs":
|
||||
self.p("\t\tbvc +")
|
||||
elif ifs == "eq":
|
||||
self.p("\t\tbne +")
|
||||
elif ifs == "ne":
|
||||
self.p("\t\tbeq +")
|
||||
self.p("\t\tjmp ({:s})".format(targetstr))
|
||||
self.p("+")
|
||||
elif ifs == "lt":
|
||||
self.p("\t\tbcs +")
|
||||
self.p("\t\tjmp ({:s})".format(targetstr))
|
||||
self.p("+")
|
||||
elif ifs == "gt":
|
||||
self.p("\t\tbcc +")
|
||||
self.p("\t\tbeq +")
|
||||
self.p("\t\tjmp ({:s})".format(targetstr))
|
||||
self.p("+")
|
||||
elif ifs == "ge":
|
||||
self.p("\t\tbcc +")
|
||||
self.p("\t\tjmp ({:s})".format(targetstr))
|
||||
self.p("+")
|
||||
elif ifs == "le":
|
||||
self.p("\t\tbeq +")
|
||||
self.p("\t\tbcs ++")
|
||||
self.p("+\t\tjmp ({:s})".format(targetstr))
|
||||
self.p("+")
|
||||
else:
|
||||
raise CodeError("invalid if status " + ifs)
|
||||
else:
|
||||
if ifs == "true":
|
||||
self.p("\t\tbne " + targetstr)
|
||||
elif ifs in ("not", "zero"):
|
||||
self.p("\t\tbeq " + targetstr)
|
||||
elif ifs in ("cc", "cs", "vc", "vs", "eq", "ne"):
|
||||
self.p("\t\tb{:s} {:s}".format(ifs, targetstr))
|
||||
elif ifs == "pos":
|
||||
self.p("\t\tbpl " + targetstr)
|
||||
elif ifs == "neg":
|
||||
self.p("\t\tbmi " + targetstr)
|
||||
elif ifs == "lt":
|
||||
self.p("\t\tbcc " + targetstr)
|
||||
elif ifs == "gt":
|
||||
self.p("\t\tbeq +")
|
||||
self.p("\t\tbcs " + targetstr)
|
||||
self.p("+")
|
||||
elif ifs == "ge":
|
||||
self.p("\t\tbcs " + targetstr)
|
||||
elif ifs == "le":
|
||||
self.p("\t\tbcc " + targetstr)
|
||||
self.p("\t\tbeq " + targetstr)
|
||||
else:
|
||||
raise CodeError("invalid if status " + ifs)
|
||||
self._generate_call_or_goto(stmt, branch_emitter)
|
||||
|
||||
def _generate_goto_conditional_truthvalue(self, stmt: CallStmt) -> None:
|
||||
# the condition is just the 'truth value' of the single value,
|
||||
# this is translated into assembly by comparing the argument to zero.
|
||||
|
@ -508,7 +508,7 @@ class SymbolName(Expression):
|
||||
|
||||
@attr.s(cmp=False)
|
||||
class Dereference(Expression):
|
||||
# one subnode: operand (SymbolName, integer LiteralValue or Register)
|
||||
# one subnode: operand (SymbolName, integer LiteralValue or Register (pair) )
|
||||
datatype = attr.ib()
|
||||
size = attr.ib(type=int, default=None)
|
||||
|
||||
@ -691,6 +691,7 @@ class ExpressionWithOperator(Expression):
|
||||
@attr.s(cmp=False, repr=False)
|
||||
class Goto(AstNode):
|
||||
# one or two subnodes: target (SymbolName, integer LiteralValue, or Dereference) and optionally: condition (Expression)
|
||||
# also the if_stmt itself can be a form of a condition (if_gt, ...)
|
||||
if_stmt = attr.ib(default=None)
|
||||
|
||||
@property
|
||||
@ -701,6 +702,10 @@ class Goto(AstNode):
|
||||
def condition(self) -> Optional[Expression]:
|
||||
return self.nodes[1] if len(self.nodes) == 2 else None # type: ignore
|
||||
|
||||
@property
|
||||
def if_cond(self) -> str:
|
||||
return self.if_stmt[3:] if self.if_stmt else ""
|
||||
|
||||
|
||||
@attr.s(cmp=False, slots=True, repr=False)
|
||||
class CallArgument(AstNode):
|
||||
|
@ -15,7 +15,7 @@ start:
|
||||
A = c64.VMCSB
|
||||
A |= 2
|
||||
c64.VMCSB = A
|
||||
c64.VMCSB |= 2 ; @todo when this works it replaces the three lines above
|
||||
;c64.VMCSB |= 2 ; @todo when this works it replaces the three lines above
|
||||
|
||||
; greeting
|
||||
c64scr.print_string("Enter your name: ")
|
||||
|
Loading…
x
Reference in New Issue
Block a user