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. Java琐记

    svn项目倒入,所选的文件夹一定是src上面以及的:然后eclipse会自动创建一个项目,项目名称就是src上级文件夹的名称:然后会按照路径下的文档结构如导入到eclipse的结构中: 被标记为// ...

  2. 洛谷1890 gcd区间

    题目描述 给定一行n个正整数a[1]..a[n].m次询问,每次询问给定一个区间[L,R],输出a[L]..a[R]的最大公因数. 输入输出格式 输入格式: 第一行两个整数n,m.第二行n个整数表示a ...

  3. C#变成数据导入Excel和导出Excel

    excel 基础 •整个excel 表格叫工作表:workbook:工作表包含的叫页:sheet:行:row:单元格:cell. •excel 中的电话号码问题,看起来像数字的字符串以半角单引号开头就 ...

  4. PHP漏洞全解(七)-Session劫持

    本文主要介绍针对PHP网站Session劫持.session劫持是一种比较复杂的攻击方法.大部分互联网上的电脑多存在被攻击的危险.这是一种劫持tcp协议的方法,所以几乎所有的局域网,都存在被劫持可能. ...

  5. 项目管理系统 SQL2005数据库查询CPU100%问题研究

    [一篮饭特稀原创,转载请注明出自http://www.cnblogs.com/wanghafan/p/4595084.html]  在项目管理系统中出现查询工程明细出现CPU100%卡死症状: 1.打 ...

  6. Linux内核态抢占机制分析

    http://blog.sina.com.cn/s/blog_502c8cc401012pxj.html [摘要]本文首先介绍非抢占式内核(Non-Preemptive Kernel)和可抢占式内核( ...

  7. CPU Benchmarks

    http://www.cpubenchmark.net/high_end_cpus.html 非常清楚~~~

  8. Android进阶篇-线程分析(一)

    转载自:http://www.trinea.cn/android/java-android%E7%BA%BF%E7%A8%8B%E6%B1%A0/ 介绍new Thread的弊端及Java四种线程池的 ...

  9. hdu4681String

    http://acm.hdu.edu.cn/showproblem.php?pid=4681 枚举A串和B串包含C串的区间  枚举区间端点算左右两端最长公共子序 #include <iostre ...

  10. hadoop mapreduce核心功能描述

    核心功能描述 应用程序通常会通过提供map和reduce来实现 Mapper和Reducer接口,它们组成作业的核心. Mapper Mapper将输入键值对(key/value pair)映射到一组 ...