介绍
Spirit是一个使用模板元编程技术实现的面向对象的递归下降解析器生成器框架。表达式模板允许我们完全使用C++来模拟扩展巴克斯范式(EBNF)的语法。
在Spirit框架中,我们仅仅使用C++就能编写目标文法。直接嵌入的EBNF文法说明可以自由地与其他C++代码混合的一起。由于C++模板的再生能力,这种文法说明是可以直接执行的。请回想一下,常规的编译器之编译器或解析器的生成器必须执行一个附加的翻译步骤,即将EBNF源代码转换为C或C++代码。
一段简单的EBNF文法片断:
group ::= '(' expression ')'
factor ::= integer | group
term ::= factor (('*' factor) | ('/' factor))*
expression ::= term (('+' term) | ('-' term))*
通过使用Spirit中的功能可被模拟成如下代码片断:
group ::= '(' >> expression >> ')';
factor ::= integer | group;
term ::= factor >> *(('*' >> factor) | ('/' >> factor));
expression ::= term >> *(('+' >> term) | ('-' >> term));
凭借表达式模板的威力,EBNF文法变成了完全合法的,且可以执行的C++代码。产生式规则expression实际上是一个对象,它有一个成员函数parse,在给定表示文法的源代码之后(就像我们刚刚声明的代码段那样),该函数会进行解析工作。不错,这是一个计算器。为了简单起见,此处我们省略了类型的声明和factor所调用的规则integer的定义。
在我们的文法说明中,产生式规则expression(传统上将其称为开始符号)能够识别如下输入:
12345
-12345
+12345
1 + 2
1 * 2
1/2 + 3/4
1 + 2 + 3 + 4
1 * 2 * 3 * 4
(1 + 2) * (3 + 4)
(-1 + 2) * (3 + -4)
1 + ((6 * 200) - 20) / 6
(1 + (2 + (3 + (4 + 5))))
当然,我们已对原始的EBNF语法做出了一些修改。这样做的目的是为了使其符合C++的语法规则。特别是我们可以看到大量的移位运算符>>。由于C++中不存在“空”运算符,因此我们不能简单地将代码写成如下形式:
a b
这种形式在数学中表示乘法;在我们的EBNF语法中表示连接(即b跟在a的后面)。而本框架使用移位运算符>>来达到该目的。我们选择向左移位运算符>>(箭头指向左边),用以表达“在其后跟随着...”。因此,正确的写法是:
a >> b
交替运算符 | 和括号( )仍保持不变。赋值运算符=取代了EBNF中的::=。最后需要指出的是,在EBNF中被当作后缀运算符使用的克林星号*在此变成了前缀运算符。请不要写成:
a* // ... 在EBNF语法中
而应写成:
*a // ... 在Spirit中
原因是在C或C++中不存在后缀星号运算符“*”。最后,我们要使用分号“;”作为每条文法规则的结束标志。
版权所有 (c) 1998-2003 Joel de Guzman
使用、修改和发行应遵守Boost软件许可证,版本1.0.(参见附带文件LICENSE_1_0.txt或者位于http://www.boost.org/LICENSE_1_0.txt处的副本)。
浙公网安备 33010602011771号