C-- 语言词法分析器:使用 GNU Flex 实现词法分析
使用 GNU Flex 实现 C-- 语言词法分析器
本文将介绍如何使用词法分析工具 GNU Flex 编写一个词法分析器,用于对 C-- 语言源代码进行词法分析,并提供测试程序和输出格式规范。
1.3.1 实验要求
你的程序需要能够查出源代码中可能包含的词法错误:
- 词法错误(错误类型 A): 即出现 C-- 词法中未定义的字符以及任何不符合 C-- 词法单元定义的字符。
1.3.2 输入格式
程序的输入是一个包含 C-- 源代码的文本文件,程序需要能够接收一个输入文件名作为参数。例如,假设你的程序名为 cc,输入文件名为 test1,程序和输入文件都位于当前目录下,那么在 Linux 命令行下运行 ./cc test1 即可获得以 test1 作为输入文件的输出结果。
1.3.3 输出格式
实验一要求通过标准输出打印程序的运行结果。对于那些包含词法错误的输入文件,只需要输出相关的词法有误的信息即可。在这种情况下,注意不要输出任何与语法树有关的内容。
要求输出的信息包括错误类型、出错的行号以及说明文字,其格式为:
Error type [错误类型] at Line [行号]: [说明文字].
说明文字的内容没有具体要求,但是错误类型和出错的行号一定要正确,因为这是判断输出的错误提示信息是否正确的唯一标准。请严格遵守实验要求中给定的错误分类(即词法错误为错误类型 A),否则将影响你的实验评分。注意,输入文件中可能会包含一个或者多个词法错误(但输入文件的同一行中保证不出现多个错误),你的程序需要将这些错误全部报告出来,每一条错误提示信息在输出中单独占一行。
对于那些没有任何词法错误的输入文件,你的程序需要打印每一个词法单元的名称以及与其对应的词素,无需打印行号。词法单元名与相应词素之间以一个冒号和一个空格隔开。每一条词法单元的信息单独占一行。
表 1-1 词法单元的例子
| 词法单元 | 非正式描述 | 词素示例 |
|---|---|---| |
| if | 字符 i, f | if |
| else | 字符 e, l, s, e | else |
| comparison | < 或 > 或 <= 或 >= 或 == 或 != | <=, != |
| id | 字母开头的字母 / 数字串 | Pi, score, D2 |
| number | 任何数字常量 | 3.14159, 0, 6.02e23 |
| literal | 在两个'之间,除'以外的任何字符 | 'core dumped' |
表 1-1 给出了一些常见的词法单元、非正式描述的词法单元的模式,并给出了一些示例词素(以下若无特殊说明,词素就是最小词法单位)。下面说明上述概念在实际中是如何应用的。在 C 语句
printf('Total = %d\n',score);
中,printf 和 score 都是和词法单元 id 的模式匹配的词素,而 'Total = %d\n' 则是一个和 literal 匹配的词素。
在很多程序设计语言中,下面的类别覆盖了大部分或所有的词法单元:
- 关键字。一个关键字的类型就是该关键字本身。
- 运算符。它可以表示单个运算符,也可以像表 1-1 中的
comparison那样,表示一类运算符。 - 标识符。一个表示所有标识符的词法单元。
- 常量。一个或多个表示常量的词法单元,比如数字和字面值字符串。
- 界符。每一个标点符号有一个词法单元,比如左右括号、逗号和分号。
1.3.6 样例
此部分样例是以任务 1 为例给出的,请仔细阅读样例,以加深对实验要求以及输出格式要求的理解。
说明: 选择任务 2 的同学,可以参考任务 1 的样例,自行设计测试样例,以反映出正确输出。
样例 1:
输入(行号是为标识需要,并非样例输入的一部分,后同):
1 int main()
2 {
3 int i = 1;
4 int j = ~i;
5 }
输出:
这个程序存在词法错误。第 4 行中的字符“~”没有在我们的 C-- 词法中被定义过,因此你的程序可以输出如下的错误提示信息:
Error type A at Line 4: Mysterious character '~'.
样例 2:
输入:
1 int inc()
2 {
3 int i;
4 i =100;
5 }
输出:
这个程序非常简单,也没有任何词法错误,因此你的程序需要输出每一个词法单元信息:
TYPE: int
ID: inc
LP: (
RP: )
LC: {
TYPE: int
ID: i
SEMI: ;
ID: i
RELOP: =
INT: 100
SEMI: ;
RC: }
编写 Flex 规则文件
以下是一个示例 Flex 规则文件,用于识别 C-- 语言中的关键字、标识符、数字、字面值和一些常见运算符。
%{
#include <stdio.h>
#include <stdlib.h>
%}
%%
"if" { printf("IF\n"); }
"else" { printf("ELSE\n"); }
"comparison" { printf("COMPARISON\n"); }
"id" { printf("ID\n"); }
"number" { printf("NUMBER\n"); }
"literal" { printf("LITERAL\n"); }
.|
{ printf("ERROR\n"); }
%%
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: ./lexer <input_file>\n");
return 1;
}
FILE *file = fopen(argv[1], "r");
if (!file) {
printf("Unable to open file\n");
return 1;
}
yyin = file;
yylex();
fclose(file);
return 0;
}
编译和运行
- 使用 Flex 编译规则文件:
flex lexer.l - 编译生成的 C 代码:
gcc lex.yy.c -o lexer - 运行程序:
./lexer test.c
其中 test.c 是您的 C-- 代码文件。
注意
- 上述示例仅为简单的词法分析器,您可能需要根据 C-- 语言的具体语法规则添加更多规则和动作。
- Flex 提供了丰富的功能,可以帮助您编写更复杂的词法分析器。
- 在编写 Flex 规则文件时,请参考 Flex 的文档以了解更详细的语法和使用说明。
原文地址: https://www.cveoy.top/t/topic/zHT 著作权归作者所有。请勿转载和采集!