【編譯原理】Lex詞法分析器
一、實驗目的
設計並實現一個詞法分析器,深刻理解編譯原理中詞法分析器的原理。
二、實驗內容
通過使用自己熟悉的語言設計並實現一個詞法分析器,是此法分析器按要求的格式輸出經過分析的程式段。
要求分析一下程式片段:
- const a=10;
- var b,c;
- procedure p;
- begin
- c:=b+a;
- end;
- begin
- read(b);
- while b#0do
- begin
- call p;writeln(2*c);read(b);
- end
- end.
該程式片段存放在example.txt中。
三、實驗步驟
1、對PL\0文法中各類單詞分類:
(1)保留字:const、var、procedure、begin、end、if、then、while、do、read、call、write、writeln
(2)常數:由0-----9這幾個數字組成
(3)識別符號:由字母打頭的字母和數字的字串
(4)運算子:+,-,*,/,:=,>=,<=,#
(5)分界符:,、.、(、)、;
2、將各類單詞對應到lex中:
(1)保留字:
reservedWord [const|var|procedure|begin|end|if|then|while|do|read|call|write|writeln],由於在lex中不區分大小寫,所以將保留字寫成:
reservedWord [cC][oO][nN][sS][tT]|[vV][aA][rR]|[pP][rR][oO][cC][eE][dD][uU][rR][eE]|
[bB][eE][gG][iI][nN]|[eE][nN][dD]|[iI][fF]|[tT][hH][eE][nN]|[wW][hH][iI]
[lL][eE]|[dD][oO]|[rR][eE][aA][dD]|[cC][aA][lL][lL]|[wW][rR][iI][tT][eE]
[wW][rR][iI][tT][eE][lL][nN]
(2)常數:
constant ([0-9])+ /*0---9這幾個數字可以重複*/
(3)識別符號:
identfier [A-Za-z]([A-Za-z][0-9])*
(4)運算子:
operator \+|-|\*|\/|:=|>=|<=|#|= /*在lex中,有特殊意義的運算子要加轉義字元\,如+、*及*、/
(5)分界符:
delimiter [,\.;\(\)]
3、PL/0的語言的詞法分析器要求跳過分隔符(如空格,回車,製表符),對應的lex定義為:
delim [""\n\t]
whitespace{delim}+
4、為lex制定一些規則:
{reservedWord}{count++;printf("\t%d\t(1,‘%s’)\n",count,yytext);} /*對保留字定規則,輸出設定*/
{operator} {count++;printf("\t%d\t(2,‘%s’)\n",count,yytext); }
{delimiter}{count++;printf("\t%d\t(3,‘%s’)\n",count,yytext);}
{constant}{count++;printf("\t%d\t(4,‘%s’)\n",count,yytext);}
{identfier}{count++;printf("\t%d\t(5,‘%s’)\n",count,yytext);}
{whitespace} {/* do nothing*/ } /*遇到空格,什麼都不做*/
5、寫子程式:
voidmain()
{
printf("詞法分析器輸出型別說明:\n");
printf("1:保留字\n");
printf("2:運算子\n");
printf("3:分界符\n");
printf("4:常 數\n");
printf("5:識別符號\n");
printf("\n");
yyin=fopen("example.txt","r");
yylex(); /* start the analysis*/
fclose(yyin);
system("PAUSE");/*暫停*/
}
intyywrap()
{
return 1;
}
當lex 讀完輸入檔案之後就會呼叫函式 yywrap 。如果返回1 表示程式的工作已經完成了,否則,返回 0。
四、實現的原始碼
- %{
- #include <stdio.h>
- #include <stdlib.h>
- int count = 0;
- %}
- delim [" "\n\t]
- whitespace {delim}+
- operator \+|-|\*|\/|:=|>=|<=|#|=
- reservedWord [cC][oO][nN][sS][tT]|[vV][aA][rR]|[pP][rR][oO][cC][eE][dD][uU][rR][eE]|[bB][eE][gG][iI][nN]|[eE][nN][dD]|[iI][fF]|[tT][hH][eE][nN]|[wW][hH][iI][lL][eE]|[dD][oO]|[rR][eE][aA][dD]|[cC][aA][lL][lL]|[wW][rR][iI][tT][eE]|[wW][rR][iI][tT][eE][lL][nN]
- delimiter [,\.;\(\)]
- constant ([0-9])+
- identfier [A-Za-z]([A-Za-z][0-9])*
- %%
- {reservedWord} {count++;printf("%d\t(1,‘%s’)\n",count,yytext);}
- {operator} { count++;printf("%d\t(2,‘%s’)\n",count,yytext); }
- {delimiter} {count++;printf("%d\t(3,‘%s’)\n",count,yytext);}
- {constant} {count++;printf("%d\t(4,‘%s’)\n",count,yytext);}
- {identfier} {count++;printf("%d\t(5,‘%s’)\n",count,yytext);}
- {whitespace} { /* do nothing*/ }
- %%
- void main()
- {
- printf("詞法分析器輸出型別說明:\n");
- printf("1:保留字\n");
- printf("2:運算子\n");
- printf("3:分界符\n");
- printf("4:常 數\n");
- printf("5:識別符號\n");
- printf("\n");
- yyin=fopen("example.txt","r");
- yylex(); /* start the analysis*/
- fclose(yyin);
- system("PAUSE");/*暫停停, 使DOS視窗停住*/
- }
- int yywrap()
- {
- return 1;
- }
五、實操作
將原始碼儲存為a.l,然後用flex(Lex)進行編譯,輸入flex a.l,編譯後生成lex.yy.c檔案,用c編譯器開啟(確保example.txt儲存在相同目錄下),編譯執行即可!
六、執行結果