自制编程语言编译器:识别变量路径并生成树构建指令
解决变量路径识别与指令序列生成的方案
核心思路:基于状态机的路径解析
既然你的语言是缩进语法(类似CoffeeScript)且已实现词法令牌流,可通过状态机模式跟踪变量路径的构建过程,同步输出对应指令。
定义解析状态
先明确几个关键状态:
START:初始状态,等待路径起始标识符IN_PATH:正在解析变量路径,处理.、[等嵌套符号IN_BRACKET:处于方括号内的索引表达式(如[baz])PATH_END:路径结束,准备输出终止指令
令牌类型映射
先将词法输出的令牌归类,方便后续判断:
IDENTIFIER:标识符(如foo、bar)DOT:.LBRACKET:[RBRACKET:]INDENT:缩进DEDENT:缩进减少NEWLINE:换行OPERATOR:运算符(如=、+)SEPARATOR:分隔符(如,)
状态流转与指令生成逻辑
以解析foo.bar[baz].hello[and][goodday].there为例,详细说明流转过程:
- 遇到第一个
IDENTIFIER(foo):- 输出
term-start(foo) - 状态切换为
IN_PATH,路径层级+1
- 输出
- 遇到
DOT:- 不输出指令,保持
IN_PATH状态,等待下一个标识符
- 不输出指令,保持
- 遇到
IDENTIFIER(bar):- 输出
term-nest(bar)(表示嵌套在foo下的子项) - 保持
IN_PATH状态,路径层级+1
- 输出
- 遇到
LBRACKET:- 输出
term-bracket-start - 状态切换为
IN_BRACKET
- 输出
- 遇到
IDENTIFIER(baz):- 输出
term-index(baz) - 保持
IN_BRACKET状态
- 输出
- 遇到
RBRACKET:- 输出
term-bracket-end - 状态切回
IN_PATH
- 输出
- 后续
.hello、[and]等重复上述逻辑,直到触发路径终止条件 - 路径终止的判断场景:
- 遇到
INDENT/DEDENT:缩进变化说明当前路径属于其他块,输出term-nest-end - 遇到
NEWLINE+非缩进令牌:换行后开启新语句,输出term-nest-end - 遇到
OPERATOR/SEPARATOR:比如foo.bar = 123中的=,说明路径是赋值左值,输出term-nest-end
- 遇到
缩进语法的特殊处理
因为是缩进驱动的语法,需额外注意:
- 缩进增加时,若当前处于路径解析状态,必须先结束当前路径,再处理块的开启
- 缩进减少时,需闭合所有未终止的路径嵌套,对应输出
term-nest-end或term-bracket-end
伪代码实现示例
current_state = "START" path_stack = [] # 用栈替代层级计数,更精准跟踪嵌套结构 for token in token_stream: if current_state == "START": if token.type == "IDENTIFIER": emit(f"term-start({token.value})") path_stack.append("dot") current_state = "IN_PATH" elif current_state == "IN_PATH": if token.type == "DOT": continue elif token.type == "IDENTIFIER": emit(f"term-nest({token.value})") path_stack.append("dot") elif token.type == "LBRACKET": emit("term-bracket-start") path_stack.append("bracket") current_state = "IN_BRACKET" elif token.type in ["INDENT", "DEDENT", "NEWLINE", "OPERATOR", "SEPARATOR"]: # 结束当前路径,逐层输出终止指令 while path_stack: nested_type = path_stack.pop() emit("term-nest-end" if nested_type == "dot" else "term-bracket-end") current_state = "START" # 处理当前非路径令牌 process_non_path_token(token) elif current_state == "IN_BRACKET": if token.type == "IDENTIFIER": emit(f"term-index({token.value})") elif token.type == "RBRACKET": emit("term-bracket-end") path_stack.pop() current_state = "IN_PATH" elif token.type in ["NEWLINE", "INDENT", "DEDENT"]: # 非法语法,强制终止并抛出错误 emit("term-bracket-end") while path_stack: emit("term-nest-end" if path_stack.pop() == "dot" else "term-bracket-end") current_state = "START" process_error("Unexpected token inside bracket expression")
验证与调试技巧
- 同时打印令牌流和生成的指令序列,逐行对比定位遗漏或错误的指令
- 编写复杂路径测试用例,比如
a[b.c].d[e][f.g],验证嵌套逻辑的正确性 - 用栈结构跟踪路径层级,比单纯的计数变量更能精准处理嵌套关系
内容的提问来源于stack exchange,提问作者Lance Pollard
相关产品推荐
相关产品推荐

