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

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