美文网首页Linux学习之路Linux我用 Linux
六. 基于Flex/Bison/符号表写一个仿bc计算器

六. 基于Flex/Bison/符号表写一个仿bc计算器

作者: Dakini_Wind | 来源:发表于2019-03-06 22:42 被阅读0次

    参考bc命令手册(执行man bc便可看到),模仿bc的语法写一个高级计算器,希望最终能够实现整个bc所具有的功能。


    [正在不断完善中...]
    当前进度:1. 实现+、-、*、/、^、括号以及他们的优先级


    实现代码:

    关于符号表设计请看我这篇《用c with class写一个符号表》

    bison代码:

    /*
     *file: bc.l
     *auther: jin1ming
     *system: manjaro
     */
    %{
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include "SymbolTable.h"
    SymbolTable *st;
    %}
    %union{ 
        double dbl;
        char* str;
    };
    
    %token <dbl> NUMBER 
    %token <str> ID
    %token POWER REM DOL
    %token ADD SUB MUL DIV
    %token EOL SCALE INC DEC
    %token LPAREN RPAREN
    %type <dbl> expression arithmetic_expression_list
    %type <dbl> arithmetic_expression
    %%
    calclist
        :/* 空规则 */
        | calclist expression EOL{ printf("= %lf\n",$2); }
        ;
    /*
     *表达式
     *分为条件表达式、赋值表达式、算数表达式
     */
    expression
        :   arithmetic_expression_list { $$ = $1; }
        ;
    /*
     *算数表达式
     *  拆分成两个,以消除偏移/规约冲突
     */
    arithmetic_expression_list
        :   arithmetic_expression_list ADD arithmetic_expression { $$ = $1 + $3; }
        |   arithmetic_expression_list SUB arithmetic_expression { $$ = $1 - $3; }
        |   arithmetic_expression_list MUL arithmetic_expression { $$ = $1 * $3; }
        |   arithmetic_expression_list DIV arithmetic_expression { $$ = $1 / $3; }
        |   arithmetic_expression_list POWER arithmetic_expression { $$ = pow($1,$3); }
        |   arithmetic_expression_list REM arithmetic_expression { $$ = (int)$1 % (int)$3; }
        /**/
        |   arithmetic_expression_list ADD LPAREN arithmetic_expression_list RPAREN { $$ = $1 + $4; }
        |   arithmetic_expression_list SUB LPAREN arithmetic_expression_list RPAREN { $$ = $1 - $4; }
        |   arithmetic_expression_list MUL LPAREN arithmetic_expression_list RPAREN { $$ = $1 * $4; }
        |   arithmetic_expression_list DIV LPAREN arithmetic_expression_list RPAREN { $$ = $1 / $4; }
        |   arithmetic_expression_list POWER LPAREN arithmetic_expression_list RPAREN { $$ = pow($1,$4); }
        |   arithmetic_expression_list REM LPAREN arithmetic_expression_list RPAREN { $$ = (int)$1 % (int)$4; }
        /**/
        |   arithmetic_expression { $$ = $1; }
        |   LPAREN arithmetic_expression_list RPAREN { $$ = $2; }
        ;
    arithmetic_expression
        : NUMBER 
        | ID    INC { double v = st->find(st,$1)+1;
                                st->modify(st,$1,v); 
                                $$ = v-1; }
        | ID    DEC { double v = st->find(st,$1)-1;
                                st->modify(st,$1,v); 
                                $$ = v+1; }
    //  |   ADD ID  { $$ = st->find(st,$2); }
    //  |   SUB ID  { $$ = 0 - st->find(st,$2); }
        ;
    
    %%
    
    int main(int argc,char **argv)
    {
            st = newSymbolTable(); 
        yyparse();
    }
    int yyerror(char *s)
    {
        printf("error: %s\n",s);
        return 0;
    }
    

    flex代码:

    /*
     *file: bc.l
     *auther: jin1ming
     *system: manjaro
     */
    %option yylineno
    %{
    #include "bc.tab.h"
    %}
     
    /*数字定义*/
    /*科学计数表示*/
    science {decimal}(\.[0-9]+)?([Ee][-+]?[0-9]+)?
    /*十进制*/
    decimal 0|[1-9][0-9]*
    /*十六进制*/
    hexadecimal 0[xX][a-fA-F0-9]+
    /*二进制*/
    binary 0[bB][01]+
    /*八进制*/
    octal 0[0-7]+
    /*总表示*/
    number ({hexadecimal}|{binary}|{science}|{octal})(([uU]?[Ll]?)|([Ll]?[Uu]?)|([fF]?))
    /*注意浮点数总是有符号,不需要Uu后缀,所以在接下来单做一个浮点数异常处理*/
    /*数字异常处理*/
    floatexcption {decimal}\.[0-9]+([Ee]?[-+]?[0-9]+)?[Uu]
    excption [0-9][0-9a-zA-Z\.]+
    
    /*小数点后的精度*/
    SCALE scale
    
    /*注释*/
    COMMENT \/\*(.|\n)*\/
    
    /*标识符定义*/
    identifier [a-z_A-Z][a-z_A-Z0-9]*
     
    /*其它字符*/
    whitespace [ \t\n\r\f\v]+
    EOL         ;
    errno       .
    %%
     /*算数运算符*/
    "+"     { return ADD; }
    "-"     { return SUB; }
    "*"     { return MUL; }
    "/"     { return DIV; }
    "^"     { return POWER; }
    "%"    { return REM; }
    "$"         { return DOL; }
    "++"            { return INC; }
    "--"        { return DEC; }
     /*标点符号*/
    "(" {   return LPAREN;  }
    ")" { return RPAREN;    }
    ";"         {   return EOL; }
     /*系统内置变量*/
    {SCALE}             { return SCALE; }
     /*数字及标识符*/
    {number}            { yylval.dbl = atof(yytext); return NUMBER;}
    {identifier} { yylval.str = strdup(yytext); return ID;}
     /*数字异常处理*/
    {floatexcption} { printf("error:2\n");exit(2);}
    {excption}      { printf("error:3\n");exit(3);}
     /*未识别字符*/
    {errno}             {printf("error:5\nOn line %d,mystery character:  %s\n",yylineno,yytext);exit(4);}
     /*跳过空白和注释*/
    {whitespace} {}
    {COMMENT}           {}
    %%
    

    相关文章

      网友评论

        本文标题:六. 基于Flex/Bison/符号表写一个仿bc计算器

        本文链接:https://www.haomeiwen.com/subject/yecouqtx.html