由前面的例子可以知道,C函数里包含数据定义部分和执行部分,执行部分就是由语句组成。计算机最基本的动作就是具备条件判断,这也是计算机具有这么大魔力的原因。而这些条件判断是通过语句来实现的。基本的语句有下面几种:
1.     控制语句:
if else
for 
while
do while
continue
break
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行的错误处理。
到这里就把基本语句函数分析完成,接着后面就需要专门地分析具体语句的处理函数。

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

  1. LCC编译器的源程序分析(2)LCC编译器的预处理

    上面已经介绍了 C 编译器的目标,其实在实现这个目标之前,是经历了很多阶段处理的,其中第一个阶段的处理,就是预处理.预处理的任务是做什么呢?在 LCC 里预处理主要是把所有包含的头文件和源程序生成一个 ...

  2. [系统安全] 六.逆向分析之条件语句和循环语句源码还原及流程控制

    您可能之前看到过我写的类似文章,为什么还要重复撰写呢?只是想更好地帮助初学者了解病毒逆向分析和系统安全,更加成体系且不破坏之前的系列.因此,我重新开设了这个专栏,准备系统整理和深入学习系统安全.逆向分 ...

  3. 随想录(lcc编译器)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途. 联系信箱:feixiaoxing @163.com] lcc编译器是一款开源编译器,和我们之前谈过的ucc差不多.一开始的时候,这款编译器是用来进行教 ...

  4. Laravel Database——查询构造器与语法编译器源码分析 (上)

    前言 在前两个文章中,我们分析了数据库的连接启动与数据库底层 CRUD 的原理,底层数据库服务支持原生 sql 的运行.本文以 mysql 为例,向大家讲述支持 Fluent 的查询构造器 query ...

  5. 【开发环境】Ubuntu 中使用 VSCode 开发 C/C++ ④ ( 创建 tasks.json 编译器构建配置文件 | tasks.json 编译器构建配置文件分析 )

    文章目录 一.创建 tasks.json 编译器构建配置文件 二.tasks.json 编译器构建配置文件分析 可以参考官方提供的文档 : https://code.visualstudio.com/ ...

  6. [安全攻防进阶篇] 四.逆向分析之条件语句和循环语句源码还原及流程控制逆向

    从2019年7月开始,我来到了一个陌生的专业--网络空间安全.初入安全领域,是非常痛苦和难受的,要学的东西太多.涉及面太广,但好在自己通过分享100篇"网络安全自学"系列文章,艰难 ...

  7. i++和++i作为参数时的编译器处理方式分析

    这是一个很简单的程序 void main() { int i=8; printf("%d,%d,%d,%d\n", ++i, --i, i++, i--); } 在这里我使用了VS ...

  8. java实现LL(1)文法分析,if语句识别,赋值语句识别

    实验要求: 1.[实验项目] 实现LL(1)分析中控制程序(表驱动程序):完成以下描述赋值语句的LL(1)文法的LL(1)分析过程. G[A]:A→V=E E→TE′ E′→ATE′|ε T→FT′ ...

  9. GCC编译器优化选项分析及具体优化了什么

    问题 在使用gcc作为编译器.在设定编译条件时,在debug模式下生成的程序正常,但是在release模式下往往会出现很多种预料之外的结果,尤其在嵌入式环境中,程序在板子上运行的时候,问题就愈发明显. ...

  10. mysql源码如何解析where字句_MySQL解析器源码分析--对select语句中子查询处理逻辑的分析(一)...

    背景 一个最简单的select语句包含select子句.from子句.where子句等,这些子句都不包含子查询(subselect),也没有union操作.而复杂的select语句包含select子句 ...

最新文章

  1. Welcome to Swift (苹果官方Swift文档初译与注解三十四)---241~247页(第五章-- 函数)
  2. C++类为什么使用private?------封装性
  3. (转)iPhone wifi使用socket连接Internet
  4. 【数据库题型大总结】应用题总结
  5. 测试工程师因迟到和人事大吵一架,结果人事被开除
  6. SAP 图标查找及方法
  7. Struts,Spring,Hibernate三大框架的面试
  8. mac上最好用的免费PDF阅读器是哪个
  9. 【教程】怎样把高德打车优惠券的cps链接添加到微信公众号里面
  10. Ubuntu卸载Anaconda步骤
  11. Freenom免费域名申请
  12. 修改MDK5(keil5)工程文件名称
  13. vim 去掉黄色阴影
  14. Linux常用命令--解压缩
  15. RF使用技巧--返回值的妙用
  16. 安装 TiDB 分布式数据库
  17. 迅龙中文搜索 0.7 nSearch版 C# 源代码下载
  18. 火狐经典主题_Firefox的2010年假日角色角色主题
  19. 敏捷领导力系列介绍--全景领导力LCP的学习心得
  20. 技术人总有想写文章的冲动却无疾而终?4个小Tips帮你快速上手~

热门文章

  1. DES的s盒输出CPA和DPA攻击
  2. 与非门如何变成非门,与门,异或门
  3. html视频设置自动播放下一个,在html5中,如何使用video标签让两个不同的视频文件按顺序自动播放?...
  4. Apache POI 操作Excel表格使用详解 最全
  5. 什么是云计算机服务,云平台是什么意思 云服务平台有哪些【详细介绍】
  6. 云计算和云服务区别是什么
  7. 高中数学知识点归纳总结三角函数与解三角形
  8. VR全景创业好不好做?蛙色VR为你解答
  9. 彻底卸载secureCRT,并重装,包括绿色版SecureCRT删除干净
  10. Linux运维工程师发展