请根据词法分析实验中给定的文法,利用flex设计一词法分析器,该分析器从标准输入读入源代码后,输出单词的类别编号及附加信息。 附加信息规定如下: 当类别为 Y_ID、num_INT 或 num_FLOAT 时,附加信息为该类别对应的属性,如 main, 100, 29.3等; 当类别为 关键字 时,附件信息为 KEYWORD; 当类别为 运算符 时,附件信息为 OPERATOR; 当类别为 其它符号时,附件信息为 SYMBOL; 例如对于源代码
int main(){ return 3; }
词法分析器的输出为:
<261, KEYWORD> <260, main> <285, SYMBOL> <286, SYMBOL> <287, SYMBOL> <269, KEYWORD> <258, 3> <292, SYMBOL> <288, SYMBOL>
请在本页面上传词法分析实验所有源代码及实验报告(源代码至少包括一个flex源文件,即 .l 文件,如有其它 .c 或 .h 文件,也请一并上传)
本实验中的单词类别定义如下,该定义包含在 token.h 中,此头文件可直接使用,无需上传
// 单词类别 enum yytokentype { num_INT = 258, num_FLOAT = 259, Y_ID = 260, Y_INT = 261, Y_VOID = 262, Y_CONST = 263, Y_IF = 264, Y_ELSE = 265, Y_WHILE = 266, Y_BREAK = 267, Y_CONTINUE = 268, Y_RETURN = 269, Y_ADD = 270, Y_SUB = 271, Y_MUL = 272, Y_DIV = 273, Y_MODULO = 274, Y_LESS = 275, Y_LESSEQ = 276, Y_GREAT = 277, Y_GREATEQ = 278, Y_NOTEQ = 279, Y_EQ = 280, Y_NOT = 281, Y_AND = 282, Y_OR = 283, Y_ASSIGN = 284, Y_LPAR = 285, Y_RPAR = 286, Y_LBRACKET = 287, Y_RBRACKET = 288, Y_LSQUARE = 289, Y_RSQUARE = 290, Y_COMMA = 291, Y_SEMICOLON = 292, Y_FLOAT = 293 };
%{
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* endptr;
enum yytokentype {
num_INT = 258,
num_FLOAT = 259,
Y_ID = 260,
Y_INT = 261,
Y_VOID = 262,
Y_CONST = 263,
Y_IF = 264,
Y_ELSE = 265,
Y_WHILE = 266,
Y_BREAK = 267,
Y_CONTINUE = 268,
Y_RETURN = 269,
Y_ADD = 270,
Y_SUB = 271,
Y_MUL = 272,
Y_DIV = 273,
Y_MODULO = 274,
Y_LESS = 275,
Y_LESSEQ = 276,
Y_GREAT = 277,
Y_GREATEQ = 278,
Y_NOTEQ = 279,
Y_EQ = 280,
Y_NOT = 281,
Y_AND = 282,
Y_OR = 283,
Y_ASSIGN = 284,
Y_LPAR = 285,
Y_RPAR = 286,
Y_LBRACKET = 287,
Y_RBRACKET = 288,
Y_LSQUARE = 289,
Y_RSQUARE = 290,
Y_COMMA = 291,
Y_SEMICOLON = 292,
Y_FLOAT = 293
};
int a1;
float a2;
%}
DIGIT [0-9]+
WORD [a-zA-Z]+
DIGIT16 [0-9a-fA-F]+
%%
0[xX]{DIGIT16} {a1 = strtol(yytext, &endptr, 16); return num_INT;}
[0-9]+ {a1 = atoi(yytext); return num_INT;}
{DIGIT}+"."*{DIGIT}* {a2 = atoi(yytext); return num_FLOAT;}
"//"(.*) {yywrap();}
"\n" {}
" " {}
"int" {return Y_INT;}
"void" {return Y_VOID;}
"const" {return Y_CONST;}
"if" {return Y_IF;}
"else" {return Y_ELSE;}
"while" {return Y_WHILE;}
"break" {return Y_BREAK;}
"continue" {return Y_CONTINUE;}
"return" {return Y_RETURN;}
[a-zA-Z_][a-zA-Z0-9_]* {return Y_ID;}
"+" {return Y_ADD; }
"-" {return Y_SUB; }
"*" {return Y_MUL; }
"/" {return Y_DIV; }
"%" {return Y_MODULO; }
"<" {return Y_LESS; }
"<=" {return Y_LESSEQ; }
">" {return Y_GREAT; }
">=" {return Y_GREATEQ; }
"!=" {return Y_NOTEQ;}
"==" {return Y_EQ; }
"!" {return Y_NOT;}
"&&" {return Y_AND;}
"||" {return Y_OR;}
"=" {return Y_ASSIGN;}
"(" {return Y_LPAR;}
")" {return Y_RPAR; }
"{" {return Y_LBRACKET;}
"}" {return Y_RBRACKET;}
"[" {return Y_LSQUARE;}
"]" {return Y_RSQUARE;}
"," {return Y_COMMA;}
";" {return Y_SEMICOLON;}
"." {return Y_FLOAT;}
%%
void main()
{
int tok;
while(tok = yylex())
{
if(tok == Y_ID)
printf("<260, %s>\n", yytext);
else if(tok == num_INT)
printf("<258, %d>\n", a1);
else if(tok == num_FLOAT)
printf("<259, %f>\n", a2);
else if(tok == Y_INT || tok == Y_VOID || tok == Y_CONST || tok == Y_IF || tok == Y_ELSE || tok == Y_WHILE || tok == Y_BREAK || tok == Y_CONTINUE || tok == Y_RETURN)
printf("<%d, %s>\n", tok, "KEYWORD");
else if(tok == Y_ADD || tok == Y_SUB || tok == Y_MUL || tok == Y_DIV || tok == Y_MODULO || tok == Y_LESS || tok == Y_LESSEQ || tok == Y_GREAT || tok == Y_GREATEQ || tok == Y_NOTEQ || tok == Y_EQ || tok == Y_NOT || tok == Y_AND || tok == Y_OR || tok == Y_ASSIGN)
printf("<%d, %s>\n", tok, "OPERATOR");
else if(tok == Y_LPAR || tok == Y_RPAR || tok == Y_LBRACKET || tok == Y_RBRACKET || tok == Y_LSQUARE || tok == Y_RSQUARE || tok == Y_COMMA || tok == Y_SEMICOLON || tok == Y_FLOAT)
printf("<%d, %s>\n", tok, "SYMBOL");
}
}
int yywrap(){
return 1;
}
本实验应用flex,实验前建议在本地安装好flex,可通过cmd命令直接操作。
flex test.l
编译lex.yy.c文件时,个人应用cmd命令调用gcc编译,较为方便。
gcc lex.yy.c
上传文件时,请将实验报告(Word文档或PDF文档)一并上传,否则系统不予通过。
实验要点: 单行注释的正则表达式及忽略处理
变量名的正则表达式
十六进制数如何转化为十进制数
flex自身全局变量和已定义函数的合理调用
注:个人作业仅供参考和学习交流,如有不足之处欢迎批评指正,请勿抄袭!