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

表达式是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

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License