自制编译器(二)

  从本次开始我们正式进入到编译的开发工作,我们将要开发的Cb语言编译器并不支持宏定义,因此我们将跳过预处理器的开发工作,实际上预处理器仅仅是对导入外部文件的定义和替换程序中的宏定义,实现起来相对难度较低,因为我们跳过此部分直接进入到狭义的编译器开发阶段。首先我们要实现的就是词法分析。

词法分析

  在编译器中负责词法分析的模块被称为词法分析器(lexical analyzer),又被称为扫描器(scanner)。他的主要作用就是将代码分割成单词,并在分割的同时推算出单词的种类,并为单词添加语义值。该阶段输出的是一个token序列,每个token包含一个单词及其种类、语义值。如图所示:词法分析

  手动编写词法分析器是件及其繁琐的事情,我们通过使用其他开源工具来生成词法分析器。在本书中我们主要使用javacc作为我们的词法分析器生成器。

javacc

  javacc是java的解析器生成器兼词法分析器生成器。为javacc描述好语法的规则,javacc就能够生成可以解析该语法的词法分析器和解析器的代码了。

  语法规则通常会用一个扩展名为’.jj’的文件来描述,该文件C称为语法描述文件。一般情况下,语法描述文件的内容多采用如下形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
options{
javacc的像选项
}
PARSER_BEGIN(解析器类名)
package 包名;
import 库名;

public class 解析器类名{
任意的java代码
}

PARSER_END(解析器类名)
词法分析器的描述

解析器的描述

javacc的词法分析器的描述规则与正则表达式很类似,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
options {
STATIC = false;
UNICODE_INPUT = true;
}

PARSER_BEGIN()

PARSER_END()

SPECIAL_TOKEN: {
<SPACE : (["\n", "\t", "\r", "\f", " "])+>
<LINECOMMENT : "//"(~["\n", "\r"])* ("\n" | "\r" | "\r\n")?>
}

TOKEN: {
<VOID :"void" >
<CHAR :"char" >
<SHORT : "short">
<INT : "int">
<LONG : "long">
<STRUCT : "struct">
<UNION : "union">
<ENUM : "enum">
<STATIC: "static">
<EXTERN: "extern">
<CONST: "const">
<SIGNED: "signed">
<UNSIGEND: "unsigned">
<IF: "if">
<ELSE: "else">
<SWITCH: "switch">
<CASE: "case">
<DEFAULT_: "default">
<WHILE: "while">
<DO: "do">
<FOR: "for">
<RETURN: "return">
<BREAK: "break;">
<CONTINUE: "continue">
<GOTO: "goto">
<TYPEDEF: "typedef">
<IMPRT: "import">
<SIZEOF: "sizeof">
}

TOKEN: {
<IDENTIFIER : ["a-z", "A"-"Z", "_"](["a"-"z", "A"-"Z", "-", "0"-"9"])*>
}

TOKEN: {
<INTEGER : ["1-9"](["0"-"9"]*("U")?("L")?)
|"0"["x", "X"]["0"-"9", "a"-"f", "A"-"F"]+("U")?("L")?
|"0"["0"-"7"]*("U")?("L")?
>
}

SPECIAL_TOKEN: {
<SPACE: ([" ", "\t", "\n", "\r", "\f"])+>
<LINE_COMMENT: "//"(~["\n", "\t"])* ("\n"|"\r\n"|"\r")?>
}

MORE:{ <"/*">: IN_BLOCK_COMMENT}
<IN_BLOCK_COMMENT> MORE: {~[]}
<IN_BLOCK_COMMNET> SPECIAL_TOKEN: {<BLOCK_COMMENT: "*/">: DEFAULT}

MORE: {<"\"": IN_STRING>}
<IN_STRING> MORE: {
<(~["\"", "\\", "\n", "\r"])+>
|<"\\" (["0"-"7"]){3}>
|<"\\" ~[]>
}
<IN_STRING> TOKEN: {<STRING: "\"">: DEFAULT}

MORE: {<"'">: IN_CHARACTER}
<IN_CHARACTER> MORE: {
<~["'", "\\", "\n", "\r"]>: CHARACTER_TERM
|<"\\" (["0"-"7"]){3}>: CHARACTER_TERM
|<"\\" ~[]>: CHARACTER_TERM
}
<CHARACTER_TERM> TOKEN: {<CHARACTER: "'">:DEFAULT}