編譯原理的龍書和虎書,各看了兩章以後,¥……&……*……@%¥node
好吧,既然是碼農,就要從基層作起,我嘗試handwritten一下C或者C的極小子集的one-pass編譯器先,等有了深切的體會再去研究那些高深的形式理論也不遲。因而,我花了幾天搞了簡單的詞法分析,還費了一包子力,憑我那捉急的智商,湊出來一個像是語法樹的東西,能解析四則運算表達式。書上說手寫編譯器用遞歸降低法最合適,我想了半天也不知道咋遞歸降低。。剛纔看了看書上的簡化手寫語法分析器,一共才100行不到,我只好望書興嘆了,唉,底子徹底不夠硬啊,差得遠啊。git
寫了幾天hardcode的一點心得:算法
終於有點明白爲何書上要咱們把文法的BNF產生式都列出來,而後再相應的爲每一個產生式寫實現函數了,這實際上是在算法解耦。 好比咱們能夠測試發現,下面的遞歸降低語法器是不支持unary operator的,好比3*-2。若是想加入這個運算規則,咱們只需在文法中新加入一條規則,而後修繕文法,最後編碼:在遞歸降低的層次中加入一個unary()函數,下層是factor(),上層是term(),完成。如此即可以經過加新的函數來擴展支持邏輯運算,比較運算。而若是像我那樣hardcode的話。。。。。。。擴展的時候翔的感受一會兒就出來了。編程
並且考慮到相似這樣的語法特性:函數
a = b = c = 1;測試
利用遞歸降低法也能完美簡潔的解決啊!編碼
爲何要編譯原理?由於我手寫的玩意已經愈來愈意大利麪條了,每擴充一個feature真是牽一髮而動全身,本身都徹底不能肯定有沒有給其餘地方引入bug,也許最後能編譯通常的C代碼文件了,可是我TM都不知道爲何它能運做,當要移植到其它平臺或者想複用來作個其它語言的編譯器時,只能傻眼了.這正是所謂的"靠人品編程".此乃碼農的標誌性特徵:先把功能趕完,bug可不敢說沒有有的話大不了加班修修補補唄...大神們作最基礎的編譯器時可不敢懷着這種大無畏精神...雖然個人意大利麪條杯具了,可是不錯的是認識到了編譯原理的重要性..lua
貼上代碼:spa
標準的遞歸降低語法器:.net
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 }
最後,無心中看到了這哥們擺弄的玩意,貌似也比我好不到哪去。。。。。。哇哈哈哈,可悲的咱碼農啊