編譯原理語義分析實驗報告
『壹』 急(高懸賞 幫個忙) 求編譯原理課程設計---c語言實現c-的語法分析,在線等
新建一個文本文檔在你工程目錄下,名字起為"輸入.txt",裡面的內容可以為
begin a:=1+7*(6+3);b:=1end#
輸出是在"輸出.txt"中查看,以下為輸出情況:
詞法分析結果如下:
(1, begin)
(10, a)
(18, :=)
(11, 1)
(13, +)
(11, 7)
(15, *)
(27, ()
(11, 6)
(13, +)
(11, 3)
(28, ))
(26, ;)
(10, b)
(18, :=)
(11, 1)
(6, end)
(0, #)
語法分析結果如下:(以四元式形式輸出)
( +, 6, 3, t1)
( *, 7, t1, t2)
( +, 1, t2, t3)
( =, t3, __, a)
( =, 1, __, b)
//提供一個編譯原理的語義分析程序 你可以直接復制 用TC進行調試
#include "stdio.h"
#include "string.h"
#include <malloc.h>
#include <conio.h>
#include "stdlib.h"
char prog[100],token[8],ch;
char *rwtab[6]={"begin","if","then","while","do","end"};
int syn,p,m,n,sum,q;
int kk;
//四元式表的結構如下:
struct
{
char result1[8];
char ag11[8];
char op1[8];
char ag21[8];
}quad[20];
char *factor();
char *expression();
int yucu();
char *term();
int statement();
int lrparser();
char *newtemp();
void scaner();
void emit(char *result,char *ag1,char *op,char *ag2);
void main()
{
FILE *fp1,*fp2;
if((fp1=fopen("輸入.txt","rt"))==NULL)
{
printf("Cannot open 輸入.txt\n");
getch();
exit(1);
}
if((fp2=fopen("輸出.txt","wt+"))==NULL)
{
printf("Cannot create 輸出.txt FILE.strike any key exit");
getch();
exit(1);
}
int j;
q=p=kk=0;
p=0;
//printf("Please Input a String(end with '#'):\n");
while(ch!='#')
{
ch = fgetc(fp1);
if(ch == EOF)
{
printf("文件為空,請檢查後再嘗試!");
return ;
}
prog[p++]=ch;
}
if(prog[p]=='#')
{
printf("輸入的待分析的串不是以'#'結尾,請修改之後再嘗試!\n");
return;
}
p=0;
char buffer1[200] = {0};
sprintf(buffer1,"詞法分析結果如下:\n");
fputs(buffer1,fp2);
//printf("詞法分析結果如下:\n");
do
{
scaner();
switch(syn)
{
case 11:
//printf("(%d,%d)\n",syn,sum);
sprintf(buffer1,"(%d, %d) \n",syn,sum);
fputs(buffer1,fp2);
break;
default:
//printf("(%d,%s)\n",syn,token);
sprintf(buffer1,"(%d, %s)\n",syn,token);
fputs(buffer1,fp2);
break;
}
}while(syn!=0);
printf("\n");
p=0;
char buffer[200]={0};
sprintf(buffer,"語法分析結果如下:(以四元式形式輸出)\n");
fputs(buffer,fp2);
//printf("語法分析結果如下:(以四元式形式輸出)\n");
scaner();//掃描函數
lrparser();
if(q>19)
printf(" to long sentense!\n");
else
{
for (j=0;j<q;j++)
{
//printf("( %s, %s, %s, %s) \n\n",quad[j].op1,quad[j].ag11,quad[j].ag21,quad[j].result1);
sprintf(buffer,"( %s, %s, %s, %s) \n\n",quad[j].op1,quad[j].ag11,quad[j].ag21,quad[j].result1);
fputs(buffer,fp2);
}
}
printf("已把相應的詞法和語法的結果保存到相應的文件中,請查閱!\n");
fclose(fp1);
fclose(fp2);
}
int lrparser()
{
int schain=0;
kk=0;
if (syn==1) //得到begin
{
scaner();//掃描下個字元
schain=yucu();
if(syn==6)//得到end
{
scaner();//掃描下個字元
if((syn==0)&&(kk==0)) //得到#
printf("Success!\n");
}
else
{
if(kk!=1)
printf("short of 'end' !\n");
kk=1;
getch();
exit(0);
}
}
else
{
printf("short of 'begin' !\n");
kk=1;
getch();
exit(0);
}
return (schain);
}
int yucu()
{
int schain=0;
schain=statement();
while(syn==26)
{
scaner();
schain=statement();
}
return (schain);
}
int statement()
{
char tt[8],eplace[8];
int schain=0;
if (syn==10)
{
strcpy(tt,token); //tt中保存的是第一個字元
scaner();
if(syn==18) //檢測到=號
{
scaner();
strcpy(eplace,expression());
emit(tt,eplace,"=","__");
schain=0;
}
else
{
printf("short of sign ':=' !\n");
kk=1;
getch();
exit(0);
}
return (schain);
}
}
char *expression()
{
char *tp,*ep2,*eplace,*tt;
tp=(char *)malloc(12);
ep2=(char *)malloc(12);
eplace=(char *)malloc(12);
tt=(char *)malloc(12);
strcpy(eplace,term());
while((syn==13)||(syn==14))
{
if (syn==13)
strcpy(tt,"+");
else
strcpy(tt,"-");
scaner();
strcpy(ep2,term());
strcpy(tp,newtemp());
emit(tp,eplace,tt,ep2);
strcpy(eplace,tp);
}
return (eplace);
}
char *term()
{
char *tp,*ep2,*eplace,*tt;
tp=(char *)malloc(12);
ep2=(char *)malloc(12);
eplace=(char *)malloc(12);
tt=(char *)malloc(12);
strcpy(eplace,factor());
while((syn==15)||(syn==16))
{
if (syn==15)
strcpy(tt,"*");
else
strcpy(tt,"/");
scaner();
strcpy(ep2,factor());
strcpy(tp,newtemp());
emit(tp,eplace,tt,ep2);
strcpy(eplace,tp);
}
return (eplace);
}
char *factor()
{
char *fplace;
fplace=(char *)malloc(12);
strcpy(fplace,"");
if(syn==10) //得到字元
{
strcpy(fplace,token);
scaner();
}
else if(syn==11) //得到數字
{
itoa(sum,fplace,10);
scaner();
}
else if(syn==27) //得到)
{
scaner();
fplace=expression();
if(syn==28) //得到(
scaner();
else
{
printf("error on ')' !\n");
kk=1;
getch();
exit(0);
}
}
else
{
printf("error on '(' !\n");
kk=1;
getch();
exit(0);
}
return (fplace);
}
//該函數回送一個新的臨時變數名,臨時變數名產生的順序為T1,T2...
char *newtemp()
{
char *p;
char m[8];
p=(char *)malloc(8);
kk++;
itoa(kk,m,10);
strcpy(p+1,m);
p[0]='t';
return(p); //設置中間變數名放在一個字元數組中,字元數組的第一個字元為t第二個字元為m表示的數值
}
void scaner()
{
sum=0;
///for(m=0;m<8;m++)
//token[m++]=NULL;
memset(token,0,8);
m=0;
ch=prog[p++];
while(ch==' ')
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--;
syn=10;
token[m++]='\0';
for(n=0;n<6;n++)
if(strcmp(token,rwtab[n])==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;
}
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;
token[m++] = ch;
ch=prog[p++];
if(ch=='=')
{
syn=18;
token[m++] = ch;
}
else
{
syn=17;
p--;
}
break;
case '+': syn=13;token[0] = ch; break;
case '-': syn=14;token[0] = ch; break;
case '*': syn=15;token[0] = ch;break;
case '/': syn=16;token[0] = ch;break;
case '(': syn=27;token[0] = ch;break;
case ')': syn=28;token[0] = ch;break;
case '=': syn=25;token[0] = ch;break;
case ';': syn=26;token[0] = ch;break;
case '#': syn=0;token[0] = ch;break;
default: syn=-1;break;
}
}
//該函數是生成一個三地址語句送到四元式表中
void emit(char *result,char *ag1,char *op,char *ag2)
{
strcpy(quad[q].result1,result);
strcpy(quad[q].ag11,ag1);
strcpy(quad[q].op1,op);
strcpy(quad[q].ag21,ag2);
q++; //統計有多少個四元式
}
『貳』 編譯原理詞法分析,語法分析,語義分析能檢測出什麼錯誤
在程序編譯中,詞法分析、語法分析和語義分析三個階段分別檢測不同類型的錯誤。
詞法分析階段主要任務是識別和分類輸入代碼中的各個符號,將文本分解成一個個詞法單元。若遇到未知詞或符號,將引發錯誤提示。
語法分析階段依據語法規則識別出代碼中的語句結構,並檢查其在語法結構上的正確性。例如,定義語句或賦值語句的格式是否符合預期。
語義分析階段進行靜態語義審查,確保代碼的含義正確無誤,遵循定義的使用規則。如,變數是否先定義再使用,標識符是否重復定義。
舉例說明,假設程序中包含以下代碼段:
int a;
a = 1 + b;
詞法分析階段會識別出各符號與詞法單元。
語法分析階段檢查賦值語句結構,發現語句「1 + b;」中,「1」與「b」均未定義,導致錯誤。
語義分析階段進一步檢查變數「b」是否已定義,如未定義則提示錯誤。
常見的語義錯誤類型包括類型不兼容、重復定義、控制流錯誤等。
總結而言,編譯器通過這三個階段的分析,有效檢測並報告程序中的各種錯誤,幫助開發者確保代碼的正確性和有效性。
『叄』 透過源碼領悟GCC到底在幹些什麼 GCC源碼分析
透過源碼領悟GCC的主要功能和運作機制:
GCC的主要功能:
- 編譯器:GCC是Linux下重要的編譯工具,主要用於將源代碼轉換為可執行文件。
- 編譯驅動器:GCC不僅是一個編譯器,更是一個編譯驅動器,它驅動cc1、as和ld三個部件完成編譯、匯編和連接的工作。
GCC的運作機制:
- 編譯過程:根據編譯原理,GCC的編譯過程包括詞法分析、語法分析、語義分析、中間語言生成、優化和目標代碼生成等步驟。
- 編譯與連接:編譯器要完成編譯原理中提到的任務,而連接器則負責將編譯器生成的代碼片段拼接成一個完整的可執行程序。GCC通過調用cc1將C語言源文件編譯為匯編文件,再由AS將匯編代碼轉換為二進制指令,最後由LD連接對象文件生成可執行程序。
- 錯誤報告:編譯器報告的錯誤一般是局部錯誤,指出錯誤所在的文件和行號;而連接器報告的錯誤通常是全局錯誤,如函數重定義、無法解決的外部符號等。
GCC源碼中的關鍵部分:
- cc1:GCC源代碼中主要包含的是cc1這部分,它負責將C語言源文件編譯為匯編文件。
- 輔助工具:GCC還包含一些輔助工具,如collect2等,用於支持整個編譯過程。
GCC的安裝與編譯:
- 依賴庫:GCC依賴於gmp、mpfr、mpc三個庫,如果機器上沒有這些庫或者版本太老,需要先下載並編譯這些依賴庫。
- 編譯過程:下載GCC源碼和依賴庫後,需要按照一定的順序編譯這些庫和GCC本身。編譯過程中需要指定安裝位置,並啟用相應的語言支持。
總結:通過分析GCC的源碼,我們可以深入理解GCC的編譯機制、運作過程以及其在整個軟體開發流程中的重要作用。同時,了解GCC的安裝和編譯過程也有助於我們更好地使用和優化GCC。