您的当前位置:首页六. 基于Flex/Bison/符号表写一个仿bc计算器

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

2024-12-13 来源:哗拓教育

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


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


实现代码:

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}           {}
%%
显示全文