/* ------------------------------------------------------------------------------------- */
/* 递归下降分析算法:little c解释器是采用递归下降来进行表达式分析的 */
/* ------------------------------------------------------------------------------------- */
exp_x递归的描述
--------------------
因为涉及到优先级的问题,所以从exp_1开始的递归子程序,都是越后递归所要完成的任务的优先级越高
,exp_1开始执行后,并不完成其本身的任务,而是向下递归,只到最下面一个子程序,然后返回,在返回的
过程中根据优先级来先后完成当前的任务。
首先从exp_0开始,其检查是否是空表达式,以及处理变量。在处理变量过程中又递归运行,使变量赋值。
exp_1主要完成的任务是计算布尔表达式,其计算过程中需要在次递归调用得到第2个值好和第一个值进行布尔
计算。
exp_2主要完成的任务是计算处理加法和减法运算。其运算过程中需要查看其后的运算时候是乘法或除法,
如果是需要先进行计算,所以在while内部需要调用exp_3,如果是4+28*2这样的,那么当exp_3返回时就会返回
56,然后才进行加法运算。此程序还需要处理7+1+2+1这样的连加或连减.
exp_3主要完成的任务是计算除法和取摸。其功能类似加减。
exp_4处理一元加或减。
exp_5最高优先级别,是()运算,
atom负责内部函数和用户定义的函数调用,并返回值给全局变量value,和返回常量值以及数字值。
----------------------
/* Entry point into parser. */
/* 分析部分程序开始执行 */
/* 程序的入口是eval_exp()函数 */
void eval_exp(int *value)
{
/* 首先取得一个符号 */
get_token();
/* 判断是否有符号,如果没有返回错误,没有表达式 */
if(!*token) {
sntx_err(NO_EXP);
return;
}
/* 如果“单词”为 ";" 的话,那么表示是一个空表达式,空表达式的值为0,表示假 */
if(*token == ';') {
*value = 0; /* empty expression */
return;
}
/* 如果不是上面2种情况,那么表达式递归分析开始执行 */
eval_exp0(value);
putback(); /* return last token read to input stream */
}
/* Process an assignment expression */
void eval_exp0(int *value)
{
char temp[ID_LEN]; /* holds name of var receiving
the assignment */
register int temp_tok;
if(token_type == IDENTIFIER) {
/* 通过变量is_var查看这个“标示符”是否已经在全局或局部变量表中 */
if(is_var(token)) { /* if a var, see if assignment */
/* 如果在的话,那么把token复制到temp变量中 */
strcpy(temp, token);
//如果不在话那么将先把token内存放的值copy到temp里,因为确定是赋值语句,那么就可能是表达式,由于token是全局变量,所以要在这里保
存。
temp_tok = token_type;//缓冲标记类型设置为token_type
get_token();//取得下一个符号,根据这个变量名字还没定义,那就说明他应该是有个赋值的语句
if(*token == '=') { /* is an assignment */ //如果是一个=符号的话,那就说明他是赋值语句
get_token();//取得符号
eval_exp0(value); //递归计算表达式
assign_var(temp, *value); //给变量赋值
return;
}
else { //
putback(); //否则恢复token以前指针的位置
strcpy(token, temp); //把temp的值给token
token_type = temp_tok;//类型为temp_tok类型
}
}
}
eval_exp1(value);//递归进入下一层
}
/* Process relational operators. */
void eval_exp1(int *value)
{
int partial_value;//另一个需要计算的表达式中的值
register char op; //此变量是操作符变量
char relops[7] = {//操作符表
LT, LE, GT, GE, EQ, NE, 0
};
eval_exp2(value);//进入下一层
op = *token; //操作符
if(strchr(relops, op)) {//如果属于操作符
get_token();//取得下一个符号
eval_exp2(&partial_value);//取得partial_value的值
switch(op) { /* perform the relational operation */
case LT://处理LT的情况 小于号
*value = *value < partial_value;//处理的真假值放到values里,values此时只可能是1或0
break;//推出switch语句
case LE://处理LE的情况 小于等于号
*value = *value <= partial_value;
break;
case GT://处理GT的情况 大于号
*value = *value > partial_value;
break;
case GE://处理GE的情况 大于等于号
*value = *value >= partial_value;
break;
case EQ://处理EQ符号 测试是否相等符号
*value = *value == partial_value;
break;
case NE://处理NE符号 测试不等符号
*value = *value != partial_value;
break;
}
}
}
/* Add or subtract two terms. */
void eval_exp2(int *value)
{
register char op;
int partial_value;
eval_exp3(value);//进入递归
while((op = *token) == '+' || op == '-') {//处理多个加号或减号
get_token();//取得一个符号
eval_exp3(&partial_value);//得到一个数字。这个值可能是来自乘法或除法或表达式传回来的值
switch(op) { //选择一个符号
case '-'://处理减号
*value = *value - partial_value;
break;
case '+'://处理加号
*value = *value + partial_value;
break;
}
}
}
/* Multiply or divide two factors. */
void eval_exp3(int *value)
{
register char op;
int partial_value, t;
eval_exp4(value);//进入下一层递归
while((op = *token) == '*' || op == '/' || op == '%') {//处理连乘或连除
get_token();//取得下一个符号
eval_exp4(&partial_value);//得到一个数字
switch(op) { /* mul, div, or modulus */
case '*'://处理乘法
*value = *value * partial_value;
break;
case '/'://处理除法
if(partial_value == 0) sntx_err(DIV_BY_ZERO);
*value = (*value) / partial_value;
break;
case '%'://处理取摸运算.余数放在value里
t = (*value) / partial_value;
*value = *value-(t * partial_value);
break;
}
}
}
//eval_exp4处理一元加或减
/* Is a unary + or -. */
void eval_exp4(int *value)
{
register char op;
op = '\0';
if(*token == '+' || *token == '-') {
op = *token;
get_token();
}
eval_exp5(value);
if(op)
if(op == '-') *value = -(*value);
}
/* Process parenthesized expression. */
void eval_exp5(int *value)
{
if((*token == '(')) {//处理(,()具有最高优先级
get_token();
eval_exp0(value); /* get subexpression */
if(*token != ')') sntx_err(PAREN_EXPECTED);//如果没有)说明语法错误
get_token();
}
else
atom(value);//取得一个值
}
void atom(int *value)
{
int i;
switch(token_type) {
/* 选择token类型 */
case IDENTIFIER:
/* 如果是变量或函数 */
i = internal_func(token);
/* 从内部结构中查找函数名是否存在 */
if(i!= -1) { /* call "standard library" function */
/* 如果不是-1的话,那么表示是内部函数 */
*value = (*intern_func.p)();
/* 通过结构中的函数指针调用内部函数,返回的值放到 value指向地址里 */
}
else if(find_func(token)) { /* call user-defined function */
/* 否则通过函数find_func查找是否是用户定义的函数,如果是的话 */
call();
/* 通过call函数调用用户定义的函数 */
*value = ret_value;
/* 函数的返回值放到value指向的地址里 */
}
else *value = find_var(token); /* get var's value */
/* 否则就认为他是一个变量的名字,通过find_var函数找到token里存放到变量值,然后放到value里 */
get_token();
/* 返回 */
return;
case NUMBER: /* is numeric constant */
/* 如果是一个数字的话 那么通过标准库函数中的atoi(在stdio.h中定义了此函数) 把字符转化为数字类型,以方便表达式计算 */
*value = atoi(token);
get_token();
/* 返回 */
return;
case DELIMITER: /* see if character constant */
/* 如果是一个字符常量的话 */
if(*token == '\'') {
/* 如果是'字符,那么把当前的值放到value里 */
*value = *prog;
prog++;
if(*prog!='\'') sntx_err(QUOTE_EXPECTED);
/* 如果不是以'符号结尾,就抛出语法错误 */
prog++;
get_token();
return ;
}
if(*token==')') return; /* process empty expression */
else sntx_err(SYNTAX); /* syntax error */
default:
sntx_err(SYNTAX); /* syntax error */
}
}