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

 
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 的计算再作出选择。 

你可能感兴趣的:(LCC编译器的源程序分析(32)for循环语句)