Atitti. 语法树AST、后缀表达式、DAG、三地址代码

抽象语法树的观点认为任何复杂的语句嵌套情况都可以借助于树的形式加以描述。确实,不得不承认应用抽象语法树可以使语句翻译变得相对容易,它很好地描述了语句、表达式之间的联系。不过,由于Neo Pascal并不会显式构造抽象语法树,所以不得不借助于其他数据结构实现。根据先前的经验,栈结构就是不二之选。

DAG(有向无环图)

后缀表达式:也称为逆波兰表达式,这种形式简单明晰,便于存储。在处理表达式翻译时,后缀表达式有着其他形式无法比拟的优势。不过,由于后缀表达式的应用领域比较单一,所以很少独立作为一个实际编译器的IR存在。

1. 后缀表达式

编辑

不包含括号,运算符放在两个运算对象的后面,所有的计算按运算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则,如:(2 + 1) * 3 , 即2 1 + 3 *

作者::  ★(attilax)>>>   绰号:老哇的爪子 ( 全名::Attilax Akbar Al Rapanui 阿提拉克斯 阿克巴 阿尔 拉帕努伊 ) 汉字名:艾龙,  EMAIL:[email protected]

转载请注明来源: http://www.cnblogs.com/attilax/

1.1. 前缀记法、中缀记法和后缀记法

它们都是对表达式的记法,因此也被称为前缀记法、中缀记法和后缀记法。它们之间的区别在于运算符相对与操作数的位置不同:前缀表达式的运算符位于与其相关的操作数之前;中缀和后缀同理。

举例:
(3 + 4) × 5 - 6 就是中缀表达式
- × + 3 4 5 6 前缀表达式
3 4 + 5 × 6 - 后缀表达式

中缀表达式(中缀记法)
中缀表达式是一种通用的算术或逻辑公式表示方法,操作符以中缀形式处于操作数的中间。中缀表达式是人们常用的算术表示方法。
虽然人的大脑很容易理解与分析中缀表达式,但对计算机来说中缀表达式却是很复杂的,因此计算表达式的值时,通常需要先将中缀表达式转换为前缀或后缀表达式,然后再进行求值。对计算机来说,计算前缀或后缀表达式的值非常简单。

三地址代码:也称为"四元组",即操作符和三个操作数地址。这是一种最为常见的IR。甚至有些书籍认为IR就是中间代码(即三地址代码

所谓的三地址,指的就是每一行代码通常包含三个地址信息,即操作数1、操作数2、结果操作数。例如,(ADD  A,1,C )这行三地址代码的含义就是A+1→C。这种形式初看与汇编语言有点类似

当然,三地址代码也不是完美的,由于它是相对离散的,在分析源程序结构方面,它就不及语法树便捷

三地址代码的理由如下:三地址代码是一种线性IR。由于输入源程序及输出目标程序都是线性的,因此,线性IR有着其他形式无法比拟的优势。另外,相对于其他表示形式而言,程序员对于线性表示形式通常会有一种莫名的亲切感,编译器设计者当然也不例外。早期编译器设计者往往都是汇编语言程序设计的高手,可以非常自然、流畅地阅读线性的三地址代码形式。同时,线性表示形式也会降低输入输出的实现难度。随着编译器"端"、"遍"等概念的出现,IR已经不仅仅是一种存储在内存中的数据结构。有时它也需要以文件形式转存输出,作为接口供其他系统读取使用。

为什么将其设计为"三地址"的形式呢?实际上,这是计算机科学家经过多年实践探索后才得到共识的。三地址代码并不是唯一的线性IR,只能说是最为常见的而已。在编译技术领域,二地址代码、单地址代码(即栈式机代码)都曾出现过,也曾在某些应用领域盛行一时,尤其是单地址代码。

然而,单地址代码的情况则截然不同了,在现代编译器设计中,单地址代码也是应用比较广泛的一种IR。尤其是近年随着混合语言的日渐壮大,单地址代码也重新进入了人们的视野。由于执行单地址代码程序的栈式机架构相对比较简单,可以非常方便地构造相关的解释器或虚拟机,所以单地址代码深受混合语言设计者的欢迎。读者熟悉的Java字节码、.NET的IL都是单地址代码

三地址代码是在二地址代码的基础上发展而来的。二地址代码的不足之处在于它通常会给其中一个源操作分量带来一定副作用。当然,这种设计的灵感最初是来源于x86指令系统的,但是却忘了一个重要的区别:x86指令中往往都是以寄存器作为暂存空间的。而暂存空间对于二地址代码却是一个棘手的问题。为了解决二地址代码的不足,人们提出了一个对源操作分量不产生任何副作用的形式,那就是三地址代码。也就是说,在一行三地址代码中,任何运算都不会改变两个源操作分量。这是三地址代码与二地址代码的主要区别。这个特性是非常重要的,它将使得编译器更自由地复用名字与值,不必考虑代码带来的副作用。

最后,再来谈谈IR的级别,即IR依赖于目标机的程度。按级别分类,可将IR分成三类:高级形式(HIR)、中级形式(MIR)、低级形式(LIR),也可称为高级中间语言、中级中间语言、低级中间语言。

高级形式(HIR)是一种尽可能保持了源语言程序结构的IR,这种形式能较好地保留源程序的原始语义信息。由于高级形式太接近源语言程序结构,所以很少有编译器将其独立作为IR传递给后端。

中级形式(MIR)既要以一种与语言无关的方式在一定程度上反映源语言的特性,又要能够适应多种体系结构的IR。中级形式是一种比较常用的IR,它兼顾了源语言、目标机的特性,又能适用于大多数优化算法。当一个编译器仅设计一种IR时,中级形式是较理想的选择。

低级形式(LIR)就是在一定程度上包含某些目标机特性的IR,比目标语言稍高级,常作为一些机器相关的优化算法的输入。不过,实际上,除了一些较大型的编译器需要使用低级形式之外,低级形式并不是很常见。因为更多编译器设计者更愿意直接基于目标语言作优化。

表5-6  if语句的翻译方案


if语句


翻 译 方 案


if <表达式> then

<语句1>

else

<语句2>


<表达式翻译>

(JNT                   , <表达式结果> , null , __L1 )

<语句1>

(JMP                   , __L2 , null , null )

(LABEL              , __L1 , null , null )

<语句2>

(LABEL              , __L2 , null , null )

如果省略了else部分,那么只需将翻译方案中第4~6行语句省略,并将第7行的"__L2"替换为"__L1"即可。semantic068、semantic069、semantic070主要的功能就是根据翻译方案翻译输入的if语句。也就是说,试图依靠这三个语义子程序,完成翻译方案中黑体语句的生成。在上述翻译方案中,可以暂且将"__L1"称为"假分支标号",而将"__L2"称为"出口标号"。另外,需注意一点,当输入语句是if-then结构时,第7行语句的标号不应该取出口标号,而应该取假分支标号,因为此时并不存在真正意义的假分支,因此,可以将假分支标号当作出口标号使用。

while语句的翻译方案


while语句


翻译方案


while <表达式> do

<语句>


(LABEL ,__L1,null,null)

<表达式翻译>

(JNT               ,<表达式结果>,null,__L0)

<语句>

(JMP               ,__L1,null,null)

(LABEL ,__L0,null,null)

5.1.2 IR设计及其级别 - 51CTO.COM.html

时间: 2024-10-17 19:38:47

Atitti. 语法树AST、后缀表达式、DAG、三地址代码的相关文章

Clang之语法抽象语法树AST

语法分析器的任务是确定某个单词流是否能够与源语言的语法适配,即设定一个称之为上下文无关语言(context-free language)的语言集合,语法分析器建立一颗与(词法分析出的)输入单词流对应的正确语法树.语法分析树的建立过程主要有两种方法:自顶向下语法分析法和自底向上分析法.AST作为语法分析树(parse tree)的一种简写方式,它独立于具体编程语言(C++.Java.C等),而且与语法分析树的建立过程无关(自顶向下和自底向上逻辑等价),是联系编译器前端.后端的重要接口.Clang的

Atitti.java exp ast java表达式语法ast构造器

/atiplat_cms/src/com/attilax/lang/AstParser.java 原理 分割tokens_slice_li 分析splitor,, 主要是dot 和end 作者::  ★(attilax)>>>   绰号:老哇的爪子 ( 全名::Attilax Akbar Al Rapanui 阿提拉克斯 阿克巴 阿尔 拉帕努伊 ) 汉字名:艾龙,  EMAIL:[email protected] 转载请注明来源: http://www.cnblogs.com/attil

AST抽象语法树 Javascript版

在javascript世界中,你可以认为抽象语法树(AST)是最底层. 再往下,就是关于转换和编译的"黑魔法"领域了. 现在,我们拆解一个简单的add函数 function add(a, b) { return a + b } 首先,我们拿到的这个语法块,是一个FunctionDeclaration(函数定义)对象. 用力拆开,它成了三块: 一个id,就是它的名字,即add 两个params,就是它的参数,即[a, b] 一块body,也就是大括号内的一堆东西 add没办法继续拆下去了

五分钟了解抽象语法树(AST)babel是如何转换的?

抽象语法树 什么是抽象语法树? It is a hierarchical program representation that presents source code structure according to the grammar of a programming language, each AST node corresponds to an item of a source code. 抽象语法树是源代码语法结构的一种抽象表示.它以树状的形式表现编程语言的语法结构,树上的每个节点

复杂网络,抽象语法树

近期看了一些软件抽象为复杂网络,以及软件抽象成静态语法树的文章.做一个小总结. 1.复杂网络是由大量的边和点组成的,边点都可以有类型,加权值,边还可以有方向.如何计算边和点的权值是一个关键点,如何在不执行代码的情况下确定边的方向,目前不确定是否已经解决. 有许多工具,可以直接扫描软件源代码,抽象为复杂网络.然而我还没亲身实践,且做个记录. Dependency Finder分析编译后的java代码,能够提取依赖图. Doxygen是使用c++开发的基于源代码注释的文档生成工具.但是这个注释,是人

栈的应用之中缀表达式转后缀表达式

1,中缀表达式的定义及为什么要将中缀表达式转换为后缀表达式? 中缀表达式(中缀记法) 中缀表达式是一种通用的算术或逻辑公式表示方法,操作符以中缀形式处于操作数的中间.中缀表达式是人们常用的算术表示方法. 虽然人的大脑很容易理解与分析中缀表达式,但对计算机来说中缀表达式却是很复杂的,因此计算表达式的值时,通常需要先将中缀表达式转换为前缀或后缀表达式,然后再进行求值.对计算机来说,计算前缀或后缀表达式的值要比中缀表达式简单. 比如,计算机计算后缀表达式的过程如下----后缀表达式的计算机求值: 从左

Python与数据结构[1] -&gt; 栈/Stack[1] -&gt; 中缀表达式与后缀表达式的转换和计算

中缀表达式与后缀表达式的转换和计算 目录 中缀表达式转换为后缀表达式 后缀表达式的计算 1 中缀表达式转换为后缀表达式 中缀表达式转换为后缀表达式的实现方式为: 依次获取中缀表达式的元素, 若元素为操作数(数字/字母等),则加入后缀表达式中 若元素为操作符,则压入栈中,此时对比入栈操作符与栈内元素的计算等级,等级大于或等于入栈元素的栈内操作符都将被弹出栈,加入到后缀表达式中 左括号直接入栈,优先级最高,不弹出栈内元素 右括号不入栈,而是弹出所有元素加入后缀表达式,直至遇见匹配的左括号,并弹出左括

使用PHP-Parser生成AST抽象语法树

0.前言 最近项目的流程逐渐清晰,但是很多关键性的技术没有掌握,也只能一步一步摸索. 由于要做基于数据流分析的静态代码分析,所以前端的工作如:词法分析.语法分析必不可少.Yacc和Lex什么的就不再考虑了,查了一天的资料,发现两款比较适合,一款是Java下的ANTLR,另一款是专门做PHP AST生成的PHP-Parser. ANTLR是编译原理领域比较著名的工具了,相对于Yacc和Lex,更加实用.但是对PHP的语法文件只有一个,折腾了半天才生成调通,发现不太适合,对于"$a=1"生

Babel(抽象语法树,又称AST)

文章:https://juejin.im/post/5a9315e46fb9a0633a711f25 https://github.com/jamiebuilds/babel-handbook/blob/master/translations/zh-Hans/plugin-handbook.md 你了解过Babel吗? 了解过抽象语法树,又称AST,有学习过,也写过一个基于AST的乞丐版模板引擎,先是词法解析token,然后生产抽象语法树,然后更改抽象语法树,当然这是插件做的事情,最后根据新的A