編譯技術實驗報告
實驗題目:
詞 詞 法分析
學 學
院:
信息學院
專 專
業(yè):
計算機科學與技術
學 學
號:
姓 姓
名:
一、 實驗目的
(1) 理解詞法分析的功能;
(2) 理解詞法分析的實現(xiàn)方法;
二 、 實驗內(nèi)容
PL0 的文法 如下
„< >?為非終結符。
„::=? 該符號的左部由右部定義,可讀作“定義為”。
„|? 表示„或?,為左部可由多個右部定義。
„{ }? 表示花括號內(nèi)的語法成分可以重復。在不加上下界時可重復0到任意次數(shù),有上下界時可重復次數(shù)的限制。
„[ ]? 表示方括號內(nèi)的成分為任選項。
„( )? 表示圓括號內(nèi)的成分優(yōu)先。
上述符號為“元符號”, 文法用上述符號作為文法符號時需要用引號„?括起。
〈程序〉∷=〈分程序〉.
〈分程序〉∷= [〈變量說明部分〉][〈過程說明部分〉]〈語句〉
〈變量說明部分〉∷=VAR〈標識符〉{,〈標識符〉}:INTEGER;
〈無符號整數(shù)〉∷=〈數(shù)字〉{〈數(shù)字〉}
〈標識符〉∷=〈字母〉{〈字母〉|〈數(shù)字〉}
〈過程說明部分〉∷=〈過程首部〉〈分程序〉{;〈過程說明部分〉};
〈過程首部〉∷=PROCEDURE〈標識符〉;
〈語句〉∷=〈賦值語句〉|〈條件語句〉|〈過程調用語句〉|〈讀語句〉|〈寫語句〉|〈復合語句〉|〈空〉
〈賦值語句〉∷=〈標識符〉∶=〈表達式〉
〈復合語句〉∷=BEGIN〈語句〉{;〈語句〉}END
〈條件〉∷=〈表達式〉〈關系運算符〉〈表達式〉
〈表達式〉∷=〈項〉{〈加法運算符〉〈項〉}
〈項〉∷=〈因子〉{〈乘法運算符〉〈因子〉}
〈因子〉∷=〈標識符〉|〈無符號整數(shù)〉|"("〈表達式〉")"
〈加法運算符〉∷=+|-
〈乘法運算符〉∷=*
〈關系運算符〉∷=<>|=|<|<=|>|>=
〈條件語句〉∷=IF〈條件〉THEN〈語句〉
〈字母〉∷=a|b|…|X|Y|Z
〈數(shù)字〉∷=0|1|2|…|8|9
現(xiàn) 實現(xiàn) PL0 的 的 詞法分析
三 、 實驗 分析與設計
PL0 詞法分析程序是一個獨立的過程,其功能是為語法語義分析提供單詞,把輸入的字符串形式的源程序分割成一個個單詞符號傳遞給語
法語義分析。
其主要方法步驟為從源程序掃描下一個字符,忽略空格、換行、TAB和注釋并識別單詞,再將不同類別的單詞歸類輸出。
四 、實驗 的 實現(xiàn)
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#include<stdbool.h>
#definenorw 11
//norw-1個關鍵字
#defineal 20
//最長的關鍵字的長度
#define ID norw
#define INT norw+1
#define COMMA norw+2
#define ENDF norw+3
#define COLON norw+4
#define SEMIC norw+5
#define ADD norw+6
#define MINUS norw+7
#define MULTI norw+8
#define EVALU norw+9
#define LE norw+10
#define NE norw+11
#define LT norw+12
#define EQ norw+13
#define GE norw+14
#define GT norw+15
#define FLOAT norw+16
char TOKEN[20];
//字符數(shù)組用來依次存放單詞詞文的各個字符
extern int lookup(char *);
//以TOKEN字符串查保留字表
extern void report_error(char);
//報告程序中的詞法錯誤
bool isalpha(char);
//判斷接收字符是否為字母
bool isalnum(char);
//判斷接收字符是否為字母或者數(shù)字
bool isdigit(char);
//判斷接收字符是否為數(shù)字
bool isannotation(char);
//判斷接收字符是否為注釋
extern char letter(char c); //用來將大寫字母轉化成小寫字母
FILE* fin;
FILE* fout;
void scanner()
{//詞法分析的主體程序,對輸入的文本文件進行詞法分析
char ch;
int i,c;
int error=0;
//記錄文件中詞法錯誤的個數(shù)
ch=fgetc(fin);
//從輸入文件中讀取一個字符
while(ch!=EOF)
{//當從輸入文件接收的字符不是文件結束符時,執(zhí)行循環(huán)
if(isalpha(ch))
{//如果從輸入文件接收的第一個字符是字母
ch=letter(ch);
TOKEN[0]=ch;
ch=fgetc(fin);i=1;
while(isalnum(ch))
{
ch=letter(ch);
TOKEN[i]=ch;i++;
ch=fgetc(fin);
}
TOKEN[i]="\0";
c=lookup(TOKEN);
//查保留字表
if(c==0) {fprintf(fout,"(%d,%s)\n", ID,TOKEN);} //輸出標識符
else fprintf(fout,"(%d,%s)\n", c,TOKEN);
//輸出接收單詞為保留字
}
if(isdigit(ch))
//如果從輸入文件接收的第一個字符是數(shù)字
{
int cdot=0;
//統(tǒng)計小數(shù)點個數(shù)
TOKEN[0]=ch;
ch=fgetc(fin);i=1;
while(isdigit(ch)||ch==".")
{//從第二個接收字符開始,當是數(shù)字或者是小數(shù)點時,執(zhí)行循環(huán)
if(ch==".")
cdot++;
TOKEN[i]=ch;i++;
ch=fgetc(fin);//重復接收字符,直到接收到非數(shù)字
if(cdot>=2)
{
error++;
TOKEN[i]="\0";
printf("%s is error\n", TOKEN);
break;
}
}
if(isalpha(ch)) //如果第二個字符是字母
{
while(isalpha(ch)) //接收完所有的字母,跳出循環(huán)
{
TOKEN[i]=ch;i++;
ch=fgetc(fin);
}
TOKEN[i]="\0";
error++;
printf("%s is error\n", TOKEN);
}
else if(cdot==0)
//當接收的字符為整型單詞時
{
fseek(fin,-1,1);
TOKEN[i]="\0";
int a,temp=0,c;
for(c=0;c<i;c++)
{
a=TOKEN[c] - "0";
if(c!=0)
{
temp=temp*10;
temp=temp+a;
}
else
{
temp=a;
}
}
fprintf(fout,"(%d,%d)\n", INT, temp);
//輸出接收單詞為整數(shù)
}
else if(cdot==1)
{
fseek(fin,-1,1);
TOKEN[i]="\0";
int a,part1=0,jc,b=0;
//b用來確定小數(shù)點所在的位置
float c=0.1,part2=0.0;
while(TOKEN[b]!=".")
{
b=b+1;
}
for(jc=0;jc<b;jc++)
{
a=TOKEN[jc] - "0";
if(jc!=0)
{
part1=part1*10;
part1=part1+a;
}
else
{
part1=a;
}
}
for(jc=b+1;jc<i;jc++)
{
a=TOKEN[jc]-"0";
part2=a*c+part2;
c=c*0.1;
}
fprintf(fout,"(%d,%f)\n", FLOAT, part1+part2);
//輸出接收單詞為小數(shù)
}else if(cdot==2)
{
fseek(fin,-1,1);
}
}
else
//如果從輸入文件接收的第一個字符既不是字母又不是數(shù)字
switch(ch)
{//將所接收到的符號字符進行分類,采取一符一類
case":":ch=fgetc(fin);
if(ch=="=") fprintf(fout,"(%d,:=)\n", EVALU);
//輸出接收符號為賦值號
else
{ch=fgetc(fin);
fseek(fin,-1,1);
//文件接收字符回推一個字符
fprintf(fout,"(%d,":")\n", COLON);
//輸出冒號
}
break;
case",":fprintf(fout,"(%d,",")\n", COMMA); break;
//輸出逗號
case".":fprintf(fout,"(%d,".")\n", ENDF);break;
//輸出句號
case";":fprintf(fout,"(%d,".")\n", SEMIC);break;
//輸出分號
case"+":fprintf(fout,"(%d,"+")\n", ADD);break;
//輸出加號
case"-":fprintf(fout,"(%d,"-")\n", MINUS);break;
//輸出減號
case"*":fprintf(fout,"(%d,"*")\n", MULTI);break;
//輸出乘號
case"<":ch=fgetc(fin);
if(ch=="=")fprintf(fout,"(%d,"<=")\n", LE);
//輸出小于或等于號
else if(ch==">")fprintf(fout,"(%d,"<>")\n", NE);
//輸出不等于號
else
{
fseek(fin,-1,1);
fprintf(fout,"(%d,"<")\n", LT);;
//輸出小于號
}
break;
case"=":fprintf(fout,"(%d,"=")\n", EQ);break;
//輸出等于號
case">":ch=fgetc(fin);
if(ch=="=")fprintf(fout,"(%d,">=")\n", GE);
//輸出大于或等于號
else
{
fseek(fin,-1,1);
fprintf(fout,"(%d,">")\n", GT);
//輸出大于號
}
break;
case" ":break;
case"\n":break;
case"\t":break;
case"/":ch=fgetc(fin);//檢查是否為單行注釋
if(ch=="/"){
while(ch!="\n"){
ch=fgetc(fin);
}
}
else {
fseek(fin,-1,1);
printf("/ is error\n");
error++;
}
break;
case"{":
while(1){
ch=fgetc(fin);
if(ch=="}") break;
if(ch==EOF)
{
fseek(fin,-1,1);
printf("{
is error\n");
error++;
break;
}
}
break;
default:printf("%c is error\n", ch);
//接收非上述字符程序報告詞法錯誤
error++;break;
}
ch=fgetc(fin);
//繼續(xù)從文件中讀取下一個單詞,直到文件結束
}//while循環(huán)結束
printf("共發(fā)現(xiàn)%d 個詞法錯誤!",error);
return;
}
int lookup(char *token)
{
int j;
char word[norw][al];
strcpy(&(word[1][0]), "begin" );
strcpy(&(word[2][0]), "end");
strcpy(&(word[3][0]), "var");
strcpy(&(word[4][0]), "integer");
strcpy(&(word[5][0]), "while");
strcpy(&(word[6][0]), "do");
strcpy(&(word[7][0]), "if");
strcpy(&(word[8][0]), "then");
strcpy(&(word[9][0]), "procedure");
strcpy(&(word[10][0]), "else");
for(j=1;j<=norw-1;j++)if(strcmp(token,word[j])==0) return j;
//以TOKEN字符串查保留字表,若查到返回保留字類別碼
return 0;
//TOKEN不是保留字,返回0
}
bool isalpha(char c)
{ //判斷接收字符是否為字母
if((c>="a"&&c<="z")||(c>="A"&&c<="Z"))return 1;
else return 0;
}
bool isalnum(char c)
{//判斷接收字符是否為字母或者數(shù)字
if((c>="a"&&c<="z")||(c>="A"&&c<="Z")||(c>="0"&&c<="9"))return 1;
else return 0;
}
bool isdigit(char c)
{//判斷接收字符是否為數(shù)字
if(c>="0"&&c<="9")return 1;
else return 0;
}
char letter(char c) //將大寫字母轉換成小寫字母,即不區(qū)分大小寫
{
if(c>="A"&&c<="Z")
{
c=c+32;
}
return c;
}
int main()
{
char filename[20];
printf("請輸入文件名:");
scanf("%s",filename);
if((fin=fopen(filename,"r"))==NULL) //打開要讀取的文本文件
{
printf("不能打開文件.\n");
exit(0);
}
printf("請輸入保存分析結果的文件名:");
scanf("%s",filename);
if((fout=fopen(filename,"w"))==NULL)
{
printf("不能打開文件.\n");
exit(0);
}
scanner();
//調用詞法分析程序
//getchar();getchar();
fclose(fin);
fclose(fout);
return 0;
}
五 、 運行的結果
推薦訪問: 實驗 詞法 編譯在偉大祖國73華誕之際,我參加了單位組織的“光影鑄魂”主題黨日活動,集中觀看了抗美援朝題材影片《長津湖》,再一次重溫這段悲壯歷史,再一次深刻感悟偉大抗美援朝精神。1950年10月,新中國剛剛成立一年,
根據(jù)省局黨組《關于舉辦習近平談治國理政(第四卷)讀書班的通知》要求,我中心通過專題學習、專題研討以及交流分享等形式,系統(tǒng)的對《習近平談治國理政》(第四卷)進行了深入的學習與交流,下面我就來談一談我個人
《習近平談治國理政》(第四卷)是在百年變局和世紀疫情相互疊加的大背景下,對以習近平同志為核心的黨中央治國理政重大戰(zhàn)略部署、重大理論創(chuàng)造、重大思想引領的系統(tǒng)呈現(xiàn)。它生動記錄了新一代黨中央領導集體統(tǒng)籌兩個
《真抓實干做好新發(fā)展階段“三農(nóng)工作”》是《習近平談治國理政》第四卷中的文章,這是習近平總書記在2020年12月28日中央農(nóng)村工作會議上的集體學習時的講話。文章指出,我常講,領導干部要胸懷黨和國家工作大
在《習近平談治國理政》第四卷中,習近平總書記強調,江山就是人民,人民就是江山,打江山、守江山,守的是人民的心。從嘉興南湖中駛出的小小紅船,到世界上最大的執(zhí)政黨,在中國共產(chǎn)黨的字典里,“人民”一詞從來都
黨的十八大以來,習近平總書記以馬克思主義戰(zhàn)略家的博大胸襟和深謀遠慮,在治國理政和推動全球治理中牢固樹立戰(zhàn)略意識,在不同場合多次圍繞戰(zhàn)略策略的重要性,戰(zhàn)略和策略的關系,提高戰(zhàn)略思維、堅定戰(zhàn)略自信、強化戰(zhàn)
《習近平談治國理政》第四卷集中展示了以習近平同志為核心的黨中央在百年變局和世紀疫情相互疊加背景下,如何更好地堅持和發(fā)展中國特色社會主義而進行的生動實踐與理論探索;對于新時代堅持和發(fā)展什么樣的中國特色社
在黨組織的關懷下,我有幸參加了區(qū)委組織部組織的入黨積極分子培訓班。為期一周的學習,學習形式多樣,課程內(nèi)容豐富,各位專家的講解細致精彩,對于我加深對黨的創(chuàng)新理論的認識、對黨的歷史的深入了解、對中共黨員的
《習近平談治國理政》第四卷《共建網(wǎng)上美好精神家園》一文中指出:網(wǎng)絡玩命是新形勢下社會文明的重要內(nèi)容,是建設網(wǎng)絡強國的重要領域。截至2021年12月,我國網(wǎng)民規(guī)模達10 32億,較2020年12月增長4
剛剛召開的中國共產(chǎn)黨第十九屆中央委員會第七次全體會議上討論并通過了黨的十九屆中央委員會向中國共產(chǎn)黨第二十次全國代表大會的報告、黨的十九屆中央紀律檢查委員會向中國共產(chǎn)黨第二十次全國代表大會的工作報告和《