parsing - LR解析如何解析这个语法中的单词“ab”:S -> ab | 在 ; T -> 一个
问题描述
假设我有语法
S -> a b | a T
T -> a
显然,语法接受 {aa,ab}。但是我很困惑LR解析如何解析单词“ab”。天真地,它可以像这样工作,通过将第一个“a”减少到 T 然后它卡住或不得不回溯。
a a => T a => stuck or backtrack
LR 解析器如何知道它不应该将第一个“a”简化为 T?
解决方案
在这种情况下,解析器将永远不会尝试归约T
,因为产生T → a
式未处于从S
. 初始状态有项目:
S → • a b
S → • a T
在这种状态下唯一可能的动作是使用 token 的 shift 动作a
。a
实际上,因为是下一个输入字符,所以我们进行移位转换到项集为的状态
S → a • b
S → a • T
T → • a
这个状态也没有 reduce 动作,它有两个不同的 shift 动作:一个 on b
,另一个 on a
。由于下一个输入是b
,因此采取了移位动作,导致项集为的状态
S → a b •
其中只有一个减少可用。
一个更有趣的例子是相当相似的语法
S → a b
S → T a
T → a
在这里,初始状态的项集确实包括 的产生式T
:
S → • a b
S → • T a
T → • a
在初始状态下唯一可用的操作仍然是 shift a
,但现在在执行 shift 之后,我们发现自己处于一个状态,其项目集是:
S → a • b
T → a •
现在我们有两个可能的动作:转移b
和减少T → a
。在这里,解析器需要使用它的能力来查看一个标记到未来(假设它是一个LR(1)
解析器)。
但要让它这样做,我们需要做一个小的调整。在构造解析自动机之前,语法总是被“增强”。增强语法通过添加一个唯一的输入结束字符来增加对输入结束的显式识别,该字符也可以参与前瞻检查。增广语法是:
S'→ S $
S → a b
S → T a
T → a
在这个语法中,我们可以看到非终结符T
后面只能跟符号a
,并且这个事实被编码到状态转换表中,其中项目集中的每个项目实际上都用一组可能的前瞻来注释。(在表格构建过程中,所有项目都被注释,但为了计算法律行为,只考虑减少的前瞻;减少是一个项目,其 • 位于末尾。)
通过这个修改,移位后达到的项目集a
是:
S → a • b
T → a • [ lookahead: { a } ]
并且前瞻使应该选择哪个动作变得绝对清楚。如果下一个输入是b
,则将其移位。如果下一个输入是a
,T
则减少。
该精度不适用于 LR(0) 解析,其中不使用前瞻。修改后的语法不是 LR(0),正是因为您提到的原因:它无法决定是否减少T
. 这个问题经常出现,这就是为什么 LR(0) 在实践中很少有用。
推荐阅读
- node.js - '(req: Request, res: IResponse, next: NextFunction) => void' 类型的参数不能使用 express.js 分配给'PathParams' 类型的参数
- regex - Bash 脚本删除包含多个单词的行,同时保留任何空格(alginment)
- python - AJAX+视图函数(API调用)+url映射如何巧妙结合?
- azure - 如何从管道 A 检查管道 B 的状态
- graphql - 阿波罗服务器订阅中的奇怪设计模式
- c# - 从 .NET 重置 AD 密码
- c# - 当我的视图模型从 xml 文件初始化时,为什么我的组合框之一为空?
- azure-devops - 忽略 AzureBlob 文件复制任务中的文件/文件夹
- python - ImageMagick可以用python程序打包吗?怎么做?
- android - Android,带有嵌入式对象列表的 ROOM 查询