[转载] LCC编译器的源程序分析(32)for循环语句

来源:互联网 发布:极域电子教室网络锁屏 编辑:程序博客网 时间:2024/05/19 03:18
C语言中的for语句使用最为灵活,不仅可以用于循环次数已经确定的情况,而且可以用于循环次数不确定而只给出循环结束条件的情况。因此,这个语句的使用频率是最高的,当然它的处理情况比上面两种循环要复杂一些。它的形式如下:
 for(表达式1;表达式2;表达式3)
       语句1
它的执行过程是先求解表达式1的值,然后再计算表达式2的值。如果其值为真,就执行语句1,然后再执行表达式3。如果其值为假,就直接跳出循环不再执行语句1和表达式3。如果在C++里还会有作用域的范围不同样的。
下面就是LCC处理for循环的代码:
#023  case FOR:     
#024         forstmt(genlabel(4), swp, lev + 1);
#025         break;
24行是调用函数forstmt来处理for语句。
 
而函数forstmt的代码如下:
#001 static void forstmt(int lab, Swtch swp, int lev)
#002 {
#003  int once = 0;
#004  Tree e1 = NULL, e2 = NULL, e3 = NULL;
#005  Coordinate pt2, pt3;
#006  
#007  t = gettok();
#008  expect('(');
#009  definept(NULL);
#010  
#011  if (kind[t] == ID)
#012         e1 = texpr(expr0, ';', FUNC);
#013  else
#014         expect(';');
#015 
#016  walk(e1, 0, 0);
#017  pt2 = src;
#018  refinc *= 10.0;
#019 
7行获取下一个记号。也就是for单词后面的左括号开始记号。
8行就是处理左括号。
9行创建了执行点。
11行是判断是否有第一个表达式,如果有就进入第12行处理,调用函数texpr来处理表达式1,并生成树e1返回来。如果没有表达式1,就在第14行直接处理下一个分号。
 
 
#020  if (kind[t] == ID)
#021         e2 = texpr(conditional, ';', FUNC);
#022  else
#023         expect(';');
#024
20行是判断第二个表达式是否存在,如果存在就调用函数texpr来处理第二个表达式。如果不存在就在第23行里处理下一个分号。
 
 
#025  pt3 = src;
#026  if (kind[t] == ID)
#027         e3 = texpr(expr0, ')', FUNC);
#028  else
#029  {
#030         static char stop[] = { IF, ID, '}', 0 };
#031         test(')', stop);
#032  }
#033 
26行是判断第三个表达式是否存在,如果存在就调用函数texpr来处理第三个表达式。如果不存在,就需要处理右括号了。
 
#034  if (e2)
#035  {
#036         once = foldcond(e1, e2);
#037         if (!once)
#038               branch(lab + 3);
#039  }
#040  
34行是判断第二个表达式是否存在,如果存在就查找循环是否需要执行一次,如果不需要执行就跳到第三个标号。
 
#041  definelab(lab);
#042  statement(lab, swp, lev);
#043  
#044  definelab(lab + 1);
#045  definept(&pt3);
41行是定义第一个标号。
42行是处理循环体的语句1
44行是定义第二个标号。
 
#046  if (e3)
#047         walk(e3, 0, 0);
#048  
#049  if (e2)
#050  {
#051         if (!once)
#052               definelab(lab + 3);
#053         definept(&pt2);
#054         walk(e2, lab, 0);
#055  }
#056  else
#057  {
#058         definept(&pt2);
#059         branch(lab);
#060  }
#061 
#062  if (findlabel(lab + 2)->ref)
#063         definelab(lab + 2);
#064 
#065 }
46行和第47行是计算第三个表达式。
第第49行到第55行是处理第二个表达式,如果第二个表达式值为真就需要跳转到第一个标号运行语句。
52行是生成第4个标号,由于不能判断是否需要运行一次时,就需要计算表达式的值,才能决定。
57行到第60行是没有第二个表达式,所以无条件跳到第一个标号那里继续运行语句1
通过运行上面的代码就会生成下面形式的汇编代码:
表达式1
标号1:语句1
标号2:表达式3
标号4:如果表达式2值不等于0 就跳到标号1
标号3
上面的优化代码,如果当常量判断表达式2要运行一次时,就直接从标号1开始运行了,不用跳到标号4作一次判断。如果不是常量判断出来的,就需要多一个跳转,先跳到标号4那里运行,作表达式2的计算再作出选择。 
  <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>