基于文法分析的表达式计算器的实现
2011-08-01 09:33
405 查看
这个基于LL分析器的计算器是大三时上编译原理的一个作业。感觉是自己做过相对比较有深度的一个程序。第一次放出来跟大家分享。希望多多指教。
这个计算器支持带括号的四则运算和乘方运算。具体实现过程如下:
词法分析器:
相关正则定义:
识别数值的DFA的状态转换图:
词法分析器的构造:
因为要识别表达式中的负数(形如1+ -1),这个工作有两个做法,一个是在词法分析的过程中使得词法分析器可以识别负数。一个是词法分析器只识别正数,让语法分析器去识别负数还是减法运算符。前一种方法不是一个标准的词法分析程序可以完成的,因为它要引用上下文。至少向前看一个字符。这就是LL文法或LR(1)文法的范围了。所以使用第二种方案。这也是大多数情况下所采用的方案。
文法分析器:
计算器的功能:计划包括含括号的实数四则运算和乘方运算。同时还可以识别出负号。
初期文法:
将上述文法消除左递归可得出下面的文法:注意乘方运算是具有右结合性的。而四则运算是左结合的。由于LL分析法本身的限制,要将一个非二义也非左递归的一个产生式:
进行转化(因为它有公共的左因子),使其可以用LL分析法进行分析。
计算出上述文法的FIRST集和FOLLOW集,如下:
分析表的建立:因为空间原因,表项中只给出产生式的右部
文法的分析表
文法分析表建立完成之后,就可以开始写程序了。代码如下:
可以看到,一个简单的计算器就有如此多的步骤。一个复杂的编译器的建立过程,即使有Yacc和Lex等的帮助,也是不容易的。
来源:南柯之石博客 作者:南柯之石 责编:豆豆技术应用
这个计算器支持带括号的四则运算和乘方运算。具体实现过程如下:
词法分析器:
相关正则定义:
DIGIT [0-9] NUMBER {DIGIT}((.{DIGIT}+)|{DIGIT}*) DELIM [ tn] OPERATOR [+|-|*|/|^|(|)|=]
识别数值的DFA的状态转换图:
词法分析器的构造:
因为要识别表达式中的负数(形如1+ -1),这个工作有两个做法,一个是在词法分析的过程中使得词法分析器可以识别负数。一个是词法分析器只识别正数,让语法分析器去识别负数还是减法运算符。前一种方法不是一个标准的词法分析程序可以完成的,因为它要引用上下文。至少向前看一个字符。这就是LL文法或LR(1)文法的范围了。所以使用第二种方案。这也是大多数情况下所采用的方案。
文法分析器:
计算器的功能:计划包括含括号的实数四则运算和乘方运算。同时还可以识别出负号。
初期文法:
将上述文法消除左递归可得出下面的文法:注意乘方运算是具有右结合性的。而四则运算是左结合的。由于LL分析法本身的限制,要将一个非二义也非左递归的一个产生式:
进行转化(因为它有公共的左因子),使其可以用LL分析法进行分析。
计算出上述文法的FIRST集和FOLLOW集,如下:
分析表的建立:因为空间原因,表项中只给出产生式的右部
id | + | - | * | / | ^ | ( | ) | $ | |
E | TE’ | TE’ | TE’ | ||||||
E’ | +TE’ | -TE’ | |||||||
T | FT’ | FT’ | FT’ | ||||||
T’ | *FT’ | /FT’ | |||||||
F | N | -N | N | ||||||
N | MN’ | MN’ | |||||||
N’ | ^N | ||||||||
M | Id | (E) |
文法分析表建立完成之后,就可以开始写程序了。代码如下:
Code 1/**/////////////////////////////////////////////////////////////////////////// 2// ExpressionCalculator 3// Version 0.1 4// Powered by nankezhishi 5// All Right reserved. 6// 本计算器支持带括号的四则、乘方运算。并可包含独立的负号。 7/**/////////////////////////////////////////////////////////////////////////// 8#include "iostream" 9#include "string" 10#include "cmath" 11using namespace std; 12 13//用于kind的值 14#define NUMBER 1000 15#define MYERROR 1001 16#define END 1002 17//词法分析器的当前状态 18int state; 19//读取的内容 20string input; 21//字符串的长度 22int inputlength; 23//字符串读取的位置. 24int i = 0; 25//词法分析器的返回值 26int returnvalue; 27//读取到数字时的值 28string strval; 29double yylval = 0; 30 31 32/**/////////////////////////////////////////////////////////////////////////// 33//词法分析器 34/**/////////////////////////////////////////////////////////////////////////// 35bool isdigit(char c){ 36 return (c >= '0' && c <= '9')?true:false; 37} 38 39bool isoperator(char c){ 40 return (c == '+'||c == '-'||c == '*'||c == '/'||c == '^'||c == '('||c == ')'||c == '=')?true:false; 41} 42 43//识别数字的DFA的状态转移函数 44int move(int state, char c){ 45 if (isdigit(c)){ 46 return (state==0)?1:state; 47 } 48 else if (state == 1 && c == '.'){ 49 return 2; 50 } 51 else if (( state == 2 || state == 1) && (c == ' ' || c == 'n' || c == 0 || isoperator(c))){ 52 i--; //操作符 53 return 3; //接受 54 } 55 else 56 return 0; 57} 58 59int lexer(){ 60 if (i == inputlength) 61 return END; 62 if (isoperator(input[i])) 63 { 64 i++; 65 return input[i-1]; //返回非数字运算符 66 } 67 int start = i; 68 for (;i < inputlength;) 69 { 70 state = move(state,input[i++]); 71 if (state == 0) 72 return MYERROR; 73 else if (state == 3) 74 { 75 strval = input.substr(start,i-start); 76 yylval = atof(strval.c_str()); 77 return NUMBER; 78 } 79 } 80} 81 82 83/**/////////////////////////////////////////////////////////////////////////// 84//语法分析器采用自上而下的分析方法. 85/**/////////////////////////////////////////////////////////////////////////// 86void match(int t){ 87 if (returnvalue == t) 88 returnvalue = lexer(); 89 else{ 90 cout << "EXPRESSION ERRON IN MATCH!" << endl; 91 } 92} 93 94double E(); 95 96double M(){ 97 double temp; 98 switch(returnvalue) 99 { 100 case NUMBER: 101 temp = yylval; 102 match(NUMBER); 103 return temp; 104 case '(': 105 match('('); 106 temp = E(); 107 match(')'); 108 return temp; 109 default: 110 cout << "EXPRESSION ERROR IN M()!" << endl; 111 return 0; 112 } 113} 114 115double N(); 116 117double N_(){ 118 switch(returnvalue) 119 { 120 case '+': 121 case '-': 122 case '*': 123 case '/': 124 case ')': 125 case END: 126 return 1; 127 case '^': 128 match('^');return N(); 129 default: 130 cout << "EXPRESSION ERROR IN N_()!" << endl; 131 return 0; 132 } 133} 134 135double N(){ 136 double m,n_; 137 switch(returnvalue) 138 { 139 case NUMBER: 140 case '(': 141 m = M(); 142 n_ = N_(); 143 return pow(m,n_); //这里不可以写做pow(M(),N_())因为参数压栈的顺序是从右向左,这样就会先调用N_()而产生错误. 144 default: 145 cout << "EXPRESSION ERROR IN N()!" << endl; 146 return 0; 147 } 148} 149 150double F(){ 151 switch(returnvalue) 152 { 153 case '-': 154 match('-');return -N(); 155 case NUMBER: 156 case '(': 157 return N(); 158 default: 159 cout << "EXPRESSION ERROR IN F()!" << endl; 160 return 0; 161 } 162} 163 164double T_(){ 165 switch(returnvalue) 166 { 167 case '+': 168 case '-': 169 case ')': 170 case END: 171 return 1; //对于乘法,这里要返回1. 172 case '*': 173 match('*');return F() * T_(); 174 case '/': 175 match('/');return 1/(F() / T_()); 176 default: 177 cout << "EXPRESSION ERROR IN T_()!" << endl; 178 return 0; 179 } 180} 181 182double T(){ 183 switch(returnvalue) 184 { 185 case NUMBER: 186 case '-': 187 case '(': 188 return F() * T_(); 189 default: 190 cout << "EXPRESSION ERROR IN T()!" << endl; 191 return 0; 192 } 193} 194 195double E_(){ 196 switch(returnvalue) 197 { 198 case '+': 199 match('+');return T() + E_(); 200 case ')': 201 case END: 202 return 0; 203 case '-': 204 match('-');return -(T() - E_()); 205 default: 206 cout << "EXPRESSION ERROR IN E_()!" << endl; 207 return 0; 208 } 209} 210 211double E(){ 212 switch(returnvalue) 213 { 214 case NUMBER: 215 case '-': 216 case '(': 217 return T() + E_(); 218 default: 219 cout << "EXPRESSION ERROR IN E()!" << endl; 220 return 0; 221 } 222} 223 224int main(){ 225 while ((cin >> input) && (inputlength = input.length()) > 0) 226 { 227 state = 0; 228 i = 0; 229 returnvalue = lexer(); 230 cout << E() << endl; 231 } 232 233 /**/////////////////////////////////////////////////////////////////////////// 234 //词法分析器测试程序 235 /**/////////////////////////////////////////////////////////////////////////// 236 //while (i < inputlength) 237 //{ 238 // returnvalue = lexer(); 239 // if (returnvalue == NUMBER) 240 // { 241 // cout << yylval << endl; 242 // } 243 // else if (returnvalue == MYERROR) 244 // { 245 // cout << "表达式错误" << endl; 246 // } 247 // else 248 // cout << (char)returnvalue << endl; 249 //} 250 251}
可以看到,一个简单的计算器就有如此多的步骤。一个复杂的编译器的建立过程,即使有Yacc和Lex等的帮助,也是不容易的。
来源:南柯之石博客 作者:南柯之石 责编:豆豆技术应用
相关文章推荐
- 基于文法分析的表达式计算器的实现
- 基于文法分析的表达式计算器的实现
- 基于文法分析的简单计算器实现
- jQuery基于cookie实现的购物车实例分析
- 基于MTD的NANDFLASH设备驱动底层实现原理分析 一
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(六) .
- 基于Visual C++之Windows核心编程代码分析(3)实现程序自动安装
- 基于visual c++之windows核心编程代码分析(51)基于匿名管道实现远程控制
- 基于visual c++之windows核心编程代码分析(59)实现网络简单代理编程
- 基于规则评分的密码强度检测算法分析及实现(JavaScript)
- 基于MTD的NANDFLASH设备驱动底层实现原理分析(六)
- 基于Hadoop技术实现的离线电商分析平台(Flume、Hadoop、Hbase、SpringMVC、highcharts)
- 【简单Web服务器搭建】基于Socket实现的最简单的Web服务器【ASP.NET原理分析】
- select(poll)实现代码实现分析(基于kernel 3.10.0)
- 基于Python实现自动慢查询分析,邮件自动发送
- 基于Visual C++之Windows核心编程代码分析(3)实现程序自动安装
- Python 基于语句检测和语句频谱分析实现文本汇总算法 (document summary algorithm)
- Apache Mahout的Taste基于Hadoop实现协同过滤推荐引擎的代码分析
- Spring Security源码分析十二:Spring Security OAuth2基于JWT实现单点登录
- <深度学习系列>基于numpy和python的反向传播算法的实现与分析