编译原理的龙书和虎书,各看了两章之后,¥……&……*……@%¥
好吧,既然是码农,就要从基层做起,我尝试handwritten一下C或者C的极小子集的one-pass编译器先,等有了深切的体会再去研究那些高深的形式理论也不迟。于是,我花了几天搞了简单的词法分析,还费了一包子力,凭我那捉急的智商,凑出来一个像是语法树的东西,能解析四则运算表达式。书上说手写编译器用递归下降法最合适,我想了半天也不知道咋递归下降。。刚才看了看书上的简化手写语法分析器,一共才100行不到,我只好望书兴叹了,唉,底子完全不够硬啊,差得远啊。
写了几天hardcode的一点心得:
终于有点明白为什么书上要我们把文法的BNF产生式都列出来,然后再相应的为每个产生式写实现函数了,这其实是在算法解耦。 比如我们可以测试发现,下面的递归下降语法器是不支持unary operator的,比如3*-2。如果想加入这个运算规则,我们只需在文法中新加入一条规则,然后修缮文法,最后编码:在递归下降的层次中加入一个unary()函数,下层是factor(),上层是term(),完成。如此便可以通过加新的函数来扩展支持逻辑运算,比较运算。而如果像我那样hardcode的话。。。。。。。扩展的时候翔的感觉一下子就出来了。
而且考虑到类似这样的语法特性:
a = b = c = 1;
利用递归下降法也能完美简洁的解决啊!
为什么要编译原理?因为我手写的玩意已经越来越意大利面条了,每扩充一个feature真是牵一发而动全身,自己都完全不能确定有没有给其他地方引入bug,也许最后能编译一般的C代码文件了,但是我TM都不知道为什么它能运作,当要移植到其它平台或者想复用来做个其它语言的编译器时,只能傻眼了.这正是所谓的"靠人品编程".此乃码农的标志性特征:先把功能赶完,bug可不敢说没有有的话大不了加班修修补补呗...大神们做最基础的编译器时可不敢怀着这种大无畏精神...虽然我的意大利面条杯具了,但是不错的是认识到了编译原理的重要性..
贴上代码:
标准的递归下降语法器:
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 char token; /*全局标志变量*/
5
6 /*递归调用的函数原型*/
7 int exp( void );
8 int term( void );
9 int factor( void );
10
11 void error( void ) /*报告出错信息的函数*/
12 {
13 fprintf( stderr, "错误\n");
14 exit( 1 );
15 }
16
17 void match( char expectedToken ) /*对当前的标志进行匹配*/
18 {
19 if( token == expectedToken ) token = getchar(); /*匹配成功,获取下一个标志*/
20 else error(); /*匹配不成功,报告错误*/
21 }
22 void Message(void)
23 {
24 printf("================================================================\n");
25 printf("* 递归实现的四则运算表达式求值程序 *\n");
26 printf("****************************************************************\n");
27 printf("使用方法:请从键盘上直接输入表达式,以回车键结束.如45*(12-2)[回车]\n");
28 printf("*****************************************************************\n\n");
29 }
30 main()
31 {
32 int result; /*运算的结果*/
33 Message();
34 printf(" >> 请输入表达式: ");
35 token = getchar(); /*载入第一个符号*/
36
37 result = exp(); /*进行计算*/
38 if( token == '\n' ) /* 是否一行结束 */
39 printf( " >> 表达式的计算结果为 : %d\n", result );
40 else error(); /* 出现了例外的字符 */
41 puts("\n\n 请按任意键退出 ...\n");
42 getch();
43 return 0;
44 }
45
46 int exp( void )
47 {
48 int temp = term(); /*计算比加减运算优先级别高的部分*/
49 while(( token == '+' ) || ( token == '-' ))
50 switch( token ) {
51 case '+': match('+'); /*加法*/
52 temp += term();
53 break;
54 case '-': match('-');
55 temp -= term(); /*减法*/
56 break;
57 }
58 return temp;
59 }
60
61 int term( void )
62 {
63 int div; /*除数*/
64 int temp = factor(); /*计算比乘除运算优先级别高的部分*/
65 while(( token == '*' ) || ( token == '/' ))
66 switch( token ) {
67 case '*': match('*'); /*乘法*/
68 temp *= factor();
69 break;
70 case '/': match('/'); /*除法*/
71 div = factor();
72 if( div == 0 ) /*需要判断除数是否为0*/
73 {
74 fprintf( stderr, "除数为0.\n" );
75 exit(1);
76 }
77 temp /= div;
78 break;
79 }
80 return temp;
81 }
82
83 int factor( void )
84 {
85 int temp;
86 if( token == '(' ) /*带有括号的运算*/
87 {
88 match( '(' );
89 temp = exp();
90 match(')');
91 }
92 else if ( isdigit( token )) /*实际的数字*/
93 {
94 ungetc( token, stdin ); /*将读入的字符退还给输入流*/
95 scanf( "%d", &temp ); /*读出数字*/
96 token = getchar(); /*读出当前的标志*/
97 }
98 else error(); /*不是括号也不是数字*/
99 return temp;
100 }
我那翔一般的代码:
1 #include "StdAfx.h"
2 #include "SyntaxTree.h"
3 #include "Compiler.h"
4
5 eTokenType SyntaxTree::lastTokenType = eTokenType_Invalid;
6
7 int SyntaxTreeOpNode::Evaluate()
8 {
9 if (!strcmp(op, "+"))
10 {
11 return lchild->Evaluate() + rchild->Evaluate();
12 }
13 else if (!strcmp(op, "-"))
14 {
15 return lchild->Evaluate() - rchild->Evaluate();
16 }
17 else if (!strcmp(op, "*"))
18 {
19 return lchild->Evaluate() * rchild->Evaluate();
20 }
21 else if (!strcmp(op, "/"))
22 {
23 return lchild->Evaluate() / rchild->Evaluate();
24 }
25 else
26 {
27 //TODO: refactoring for no ugly if-else
28 assert(0);
29 return 0;
30 }
31 }
32
33 bool SyntaxTreeOpNode::IsThisOpPriorityHigher( const char* s )
34 {
35 return cl.opPriorityMap[op] >= cl.opPriorityMap[s];
36 }
37
38 int SyntaxTreeLeafNode::Evaluate()
39 {
40 return value;
41 }
42
43 int SyntaxTreeRootNode::Evaluate()
44 {
45 assert(rchild && "WTF!? This is not my tree!");
46 return rchild->Evaluate();
47 }
48
49 SyntaxTree::SyntaxTree()
50 :root(nullptr)
51 {
52 }
53
54 SyntaxTree::~SyntaxTree()
55 {
56 ResetTree();
57 }
58
59 bool SyntaxTree::ConstructTree(int len)
60 {
61 const char* expstart = cl.sentence + cl.sentence_curpos;
62 assert(expstart[0] != 0);
63 char op[MAX_IDENT_LEN];
64 eTokenType type;
65 SyntaxTreeNode* curNode = root;
66 std::vector<int> vecNums;
67 std::vector<SyntaxTreeOpNode*> vecFlatNodes;
68
69 //1.首先构建运算符的树结构
70 while (cl.sentence_curpos < len)
71 {
72 type = cl.ScanWord(op);
73 if (type == eTokenType_Operator)
74 {
75 auto iter = cl.opPriorityMap.find(op);
76 assert(iter != cl.opPriorityMap.end() && "Invalid op!");
77 SyntaxTreeOpNode* node = new SyntaxTreeOpNode;
78 strcpy_s(node->op, ARRAYSIZE(node->op), op);
79
80 //unary op process
81 bool bUnary = op[1]==0 && (op[0]=='+' || op[0]=='-');
82 if (lastTokenType==eTokenType_Operator || lastTokenType==eTokenType_LBracket && bUnary)
83 {
84 vecNums.push_back(0);
85 curNode->rchild = node;
86 node->parent = curNode;
87 }
88 else if (curNode->IsThisOpPriorityHigher(op))
89 {
90 assert(node->parent == nullptr);
91 curNode->parent = node;
92 node->lchild = curNode;
93 //降低root高度
94 root->rchild = node;
95 node->parent = root;
96 }
97 else
98 {
99 curNode->rchild = node;
100 node->parent = curNode;
101 }
102 curNode = node;
103 vecFlatNodes.push_back(node);
104 }
105 else if (type == eTokenType_ConstantNumber)
106 {
107 vecNums.push_back(atoi(op));
108 }
109 else if (type == eTokenType_LBracket)
110 {
111 int substr_len = len - 1;
112 //must find a matching r-bracket!
113 bool bFind = false;
114 while (substr_len >= cl.sentence_curpos)
115 {
116 if(cl.sentence[substr_len] == ')')
117 {
118 bFind = true;
119 break;
120 }
121 --substr_len;
122 }
123 if (bFind)
124 {
125 //对于括号,我们利用递归来求值...
126 SyntaxTree tmpTree;
127 tmpTree.ResetTree();
128 if(tmpTree.ConstructTree(substr_len))
129 vecNums.push_back(tmpTree.Evaluate());
130 else
131 return false;
132
133 assert(cl.sentence[cl.sentence_curpos] == ')' && "Can't be true!...");
134 ++cl.sentence_curpos;
135 }
136 else
137 {
138 LOG_ERR(eErr_NotMatchBracket);
139 return false;
140 }
141 type = eTokenType_ConstantNumber;
142 }
143 else
144 {
145 LOG_ERR(eErr_InvalidExpression);
146 return false;
147 }
148 lastTokenType = type;
149 }
150
151 //2.然后为每个运算符插入叶节点
152 if (root->rchild == nullptr)
153 {
154 LOG_ERR(eErr_InvalidExpression);
155 return false;
156 }
157
158 size_t leaf = 0, totalLeaf = vecNums.size();
159 for (size_t i=0; i<vecFlatNodes.size(); ++i)
160 {
161 SyntaxTreeOpNode* node = vecFlatNodes[i];
162 if (!node->lchild)
163 {
164 if (leaf < totalLeaf)
165 {
166 SyntaxTreeLeafNode* leafNode = new SyntaxTreeLeafNode;
167 leafNode->value = vecNums[leaf];
168 node->lchild = leafNode;
169 leafNode->parent = node;
170 ++leaf;
171 }
172 else
173 {
174 LOG_ERR(eErr_InvalidExpression);
175 return false;
176 }
177 }
178 if (!node->rchild)
179 {
180 if (leaf < totalLeaf)
181 {
182 SyntaxTreeLeafNode* leafNode = new SyntaxTreeLeafNode;
183 leafNode->value = vecNums[leaf];
184 node->rchild = leafNode;
185 leafNode->parent = node;
186 ++leaf;
187 }
188 else
189 {
190 LOG_ERR(eErr_InvalidExpression);
191 return false;
192 }
193 }
194 }
195
196 return true;
197 }
198
199 void SyntaxTree::ResetTree()
200 {
201 SAFE_DELETE(root);
202 root = new SyntaxTreeRootNode;
203 }
204
205 int SyntaxTree::Evaluate()
206 {
207 return root->Evaluate();
208 }
最后,无意中看到了这哥们摆弄的玩意,貌似也比我好不到哪去。。。。。。哇哈哈哈,可悲的咱码农啊
http://blog.csdn.net/zhouzxi/article/details/7897301
来源:https://www.cnblogs.com/mavaL/p/3292680.html