Parsing 词法分析器与语法分析器
词法分析器和语法分析器在理论上真的有那么大的不同吗 讨厌正则表达式似乎很时髦: 然而,流行的基于词法分析的工具:,或,都使用正则表达式。他们似乎什么都不知道 什么时候词汇量足够,什么时候需要EBNFParsing 词法分析器与语法分析器,parsing,antlr,lexer,pygments,Parsing,Antlr,Lexer,Pygments,词法分析器和语法分析器在理论上真的有那么大的不同吗 讨厌正则表达式似乎很时髦: 然而,流行的基于词法分析的工具:,或,都使用正则表达式。他们似乎什么都不知道 什么时候词汇量足够,什么时候需要EBNF 是否有人将这些lexer生成的令牌用于bison或antlr解析器生成器?是的,它们在理论和实现上都有很大的不同 词法分析器用于识别构成语言元素的“单词”,因为这些单词的结构通常很简单。正则表达式非常擅长处理这种简单的结构,并且有非常高性能的正则表达式匹配引擎用于实现lexer 解析器用于识别语言短
是否有人将这些lexer生成的令牌用于bison或antlr解析器生成器?是的,它们在理论和实现上都有很大的不同 词法分析器用于识别构成语言元素的“单词”,因为这些单词的结构通常很简单。正则表达式非常擅长处理这种简单的结构,并且有非常高性能的正则表达式匹配引擎用于实现lexer 解析器用于识别语言短语的“结构”。这种结构通常远远超出“正则表达式”所能识别的范围,因此需要 “上下文敏感”解析器来提取这种结构。上下文敏感解析器 很难构建,因此工程上的折衷方案是使用“上下文无关”语法 并向解析器(“符号表”等)添加hack来处理上下文敏感部分 词法分析和解析技术都不可能很快消失
它们可以通过决定使用“解析”技术来识别“单词”来统一,正如目前所谓的无扫描GLR解析器所探索的那样。这有一个运行时成本,因为您正在将更通用的机器应用于通常不需要它的问题,并且通常您会在开销中为此付费。在有大量空闲周期的地方,开销可能并不重要。如果您处理大量文本,那么开销确实很重要,经典正则表达式解析器将继续使用。解析器和词法分析器的共同点:
- 提示:字母表不一定是字母表。但是它 必须是语言的原子符号 解析器/词法分析器可以理解
- lexer的符号:ASCII字符
- 解析器的符号:特定的标记,它们是语法的终端符号
- 这就是真正的区别所在。详见下文
- 词汇学习者理解的语法:常规语法(乔姆斯基的第3级)
- 语法分析器理解的语法:上下文无关语法(乔姆斯基的第2级)
- 词法者通过将词素(输入的符号串)分类为特定的标记来附加意义。例如,所有这些词素:
,*
,==
什么时候词汇量足够,什么时候需要EBNF EBNF并没有给语法增加太多功能。这只是一个方便/快捷的符号/“语法糖”,而不是标准的乔姆斯基范式(CNF)语法规则。例如,EBNF替代方案:
您只需单独列出每个备选产品,即可在CNF中实现:S --> A | B
EBNF中的可选元素:S --> A // `S` can be `A`, S --> B // or it can be `B`.
S --> X?
S --> A*
您可以在CNF中通过使用可为空的产生式来实现,也就是说,可以用空字符串替换的产生式(此处仅用空产生式表示;其他使用epsilon或lambda或交叉圆): 类似于上面最后一个S --> A+
形式的产品称为“擦除”,因为它可以擦除它在其他产品中代表的任何内容(产品是空字符串而不是其他内容) EBNF的零次或多次重复:B
S --> X?
S --> A*
您可以通过使用递归产生(recursiveproduction)来实现,也就是说,将自身嵌入其中某个位置的产生(recursiveproduction)。这可以通过两种方式实现。第一个是左递归(通常应该避免,因为自上而下的递归下降解析器无法解析它): 知道它只生成一个空字符串(最终)后跟零个或多个S --> A+
s,相同的字符串(但不是相同的语言!)可以使用正确的递归表示: 对于EBNF的一次或多次重复,当涉及到A
时:+
S --> X?
S --> A*
可以通过分解出一个S --> A+
并像前面一样使用A
来完成:*
您可以用CNF这样表示(我在这里使用右递归;作为练习,尝试自己找出另一个): 知道了这一点,您现在可能可以将正则表达式的语法(即正则语法)识别为可以在仅由终端符号组成的单个EBNF产品中表达的语法。更一般地说,当您看到类似以下内容的产品时,您可以识别常规语法:S --> A A*
也就是说,只使用空字符串、终端符号、简单的非终端进行替换和状态更改,并且只使用递归实现重复(迭代,它只是线性递归,不象分支树那样)。没有比这些更高级的了,那么你肯定这是一个常规语法,你可以使用lexer来实现 但是,当您的语法以一种非平凡的方式使用递归时,会产生类似树的、自相似的嵌套结构,如下所示:A --> // Empty (nullable) production (AKA erasure). B --> x // Single terminal symbol. C --> y D // Simple state change from `C` to `D` when seeing input `y`. E --> F z // Simple state change from `E` to `F` when seeing input `z`. G --> G u // Left recursion. H --> v H // Right recursion.
然后您可以很容易地看到,正则表达式无法实现这一点,因为您无法以任何方式将其解析为单个EBNF产品;您最终将无限期地替换S --> a S b // `S` can be itself "parenthesized" by `a` and `b` on both sides. S --> // or it could be (ultimately) empty, which ends recursion.
,这将始终在两侧添加另一个S
S和a
S。词法分析器(更具体地说:词法分析器使用的有限状态自动机)不能计数到任意数(它们是有限的,记得吗?),所以它们不知道有多少个b
s与这么多a
s均匀匹配。这样的语法称为上下文无关语法(至少是这样),它们需要解析器 上下文无关语法是众所周知的语法分析,因此它们被广泛用于描述b