编译技术:词法分析

编译技术:词法分析

BaconToast Lv3

词法分析设计

编码前的设计

需求分析

读取 testfile.txt 中的代码,分析其词法成分并将结果输出至 lexer.txt。如果存在错误则将错误信息输出至 error.txt

单词的类别码定义见下表。

词法分析单词类别码

单词名称 类别码 单词名称 类别码 单词名称 类别码 单词名称 类别码
Ident IDENFR else ELSETK * MULT ; SEMICN
IntConst INTCON ! NOT / DIV , COMMA
StringConst STRCON && AND % MOD ( LPARENT
const CONSTTK || OR < LSS ) RPARENT
int INTTK for FORTK <= LEQ [ LBRACK
static STATICTK return RETURNTK > GRE ] RBRACK
break BREAKTK void VOIDTK >= GEQ { LBRACE
continue CONTINUETK + PLUS == EQL } RBRACE
if IFTK - MINU != NEQ = ASSIGN
main MAINTK printf PRINTFTK

错误类型定义见下表。

词法分析错误类型

错误类型 类别码 解释
非法符号 a 出现了 &| 两个符号,应该当作 &&|| 处理

文件组织

新建类 src\utils\IOHandler.java,该类实现文件定向以及输出。

新建类 src\frontend\Frontend.java,该类是前端的“主函数”。

新建目录 src\frontend\lexer,该部分完成所有的词法分析部分,其中包含三个类:

  • TokenType:枚举类,列举所有的单词类别码。
  • Token:定义一个单词对象,存储类别、字面量、行号信息。
  • Lexer:该模块“主函数”,输入字符流并解析单词。

新建目录 src\error,该部分复制错误处理,其中包含三个类:

  • ErrorType:枚举类,列举所有错误码。
  • Error:定义一个错误对象,存储错误类型、行号。
  • ErrorCatcher:负责捕获异常,内含一个 ArrayList 存储错误。

编码完成之后的修改

Lexer 类

该部分定义了多个“lexer”方法:整体思路是根据当前字符 currentChar 信息,分析固定单词组分,返回 Token 对象。其中存在特殊处理,例如对于注释的解析方法 lexerAnnotation

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
/**  
* lexer annotation and operator division * @return TokenType DIV
*/
private Token lexerAnnotation() {
StringBuilder sb = new StringBuilder();
sb.append(this.currentChar);
this.read();

if (this.currentChar == '/') {
// ...
} else if (this.currentChar == '*') {
// ...
} else {
return new Token(TokenType.DIV, sb.toString(), this.lineNumber);
}
}
```

对于除法符号 `/` 的解析在此处完成。

此外,处理运算符时,将运算符分为三类:单运算符(如 `+`)、含等于号的双运算符(如 `<=`)、重复的双运算符(如 `&&`)。之所以将双运算符做区分,是因为 `<=`、`==`、`!=` 等运算符与 `<`、`=`、`!` 是前缀的关系,需要额外读取一个等号判断属于哪个。

```Java
/**
* lexer operators except division * @return TokenType NOT, PLUS, MINU, MULT, MOD,
* LSS, LEQ, GRE, GEQ, EQL, NEQ, ASSIGN, SEMICN, COMMA, * LPARENT, RPARENT, LBRACK, RBRACK, LBRACE, RBRACE */private Token lexerOperator() {
return switch (this.currentChar) {
case '+', '-', '*', '%', ';', ',', '(', ')', '[', ']', '{', '}' -> this.lexerSingleOp();
case '<', '>', '=', '!' -> this.lexerSecondEq();
case '&', '|' -> this.lexerRepeatOp();
default -> this.lexerError();
};
}

TokenType 类

除了基础单词类别码,为了便于词法分析完成还定义了两种枚举类型:TokenType.EOFTokenType.ERROR,前者是循环结束标志,后者是错误处理。

实际上这个 ERROR 并未用到,因为在读取到单个 &| 时便抛出异常,然后当作正常处理。这里的 ERROR 是便于迭代以及可维护性考量。

  • Title: 编译技术:词法分析
  • Author: BaconToast
  • Created at : 2025-11-14 22:38:29
  • Updated at : 2025-11-18 13:26:32
  • Link: https://bacontoast-pro.github.io/2025/11/14/compiler/lexer/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments
On this page
编译技术:词法分析