LCC编译器的源程序分析(22)基本表达式

来源:互联网 发布:nginx 1.8.0下载 编辑:程序博客网 时间:2024/05/21 07:48
表达式是C编译器里最重要的一部份,由于表达式的使用是无所不在,任何的计算都需要使用到表达式运算。这次就带你去分析一下LCC编译器处理表达式的代码。
比如在例子里:
int nTest1 = 1;
int nTest2 = 2;
赋值语句的右边是一个表达式,这个表达式可以简单的也可以复杂的。像下面语句的右边也是表达式:
nTest3 = nTest1 + nTest2;
还有很多地方都需要使用到表达式的,在LCC里处理表达式的方法是递归下降的分析方法,比如分析语句(nTest1 = 1)右边的表达式产生下面的调用关系:
#001 expr1
#002   expr2
#003                    expr3
#004                         unary
#005                               primary
它是使用递归的调用关系来分析优先级,最低优先级在expr里,接着高一点的在expr1里,依次类推。primary函数是处理最基本的运算单元,比如常量字符串,常量等。由于在赋值语句右边不可能出现逗号表达式,所以直接就调用expr1来处理右边的表达式。下面就来分析基本表达式primary,它的代码如下:
#001 static Tree primary(void)
#002 {
#003     Tree p;
#004 
#005     assert(t != '(');
#006     switch (t)
#007     {
#008     case ICON:
#009     case FCON:
#010          p = tree(mkop(CNST,tsym->type), tsym->type, NULL, NULL);
#011          p->u.v = tsym->u.c.v;
#012          break;
第8行是识别整型常量,比如像1,100,200,0xF3等等。
第9行是识别浮点数常量,比如像1.0f, 5.5等等。
第10行是创建一个树节点来表示这个常量。其实,这就是LCC的中间表示。
 
#013     case SCON:
#014          if (ischar(tsym->type->type))
#015              tsym->u.c.v.p = stringn(tsym->u.c.v.p, tsym->type->size);
#016             else
#017              tsym->u.c.v.p = memcpy(allocate((tsym->type->size/widechar->size)*sizeof (int), PERM),
#018                     tsym->u.c.v.p, (tsym->type->size/widechar->size)*sizeof (int));
#019 
#020             tsym = constant(tsym->type, tsym->u.c.v);
#021             if (tsym->u.c.loc == NULL)
#022              tsym->u.c.loc = genident(STATIC, tsym->type, GLOBAL);
#023             p = idtree(tsym->u.c.loc); break;
第13行是识别处理字符串常量,比如像“abc”。
第15行是处理一般字符串。
第16行是处理宽字符串。
第20行是生成字符串常量符号。然后在第23行里创建一个ID树节点来表示这个字符串。
 
 
#024     case ID:  
#025          if (tsym == NULL)
#026          {
#027                Symbol p = install(token, &identifiers, level, PERM);
#028                p->src = src;
#029                if (getchr() == '(')
#030                {
#031                     Symbol q = lookup(token, externals);
#032                     p->type = func(inttype, NULL, 1);
#033                     p->sclass = EXTERN;
#034 
#035                     if (Aflag >= 1)
#036                           warning("missing prototype/n");
#037                     if (q && !eqtype(q->type, p->type, 1))
#038                           warning("implicit declaration of `%s' does not match previous declaration at
#039 %w/n", q->name, &q->src);
#040 
#041                     if (q == NULL)
#042                     {
#043                           q = install(p->name, &externals, GLOBAL, PERM);
#044                           q->type = p->type;
#045                           q->sclass = EXTERN;
#046                           q->src = src;
#047                           (*IR->defsymbol)(q);
#048                     }
#049                     p->u.alias = q;
#050                }
#051                else
#052                {
#053                     error("undeclared identifier `%s'/n", p->name);
#054                     p->sclass = AUTO;
#055                     p->type = inttype;
#056                     if (p->scope == GLOBAL)
#057                           (*IR->defsymbol)(p);
#058                     else
#059                           addlocal(p);
#060                }
#061                t = gettok();
#062                if (xref)
#063                     use(p, src);
#064                return idtree(p);
#065          }
上面这段代码是处理表达式中的ID没有符号表的情况,目前先把这段代码放下,以后再分析。
 
#066 
#067          if (xref)
#068                use(tsym, src);
#069          if (tsym->sclass == ENUM)
#070                p = consttree(tsym->u.value, inttype);
#071          else
#072          {
#073                if (tsym->sclass == TYPEDEF)
#074                     error("illegal use of type name `%s'/n", tsym->name);
#075                p = idtree(tsym);
#076          }
#077          break;
像上面的表达式(nTest3 = nTest1 + nTest2;),其中nTest3的识别就是在第75行里生成ID树节点。第69行是处理枚举的类型,生成常量树节点。
 
 
#078     case FIRSTARG:
#079          if (level > PARAM && cfunc && cfunc->u.f.callee[0])
#080                p = idtree(cfunc->u.f.callee[0]);
#081          else {
#082                error("illegal use of `%k'/n", FIRSTARG);
#083                p = cnsttree(inttype, 0L);
#084          }
#085          break;
上面处理__firstarg参数。
 
 
#086     default:
#087          error("illegal expression/n");
#088                p = cnsttree(inttype, 0L);
#089     }
#090     t = gettok();
#091     return p;
#092 }
87行处理不能识别的基本表达式,提示出错,并创建0常量的树节点。
 
通过上面的函数分析可知,基本表达式的就是常量和变量ID,不管多么复杂的表达式都是有这两种类型构成的。也可以看到C的基本表达式的语法如下:
primary-expression:
identifier
 
constant
 
string-literal
 
( expression )
 
expression:
assignment-expression
 
expression , assignment-expression