Lex和Yacc可以自己解析吗?

时间:2014-07-19 01:13:53

标签: bison yacc lex

Lex和Yacc能一起,lex和解析Lex和Yacc吗?

换句话说,是否可以编写自托管的Lex / Yacc组合,生成自己的解析器?

编辑:我并不是说组合需要完全解析输入的C部分。特别是,它不需要处理typedef-name / identifier冲突,或者构建一个完整的符号表(虽然我相信两者都可以用词法分析器和解析器中的C代码处理) 。这是因为C代码被逐字复制到输出中。

编辑2:基本上,Lex和Yacc(语言,而不是程序)是否有LALR(1)语法?

4 个答案:

答案 0 :(得分:3)

嗯,答案实际上比第一个答案所报道的要复杂得多。我声称,不,YACC不能解析YACC,但邪恶就在细节中。

YACC的自然语法包括:

gram: %empty | gram rule
rule: ID ":" rhs
rhs: %empty | rhs ID

(使用类似Bison的约定:":"是无值标记,ID是标识符的标记,%empty强调空RHS的规则。

不难看出这个语法不是LR(1)。 LR(1)大致意味着当光标前进时,您只需通过查看下一个标记即可知道在哪个规则中。然后考虑以下(有效)输入:

ID : ID ID
ID : ID
ID :

你可以在启动规则时轻松发现并在下一个规则开始时发现吗?好吧,这样太容易了,试着找出YACC会看到它:

ID : ID ID ID : ID ID :

你怎么知道第一条规则何时完成?将光标的位置视为下面的.

ID : ID . ID ID : ID ID :

第一条规则完成了吗?当然不是。下一步呢?

ID : ID ID . ID : ID ID :

第一条规则完成了吗?很明显是的。但在这两种情况下,下一个标记(又名“前瞻”)是ID;它是以下令牌,有助于确定当前规则是否已完成(":")或(ID)。换句话说,1前瞻是不够的,这个语法不是LR(1),因此也不是LALR(1)(这是YACC接受的语法类)。显然它是LR(2)。

如果我们接受更改语言并要求终止;规则,那么使这个语法LR(1)非常容易:

ID : ID ID ; ID : ID ; ID : ;

不幸的是,为时已晚,POSIX没有决定强制使用这个分号,所以YACC的实现必须处理这个LR(2)语法。

在Bison的情况下,它使用整洁/脏(取决于你的观点)技巧来处理它: scanner 被教导使“常规”标识符(ID)之间的区别)和一个后跟冒号的标识符(ID_COLON)。然后令牌流读取

ID_COLON ID ID ID_COLON ID ID_COLON

这显然是LR(1)。

那么为什么从YACC开始就不需要分号?好吧,由于明显的引导原因,YACC不能首先在YACC中编写,所以我想S. Johnson从未意识到他手工编写的解析器实际上接受了比LR(1)更难的语法。 Bison和byacc来自一个普通的克隆,其解析器也是手工编写的。 Bison自己的解析器在2002年(commit e9955c83734d0a545d7822a1feb9c4a8038a62cb)之后很久就被引导了。

我写的很多东西都可以根据你看到的东西进行辩论。我声称“自然”语法不是LR(1),但我不认为人们可以在这里定义“自然”。所以是的,其他人可能会说YACC的语法是LR(1)。但最后,我们没事,因为如果一种语言是LR(k),那么它就是LR(1)(即LR(k)语法可以变成LR(1)怪物语法,这是证明使用类似的脏/整洁的技巧)。

Wrt Flex,嗯,是的,它是自举的,但这也是有点不真实的说法:它的整体语法非常简单,并且可以通过regexp轻松描述。然而,正则表达式本身逃脱了常规语言的范围:有括号!所以在Lex / Flex内部,必须有一个真正的解析器,无论是生成还是手写,都要解析regexp。

询问Lex是否被引导类似于询问C预处理器是否被引导:是的,我确定那里有#include:)

答案 1 :(得分:1)

是的,他们确实这样做了。 lex的 flex 实现是自举的。如果我没记错的话,同上 yacc

  

编辑2:基本上,Lex和Yacc(语言,而不是程序)是否有LALR(1)语法?

这不是同一个问题。 yacc 具有LALR(1)语法。 lex,也是如此,但这并不意味着 lex 使用/可以使用生成的解析器。但它可以扫描自己的.l文件。

答案 2 :(得分:0)

yacc的POSIX规范包括用于识别Yacc输入的Yacc语法。因此,是的,Yacc语法可以用Yacc编写。

lex的POSIX规范不包含它识别的正则表达式的Lex规范。但是,这并不意味着无法生成这样的规范。

答案 3 :(得分:0)

上面给出的答案是事情的本质。规则末尾没有强制分号,因此需要额外的前瞻来确定标识符后面是否有冒号。如果是,则这表示新规则的左侧。

事实上,有可能解析 yacc 即使有这个问题,而不必像 bison 那样破解 yacc 语法 - 只是根本不使用 yacc,而只使用 lex!

POSIX 指定的语法实际上是一个正则 语法,它指定了一个有限状态转换器。转换器是确定性的,正是因为可以解决标识符冒号歧义。因此,如果您以正确的方式利用 lex 的启动条件工具在 lex 中设置正确类型的有限状态机,那么您应该能够使用 lex ... 解析 yacc 语法并引导 yacc 的实现只是 lex。