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

来源:互联网 发布:极域电子教室网络锁屏 编辑:程序博客网 时间:2024/05/19 02:24
前面已经介绍了很多表达式,但还没有介绍函数表达式语句,那么在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处理。 

  <script type="text/javascript"><!--google_ad_client = "pub-0904655026211899";google_ad_width = 468;google_ad_height = 60;google_ad_format = "468x60_as";google_ad_type = "text_image";google_ad_channel = "";google_color_border = "336699";google_color_bg = "FFFFFF";google_color_link = "0000FF";google_color_text = "000000";google_color_url = "008000";//--></script> <script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>
原创粉丝点击