⑴ 編譯原理中 文法 文法G定義為四元組(Vn ,Vt,P,S)這4個是什麼意思 另外 終結符和非終結符是什麼意思
文法G是一個四元式(Vt,Vn,S,P)
其中Vt是一個非空有限集,它的每個元素稱為終結符號
Vn是一個非空有限集,它的每個元素稱為非終結符號(Vt和Vn的交集為空)
S是一個非終結符號,稱為開始符號
P是一個產生式集合(有限),每個產生式的形式是P-->a
開始S必須在某個產生式的左部出現一次
終結符指組成語言的基本符號(如基本字、標識符、常數、算符、界符)
非終結符號(也稱語法變數)表示一定符號串的集合。
你看到小寫字母一般是終結符,大寫字母肯定是非終結符
不明白可以聯系。
⑵ 編譯原理的LL(1)文法是什麼意思
LL(1)的含義:第1個L表明自頂向下分析是從左向右掃描輸入串,第2個L表明分析過程中將用最左到推倒,1表明只需向右看一個符號便可決定如何推倒即選擇哪個產生式(規則)進行推導,類似也可以有LL(k)文法,也就是需要向前查看k個符號才能確定選用哪個產生式。
這是從我們編譯原理課本上抄來的,希望對你有幫助
⑶ 編譯原理的LL(1)文法是什麼意思
1.文法不含左遞歸,沒有公共左因子
2.對於文法中的每個非終結符A的產生式的候選首符集兩兩不相交。
3.對於文法中的每個非終結符A,它存在某個候選首符集包括ε,則FIRST(A)∩FOLLOW(A)=空
滿足以上條件的文法為LL(1)文法
⑷ 編譯原理文法分析
改完了,能文法分析出來了!!
大概 跟你說下 你的錯誤吧:
出錯地點:
1.聲明的stack[50]沒有初始化;
2.stack的入棧是錯誤的,按照你的方式,如果原來有TM,再加入T->FN,則M就被擠出來了.(這里很關鍵,你對照我給你改的再看看)
3.s指針在你入棧操作以後並沒有指向棧頂,而是保持了不變,這肯定是有問題的.(傳入push函數的時候直接傳參數s就好了.)
4.if(*s==*p){***}else{}的else的右括弧管轄的范圍 有錯誤
不嫌棄的話,可以去http://blog.csdn.net/fangguanya,我的BLOG,不怎麼充實,呵呵,有這個程序的運行結果的. 謝謝 呵呵.
總之你對照我給你改的再看看吧. 我把我的測試輸出 也給保留了.你好對照點.
(PS.我用的vs2005,用的時候你改下頭申明,其他一樣)
// grammar.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include<iostream>
using namespace std;
char * spush(char *stack,char *pt);
bool analyse(char *p);
void main()
{
//將分析串存放在二維數組中
char input[5][10]={"i+i#",
"i*(i+i)#",
"i*i+i#",
"i+*#",
"+i*i#"};
bool flag; //定義一個布爾型的標記量
for(int h=0;h<5;++h)
{
flag=analyse(input[h]);
if(flag) cout<<"恭喜你!"<<input[h]<<"語法分析成功,合法!"<<endl;
else cout<<"對不起!"<<input[h]<<"語法分析失敗,非法!"<<endl;
}
int aaa;
cin>>aaa;
}
//定義各一將串逆序入棧的函數
char * spush(char *stack,char *pt)
{
int l=0;
//while循環的作用是將指針指向字元串的末尾,然後再由後向前入棧,從而實現逆序
while(*pt!='\0')
{
pt++;
l++;
}
if (*stack == '#')
{
stack++;
}
while(l)
{
pt--;
char cTempIntoStack = (*pt);
*stack=cTempIntoStack;
stack++;
l--;
}
stack--; //由於前面向前加了一位,要返回
////////////////
return stack;
///////////////////////////////////
}
/*LL(1)分析表
i + * ( ) #
E TM +TM
F i (E)
M TM e e
N e *FN e e
T FN FN
*/
//分析函數
bool analyse(char *p){
char analyseTable[5][6][4]={
"TM", "", "", "TM", "", "",
"i", "", "", "(E)", "", "",
"", "+TM", "", "", "e", "e",
"", "e", "*FN", "", "e", "e",
"FN", "", "", "TN", "", ""
};
char *stack = new char[50]; //定義一個棧空間
for (int iStack = 0;iStack<50 ;iStack++)
{
stack[iStack] = 0;
}
char *s=stack; //用指針*s指向棧的起始地址
*s='#'; //將「#」入棧
s++; //指針加1
*s='E'; //將「E」入棧
//下面的while循環實現字元串的詞法分析操作
int count = 0;
while(*s!='#' || *p!='#'){
count++;
char * temp = s;
cout<<"NO."<<count<<endl;
cout<<"STACK"<<endl;
while (*temp != '#')
{
cout<<*temp<<" ";
temp--;
}
cout<<endl;
int x,y;
//若果棧頂數據和分析串的字元匹配,則將符號棧的棧頂數據出棧(即將棧頂指針減1)
if(*s==*p){
cout<<"Before :"<<*s<<endl;
s--;
p++;
cout<<"After :"<<*s<<endl;
}
//當符號棧和分析串的字元不匹配時,查分析表
else {
switch(*s){
case 'E':x=0;break;
case 'F':x=1;break;
case 'M':x=2;break;
case 'N':x=3;break;
case 'T':x=4;break;
default:return false;
}
switch(*p){
case 'i':y=0;break;
case '+':y=1;break;
case '*':y=2;break;
case '(':y=3;break;
case ')':y=4;break;
case '#':y=5;break;
default:return false;
}
//若果對應的為空,則分析串非法,退出
if(analyseTable[x][y][0]=='\0') return false;
//若查表所對應的為'e',則將符號棧的棧頂數據出棧
else if(analyseTable[x][y][0]=='e') s--;
//其它,這時將查表所得的項逆序入符號棧
else {
s=spush(s,analyseTable[x][y]);
}
}
}
return true; //分析成功,返回
}
⑸ 編譯原理 中的文法和語言 區別是什麼麻煩高手指點。謝謝
文法是語言語法的描述工具,使用有限的規則將無限的語言描述出來。
語言是文法所描述的所有橘子的集合,通俗點說吧,你看咱們平時說話不是都要遵從一定的語法規則嗎,比如句子「主謂賓」這樣的形式,文法就是用四元組要素(開始符號,終結符,非終結符,終止符號)將這些語法規則一條條的列出來,而語言就相當於我們能用這些語法規則所說出來的所有的話,具體實際的話~~嘿嘿
⑹ 編譯原理的文法是什麼
文法是描述語言規則的形式規則。實際上就是用一個四元組G=(VT,VN,S,P)定義的一個推理方式。其中VT是終結符,VN是非終結符,S是開始符號,P是一組產生規則。
⑺ 編譯原理全部的名詞解釋
書上有別那麼懶!。。。。
編譯過程的六個階段:詞法分析,語法分析,語義分析,中間代碼生成,代碼優化,目標代碼生成
解釋程序:把某種語言的源程序轉換成等價的另一種語言程序——目標語言程序,然後再執行目標程序。解釋方式是接受某高級語言的一個語句輸入,進行解釋並控制計算機執行,馬上得到這句的執行結果,然後再接受下一句。
編譯程序:就是指這樣一種程序,通過它能夠將用高級語言編寫的源程序轉換成與之在邏輯上等價的低級語言形式的目標程序(機器語言程序或匯編語言程序)。
解釋程序和編譯程序的根本區別:是否生成目標代碼
句子的二義性(這里的二義性是指語法結構上的。):文法G[S]的一個句子如果能找到兩種不同的最左推導(或最右推導),或者存在兩棵不同的語法樹,則稱這個句子是二義性的。
文法的二義性:一個文法如果包含二義性的句子,則這個文法是二義文法,否則是無二義文法。
LL(1)的含義:(LL(1)文法是無二義的; LL(1)文法不含左遞歸)
第1個L:從左到右掃描輸入串 第2個L:生成的是最左推導
1 :向右看1個輸入符號便可決定選擇哪個產生式
某些非LL(1)文法到LL(1)文法的等價變換: 1. 提取公因子 2. 消除左遞歸
文法符號的屬性:單詞的含義,即與文法符號相關的一些信息。如,類型、值、存儲地址等。
一個屬性文法(attribute grammar)是一個三元組A=(G, V, F)
G:上下文無關文法。
V:屬性的有窮集。每個屬性與文法的一個終結符或非終結符相連。屬性與變數一樣,可以進行計算和傳遞。
F:關於屬性的斷言或謂詞(一組屬性的計算規則)的有窮集。斷言或語義規則與一個產生式相聯,只引用該產生式左端或右端的終結符或非終結符相聯的屬性。
綜合屬性:若產生式左部的單非終結符A的屬性值由右部各非終結符的屬性值決定,則A的屬性稱為綜合屬
繼承屬性:若產生式右部符號B的屬性值是根據左部非終結符的屬性值或者右部其它符號的屬性值決定的,則B的屬性為繼承屬性。
(1)非終結符既可有綜合屬性也可有繼承屬性,但文法開始符號沒有繼承屬性。
(2) 終結符只有綜合屬性,沒有繼承屬性,它們由詞法程序提供。
在計算時: 綜合屬性沿屬性語法樹向上傳遞;繼承屬性沿屬性語法樹向下傳遞。
語法制導翻譯:是指在語法分析過程中,完成附加在所使用的產生式上的語義規則描述的動作。
語法制導翻譯實現:對單詞符號串進行語法分析,構造語法分析樹,然後根據需要構造屬性依賴圖,遍歷語法樹並在語法樹的各結點處按語義規則進行計算。
中間代碼(中間語言)
1、是復雜性介於源程序語言和機器語言的一種表示形式。
2、一般,快速編譯程序直接生成目標代碼。
3、為了使編譯程序結構在邏輯上更為簡單明確,常採用中間代碼,這樣可以將與機器相關的某些實現細節置於代碼生成階段仔細處理,並且可以在中間代碼一級進行優化工作,使得代碼優化比較容易實現。
何謂中間代碼:源程序的一種內部表示,不依賴目標機的結構,易於代碼的機械生成。
為何要轉換成中間代碼:(1)邏輯結構清楚;利於不同目標機上實現同一種語言。
(2)便於移植,便於修改,便於進行與機器無關的優化。
中間代碼的幾種形式:逆波蘭記號 ,三元式和樹形表示 ,四元式
符號表的一般形式:一張符號表的的組成包括兩項,即名字欄和信息欄。
信息欄包含許多子欄和標志位,用來記錄相應名字和種種不同屬性,名字欄也稱主欄。主欄的內容稱為關鍵字(key word)。
符號表的功能:(1)收集符號屬性 (2) 上下文語義的合法性檢查的依據: 檢查標識符屬性在上下文中的一致性和合法性。(3)作為目標代碼生成階段地址分配的依據
符號的主要屬性及作用:
1. 符號名 2. 符號的類型 (整型、實型、字元串型等))3. 符號的存儲類別(公共、私有)
4. 符號的作用域及可視性 (全局、局部) 5. 符號變數的存儲分配信息 (靜態存儲區、動態存儲區)
存儲分配方案策略:靜態存儲分配;動態存儲分配:棧式、 堆式。
靜態存儲分配
1、基本策略
在編譯時就安排好目標程序運行時的全部數據空間,並能確定每個數據項的單元地址。
2、適用的分配對象:子程序的目標代碼段;全局數據目標(全局變數)
3、靜態存儲分配的要求:不允許遞歸調用,不含有可變數組。
FORTRAN程序是段結構,不允許遞歸,數據名大小、性質固定。 是典型的靜態分配
動態存儲分配
1、如果一個程序設計語言允許遞歸過程、可變數組或允許用戶自由申請和釋放空間,那麼,就需要採用動態存儲管理技術。
2、兩種動態存儲分配方式:棧式,堆式
棧式動態存儲分配
分配策略:將整個程序的數據空間設計為一個棧。
【例】在具有遞歸結構的語言程序中,每當調用一個過程時,它所需的數據空間就分配在棧頂,每當過程工作結束時就釋放這部分空間。
過程所需的數據空間包括兩部分
一部分是生存期在本過程這次活動中的數據對象。如局部變數、參數單元、臨時變數等;
另一部分則是用以管理過程活動的記錄信息(連接數據)。
活動記錄(AR)
一個過程的一次執行所需要的信息使用一個連續的存儲區來管理,這個區 (塊)叫做一個活動記錄。
構成
1、臨時工作單元;2、局部變數;3、機器狀態信息;4、存取鏈;
5、控制鏈;6、實參;7、返回地址
什麼是代碼優化
所謂優化,就是對代碼進行等價變換,使得變換後的代碼運行結果與變換前代碼運行結果相同,而運行速度加快或佔用存儲空間減少。
優化原則:等價原則:經過優化後不應改變程序運行的結果。
有效原則:使優化後所產生的目標代碼運行時間較短,佔用的存儲空間較小。
合算原則:以盡可能低的代價取得較好的優化效果。
常見的優化技術
(1) 刪除多餘運算(刪除公共子表達式) (2) 代碼外提 +刪除歸納變數+ (3)強度削弱; (4)變換循環控制條件 (5)合並已知量與復寫傳播 (6)刪除無用賦值
基本塊定義
程序中只有一個入口和一個出口的一段順序執行的語句序列,稱為程序的一個基本塊。
給我分數啊。。。
⑻ 在編譯原理中: 文法S——>SS+|SS*|a能產生什麼語言,並驗證! 求高人指導!
為了使問題簡化,我們考慮文法S->ss+|a,考慮s->ss*時,只要把+換成*即可。
0層遞歸是,s->a,文法的語言是{a}。是後綴表達式。
1層以內遞歸時,文法語言是{a,aa+}。是後綴表達式。
2層以內遞歸時,文法語言是{a,aa+}.{a,aa+}.{+}。其中.表示連接,是後綴表達式。
依此類推,多少層的遞歸都是後綴表達式。
把表達式的+換成*後依然為後綴表達式。
下面證明文法產生的語言是所有的以a為變數,以+和*為運算符的後綴表達式。
因為每個表達式都對應一個常規的表達式(如1*2+3就是常規表達式),下面只需證明語言能產生的後綴表達式對應所有的常規表達式。當常規表達式只有一個運算符,對應aa+或aa*。當常規表達式有兩個運算符,可寫成(表達式1).{+|*}.(表達式2),因為表達式1和2都只含一個運算符,所以可以用語言表示,上述常規表達式可用後綴表達式(表達式1).(表達式2).{+l*}表示。所以不管常規表達式有多少個運算符,都可以由語言的後綴表達式對應。
⑼ 如何通俗易懂地解釋編譯原理中語法分析的過程
分成詞法分析,語法分析(LL演算法,遞歸下降演算法,LR演算法),語義分析,運行時環境,中間代碼,代碼生成,代碼優化這些部分。其實現在很多編譯原理的教材都是按照85,86出版的那本龍書來安排教學內容的,所以那本龍書的內容格式幾乎成了現在編譯原理教材的定式,包括國內的教材也是如此。一般來說,大學裡面的本科教學是不可能把上面的所有部分都認真講完的,而是比較偏重於前面幾個部分。像代碼優化那部分東西,就像個無底洞一樣,如果要認真講,就是單獨開一個學期的課也不可能講得清楚。所以,一般對於本科生,對詞法分析和語法分析掌握要求就相對要高一點了。
詞法分析相對來說比較簡單。可能是詞法分析程序本身實現起來很簡單吧,很多沒有學過編譯原理的人也同樣可以寫出各種各樣的詞法分析程序。不過編譯原理在講解詞法分析的時候,重點把正則表達式和自動機原理加了進來,然後以一種十分標準的方式來講解詞法分析程序的產生。這樣的做法道理很明顯,就是要讓詞法分析從程序上升到理論的地步。
語法分析部分就比較麻煩一點了。現在一般有兩種語法分析演算法,LL自頂向下演算法和LR自底向上演算法。LL演算法還好說,到了LR演算法的時候,困難就來了。很多自學編譯原理的都是遇到LR演算法的理解成問題後就放棄了自學。其實這些東西都是只要大家理解就可以了,又不是像詞法分析那樣非得自己寫出來才算真正的會。像LR演算法的語法分析器,一般都是用工具Yacc來生成,實踐中完全沒有比較自己來實現。對於LL演算法中特殊的遞歸下降演算法,因為其實踐十分簡單,那麼就應該要求每個學生都能自己寫。當然,現在也有不少好的LL演算法的語法分析器,不過要是換在非C平台,比如Java,Delphi,你不能運用YACC工具了,那麼你就只有自己來寫語法分析器。