一、實驗目的
設計、編制並調試一個詞法分析程序,加深對詞法分析原理的理解。
二、實驗要求
2.1 待分析的簡單的詞法
(1)關鍵字:
begin if then while do end
所有的關鍵字都是小寫。
(2)運算符和界符
:= + - * /
< <= <> > >= =
; ( ) #
(3)其他單詞是標識符(ID)和整型常數(NUM),通過以下正規式定義:
ID = letter (letter | digit)*
NUM = digit digit*
(4)空格有空白、制表符和換行符組成。空格一般用來分隔ID、NUM、運算符、界符和關鍵字,詞法分析階段通常被忽略。
2.2 各種單詞符號對應的種別碼:
表2.1 各種單詞符號對應的種別碼
2.3 詞法分析程序的功能:
輸入:所給文法的源程序字符串。
輸出:二元組(syn,token或num)構成的序列。
其中:syn為單詞種別碼;
token為存放的單詞自身字符串;
num為整型常數。
例如:對源程序begin x:=9; if x>9 then x:=2*x+1/3; end #
的Pascal源文件,經過詞法分析后輸出如下序列:
(1,begin)(10,x)(18,:=)(11,9)(26,;)(2,if)…
三、實驗過程
- 首先需要了解flex語法格式
%{
C語言聲明,一般聲明全局變量和函數,以及頭文件包含,會復制進lex.yy.c中
%}
定義正則表達式的名字,可以在規則段中使用
%%
規則段,每一行都是一條規則,每一條規則由匹配模式和動作組成。每當一個模式被匹配到,后面的動作被執行!模式一般使用正則表達式書寫,動作部分為C代碼
%%
用戶自定義過程,直接復制到lex.yy.c末尾
- 下表列出了部分常用的正則表達式
- flex提供的2個全局變量:
yytext:剛剛匹配到的字符串 yyleng:剛剛匹配到的字符串的長度
- 代碼段如下(注意:規則行務必沒有縮進,且對應的動作必須在同一行開始):
%{
#include <stdio.h>
#include <string.h>
%}
ALPHA [a-zA-Z]
ID {ALPHA}+[a-zA-Z0-9_]*
KEY begin|if|then|while|do|end
NUM [\-]?[1-9][0-9]*|0
%%
{KEY} {
if(yytext[0]=='b')
printf("(1,%s)",yytext);
else if(yytext[0]=='i')
printf("(2,%s)",yytext);
else if(yytext[0]=='t')
printf("(3,%s)",yytext);
else if(yytext[0]=='w')
printf("(4,%s)",yytext);
else if(yytext[0]=='d')
printf("(5,%s)",yytext);
else if(yytext[0]=='e')
printf("(6,%s)",yytext);
}
{ID} printf("(10,%s)",yytext);
{NUM} printf("(11,%s)",yytext);
\+ printf("(13,%s)",yytext);
\- printf("(14,%s)",yytext);
\* printf("(15,%s)",yytext);
\/ printf("(16,%s)",yytext);
\: printf("(17,%s)",yytext);
\:= printf("(18,%s)",yytext);
\< printf("(20,%s)",yytext);
\<> printf("(21,%s)",yytext);
\<= printf("(22,%s)",yytext);
\> printf("(23,%s)",yytext);
\>= printf("(24,%s)",yytext);
\= printf("(25,%s)",yytext);
; printf("(26,%s)",yytext);
\( printf("(27,%s)",yytext);
\) printf("(28,%s)",yytext);
\# printf("(0,%s)",yytext);
\n printf("\n");
.
%%
int main(int argc, char **argv)
{
yylex();
yywrap();
}
int yywrap()
{
return 1;
}
解釋:
- ALPHA是字母,ID是標識符,KEY是關鍵字,NUM整型常數
- 關鍵字比標識符優先,所以要放它前面,不然識別會有錯誤
- 符號'.'表示除\n外的所有字符
- 整型常數可以是負數也可以是0
- 匹配的那些符號,要加上雙引號或者在前面都加上\(轉義字符)
四、實驗結果
- 用管理員身份打開cmd窗口
- 進入到該代碼文本文件所在的文件夾內
- 然后輸入下面兩行命令,完成對代碼的編譯生成。
flex test.l //此后會生成C文件lex.yy.c
gcc lex.yy.c //使用gcc編譯成可執行文件
- 我這里生成的是a.exe文件,在窗口中輸入a.exe或a回車,運行該文件
即可輸入字符串來驗證結果。
可以看到結果是正確的。