lastking的专栏

Nothing Lost,Nothing Gain!

little c解释器分析[二]

/* ------------------------------------------------------------------------------------- */
/* 递归下降分析算法: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 */
 }
}
阅读更多
个人分类: Compile编译技术
想对作者说点什么? 我来说一句

little c解释器分析

2008年11月30日 8KB 下载

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭