你也可以通过我的独立博客 —— www.huliujia.com 获取本篇文章
编译器简介
编程语言是人和计算机交流的媒介,但是计算机只能理解二进制语言,编译器的工作就是把人可以理解的编程语言翻译成机器可以理解的二进制语言,即可执行文件。
编译过程可以细分为7个阶段
- 词法分析
- 语法分析
- 语义分析
- 中间代码生成
- 机器无关的代码优化
- 代码生成
- 机器相关的代码优化
每个阶段都以上一个阶段的输出为输入,其中词法分析的输入是源代码,第7阶段的输出为最终的可执行文件。编译器使用符号表来存储和程序相关的信息,比如变量、函数等。符号表贯穿了编译器的所有阶段,每个阶段都会用到。实际开发时,通常会把多个阶段整合为一个阶段,并不会严格按照7个阶段来开发。
一个简单的集合运算语言
大部分教程都是使用计算器作为演示的例子,笔者学习的时候也是以计算器为样例的,由于计算器只涉及到数字,虽然处理起来非常简单,但是能够展示的特性太单一。所以本文设计了另一种简单但是展示面更广的集合运算语言。
就把这个语言叫做AlphaGun吧。AlphaGun中只有集合这一种变量类型,并且变量名只能是大写的英文字母,集合由小写的英文字母组成,集合内的元素不能有重复。所以最多支持26个变量名,每个集合最多26个元素。AlphaGun支持集合的并(∪)、交(∩)、求差(-)三种操作。其中"∪"、“∩"优先级相同,两者并列时使用左结合规则,两者优先级都大于”-"。AlphaGun以换行符作为语句的分隔符,每行最多一个句子。下面举个栗子:
// 使用”//“作为注释的标志
A = [a, b, c] //初始化A集合
B = [c,e,z] //初始化B集合
PRINT A //PRINT是关键字,打印集合,一次最多打印一个集合
PRINT B
C = A ∪ B
PRINT C
D = A ∩ C
PRINT D
E = A ∪ B ∩ C ∪ D
PRINT E
词法分析
词法分析是编译器的第一阶段,词法分析器把输入的字符流(源代码)转换为token流,比如 sum=num+10;就可以被划分为5个词素:“sum”、"="、“num”、"+"、“10”、";"。 每个词素对应一个token。
原始的词法分析器是开发者根据词法规则从零开始编写的,这种方式开发速度慢、迭代成本和维护成本都比较高。Flex是一个开源的词法分析器生成器,开发者只需要写好词法规则,Flex就可以自动生成词法分析器,把开发者从繁琐的编码中解放出来,实现快速开发、低成本迭代和维护。
本章主要介绍Flex的使用。
Flex的语法
下面是为AlphaGun编写的Flex规则
%option noyywrap
%{
#include <stdio.h>
%}
%%
PRINT { printf("PRINT, '%s'\n", yytext); }
[A-Z] { printf("IDENTIFIER, '%s'\n", yytext); }
[a-z] { printf("STRING, '%s'\n", yytext); }
"," { printf("COMMA, '%s'\n", yytext); }
"[" { printf("LEFT_BRACKET, '%s'\n", yytext); }
"]" { printf("RIGHT_BRACKET, '%s'\n", yytext); }
"=" { printf("ASSIGN, '%s&#