实验报告:词法分析器

实验报告:词法分析器

一些基本概念:

  1. lex:词法分析器的自动产生系统
    lex.exe将lex源程序转换成lex.yy.c文件(由命令flex xxx.lex执行)
    编译lex.yy.c生成可执行文件,该可执行文件即可将源语言程序切割为单词符号串
  2. lex源程序的识别规则:由正规式和相应的动作组成
    格式:在一行中以“正规式 动作”形式书写,动作用大括号括起
  3. 关于yylex()函数
    作用:调用yylex()启动或者重新开始扫描
    用户段代码:段中的所有代码都被拷贝到yylex()。以空白开始的行被假定是用户代码。"%%"后的代码直接放置在接近扫描程序的开始处,在第一条执行的语句之前。
  4. 输出的单词符号分类:
    K(关键字)I(标识符)C(常量,此处常量指整型)
    O(算符) D(界符) T(其他)
    F(浮点数)S(字符串)R(字符)
    A (整型数组)

实验思路:

  1. 设立一个结构体cell用于存储识别出的每一个单词及其属性,cell含有单词类,单词名,长度,行列数据。其实最后发现此处设置一个结构体并没有太大的用处,或者说在词法分析这一步完全不需要结构体,只有可能方便后续的操作
  2. 每次识别成功执行add_cell()函数,改函数根据传入参数(一个int类型的值)的不同为单词分类并确定该单词的行列数据,同时打印出相关的数据到“result.txt”

关于识别规则:

  1. 错误字符(即T类字符)的判定:
    ①含有非法字符的标识符,非法字符指 “?!$&#@`” 这些字符
    ②以数字开头的标识符
    ③含有一个以上浮点符号的浮点数
  2. 整型的判定:
    为方便表示,只保有interger和longint两个关键字,均为以 “+” 或 “-” 开头的0-9数字组成,或者是没有表示正负的符号

语言扩展:

  1. 支持字符、字符串类型及相关运算
    pascal对应的声明规则为 var a:string ,冒号后接变量的类型
    添加关键字 string char ;添加识别条件识别 ‘xxx’ 和 “xxx” 样式的语句,将字符串归为 S 类,字符归为 A 类
  2. 支持for循环语句:
    添加关键字 for to downto do
  3. 支持repeat语句:
    添加关键字 repeat until
  4. 支持浮点类型及相关运算:
    为方便表示,只保有单精度和双精度两类浮点数,因此添加关键字 single double;添加识别浮点数的语句并将其归为 F 类
  5. 支持整形数组(一维):
    pascal对应的声明规则为 var a:array[1…n] of interger 即 var 数组名:array[下标1…下标2] of 元素数据类型
    因此需要添加关键字 array of 以及数值类型(前文中已经添加)
    同时添加一个新的类型 A类 表示数组
    以上述数组声明为例,词法分析器最后的结果为
    var(K) a(I) :(D) array(K) 1…n of(K) interger(K)

遇到的问题:

  1. 文件指针(FILE*)在第一部分声明,在主函数中定义(在第一部分定义会报错我也不知道为什么。。。)
  2. 结构体中保存单词名的指针char* name只是粗略地将yytext的值传入并没有为该指针分配相应的空间(如果分配空间大小应为yyleng),后续如果用到了该指针需要注意其停止输出的部分
  3. 错误字符只能识别很有限的一部分(毕竟如果写代码的人乱写代码就会有很多句式识别不出来)
  4. 由于包含关系,为避免错误识别,非法的标识符以及关键字需要在标识符之前识别;char和string类需要在最开始识别,否则可能将字符串识别成标识符或者非法标识符
  5. 在用 . 表示除换行外字符时使用圆括号(),若使用方括号[]意思是 . 不表示任何字符而表示特定字符

Summary:

词法分析器的设计其实不需要过多的考虑语法和单词的属性,只需要将不同类单词的特点用正规式准确表示并将其分类同时记录单词的名字即可。对于不同的数据类型,无论数据类型如何,变量名一定是属于关键字一类,不同的数据本身再进行数据类型的分类,这样可以大大减少分词过程中的工作量,添加关键字也是如此。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实验目的: 1.理解词法分析程序的基本原理和算法。 2.掌握Flex工具的使用方法。 3.掌握正则表达式的使用方法。 实验要求: 1.设计一个简单的词法分析程序,能够识别出以下关键字:if, else, for, while, do, break, continue, return。 2.能够识别出整数、浮点数、标识符、运算符、界符等。 3.能够对输入的代码进行词法分析并输出结果。 实验过程: 1.安装Flex工具。 2.编写词法分析器的规则。 3.编写测试程序。 4.使用Flex工具生成词法分析器。 5.编译并运行测试程序。 实验步骤: 1.安装Flex工具。 在Ubuntu系统中,可以使用以下命令安装Flex工具: ``` sudo apt-get install flex ``` 2.编写词法分析器的规则。 在本实验中,我们需要识别出以下关键字: if, else, for, while, do, break, continue, return 可以使用以下正则表达式进行匹配: ``` "if" {return IF;} "else" {return ELSE;} "for" {return FOR;} "while" {return WHILE;} "do" {return DO;} "break" {return BREAK;} "continue" {return CONTINUE;} "return" {return RETURN;} ``` 我们还需要识别出整数和浮点数。可以使用以下正则表达式进行匹配: ``` [0-9]+ {yylval.num = atoi(yytext); return INT;} [0-9]+"."[0-9]+ {yylval.fnum = atof(yytext); return FLOAT;} ``` 其中,yylval是Flex工具自带的一个全局变量,用于存储识别出的标识符、整数或浮点数的值。 我们还需要识别出运算符和界符。可以使用以下正则表达式进行匹配: ``` "+" {return ADD;} "-" {return SUB;} "*" {return MUL;} "/" {return DIV;} "%" {return MOD;} "=" {return ASSIGN;} ">" {return GT;} ">=" {return GE;} "<" {return LT;} "<=" {return LE;} "!=" {return NE;} "==" {return EQ;} ";" {return SEMICOLON;} "," {return COMMA;} "(" {return LPAREN;} ")" {return RPAREN;} "{" {return LBRACE;} "}" {return RBRACE;} ``` 最后,我们需要识别出标识符。可以使用以下正则表达式进行匹配: ``` [a-zA-Z][a-zA-Z0-9]* {yylval.id = strdup(yytext); return IDENTIFIER;} ``` 3.编写测试程序。 在本实验中,我们编写一个简单的测试程序,用于测试词法分析器是否正确。 ```c %{ #include "lex.yy.h" %} %option noyywrap %{ int yylex(); void yyerror(char *); %} %union { int num; float fnum; char *id; } %token IF ELSE FOR WHILE DO BREAK CONTINUE RETURN %token INT FLOAT %token ADD SUB MUL DIV MOD %token ASSIGN GT GE LT LE NE EQ %token SEMICOLON COMMA %token LPAREN RPAREN LBRACE RBRACE %token IDENTIFIER %% {if} {printf("IF\n");} {else} {printf("ELSE\n");} {for} {printf("FOR\n");} {while} {printf("WHILE\n");} {do} {printf("DO\n");} {break} {printf("BREAK\n");} {continue} {printf("CONTINUE\n");} {return} {printf("RETURN\n");} [0-9]+ {yylval.num = atoi(yytext); printf("INT %d\n", yylval.num);} [0-9]+"."[0-9]+ {yylval.fnum = atof(yytext); printf("FLOAT %f\n", yylval.fnum);} "+" {printf("ADD\n");} "-" {printf("SUB\n");} "*" {printf("MUL\n");} "/" {printf("DIV\n");} "%" {printf("MOD\n");} "=" {printf("ASSIGN\n");} ">" {printf("GT\n");} ">=" {printf("GE\n");} "<" {printf("LT\n");} "<=" {printf("LE\n");} "!=" {printf("NE\n");} "==" {printf("EQ\n");} ";" {printf("SEMICOLON\n");} "," {printf("COMMA\n");} "(" {printf("LPAREN\n");} ")" {printf("RPAREN\n");} "{" {printf("LBRACE\n");} "}" {printf("RBRACE\n");} [a-zA-Z][a-zA-Z0-9]* {yylval.id = strdup(yytext); printf("IDENTIFIER %s\n", yylval.id);} [ \t\n]+ { /* skip whitespace */ } %% int main(int argc, char *argv[]) { FILE *yyin = fopen(argv[1], "r"); if (!yyin) { printf("Cannot open input file!\n"); return -1; } yylex(); fclose(yyin); return 0; } void yyerror(char *s) { printf("%s\n", s); } ``` 4.使用Flex工具生成词法分析器。 可以使用以下命令生成词法分析器: ``` flex lexer.l ``` 该命令将生成一个名为lex.yy.c的文件,即词法分析器。 5.编译并运行测试程序。 可以使用以下命令编译测试程序: ``` gcc -o lexer lex.yy.c -lfl ``` 该命令将生成一个名为lexer的可执行文件。 可以使用以下命令运行测试程序: ``` ./lexer test.c ``` 其中,test.c是一个待分析的C程序。 实验结果: 假设我们有一个名为test.c的C程序,内容如下: ```c #include <stdio.h> int main() { int a = 10; float b = 3.14; if (a > 5) { printf("a is greater than 5\n"); } else { printf("a is less than or equal to 5\n"); } return 0; } ``` 使用词法分析器对该程序进行分析,输出如下: ``` #include <stdio.h> IDENTIFIER printf LPAREN STRING "a is greater than 5\n" RPAREN SEMICOLON INT IDENTIFIER main LPAREN RPAREN LBRACE INT IDENTIFIER a ASSIGN INT 10 SEMICOLON FLOAT IDENTIFIER b ASSIGN FLOAT 3.140000 SEMICOLON IF LPAREN IDENTIFIER a GT INT 5 RPAREN LBRACE IDENTIFIER printf LPAREN STRING "a is greater than 5\n" RPAREN SEMICOLON RBRACE ELSE LBRACE IDENTIFIER printf LPAREN STRING "a is less than or equal to 5\n" RPAREN SEMICOLON RBRACE RETURN INT 0 SEMICOLON RBRACE ``` 可以看到,词法分析器成功地识别出了关键字、标识符、整数、浮点数、运算符和界符等,并正确地输出了结果。 实验总结: 本实验中,我们学习了词法分析程序的基本原理和算法,并使用Flex工具和正则表达式编写了一个简单的词法分析器词法分析器能够识别出关键字、标识符、整数、浮点数、运算符和界符等,并对输入的代码进行了正确的分析。通过本实验的学习,我们深入理解了编译原理中的词法分析过程,提高了对编译原理的理解和应用能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值