資源簡介
一、實驗目的:
通過設計編制調試一個具體的詞法分析程序,加深對詞法分析原理的理解。并掌握在對程序設計語言源程序進行掃描過程中將其分解為各類單詞的詞法分析方法。
編制一個讀單詞過程,從輸入的源程序中,識別出各個具有獨立意義的單詞,即基本保留字、標識符、常數、運算符、分隔符五大類。并依次輸出各個單詞的內部編碼及單詞符號自身值。(遇到錯誤時可顯示“Error”,然后跳過錯誤部分繼續顯示)
二、實驗預習提示
1、詞法分析器的功能和輸出格式
詞法分析器的功能是輸入源程序,輸出單詞符號。詞法分析器的單詞符號常常表示成以下的二元式(單詞種別碼,單詞符號的屬性值)。本實驗中,采用的是按類來安排種別碼的方式。
2、部分單詞的BNF表示(可參考教材43頁的狀態轉換圖)
->
->||
|ε
->
-> |ε
-> +
-> -
-> >
-> >=
3、 做詞法分析器需要把對象語言的詞法全部描述出來,在這我們取C語言子集,它的詞法如下:
(1)關鍵字
main if else int return void while…….. 所有的關鍵字都是小寫。
(2)專用符號
= + - * / <= > >= == != ; : , { } [ ] ( )
(3)空格和空白、制表符和換行符。
空格一般用來分隔ID、NUM、專用符號和關鍵字,在詞法分析階段通常被忽略。
各種單詞符號的種別碼,這是一種符號一個編碼的設計。只供參考!
單詞符號 種別碼 單詞符號 種別碼
main 2 [ 28
int 1 ] 29
char 3 { 30
If 4 } 31
else 5 , 32
for 6 : 33
while 7 ; 34
ID 10 > 35
NUM 20 = 37
+ 22 +”,當前字符為’>’,此時,分析器倒底是將其分析為大于關系運算符還是大于等于關系運算符呢?顯然,只有知道下一個字符是什么才能下結論。于是分析器讀入下一個字符’+’,這時可知應將’>’解釋為大于運算符。但此時,超前讀了一個字符’+’,所以要回退一個字符,詞法分析器才能正常運行。在分析標識符,無符號整數等時也有類似情況。
5、模塊結構
見附圖
三、實驗過程和指導:
(一)準備:
1.閱讀課本有關章節,明確語言的語法,寫出基本保留字、標識符、常數、運算符、分隔符和程序例。
2.編制好程序。
3.準備好多組測試數據。
(二)上機調試:
(三)程序要求:
程序輸入/輸出示例:
如源程序為C語言。輸入如下一段:
main()
{
int a,b;
a = 10;
b = a + 20;
}
要求輸出如右圖。
(2,“main”)
(5,“(” )
(5,“ )” )
(5,“{ ” )
(1,“int” )
(2,“a” )
(5,“,” )
(2,“b” )
(5,“;” )
(2,“a” )
(4,“=” )
(3,“10” )
(5,“;” )
(2,“b” )
(4,“=” )
(2,“a” )
(4,“+” )
(3,“20” )
(5,“;” )
(5,“}” )
說明:
識別保留字:if、int、for、while、do、return、break、continue;
單詞種別碼為1。
其他的都識別為標識符;單詞種別碼為2。
常數為無符號整形數;單詞種別碼為3。
運算符包括:+、-、*、/、=、>、=、<=、!= ;單詞種別碼為4。
分隔符包括:,、;、{、}、(、); 單詞種別碼為5。
以上為參考,具體可自行增刪。
程序思路(參考):
這里以開始定義的C語言子集的源程序作為詞法分析程序的輸入數據。在詞法分析中,自文件頭開始掃描源程序字符,一旦發現符合“單詞”定義的源程序字符串時,將它翻譯成固定長度的單詞內部表示,并查填適當的信息表。
經過詞法分析后,源程序字符串(源程序的外部表示)被翻譯
代碼片段和文件信息
#include
#include
#include
char?ch;
bool?isletter(char?ch);
bool?isnumber(char?ch);
void?scanner(FILE?*f);
void?main()
{
char?fname[20];
FILE?*fp;
do{
printf(“Input?the?filename:“);
scanf(“%s“fname);
fp?=?fopen(fname“r“);
}while(!fp);
scanner(fp);
fclose(fp);
}
bool?isletter(char?ch)//是否為字母
{
if(ch>=‘A‘&&ch<=‘Z‘||ch>=‘a‘&&ch<=‘z‘)
return?true;
else
return?false;
}
bool?isnumber(char?ch)//是否為數字
{
if(ch>=‘0‘&&ch<=‘9‘)
return?true;
else
return?false;
}
void?scanner(FILE?*f)
{
char?arr[20];
int?i=0j=0;
while(1)
{
ch?=?fgetc(f);
if(?ch==‘?‘||?ch?==‘\t‘)
;//過濾掉空格和tab
else?if(?ch==‘\n‘)
;//回車換行符,為下面進行錯誤判斷
else?if(?isnumber(ch))//讀入的是數字
{
while(isnumber(ch))
{ ?
arr[j]?=?ch;
j++;
ch?=?fgetc(f);
}
????fseek(f-1LSEEK_CUR);//文件指針后退一個字節
char*?temp1?=(char*)malloc(j+1);
memcpy(temp1arrj);
temp1[j]?=‘\0‘;
j=0;//恢復初始狀態,以備下次使用
printf(“(%d\t\“%s\“)\n“20temp1);//常數
free(temp1);//釋放內存
}
else?if(isletter(ch))//是字母開頭的
{
while(isletter(ch)?||?isnumber(ch))
{
arr[i]?=ch;
i++;
ch?=?fgetc(f);
}
fseek(f-1LSEEK_CUR);
char*?temp1?=(char*)malloc(i+1);
memcpy(temp1arri);
temp1[i]?=‘\0‘;
i=0;
/*基本思想同處理數字的*/
??????????if(strcmp(temp1“main“)==0)//關鍵字和temp字符串相同的,找到并輸出
?printf(“(%d\t\“%s\“)\n“2temp1);
??else?if(strcmp(temp1“int“)==0)
??printf(“(%d\t\“%s\“)\n“1temp1);
??else?if(strcmp(temp1“if“)==0)
??printf(“(%d\t\“%s\“)\n“4temp1);
??else?if(strcmp(temp1“else“)==0)
??printf(“(%d\t\“%s\“)\n“5temp1);
??else?if(strcmp(temp1“for“)==0)
??printf(“(%d\t\“%s\“)\n“6temp1);
??else?if(strcmp(temp1“while“)==0)
??printf(“(%d\t\“%s\“)\n“7temp1);
??else?if(strcmp(temp1“char“)==0)
??printf(“(%d\t\“%s\“)\n“3temp1);
??else?if(st
評論
共有 條評論