編譯原理實驗 —— 語法分析器
阿新 • • 發佈:2018-11-03
/* 待分析的簡單語言的語法 用擴充的BNF表示如下: ⑴<程式>::=begin<語句串>end ⑵<語句串>::=<語句>{;<語句>} ⑶<語句>::=<賦值語句> ⑷<賦值語句>::=ID:=<表示式> ⑸<表示式>::=<項>{+<項> | -<項>} ⑹<項>::=<因子>{*<因子> | /<因子> ⑺<因子>::=ID | NUM | (<表示式>) */ #include "stdio.h" #include "string.h" char prog[100],token[8],ch;//prog[100],用來儲存要處理的物件,token用來與關鍵字比較,ch用來儲存一個字元 char *rwtab[6]={"begin","if","then","while","do","end"};//關鍵字表 int syn,p,m,n,sum; /*syn是種別碼,p為prog陣列的指標,m為token陣列的指標,n為rwtab陣列的指標,sum為詞法分析器裡的數字數值大小*/ int flag;//flag與判斷是否end有關 void factor(void);//因式 factor void expression(void);//表示式 expression void yucu(void); void term(void);//項 term void statement(void);// 語句 statement void parser(void); void scaner(void);//掃描器 int main(void) { p=flag=0; printf("\nplease input a string (end with '#'): \n"); /*從命令列讀取要處理的物件,並存儲在prog[]陣列中*/ do { scanf("%c",&ch); //printf("\n input %c now\n",ch); prog[p++]=ch; }while(ch!='#'); p=0; scaner();//主要完成賦值種別碼等詞法分析功能 parser();//呼叫各種遞迴子程式,完成語法分析的過程 //getch(); } /*呼叫各種遞迴子程式,完成語法分析的過程*/ void parser(void) { if(syn==1)//begin { scaner(); /*讀下一個單詞符號*/ yucu(); /*呼叫yucu()函式;*/ if(syn==6)//end { scaner(); if((syn==0)&&(flag==0))//出現#且flag=0 printf("success!\n"); } else { if(flag!=1) printf("the string haven't got a 'end'!\n");//flag來判斷是否end flag=1; } } else { printf("haven't got a 'begin'!\n"); flag=1; } return; } void yucu(void) { statement(); /*呼叫函式statement();*/ while(syn==26)//分號 { scaner(); /*讀下一個單詞符號*/ if(syn!=6) statement(); /*呼叫函式statement();*/ } return; } void statement(void) { if(syn==10) { scaner(); /*讀下一個單詞符號*/ if(syn==18) { scaner(); /*讀下一個單詞符號*/ expression(); /*呼叫函式expression();*/ } else { printf("the sing ':=' is wrong!\n"); flag=1; } } else { printf("wrong sentence!\n"); flag=1; } return; } void expression(void) { term(); while((syn==13)||(syn==14)) { scaner(); /*讀下一個單詞符號*/ term(); /*呼叫函式term();*/ } return; } void term(void) { factor(); while((syn==15)||(syn==16)) { scaner(); /*讀下一個單詞符號*/ factor(); /*呼叫函式factor(); */ } return; } void factor(void)//因式處理函式 { if((syn==10)||(syn==11))//識別符號,數字 { scaner(); } else if(syn==27)//開頭是左括號( { scaner(); /*讀下一個單詞符號*/ expression(); /*呼叫函式statement();*/ if(syn==28)//出現右括號) { scaner(); /*讀下一個單詞符號*/ } else { printf("the error on '('\n"); flag=1; } } else { printf("the expression error!\n"); flag=1; } return; } /*主要完成賦值種別碼等詞法分析功能*/ void scaner(void)//掃描器,詞法分析器內容 { sum=0;//數字初始化為0 for(m=0;m<8;m++)//初始化token token[m++]=NULL; m=0;//m為token的指標 ch=prog[p++];//陣列指標+1 while(ch==' ')//遇到空格+1 ch=prog[p++]; if(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A')))//遇到字母 { while(((ch<='z')&&(ch>='a'))||((ch<='Z')&&(ch>='A'))||((ch>='0')&&(ch<='9'))) { token[m++]=ch; ch=prog[p++];//p+1,下次迴圈使用 } p--;//迴圈跳出,要-1 syn=10;//10,字母開頭 token[m++]='\0';//\0為字串結束符 /*判別是否為關鍵字*/ for(n=0;n<6;n++)//n為rwtab的指標 if(strcmp(token,rwtab[n])==0)//strcmp返回值為0,則兩個引數大小相同 { syn=n+1; break; } } else if((ch>='0')&&(ch<='9'))//遇到數字 { while((ch>='0')&&(ch<='9')) { sum=sum*10+ch-'0'; ch=prog[p++]; } p--;//回溯 syn=11;//11為數字 } /*除數字和字母開頭以外的其他符號*/ else switch(ch) { case '<': m=0; ch=prog[p++]; if(ch=='>') { syn=21; } else if(ch=='=') { syn=22; } else { syn=20; p--;//回溯 } break; case '>': m=0; ch=prog[p++]; if(ch=='=') { syn=24; } else { syn=23; p--; } break; case ':': m=0; ch=prog[p++]; if(ch=='=') { syn=18; } else { syn=17; p--; } break; case '+': syn=13; break; case '-': syn=14; break; case '*': syn=15; break; case '/': syn=16; break; case '(': syn=27; break; case ')': syn=28; break; case '=': syn=25; break; case ';': syn=26; break; case '#': syn=0; break; default: syn=-1; break; } }