小白说编译原理-3-yacc基本用法
来源:互联网 发布:js触发超链接点击事件 编辑:程序博客网 时间:2024/05/22 02:29
前提说明
前面lex的例子说明了可以通过定义正规式的方式,实现一个词法分析器。 它主要是通过lex编译器将用户定义的正规式以及相应的action编译成对应的c++代码,交给c++编译器生成可执行程序exe。
同样的,应该可以定义语法规则,并由语法编译器将语法规则以及action编译成相应的c++代码,并执行。
这就是我们这节要说明的yacc。
yacc规则
声明部分
C++头文件,函数声明
文法记号的声明(类似于lex中词法token的声明),例如%token DIGIT
%%
翻译规则
%%
翻译规则主要文法产生式和对应的动作组成。
例如 expr : expr ‘+’ term {$$ = $1 + $2}
其他c++语言的代码
yacc示例,简单计算器
%{%}%name yacc// class definition{ // place any extra class members here virtual int yygettoken();}// constructor{ // place any extra initialisation code here}// destructor{ // place any extra cleanup code here}// place any declarations here%include {#ifndef YYSTYPE#define YYSTYPE double#endif}%%lines : lines expr '\n' {printf("%f\n", $2);} | lines '\n' |//empty line ;expr : expr '+' term {$$ = $1 + $3;} | expr '-' term {$$ = $1 - $3;} | term ;term : term '*' factor {$$ = $1 * $3;} | term '/' factor {$$ = $1 / $3;} | factor {$$=$1;} ;factor : '(' expr ')' {$$=$2;} | DIGIT ;DIGIT:'0'{ $$ = 0.0; }|'1'{ $$ = 1.0; }|'2'{ $$ = 2.0; }|'3'{ $$ = 3.0; }|'4'{ $$ = 4.0; }|'5'{ $$ = 5.0; }|'6'{ $$ = 6.0; }|'7'{ $$ = 7.0; }|'8'{ $$ = 8.0; }|'9'{ $$ = 9.0; } ; %%int YYPARSERNAME::yygettoken(){ return getchar();}int main(){//create a lexer, and call the lex function.//it will read from stdin and parser the tokens. int n = 1; YYPARSERNAME parser; if (parser.yycreate()) { n = parser.yyparse(); } return n;}
计算器解释
- 添加gettoken函数
virtual int yygettoken(); - expr : expr ‘+’ term {$$ = $1 + $3;}
计算加法,$$表示当返回值,\$1表示第一个参数,\$3表示第三个参数 - main
创建parser语法分析器,调用gettoken分析,即可。
巧妙的地方
1,支持多行
多行的关键在于lines的表示,lines既可以表示为空,又可以表示为lines expr ‘\n’
2,支持算符优先级
term和factor的使用,先使用term,再使用factor
3,支持括号
最终的factor因子的表示,既可以表示单个数字,还可以表示(expr)。
3,只支持单个数字的加减乘除
这是由于对于DIGIT的解释只支持单个数字
更新版本支持浮点数
%{#include <stdio.h>%}%name yacc// class definition{ // place any extra class members here virtual int yygettoken(); double yyvalue;}// constructor{ // place any extra initialisation code here}// destructor{ // place any extra cleanup code here}// place any declarations here%include {#ifndef YYSTYPE#define YYSTYPE double#endif}%token NUMBER%%lines : lines expr '\n' {printf("%f\n", $2);} | lines '\n' |//empty line ;expr : expr '+' term {$$ = $1 + $3;} | expr '-' term {$$ = $1 - $3;} | term ;term : term '*' factor {$$ = $1 * $3;} | term '/' factor {$$ = $1 / $3;} | factor {$$=$1;} ;factor : '(' expr ')' {$$=$2;} | NUMBER {$$=yyvalue;} ; %%int YYPARSERNAME::yygettoken(){ int c; double value; while((c = getchar()) == ' ');//jump the empty //here not the blank if(isdigit(c) || c == '.'){ ungetc(c, stdin); cin>>value; yyvalue = value; return NUMBER; } return c;}int main(){//create a lexer, and call the lex function.//it will read from stdin and parser the tokens. int n = 1; YYPARSERNAME parser; if (parser.yycreate()) { n = parser.yyparse(); } return n;}
修改的地方
- 删除了DIGIT采用语法分析器进行的表达,过去gettoken直接返回char型字符,由DIGIT或者+,-等进行语法翻译。现在使用一个token标记NUMBER, 它代表一个数字。这个NUMBER标记是由对应的词法分析gettoken进行返回的。
- gettoken中,如果遇到数字,则使用cin方式读取double型变量,保存到变量yylvalue中,这样当语法分析的过程中,遇到number,将yylvalue赋值给当前返回即可,即可以读取到浮点值。
- 为了更好的适应性,词法分析中还进行了跳过空格的操作,对于非数字不进行解析,直接返回。
本人lpstudy,转载请注明出处: http://blog.csdn.net/lpstudy/article/details/51225953
0 0
- 小白说编译原理-3-yacc基本用法
- 小白说编译原理-4-计算器yacc
- 小白说编译原理-2-lex基本用法
- 小白说编译原理-6-lex和yacc环境配置-多图
- 【编译原理】用Yacc做语法分析
- 编译原理——lex 与yacc实例剖析
- 用Yacc实现语法分析器-4-编译原理
- 编译原理学习-Windows下Lex和yacc使用
- RSA基本用法原理
- gcc编译基本用法
- gcc编译基本用法
- yacc用法(未完成)
- 编译原理课设——《TINY编译器》,用yacc生成语法扫描实现编译器
- 编译原理学习基本步骤
- 编译原理之基本构成
- 【编译原理】编译器的编译基本过程
- Lex/Yacc的学习——《编译原理及实践》附录B tiny编译器源码在linux下编译实现
- 编译原理课设——《TINY编译器》,用lex和yacc生成词法语法分析源码,实现编译器
- 码农小汪剑指Offer之39-和为S的连续正数序列
- 利用AS修改Jar包中class文件内容
- 阅读Android源码
- 记录在项目中碰到的问题和需要总结的东西(1)
- 自定义控件:自定义组合控件+自定义属性
- 小白说编译原理-3-yacc基本用法
- Five
- ECS上配置webmin和yum安装
- android studio2.0去除运行按钮旁边闪电标志的方法
- 多条件动态参数查询方法
- Django
- 基于语句的主从复制问题
- Android性能优化之路(五年之痒)
- Coursera - POC Part2 - Fifteen Puzzle