編譯原理實驗之源程式的預處理及詞法分析程式設計
題目要求:
1、實現預處理功能
源程式中可能包含有對程式執行無意義的符號,要求將其剔除。
首先編制一個源程式的輸入過程,從鍵盤、檔案或文字框輸入若干行語句,依次存入輸入緩衝區(字元型資料);然後編制一個預處理子程式,去掉輸入串中的回車符、換行符和跳格符等編輯性文字;把多個空白符合併為一個;去掉註釋。
2、實現詞法分析功能
輸入:所給文法的源程式字串。
輸出:二元組(syn,token或sum)構成的序列。其中,
syn為單詞種別碼。
Token為存放的單詞自身字串。
Sum為整型常量。
具體實現時,可以將單詞的二元組用結構進行處理。
3、待分析的C語言子集的詞法
1)關鍵字
main if then while do static int double struct break else long switch case typedef char return const float short continue for void default sizeof do
所有的關鍵字都是小寫。
2)運算子和界符
+ - * / : := < <> <= > >= = ; ( ) #
3)其他標記ID和NUM
通過以下正規式定義其他標記:
ID→letter(letter|digit)*
NUM→digit digit*
letter→a|…|z|A|…|Z
digit→0|…|9…
4)空格由空白、製表符和換行符組成
空格一般用來分隔ID、NUM、專用符號和關鍵字,詞法分析階段通常被忽略。
4、各種單詞符號對應的種別碼
表1 各種單詞符號的種別碼
單詞符號 種別碼 單詞符號 種別碼
main 1 ; 41
if 2 ( 42
then 3 ) 43
while 4 int 7
do 5 double 8
static 6 struct 9
ID 25 break 10
NUM 26 else 11
+ 27 long 12
- 28 switch 13
* 29 case 14
/ 30 typedef 15
: 31 char 16
:= 32 return 17
< 33 const 18
<> 34 float 19
<= 35 short 20
> 36 continue 21
>= 37 for 22
= 38 void 23
default 39 sizeof 24
do 40 # 0
題目要求如上,鄙人自己寫的如下(這是早幾個月前寫的,沒有再檢查對錯,由於當初老師給的實驗要求就有問題所以裡面的會有一些小問題不影響,且鄙人寫程式碼習慣寫註釋比較好理解):
第一步程式碼:
#include<stdio.h>
#include<String.h>
int main(){
FILE *p;
int falg = 0,len,i=0,j=0;//
char str[1000],str1[1000],c;
if((p=fopen("e:\\test.txt","rt"))==NULL){
printf("無法開啟");
return 0;
}
else{
//fgets(str,1000,p);
while((c=getc(p))!=EOF){
str[i++] = c;
}
fclose(p);
str[i] = '\0';
for(i=0;i<strlen(str);i++){
if(str[i]=='/'&&str[i+1]=='/'){
while(str[i++]!='\n'){}
}//單行註釋
else if(str[i]=='/'&&str[i+1]=='*'){
while(!(str[i]=='*'&&str[i+1]=='/')){i++;}
i+=2;
}//多行註釋
else if(str[i]==' '&&str[i+1]==' '){
while(str[i]==' '){i++;}
i--;
if(str1[j-1]!=' ')
str1[j++]=' ';
}//多個空格,去除空格
else if(str[i]=='\n') {
if(str1[j-1]!=' ')
str1[j++]=' ';
}//換行處理,
else if(str[i]==9){
while(str[i]==9){
i++;
}
if(str1[j-1]!=' ')
str1[j++]=' ';
i--;
}//tab鍵處理
else str1[j++] = str[i];//其他字元處理
}
str1[j] = '\0';
// printf("%s\n",str);
// printf("%s\n",str1);
/*
for(int k=0;k<strlen(str1);k++){
if(str1[k]!=' ')
printf("%c",str1[k]);
else printf("_");
}
*/
if((p = fopen("e:\\test1.txt","w"))==NULL){
printf("can not find it!");
return 0;
}
else{
if(fputs(str1,p)!=0){
printf("儲存失敗!");
}
else printf("儲存成功!");
}
fclose(p);
}
return 0;
}
第二部分程式碼:
#include<stdio.h>
#include<String.h>
int main(){
FILE *p;
int falg = 0,len,i=0,j=0;//
char *rwtab[27]={"","main","if","then","while","do",
"static","int","double","struct","break","else","long",
"switch","case","typedef","char","return","const","float",
"short","continue","for","void","sizeof","default","do"};//26個
char str[1000],str1[1000],c;
int syn,num;
char token[200];
if((p=fopen("e:\\test1.txt","rt"))==NULL){
printf("無法開啟");
return 0;
}
//fgets(str,1000,p);
while((c=getc(p))!=EOF){
str[i++] = c;
}
fclose(p);
if((p=fopen("e:\\test2.txt","w"))==NULL){
printf("無法開啟");
return 0;
}
str[i] = '\0';
//printf("%s\n",str);
for(i=0;str[i]!='\0';){
j = 0;
num = -1;
if((str[i]>='a'&&str[i]<='z')||(str[i]>='A'&&str[i]<='Z')||str[i]=='_'){
while((str[i]>='a'&&str[i]<='z')||(str[i]>='A'&&str[i]<='Z')||(str[i]>='0'&&str[i]<='9')||str[i]=='_'){
token[j++] = str[i++];
}
token[j] = '\0';
for(int k=1;k<27;k++){
if(strcmp(rwtab[k],token)==0)
break;
}
if(k<25)
syn = k;
else if(k==25)
syn = 39;
else if(k==26)
syn = 40;
else syn = 25;
}//關鍵字和標示符處理
else if((str[i]>='0'&&str[i]<='9')&&((str[i+1]>='a'&&str[i+1]<='z')||
(str[i+1]>='A'&&str[i+1]<='Z')||str[i+1]=='_'||(str[i+1]>='0'&&str[i+1]<='9'))){
syn = -3;
while((str[i]>='a'&&str[i]<='z')||
(str[i]>='A'&&str[i]<='Z')||str[i]=='_'||(str[i]>='0'&&str[i]<='9')){
token[j++] = str[i++];
}
i--;
}
else if(str[i]>='0'&&str[i]<='9'){
num = 0;
while(str[i]>='0'&&str[i]<='9'){
num = num*10+str[i++]-'0';
}
syn = 26;
}//數字在此處處理
else {//printf("%c********************************\n",str[i]);
if(str[i]==':'&&str[i+1]=='='){
syn = 32;
token[j++] = str[i];
token[j++] = str[i++];
}
else if(str[i]=='<'&&str[i+1]=='>'){
syn = 34;
token[j++] = str[i];
token[j++] = str[i++];
}
else if(str[i]=='<'&&str[i+1]=='='){
syn = 35;
token[j++] = str[i];
token[j++] = str[i++];
}
else if(str[i]=='>'&&str[i+1]=='='){
syn = 36;
token[j++] = str[i];
token[j++] = str[i++];
}
else if(str[i]==' '){
i++;
syn = -2;
}//空格處理
/*
else if(str[i]!=' '){
syn = -1;
while(str[i++]!=' '){
token[j++] = str[i];
}
}//不明字元的處理
*/
else{
switch(str[i]){
case '+': syn = 27;break;
case '-': syn = 28;break;
case '*': syn = 29;break;
case '/': syn = 30;break;
case ':': syn = 31;break;
case '<': syn = 33;break;
case '>': syn = 36;break;
case ';': syn = 41;break;
case ')': syn = 43;break;
case '(': syn = 42;break;
case '#': syn = 0;break;
case '=':syn = 38;break;
default: syn = -1;break;
}
//printf("%c********************************\n",str[i]);
token[j++] = str[i++];
}
}
token[j] = '\0';
if(num!=-1){
printf("%d %d\n",num,syn);
fprintf(p,"%d %d\n",num,syn);
char A[100];
int i=0;
while(num){
A[i++] = num%2;
num = num/2;
}
for(i--;i>=0;i--){
printf("%c ",A[i]+'0');
fprintf(p,"%c ",A[i]+'0');
}
printf(" %d\n",syn);
fprintf(p,"%d\n",syn);
}
else if(syn!=-1&&syn !=-2 &&syn!=-3){
printf("%s %d\n",token,syn);
fprintf(p,"%s %d\n",token,syn);
}
else if(syn==-1){
printf("%s error\n",token);
fprintf(p,"%s error\n",token);
}
else if(syn == -3){
printf("%s error ID\n",token);
fprintf(p,"%s error ID\n",token);
}
}
fclose(p);
return 0;
}
程式碼已粘上,如有什麼漏洞都可再與鄙人聯絡。歡迎評論。