add do..while psuedoinstruction

This commit is contained in:
Alex Bates 2020-10-23 19:35:45 +01:00
parent 652c52d3dd
commit d29496e6e0
No known key found for this signature in database
GPG Key ID: 5E11C2DB78877706
2 changed files with 58 additions and 34 deletions

View File

@ -90,12 +90,10 @@ Script M(GoombaIdle) = SCRIPT({
SetSelfEnemyFlagBits(0x00000020, TRUE)
// Wait until read_sign sets NPC var 0
lbl:
GetSelfVar(0, SI_VAR(0))
sleep 1
if SI_VAR(0) == FALSE {
goto lbl
}
do {
GetSelfVar(0, SI_VAR(0))
sleep 1
} while SI_VAR(0) == FALSE
// Peel and jump off the sign
SetNpcFlagBits(NpcId_SELF, 0x00240000, TRUE)

View File

@ -29,6 +29,7 @@ script_parser = Lark(r"""
| label ":" -> label_decl
| "goto" label -> label_goto
| if_stmt
| do_while_stmt
| "return" -> return_stmt
| "break" -> break_stmt
| "sleep" expr -> sleep_stmt
@ -52,6 +53,8 @@ script_parser = Lark(r"""
?if_op: "==" -> if_op_eq
| "!=" -> if_op_ne
do_while_stmt: "do" block "while" expr if_op expr
suspend_stmt: "suspend" control_type expr ("," control_type expr)* [","]
resume_stmt: "resume" control_type expr ("," control_type expr)* [","]
kill_stmt: "kill" control_type expr ("," control_type expr)* [","]
@ -114,7 +117,7 @@ class Cmd():
self.context = []
def add_context(self, context):
self.context.append(context)
self.context.insert(0, context)
def to_bytecode(self):
return [ self.opcode, len(self.args), *self.args ]
@ -128,22 +131,32 @@ class BreakCmd(Cmd):
@property
def opcode(self):
# are we in a switch or a loop?
context = None
for c in self.context:
if c in ("switch", "loop"):
context = c
if not context:
return 0x01 # END
elif context == "loop":
return 0x07 # SI_BREAK_LOOP
elif context == "switch":
return 0x22 # BREAK_CASE
for ctx in self.context:
if "break_opcode" in ctx:
return ctx.break_opcode(self.meta)
return 0x01 # break out of whole script (end; no return)
def __str__(self):
return "BreakCmd"
class CmdCtx():
pass
class IfCtx(CmdCtx):
pass
class SwitchCtx(CmdCtx):
def break_opcode(self, meta):
return Cmd(0x22)
class LoopCtx(CmdCtx):
def break_opcode(self, meta):
return Cmd(0x07)
class DoWhileCtx(CmdCtx):
def break_opcode(self, meta):
raise CompileError("breaking out of a do..while loop is not supported (hint: use a label)", meta)
class CompileError(Exception):
def __init__(self, message, meta):
super().__init__(message)
@ -168,6 +181,10 @@ class LabelAllocation(Visitor):
raise CompileError(f"label `{name}' already declared", tree.meta)
self.labels.append(name)
def gen_label(self):
self.labels.append("$generated")
return len(self.labels) - 1
@v_args(tree=True)
class Compile(Transformer):
SIGNED_INT = str
@ -210,7 +227,7 @@ class Compile(Transformer):
a, op, b, block = tree.children
for cmd in block:
if type(cmd) == Cmd:
cmd.add_context("if")
cmd.add_context(IfCtx())
return [ Cmd(op, a, b, meta=tree.meta), *block, Cmd(0x13) ]
def if_op_eq(self, tree): return 0x0A
def if_op_ne(self, tree): return 0x0B
@ -221,16 +238,36 @@ class Compile(Transformer):
for cmd in block:
if type(cmd) == Cmd:
cmd.add_context("loop")
cmd.add_context(LoopCtx())
return [ Cmd(0x05, expr, meta=tree.meta), *block, Cmd(0x06) ]
def return_stmt(self, tree): return Cmd(0x02, meta=tree.meta)
# do..while pseudoinstruction
def do_while_stmt(self, tree):
block, a, op, b = tree.children
for cmd in block:
if type(cmd) == Cmd:
cmd.add_context(DoWhileCtx())
label = self.alloc.gen_label()
return [
Cmd(0x03, label, meta=tree.meta), # label:
*block,
Cmd(op, a, b, meta=tree.meta), # if a op b
Cmd(0x04, label, meta=tree.meta), # goto label
Cmd(0x13, meta=tree.meta), # end if
]
def return_stmt(self, tree):
return Cmd(0x02, meta=tree.meta)
def break_stmt(self, tree):
return BreakCmd(meta=tree.meta)
def set_group(self, tree): return Cmd(0x4D, tree.children[0], meta=tree.meta)
def set_group(self, tree):
return Cmd(0x4D, tree.children[0], meta=tree.meta)
def suspend_stmt(self, tree):
commands = []
@ -355,17 +392,6 @@ class Compile(Transformer):
return self.alloc.labels.index(name)
raise CompileError(f"label `{name}' is undeclared", tree.meta)
#define SI_SET_CONST(var, value) SI_CMD(0x25, var, value) // Does not get_variable
#define SI_SUB(a, b) SI_CMD(0x28, a, b) // -=
#define SI_MUL(a, b) SI_CMD(0x29, a, b) // *=
#define SI_DIV(a, b) SI_CMD(0x2A, a, b) // /=
#define SI_MOD(a, b) SI_CMD(0x2B, a, b) // %=
#define SI_SET_F(var, value) SI_CMD(0x26, var, value)
#define SI_SUB_F(a, b) SI_CMD(0x2D, a, b) // -=
#define SI_MUL_F(a, b) SI_CMD(0x2E, a, b) // *=
#define SI_DIV_F(a, b) SI_CMD(0x2F, a, b) // /=
def compile_script(s):
tree = script_parser.parse(s)