编译原理中词法分析--部分实现
一.前言
某屬于在校大學(xué)生,幾天前老師布置了一個編譯原理作業(yè),將詞法分析–部分實現(xiàn),頭疼,眾所周之,編譯原理是計算機專業(yè)中最令人頭疼的課程,聽懂已經(jīng)很不容易了,TMD讓我用C語言實現(xiàn) ,頭大。經(jīng)過幾個小時寫了一個大概,已經(jīng)完成了老師的初步要求。廢話不多說。直接干!!
二.要求及內(nèi)容
一、授課內(nèi)容:
 (一) 授課科目:編譯原理
 (二) 授課內(nèi)容:實驗一 詞法分析
 (三) 授課類型:實 驗
 (四) 授課時間:4學(xué)時(計劃)
 二、教學(xué)目的要求:
 1.目的:通過設(shè)計、編制、調(diào)試一個具體的詞法分析程序加深對詞法分析原理的理解,并掌握在對程序設(shè)計語言源程序進行掃描過程中將其分解為各類單詞的詞法分析方法。
 2.要求:
 (1)選擇在國際國內(nèi)有代表性的高級程序設(shè)計語言的源程序作為詞法分析對象。
 (2)根據(jù)數(shù)學(xué)要求和學(xué)生具體情況,從上列語言之一中選取一個適當大小的子集,可以選取一類典型單詞,也可以盡可能使各種類型的單詞都能兼顧到。
 三、教學(xué)設(shè)想:
 1.教學(xué)方法設(shè)想:先以例子講解,然后學(xué)生動手實驗,實驗為主。
 2.教具運用設(shè)想:多媒體。
 四、教學(xué)過程:
 1. 題目 試用直接分析方法編制C語言子集的詞法分析程序。其BNF定義如下:
 〈PASCAL子集程序〉::=〈變量說明〉BEGIN〈語句表〉ENG。
 〈變量說明〉::=〈空〉| VAR〈變量表〉:〈類型〉
 〈變量表〉::=〈變量〉|〈變量表〉,〈變量〉
 〈類型〉::=〈標識符〉
 〈語句表〉::=〈語句〉|〈語句表〉〈語句〉
 〈語句〉::=〈賦值語句〉|〈條件語句〉|〈WHILE語句〉|〈復(fù)合語句〉|〈過程定義〉
 〈賦值語句〉::=〈變量〉::=〈算術(shù)表達式〉
 〈條件語句〉::=〈IF〉〈布爾表達式〉THEN〈語句〉ELSE〈語句〉
 〈WHILE語句〉::=WHILE〈布爾表達式〉DO〈語句〉
 〈復(fù)合語句〉::=BEGIN〈語句表〉END
 〈過程定義〉::=PROCEDURE〈標識符〉〈參數(shù)表〉BEGIN〈語句表〉END
 〈參數(shù)表〉::=〈空〉|(〈標識符表〉)
 〈標識符表〉::=〈標識符〉|〈標識符表〉,〈標識符〉
 〈算術(shù)表達式〉::=〈項〉|〈算術(shù)表達式〉+〈項〉
 〈項〉::=〈初等量〉|〈項〉*〈初等量〉
 〈初等量〉::=〈無符號數(shù)〉|〈變量〉|(〈算術(shù)表達式〉)
 〈布爾表達式〉::=〈算術(shù)表達式〉〈關(guān)系符〉〈算術(shù)表達式〉
 〈變量〉::=〈標識符〉
 〈標識符〉::=〈字母〉|〈標識符〉〈字母〉|〈標識符〉〈數(shù)字〉
 〈無符號數(shù)〉::=〈數(shù)字〉|〈無符號數(shù)〉〈數(shù)字〉
 〈關(guān)系符〉::=〈 = |〈 〉| 〉
 〈字母〉::=A | B| C| D| E | F| G | H | I | J | K | L| M | N | O | P|Q | R |S | T| U| V| W| X| Y| Z
 〈數(shù)字〉::=0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
 〈空〉::=
 詞法分析是編譯程序的第一個處理階段。這里所謂直接分析方法,即自左至右掃描源程序,一旦發(fā)現(xiàn)有獨立意義的字符串時,立即將其改造成長度統(tǒng)一的最小語法單位,同時查填各類單詞表格并做一些語法檢查,為以后的語法分析提供方便。
 具體的處理過程是,在掃描字符串時,一旦識別出關(guān)鍵字(K)、標識符(I)、常數(shù)(C)和界符(P)中之一,即以單詞形式(剔去多余的空白符)輸出。每次調(diào)用詞法分析程序,它均能自動繼續(xù)掃描下去,形成下一個單詞,直至整個源程序全部掃描完畢,習(xí)慣年成相應(yīng)的單詞串。
 各類單詞均有相同的結(jié)構(gòu)和長度。每個單詞由兩部分組成: (t, i)
 其中t表示單詞種類。共分四類,即K類、I類、C類和P類。每類對應(yīng)一種表格,分別存放該類各個不同的單詞。I為指向該類表格一個特定項目的指針。因此,(t, i)唯一地確定了一個單詞。
 K,P兩種表格的內(nèi)容取決于所選語言的子集,而I,C兩種表格則是根據(jù)臨時輸入的源程序字符串形成的。
 2.算法 詞法分析程序在掃描過程中,依次從源程序驅(qū)除源字符,并根據(jù)第一個字符(有時還需多讀一個字符)判斷屬于K,I,C,P中的哪一類單詞,確定單詞的t和i 。在詞法分析過程中,K、P兩表是固定不變的(由語言來確定),源程序字符串只能從其中選取。I、C兩表是在分析過程中不斷形成的。其詞法分析的算法如圖2-7-2所示。
 為了防止實習(xí)良過大,達不到實習(xí)的目的,實習(xí)時采用的數(shù)據(jù)結(jié)構(gòu)在不同程度上均應(yīng)作適當?shù)暮喕?#xff0c;所選的關(guān)鍵字(K)和界符表(P)
 如表2-7-1和表2-7-2所示
關(guān)鍵字表包括九個代表性的關(guān)鍵字。界符表包括關(guān)系運算符三種(其中小于等于和不等于均系由兩個字符組成的符合字符),算術(shù)運算符和分隔符各兩種,圓括號一對,加上賦值號共十一種。這兩個表的內(nèi)容表明,PASCAL語言的賦值語句、條件語句、WHILE型循環(huán)語句、復(fù)合語句過程及變量說明均可作為源程序例子輸入給詞法分析程序。標識符表中的每一項包含一個標識符。常數(shù)表中的每一項包含一個整常數(shù)。后兩表都是在詞法分析過程中產(chǎn)生的。
 三.說明
 本程序是對C語言進行詞法分析,對老師的要求進行了改編
 ci 常數(shù)表
 k 關(guān)鍵字表
 id 標識符表
 p 界符表
 實現(xiàn)功能(在基本功能之上):
 1.可以分析小數(shù)
 2.可以循環(huán)
 3. 可以識別標識符
 附圖:
 
 
四.實現(xiàn)
#include <stdio.h> #include<math.h> #define keylen 10 #define identlen 10 #include<stdlib.h> typedef struct {char ty;int point; } outreco; char flag_a; int flag=1;//標志位,1為繼續(xù),0為不繼續(xù) int cip=0,ip=0,pint=0,i,j,l,m,errors=0; char char1; double ci[10]={0,0,0,0,0,0,0,0,0,0}; char k[10][10]={"begin","while","for","if","else","long","case","do","main","int"},id[10][10]={""},token[10]={' '},instring[80]; char p[11][3]={"<=","<>","<","(","*","==","=","+",")",";",","}; outreco outtoken; void GetChar() {char1=instring[pint];pint++; }void error() {errors=1;printf("error!\n");system("PAUSE");// pint++; }void lexical()//詞法分析 {double num;int l,m=0,_num,b,i,len=0;for(i=0;i<identlen;i++) token[i]='\0';errors=0;GetChar();while(char1==' ') GetChar(); //過濾空格 if(char1>='a'&&char1<='z'||char1>='A'&&char1<='Z'||char1=='_') {while(char1>='a'&&char1<='z'||char1>='0'&&char1<='9'||char1>='A'&&char1<='Z'||char1=='_'){if(m<identlen){token[m]=char1;m++;}GetChar();} //end of whilepint--;l=0;b=0;while(l<keylen && !b)//屬于關(guān)鍵字情況 {b=1;i=0;while(i<identlen && b)if( k[l][i]==token[i]) i++;else b=0;if(!b) l++;} //end of whileif(l<keylen){outtoken.ty='k';outtoken.point=l+1;}else //屬于標識符的情況{l=0;b=0;while(l<ip && !b){b=1;i=0;while(i<identlen && b)if( id[l][i]==token[i]) i++;else b=0;if(!b) l++;} //end of whileif(l<ip){outtoken.ty='i';outtoken.point=l+1;}else if(l>=ip)//標識符表中沒有此標識符 {for(m=0;m<identlen;m++)id[ip][m]=token[m];ip=ip+1;outtoken.ty='i';outtoken.point=l+1;}}} //end of if characterelse if(char1 >='0'&&char1<='9'||char1=='.'){num=0;_num=0;//存放小數(shù)部分 while(char1 >='0'&&char1<='9'){num=num*10+char1-'0'; //整數(shù) token[m++]=char1;GetChar();}if(char1=='.'){GetChar();while(char1 >='0'&&char1<='9'){_num=_num*10+char1-'0'; //小數(shù)部分 len++;token[m++]='.';token[m++]=char1;GetChar();}pint--;num=num+_num/(pow(10,len));}l=-1;do{l++;}while(l<cip && num!=ci[l]);if(l==cip) //識別出一個新的數(shù){ci[l]=num;cip++;}outtoken.ty='c';outtoken.point=l+1;} //識別實數(shù)的過程結(jié)束else if( char1=='<'||char1=='('||char1=='*'||char1=='='||char1=='+'||char1==')'||char1==';'||char1==','){outtoken.ty='p';token[m++]=char1;switch(char1){case '<':GetChar();if(char1!='='&&char1!='>'){ outtoken.point=3;pint--;}else {if(char1=='=') outtoken.point=1;else outtoken.point=2 ;token[m++]=char1;}break;case '(':outtoken.point=4;break;case '*':outtoken.point=5;break;case '=':GetChar();if(char1=='='){ token[m++]=char1;outtoken.point=6;}else{outtoken.point=7;pint--;}break;case '+':outtoken.point=8;break;case ')':outtoken.point=9;break;case ';':outtoken.point=10;break;case ',':outtoken.point=11;break;}//end of switch} //end of if pelse error();} // end of lexicalvoid main(){//int i;ip=0;cip=0;pint=0;printf("\t******************按@鍵退出*********************************\n"); printf("\tK:"); for(i=0;i<10;i++)printf("%6s",k[i]); printf("\n"); printf("\t**************************************************************\n"); printf("\tP:"); for(i=0;i<11;i++)printf("%5s",p[i]); printf("\n"); printf("\t**************************************************************\n"); printf("source, input!\n");//scanf("%s",instring);gets(instring); // pint=0; // if(instring[pint]=='@'){ // break; // }do{lexical();if(!errors){printf("(%c,%2d)\n",outtoken.ty,outtoken.point);//以二元組的形式輸出單詞printf("識別的單詞為:%s\n",token);}}while(instring[pint]!='\0');system("PAUSE");while(1){//ip=-1;//cip=0;//pint=0; // printf("continue?y/n:\n"); // scanf("%c",&flag_a); // getchar(); // if(flag_a=='y') // { // flag=1; // } // else // { // flag=0; // break; // } system("CLS");printf("\t******************按@鍵退出*********************************\n");printf("\tK:"); for(i=0;i<10;i++)printf("%6s",k[i]);printf("\n"); printf("\t**************************************************************\n");printf("\tP:"); for(i=0;i<11;i++)printf("%5s",p[i]);printf("\n"); printf("\t**************************************************************\n");printf("\ti:"); for(i=0;i<10;i++)printf("%6s",id[i]);printf("\n"); printf("\t**************************************************************\n");printf("\tC:"); for(i=0;i<cip;i++)printf("%6g",ci[i]);printf("\n"); printf("\t**************************************************************\n");printf("source, input!\n");//scanf("%s",instring);for(i=0;i<80;i++) instring[i]='\0';//fflush(stdin);//清除緩存區(qū)讓gets可以讀取鍵盤輸入的數(shù)據(jù) gets(instring);pint=0;if(instring[pint]=='@'){break;}do{lexical();if(!errors){printf("(%c,%2d)\n",outtoken.ty,outtoken.point);//以二元組的形式輸出單詞printf("識別的單詞為:%s\n",token);}}while(instring[pint]!='\0');system("PAUSE");}}總結(jié)
以上是生活随笔為你收集整理的编译原理中词法分析--部分实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: shell脚本判断上一个命令是否执行成功
- 下一篇: JAVA面试整理之——JAVA基础
