当我开始使用解析器组合器时,我的第一个反应是从感觉上像是在解析和词法化之间的人为区别中解放出来。突然所有的一切都只是解析!
但是,我最近在codereview.stackexchange上发现了此帖子,说明有人在恢复这种区别。起初我以为这对他们很愚蠢,但是后来Parsec中存在支持这种行为的功能这一事实使我开始质疑自己。
在解析器组合器中对已经词法化的流进行解析有什么优点/缺点?
当我开始使用解析器组合器时,我的第一个反应是从感觉上像是在解析和词法化之间的人为区别中解放出来。突然所有的一切都只是解析!
但是,我最近在codereview.stackexchange上发现了此帖子,说明有人在恢复这种区别。起初我以为这对他们很愚蠢,但是后来Parsec中存在支持这种行为的功能这一事实使我开始质疑自己。
在解析器组合器中对已经词法化的流进行解析有什么优点/缺点?
Answers:
在解析下,我们最常理解上下文无关语言的分析。上下文无关的语言比常规语言更强大,因此解析器可以(通常)立即执行词法分析器的工作。
但是,这是a)非常不自然的b)通常效率低下。
对于a),如果我考虑一个if
表达式的外观,我认为IF expr THEN expr ELSE expr而不是'i'f',也许是空格,那么表达式可以以任何字符开头,依此类推。理念。
对于b),有强大的工具可以出色地识别词汇实体,例如标识符,文字,各种方括号等。它们几乎可以立即完成工作,并为您提供一个不错的界面:令牌列表。不再担心在解析器中跳过空格,当解析器处理令牌而不是字符时,解析器将更加抽象。
毕竟,如果您认为解析器应该忙于处理低级内容,那么为什么还要处理字符呢?一个人也可以写在位的水平!您会发现,这种在位级别上运行的解析器几乎是难以理解的。字符和标记相同。
只是我的2美分。
if = string "if" >> expr >> string "then" >> expr >> string "else" >> expr
。
每个人都建议将词法分析与语法分析分开是一种“良好做法”,我不得不不同意-在许多情况下,单遍执行词法分析与语法分析可以提供更多的功能,并且性能影响不如本文中介绍的那么糟糕。其他答案(请参阅Packrat)。
当必须在一个输入流中混合使用多种不同的语言时,这种方法将大放异彩。这不仅是由像怪异的导向元编程语言需要卡塔丁和一致好评,但对于更多的主流应用,以及像有文化的编程在注释中使用HTML,馅的Javascript成HTML(混合乳液,并说,C ++),以及以此类推。
词法分析器可识别常规语言,而解析器可识别上下文无关的语言。由于每种常规语言也是上下文无关的(可以通过所谓的右线性语法定义),因此解析器还可以识别常规语言,并且解析器和词法分析器之间的区别似乎增加了一些不必要的复杂性:单个上下文语法(解析器)可以完成解析器和词法分析器的工作。
另一方面,通过常规语言(因此是词法分析器)捕获上下文无关语言的某些元素可能很有用,因为
因此,将分析与词法分析分开具有优势,您可以使用更简单的上下文无关文法,并在词法分析器(divide et impera)中封装一些基本(通常是常规)任务。
编辑
我对解析器组合器不熟悉,因此我不确定上述注意事项在这种情况下如何应用。我的印象是,即使使用解析器组合器只有一个上下文无关的语法,在两个级别之间进行区分(词法分析/解析)也可以帮助使这种语法更加模块化。如前所述,较低的词法分析层可以包含用于标识符,文字等的基本可重用解析器。
\alpha'_1 (K_0, \vec{T})
\ alpha'_1,K_0和\ vec {T}之类的表达式。是标识符。
简而言之,应将词法分析和语法分析分开,因为它们是不同的复杂性。Lexing是DFA(确定性有限自动机),解析器是PDA(下推自动机)。这意味着与lexing相比,解析在本质上消耗更多的资源,并且只有DFA可以使用特定的优化技术。此外,编写有限状态机要简单得多,并且更容易实现自动化。
通过使用语法分析算法来浪费您的时间。
单独的parse / lex的主要优点之一是中间表示-令牌流。可以以多种方式处理此问题,否则无法使用合并的lex / parse进行处理。
就是说,我发现,相对于学习一些解析器生成器,并且必须弄清楚如何在解析器生成器的规则内表达语法的弱点,良好的'ol递归体面操作可以更简单,更轻松地工作。