├── #config └── properties.json ├── #import └── global.gml ├── .gitignore ├── README.md ├── datafiles ├── txr-doc-cn.dmd ├── txr-doc-cn.html ├── txr-doc.dmd └── txr-doc.html ├── export ├── thumb.bat └── thumb.svg ├── fonts └── fnt_test │ ├── fnt_test.png │ └── fnt_test.yy ├── objects ├── obj_txr_demo │ ├── Create_0.gml │ ├── Draw_0.gml │ └── obj_txr_demo.yy ├── obj_txr_demo_dialog │ ├── Draw_0.gml │ └── obj_txr_demo_dialog.yy └── obj_txr_demo_wait │ ├── Alarm_0.gml │ └── obj_txr_demo_wait.yy ├── options ├── amazonfire │ └── options_amazonfire.yy ├── android │ └── options_android.yy ├── html5 │ └── options_html5.yy ├── ios │ └── options_ios.yy ├── linux │ └── options_linux.yy ├── mac │ └── options_mac.yy ├── main │ ├── inherited │ │ └── options_main.inherited.yy │ └── options_main.yy ├── operagx │ └── options_operagx.yy ├── ps4 │ └── options_ps4.yy ├── ps5 │ └── options_ps5.yy ├── switch │ └── options_switch.yy ├── tvos │ └── options_tvos.yy ├── windows │ └── options_windows.yy ├── windowsuap │ └── options_windowsuap.yy ├── xboxone │ └── options_xboxone.yy └── xboxseriesxs │ └── options_xboxseriesxs.yy ├── rooms └── room0 │ └── room0.yy ├── scripts ├── scr_txr_demo_abs │ ├── scr_txr_demo_abs.gml │ └── scr_txr_demo_abs.yy ├── scr_txr_demo_af │ ├── scr_txr_demo_af.gml │ └── scr_txr_demo_af.yy ├── scr_txr_demo_array │ ├── scr_txr_demo_array.gml │ └── scr_txr_demo_array.yy ├── scr_txr_demo_assert │ ├── scr_txr_demo_assert.gml │ └── scr_txr_demo_assert.yy ├── scr_txr_demo_call_label │ ├── scr_txr_demo_call_label.gml │ └── scr_txr_demo_call_label.yy ├── scr_txr_demo_default_func │ ├── scr_txr_demo_default_func.gml │ └── scr_txr_demo_default_func.yy ├── scr_txr_demo_dlg │ ├── scr_txr_demo_dlg.gml │ └── scr_txr_demo_dlg.yy ├── scr_txr_demo_draw_text │ ├── scr_txr_demo_draw_text.gml │ └── scr_txr_demo_draw_text.yy ├── scr_txr_demo_get_dummy │ ├── scr_txr_demo_get_dummy.gml │ └── scr_txr_demo_get_dummy.yy ├── scr_txr_demo_global_get │ ├── scr_txr_demo_global_get.gml │ └── scr_txr_demo_global_get.yy ├── scr_txr_demo_global_set │ ├── scr_txr_demo_global_set.gml │ └── scr_txr_demo_global_set.yy ├── scr_txr_demo_lerp │ ├── scr_txr_demo_lerp.gml │ └── scr_txr_demo_lerp.yy ├── scr_txr_demo_trace │ ├── scr_txr_demo_trace.gml │ └── scr_txr_demo_trace.yy ├── scr_txr_demo_wait │ ├── scr_txr_demo_wait.gml │ └── scr_txr_demo_wait.yy ├── txr_action_print │ ├── txr_action_print.gml │ └── txr_action_print.yy ├── txr_action_read │ ├── txr_action_read.gml │ └── txr_action_read.yy ├── txr_action_write │ ├── txr_action_write.gml │ └── txr_action_write.yy ├── txr_build │ ├── txr_build.gml │ └── txr_build.yy ├── txr_build_expr │ ├── txr_build_expr.gml │ └── txr_build_expr.yy ├── txr_build_loop_body │ ├── txr_build_loop_body.gml │ └── txr_build_loop_body.yy ├── txr_build_ops │ ├── txr_build_ops.gml │ └── txr_build_ops.yy ├── txr_build_stat │ ├── txr_build_stat.gml │ └── txr_build_stat.yy ├── txr_compile │ ├── txr_compile.gml │ └── txr_compile.yy ├── txr_compile_expr │ ├── txr_compile_expr.gml │ └── txr_compile_expr.yy ├── txr_compile_getter │ ├── txr_compile_getter.gml │ └── txr_compile_getter.yy ├── txr_compile_patch_break_continue │ ├── txr_compile_patch_break_continue.gml │ └── txr_compile_patch_break_continue.yy ├── txr_compile_setter │ ├── txr_compile_setter.gml │ └── txr_compile_setter.yy ├── txr_constant_add │ ├── txr_constant_add.gml │ └── txr_constant_add.yy ├── txr_exec │ ├── txr_exec.gml │ └── txr_exec.yy ├── txr_exec_actions │ ├── txr_exec_actions.gml │ └── txr_exec_actions.yy ├── txr_exec_string │ ├── txr_exec_string.gml │ └── txr_exec_string.yy ├── txr_function_add │ ├── txr_function_add.gml │ └── txr_function_add.yy ├── txr_init │ ├── txr_init.gml │ └── txr_init.yy ├── txr_is_number │ ├── txr_is_number.gml │ └── txr_is_number.yy ├── txr_parse │ ├── txr_parse.gml │ └── txr_parse.yy ├── txr_print_pos │ ├── txr_print_pos.gml │ └── txr_print_pos.yy ├── txr_program_print │ ├── txr_program_print.gml │ └── txr_program_print.yy ├── txr_program_read │ ├── txr_program_read.gml │ └── txr_program_read.yy ├── txr_program_write │ ├── txr_program_write.gml │ └── txr_program_write.yy ├── txr_sfmt │ ├── txr_sfmt.gml │ └── txr_sfmt.yy ├── txr_test_all │ ├── txr_test_all.gml │ └── txr_test_all.yy ├── txr_test_constant │ ├── txr_test_constant.gml │ └── txr_test_constant.yy ├── txr_test_struct │ ├── txr_test_struct.gml │ └── txr_test_struct.yy ├── txr_test_value_call │ ├── txr_test_value_call.gml │ └── txr_test_value_call.yy ├── txr_thread_create │ ├── txr_thread_create.gml │ └── txr_thread_create.yy ├── txr_thread_destroy │ ├── txr_thread_destroy.gml │ └── txr_thread_destroy.yy ├── txr_thread_jump │ ├── txr_thread_jump.gml │ └── txr_thread_jump.yy ├── txr_thread_jump_push │ ├── txr_thread_jump_push.gml │ └── txr_thread_jump_push.yy ├── txr_thread_read │ ├── txr_thread_read.gml │ └── txr_thread_read.yy ├── txr_thread_reset │ ├── txr_thread_reset.gml │ └── txr_thread_reset.yy ├── txr_thread_resume │ ├── txr_thread_resume.gml │ └── txr_thread_resume.yy ├── txr_thread_write │ ├── txr_thread_write.gml │ └── txr_thread_write.yy ├── txr_thread_yield │ ├── txr_thread_yield.gml │ └── txr_thread_yield.yy ├── txr_throw │ ├── txr_throw.gml │ └── txr_throw.yy ├── txr_throw_at │ ├── txr_throw_at.gml │ └── txr_throw_at.yy ├── txr_value_read │ ├── txr_value_read.gml │ └── txr_value_read.yy └── txr_value_write │ ├── txr_value_write.gml │ └── txr_value_write.yy ├── txr2.resource_order └── txr2.yyp /#config/properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "indentSize": 4, 3 | "indentWithTabs": true, 4 | "linterPrefs": { 5 | "blockScopedCase": true, 6 | "blockScopedVar": true, 7 | "requireFields": true 8 | }, 9 | "templateStringScript": "txr_sfmt" 10 | } -------------------------------------------------------------------------------- /#import/global.gml: -------------------------------------------------------------------------------- 1 | // nothing particular 2 | //!#import buffer_* in Buffer: 3 | //!#import buffer_u8 in bt.u8 4 | //!#import buffer_u32 in bt.u32 5 | //!#import buffer_s32 in bt.s32 6 | //!#import buffer_u64 in bt.s64 7 | //!#import buffer_f64 in bt.f64 8 | //!#import buffer_bool in bt.bool 9 | //!#import buffer_string in bt.st 10 | //!#import buffer_text in bt.cc 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /export/* 2 | !/export/thumb.svg 3 | !/export/thumb.bat 4 | /#backups/ 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tiny-expression-runtime 2 | **Quick links:** [Documentation](https://yal.cc/r/19/txr/) · [GM Marketplace page](https://marketplace.yoyogames.com/assets/7814/txr) · [itch.io page](https://yellowafterlife.itch.io/gamemaker-txr) 3 | **Explanation:** [part 1](https://yal.cc/interpreters-guide/) · [part 2](https://yal.cc/interpreters-guide-2/) 4 | **Versions**: GameMaker Studio 2 5 | **Platforms:** All of them 6 | 7 | TXR is a demo project for my series on writing custom interpreters. It lets you compile and run snippets of GML-like code. 8 | 9 | This can be used as a replacement for execute_string, for small-scale modding support, dialogue systems, or numerous other purposes. 10 | 11 | You can choose which scripts to expose to interpreted code, have it access instance variables, process arguments, pause/resume execution, save/load execution state, inspect execution state, etc. 12 | -------------------------------------------------------------------------------- /datafiles/txr-doc-cn.dmd: -------------------------------------------------------------------------------- 1 | ```set template default.html``` 2 | ```set title TXR cheatsheet``` 3 | ```setmd intro 4 | 这是 [YellowAfterlife](https://yal.cc) 为 微小表达运行时 编写的"备忘录". 5 | 项目文件可以从 [itch.io](https://yellowafterlife.itch.io/gamemaker-interpreters) 或 [GM Marketplace](https://marketplace.yoyogames.com/assets/7814/_)下载 6 | 如有疑问,请使用 [论坛](https://yellowafterlife.itch.io/gamemaker-txr/community) 或 [向我发送电子邮件](//yellowafterlife@hotmail.com). 7 | 本文档的最新版本始终可以在 [网上](https://yal.cc/r/19/txr) 找到. 8 | 翻译:yunzl 9 | 10 | 出于实际原因,本文档介绍了TXR的最新版本. 11 | ``` 12 | ```set quick-display-intro 点击项目以展开/折叠它们.``` 13 | ```set quick-display-controls 快速显示控件:``` 14 | ```set quick-display-categories 类别``` 15 | ```set quick-display-sections 小节``` 16 | ```set quick-display-everything 所有``` 17 | ```set quick-display-nightmode 切换夜间模式``` 18 | ```gmlapi fnames2``` 19 | ```gmlkeywords 20 | select option 21 | ``` 22 | ```set tag:defcode gml``` 23 | #[TXR 语法](syntax) { 24 | #[表达式](expressions) { 25 | TXR支持各种基本表达式: 26 | --{ 27 | -- 数字: `4`, `4.5`, 和 `-4` 都没问题. 不过现在不支持十六进制. 28 | -- 字符串: `"你好"` 或 `'你好'`. GMS1风格 (无转义字符) 29 | -- 常量: `true`, `false` 你可以在 `txr_parse` 添加自定义项. 30 | -- 括号: `(...)` 绝大多数是可选的. 31 | } 32 | } 33 | #[运算符](operators) { 34 | TXR支持多种常用运算符. 35 | 36 | 按优先级分组的二进制运算符: 37 | --{ 38 | -- `*`, `/`, `%`, `div` 39 | -- `+`, `-` (ECMAScript风格允许 `"a" + 4` -> `"a4"` ) 40 | -- `<<`, `>>` 41 | -- `&`, `|`, `^` 42 | -- `==`, `!=`, `<`, `>`, `<=`, `>=` 43 | -- `&&` (ES风格允许 `(4 && 5)` -> `5`) 44 | -- `||` (ES风格允许 `(4 || 5)` -> `4`) 45 | } 46 | `&&` 和 `||` 都支持断路. 47 | 48 | 一元运算符: 49 | --{ 50 | -- `!` (一元非) 51 | -- `-` (否定) 52 | -- `~` (位反转) 53 | -- `+` (什么都不做, 但你可以这样 `a = +4`) 54 | -- `++` (前缀和后缀) 55 | -- `--` (前缀和后缀) 56 | } 57 | } 58 | #[函数调用](function-calls) { 59 | 函数通过 [txr_function_add] 向TXR公开; 60 | 61 | 支持固定参数函数和可变参数函数. 62 | 63 | 最多可以传递16个参数 (如果需要更多,请将其添加到 `txr_thread_resume` 的 `txr_action.call` 中) 64 | } 65 | #[语句](statements) { 66 | 从第2部分开始,TXR允许使用语句. 67 | 68 | 语句可以是: 69 | --{ 70 | -- [赋值](assignments) 71 | -- [变量声明](variables) 72 | -- 括号语句 (`{...}`) 73 | -- [分支](branching) 74 | -- [函数调用](function-calls) 75 | -- 前缀/后缀 增量/减量 (`v++`, `--v`, ...) 76 | } 77 | } 78 | #[变量](variables) { 79 | 你可以通过GML样式 `var` 语法声明局部变量 80 | ``` 81 | var i; 82 | var k = 0; 83 | var z = true, s = "hi"; 84 | ``` 85 | 默认情况下,对任何非局部变量的访问都将映射到调用实例的变量. 你可以在 `txr_thread_resume` (`ident`, `set_ident`) 自定义此选项 86 | } 87 | #[赋值](assignments) { 88 | 您可以通过传统的 `name = value` 语法分配变量. 89 | 90 | 还支持赋值运算符 (`+=`, ...). 91 | } 92 | #[分支](branching) { 93 | TXR支持许多常见的分支语句: 94 | #[if ](if-then) { 95 | 括号是可选的. 96 | } 97 | #[if else ](if-then-else){} 98 | #[while ](while) { 99 | 支持 `break`/`continue`. 100 | } 101 | #[do while ](do-while) { 102 | 支持 `break`/`continue`. 103 | } 104 | #[for (; ; ) ]() { 105 | 支持 `break`/`continue`. 106 | 107 | 分号和括号是可选的,但最好不要滥用它. 108 | } 109 | #[switch () { ... }]() { 110 | 常见的 `switch` 块. 111 | 112 | `case` 将以 `break` 终止. 113 | 114 | 与GML-VM非常相似,支持任意大小写表达式意味着这是一堆稍微优化的if语句。 115 | } 116 | 以下为非标准: 117 | #[select () { ... }]() { 118 | 本质上是一种 [switch] 方法的简写.所以, 119 | ``` 120 | select (func(1, 2)) { 121 | option "A": trace("A"); 122 | option "B": trace("B"); 123 | default: trace("default"); 124 | } 125 | ``` 126 | 与之相同的 127 | ``` 128 | switch (func(1, 2, "A", "B")) { 129 | case 0: trace("A"); break; 130 | case 1: trace("B"); break; 131 | default: trace("default"); 132 | } 133 | ``` 134 | } 135 | [Gotos](https://en.wikipedia.org/wiki/Goto)是构建代码的一种糟糕的方式,但对于对话/等等来说非常方便: 136 | #[label