【发布时间】:2020-08-21 17:32:52
【问题描述】:
好的,我的解析器生成器的冒险继续。这次摸到了一个经典的语法,据说是LALR语法:
start -> a a
a -> "A" a
a -> "B"
当我将它放入我的解析器生成器时,它会给我输出:
LIST OF STATES:
-----------------------
<0: S' -> . start , $
start -> . a a , $
a -> . "A" a , "A" / "B"
a -> . "B" , "A" / "B"
{NTerm(start): 1, Term(A): 2, Term(B): 3, NTerm(a): 4}>(3104365621624877555)
--------------------
<1: S' -> start . , $
{}>(3969511602615904846)
--------------------
<2: a -> "A" . a , "A" / "B"
a -> . "A" a , "A" / "B"
a -> . "B" , "A" / "B"
{Term(A): 2, Term(B): 3, NTerm(a): 5}>(5490562805113673592)
--------------------
<3: a -> "B" . , "A" / "B"
{}>(-4845209343945471034)
--------------------
<4: start -> a . a , $
a -> . "A" a , $
a -> . "B" , $
{Term(A): 6, Term(B): 7, NTerm(a): 8}>(598157158659875896)
--------------------
<5: a -> "A" a . , "A" / "B"
{}>(436327415052220213)
--------------------
<6: a -> "A" . a , $
a -> . "A" a , $
a -> . "B" , $
{Term(A): 6, Term(B): 7, NTerm(a): 9}>(5490562805113673592)
--------------------
<7: a -> "B" . , $
{}>(-4845209343945471034)
--------------------
<8: start -> a a . , $
{}>(5795088700656730485)
--------------------
<9: a -> "A" a . , $
{}>(436327415052220213)
POSSIBLE STATES TO JOIN: (2, 6), (3, 7), (5, 9)
ATTEMPTING CONVERSION TO LALR GRAMMAR...FAILED
CONTINUING WITH CLR(1)...
这些状态与我在其他资源中读到的关于编译 LALR 语法的内容相匹配——这一步看起来不错,它会产生正确的状态,就像我手动完成一样。生成器建议——这也是其他消息来源所说的将 CLR(1) 语法转换为 LALR 的内容——声明 (2,6),(3,7),(5,9) 可以加入,但它不能这样做。
当我查看生成的 action 和 goto 表时,我明白了原因:
如您所见,无法加入状态 2 和 6,因为存在不兼容的项目 s2 <> s6、s3 <> s7 等。
但最让我吃惊的是生成器完成了它的工作并生成了一个运行程序。当我在测试数据上运行这个程序时,它会接受数据!所以,我的生成器生成了正确的表格。
这是否意味着这种经典的“LALR”语法只有在人工编译时才是 LALR?我的解析器生成器有什么不同?
【问题讨论】:
-
“据说是”和“在其他来源中阅读”仔细未能指定信息的实际来源。如果您怀疑您获得的建议不正确,最好实际引用来源,或者如果可能,提供链接。另外,从你的语法生成器的输出来看,那些看似任意的巨大数字贡献了什么价值?如果它们是指针,请考虑使用十六进制输出格式:至少在 C 中,
void*具有%p格式。 -
你的生成器是 LR(1)——由于 LR(1) 是 LALR(1) 的超集,它可以很好地处理 LALR(1) 语法,它只是以额外的状态结束.