昨夜天气闷热,午夜里醒了,再难入睡,十分痛苦,于是起来打开电脑上网胡乱翻阅。
看到boost里面一个叫 spirit 的家伙,它的自我介绍里面这样写道:
Spirit is an object-oriented recursive-descent parser generator framework implemented using template meta-programming techniques.
有了它,就拥有了来自外星球的神奇力量,能够在C++代码里面像写 EBNF 一样写代码。真是无比神奇。我不得不对它的作者敬佩得五体投地。梦想着我自己能有一天也可以有能力带一点“来自外星球的神奇力量”来地球。向前辈高人致敬,向前辈高人学习……
看到boost里面一个叫 spirit 的家伙,它的自我介绍里面这样写道:
Spirit is an object-oriented recursive-descent parser generator framework implemented using template meta-programming techniques.
有了它,就拥有了来自外星球的神奇力量,能够在C++代码里面像写 EBNF 一样写代码。真是无比神奇。我不得不对它的作者敬佩得五体投地。梦想着我自己能有一天也可以有能力带一点“来自外星球的神奇力量”来地球。向前辈高人致敬,向前辈高人学习……
A simple EBNF grammar snippet:
group ::= '(' expression ')'
factor ::= integer | group
term ::= factor (('*' factor) | ('/' factor))*
expression ::= term (('+' term) | ('-' term))*
is approximated using Spirit's facilities as seen in this code snippet:
group = '(' >> expression >> ')'; factor = integer | group; term = factor >> *(('*' >> factor) | ('/' >> factor)); expression = term >> *(('+' >> term) | ('-' >> term));
找了点示例,胡乱改吧改吧,就是一个可以整形数加减乘除的计算器,wow,真的能计算。download source code here
1
2 #include <boost/spirit/core.hpp>
3 #include <iostream>
4 #include <string>
5
6 ////////////////////////////////////////////////////////////////////////////
7 using namespace std;
8 using namespace boost::spirit;
9
10 vector<int> operands;
11
12 ////////////////////////////////////////////////////////////////////////////
13 //
14 // Semantic actions
15 //
16 ////////////////////////////////////////////////////////////////////////////
17 void do_int(char const* str, char const* end)
18 {
19 string s(str, end);
20 int v = atoi(s.c_str());
21 operands.push_back(v);
22
23 }
24 void do_add(char const*, char const*) { int op = operands.back(); operands.pop_back();operands.back() += op; }
25 void do_subt(char const*, char const*) { int op = operands.back(); operands.pop_back();operands.back() -= op; }
26 void do_mult(char const*, char const*) { int op = operands.back(); operands.pop_back();operands.back() *= op; }
27 void do_div(char const*, char const*) { int op = operands.back(); operands.pop_back();operands.back() /= op; }
28 void do_neg(char const*, char const*) { operands.back() = 0-operands.back(); }
29
30 ////////////////////////////////////////////////////////////////////////////
31 //
32 // Our calculator grammar
33 //
34 ////////////////////////////////////////////////////////////////////////////
35 struct calculator : public grammar<calculator>
36 {
37 template <typename ScannerT>
38 struct definition
39 {
40 definition(calculator const& /*self*/)
41 {
42 expression
43 = term
44 >> *( ('+' >> term)[&do_add]
45 | ('-' >> term)[&do_subt]
46 )
47 ;
48
49 term
50 = factor
51 >> *( ('*' >> factor)[&do_mult]
52 | ('/' >> factor)[&do_div]
53 )
54 ;
55
56 factor
57 = lexeme_d[(+digit_p)[&do_int]] // lexeme_d directive to turns off white space skipping
58 | '(' >> expression >> ')'
59 | ('-' >> factor)[&do_neg]
60 | ('+' >> factor)
61 ;
62 }
63
64 rule<ScannerT> expression, term, factor;
65 rule<ScannerT> const&
66 start() const { return expression; }
67 };
68 };
69
70 ////////////////////////////////////////////////////////////////////////////
71 //
72 // Main program
73 //
74 ////////////////////////////////////////////////////////////////////////////
75 int
76 main()
77 {
78 cout << "/////////////////////////////////////////////////////////\n\n";
79 cout << "\t\tExpression parser\n\n";
80 cout << "/////////////////////////////////////////////////////////\n\n";
81 cout << "Type an expressionor [q or Q] to quit\n\n";
82
83 calculator calc; // Our parser
84
85 string str;
86 while (getline(cin, str))
87 {
88 if (str.empty() || str[0] == 'q' || str[0] == 'Q')
89 break;
90
91 operands.clear();
92 parse_info<> info = parse(str.c_str(), calc, space_p);
93
94 if (info.full)
95 {
96 cout << "-------------------------\n";
97 cout << "Parsing succeeded\n";
98 cout << "Result:" << operands.back() << endl;
99 cout << "-------------------------\n";
100 }
101 else
102 {
103 cout << "-------------------------\n";
104 cout << "Parsing failed\n";
105 cout << "stopped at: \": " << info.stop << "\"\n";
106 cout << "-------------------------\n";
107 }
108 }
109
110 cout << "Bye :-) \n\n";
111 return 0;
112 }
2 #include <boost/spirit/core.hpp>
3 #include <iostream>
4 #include <string>
5
6 ////////////////////////////////////////////////////////////////////////////
7 using namespace std;
8 using namespace boost::spirit;
9
10 vector<int> operands;
11
12 ////////////////////////////////////////////////////////////////////////////
13 //
14 // Semantic actions
15 //
16 ////////////////////////////////////////////////////////////////////////////
17 void do_int(char const* str, char const* end)
18 {
19 string s(str, end);
20 int v = atoi(s.c_str());
21 operands.push_back(v);
22
23 }
24 void do_add(char const*, char const*) { int op = operands.back(); operands.pop_back();operands.back() += op; }
25 void do_subt(char const*, char const*) { int op = operands.back(); operands.pop_back();operands.back() -= op; }
26 void do_mult(char const*, char const*) { int op = operands.back(); operands.pop_back();operands.back() *= op; }
27 void do_div(char const*, char const*) { int op = operands.back(); operands.pop_back();operands.back() /= op; }
28 void do_neg(char const*, char const*) { operands.back() = 0-operands.back(); }
29
30 ////////////////////////////////////////////////////////////////////////////
31 //
32 // Our calculator grammar
33 //
34 ////////////////////////////////////////////////////////////////////////////
35 struct calculator : public grammar<calculator>
36 {
37 template <typename ScannerT>
38 struct definition
39 {
40 definition(calculator const& /*self*/)
41 {
42 expression
43 = term
44 >> *( ('+' >> term)[&do_add]
45 | ('-' >> term)[&do_subt]
46 )
47 ;
48
49 term
50 = factor
51 >> *( ('*' >> factor)[&do_mult]
52 | ('/' >> factor)[&do_div]
53 )
54 ;
55
56 factor
57 = lexeme_d[(+digit_p)[&do_int]] // lexeme_d directive to turns off white space skipping
58 | '(' >> expression >> ')'
59 | ('-' >> factor)[&do_neg]
60 | ('+' >> factor)
61 ;
62 }
63
64 rule<ScannerT> expression, term, factor;
65 rule<ScannerT> const&
66 start() const { return expression; }
67 };
68 };
69
70 ////////////////////////////////////////////////////////////////////////////
71 //
72 // Main program
73 //
74 ////////////////////////////////////////////////////////////////////////////
75 int
76 main()
77 {
78 cout << "/////////////////////////////////////////////////////////\n\n";
79 cout << "\t\tExpression parser\n\n";
80 cout << "/////////////////////////////////////////////////////////\n\n";
81 cout << "Type an expressionor [q or Q] to quit\n\n";
82
83 calculator calc; // Our parser
84
85 string str;
86 while (getline(cin, str))
87 {
88 if (str.empty() || str[0] == 'q' || str[0] == 'Q')
89 break;
90
91 operands.clear();
92 parse_info<> info = parse(str.c_str(), calc, space_p);
93
94 if (info.full)
95 {
96 cout << "-------------------------\n";
97 cout << "Parsing succeeded\n";
98 cout << "Result:" << operands.back() << endl;
99 cout << "-------------------------\n";
100 }
101 else
102 {
103 cout << "-------------------------\n";
104 cout << "Parsing failed\n";
105 cout << "stopped at: \": " << info.stop << "\"\n";
106 cout << "-------------------------\n";
107 }
108 }
109
110 cout << "Bye :-) \n\n";
111 return 0;
112 }
这代码如此的美妙,实在无需多余的解释……
spirit 可以在 boost 类库 (http://www.boost.org/)里面找到。下载后解压,只需在 Project 属性页中的
Additional Include Directories 中添加boost的目录便可以使用了