看到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的目录便可以使用了