zoukankan      html  css  js  c++  java
  • 果然还是SB了

    编译原理的龙书和虎书,各看了两章之后,¥……&……*……@%¥

    好吧,既然是码农,就要从基层做起,我尝试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, "错误
    ");
     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("================================================================
    ");
     25     printf("*               递归实现的四则运算表达式求值程序               *
    ");
     26     printf("****************************************************************
    ");
     27     printf("使用方法:请从键盘上直接输入表达式,以回车键结束.如45*(12-2)[回车]
    ");
     28     printf("*****************************************************************
    
    ");
     29 }
     30 main()
     31 {
     32     int result;  /*运算的结果*/
     33     Message();
     34     printf(" >> 请输入表达式: ");
     35     token = getchar(); /*载入第一个符号*/
     36     
     37     result = exp(); /*进行计算*/
     38     if( token == '
    ' ) /* 是否一行结束 */
     39         printf( " >> 表达式的计算结果为 : %d
    ", result );
     40     else error(); /* 出现了例外的字符 */
     41     puts("
    
                      请按任意键退出 ...
    ");
     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.
    " );
     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

  • 相关阅读:
    最小生成树问题-prim算法求解
    排序算法7---快速排序算法
    IOS工作笔记(九)
    NSUserDefaults的一些用法
    UIActionSheet的简单使用
    如何处理过多使用懒加载的问题?
    prefix.pch文件的一些简单使用
    IOS工作笔记(八)
    登录时本地保存账号密码及关闭ARC的方法
    IOS页面跳转的方法
  • 原文地址:https://www.cnblogs.com/mavaL/p/3292680.html
Copyright © 2011-2022 走看看