【编译原理】三地址码

编译器构造

在这里插入图片描述

编译器的结构

在这里插入图片描述
语义检查后,代码由中间代码表示。

中间码是语法成分的语义结构表达。

中间语言

  1. 从低级语言过渡到高级语言
  2. 与机器无关
  3. 源语言和目标语言之间的一致性
  4. 它使编译器的结构逻辑简单
    在这里插入图片描述

中间语言表达式

x = a * b + c

逆波兰(RPN)形式

Reverse Polish notation也称为后缀
在这里插入图片描述

图形(语义树)

  1. 抽象语法树
  2. 有向无环图
    在这里插入图片描述

三地址码表达形式

在这里插入图片描述

四地址码表达形式

在这里插入图片描述

三地址码

三地址码(TAC)是表示编译器使用的中间码的一种形式。

三个地址代码中的每条指令都可以描述为四元组(有时也称为“四元组”)。

(运算符、操作数1、操作数2、结果)
在这里插入图片描述

三地址码(TAC)指令

在这里插入图片描述

三地址码的使用和特点

即使某些指令使用的操作数多于或少于两个,术语“三地址码”仍被使用:

  1. 经典、无操作数
  2. 这种格式的中间代码的读取操作都是相同的长度

三种地址码的主要特点是:

  1. 每条指令只执行一个基本操作
  2. 源和目标可以引用任何可用的寄存器

文字表

文字表类似于符号表,只是其条目是输入流中出现的值的任何文字表示。

例如,数字文字,如整数文字(“3”、“109”)或浮点/实数文字(“3.14”或其他浮点数符号)。

或字符文字(‘a’,‘1’)

或字符串文字(“hello,world!”)

  1. 通过将它们保存在表中,编译器可以使用它们在表中的地址来引用它们,而不是直接使用文本
    1)同样,它通过符号表中的地址引用符号
    2)但请稍后查看可能的优化
  2. 其中一些表可以由语法分析器填充。
    1)字符串文本,例如每当遇到常量字符串时
    2)除了查找之外,该表还可用于后期生成输出二进制文件中的静态值块
  3. 其他可以作为函数“填充”
    1)integerTable = func(key)=>index
    2)floatTable = func (key)=>key

优化阶段

  1. 这些改进是优化阶段的一部分
    1)这些改进与生成的特定机器代码无关
    2)当解析器检查实际生成的代码时,可能会有进一步的优化
  2. TAC表示的优点之一是它比解析树表示更容易优化

Thanks to Dr. John: Some contents are from their slides.

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
地址代码是编译原理语法分析后的中间语言的一种,这是我刚完成的地址代码生成器,符合的语法规则及其语义规则如下(S→if C then S1 else S2,这条规则没有加,其余都已完成,也许还有bug,欢迎大家给予指正):产生式 语义规则S → id = E S.code = E.code || gen(id.place’:=’E.place)S → if C then S1 C.true = newlabel; C.false = S.next;S1.next = S.next;S.code = C.code || gen(E.true’:’) || S1.codeS → if C then S1 else S2 C.true = newlabel; C.false = newlabel;S1.next = S2.next =S.next;S.code = C.code || gen(E.true’:’) || S1.code ||gen(‘goto’,S.next)|| gen(E.false’:’) || S2.codeS → while C do S1 S.begin = newlabel; C.true = newlabel;C.false = S.next; S1.next = S.begin;S.code = gen(S.begin’:’) || C.code ||gen(E.true’:’) || S1.code || gen(‘goto’S.begin);C → E1 > E2 C.code = E1.code || E2.code ||gen(‘if’E1.place’>’E2.place’goto’C.true) ||gen(‘goto’C.false)C → E1 < E2 C.code = E1.code || E2.code ||gen(‘if’E1.place’<’E2.place’goto’C.true) ||gen(‘goto’C.false)C → E1 = E2 C.code = E1.code || E2.code ||gen(‘if’E1.place’=’E2.place’goto’C.true) ||gen(‘goto’C.false)E → E1 + T E.place = newtemp;E.code = E1.code||T.code||gen(E.place’:=’E1.place’+’T.place)E → E1 - T E.place = newtemp; E.code = E1.code || T.code ||gen(E.place’:=’E1.place’-’T.place)E → T E.place = T.place; E.code = T.codeT → F T.place = F.place; T.code = F.codeT → T1 * F T.place = newtemp;T.code = T1.code || F.code ||gen(T.place’:=’T1.place’*’F.place)T → T1 / F T.place = newtemp; T.code = T1.code || F.code ||gen(T.place’:=’T1.place’/’F.place)F → ( E ) F.place = E
在R语言中,字节码编译是通过R的解释器和编译器的协作来实现的。下面是R语言字节码编译的简要原理: 1. 解释器:当你运行R代码时,解释器会逐行读取代码并执行。解释器会将代码翻译成一条条的指令,然后逐个执行这些指令。这种逐行解释执行的方式可以实现动态语言的灵活性和交互性。 2. 编译器:R语言还有一个即时编译器(Just-in-Time Compiler,JIT Compiler),它可以将一段代码(称为函数)编译成字节码形式,以提高执行效率。编译器会将函数的源代码分析并转换为字节码表示形式。 3. 字节码:字节码是一种中间形式的代码,它比源代码更接近于机器指令。字节码是由一系列的指令(例如,操作数栈操作、变量存取等)组成的,每条指令都对应着一种特定的操作。 4. 解释执行和即时编译:当解释器遇到已经被编译的函数时,它会直接执行对应的字节码指令,而不需要逐行解释执行源代码。这样可以提高函数的执行效率。 5. 缓存和优化:为了提高性能,R语言的编译器通常会将编译后的字节码缓存起来,以便下次再次调用相同的函数时可以直接使用缓存的字节码。此外,编译器还会进行一些优化,例如代码内联、循环展开等,以进一步提高执行效率。 需要注意的是,R语言的字节码编译是在函数级别进行的,并不是将整个脚本都编译成字节码。只有在函数被调用时,才会将函数的代码编译成字节码。这样可以灵活地处理不同函数的执行需求。 希望这个简要的解释能够帮助你理解R语言字节码编译的原理。如果你有更多具体的问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值