每当找到一些正则表达式时,我都使用lex来执行某些代码, Yacc可以做更多的事吗?如果是,那又是什么?
答案 0 :(得分:35)
是的,YACC是一个解析器,Lex是一个词法分析器。它们通常一起使用:Lex字符串输入,YACC Lex提供的标记化输入。
现在,正则表达式只能表示常规语言。常规语言的一个限制是缺乏“记忆”。您无法根据之前的内容在字符串中进一步定义接受规则。
这在括号中很明显。常规语言无法将嵌套括号与正确级别匹配。或任何其他此类结构。 (大多数)计算机语言的语法可以做和做,并且因此,它们不能用Lexer或正则表达式解析。这就是YACC的用武之地。
也可以扭转这个问题。如果YACC可以做更多,为什么不用它进行词法分析呢?好吧,碰巧你可以非常有效地验证正则表达式的有效性,这不是一般语法的情况 - 不是同一级别。如果语言的词汇规则足够简单,YACC仍然可以进行基本的词汇分析。
答案 1 :(得分:10)
lex是lexical analyzer。它将文本拆分为令牌。它的功效大致相当于正则表达式匹配。 yacc是parser generator。它需要一系列标记(例如,来自lex)并将它们解释为一系列语句。它的功效大致相当于无上下文语法。
lex和yacc的典型应用是用于实现编程语言。 lex将输入标记为输入,将其分解为关键字,常量,标点符号等。然后yacc实现实际的计算机语言;例如,识别for语句或函数定义。
在实际意义上,您经常使用lex将输入文本处理成块。然后使用yacc将这些块串起来并将它们处理成更大的含义。
答案 2 :(得分:10)
lex用于标记输入。也就是说,将输入分离为语法定义的最低级别对象。例如,您使用lex来标识关键字,标识符,字符串,注释,空格等。
yacc用于解析语法。语法是对您的语言的描述,通常在EBNF或其他一些无上下文语法中定义。一旦您将语法描述为yacc,就可以在识别语言元素时使用它来运行工具的操作。例如,这可能是构造用于表达式求解的语法树,定义范围对象,记录变量定义等等。
它们是免费产品。
答案 3 :(得分:2)
lex和yacc通常一起使用。这就是您通常使用两者构建应用程序的方法:
输入流(字符) - > Lex(代币) - > Yacc(抽象语法树) - >你的申请
更一般地说,Lex会做的是从头开始读取源文件,并尝试匹配一些正则表达式(lex有自己的特殊语法,这与perl或sed有点不同表达式),然后将使用它识别的每个标记调用另一个程序。标记可以只是一个简单的枚举值,如关键字或运算符,或者可能附加一些元数据,如文字值。
Lex通常(虽然不是必须)用来调用Yacc。 Yacc使用LALR解析器算法,粗略地说,通过将每个令牌推送到堆栈上来工作。如果堆栈具有它识别的一系列令牌,它将弹出所有令牌,执行操作,并将另一个令牌推回堆栈。
Yacc工作的适当词汇实际上是终端和非终端。终端是从调用程序(通常是Lex)获得的令牌,而非终端是在其堆栈上匹配序列的结果。
通常,每个Yacc规则所采取的操作要么是评估规则所对应的计算结果,要么是为了处理另一个应用程序层而生成中间表示(如语法树)。
Yacc和lex一样,可以与另一个分开使用。例如,您可以通过从源文本传递单个字符来使用Yacc,并使用Yacc规则识别每种令牌。然而,Yacc的设计并不是那么容易使用,因此得到的词法分析器将比Lex中的等效词法分析器复杂得多。更典型的用法是出于性能原因或者因为你需要更聪明的词法分析器来制作手工编码的词法分析器。第二种情况的一个常见例子是在C语言中使用,它必须知道标识符的先前使用,以了解它们是否用于描述类型或变量。
答案 4 :(得分:1)
Lex是一个用于构建词法分析器的工具,它可以做一些相当愚蠢的词法(比如查找关键词)。 Yacc是一个解析器生成器,可以为真正的计算机语言创建解析器。它的分析通常基于lex的输出(这是一个令牌流),从而可以创建编程语言的解析树 - 这比lex更多。
传统上,编译器构建器区分词法和句法分析 - 这是编译器中的两个重要步骤(进一步遵循例如代码创建,优化)。