支持+ - * / ( ) ! ,和使用变量进行运算。
lexer.l 词法解析
%{
#include "y.tab.h"
#include <string>
#include <vector>
using namespace std;
vector<string> str_table;
%}
%%
[0-9]+ { yylval = atoi(yytext); return NUMBER; } // 识别数字,并转化为整数
"list" { return LIST; } // 列出所有符号命令
"exit" { return EXIT; } // 退出
"-" { return MINUS; } // 减号和负号
"+" { return PLUS; } // 加号
"*" { return MULTIPLY; } // 乘号
"/" { return DIVIDE; } // 除号
"(" { return LP; } // 左括号
")" { return RP; } // 右括号
"!" { return FACT; } // 阶乘符号
"=" { return ASSIGN; } //赋值符号
"\n" { return EOL; } // EOL: End of Line
[a-z][a-zA-Z0-9_]* {
string temp_str(yytext);
for(int i=0;i<str_table.size();i++){
if(str_table[i]==temp_str){
yylval=i; break;
}
}
yylval=str_table.size();
str_table.push_back(temp_str);
return VARIABLE ;
} //变量
. { return EOF; } // 结束符号
%%
这里解析到变量的时候,把变量名加入到符号表,以便后续的读取
parser.y
%{
#include <iostream>
#include <map>
#include <vector>
#include <string>
using namespace std;
extern vector<string> str_table;
int yylex(void);
void yyerror(char *);
int factorial(int n);
map<string,int> mp;
extern string now_str;
%}
%token NUMBER PLUS MINUS MULTIPLY DIVIDE LP RP FACT VARIABLE ASSIGN EOL LIST EXIT
%right ASSIGN
%left PLUS MINUS
%left MULTIPLY DIVIDE
%right FACT
%nonassoc UMINUS
%%
program:
| program cmd
| program stat
| program expression EOL { cout << "result : " << $2 << endl; }
;
cmd: LIST EOL {
for(auto &elem : mp) {
cout << elem.first << " : " << elem.second << endl;
}
}
| EXIT EOL {
exit(0);
}
;
stat: VARIABLE ASSIGN expression EOL { mp[str_table[$1]] = $3; }
;
expression: term
| expression PLUS term { $$ = $1 + $3; }
| expression MINUS term { $$ = $1 - $3; }
;
term: factor
| term MULTIPLY factor { $$ = $1 * $3; }
| term DIVIDE factor { $$ = $1 / $3; }
;
factor: NUMBER
| VARIABLE {
if(mp.count(str_table[$1])) {
$$ = mp[str_table[$1]];
} else {
cerr << "variable not init : " << str_table[$1] << endl;
YYABORT; // 更改这里使用 YYABORT 终止解析,而不是返回 -1
}
}
| LP expression RP { $$ = $2; }
| MINUS factor %prec UMINUS { $$ = -$2; }
| factor FACT { $$ = factorial($1); }
;
%%
int factorial(int n) {
int res=1;
for(int i=2;i<=n;i++){
res*=i;
}
return res;
}
void yyerror(char *s) {
fprintf(stderr, "%s\n", s);
}
int main(void) {
yyparse();
return 0;
}
yacc功能还是蛮强大的,哈哈,我的词法写的不咋地,也能解析出来。
Makefile
calc: lex.yy.c y.tab.c
g++ lex.yy.c y.tab.c -o calc -ll -std=c++11
lex.yy.c: lexer.l
flex lexer.l
y.tab.c: parser.y
yacc -d parser.y -o y.tab.c -Wcounterexamples
clean:
rm -f lex.yy.c y.tab.c y.tab.h calc
最后结果
第一个例子表达式之间不能输入空格,我的词法解析的时候碰到空格直接返回结束符号了,然后就相当于输入一个c,就结束了。
第二个例子是正常的。
这里所有的值都是int的,/ 是整除。