当前课程知识点:Compilers Techniques > 8 Design and Implementation of a Simple Compiler > 8.2 Basic > 8.2.1 Scanner
返回《Compilers Techniques》慕课在线视频课程列表
返回《Compilers Techniques》慕课在线视频列表
各位同学大家好
我们在学习完编译器
基本的知识之后
我们是不是可以自己来编写一个编译器呢?
从这节课开始
我们就来学习一下
基于Python的简易编译器实现
我们可以从头到尾
来学习一下
如何自己来编写一个编译器
我们先来看一下这张图
这是我们所设计的
简易编译器的架构
我们看到
编辑器通常前端分为三个部分
包括Scanner、Parser和语义分析的部分
那么针对Scanner
主要是扫描源程序
获取记号列表
Scanner会根据类型的定义
及其正规表达式
将我们输入的源代码
分割成记号的列表
也就是token list
第二个部分是Parser
它会根据上下文无关文法
将我们词法分析器
获取的结果token list
变成一棵语法分析树
第三个部分是语义分析的部分
在这个部分
我们会根据不同的产生式
指定不同的属性文法
从而实现上下文有关的分析
进而产生中间的表示IR
最后一部分是代码生成
在代码生成之后
我们会得到汇编语言的输出
首先我们来看一下Scanner
Scanner的作用是什么呢?
Scanner的作用就是
我们需要将输入的源程序
变成token list
以便后继供句法分析器
进一步进行分析使用
那么编译器在处理源程序的时候
划分token的依据是什么呢?
划分的依据就是类型的定义
也就是我们希望编译生成的语言
对应的类型定义
那么
我们为什么需要将类型定义
从Scanner当中分离出来呢?
这是因为针对不同的应用
我们需要设计不同的类型定义
以满足我们所需要编写的编译器
比如说我们来看这两个例子
针对计算器
如果我们想编写一个编译器
那么对应的类型定义
可能需要包括左括号、右括号、
数字、加减乘除、赋值语句、
符号串等等这样的类型定义
而大家观察右边
我们看到
如果我们想要针对SQL来编写
一个对应的编译器
那么这个SQL对应的类型定义
就和之前的计算器类型定义
是完全不一样的
比如说
里边的关键字就会包括 select、from、
where这样的关键字
那么在SQL类型定义当中
还会包括and、逗号、句号、星号、
等号、小于号、大于号等等
这也就是说明
我们需要针对不同的应用
来设计不同的类型定义
所以我们需要将类型定义
从Scanner当中分离出来
在类型定义的部分
我们需要设计好每一种类型定义的格式
也就是我们需要给出
每一种类型对应的正式名称、
匹配规则、以及显示的名称
比如说
针对用户自己定义的变量
我们给出正式的名称Identifier
然后给出对应的匹配规则
在这里我们使用正规式
去表示对应的匹配规则
最后
我们给出它的显示名字是id
类型定义放在typeDef.py这个文件当中
去进行一个实现
在这个文件当中
包含着一个类
TypeDefinition
这个类用来实现对应的类型定义
我们看到其中包含一个load这样的一个方法
这个方法通过读取文件
来逐行读取源程序
然后来添加定义
在添加定义的时候
我们保存了对应的映像
这样可以减少后期步骤当中
对内存的占用
此外
作为词法分析器的Scanner
为了实现上的方便
我们调用了Python的re库来实现
在scanner.py这个文件当中
我们实现了扫描源程序这样的功能
我们看到在读取类型定义之后
可以利用正则表达式
来进行匹配
可以利用re的函数
迭代去匹配对应的类型
这里我们给出一个例子
这是Scanner运行一次的输出
那么在输出当中
我们可以看到
源程序当中
每一个符号都被识别出来
这一讲就到这里
谢谢大家
-1.1 Overview of Compilers Techniques
--Chapter 1 Overview of Compilers Techniques
--Overview of Compilers Techniques
-2.1 Lexical Tokens, Strings and Language
--2.1 Lexical Tokens, Strings and Language
--2.1 Lexical Tokens, Strings and Language
-2.2 Regular form
--2.2 Regular form
-2.3 Finite automata
--2.3 Finite automata
-2.4 DFA construction, Subset construction, Simpleset DFA
--2.4 DFA construction, Subset construction, Simpleset DFA
-2.5 Lex
--2.5 Lex
-3.1 Context-free Grammars
--3.1.1 The Role of the Parser
--3.1.2 The Formal Definition of a Context-free Grammar
-3.2 Writing a Grammar
--3.2.1 Elimination of Left Recursion
--3.2 Top-Down Parsing
-3.3 Languages and Grammars
--3.3 Language and Grammars
-3.4 Top-Down Parsing
--3.4.3 Recursive Descent Analysis
--3.4.4 Nonrecursive Descent Analysis
-3.5 Bottom-up Parsing
--Bottom-up Parsing
-3.6 LR Parsing
--3.6.6 Characteristics of LR Parsing
--3.6.7 Non Ambiguous and Not LR Context-Free Grammars
-4.1 Syntax-Directed Definitions
--4.1.2 Attribute Dependency Graphs and Ordering the Evaluation of Attributes
--Syntax-Directed Definitions
-4.2 Bottom-Up Calculation of S Attribute
--4.2.1 Bottom-Up Calculation of S-Attributed
-4.3 L-Attributed Definitions
--4.3.1 L-Attributed Definitions
--4.3.3 Design of Predictive Translator
--L-Attributed Definitions
-4.4 Bottom-Up Parsing of L-Attributed Translation
--4.4.1 Bottom-Up Parsing of L-Attributed Translation
--4.4.2 Simulate the Parsing of Inherited Properties
--Bottom-Up Parsing of L-Attributed Translation
-5.1 Overview
--Overview
-5.2 Global Stack Storage
-5.3 Calling Sequences
-5.4 Non Local Names
--5.4 Non Local Names and dynamic scope
--Non Local Name
-6.1 Overview of Intermediate Code Generation
--6.1 Overview of Intermediate Code Generation
-6.2 Declaration Statements
-7.1 Issues in the Design of Code Generator
--7.1 Issues in the Design of Code Generator
-7.2 Target Machine
--Target Machine
-7.3 Basic Blocks and Flow Graphs
--7.3 Basic Blocks and Flow Graphs
-7.4 A Simple Code Generator
-8.1 Demonstration of Compiler Framework based on Python
--8.1 Demonstration of Compiler Framework based on Python
-8.2 Basic
--8.2.4 SA
-8.3 SimpleJava