[实现除函数定义及if while for语句的其它大部分功能]
参考bc
命令手册(执行man bc
便可看到),模仿bc的语法写一个高级计算器,能够实现整个bc所具有的大部分功能。
功能:
实现以下符号及其优先级
+
、-
、*
、/
、^
、(
、)
、
&&
、||
、++
、--
、%
、=
、
+=
、-=
、*=
、/=
实现给标识符赋值和调用
实现多行计算,使用
;
和\n
进行隔开实现内置变量
scale
来控制数字精度
,obase来控制进制格式
将
math.h
中函数全部移植
已知bug:
- 数字过大会溢出
- 给变量赋值语句,
=
两边不能有空格
效果演示:
sbc计算器演示效果
实现代码:
关于符号表设计请看我这篇《用c with class写一个符号表》
脚本:
#!/bin/bash
echo "flex执行开始!"
flex -o sbc.yy.c bc.l
echo "bison执行开始!"
bison -o sbc.tab.h bc.y
echo "gcc编译开始!"
gcc -o sbc -w *.c *.h -lfl -lrt -lm -lpthread
echo "删除中间文件..."
rm sbc.yy.c sbc.tab.*
echo "执行生成最终目标文件..."
echo "sbc计算器 v1.0.0"
./sbc
rm sbc
bison代码:
/*
*file: bc.y
*auther: jin1ming
*system: manjaro
*/
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "SymbolTable.h"
SymbolTable *st;
double getKey(SymbolTable* s,char* id);
void printBinary(int n);
int scale;//控制计算精度
int obase;//输出进制格式
char format[20];
%}
%union{
double dbl;
char* str;
};
%token <dbl> NUMBER IDs
%token <str> ID
%type <dbl> expression arithmetic_expression_list
%type <dbl> arithmetic_expression conditional_expression_list
%type <dbl> conditional_expression math_func
/*以下操作符有优先级,顺序不可改变*/
%left LOR
%left LAND
%left OR
%left AND
%left NEQ EQL
%left LSS GTR LEQ GEQ
%left ADD SUB
%left MUL DIV REM
%left POWER
%right ASSIGN ADD_ASSIGN SUB_ASSIGN MUL_ASSIGN DIV_ASSIGN REM_ASSIGN
%token EOL SCALE INC DEC NOT OBASE
%token LPAREN RPAREN COMMA
%token ACOS ASIN ATAN ATAN2 COS COSH FMOD
%token SIN SINH TANH EXP FREXP LDEXP FLOOR
%token LOG LOG10 MODF POW SQRT CEIL FABS
%%
calclist
: /* 空规则 */
| calclist statement EOL
;
/*
*所识别语句分为2种:
* 1.表达式,类似1+1,识别将输出结果
* 2.赋值语句,类似i=1,识别将进行赋值或修改值
*/
statement
: expression { if(obase == 10){
sprintf(format,"= %%.%dlf\n",scale);
printf(format,$1);
}else if (obase == 8) {
printf("= %o\n",(int)$1);
} else if (obase == 16) {
printf("= %x\n",(int)$1);
} else if (obase == 2) {
printf("= ");
printBinary((int)$1);
printf("\n");
}
}
| assignment
| /* 空规则,匹配空行 */
| system_statement
;
/*一些内置环境变量*/
system_statement
: SCALE ASSIGN NUMBER {scale = (int)$3; }
| OBASE ASSIGN NUMBER {obase = (int)$3; }
;
/*
*表达式
*分为条件表达式、算数表达式
*/
expression
: arithmetic_expression_list { $$ = $1; }
| conditional_expression_list { $$ = $1; }
;
/*赋值运算*/
assignment
: ID ASSIGN expression
{ st->modify(st,$1,$3); }
| ID ADD_ASSIGN expression
{ double tem = st->find(st,$1);
st->modify(st,$1,tem+$3); }
| ID SUB_ASSIGN expression
{ double tem = st->find(st,$1);
st->modify(st,$1,tem-$3); }
| ID MUL_ASSIGN expression
{ double tem = st->find(st,$1);
st->modify(st,$1,tem*$3); }
| ID DIV_ASSIGN expression
{ double tem = st->find(st,$1);
st->modify(st,$1,tem/$3); }
| ID REM_ASSIGN expression
{ double tem = st->find(st,$1);
st->modify(st,$1,(int)tem%(int)$3); }
;
/*
*算数表达式
* 拆分成两个,以消除偏移/规约冲突
*/
arithmetic_expression_list
: arithmetic_expression_list ADD arithmetic_expression_list
{ $$ = $1 + $3; }
| arithmetic_expression_list SUB arithmetic_expression_list
{ $$ = $1 - $3; }
| arithmetic_expression_list MUL arithmetic_expression_list
{ $$ = $1 * $3; }
| arithmetic_expression_list DIV arithmetic_expression_list
{ if(0 == $3) {
yyerror("errno:6\tDevided by zero!\n");
exit(6);
}
$$ = $1 / $3; }
| arithmetic_expression_list POWER arithmetic_expression_list
{ $$ = pow($1,$3); }
| arithmetic_expression_list REM arithmetic_expression_list
{ $$ = (int)$1 % (int)$3; }
| arithmetic_expression
{ $$ = $1; }
| LPAREN arithmetic_expression_list RPAREN
{ $$ = $2; }
| math_func
;
math_func
: ACOS arithmetic_expression_list RPAREN
{ $$ = acos($2); }
| ASIN arithmetic_expression_list RPAREN
{ $$ = asin($2); }
| ATAN arithmetic_expression_list RPAREN
{ $$ = atan($2); }
| ATAN2 arithmetic_expression_list COMMA arithmetic_expression_list RPAREN
{ $$ = atan2($2,$4); }
| COS arithmetic_expression_list RPAREN
{ $$ = cos($2); }
| COSH arithmetic_expression_list RPAREN
{ $$ = cosh($2); }
| FMOD arithmetic_expression_list COMMA arithmetic_expression_list RPAREN
{ $$ = fmod($2,$4); }
| SIN arithmetic_expression_list RPAREN
{ $$ = sin($2); }
| SINH arithmetic_expression_list RPAREN
{ $$ = sinh($2); }
| TANH arithmetic_expression_list RPAREN
{ $$ = tanh($2); }
| EXP arithmetic_expression_list RPAREN
{ $$ = exp($2); }
| FREXP arithmetic_expression_list COMMA arithmetic_expression_list RPAREN
{ $$ = frexp($2,(int)$4); }
| LDEXP arithmetic_expression_list COMMA arithmetic_expression_list RPAREN
{ $$ = ldexp($2,(int)$4); }
| FLOOR arithmetic_expression_list RPAREN
{ $$ = floor($2); }
| LOG arithmetic_expression_list RPAREN
{ $$ = log($2); }
| LOG10 arithmetic_expression_list RPAREN
{ $$ = log10($2); }
| MODF arithmetic_expression_list COMMA arithmetic_expression_list RPAREN
{ $$ = modf($2,&$4); }
| POW arithmetic_expression_list COMMA arithmetic_expression_list RPAREN
{ $$ = pow($2,$4); }
| SQRT arithmetic_expression_list RPAREN
{ $$ = sqrt($2); }
| CEIL arithmetic_expression_list RPAREN
{ $$ = ceil($2); }
| FABS arithmetic_expression_list RPAREN
{ $$ = fabs($2); }
;
arithmetic_expression
: NUMBER { $$ = $1; }
| ID { $$ = getKey(st,$1); }
| 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; }
/* | INC ID { double v = st->find(st,$2)+1;
st->modify(st,$2,v);
$$ = v; }
| DEC ID { double v = st->find(st,$2)-1;
st->modify(st,$2,v);
$$ = v; }
*/
| ADD ID { $$ = st->find(st,$2); }
| SUB ID { $$ = 0 - st->find(st,$2); }
;
/*
*条件表达式
*拆分成两个,以消除偏移/规约冲突
*/
conditional_expression_list
: conditional_expression { $$ = $1; }
| conditional_expression LAND conditional_expression
conditional_expression { $$ = $1 && $3; }
| conditional_expression LOR conditional_expression
conditional_expression { $$ = $1 || $3; }
;
conditional_expression
: arithmetic_expression EQL arithmetic_expression
{ $$ = ( $1 == $3 ); }
| arithmetic_expression LSS arithmetic_expression
{ $$ = ( $1 < $3 ); }
| arithmetic_expression GTR arithmetic_expression
{ $$ = ( $1 > $3 ); }
| arithmetic_expression NEQ arithmetic_expression
{ $$ = ( $1 != $3 ); }
| arithmetic_expression LEQ arithmetic_expression
{ $$ = ( $1 <= $3 ); }
| arithmetic_expression GEQ arithmetic_expression
{ $$ = ( $1 >= $3 ); }
| NOT conditional_expression { $$ = !$2; }
;
%%
int main(int argc,char **argv)
{
st = newSymbolTable();
scale = 0;//默认不保留小数
obase = 10;//默认输出十进制
yyparse();
return 0;
}
int yyerror(char *s)
{
printf("error: %s\n",s);
return 0;
}
/*如果符号表不存在当前标识符,将返回0*/
double getKey(SymbolTable* s,char* id)
{
double tmp = st->find(st,id);
if(st->find(st,id) == __DBL_MAX__) {
return (double)0;
} else {
return tmp;
}
return (double)0;
}
void printBinary(int n)
{
int a;
a=n%2;
n=n>>1;
if (n!=0)
printBinary(n);
printf("%d",a);
}
flex代码:
/*
*file: bc.l
*auther: jin1ming
*system: manjaro
*/
%option yylineno
%{
#include "sbc.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
/*输出进制*/
OBASE obase
/*注释*/
COMMENT \/\*(.|\n)*\/
/*标识符定义*/
identifier [a-z_A-Z][a-z_A-Z0-9]*
/*其它字符*/
whitespace [ \s\t\r\f\v]+
COMMA ,
EOL ;
errno .
%%
"=" { return ASSIGN; }
"+=" { return ADD_ASSIGN; }
"-=" { return SUB_ASSIGN; }
"*=" { return MUL_ASSIGN; }
"/=" { return DIV_ASSIGN; }
"%=" { return REM_ASSIGN; }
/*运算符*/
"+" { return ADD; }
"-" { return SUB; }
"*" { return MUL; }
"/" { return DIV; }
"^" { return POWER; }
"%" { return REM; }
"++" { return INC; }
"--" { return DEC; }
"!" { return NOT; }
"&&" { return LAND; }
"||" { return LOR; }
/*函数库*/
"acos(" { return ACOS; }
"asin(" { return ASIN; }
"atan(" { return ATAN; }
"atan2(" { return ATAN2; }
"cos(" { return COS; }
"cosh(" { return COSH; }
"sin(" { return SIN; }
"sinh(" { return SINH; }
"tanh(" { return TANH; }
"exp(" { return EXP; }
"frexp(" { return FREXP; }
"ldexp(" { return LDEXP; }
"log(" { return LOG; }
"log10(" { return LOG10; }
"modf(" { return MODF; }
"pow(" { return POW; }
"sqrt(" { return SQRT; }
"ceil(" { return CEIL; }
"fabs(" { return FABS; }
"floor(" { return FLOOR; }
"fmod(" { return FMOD; }
/*标点符号*/
"(" { return LPAREN; }
")" { return RPAREN; }
"," { return COMMA; }
(;\n)|\n|; { return EOL; }
/*系统内置变量*/
{SCALE} { return SCALE; }
{OBASE} { return OBASE; }
/*数字及标识符*/
{number} { yylval.dbl = atof(yytext); return NUMBER;}
{identifier} { yylval.str = strdup(yytext); return ID;}
/*数字异常处理*/
{floatexcption} { printf("errno:2\tfloatexcption\n");exit(2);}
{excption} { printf("errno:3\texcption\n");exit(3);}
/*未识别字符*/
{errno} {printf("errno:5\tOn line %d,mystery character: %s\n",yylineno,yytext);exit(4);}
/*跳过空白和注释*/
{whitespace} {}
{COMMENT} {}
%%