《語(yǔ)法分析實(shí)驗(yàn)報(bào)告.docx》由會(huì)員分享,可在線(xiàn)閱讀,更多相關(guān)《語(yǔ)法分析實(shí)驗(yàn)報(bào)告.docx(10頁(yè)珍藏版)》請(qǐng)?jiān)谘b配圖網(wǎng)上搜索。
語(yǔ)法分析實(shí)驗(yàn)報(bào)告
一、 語(yǔ)法分析功能與目的
語(yǔ)法分析是編譯過(guò)程的核心部分,它的主要任務(wù)是按照程序語(yǔ)言的語(yǔ)法規(guī)則,從由詞法分析輸出的源程序符號(hào)串中識(shí)別出各類(lèi)語(yǔ)法成分,同時(shí)進(jìn)行語(yǔ)法檢查,為語(yǔ)義分析和代碼生成作準(zhǔn)備。執(zhí)行語(yǔ)法分析任務(wù)的程序叫語(yǔ)法分析程序或語(yǔ)法分析器。
語(yǔ)法分析程序以詞法分析輸出的符號(hào)串作為輸入,在分析過(guò)程中檢查這個(gè)符號(hào)串是否為該程序語(yǔ)言的句子。如是,則輸出該句子的分析數(shù),否則就表示源程序存在語(yǔ)法錯(cuò)誤,需要報(bào)告錯(cuò)誤的性質(zhì)和位置。
二、TEST語(yǔ)法規(guī)則
①<程序>∶∶={<聲明序列><語(yǔ)句序列>}
②<聲明序列>∶∶=<聲明序列><聲明語(yǔ)句>|ε
③<聲明語(yǔ)句>∶∶=int <標(biāo)識(shí)符>;
④<語(yǔ)句序列>::=<語(yǔ)句序列><語(yǔ)句>|ε
⑤<語(yǔ)句>::=
|||
|||<復(fù)合語(yǔ)句>|<表達(dá)式語(yǔ)句>
⑥::=if(<表達(dá)式>)<語(yǔ)句>[else<語(yǔ)句>]
⑦::=while(<表達(dá)式>)<表達(dá)式>
⑧:=for(<表達(dá)式>;<表達(dá)式>;<表達(dá)式>)<語(yǔ)句>
⑨::=write<表達(dá)式>;
⑩::=read<標(biāo)識(shí)符>;
⑴<復(fù)合語(yǔ)句>::={<語(yǔ)句序列>}
⑵<表達(dá)式語(yǔ)句>:=<表達(dá)式>;|;
⑶<表達(dá)式>::=<標(biāo)識(shí)符>=<布爾表達(dá)式>|<布爾表達(dá)式>
⑷<布爾表達(dá)式>:=<算術(shù)表達(dá)式>
|<算術(shù)表達(dá)式>(>|<|>=|<=|==|!=)<算術(shù)表達(dá)式>
⑸<算術(shù)表達(dá)式>::=<項(xiàng)>{(+|-)<項(xiàng)>}
⑹<項(xiàng)>::=<因子>{(*|/)<因子>}
⑺<因子>::=(<表達(dá)式>)|<標(biāo)識(shí)符>|<無(wú)符號(hào)整數(shù)>
⑻::=do<語(yǔ)句>while(<表達(dá)式>);
三、 實(shí)驗(yàn)四要求及改進(jìn)思路
實(shí)驗(yàn)要求:
修改詞法分析程序TESTscan.c和語(yǔ)法分析程序TESTparse.c這二個(gè)文件,使該程序能分析:
(1) do語(yǔ)句(有關(guān)文法規(guī)則參見(jiàn)P77的習(xí)題8。)
(2) 同一行中聲明多個(gè)變量(文法規(guī)則參見(jiàn)P77的習(xí)題7)。
例如:原先可以分析的變量聲明是:
int a;
int b;
現(xiàn)在能分析的變量聲明是: int a, b;
改進(jìn)思路:
對(duì)于問(wèn)題(1),由于do語(yǔ)句的語(yǔ)法規(guī)則為
::=do<語(yǔ)句>while(<表達(dá)式>);
do語(yǔ)句的正確輸入形式為:
do {表達(dá)式}
while (表達(dá)式);
所以do語(yǔ)句的前半部分為一個(gè)復(fù)合語(yǔ)句,所以在語(yǔ)法分析程序中要能分析出do語(yǔ)句,必須在定義do語(yǔ)句時(shí)先要求該句子屬于復(fù)合語(yǔ)句,然后使指針為while,再到(,然后是表達(dá)式,接著就是),最后為;,這就是完整的do語(yǔ)句。
①定義do語(yǔ)句的代碼如下:
int do_stat()
{
int es = 0;
fscanf(fp,"%s %s\n",&token,&token1);
printf("%s %s\n",token,token1);
es=compound_stat(); //調(diào)用復(fù)合語(yǔ)句
if(es>0) return (es);
if (strcmp(token, "while")) return(es=8);
fscanf(fp,"%s %s\n",&token,&token1);
printf("%s %s\n",token,token1);
if (strcmp(token, "(")) return(es=5); //少左括號(hào)
fscanf(fp,"%s %s\n",&token,&token1);
printf("%s %s\n",token,token1);
es = expression(); //調(diào)用表達(dá)式
if(es>0) return (es);
if (strcmp(token, ")")) return(es=6); //少右括號(hào)
fscanf(fp,"%s %s\n",&token,&token1);
printf("%s %s\n",token,token1);
if (strcmp(token, ";")) return(es=4); //少分號(hào)
fscanf(fp,"%s %s\n",&token,&token1);
printf("%s %s\n",token,token1);
return es;
}
②然后在語(yǔ)法分析程序的開(kāi)始定義的函數(shù)中必須加上int do_stat();;
③然后在函數(shù)出錯(cuò)的情況switch (es)的函數(shù)中加上case 8: printf("do后面缺少while! \n"); break;,這是說(shuō)明do語(yǔ)句不完整的出錯(cuò)情況。
對(duì)于問(wèn)題(2):同一行中定義多個(gè)變量,對(duì)比前后變化的兩個(gè)變量聲明形式,我們可以看出同一行中定義多個(gè)變量時(shí),在分析第一個(gè)變量時(shí)原來(lái)的變量聲明能分析得出來(lái),但是在接下來(lái)的變量中就有變化了,在同一行定義多個(gè)變量的第二個(gè)變量是接第一個(gè)變量后的,第二個(gè)變量的為第一個(gè)變量后接著一個(gè)逗號(hào),然后就是第二個(gè)變量,如果同一行有n多個(gè)變量,那么從第三個(gè)變量開(kāi)始,就先能分析出其必須先要分析出第二個(gè)變量,以此類(lèi)推,分析出第n個(gè)變量就必須分析出前n-1個(gè)變量,而且要能分析出第n(n>2)個(gè)變量,其要求就如同分析出第二個(gè)變量,它就是一個(gè)反復(fù)調(diào)用的過(guò)程。我們可以定義一個(gè)函數(shù)d(),要求它的結(jié)構(gòu)為逗號(hào)后接著標(biāo)識(shí)符,然后就由原來(lái)的分析出單個(gè)變量的變量聲明在分析到標(biāo)識(shí)符的時(shí)候調(diào)用我們定義的函數(shù)d(),就能實(shí)現(xiàn)一行識(shí)別出多個(gè)變量了。
函數(shù)d()的定義如下:
int d()
{if(strcmp(token,",")==0)
{ int es=0;
fscanf(fp,"%s %s\n",&token,&token1);
printf("%s %s\n",token,token1);
if (strcmp (token, "ID")) return (es=3); //不是標(biāo)識(shí)符
fscanf(fp,"%s %s\n",&token,&token1);
printf("%s %s\n",token,token1);
d();
}
}
在聲明語(yǔ)句定義時(shí)調(diào)用d()函數(shù)實(shí)現(xiàn)一行識(shí)別出多個(gè)變量的情況如下:
// : : = int ID;
int declaration_stat()
{
int es=0;
fscanf(fp, "%s %s\n", &token, &token1);
printf ("%s %s\n",token, token1);
if (strcmp (token, "ID")) return (es=3); //不是標(biāo)識(shí)符
fscanf(fp,"%s %s\n",&token,&token1);
printf("%s %s\n",token,token1);
d();
if (strcmp(token,";")) return(es=4);
fscanf (fp, "%s %s\n", &token, &token1);
printf ("%s %s\n",token, token1);
return(es);
}
四、 該語(yǔ)法分析程序是遞歸下降分析的語(yǔ)法分析方法
遞歸下降分析的方法思路是將文法中的每一個(gè)非終結(jié)符U的文法規(guī)則看作是識(shí)別U的一個(gè)過(guò)程定義,為每個(gè)非終結(jié)符另構(gòu)造一個(gè)子程序,以完成該非終結(jié)符號(hào)所對(duì)應(yīng)的語(yǔ)法成分的分析和識(shí)別任務(wù)。
如果U的文法規(guī)則的右部只有一個(gè)候選式,按從左向右的順序依次構(gòu)造規(guī)則U的識(shí)別過(guò)程代碼:
①如果有終結(jié)符號(hào),判斷能否與輸入的符號(hào)相等,如果想等,表示識(shí)別成功,讀入指針指向下一個(gè)輸入符號(hào);如果不想等,則意味著輸入串此時(shí)有語(yǔ)法錯(cuò)誤;
②如果是非終結(jié)符號(hào),則簡(jiǎn)單調(diào)用這個(gè)非終結(jié)符號(hào)的子程序,由這個(gè)子程序完成該非終結(jié)符號(hào)所對(duì)應(yīng)的語(yǔ)法成分分析和識(shí)別任務(wù);
③當(dāng)一條規(guī)則右部有多個(gè)候選式時(shí),則根據(jù)每個(gè)候選式的第一個(gè)符號(hào)確定該候選式分支;
只有被調(diào)用的分析識(shí)別某語(yǔ)法成分的子程序匹配輸入串成功,且正確返回時(shí),該語(yǔ)法成分才算真正獲得識(shí)別。
五、輸入文件內(nèi)容及屏幕輸出內(nèi)容
⑴①輸入正確的源文件如下:
詞法分析結(jié)果內(nèi)容如下:
②語(yǔ)法分析屏幕輸出的內(nèi)容如下:
下面接著余下的輸出部分:
⑵①輸入文件為錯(cuò)誤的源文件如下:
語(yǔ)法分析屏幕輸出的內(nèi)容如下:
從語(yǔ)法分析結(jié)果中我們看到語(yǔ)法分析都for語(yǔ)句的后半句i++的時(shí)候就停止了,然后錯(cuò)誤的緣由是缺少操作數(shù),因?yàn)閒or語(yǔ)句后接著的是<語(yǔ)句>,而i++:形式?jīng)]有符合TEST的語(yǔ)法規(guī)則里的任何一種語(yǔ)句規(guī)則,所以出現(xiàn)錯(cuò)誤。
②當(dāng)輸入源程序改為如下:
語(yǔ)法分析屏幕輸出的內(nèi)容如下:
從語(yǔ)法分析輸出結(jié)果我們看出當(dāng)分析到do語(yǔ)句的最后時(shí)出錯(cuò),錯(cuò)誤為缺少分號(hào),說(shuō)明我們的源文件輸入do語(yǔ)句有錯(cuò),查看do語(yǔ)句的標(biāo)準(zhǔn)形式,最后面應(yīng)該以分號(hào)結(jié)束,而我們輸入的源文件缺少了分號(hào),所以出現(xiàn)了錯(cuò)誤。
③當(dāng)輸入源文件為如下所示時(shí):
語(yǔ)法分析屏幕輸出如下所示:
我們從語(yǔ)法分析結(jié)果看出,這次語(yǔ)法分析根本就無(wú)法開(kāi)始,錯(cuò)誤為缺少{,說(shuō)明我們的輸入的程序開(kāi)始就有錯(cuò)誤,查看TEST語(yǔ)法規(guī)則,第一個(gè)規(guī)則為<程序>∶∶={<聲明序列><語(yǔ)句序列>},說(shuō)明輸入程序以{開(kāi)始并以}結(jié)束,而反觀我們的輸入程序,并沒(méi)有以{開(kāi)始,所以語(yǔ)法分析根本無(wú)法進(jìn)行,所以出現(xiàn)了缺少{ 的錯(cuò)誤提醒。
六、實(shí)驗(yàn)體會(huì)
通過(guò)本次實(shí)驗(yàn),我們更加了解了語(yǔ)法分析的原理以及其與詞法分析的關(guān)系,語(yǔ)法分析和詞法相比其又更加復(fù)雜了一點(diǎn)點(diǎn),雖然每次修改代碼的時(shí)候我都感覺(jué)很艱難,因?yàn)镃++學(xué)得不好,但是在其他兩位組員的努力下就能順利的解決了,最后我也能在他們的幫助下懂得了實(shí)驗(yàn)的原理與解答過(guò)程,真心感謝呀。
鏈接地址:http://appdesigncorp.com/p-9084552.html