• 表达式计算器(LL1文法)


    LL(1)文法求算数表达式的值
    递归子程序法

    分析过程:

    表达式文法G[E]:
    E->E+T|E-T|T
    T->T*F|T/F|T%F|F
    F->N^F|N
    N->(E)|NUM|+NUM|-NUM

    消除左递归、左公共因子
    E ->TE'
    E'->+TE'|-TE'|ε
    T ->FT'
    T'->*FT'|/FT'|%FT'|ε
    F ->NF'
    F'->^F|ε
    N->(E)|NUM|+NUM|-NUM

    FIRST集和FOLLOW集

    LL(1)分析表

    (应该没错吧……表示昨天刚考完试……)

    (嗯。。我承认我抄。。咳咳。。借鉴了这份代码http://ideone.com/o2Ag4。。还是炮姐写的好。。)

    #include <cstdio>
    #include <cmath>
    
    /**
     * LL(1)文法求算数表达式的值
     * 递归子程序法
    **/
    
    enum SYM_KIND {     // 符号类型
        SYM_NUM,        // num
        SYM_ADD,        // +
        SYM_SUB,        // -
        SYM_MUL,        // *
        SYM_DIV,        // /
        SYM_MOD,        // %
        SYM_POW,        // ^
        SYM_LBR,        // (
        SYM_RBR,        // )
        SYM_END,        // ''
        SYM_ERR         // 其他不合法符号
    };
    
    enum ERR_KIND {     // 状态
        ERR_OK,
        ERR_INVALID_CHAR,
        ERR_NO_OPERATOR,
        ERR_BR_NOT_MATCH,
        ERR_NO_NUM,
        ERR_END
    };
    
    char expr[2000];    // 表达式
    int pos;            // 读取到表达式的位置
    double val;
    ERR_KIND err;
    
    void F();
    void E();
    
    void NUM()
    {
        val = 0;
        while (expr[pos] <= '9' && expr[pos] >= '0')
        {
            val = val * 10 + expr[pos] - '0';
            pos++;
        }
        if (expr[pos] == '.')
        {
            pos++;
            double eo = 0.1;
            while (expr[pos] <= '9' && expr[pos] >= '0')
            {
                val += (expr[pos] - '0') * eo;
                eo *= 0.1;
                pos++;
            }
        }
    }
    
    SYM_KIND get_sym()   // 读取一个单词
    {
        char ch = expr[pos++];
        while (ch == ' ' || ch == '	') // 忽略空格
            ch = expr[pos++];
        if (ch <= '9' && ch >= '0')
        {
            pos--;
            NUM();
            return SYM_NUM;
        }
        else if (ch == '+') return SYM_ADD;
        else if (ch == '-') return SYM_SUB;
        else if (ch == '*') return SYM_MUL;
        else if (ch == '/') return SYM_DIV;
        else if (ch == '%') return SYM_MOD;
        else if (ch == '^') return SYM_POW;
        else if (ch == '(') return SYM_LBR;
        else if (ch == ')') return SYM_RBR;
        else if (ch == '')
        {
            err = ERR_END;
            return SYM_END;
        }
        err = ERR_INVALID_CHAR;
        return SYM_ERR;
    }
    
    void N()  // N->(E)|NUM|+NUM|-NUM
    {
        if (err != ERR_OK) return ;
        SYM_KIND kind = get_sym();
        if (kind == SYM_LBR)
        {
            E();
            if (err == ERR_END)
            {
                err = ERR_BR_NOT_MATCH;
            }
            else if (err == ERR_OK)
            {
                kind = get_sym();
                if (kind != SYM_RBR)
                    err = ERR_BR_NOT_MATCH;
            }
        }
        else if (kind == SYM_ADD)
        {
            kind = get_sym();
            if (kind != SYM_NUM)
            {
                err = ERR_NO_NUM;
            }
        }
        else if (kind == SYM_SUB)
        {
            kind = get_sym();
            if (kind != SYM_NUM)
            {
                err = ERR_NO_NUM;
            }
            val = -val;
        }
        else if (kind != SYM_NUM)
        {
            err = ERR_NO_NUM;
        }
    }
    
    void F_() // F'->^F|ε
    {
        if (err != ERR_OK) return ;
        SYM_KIND kind = get_sym();
        double tmp = val;
        if (kind == SYM_POW)
        {
            F();
            val = pow(tmp, val);
        }
        else if (kind == SYM_ADD || kind == SYM_SUB || kind == SYM_MUL || kind == SYM_DIV
                || kind == SYM_MOD || kind == SYM_END || kind == SYM_RBR)
        {
            pos--;
        }
        else if (kind != SYM_ERR)
            err = ERR_NO_OPERATOR;
    }
    
    void F()  // F ->NF'
    {
        if (err != ERR_OK) return ;
        N();
        F_();
    }
    
    void T_() // T'->*FT'|/FT'|%FT'|ε
    {
        if (err != ERR_OK) return ;
        SYM_KIND kind = get_sym();
        double tmp = val;
        if (kind == SYM_MUL)
        {
            F();
            val *= tmp;
            T_();
        }
        else if (kind == SYM_DIV)
        {
            F();
            val = tmp / val;
            T_();
        }
        else if (kind == SYM_MOD)
        {
            F();
            val = fmod(tmp, val);
            T_();
        }
        else if (kind == SYM_ADD || kind == SYM_SUB || kind == SYM_RBR || kind == SYM_END)
        {
            pos--;
        }
        else if (kind != SYM_ERR)
        {
            err = ERR_NO_OPERATOR;
        }
    }
    
    void T()   // T ->FT'
    {
        if (err != ERR_OK) return ;
        F();
        T_();
    }
    
    void E_()  // E'->+TE'|-TE'|ε
    {
        if (err != ERR_OK) return ;
        SYM_KIND kind = get_sym();
        double tmp = val;
        if (kind == SYM_ADD)
        {
            T();
            val = tmp + val;
            E_();
        }
        else if (kind == SYM_SUB)
        {
            T();
            val = tmp - val;
            E_();
        }
        else if (kind == SYM_END || kind == SYM_RBR)
        {
            pos--;
        }
        else if (kind != SYM_ERR)
        {
            err = ERR_NO_OPERATOR;
        }
    }
    
    void E()   // E ->TE'
    {
        if (err != ERR_OK) return ;
        T();
        E_();
    }
    
    void output_err()
    {
        if (err == ERR_OK)
        {
            err = ERR_BR_NOT_MATCH;
            pos++;
        }
        printf("%*s ^", pos, "");
        if (err == ERR_BR_NOT_MATCH) printf("括号不匹配
    ");
        else if (err == ERR_NO_NUM) printf("缺少一个数字
    ");
        else if (err == ERR_NO_OPERATOR) printf("缺少一份运算符
    ");
        else if (err == ERR_INVALID_CHAR) printf("不合法字符
    ");
    }
    
    int main()
    {
        printf(">>");
        while (gets(expr) != NULL)
        {
            pos = 0;
            err = ERR_OK;
            E();
            if (err == ERR_END) printf("%g
    ", val);
            else output_err();
            printf(">>");
        }
        return 0;
    }
    View Code

     

    运行结果:
    >>3+4^2.2
    24.1121
    >>2-7/8
    1.125
    >>(8+0
               ^括号不匹配
    >>7%5
    2
    >>7+9.9+
                  ^缺少一个数字

    加个界面……

  • 相关阅读:
    java 集合list遍历时删除元素
    循环中的continue功能
    sql中的!=判断的注意事项
    oracle中时间处理
    judge return character
    ashamed
    char and number transform
    将十进制转化为二进制
    算法和程序
    输入分子和分母,打印出前1000位小数
  • 原文地址:https://www.cnblogs.com/wenruo/p/5077940.html
Copyright © 2020-2023  润新知