compiler-construction - 如何使用可选前缀 LL(2) 制作语法?
问题描述
考虑这个语法
start: lvalue ASSIGN expr SEMICOLON | expr SEMICOLON;
expr: OPENPAREN expr CLOSEPAREN | literal | lvalue;
lvalue: ID lvalue_tail ;
lvalue_tail: OPENBRACK expr CLOSEBRACK | ;
ID : [a-zA-Z]+[a-zA-Z0-9_]* ;
lvalue
an 也是如此expr
,但 anexpr
可能不是lvalue
。
有了这个输入var[10]
,语法将需要 4 次前瞻(ID、openbrack、literal、closebrack)才能确定是否应该选择lvalue expr
or expr
。
我如何制作这样的语法 LL(2)?
注意:expr
这里是简化的,大写字母的符号是终端。
解决方案
与仅使用 LALR 解析器生成器相比,我不确定通过减少该语法的 LL 前瞻可以达到什么目的,因为未修改的语法是 LALR(1)。
然而,它可以通过分离expr
成lvalue
我们可能称之为的东西来完成rvalue
——即,在赋值运算符的左侧不可用的表达式。这可能会产生类似的东西
start: lvalue start_tail | rvalue SEMICOLON;
start_tail: ASSIGN expr SEMICOLON | SEMICOLON;
expr: lvalue | rvalue;
rvalue: OPENPAREN expr CLOSEPAREN | literal;
lvalue: ID lvalue_tail ;
lvalue_tail: OPENBRACK expr CLOSEBRACK | ;
ID : [a-zA-Z]+[a-zA-Z0-9_]* ;
该文法除了是 LL(2) 之外,还是 LL(1)。但是,将其扩展以包含更多语言可能会被证明是棘手的。
(如果上面的链接失效,它只是指向一个在线工具,它验证了语法是 LL(1)。)
推荐阅读
- node.js - 如何将中间件作为参数传递给模块
- crystal-reports - 水晶报表中等于1000时如何重置记录号
- python - 遍历游标时如何防止sqlite缓存结果
- javascript - 单击自身以及其他按钮时更改按钮的图像源属性
- javascript - Ionic 应用程序在初始化完成之前开始工作
- jquery - 具有动态创建表的数据表
- linux - 如何将 linux 中的 vcpkg 与交叉构建工具链以及 sysroot 集成?
- batch-file - 如何使用批处理解决此问题(过滤程序)?
- python - 从顶部的路径数创建顶部对,创建连续图,只有一个选项
- python - 如何比较 URI 编码的字符串?