mirror of
https://github.com/pmret/papermario.git
synced 2024-09-18 23:42:35 +02:00
implement SCRIPT(...) dsl
This commit is contained in:
parent
54c337596b
commit
83153acb59
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
# Python
|
# Python
|
||||||
__pycache__/
|
__pycache__/
|
||||||
venv/
|
venv/
|
||||||
|
.lark_cache*
|
||||||
|
|
||||||
# Misc
|
# Misc
|
||||||
.idea/
|
.idea/
|
||||||
|
3
.vscode/c_cpp_properties.json
vendored
3
.vscode/c_cpp_properties.json
vendored
@ -8,7 +8,8 @@
|
|||||||
],
|
],
|
||||||
"defines": [
|
"defines": [
|
||||||
"F3DEX_GBI_2",
|
"F3DEX_GBI_2",
|
||||||
"_LANGUAGE_C"
|
"_LANGUAGE_C",
|
||||||
|
"SCRIPT(...)={}"
|
||||||
],
|
],
|
||||||
"cStandard": "c89",
|
"cStandard": "c89",
|
||||||
"cppStandard": "c++17",
|
"cppStandard": "c++17",
|
||||||
|
1
.vscode/extensions.json
vendored
1
.vscode/extensions.json
vendored
@ -3,6 +3,7 @@
|
|||||||
"ms-vscode.cpptools",
|
"ms-vscode.cpptools",
|
||||||
"nanaian.vscode-star-rod",
|
"nanaian.vscode-star-rod",
|
||||||
"notskm.clang-tidy",
|
"notskm.clang-tidy",
|
||||||
|
"EditorConfig.EditorConfig",
|
||||||
],
|
],
|
||||||
"unwantedRecommendations": [
|
"unwantedRecommendations": [
|
||||||
"llvm-vs-code-extensions.vscode-clangd",
|
"llvm-vs-code-extensions.vscode-clangd",
|
||||||
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -1,6 +1,4 @@
|
|||||||
{
|
{
|
||||||
"editor.detectIndentation": false,
|
|
||||||
"editor.insertSpaces": true,
|
|
||||||
"files.eol": "\n",
|
"files.eol": "\n",
|
||||||
"files.insertFinalNewline": true,
|
"files.insertFinalNewline": true,
|
||||||
"editor.rulers": [120],
|
"editor.rulers": [120],
|
||||||
@ -10,6 +8,7 @@
|
|||||||
"-Iinclude/PR",
|
"-Iinclude/PR",
|
||||||
"-Isrc",
|
"-Isrc",
|
||||||
"-D_LANGUAGE_C",
|
"-D_LANGUAGE_C",
|
||||||
|
"-DSCRIPT(...)={}",
|
||||||
],
|
],
|
||||||
"python.pythonPath": "/usr/bin/python3",
|
"python.pythonPath": "/usr/bin/python3",
|
||||||
}
|
}
|
||||||
|
2
Doxyfile
2
Doxyfile
@ -103,7 +103,7 @@ GENERATE_LATEX = NO
|
|||||||
ENABLE_PREPROCESSING = YES
|
ENABLE_PREPROCESSING = YES
|
||||||
MACRO_EXPANSION = YES
|
MACRO_EXPANSION = YES
|
||||||
EXPAND_ONLY_PREDEF = YES
|
EXPAND_ONLY_PREDEF = YES
|
||||||
PREDEFINED = DOXYGEN NON_MATCHING __attribute__((x))=
|
PREDEFINED = DOXYGEN NON_MATCHING SCRIPT(...)={} __attribute__((x))=
|
||||||
EXPAND_AS_DEFINED = INCLUDE_ASM UNK_TYPE UNK_PTR UNK_RET UNK_FUN_ARG UNK_FUN_PTR UNK_ARGS M
|
EXPAND_AS_DEFINED = INCLUDE_ASM UNK_TYPE UNK_PTR UNK_RET UNK_FUN_ARG UNK_FUN_PTR UNK_ARGS M
|
||||||
SKIP_FUNCTION_MACROS = YES
|
SKIP_FUNCTION_MACROS = YES
|
||||||
|
|
||||||
|
2
Makefile
2
Makefile
@ -97,7 +97,7 @@ $(BUILD_DIR)/%.s.o: %.s
|
|||||||
$(AS) $(ASFLAGS) -o $@ $<
|
$(AS) $(ASFLAGS) -o $@ $<
|
||||||
|
|
||||||
$(BUILD_DIR)/%.c.o: %.c $(H_FILES)
|
$(BUILD_DIR)/%.c.o: %.c $(H_FILES)
|
||||||
cpp $(CPPFLAGS) $< | $(CC) $(CFLAGS) -o - | $(OLD_AS) $(OLDASFLAGS) - -o $@
|
cpp $(CPPFLAGS) $< | tools/compile_dsl_macros.py | $(CC) $(CFLAGS) -o - | $(OLD_AS) $(OLDASFLAGS) - -o $@
|
||||||
|
|
||||||
$(BUILD_DIR)/%.bin.o: %.bin
|
$(BUILD_DIR)/%.bin.o: %.bin
|
||||||
$(LD) -r -b binary -o $@ $<
|
$(LD) -r -b binary -o $@ $<
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
COMPILER_OPTS="-std=gnu89 -Iinclude -Isrc -D_LANGUAGE_C"
|
COMPILER_OPTS="-std=gnu89 -Iinclude -Isrc -D_LANGUAGE_C -DSCRIPT(...)={}"
|
||||||
|
|
||||||
shopt -s globstar
|
shopt -s globstar
|
||||||
|
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
capstone
|
capstone
|
||||||
PyYAML
|
PyYAML
|
||||||
|
lark-parser
|
||||||
|
@ -205,30 +205,22 @@ NpcGroupList M(npcGroupList) = {
|
|||||||
NPC_GROUP_LIST_END(),
|
NPC_GROUP_LIST_END(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// *INDENT-OFF*
|
Script M(ReadEastSign) = SCRIPT({
|
||||||
Script M(ReadEastSign) = {
|
func_800441F0(SI_VAR(0))
|
||||||
SI_CALL(func_800441F0, SI_VAR(0)),
|
if SI_VAR(0) == 1 {
|
||||||
SI_IF_EQ(SI_VAR(0), 1),
|
return
|
||||||
SI_RETURN(),
|
}
|
||||||
SI_END_IF(),
|
|
||||||
|
|
||||||
SI_GROUP(0),
|
setgroup 0
|
||||||
|
|
||||||
SI_CALL(func_802D5830, 1),
|
func_802D5830(1)
|
||||||
SI_CALL(DisablePlayerInput, 1),
|
DisablePlayerInput(1)
|
||||||
SI_CALL(ShowMessageAtScreenPos, MessageID_SIGN_GOOMBA_KINGS_FORTRESS_AHEAD, 160, 40),
|
ShowMessageAtScreenPos(MessageID_SIGN_GOOMBA_KINGS_FORTRESS_AHEAD, 160, 40)
|
||||||
SI_CALL(DisablePlayerInput, 0),
|
DisablePlayerInput(0)
|
||||||
SI_CALL(func_802D5830, 0),
|
func_802D5830(0)
|
||||||
|
});
|
||||||
|
|
||||||
SI_RETURN(),
|
Script M(MakeEntities) = SCRIPT({
|
||||||
SI_END(),
|
MakeEntity(0x802EAFDC, 436, 0, -42, 0, 0x80000000)
|
||||||
};
|
AssignScript(M(ReadEastSign))
|
||||||
|
});
|
||||||
Script M(MakeEntities) = {
|
|
||||||
SI_CALL(MakeEntity, 0x802EAFDC, 436, 0, -42, 0, 0x80000000),
|
|
||||||
SI_CALL(AssignScript, &M(ReadEastSign)),
|
|
||||||
|
|
||||||
SI_RETURN(),
|
|
||||||
SI_END(),
|
|
||||||
};
|
|
||||||
// *INDENT-ON*
|
|
||||||
|
229
tools/compile_dsl_macros.py
Executable file
229
tools/compile_dsl_macros.py
Executable file
@ -0,0 +1,229 @@
|
|||||||
|
#! /usr/bin/python3
|
||||||
|
|
||||||
|
from sys import stdin, stderr
|
||||||
|
from lark import Lark, exceptions, Transformer, v_args
|
||||||
|
|
||||||
|
def eprint(*args, **kwargs):
|
||||||
|
print(*args, file=stderr, **kwargs)
|
||||||
|
|
||||||
|
"""
|
||||||
|
write_buf = ""
|
||||||
|
def write(s):
|
||||||
|
global write_buf
|
||||||
|
write_buf += s
|
||||||
|
def flush():
|
||||||
|
global write_buf
|
||||||
|
print(write_buf, end="")
|
||||||
|
write_buf = ""
|
||||||
|
"""
|
||||||
|
def write(s):
|
||||||
|
print(s, end="")
|
||||||
|
def flush():
|
||||||
|
pass
|
||||||
|
#"""
|
||||||
|
|
||||||
|
script_parser = Lark(r"""
|
||||||
|
|
||||||
|
block: "{" line* "}"
|
||||||
|
|
||||||
|
?line: call
|
||||||
|
| if_stmt
|
||||||
|
| "return" -> return_stmt
|
||||||
|
| "setgroup" expr -> setgroup
|
||||||
|
|
||||||
|
call: CNAME "(" [expr ("," expr)* [","]] ")"
|
||||||
|
|
||||||
|
if_stmt: "if" expr if_op expr block ["else" block]
|
||||||
|
|
||||||
|
?if_op: "==" -> if_op_eq
|
||||||
|
|
||||||
|
?expr: c_const_expr
|
||||||
|
| ESCAPED_STRING
|
||||||
|
| SIGNED_INT
|
||||||
|
| DECIMAL
|
||||||
|
| HEX_INT
|
||||||
|
| CNAME
|
||||||
|
|
||||||
|
c_const_expr: "(" (c_const_expr | NOT_PARENS)+ ")"
|
||||||
|
NOT_PARENS: /[^()]+/
|
||||||
|
|
||||||
|
%import common.CNAME
|
||||||
|
%import common.SIGNED_INT
|
||||||
|
%import common.DECIMAL
|
||||||
|
%import common.HEXDIGIT
|
||||||
|
%import common.ESCAPED_STRING
|
||||||
|
|
||||||
|
HEX_INT: ["+"|"-"] "0x" HEXDIGIT+
|
||||||
|
|
||||||
|
LINE_COMMENT: "//" /[^\n]*/ NEWLINE
|
||||||
|
%ignore LINE_COMMENT
|
||||||
|
|
||||||
|
%import common.WS
|
||||||
|
%import common.NEWLINE
|
||||||
|
%ignore WS
|
||||||
|
|
||||||
|
""", start="block")#, parser="lalr", cache=True)
|
||||||
|
|
||||||
|
def si_cmd(opcode, *args):
|
||||||
|
return [opcode, len(args), *args]
|
||||||
|
|
||||||
|
@v_args(inline=True)
|
||||||
|
class Compile(Transformer):
|
||||||
|
SIGNED_INT = str
|
||||||
|
DECIMAL = float # TODO: fixed
|
||||||
|
HEX_INT = str
|
||||||
|
ESCAPED_STRING = eval
|
||||||
|
|
||||||
|
def CNAME(self, name):
|
||||||
|
return f"(Bytecode)({name})"
|
||||||
|
|
||||||
|
NOT_PARENS = str
|
||||||
|
def c_const_expr(self, *args): # usually a macro expansion
|
||||||
|
return f"(Bytecode)({' '.join(args)})"
|
||||||
|
|
||||||
|
def block(self, *lines):
|
||||||
|
flat = []
|
||||||
|
for line in lines:
|
||||||
|
if type(line) != list:
|
||||||
|
eprint(f"uncompiled: {line}")
|
||||||
|
else:
|
||||||
|
flat += line
|
||||||
|
return flat
|
||||||
|
|
||||||
|
def call(self, func, *args):
|
||||||
|
# TODO: type checking etc
|
||||||
|
return si_cmd(0x43, func, *args)
|
||||||
|
|
||||||
|
def if_stmt(self, a, op, b, block):
|
||||||
|
return si_cmd(op, a, b) + block + si_cmd(0x13)
|
||||||
|
def if_op_eq(self): return 0x0A
|
||||||
|
|
||||||
|
def return_stmt(self): return si_cmd(0x02)
|
||||||
|
|
||||||
|
def setgroup(self, group):
|
||||||
|
return si_cmd(0x4D, group)
|
||||||
|
|
||||||
|
def compile_script(s):
|
||||||
|
tree = script_parser.parse(s)
|
||||||
|
#eprint(tree.pretty())
|
||||||
|
return Compile().transform(tree) + si_cmd(0x02) + si_cmd(0x01)
|
||||||
|
|
||||||
|
def read_until_closing_paren(depth=1, lex_strings=False):
|
||||||
|
text = ""
|
||||||
|
|
||||||
|
in_string = False
|
||||||
|
string_escape = False
|
||||||
|
|
||||||
|
while True:
|
||||||
|
char = stdin.read(1)
|
||||||
|
|
||||||
|
if len(char) == 0:
|
||||||
|
# EOF
|
||||||
|
return text
|
||||||
|
|
||||||
|
if string_escape == True:
|
||||||
|
string_escape = False
|
||||||
|
elif char == "(" and not in_string:
|
||||||
|
depth += 1
|
||||||
|
elif char == ")" and not in_string:
|
||||||
|
depth -= 1
|
||||||
|
if depth == 0:
|
||||||
|
break
|
||||||
|
elif char == '"' and lex_strings:
|
||||||
|
in_string = not in_string
|
||||||
|
elif char == "\\" and in_string:
|
||||||
|
string_escape = True
|
||||||
|
|
||||||
|
text += char
|
||||||
|
|
||||||
|
return text
|
||||||
|
|
||||||
|
def read_line():
|
||||||
|
line = ""
|
||||||
|
|
||||||
|
while True:
|
||||||
|
char = stdin.read(1)
|
||||||
|
|
||||||
|
if len(char) == 0:
|
||||||
|
# EOF
|
||||||
|
return line
|
||||||
|
|
||||||
|
if char == "\n":
|
||||||
|
break
|
||||||
|
|
||||||
|
line += char
|
||||||
|
|
||||||
|
return line
|
||||||
|
|
||||||
|
# Expects output from C preprocessor on stdin
|
||||||
|
if __name__ == "__main__":
|
||||||
|
line_no = 1
|
||||||
|
char_no = 1
|
||||||
|
file_info = []
|
||||||
|
error = False
|
||||||
|
|
||||||
|
macro_name = "" # captures recent UPPER_CASE identifier
|
||||||
|
prev_char = ""
|
||||||
|
while True:
|
||||||
|
char = stdin.read(1)
|
||||||
|
|
||||||
|
if len(char) == 0:
|
||||||
|
# EOF
|
||||||
|
write(macro_name)
|
||||||
|
if error:
|
||||||
|
exit(1)
|
||||||
|
else:
|
||||||
|
#with open("debug.i", "w") as i:
|
||||||
|
# i.write(write_buf)
|
||||||
|
flush()
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
if char == "#" and (prev_char == "\n" or prev_char == ""):
|
||||||
|
# cpp line/file marker
|
||||||
|
line = read_line()
|
||||||
|
line_split = line[1:].split(" ")
|
||||||
|
|
||||||
|
line_no = int(line_split[0])
|
||||||
|
file_info = line_split[1:]
|
||||||
|
|
||||||
|
write("#" + line + "\n")
|
||||||
|
elif char == "(":
|
||||||
|
# SCRIPT(...)
|
||||||
|
if macro_name == "SCRIPT":
|
||||||
|
script_source = read_until_closing_paren(lex_strings=True)
|
||||||
|
|
||||||
|
try:
|
||||||
|
bytecode = compile_script(script_source)
|
||||||
|
|
||||||
|
write("{")
|
||||||
|
for word in bytecode:
|
||||||
|
write(f"{word},")
|
||||||
|
write("}")
|
||||||
|
except exceptions.UnexpectedToken as e:
|
||||||
|
line = e.line + line_no
|
||||||
|
filename = file_info[0][1:-1]
|
||||||
|
|
||||||
|
eprint(e.get_context(script_source))
|
||||||
|
eprint(f"{filename}:{line}: script parse error: unexpected `{e.token}'")
|
||||||
|
|
||||||
|
error = True
|
||||||
|
|
||||||
|
line_no += script_source.count("\n")
|
||||||
|
write(f"\n# {line_no} {file_info[0]}\n")
|
||||||
|
else:
|
||||||
|
# leave non-macro in source
|
||||||
|
write(macro_name + char)
|
||||||
|
|
||||||
|
macro_name = ""
|
||||||
|
elif char == "_" or (char >= 'A' and char <= 'Z'):
|
||||||
|
macro_name += char
|
||||||
|
else:
|
||||||
|
write(macro_name + char)
|
||||||
|
macro_name = ""
|
||||||
|
|
||||||
|
if char == "\n":
|
||||||
|
char_no = 0
|
||||||
|
line_no += 1
|
||||||
|
|
||||||
|
char_no += 1
|
||||||
|
prev_char = char
|
@ -2,9 +2,9 @@ name: "Paper Mario (North America)"
|
|||||||
basename: "papermario"
|
basename: "papermario"
|
||||||
options:
|
options:
|
||||||
find-file-boundaries: True
|
find-file-boundaries: True
|
||||||
pycparser_flags: ["-Iinclude", "-D_LANGUAGE_C", "-ffreestanding", "-DF3DEX_GBI_2", "-DSPLAT"]
|
|
||||||
compiler: "GCC"
|
compiler: "GCC"
|
||||||
mnemonic_ljust: 10
|
mnemonic_ljust: 10
|
||||||
|
o_as_suffix: yes
|
||||||
segments:
|
segments:
|
||||||
- name: header
|
- name: header
|
||||||
type: header
|
type: header
|
||||||
|
Loading…
Reference in New Issue
Block a user