热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

LCC编译器的源程序分析(27)基本语句

由前面的例子可以知道,C函数里包含数据定义部分和执行部分,执行部分就是由语句组成。计算机最基本的动作就是具备条件判断,这也是计算机具有这么大魔力的原因。而这些条件判断是通过语句
由前面的例子可以知道, C 函数里包含数据定义部分和执行部分,执行部分就是由语句组成。计算机最基本的动作就是具备条件判断,这也是计算机具有这么大魔力的原因。而这些条件判断是通过语句来实现的。基本的语句有下面几种:
1.     控制语句 :
if else
for 
while
do while
continue
brea k
switch
goto
return
2.     函数调用语句
max(a,b);
3.     表达式语句
nPos = 10;
4.     空语句
;
最后面一种在 LCC 里会提示警告的。
在这节和后面跟着的节就是分析这些基本语句是怎么样处理,以及会生成什么样的代码。在 compound 函数里是这样调用语句分析函数的:
#052  while (kind[t] == IF || kind[t] == ID)
#053  {
#054         statement(loop, swp, lev);
#055  }   
#056  
因此要去分析函数 statement 是怎么样分析处理上面出现的语句。
 
下面就是 statement 的代码:
#001 // 所有基本语句处理函数。
#002 // 蔡军生 2007/06/02
#003 void statement(int loop, Swtch swp, int lev)
#004 {
#005  float ref = refinc;
#006 
#007  if (Aflag >= 2 && lev == 15)
#008          warning("more than 15 levels of nested statements/n");
#009 
5 行是保存引用计数。
7 行是判断递归调用超过 15 层。
 
#010  switch (t)
#011  {
#012  case IF:      
#013         ifstmt(genlabel(2), loop, swp, lev + 1);
#014         break;
13 行是调函数 ifstmt 来处理 if 语句。
 
#015  case WHILE:   
#016         whilestmt(genlabel(3), swp, lev + 1);
#017         break;
16 行是调用函数 whilestmt 来处理 while 语句。
 
#018  case DO:      
#019         dostmt(genlabel(3), swp, lev + 1);
#020         expect(';');
#021         break;
#022 
19 行是调用函数 dostmt 来处理 do while 语句。
20 行是处理 do while 语句后需要分号。
 
 
#023  case FOR:     
#024         forstmt(genlabel(4), swp, lev + 1);
#025         break;
24 行是调用函数 forstmt 来处理 for 语句。
 
 
#026  case BREAK:   
#027         walk(NULL, 0, 0);
#028         definept(NULL);
#029 
#030         if (swp && swp->lab > loop)
#031               branch(swp->lab + 1);
#032         else if (loop)
#033               branch(loop + 2);
#034         else
#035               error("illegal break statement/n");
#036 
#037         t = gettok();
#038         expect(';');
#039         break;
#040 
31,33 行是调用函数 branch 来处理 break 语句。
 
 
#041  case CONTINUE:
#042         walk(NULL, 0, 0);
#043         definept(NULL);
#044 
#045         if (loop)
#046               branch(loop + 1);
#047         else
#048               error("illegal continue statement/n");
#049 
#050         t = gettok();
#051         expect(';');
#052         break;
#053 
46 行是调用函数 branch 来处理 continue 语句。
 
 
#054  case SWITCH:  
#055         swstmt(loop, genlabel(2), lev + 1);
#056         break;
55 行是调用函数 swstmt 来处理 switch 语句。
 
 
#057  case CASE:    
#058         {
#059               int lab = genlabel(1);
#060               if (swp == NULL)
#061                    error("illegal case label/n");
#062 
#063               definelab(lab);
#064               while (t == CASE)
#065               {
#066                    static char stop[] = { IF, ID, 0 };
#067                    Tree p;
#068                    t = gettok();
#069                    p = constexpr(0);
#070                    if (generic(p->op) == CNST && isint(p->type))
#071                    {
#072                          if (swp)
#073                          {
#074                               needconst++;
#075                               p = cast(p, swp->sym->type);
#076                               if (p->type->op == UNSIGNED)
#077                                     p->u.v.i = extend(p->u.v.u, p->type);
#078                               needconst--;
#079                               caselabel(swp, p->u.v.i, lab);
#080                          }
#081                    }
#082                    else
#083                          error("case label must be a constant integer expression/n");
#084 
#085                    test(':', stop);
#086               }
#087               statement(loop, swp, lev);
#088         }
#089         break;
59 行是调用函数 genlabel 生成标号。
64 行是处理所有 case 语句。
69 行是处理 case 语句后面的常量表达式,调用函数 constexpr 来处理。
70 行到第 81 行是作类型转换的工作,如果不能处理常量类型,就会在第 83 行里提示出错。
87 行是递归调用函数 statement 处理 case 语句里语句。
 
 
#090  case DEFAULT: 
#091         if (swp == NULL)
#092               error("illegal default label/n");
#093         else if (swp->deflab)
#094               error("extra default label/n");
#095         else
#096         {
#097               swp->deflab = findlabel(swp->lab);
#098               definelab(swp->deflab->u.l.label);
#099         }
#100         t = gettok();
#101         expect(':');
#102         statement(loop, swp, lev);
#103         break;
97 行是查找 default 语句生成的标号。
98 行是定义这个标号。
102 行是调用函数 statement 递归处理所有后面语句。
 
#104  case RETURN: 
#105         {
#106               Type rty = freturn(cfunc->type);
#107               t = gettok();
#108               definept(NULL);
#109               if (t != ';')
#110                    if (rty == voidtype)
#111                    {
#112                          error("extraneous return value/n");
#113                          expr(0);
#114                          retcode(NULL);
#115                    }
#116                    else
#117                          retcode(expr(0));
#118               else
#119               {
#120                    if (rty != voidtype)
#121                    {
#122                          warning("missing return value/n");
#123                          retcode(cnsttree(inttype, 0L));
#124                    }
#125                    else
#126                          retcode(NULL);
#127               }
#128               branch(cfunc->u.f.label);
#129         }
#130         expect(';');
#131         break;
#132 
106 行是取得函数返回的类型。
109 行是判断返回语句是否有返回值,如果有返回值,但函数定义类型没有返回值就提示出错,这是在第 110 行里处理。如果函数定义有返回值,并且 return 语句也有返回值就调用第 117 行里的 retcode(expr(0)) 来处理返回表达式的值。
如果 return 语句后面没有返回值,但函数需要返回值,这样是出错的,是在第 120 行里处理。如果真的没有返回值,就是返回空值,在第 126 行里处理。
128 行跳转到函数调用之后标号执行。
 
#133  case '{':    
#134         compound(loop, swp, lev + 1);
#135         break;
当是大括号开始时,又是复合语句,所以要递归调用函数 compound 来处理。
 
 
#136  case ';':    
#137         definept(NULL);
#138         t = gettok();
#139         break;
上面是空行语句的处理。
 
#140  case GOTO:   
#141         walk(NULL, 0, 0);
#142         definept(NULL);
#143         t = gettok();
#144         if (t == ID)
#145         {
#146               Symbol p = lookup(token, stmtlabs);
#147 
#148               if (p == NULL)
#149               {
#150                    p = install(token, &stmtlabs, 0, FUNC);
#151                    p->scope = LABELS;
#152                    p->u.l.label = genlabel(1);
#153                    p->src = src;
#154               }
#155               use(p, src);
#156                branch(p->u.l.label);
#157               t = gettok();
#158         }
#159         else
#160               error("missing label in goto/n"); expect(';');
#161         break;
#162 
上面是 goto 语句的处理。
144 行先判断 goto 语句后面是否标号 ID ,如果是就运行 146 行的代码来查找已经定义的标号。如果没有找到就生成一个新的标号。最后在第 156 行里跳到标号的位置运行后面的代码。
 
 
#163  case ID:    
#164         if (getchr() == ':')
#165         {
#166               stmtlabel();
#167               statement(loop, swp, lev);
#168               break;
#169         }
上面处理标号语句。
166 行调用函数 stmtlabel 来处理标号语句,最后调用函数 statement 处理其它跟着的语句。
 
#170  default:    
#171         definept(NULL);
#172          if (kind[t] != ID)
#173         {
#174               error("unrecognized statement/n");
#175               t = gettok();
#176         }
#177         else
#178         {
#179               Tree e = expr0(0);
#180               listnodes(e, 0, 0);
#181               if (nodecount == 0 || nodecount > 200)
#182                    walk(NULL, 0, 0);
#183               else if (glevel) walk(NULL, 0, 0);
#184               deallocate(STMT);
#185         }
#186         expect(';');
#187         break;
#188 
#189  }
#190 
#191  if (kind[t] != IF && kind[t] != ID
#192         && t != '}' && t != EOI)
#193  {
#194         static char stop[] = { IF, ID, '}', 0 };
#195         error("illegal statement termination/n");
#196         skipto(0, stop);
#197  }
#198  refinc = ref;
#199 }
#200 
如果一个 ID 后面没有跟着冒号,那么它是一个表达式语句。
比如像例子里的语句:
nTest3 = nTest1 + nTest2;
这就是 ID 开始的表达式语句。它会调用前面介绍的表达式处理函数 expr0 来分析的。
172 行到 175 行处理不是 ID 的出错。
179 行是处理右边的表达式。
180 行是调用函数 listnodes 来遍历整个语句树,主要的目的是生成中间的树表示,删除公共的表达式节点,起到优化代码的作用,为后面生成代码作好准备工作。
181 行是当中间表示的树节点多于 200 个就进行代码生成。
191 行是出错的符号,并进入第 195 行到第 196 行的错误处理。
 
到这里就把基本语句函数分析完成,接着后面就需要专门地分析具体语句的处理函数。
 

推荐阅读
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 本文讨论了Kotlin中扩展函数的一些惯用用法以及其合理性。作者认为在某些情况下,定义扩展函数没有意义,但官方的编码约定支持这种方式。文章还介绍了在类之外定义扩展函数的具体用法,并讨论了避免使用扩展函数的边缘情况。作者提出了对于扩展函数的合理性的质疑,并给出了自己的反驳。最后,文章强调了在编写Kotlin代码时可以自由地使用扩展函数的重要性。 ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 开源Keras Faster RCNN模型介绍及代码结构解析
    本文介绍了开源Keras Faster RCNN模型的环境需求和代码结构,包括FasterRCNN源码解析、RPN与classifier定义、data_generators.py文件的功能以及损失计算。同时提供了该模型的开源地址和安装所需的库。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • HashMap的扩容知识详解
    本文详细介绍了HashMap的扩容知识,包括扩容的概述、扩容条件以及1.7版本中的扩容方法。通过学习本文,读者可以全面了解HashMap的扩容机制,提升对HashMap的理解和应用能力。 ... [详细]
  • 1Lock与ReadWriteLock1.1LockpublicinterfaceLock{voidlock();voidlockInterruptibl ... [详细]
  • 求解连通树的最小长度及优化
    本文介绍了求解连通树的最小长度的方法,并通过四边形不等式进行了优化。具体方法为使用状态转移方程求解树的最小长度,并通过四边形不等式进行优化。 ... [详细]
  • 判断编码是否可立即解码的程序及电话号码一致性判断程序
    本文介绍了两个编程题目,一个是判断编码是否可立即解码的程序,另一个是判断电话号码一致性的程序。对于第一个题目,给出一组二进制编码,判断是否存在一个编码是另一个编码的前缀,如果不存在则称为可立即解码的编码。对于第二个题目,给出一些电话号码,判断是否存在一个号码是另一个号码的前缀,如果不存在则说明这些号码是一致的。两个题目的解法类似,都使用了树的数据结构来实现。 ... [详细]
  • 文章目录题目:二叉搜索树中的两个节点被错误地交换。基本思想1:中序遍历题目:二叉搜索树中的两个节点被错误地交换。请在不改变其结构的情况下 ... [详细]
  • 本文由编程笔记#小编为大家整理,主要介绍了源码分析--ConcurrentHashMap与HashTable(JDK1.8)相关的知识,希望对你有一定的参考价值。  Concu ... [详细]
  • 二叉树的前序遍历(递归版):publicArrayList<Integer> ... [详细]
author-avatar
吴力强尹泽楠1991
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有