实验目的:
(1)熟悉 C 语言的词法规则,了解编译器词法分析器的主要功能和实现技术,掌握典型词法分析器构造方法,设计并实现 C 语言词法分析器;
(2)了解 Flex 工作原理和基本思想,学习使用工具自动生成词法分析器;
(3)掌握编译器从前端到后端各个模块的工作原理,词法分析模块与其他模块之间的交互过程。
实验内容:
根据 C 语言的词法规则,设计识别 C 语言所有单词类的词法分析器的确定有限状态自动机,并使用 Java、C\C++或者 Python 其中任何一种语言,采用程序中心法或者数据中心法设计并实现词法分析器。词法分析器的输入为 C 语言源程序,输出为属性字流。
实验要求:
基于示例实现,对于如下的测试程序
scanner_example.c: int sum(int a, int b) { return a + b; }
输出的属性字流存储在 scanner_example.tokens 文件中,具体内容见下:
[@0,0:2=‘int’,<‘int’>,1:0]
[@1,4:6=‘sum’,,1:4]
[@2,8:8=’(’,<’(’>,1:8]
[@3,10:12=‘int’,<‘int’>,1:10]
[@4,14:14=‘a’,,1:14]
[@5,16:16=’,’,<’,’>,1:16]
[@6,18:20=‘int’,<‘int’>,1:18]
[@7,22:22=‘b’,,1:22]
[@8,24:24=’)’,<’)’>,1:24]
[@9,26:26=’{’,<’{’>,1:26]
[@10,28:33=‘return’,<‘return’>,1:28]
[@11,35:35=‘a’,,1:35]
[@12,37:37=’+’,<’+’>,1:37]
[@13,39:39=‘b’,,1:39]
[@14,41:41=’;’,<’;’>,1:41]
[@15,43:43=’}’,<’}’>,1:43]
[@16,47:46=’’,,2:0]
在这个输出的 token 流中,每行为一个 token,以@开头的数字表示 token 的序号,紧接着的 xx:xx 表示 token 文本对应的开始列和结束列,“=”后面给出了这个范围之内 token 的具体文本,“<>”之内表示 token 的类型,最后一个数字对 xx:xx 表示起始行和起始列。需要说明的是,在这个例子中,运算符等的类型就是其自身,属性流的最后放置了一个“EOF”表示属性字的结束位置。
本实验所用到的工具是flex,关于flex下载安装方法的参考,关于flex这一工具的使用方法的参考,关于代码写法的参考,代码见下:
%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int toke=0;
int line=0;
int len,fin;
FILE *fp;
%}
DIGIT [0-9]
OINTEGER [1-9]{DIGIT}*
INTEGER ("+"|"-")?{DIGIT}+
DECIMAL {INTEGER}.{DIGIT}+
FLOAT {INTEGER}.{DIGIT}+("e"(("+"|"-"){OINTEGER})?)?
LETTER [a-zA-Z]
IDENTIFIER ({LETTER}|_)({LETTER}|_|{DIGIT})*
COMMENT ("/*"|"*").*
KEYWORD ("auto"|"break"|"case"|"char"|"const"|"continue"|"default"|"do"|"double"|"else"|"enum"|"extern"|"float"|"for"|"goto"|"if"|"inline"|"int"|"long"|"register"|"restrict"|"return"|"short"|"signed"|"sizeof"|"static"|"struct"|"switch"|"typedef"|"union"|"unsigned"|"void"|"volatile"|"while")
BRACKET ("["|"]"|"("|")"|"{"|"}"|"."|"->"|"++"|"--"|"&"|"*"|"+"|"-"|"~"|"!"|"/"|"%"|"<<"|">>"|"<"|">"|"<="|">="|"=="|"!="|"^"|"|"|"&&"|"||"|"?"|":"|";"|"..."|"="|"*="|"/="|"%="|"+="|"-="|"<<="|">>="|"&="|"^="|"|="|","|"#"|"##"|"<:"|":>"|"<%"|"%>"|"%:"|"%:%:")
TYPEIDENTITY ("%"|"&")[a-z]
%%
{KEYWORD} {
len=strlen(yytext)-1;
fin=len+line;
fprintf(fp,"[@%d,%d:%d='%s',<'%s'>,1:%d]",toke,line,fin,yytext,yytext,line);
toke++;
line=fin+2;
}
{TYPEIDENTITY} {
len=strlen(yytext)-1;
fin=len+line;
fprintf(fp,"[@%d,%d:%d='%s',<'typeidentify'>,1:%d]",toke,line,fin,yytext,line);
toke++;
line=fin+2;
}
{DECIMAL} {
len=strlen(yytext)-1;
fin=len+line;
fprintf(fp,"[@%d,%d:%d='%s',<'decimal'>,1:%d]",toke,line,fin,yytext,line);
toke++;
line=fin+2;
}
{INTEGER} {
len=strlen(yytext)-1;
fin=len+line;
fprintf(fp,"[@%d,%d:%d='%s',<'integer'>,1:%d]",toke,line,fin,yytext,line);
toke++;
line=fin+2;
}
{FLOAT} {
char *p = strchr(yytext, 'e');
if (p && yytext[strlen(yytext)-1] == 'e')
{
fprintf(fp,"Error at Illegal floating point number \"%s\".\n",yytext);
return 0;
}
else
{
len=strlen(yytext)-1;
fin=len+line;
fprintf(fp,"[@%d,%d:%d='%s',<'float'>,1:%d]",toke,line,fin,yytext,line);
toke++;
line=fin+2;
}
}
{IDENTIFIER} {
len=strlen(yytext)-1;
fin=len+line;
fprintf(fp,"[@%d,%d:%d='%s',<'Identifier'>,1:%d]",toke,line,fin,yytext,line);
toke++;
line=fin+2;
}
{BRACKET} {
len=strlen(yytext)-1;
fin=len+line;
fprintf(fp,"[@%d,%d:%d='%s',<'%s'>,1:%d]",toke,line,fin,yytext,yytext,line);
toke++;
line=fin+2;
}
{COMMENT} {}
. {}
%%
int main(int argc,char *argv[])
{
yyin=fopen("scanner_example.c","r");
fp=fopen("scanner_example.tokens","w");
yylex();
fin=line-1;
fprintf(fp,"\n[@%d,%d:%d='<EOF>',<EOF>,2:0]",toke,line,fin);
return 0;
}
int yywrap()
{
return 1;
}