数学函数--Math
ANSI-C 定义了许多数学函数例如 sin()
, sqrt()
, exp()
等等。作为另一个继承的练习,我们将添加库函数使用一个单个 double
参数并且具有一个 double
结构到我们的计算器。
这些函数工作的就如同一元运算符一样。我们可以定义一个新的类型给节点给每个函数并且收集大多数功能从 Minus
和 Name
类,但是这里有一个更简单的方法。我们扩展 struct Name
到 struct Math
如下:
struct Math { struct Name _;
double (* funct) (double);
};
#define funct(tree) (((struct Math *) left(tree)) -> funct)
额外的给函数名称用于输入和标识符给识别,我们存储像 sin()
的库函数的地址在符号表项中。
在初始化期间我们调用下面的函数来输入所有的函数描述到符号表中:
#include <math.h>
void initMath (void) {
static const struct Math functions [] = {
{ &_Math, "sqrt", MATH, sqrt },
...
0 };
const struct Math * mp;
for (mp = functions; mp -> _.name; ++ mp)
install(mp);
}
一个函数调用是一个因子就好像使用一个减号标记一样。对于识别我们需要扩展我们的语法对因子:
factor : NUMBER
| - factor
| ...
| MATH ( sum )
MATH
是公共标识符对所有函数输入通过 initMath()
。这个翻译到下面的附加 factor()
在识别器中:
static void * factor (void) {
void * result;
...
switch (token) {
case MATH:
{
const struct Name * fp = symbol;
if (scan(0) != '(')
error("expecting (");
scan(0);
result = new(Math, fp, sum());
if (token != ')')
error("expecting )");
break;
}
symbol
首先包含符号表元素对一个函数例如 sin()
。我们保存这个指针并且构建表达式树对于函数参数通过调用 sum()
。然后我们使用 Math
,类型描述给函数,并且让 new()
构建下面的节点给表达式树:
我们让一个二元节点的左边只想符号表元素给函数并且我们附加参数树在右边。这个二元节点具有 Math
作为类型描述,也就是说,方法 doMath()
和 freeMath()
将会被调用来分别执行和删除节点。
Math 节点仍然使用 mkBin()
构建,因为这个函数不关心指针的后代。 freeMath()
,然而,可能只会删除右子树:
static void freeMath (void * tree) {
delete(right(tree));
free(tree);
}
如果我们仔细看上图,我们可以看到一个 Math
节点的执行是非常容易的。 doMath()
需要调用存储在符号表中元素可以被访问的作为左后代二元节点从之被调用:
static double doMath (const void * tree) {
double result = exec(right(tree));
errno = 0;
result = funct(tree)(result);
if (errno)
error("error in %s: %s",
((struct Math *) left(tree)) -> _.name,
strerror(errno));
return result;
}
唯一的问题是抓住数字错误通过检测 errno
变量在 ANSI-C 头文件 errno.h
中声明。这个完成了数学函数的实现给计算器。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论