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文法)的更多相关文章

  1. .net表达式计算器(中缀表达式转后缀表达式,支持20多个数学函数,支持函数嵌套)

    最近在网上查了一下表达工计算器的类库,发现Java版本的有一个比较成熟的叫W3EVal,好像是一个IBM工程师写的,.net就很少了(可能是我了解不够多),但投机取巧的实现思路有很多,比如: (1)将 ...

  2. 基于语法分析器GOLD Parser开发的数学表达式计算器

    最近发现一款文法分析神器,看完官网(http://goldparser.org/)的介绍后感觉很犀利的样子,于是就拿来测试了一番,写了一个数学表达式分析的小程序,支持的数学运算符如下所示:常规运算:+ ...

  3. java面向对象课程设计-数学表达式计算器

    项目简介 设计一个计算器,其能够: 1)由用户输入一个简单的四则运算表达式,求出其计算结果后显示. 2)特殊数学函数,如:绝对值.取整.三角函数.倒数.平方根.平方.立方等. 3)对一定范围内的数字将 ...

  4. 【编译原理】LL1文法语法分析器

    上篇文章[编译原理]语法分析--自上向下分析 分析了LL1语法,文章最后说给出栗子,现在补上去. 说明: 这个语法分析器是利用LL1分析方法实现的. 预测分析表和终结符以及非终结符都是针对一个特定文法 ...

  5. Basic Calculator - Stack(表达式计算器)

    978. Basic Calculator https://www.lintcode.com/problem/basic-calculator/description public class Sol ...

  6. 编译原理LL1文法分析树(绘图过程)算法实现

    import hjzgg.analysistable.AnalysisTable; import hjzgg.first.First; import hjzgg.follow.Follow; impo ...

  7. 编译原理LL1文法分析表算法实现

    import hjzgg.first.First; import hjzgg.follow.Follow; import hjzgg.tablenode.TableNode; import hjzgg ...

  8. 编译原理LL1文法Follow集算法实现

    import hjzgg.first.First; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set ...

  9. 编译原理 LL1文法First集算法实现

    import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; import java.util.TreeMap ...

随机推荐

  1. 实现strlen,strcpy,strcat,strcmp同功能的函数stringLength,stringCopy,stringCatch,stringCompare

    #import <Foundation/Foundation.h> /* 求字符串长度 */ int stringLength(char arr[]); /* 复制字符串 将arr1 复制 ...

  2. 综合经验:IO读写错误必然导致程序崩溃

    仿佛是忽然间产生的问题,每次程序退出时候,必然崩溃,花了整整一天才找到原因,就是对数据库的IO读写错误.主要是因为析构函数调用了Disconnect函数,内容如下: void SFTPTool::Di ...

  3. Spring事务传播机制

    Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播,即协调已经有事务标识的方法之间的发生调用时的事务 ...

  4. velocity-1.7中vm文件的存放位置

    velocity-1.7中关于vm文件存放 demo: public class App_example1 { public App_example1() { String propfile=&quo ...

  5. Android-加载透明PNG图片变黑的问题

    png和jpg作为两种最常用的图片格式,首先我们要知道他们的区别: 1.从一般图片的外观上来说,他们是无法直接判断的 2.从文件大小上来说,同样一张图png肯定比jpg的大 3.通过查资料咱们可以发现 ...

  6. plsql 书写命名规范

    俗话说事不预则废,无规矩不成方圆. 对sql脚本程序的设计,个人认为应该是从编码规范开始. 前段时间公司一些同事提交的脚本,风格迥异,让我审核起来倍感难受,丝毫没有审核代码的快感. 特整理了公司部分常 ...

  7. Form – 保存自動關閉當前窗口

    FAQ: 在BUTTON的触发器中,写如下代码, commit_form; go_bloack('你想显示的那个window的block'); --或者写 show_view('你要显示的canvas ...

  8. cogs_14_搭配飞行员_(二分图匹配+最大流,网络流24题#01)

    描述 http://cojs.tk/cogs/problem/problem.php?pid=14 有一些正飞行员和副飞行员,给出每个正飞行员可以和哪些副飞行员一起飞.一架飞机上必须一正一副,求最多多 ...

  9. 自定义web服务器(四)

    关于HTTP协议的具体内容,前面章节已经有所讲解,相信读者已有所了解,在此不在累述,本章节讲解自定义web服务器.  一,.net提供自定义Web服务器的类 以下只是写主要的类 1.HTTPListe ...

  10. JVM内存模型及内存分配过程

    一.JVM内存模型 JVM主要管理两种类型内存:堆(Heap)和非堆(Permanent区域). 1.Heap是运行时数据区域,所有类实例和数组的内存均从此处分配.Heap区分两大块,一块是 Youn ...