sample语⾔词法分析_编译原理:DIY⼀门编程语⾔(1)--⼊
门
我相信很多⼈都好奇过我们⽤的编程语⾔是怎样⼀步步编译成机器语⾔的以及我们是否可以⾃⼰设计⼀门编程语⾔呢?编译器经常被⼤家认为是⼀个很⾼深莫测的话题,但是其实并⾮如此,编译的核⼼思想就是通过⼀步步的转换逐渐的把⾼级语⾔翻译到汇编语⾔。当然⼀个优秀的编译器还是相当复杂的,⾥⾯的各种优化过程是这么多年来⼤家⼀起积累的成果。我希望通过这系列⽂章能让更多的⼈去接触到这个领域,以及尝试⾃⼰写⼀个简单的编译器。 那么上⾯说清楚了这个系列的⽬的,简单地说⼀下对⽬标读者的两点期待:
1. 我希望读者已经掌握⼀门编程语⾔ ⽆论是Java C++ Python 或者Rust等都可以
2. ⼤致了解汇编语⾔,⽆论是什么架构的汇编都可以
那么我们就先简单地来说⼀说程序是怎么编译的吧! ⾸先呢我们通常将编译器划分为两⼤【也可分为三⼤部分 后⾯会详细说明】部分,也就是前端 和 后端。 前端⼀般负责和源语⾔相关的内容,后端则负责和⽬标语⾔或架构相关的内容。 前端⼀般分为下⾯三个部分: 词法分析,语法分析 和 语义分析。
词法分析:
jsp的基本语法词法分析是将输⼊的源程序分割成符记 (Token), 这步也经常被称为符记化。这⾥举个例⼦(这个语⾔演变与虎书[1]中的Tiger, 这篇教程将会以此为例,读者也可以⾃⾏加以改造):
main let
var name : int := 1;
in
name := name + 1;
printi(name);
end;
在这个程序⾥⾯ main, let, var, a, 冒号等等都会变成 Token,这些 Token 是组成语⾔的最⼩单位。可能最初的时候 Token 的概念有点模糊,因为它既可以是固定的字串符(例如语⾔的保留关键字 (keyword) )也可以是满⾜特定要求的字串符(例如标识符(Identifier))。 在上⾯的例⼦中, let, var, in 等则是语⾔的保留关键字,⽽ name 则是⼀个标识符。
语法分析:
通过词法分析我们已经将原有的输⼊转换成了⼀串符记,接下来的任务就是将这些符记按照我们所定义的语法转换成“句⼦”。 有了这些句⼦我们才能去理解这个程序所要表达的含义。依然以上⾯的那⼀⼩段程序为例,经过词法分析后我们应该可以得到类似如下的内容
程序设计语言仅仅使用顺序选择和重复<KeywordMain> <KeywordLet>
<KeywordVar> <Identifier> <Colon> <IntType> <OpAssign> <Number> <Semicolon>
<KeywordIn>
<Identifier> <OpAssign> <Identifier> <OpPlus> <Number> <Semicolon>
<Identifier> <LParn> <Identifier> <RParn> <Semicolon>
<KeywordEnd> <Semicolon>
颜表达的意思可能这⾥有些⼈会好奇,我们经过词法分析达到了什么⽬的呢? 好像这输出和输⼊的源⽂件很相像啊。 ⾸先虽然这看起来很像,但是这是对于源代码的⼀个抽象, ⽤户的变量名啊,类型啊等等都抽象成了 类似于 Identifier 这样的符记(Token)。通过这些固定的符记就可以按照语法组成句⼦了。 那么语法到底长什么样⼦呢?
<tigerProgram> = <KeywordMain> <KeywordLet> <declSegment> <KeywordIn> <stmtList> <KeywordEnd> <Semicolon>
<declSegment> = <varDeclList> <varDeclList> = <NULL> | <varDecl> <varDeclList>
<varDecl> = <KeywordVar> <idList> [<OpAssign> <const>] <Semicolon>
<idList> = <Identifier> | <Identifier> <Comma> <idList>
上⾯简单的写了⼀点点语法, 并不完整。 这个格式叫做BNF (Backus–Naur Form)。 在上⾯这个例⼦中所有 Non-Terminal[2] 都已⼩写驼峰命名, ⼤写驼峰则是 Terminal 也可说是符记。 ⽐如 其中第三⾏的 <varDeclList> 的意思是 <varDeclList> 定义为 空(NULL)或者 <varDecl> 和 <varDeclList> 本⾝。 这⾥⼤家会发现语法定义是可以递归的。 通过允许递归则可以实现⼀个或多个规则组成⼀个更⼤的规则。
原理今天先讲到这⾥, 下次我们再来⼀起了解构建AST(Abstract Syntax Tree)和语义分析。现在我们切换⼀下思维, 来了解⼀下我们这个教程⾥⾯将会实现的语⾔。
我们将实现⼀个⾮常简单地Tiger语⾔的变种。这个语⾔有两种默认类型 int 和 float (⽀持数组), 可以进⾏ + - * / % 五种运算, 可以创建以及调⽤函数, 每个函数可以返回0或1个返回值。所有⾮数组变量传递值, 数组类变量传递指针。【但没有指针类型】
系统内置 printi 和 printf 两个函数 分别可以打印⼀个int 和 float。
下⾯给⼀⼩段tiger 程序
main let
type myInt = int;
var a, b : int;
var c : myInt;
python入门教程 非常详细 pdfin begin
kinds翻译a := a + b;
let func magic() begin
a := a + 1;
end;
magic();
printi(a);
end;
教程中将会使⽤ C++ 作为实现语⾔,读者不⼀定需要使⽤C++, ⽤Java, Rust 乃⾄ Python 都可以。 使⽤⼀门⾃⼰熟悉的语⾔,会让这个学习的过程变得容易⼀些。
希望⼤家都能跟着这个教程接下来⼀起做出⼀门⾃⼰的编程语⾔。
Part 2:
Codetector:编译原理:⾃⼰DIY⼀门编程语⾔ (2) - 语义分析和 Antlr希望⼤家都能跟着这个教程接下来⼀起做出⼀门⾃⼰的编程语⾔。
Codetector:编译原理:⾃⼰DIY⼀门编程语⾔ (2) - 语义分析和 Antlr z huanlan.zhihu
qt下载网站写⽂不易,如果喜欢就给个赞吧~
参考
1. ^Modern Compiler Implementation in Java www.cs.princeton.edu/~appel/modern/java/
2. ^Non-Terminal定义为可以继续展开为其他规则的规则
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论