参考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} {}
%%