自定义计算公式的原理

最近在开发工资管理模块的时候需要用到自定义的计算公式,凭自己当前的积累只能完成自定义公式的语法检查,在公式解析的时候一筹莫展,然后在网上看到这篇文章,记录下来

原始地址:http://www.hust-snde.com/hust/work/function/pubforum/forumtopic.jsp?forumlist_id=1447&id=29222

  编译原理被认为是计算机专业课程中最为艰深的课程(之一?), 学习, 理解并灵活运用该技术对于自学者而言, 将是一个比较漫长的过程. 从年前对antlr感兴趣到现在, mssqlserver的查询语句解析还只是完成了冰山一角, 但是积累的知识则刚好够完成一个自定义公式解析器(支持表达式嵌套). 专业一点来讲, 就是复杂表达式的词法分析和语义分析. 思路: 1, 编写表达式的语法式: 据说完成这一步相当于完成了整个编译的50%. 这一步我们要根据需要整理基本记 号和复合语法元素. 2, 词法分析: 将输入的自定义公式字符串视作字符输入流, 将字符组合成为已定义的记号序列, 并去除各种占位符(空格, 换行等)和注释. 注意, 不要试图在这一步使用我们在操作文件读写时常用的"行处理模式". 因为 对于编译器来讲, "行"只是一个视觉概念, 在处理跨行的逻辑时(比如block comment), 使用这种模式会非常痛苦. 3, 语义分析: 在这一步我使用的是自顶向下分析算法, 利用递归来解决表达式的嵌套解析. 相信 这也是大多数分析器解决嵌套问题的办法. 数据 结构方面, 与递归相匹配, 栈(stack)是我们不可缺少的利器. 非常可笑的是, 我曾经一直在为数据结构苦恼, 直到某天与同事讨论一个模板翻 译的问题时才猛然醒悟, 思路也为之豁然开朗. 由此可见独立钻研固然重要, 头脑风 暴也是必不可少. 基本上, 每个函数对应一个复合语法元素. 为简单起见, 只需返回bool值即可. 4, 构造语法生成树: 第三步已经搭好了架子. 现在要织入记录解析过程中各个阶段的中间结果的代码. 可以想像一棵不断生长的树, 而语义分析是一个不断试探(判断记号组合是否吻合某个 语法)的过程, 每次试探成功, 则树会长出一条相应的分支, 如果试探失败, 则要把当 前分支砍掉. 当所有试探过程结束时, 我们就会得到一棵"丰满"的树. 因为存在递归试探的过程,所以这些临时的分支信息也要用栈来保存. 之所以说 "临时", 是因为试探时我们并不直到这个分支会不会突然随上级分支的砍掉而随时消失. 5, 遍历生成树并求值: 同样, 使用递归可以很方便地完成树的遍历. 思路: a, 求生成树的值就是求树的根的值. 同时这也要求我们的节点的数据结构能支持存储 子树的生成值和值类型这两个信息. b, 如何求取一个节点的值? 节点的值就是节点的所有儿子求值后再进行复合运算的 结果值. 比如一个表达式为"某数字+某函数", 则该表达式是一个上级节点, 并 包含"某数字", "+"和"某函数"三个子结点. 而该函数又是其他表达式元素组成 的一棵子树的根节点. 所以, 递归求取所有节点的值即可. c, "得到所有儿子的值以后求取当前节点的值", 这个过程类似于求取四则运算. 我们 可以通过语法设计(比如, "(mexp) -> mexp")去除括号, 以免为这里的求值过程 添加困难. 我们唯一需要考虑的是"乘除"比"加减"的优先级高, 所以要从左到右 先合并"乘除", 后合并"加减". 第3步的语义分析已经考虑了所有的格式不合法的 情况, 在这里我们只需要关心诸如"数据类型是否匹配"和"除数不能为0"这样的 高级异常.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值