val1 / val2;
break;
case NEGATIVE:
val = val1*(-1);
break;
default:
printf("
cal: Unknown operation.\n"); exit(1); break; } break; case IdK: s = findSym(node->val.name); if (NULL == s) { /*未声明的id默认值为0*/ addSym(node->val.name, 0); val = 0; } else { val = s->val; } break; default: printf("
calc: Unknown expression type.\n"); exit(1); break; } break; case Stmt:
/*赋值语句的计算*/
switch (node->attr.s)
{
case AssignK:
val1 = val = calc(node->child[1]);
s = findSym(node->child[0]->val.name);
if (NULL == s)
{
addSym(node->child[0]->val.name, val1);
}
else
{
s->val = val1;
}
break;
default:
printf("
calc: Unknown stmt kind.\n");
exit(1);
break;
}
break;
}
if (NULL != node->brother)
{
val = calc(node->brother);
}
return val;
}
可以看到该函数有两层的switch嵌套,第一层switch判断节点的类型是语句还是表达式,第二层switch判断其子类型,比如表达式可以是常数、标识符、数学表达式,语句目前只有赋值语句一种,将来可以能有if语句、while语句等等。在计算计算赋值语句分支中,先计算赋值符号右边表达式的值,这个值将会赋给左边标识符,并且作为赋值符号的值而返回。对于左边标识符,先判断其是否在符号表中,如果不在就将其添加到符号表,并把右边表达式的值赋给它,以便后面引用到该标识符时使用。
在计算switch的表达式标识符的分支中,也是先查找其是否在符号表中,如果在的话,就直接返回符号表中保存的该标识符的值。如果不在,那么就将该标识符添加到符号表,并初始化为0。
另外的一些改变是getToken函数,添加了识别标识符的分支,下面仅列出其添加的代码:
default:
/*首字符是字母或者下划线*/
if (isalpha(c) || ('_' == c))
{
/*可以是下划线字母或者数字*/
while (isalnum(c) || ('_' == c))
{
tval[index++] = c;
c = nextChar();
}
pushBack();
token = ID;
state = DONE;
}
else
{
printf("
getToken: Unknown character.\n");
exit(1);
}
break;
添加的代码是在switch的default分支中,如果取出的字符c是一个字母或者下划线,那么说明是一个标识符的开始,然后while循环将标识符从缓冲区中取出放到另一个存储标识符字符串的小缓冲区中,直到遇到一个非字母和下划线的字符。
下面是向符号表添加符号和查找符号的两个函数:
void addSym(char *name, int val)
{
if (symidx >= SYMNUM)
{
printf("
addSym: too much symbol.\n");
exit(1);
}
symTbl[symidx] = (Sym *)malloc(sizeof(Sym));
symTbl[symidx]->name = name;
symTbl[symidx]->val = val;
symidx++;
}
Sym *findSym(char *name)
{
int i;
for (i = 0; i < symidx; i++)
{
if (!strcmp(symTbl[i]->name, name))
{
return symTbl[i];
}
}
return NULL;
}
这两个函数比较简单,就是用一个数组和一个下标来管理,查找使用顺序查找,简直是简单到不能忍了,不过目前来说,还是够用就好,够用就好,呵呵。
好了,这个带变量,带语句版本的计算器就完成了。下面看看效果。
建立一个测试文件test.txt,输入以下内容:
num1 := 5;
num2 := num1 + 10;
num3 := num2 * num1 - 20 / num1;
接下来编译计算器
gcc -fno-builtin mycomplier.c -o mycpl
执行
./mycpl test.txt
将会输出 The result is 71.
看到这一条条带变量的语句,还能计算出正确的结果,真是觉点有点像那么回事 Y(^_^)Y。
源代码下载路径 http://download.csdn.net/detail/luo3532869/8039017
Email: robin.long.219@gmail.com
有问题欢迎交流~~~~~