`
RednaxelaFX
  • 浏览: 3047705 次
  • 性别: Icon_minigender_1
  • 来自: 海外
社区版块
存档分类
最新评论

对C语义的for循环的基本代码生成模式

阅读更多
之前有同学在做龙书(第二版)题目,做到8.4的练习,跟我对答案,然后聊起C语言的for循环的代码生成有几种常见的模式。顺道跟大家分享讨论一下。

C语言的for循环大家应该都很熟悉了,C系语言大都有一样或几乎一样的语法结构:一个循环初始化,一个循环条件,一个循环再初始化,然后一个循环体。通常循环初始化在最前面,再初始化的逻辑直接黏在循环体后面,能有变化的就是循环条件的代码生成到什么位置。

举个例子,
for (int i = 0; i < 100; i++) {
  foo();
}

把它翻译为龙书第8章所用的三地址指令,可以用许多不同的模式翻译,这里举三种例子:
(注释里标出了基本块的标号、前导基本块、后继基本块,以及基本块的内容等信息。应该很直观吧?)

第一种:循环条件放前面,循环末尾用无条件跳转回到开头:
// B0 -> B1: loop initialize
(1)  i = 0

// B1 <- { B0, B2 }, -> { B2, B3 }: loop condition
(2)  if i >= 100 goto (6)  // note: inverted condition

// B2 <- B1, -> B1: loop body
(3)  call foo()
(4)  i = i + 1
(5)  goto (2)

// B3 <- B1: after loop
(6)  ...





第二种:循环条件放后面,在进入循环的地方先无条件跳转到位于循环末尾的条件:
// B0 -> B2: loop initialize
(1)  i = 0
(2)  goto (5)

// B1 <- B2, -> B2: loop body
(3)  call foo()
(4)  i = i + 1

// B2 <- { B0, B1 }, -> { B1, B3 }: loop condition
(5)  if i < 100 goto (3)

// B3 <- B2: after loop
(6)  ...





第三种:在进入循环的地方先判断是否跳过循环,然后循环条件放在末尾:
// B0 -> { B1, B3 }: loop initialize
(1)  i = 0
(2)  if i >= 100 goto (6)  // note: inverted condition

// B1 <- { B0, B2 }, -> B2: loop body
(3)  call foo()
(4)  i = i + 1

// B2 <- B1, -> { B1, B3 }: loop condition
(5)  if i < 100 goto (3)

// B3 <- { B0, B2 }: after loop
(6)  ...




顺带一提,这个具体例子中循环条件是拿循环变量与一个编译时常量比较,所以这个版本的代码的(2)可以非常轻易的通过条件常量传播消除掉,等价变换为:
// B0 -> B1: loop initialize
(1)  i = 0

// B1 <- { B0, B2 }, -> B2: loop body
(2)  call foo()
(3)  i = i + 1

// B2 <- B1, -> { B1, B3 }: loop condition
(4)  if i < 100 goto (2)

// B3 <- { B0, B2 }: after loop
(5)  ...




而前两种模式没那么容易消除其中的指令。


有兴趣的同学可以来讨论下这几种模式的异同点
注意三地址指令的条数,基本块的个数与划分,基本块之间控制流边的总个数,代码的静态与动态的情况的关系,等等。

当然这不是啥新问题,早就有很多论文讨论过了。
例如说某篇1978年的小论文⋯名字就先不说了免得剧透。有兴趣的同学自己思考喔。

========================================

下面补充些在实际生活种能看到的例子。

1. Java虚拟机规范,Java SE 7版,3.2小节
这里举了几个Java的for循环翻译为字节码的范例,都符合上面说的“第二种”模式。
例如把这样的代码:
void spin() {
    int i;
    for (i = 0; i < 100; i++) {
        ;    // Loop body is empty
    }
}

翻译为:
0:   iconst_0       // Push int constant 0
1:   istore_1       // Store into local variable 1 (i=0)
2:   goto 8         // First time through don't increment
5:   iinc 1, 1       // Increment local variable 1 by 1 (i++)
8:   iload_1        // Push local variable 1 (i)
9:   bipush 100     // Push int constant 100
11:  if_icmplt 5    // Compare and loop if less than (i < 100)
14:  return         // Return void when done

Eclipse Compiler for Java (ecj)就采取了这种模式。但Oracle JDK6里自带的javac实际用的代码生成策略却是前面说的“第一种”,将上面的例子编译为:
0:	iconst_0
1:	istore_1
2:	iload_1
3:	bipush	100
5:	if_icmpge	14
8:	iinc	1, 1
11:	goto	2
14:	return

好玩吧呵呵厚⋯
  • 大小: 20.4 KB
  • 大小: 19.2 KB
  • 大小: 27.6 KB
  • 大小: 17.1 KB
分享到:
评论

相关推荐

    第七章-第二讲-1

    《第七章 语义分析的中间代码生成》 在编译器设计中,语义分析是将源程序转化为机器可理解形式的关键阶段。本章主要探讨的是如何在语义分析阶段生成中间代码,这是一种便于优化和目标代码生成的抽象表示。中间代码...

    编译原理课程设计报告书

    《编译原理》课程设计报告书是对FOR循环语句翻译程序设计的一份详细说明,旨在深化学生对编译原理的理解,包括语法分析、语义分析和中间代码生成。以下是报告书涉及的关键知识点: 1. **编译原理基础**:课程设计...

    编译原理词法语法分析c语言程序

    综上所述,"编译原理词法语法分析c语言程序"涵盖的内容从源代码的读取开始,经过词法分析、语法分析、语义分析、优化、代码生成,直至形成最终的可执行文件。这一系列过程是理解和构建编译器的基础,也是开发者深入...

    Java实现C语言词法分析

    在C语言中,这些元素包括但不限于`int`、`for`(关键字)、`myVar`(标识符)、`34`(整型常量)、`+`和`-`(运算符)。词法分析器通常通过正则表达式或者有限状态自动机来识别这些模式。 在Java中实现C语言的词法...

    《编译原理》西北工业大学第三版课后答案

    逗号运算符在C语言中可以用于分隔变量列表,表达式组合,以及在for循环中控制流程。 练习中还涉及到前后文无关文法和语言,这是编译原理中的重要概念,用于描述语言的结构。例如,给定的文法可以生成特定类型的字符...

    同济大学编译原理课程设计类C编译器任务.zip

    这个任务旨在帮助你深入理解编译器的工作原理,掌握词法分析、语法分析、语义分析以及代码生成等关键步骤。 1. **词法分析**: 词法分析是编译器的第一步,它的任务是将源代码分解成一系列的标记(token)。对于...

    PL0 编译器

    总结来说,PL0编译器是一个用于理解和转换PL0源代码的程序,其设计和实现涉及多个阶段,包括词法分析、语法分析、语义分析、中间代码生成以及目标代码生成。虽然PL0语言简单,但它提供了一个理解编译器工作原理的...

    编译原理 吉林大学 视频

    这一过程涉及到词法分析、语法分析、语义分析、中间代码生成、代码优化以及目标代码生成等多个步骤。 2. **重要性**:掌握编译原理对于软件开发人员来说至关重要,它不仅能够帮助开发者更好地理解程序运行的底层机制...

    Turbo C2.0-编程软件怀旧版

    它支持标准C89规范,提供了基本的输入输出函数(如`printf`和`scanf`)、控制结构(如`if...else`,`for`,`while`循环)、数组、指针、函数等核心概念的实践平台。通过它,学生可以直观地理解这些概念,并在实践中...

    编译原理课程设计

    3. **语法**:类Pascal语言的语法结构包括声明部分(变量、常量、类型定义等)、程序块、函数和过程声明以及控制结构(如if-then-else, for循环,while循环)。了解这些语法元素的组合规则对创建有效的解析器至关...

    编译原理(第2版)课件

    8.6.3 for循环语句 8.6.4 出口语句 8.6.5 goto语句 8.6.6 过程调用的四元式产生 8.7 说明语句的翻译 8.7.1 简单说明语句的翻译 8.7.2 过程中的说明 8.8 数组和结构的翻译 8.8.1 数组说明和数组元素的引用 8.8.2 结构...

    C语言词法分析器可识别常数、字符、关键字等

    总之,C语言的词法分析器是编译过程中的重要环节,它负责识别并分类源代码中的常数、字符和关键字,为后续的语法分析和代码生成奠定了基础。理解和掌握词法分析器的工作原理对于编程和编译器设计来说至关重要。

    编译原理实验

    在PL的扩展中,可以考虑添加更灵活的匹配规则,如支持范围匹配或模式匹配,这需要设计新的语法和语义规则,并在解析和代码生成阶段进行相应处理。 8. **源代码结构**:压缩包中的`src`目录可能包含了实验的源代码,...

    编译原理课程设计PL0语言的扩充

    词法分析器通常使用正则表达式来定义单词记号的模式,通过扫描源代码生成单词记号流。 接下来是语法分析,它将单词记号流转化为抽象语法树(AST)。PL0语言的扩展可能涉及新的语句结构或表达式。比如,引入条件语句...

    2013广工编译原理试题

    综上所述,“2013广工编译原理试题”所涵盖的知识点包括但不限于编译器的基本概念、编译过程、文法与自动机理论、符号表管理、错误处理以及目标代码生成与优化等方面。这些知识点构成了编译原理的核心内容,对于理解...

    C和C++程序设计

    这本书可能详细介绍了词法分析、语法分析、语义分析、优化和目标代码生成等编译过程,对理解C和C++程序的底层工作原理有很大帮助。 7. **C.参考大全第四版.PDF**:C语言参考大全是C程序员必备的工具书,它提供了...

    Compiladores:C语言编译器

    C语言编译器的构建涉及多个阶段,包括词法分析、语法分析、语义分析、中间代码生成、优化以及目标代码生成。在这些阶段中,Flex和Bison主要负责前两步,为后续的编译过程奠定基础。 1. **词法分析**:Flex根据预...

Global site tag (gtag.js) - Google Analytics