表达式计算器(LL1文法)
LL(1)文法求算数表达式的值
递归子程序法
分析过程:
表达式文法G[E]:
E->E+T|E-T|T
T->T*F|T/F|T%F|F
F->N^F|N
N->(E)|NUM|+NUM|-NUM
消除左递归、左公共因子
E ->TE'
E'->+TE'|-TE'|ε
T ->FT'
T'->*FT'|/FT'|%FT'|ε
F ->NF'
F'->^F|ε
N->(E)|NUM|+NUM|-NUM
FIRST集和FOLLOW集
LL(1)分析表
(应该没错吧……表示昨天刚考完试……)
(嗯。。我承认我抄。。咳咳。。借鉴了这份代码http://ideone.com/o2Ag4。。还是炮姐写的好。。)
#include <cstdio>
#include <cmath> /**
* LL(1)文法求算数表达式的值
* 递归子程序法
**/ enum SYM_KIND { // 符号类型
SYM_NUM, // num
SYM_ADD, // +
SYM_SUB, // -
SYM_MUL, // *
SYM_DIV, // /
SYM_MOD, // %
SYM_POW, // ^
SYM_LBR, // (
SYM_RBR, // )
SYM_END, // '\0'
SYM_ERR // 其他不合法符号
}; enum ERR_KIND { // 状态
ERR_OK,
ERR_INVALID_CHAR,
ERR_NO_OPERATOR,
ERR_BR_NOT_MATCH,
ERR_NO_NUM,
ERR_END
}; char expr[]; // 表达式
int pos; // 读取到表达式的位置
double val;
ERR_KIND err; void F();
void E(); void NUM()
{
val = ;
while (expr[pos] <= '' && expr[pos] >= '')
{
val = val * + expr[pos] - '';
pos++;
}
if (expr[pos] == '.')
{
pos++;
double eo = 0.1;
while (expr[pos] <= '' && expr[pos] >= '')
{
val += (expr[pos] - '') * eo;
eo *= 0.1;
pos++;
}
}
} SYM_KIND get_sym() // 读取一个单词
{
char ch = expr[pos++];
while (ch == ' ' || ch == '\t') // 忽略空格
ch = expr[pos++];
if (ch <= '' && ch >= '')
{
pos--;
NUM();
return SYM_NUM;
}
else if (ch == '+') return SYM_ADD;
else if (ch == '-') return SYM_SUB;
else if (ch == '*') return SYM_MUL;
else if (ch == '/') return SYM_DIV;
else if (ch == '%') return SYM_MOD;
else if (ch == '^') return SYM_POW;
else if (ch == '(') return SYM_LBR;
else if (ch == ')') return SYM_RBR;
else if (ch == '\0')
{
err = ERR_END;
return SYM_END;
}
err = ERR_INVALID_CHAR;
return SYM_ERR;
} void N() // N->(E)|NUM|+NUM|-NUM
{
if (err != ERR_OK) return ;
SYM_KIND kind = get_sym();
if (kind == SYM_LBR)
{
E();
if (err == ERR_END)
{
err = ERR_BR_NOT_MATCH;
}
else if (err == ERR_OK)
{
kind = get_sym();
if (kind != SYM_RBR)
err = ERR_BR_NOT_MATCH;
}
}
else if (kind == SYM_ADD)
{
kind = get_sym();
if (kind != SYM_NUM)
{
err = ERR_NO_NUM;
}
}
else if (kind == SYM_SUB)
{
kind = get_sym();
if (kind != SYM_NUM)
{
err = ERR_NO_NUM;
}
val = -val;
}
else if (kind != SYM_NUM)
{
err = ERR_NO_NUM;
}
} void F_() // F'->^F|ε
{
if (err != ERR_OK) return ;
SYM_KIND kind = get_sym();
double tmp = val;
if (kind == SYM_POW)
{
F();
val = pow(tmp, val);
}
else if (kind == SYM_ADD || kind == SYM_SUB || kind == SYM_MUL || kind == SYM_DIV
|| kind == SYM_MOD || kind == SYM_END || kind == SYM_RBR)
{
pos--;
}
else if (kind != SYM_ERR)
err = ERR_NO_OPERATOR;
} void F() // F ->NF'
{
if (err != ERR_OK) return ;
N();
F_();
} void T_() // T'->*FT'|/FT'|%FT'|ε
{
if (err != ERR_OK) return ;
SYM_KIND kind = get_sym();
double tmp = val;
if (kind == SYM_MUL)
{
F();
val *= tmp;
T_();
}
else if (kind == SYM_DIV)
{
F();
val = tmp / val;
T_();
}
else if (kind == SYM_MOD)
{
F();
val = fmod(tmp, val);
T_();
}
else if (kind == SYM_ADD || kind == SYM_SUB || kind == SYM_RBR || kind == SYM_END)
{
pos--;
}
else if (kind != SYM_ERR)
{
err = ERR_NO_OPERATOR;
}
} void T() // T ->FT'
{
if (err != ERR_OK) return ;
F();
T_();
} void E_() // E'->+TE'|-TE'|ε
{
if (err != ERR_OK) return ;
SYM_KIND kind = get_sym();
double tmp = val;
if (kind == SYM_ADD)
{
T();
val = tmp + val;
E_();
}
else if (kind == SYM_SUB)
{
T();
val = tmp - val;
E_();
}
else if (kind == SYM_END || kind == SYM_RBR)
{
pos--;
}
else if (kind != SYM_ERR)
{
err = ERR_NO_OPERATOR;
}
} void E() // E ->TE'
{
if (err != ERR_OK) return ;
T();
E_();
} void output_err()
{
if (err == ERR_OK)
{
err = ERR_BR_NOT_MATCH;
pos++;
}
printf("%*s ^", pos, "");
if (err == ERR_BR_NOT_MATCH) printf("括号不匹配\n");
else if (err == ERR_NO_NUM) printf("缺少一个数字\n");
else if (err == ERR_NO_OPERATOR) printf("缺少一份运算符\n");
else if (err == ERR_INVALID_CHAR) printf("不合法字符\n");
} int main()
{
printf(">>");
while (gets(expr) != NULL)
{
pos = ;
err = ERR_OK;
E();
if (err == ERR_END) printf("%g\n", val);
else output_err();
printf(">>");
}
return ;
}
运行结果:
>>3+4^2.2
24.1121
>>2-7/8
1.125
>>(8+0
^括号不匹配
>>7%5
2
>>7+9.9+
^缺少一个数字
加个界面……
表达式计算器(LL1文法)的更多相关文章
- .net表达式计算器(中缀表达式转后缀表达式,支持20多个数学函数,支持函数嵌套)
最近在网上查了一下表达工计算器的类库,发现Java版本的有一个比较成熟的叫W3EVal,好像是一个IBM工程师写的,.net就很少了(可能是我了解不够多),但投机取巧的实现思路有很多,比如: (1)将 ...
- 基于语法分析器GOLD Parser开发的数学表达式计算器
最近发现一款文法分析神器,看完官网(http://goldparser.org/)的介绍后感觉很犀利的样子,于是就拿来测试了一番,写了一个数学表达式分析的小程序,支持的数学运算符如下所示:常规运算:+ ...
- java面向对象课程设计-数学表达式计算器
项目简介 设计一个计算器,其能够: 1)由用户输入一个简单的四则运算表达式,求出其计算结果后显示. 2)特殊数学函数,如:绝对值.取整.三角函数.倒数.平方根.平方.立方等. 3)对一定范围内的数字将 ...
- 【编译原理】LL1文法语法分析器
上篇文章[编译原理]语法分析--自上向下分析 分析了LL1语法,文章最后说给出栗子,现在补上去. 说明: 这个语法分析器是利用LL1分析方法实现的. 预测分析表和终结符以及非终结符都是针对一个特定文法 ...
- Basic Calculator - Stack(表达式计算器)
978. Basic Calculator https://www.lintcode.com/problem/basic-calculator/description public class Sol ...
- 编译原理LL1文法分析树(绘图过程)算法实现
import hjzgg.analysistable.AnalysisTable; import hjzgg.first.First; import hjzgg.follow.Follow; impo ...
- 编译原理LL1文法分析表算法实现
import hjzgg.first.First; import hjzgg.follow.Follow; import hjzgg.tablenode.TableNode; import hjzgg ...
- 编译原理LL1文法Follow集算法实现
import hjzgg.first.First; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set ...
- 编译原理 LL1文法First集算法实现
import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.TreeMap ...
随机推荐
- Razor语法小记
1.代码块中,<text>标签用来输出,如: @{ <text>sdfsdf</text> } 输出Html: sdfsdf
- MVC 4 网页版发送 邮件的配置问题
有时项目要用到邮箱验证就要发送邮件传统的解决方案: public void SendResetPasswordEmail(string email) { MailAddress from = new ...
- iOS8的一些控件的变更---备用
UISearchDisplayController变更为UISearchController UIAlertView变更为UIAlertController 如果添加点击事件则需要使用UIAlertC ...
- ExtJS4.2学习(16)制作表单(转)
鸣谢:http://www.shuyangyang.com.cn/jishuliangongfang/qianduanjishu/2013-12-10/188.html --------------- ...
- bzoj 2555: SubString 后缀自动机+LCT
2555: SubString Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 688 Solved: 235[Submit][Status][Dis ...
- JS获取IP、MAC和主机名的几种方法
方法一(只针对IE且客户端的IE允许AcitiveX运行,通过平台:XP,SERVER03,2000): 获取客户端IP. <HTML> <HEAD> <TITLE> ...
- 【win8技巧】应用商店里面如何搜索应用app
win8应用商店搜索app软件的技巧 1.组合键 WIN+C 打开屏幕最右边磁条 2.点击搜索,输入你想搜的软件名称,里面会列出你已经安装的app或者你点击下面的应用商店选项,就可以搜索互联网上应用商 ...
- hdu 4814 Golden Radio Base
详解见:http://blog.csdn.net/tri_integral/article/details/18666797 #include<cstdio> #include<cs ...
- 从 C++ 到 Qt(命令行编译)good
从 C++ 到 Qt 转载自:http://hi.baidu.com/cyclone/blog/item/8f8f08fa52d22f8758ee9006.html Qt 是 C++ 的库,Qt在an ...
- Java 异常类层次结构
在Java中,异常分为受检查的异常,与运行时异常. 两者都在异常类层次结构中. 下面的图展示了Java异常类的继承关系. 图1 粉红色的是受检查的异常(checked exceptions),其必须被 ...