使用 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);

中,printfscore 都是和词法单元 id 的模式匹配的词素,而 'Total = %d\n' 则是一个和 literal 匹配的词素。

在很多程序设计语言中,下面的类别覆盖了大部分或所有的词法单元:

  1. 关键字。一个关键字的类型就是该关键字本身。
  2. 运算符。它可以表示单个运算符,也可以像表 1-1 中的 comparison 那样,表示一类运算符。
  3. 标识符。一个表示所有标识符的词法单元。
  4. 常量。一个或多个表示常量的词法单元,比如数字和字面值字符串。
  5. 界符。每一个标点符号有一个词法单元,比如左右括号、逗号和分号。

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;
}

编译和运行

  1. 使用 Flex 编译规则文件:flex lexer.l
  2. 编译生成的 C 代码:gcc lex.yy.c -o lexer
  3. 运行程序:./lexer test.c

其中 test.c 是您的 C-- 代码文件。

注意

  • 上述示例仅为简单的词法分析器,您可能需要根据 C-- 语言的具体语法规则添加更多规则和动作。
  • Flex 提供了丰富的功能,可以帮助您编写更复杂的词法分析器。
  • 在编写 Flex 规则文件时,请参考 Flex 的文档以了解更详细的语法和使用说明。
C-- 语言词法分析器:使用 GNU Flex 实现词法分析

原文地址: https://www.cveoy.top/t/topic/zHT 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录