LCC编译器的源程序分析(39)goto语句

在现代设计的程序里,很少再用到goto语句了。虽然使用goto语句是比较高效,但它使程序也会得非常难懂,非常难维护,比较容易出错,所以很少使用goto语句的。goto语句为无条件跳转语句,它的一般形式为:
goto 标号;
在LCC里的是用下面的代码来处理:
#001 case GOTO:
#002 walk(NULL, 0, 0);
#003 definept(NULL);
#004 t = gettok();
#005 if (t == ID)
#006 {
#007 Symbol p = lookup(token, stmtlabs);
#008
#009 if (p == NULL)
#010 {
#011 p = install(token, &stmtlabs, 0, FUNC);
#012 p->scope = LABELS;
#013 p->u.l.label = genlabel(1);
#014 p->src = src;
#015 }
#016 use(p, src);
#017 branch(p->u.l.label);
#018 t = gettok();
#019 }
#020 else
#021 error("missing label in goto\n"); expect(';');
#022 break;
第2行复位所有分配的内存。
第3行定义执行点。
第4行获取下一个记号。
第5行判断goto语句后面是否标号变量。如果是标号变量,就跳到第6行到第19行里处理。否则就在第21行里提示出错。
第7行里查找标号是否已经定义。
第9行是当标号还没有定义时,就把这个标号安装到符号表里。这是在第9行到第15行里处理。
第17行是生成跳转到标号的代码。

下面再来分析标号语句是怎么样定义的,如下:
#001 case ID:
#002 if (getchr() == ':')
#003 {
#004 stmtlabel();
#005 statement(loop, swp, lev);
#006 break;
#007 }
第2行就判断一个ID标识符是否标号变量,如果在一个ID后面紧跟着一个冒号,就是表示声明了一个标号变量,所以在第4行里调用函数stmtlabel来处理标号。
第5行是处理标号后面的语句。

下面来分析函数stmtlabel:
#001 static void stmtlabel(void)
#002 {
#003 Symbol p = lookup(token, stmtlabs);
#004
#005 if (p == NULL)
#006 {
#007 p = install(token, &stmtlabs, 0, FUNC);
#008 p->scope = LABELS;
#009 p->u.l.label = genlabel(1);
#010 p->src = src;
#011 }
#012
#013 if (p->defined)
#014 error("redefinition of label ‘%s’ previously defined at %w\n", p->name, &p->src);
#015
#016 p->defined = 1;
#017 definelab(p->u.l.label);
#018 t = gettok();
#019 expect(':');
#020 }
第3行是查找这个标号是否定义。
第5行判断这个标号是否定义,如果没有定义就添加到符号表。
第7行是保存到符号表。
第8行到第10行都是设置标号的属性。
第13行当重复定义标号时,提示出错。
第16行设置这个标号已经定义。
第17行定义一个标号。
第18行获取下一个记号。
第19行检查标号后是否冒号。

这样就可以处理goto语句和标号语句了,到这里就把所有基本的语句分析完成了。

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