也许您已经听说过解析器生成器,例如 yacc、bison 或 ANTLR 工具。解析器生成器是一种工具,当输入语言的正式描述时,将生成解析器作为其输出。 这个输出是可以被编译/解释的代码,并且可以用源代码作为输入来生成语法树。
有许多解析器生成器,它们接收的格式和它们产生的输出语言不同。他们中的大多数无法使用上下文语法(CFG)作为输入。CFG是一组规则,用于描述如何在语言中形成正确(根据语法有效)的句子。CFG最常见的符号形式是Backus-Naur形式(BFN)或者Extended Backus-Naur形式 (EBNF)。
PrimaryExpression ::= "this"
| ObjectLiteral
| ( "(" Expression ")" )
| Identifier
| ArrayLiteral
| Litera
Literal ::= ( <DECIMAL_LITERAL>
| <HEX_INTEGER_LITERAL>
| <STRING_LITERAL>
| <BOOLEAN_LITERAL>
| <NULL_LITERAL>
| <REGULAR_EXPRESSION_LITERAL> )
Identifier ::= <IDENTIFIER_NAME>
ArrayLiteral ::= "[" ( ( Elision )? "]"
| ElementList Elision "]"
| ( ElementList )? "]")
ElementList ::= ( Elision )? AssignmentExpression
( Elision AssignmentExpression )*
Elision ::= ( "," )+
ObjectLiteral ::= "{" ( PropertyNameAndValueList )? "}"
PropertyNameAndValueList ::= PropertyNameAndValue ( "," PropertyNameAndValue
| "," )*
PropertyNameAndValue ::= PropertyName ":" AssignmentExpression
PropertyName ::= Identifier
| <STRING_LITERAL>
| <DECIMAL_LITERAL>
这是 BNF 中 EcmaScript 语法的完整描述的一部分。 例如,解析器生成器会将类似的东西转换成可编译的 C 代码。
可能你已经听说过你应该使用一个解析器生成器代替写一个解析器。“跳过这一部分”,他们说,“这是一个已解决的问题。”这种推荐的原因是解析器非常适合自动生成。解析是计算机科学中最容易理解的分支之一,真正聪明的人已经在解析问题上投入了大量的时间,他们的工作成果是CFG、BNF、EBNF、解析器生成器和其中使用的高级解析技术。为什么不你不应该利用它?
我不认为学习写你自己的解析器浪费时间。我实际上觉得它非常有价值。只有在你写过自己的解析器之后才能尝试,或者至少尝试一下,你将会看到解析器生成的优点,他们拥有的缺点和他们的问题。对我来说,解析器生成器的概念只有在我写完第一个解析器后才会明白。 我看着它,然后才真正了解如何自动生成此代码。
大多数人,推荐使用解析器生成器的人,当其他人想要开始使用解析器和编译器时,只是因为他们之前自己编写过解析器。他们已经看到了可用的问题和解决方案,并决定最好使用现有工具来完成这项工作。它们是正确的——当你想要完成某件事并且处于生产环境中时,正确性和稳健性是优先事项。当然,那时你不应该尝试编写自己的解析器,尤其是如果你以前从未编写过。
但我们是来学习的,我们想了解解析器是如何工作的,此外,我认为这非常有趣。
< 2.1解析器 | > 2.3为Monkey语言写一个解析器 |
---|