LCC编译器的源程序分析(28)函数表达式语句

前面已经介绍了很多表达式,但还没有介绍函数表达式语句,那么在LCC里是怎么样处理函数调用,也就是函数表达式的呢?现在就来分析函数表达式的代码,函数调用是使用非常多的,因此分析这里的代码,需要非常仔细地查看。
从hello.i例子里,就可看到下面的函数表达式语句:
 printf("nTest3 = %d/r/n",nTest3);
它是由ID名称printf、表达式("nTest3 = %d/r/n",nTest3)、分号组成的。通过调用函数 expr0 来处理函数表达式,由于前面已经介绍那些相关的表达式,现在只去分析函数 postfix 表达式就可以了。它是从函数 unary 里进入,如下面所示:
#001 static Tree unary(void)
#002 {
#003  Tree p;
#197  default:
#198         p = postfix(primary());
主要是调用函数 postfix 来处理。先调用函数 primary 来处理 printf的ID名称,然后进入函数 postfix 处理后面的括号中的表达式,最后生成调用树的中间表示。下面就来分析函数 postfix 的代码,主要分析处理函数表达式的代码。
#001 static Tree postfix(Tree p)
#002 {
#003  for (;;)
#004         switch (t)
#005  {
3 行是处理所有 ID 后面的记号,比如函数表达式里的括号中内容。
4 行根据当前记号来识别自增、自减、数组、函数表达式。
 
#006         case INCR: 
#007               p = tree(RIGHT, p->type,
#008                    tree(RIGHT, p->type,
#009                    p,
#010                    incr(t, p, consttree(1, inttype))),
#011                    p);
#012               t = gettok();
#013               break;
#014         case DECR: 
#015               p = tree(RIGHT, p->type,
#016                    tree(RIGHT, p->type,
#017                    p,
#018                    incr(t, p, consttree(1, inttype))),
#019                    p);
#020                t = gettok();
#021               break;
#022         case '[':  
#023               {
#024                    Tree q;
#025                    t = gettok();
#026                    q = expr(']');
#027                    if (YYnull)
#028                          if (isptr(p->type))
#029                               p = nullcheck(p);
#030                          else if (isptr(q->type))
#031                               q = nullcheck(q);
#032                    p = (*optree['+'])(ADD, pointer(p), pointer(q));
#033                    if (isptr(p->type) && isarray(p->type->type))
#034                          p = retype(p, p->type->type);
#035                    else
#036                          p = rvalue(p);
#037               }
#038               break;
#039         case '(':  
#040               {
#041                    Type ty;
#042                    Coordinate pt;
#043                    p = pointer(p);
#044                    if (isptr(p->type) && isfunc(p->type->type))
#045                          ty = p->type->type;
#046                    else
#047                    {
#048                          error("found `%t' expected a function/n", p->type);
#049                          ty = func(voidtype, NULL, 1);
#050                          p = retype(p, ptr(ty));
#051                    }
#052 
#053                    pt = src;
#054                    t = gettok();
#055                    p = call(p, ty, pt);
#056               }
#057               break;
39 行是括号开始的函数表达式。
43 行是处理函数的树节点指针。
45 行是获取函数返回类型。
48 行是出错处理。
49 行是设置函数返回值为空。
50 行生成返回的树节点。
53 行是保存当前函数的位置。
54 行是获取下一个记号。
55 行是调用函数 call 来生成调用函数树,后面再接着分析怎么样生成调用树的。
 
#058         case '.':  
#059               t = gettok();
#060               if (t == ID)
#061               {
#062                    if (isstruct(p->type))
#063                    {
#064                          Tree q = addrof(p);
#065                          p = field(q, token);
#066                          q = rightkid(q);
#067                          if (isaddrop(q->op) && q->u.sym->temporary)
#068                               p = tree(RIGHT, p->type, p, NULL);
#069                    }
#070                    else
#071                          error("left operand of . has incompatible type `%t'/n",
#072                          p->type);
#073                    t = gettok();
#074               }
#075               else
#076                    error("field name expected/n"); break;
#077         case DEREF:
#078               t = gettok();
#079               p = pointer(p);
#080               if (t == ID)
#081               {
#082                    if (isptr(p->type) && isstruct(p->type->type))
#083                    {
#084                          if (YYnull)
#085                               p = nullcheck(p);
#086                          p = field(p, token);
#087                    }
#088                    else
#089                          error("left operand of -> has incompatible type `%t'/n", p->type);
#090 
#091                    t = gettok();
#092               }
#093               else
#094                    error("field name expected/n"); break;
#095         default:
#096               return p;
#097  }
#098 }
 
上面的函数 postfix 并没有处理函数括号里的表达式,而是调用函数 call 来处理的。下面来分析函数 call 怎么样处理函数参数传递,它的代码如下:
#001 Tree call(Tree f, Type fty, Coordinate src)
#002 {
#003      int n = 0;
#004      Tree args = NULL, r = NULL, e;
#005      Type *proto, rty = unqual(freturn(fty));
#006      Symbol t3 = NULL;
#007 
#008      if (fty->u.f.oldstyle)
#009           proto = NULL;
#010      else
#011           proto = fty->u.f.proto;
#012 
#013      if (hascall(f))
#014           r = f;
#015 
#016      if (isstruct(rty))
#017      {
#018           t3 = temporary(AUTO, unqual(rty));
#019           if (rty->size == 0)
#020                 error("illegal use of incomplete type `%t'/n", rty);
#021      }
#022 
第8行判断是否使用旧风格的函数声明,如果使用新的函数声明,就在第11行里保存返回类型。
第13行是判断是否已经调用过这个函数。
第16行是判断返回类型是否结构类型,如果是结构类型,就需要创建临时返回符号t3。

第23行判断这个函数是否空的参数列表,如果是空的参数列表就不用去运行参数处理代码。如果非空的参数列表,就运行第24行for循环处理所有参数。
#023      if (t != ')')
#024           for (;;)
#025           {
#026                 Tree q = pointer(expr1(0));
第26行处理调用函数的第一个参数,生成一棵表达式树返回。
 
#027                 if (proto && *proto && *proto != voidtype)
#028                 {
#029                      Type aty;
#030                      q = value(q);
#031                      aty = assign(*proto, q);
#032                      if (aty)
#033                            q = cast(q, aty);
#034                      else
#035                            error("type error in argument %d to %s; found `%t' expected `%t'/n", n + 1, funcname(f),
#036 
#037                            q->type, *proto);
#038                      if ((isint(q->type) || isenum(q->type))
#039                            && q->type->size != inttype->size)
#040                            q = cast(q, promote(q->type));
#041                      ++proto;
#042                 }
#043                 else
#044                 {
#045                      if (!fty->u.f.oldstyle && *proto == NULL)
#046                            error("too many arguments to %s/n", funcname(f));
#047                      q = value(q);
#048                      if (isarray(q->type) || q->type->size == 0)
#049                            error("type error in argument %d to %s; `%t' is illegal/n", n + 1, funcname(f), q->type);
#050 
#051                      else
#052                            q = cast(q, promote(q->type));
#053                 }
#054 
第27行判断参数与声明函数是否一样的类型,如果不一样第29行到第41行处理。如果一样,就跳到第45行到第52行处理。
第30行获取参数的类型。
第33行进行参数的类型转换。
第52行也是类型转换。
 
#055                 if (!IR->wants_argb && isstruct(q->type))
#056                      if (iscallb(q))
#057                            q = addrof(q);
#058                      else
#059                      {
#060                            Symbol t1 = temporary(AUTO, unqual(q->type));
#061                            q = asgn(t1, q);
#062                            q = tree(RIGHT, ptr(t1->type),
#063                                  root(q), lvalue(idtree(t1)));
#064                      }
#065 
#066                      if (q->type->size == 0)
#067                            q->type = inttype;
#068 
#069                      if (hascall(q))
#070                            r = r ? tree(RIGHT, voidtype, r, q) : q;
#071 
#072                      args = tree(mkop(ARG, q->type), q->type, q, args);
#073                      n++;
#074                     
#075                      if (Aflag >= 2 && n == 32)
#076                            warning("more than 31 arguments in a call to %s/n",
#077                            funcname(f));
#078                     
#079                      if (t != ',')
#080                            break;
#081                      t = gettok();
#082           }
#083 
第55行是判断是否有返回值的处理,如果有返回值就不用运行第56行到第64行的代码。
第66行判断类型大小是否为0,如果是就需要初始化为缺省类型。
第72行是生成参数树。
第79行是判断是否还有下一个参数,如果没有就跳出for循环;如果有就继续处理下一个参数。
 
#084           expect(')');
#085          
#086           if (proto && *proto && *proto != voidtype)
#087                 error("insufficient number of arguments to %s/n",
#088                 funcname(f));
#089          
#090           if (r)
#091                 args = tree(RIGHT, voidtype, r, args);
#092          
#093           e = calltree(f, rty, args, t3);
#094          
#095           if (events.calls)
#096                 apply(events.calls, &src, &e);
#097          
#098           return e;
#099 }
第84行是检查是否函数调用结束符号。
第90行判断是否已经调用,如果有调用就生成引用树。
第93行是调用函数calltree来生成调用树。主要把返回值、参数树等组成调用树返回。
 
上面分析了函数调用代码的处理,然后把调用函数生成树形的中间表示返回,再一步的处理就是根据调用树来进行 DAG 处理。 

你可能感兴趣的:(LCC编译器的源程序分析(28)函数表达式语句)