編譯原理運算符
1. 編譯原理:優先函數 f和g 到底怎麼看啊,不懂怎麼構造的 求解...
求算符優先函數的方法—迭代法
若已知運算符之間的優先關系,可按如下步驟構造優先函數:
1、對每個運算符a(包括#在內)令f(a)=g(a)=1
2、如果a⋗b且f(a)<=g(b),令f(a)=g(b)+1
3、如果a⋖b且f(a)>=g(b),令g(b)= f(a)+1
4、如果a≐b而f(a) ≠g(b),令min{f(a),g(b)}=max{f(a),g(b)}
5、重復2~4,直到過程收斂。如果重復過程中有一個值大於2n,則表明不存在算符優先函數。
2. 編譯原理四元式
四元式的一般形式為(op, arg1, arg2, result),其中:op為一個二元(也可以是零元或一元)運算符。arg1和arg2為兩個運算對象,可以是變數、常數或者系統定義的臨時變數名。result為運算結果。
第一步:T1=a*b,
第二步:T2=c*d,
第三步:T3=T2/e,
第四步:T4=T1-T3,
第五步:f=T4.
3. java中的正則表達式跟編譯原理有什麼聯系
首先,正則表達式不僅在Java里有,其它語言裡面也有,它是一個數學上的概念,各個語言中的正則表達式是它的不同形式的實現。
其次,編譯原理的詞法分析里,會用到正則表達式去匹配源程序中的各種token(記號),比如說
int a = 8;
里識別出:
類型名:int
變數名:a
運算符:=
數字:8
結尾分號:;
總之,二者有聯系,但不是一回事。
4. 編譯原理有有符號un-1.u=un嗎
編譯程序把源程序翻譯為目標程序。根據源程序的語言種類,翻譯程序可以分為匯編程序與編譯程序。與之相對,解釋程序是對源程序進行解釋執行的程序。相應的可以將高級語言分為
編譯型 C/C++, Swift, etc.
解釋型 Python, javascript, etc.
混合型 Java, etc.
本文重點放在編譯程序的設計上。典型的編譯程序具有 7 77 個邏輯部分
對源程序掃描一次被稱為一遍 (pass)。典型的一遍掃描編譯程序有如下形式
通常將中間代碼生成前的分析部分稱為編譯器的前端,其後的綜合部分則被稱為後端。這樣就把一個編譯程序分為了與源語言相關和與目標機有關的兩個獨立的部分,降低了程序的耦合。假設 llvm 編譯器 支持 M MM 種源語言到 N NN 種目標語言的編譯
傳統的編譯器如 gcc 可能需要開發 M × N M \times NM×N 個不同的子模塊。而 llvm 使用統一的中間語言 llvm Intermediate Representation 只需要 M MM 個前端與 N NN 個後端,大大降低了開發成本。
文法
設非空有窮集合 Σ \SigmaΣ 為一字母表,則其上的符號串為 ∀ s ∈ Σ ∗ \forall s \in \Sigma^*∀s∈Σ
∗
,其中 ∗ *∗ 表示集合的閉包。特別的記 Σ 0 = ε \Sigma^0 = {\varepsilon}Σ
0
=ε 為空串組成的集合。規則通常寫作
U : : = x or U → x , ∣ U ∣ = 1 , ∣ x ∣ ≥ 0 U ::= x\text{ or }U\rightarrow x,\quad |U| = 1, |x| \ge 0U::=x or U→x,∣U∣=1,∣x∣≥0
其中左部 U UU 是符號,右部 x xx 是有窮符號串。規則的集合 P PP 即可確定一個文法 G GG
<程序> ::= <常量說明><變數說明><函數說明>
<常量說明> ::= {const<常量定義>;}
<常量定義> ::= int<標識符>=<整數>{,<標識符>=<整數>}|char<標識符>=<字元>{,<標識符>=<字元>}
<變數說明> ::= {<類型標識符><變數定義>;}
<變數定義> ::= <標識符>[<下標>]{,<標識符>[<下標>]}
<下標> ::= '['<無符號整數>']' // <無符號整數>表示數組元素的個數,其值需大於0
<函數說明> ::= {(<類型標識符>|void)<函數定義>}void<主函數>
<函數定義> ::= <標識符>'('<參數表>')'<復合語句>
<參數表> ::= [<類型標識符><標識符>{,<類型標識符><標識符>}]
<主函數> ::= main'('')'<復合語句>
<復合語句> ::= '{'<常量說明><變數說明>{<語句>}'}'
<語句> ::= <條件語句>|'{'{<語句>}'}'|<函數調用語句>;|<賦值語句>;|<讀語句>;|<寫語句>;|<返回語句>;|;
<條件語句> ::= <if語句>|<while語句>|<do語句>|<for語句>
<if語句> ::= if'('<條件>')'<語句>[else<語句>]
<while語句> ::= while'('<條件>')'<語句>
<do語句> ::= do<語句>while'('<條件>')'
<for語句> ::= for'('<標識符>=<表達式>;<條件>;<標識符>=<標識符><加法運算符><無符號整數>')'<語句>
<條件> ::= <表達式>[<關系運算符><表達式>] // 表達式為0條件為假,否則為真
<函數調用語句> ::= <標識符>'('[<表達式>{,<表達式>}]')'
<賦值語句> ::= <標識符>['['<表達式>']']=<表達式>
<讀語句> ::= scanf'('<標識符>{,<標識符>}')'
<寫語句> ::= printf'('<字元串>[,<表達式>]')'|printf'('<表達式>')'
<返回語句> ::= return['('<表達式>')']
<表達式> ::= [<加法運算符>]<項>{<加法運算符><項>} // [+|-]只作用於第一個<項>
<項> ::= <因子>{<乘法運算符><因子>}
<因子> ::= <標識符>['['<表達式>']']|'('<表達式>')'|<整數>|<字元>|<函數調用語句>
<整數> ::= [<加法運算符>]<無符號整數>
<標識符> ::= <字母>{<字母>|<數字>}
<無符號整數> ::= <非零數字>{<數字>}|0
<數字> ::= 0|<非零數字>
<非零數字> ::= 1|...|9
<字元> ::= '<加法運算符>'|'<乘法運算符>'|'<字母>'|'<數字>'
<字元串> ::= "{十進制編碼為32,33,35-126的ASCII字元}"
<類型標識符> ::= int|char
<加法運算符> ::= +|-
<乘法運算符> ::= *|/
<關系運算符> ::= <|<=|>|>=|!=|==
<字母> ::= _|a|...|z|A|...|Z
復制
上述文法使用擴充的 BNF 表示法進行描述
符號 定義 說明
∣ \vert∣ 或 作用域由括弧限定
{ t } n m \{t\}^m_n{t}
n
m
將 t tt 重復連接 n ∼ m n \sim mn∼m 次 預設時 m = ∞ , n = 0 m = \infin,\ n = 0m=∞, n=0
[ t ] [t][t] 符號串 t tt 可有可無 等價於 { t } 1 \{t\}^1{t}
1
( t ) (t)(t) 局部作用域 主要用於限定 ∣ \vert∣ 范圍
相關概念有
概念 符號 定義 示例
識別符號 Z ZZ 文法中第一條規則的左部符號 <程序>
字匯表 V VV 文法中出現的全部符號 { <程序>, <常量說明>, …, 0, 1, … }
非終結符號集 V n V_nV
n
全部規則的左部組成的集合 { <程序>, <常量說明>, <變數說明>, … }
終結符號集 V t V_tV
t
V − V n V - V_nV−V
n
{ 0, 1, …, _, a, b, … }
設 U : : = u ∈ P U ::= u \in PU::=u∈P 則對於 ∀ x , y ∈ V ∗ \forall x, y \in V^*∀x,y∈V
∗
有直接推導 x U y ⇒ x u y xUy \Rightarrow xuyxUy⇒xuy 。如果 y ∈ V t ∗ y \in V_t^*y∈V
t
∗
則 x U y ⤃ x u y xUy\ ⤃\ xuyxUy ⤃ xuy 稱為規范推導。直接推導序列 u 0 ⇒ u 1 ⇒ ⋯ ⇒ u n u_0 \Rightarrow u_1 \Rightarrow \cdots \Rightarrow u_nu
0
⇒u
1
⇒⋯⇒u
n
可簡記為
{ u 0 ⇒ + u n n > 0 u 0 ⇒ ∗ u n n ≥ 0 \begin{cases} u_0 \mathop\Rightarrow\limits^+ u_n & n > 0\\ u_0 \mathop\Rightarrow\limits^* u_n & n \ge 0\\ \end{cases}{
u
0
⇒
+
u
n
u
0
⇒
∗
u
n
n
>
0
n
≥
0
進一步定義
句型 V ∗ ∋ x ⇐ ∗ Z V^* \ni x \mathop\Leftarrow\limits^* ZV
∗
∋x
⇐
∗
Z
句子 V t ∗ ∋ x ⇐ + Z V_t^* \ni x \mathop\Leftarrow\limits^+ ZV
t
∗
∋x
⇐
+
Z
語言 L ( G ) = { x ∣ x is sentence } L(G) = \{ x| x\text{ is sentence} \}L(G)={x∣x is sentence}
如果文法 G GG 和 G ′ G'G
′
有 L ( G ) = L ( G ′ ) L(G) = L(G')L(G)=L(G
′
) ,則稱這兩個文法等價。設 w = x u y w=xuyw=xuy 為一句型,稱 u uu 為一個相對於 U ∈ V n U \in V_nU∈V
n
的
w ww 的短語 如果 Z ⇒ ∗ x U y ∧ U ⇒ + u Z \mathop\Rightarrow\limits^* xUy \land U \mathop\Rightarrow\limits^+ uZ
⇒
∗
xUy∧U
⇒
+
u
w ww 的簡單短語 如果 u uu 是短語且 U ⇒ u U \mathop\Rightarrow\limits uU⇒u
句型的最左簡單短語稱為句柄。
二義性
文法 G GG 是二義性的,如果 ∃ x ∈ L ( G ) \exist x \in L(G)∃x∈L(G) 使下列條件之一成立
x xx 可以對應兩顆不同的語法樹
x xx 有兩個不同的規范推導
5. 闄堢伀鏃 緙栬瘧鍘熺悊
絎涓絝狅細緙栬瘧鍘熺悊鍏ラ棬</
鍦ㄧ▼搴忕殑涓栫晫閲岋紝緲昏瘧紼嬪簭鏄璇璦闂寸殑妗ユ侊紝瀹冨皢婧愯璦浠g爜杞鍖栦負閫昏緫絳変環鐨勬墽琛屽艦寮忥紙婧愯璦紼嬪簭 → 閫昏緫絳変環鐩鏍囪璦紼嬪簭</錛夈傜紪璇戠▼搴忓垯鎵婕旂潃鍏抽敭瑙掕壊錛岄氳繃楂樼駭璇璦錛堝侾ython錛夎漿鍖栦負浣庣駭璇璦錛堝傛眹緙栨垨鏈哄櫒鐮侊級錛岀粡榪囩紪璇戝啀鎵ц岋紝鎻愬崌璁$畻鏁堢巼錛楂樼駭璇璦 → 浣庣駭璇璦 → 璁$畻鎵ц</錛夈傜浉姣斾箣涓嬶紝瑙i噴紼嬪簭鍒欏疄鏃惰В鏋愬苟鎵ц岋紝娌℃湁棰勫厛緙栬瘧鐨勮繃紼嬨
緙栬瘧榪囩▼閫氬父鍒嗕負浜斾釜闃舵碉細璇嶆硶鍒嗘瀽銆佽娉曞垎鏋愩佽涔夊垎鏋愩佷紭鍖栧拰鐩鏍囦唬鐮佺敓鎴愩傚叾涓錛岀﹀彿琛ㄦ槸紼嬪簭鐨勪腑鏋錛岃板綍婧愪唬鐮佺殑鍏抽敭淇℃伅錛屾秹鍙婂悇縐嶈〃鏍礆紙絎﹀彿琛錛氭簮紼嬪簭淇℃伅鐨勯泦鎴愪粨搴</錛夈傞亶鍘嗘簮鏂囦歡鏄紼嬪簭澶勭悊鐨勬牳蹇冪幆鑺傦紝緙栬瘧鍣ㄥ垎涓哄墠絝鍜屽悗絝錛屽墠絝鍏蟲敞婧愯璦鐗規э紝鍚庣鍒欓傚簲鐩鏍囨満鍣ㄦ灦鏋勶紙緙栬瘧鍓嶇錛氭簮璇璦鐗規х殑澶勭悊錛岀紪璇戝悗絝錛氱洰鏍囨満鍣ㄧ殑閫傞厤</錛夈
璇璦鐨勫畾涔夌敱璇娉曞拰璇涔変袱閮ㄥ垎鏋勬垚錛屽寘鎷鎶借薄鐨勯昏緫緇撴瀯鍜岃$畻鏈烘墽琛岀殑緇嗚妭銆傜▼搴忎腑鐨勮鍙ュ垎涓烘墽琛屾у拰璇存槑鎬э紝濡傝祴鍊箋佹帶鍒舵祦鍜岃緭鍏/杈撳嚭鎸囦護錛鎵ц屼笌璇存槑錛氳璦鐨勫熀鐭</錛夈備笂涓嬫枃鏃犲叧鏂囨硶鐢辯粓緇撶﹀彿銆侀潪緇堢粨絎︺佸紑濮嬬﹀彿鍜屼駭鐢熷紡瀹氫箟錛屾瀯鎴愮▼搴忕粨鏋勭殑鍩虹錛涓婁笅鏂囨棤鍏蟲枃娉曪細緙栫▼璇璦鐨勯ㄦ灦</錛夈
鎺ヤ笅鏉ョ殑絝犺妭娣卞叆鎺㈣ㄦ枃娉曠殑紜瀹氭у拰浜屼箟鎬э紝浠ュ強鏂囨硶鐨勭被鍨嬪垝鍒嗭紝濡傜煭璇鏂囨硶銆佷笂涓嬫枃鏈夊叧鏂囨硶絳夛紝榪欎簺閮芥槸璁捐″拰鐞嗚В緙栬瘧鍣ㄧ殑鍏抽敭姒傚康錛鏂囨硶綾誨瀷錛氫粠綆鍗曞埌澶嶆潅錛屽畾涔夎璦鐨勮竟鐣</錛夈
璇嶆硶鍒嗘瀽鍣ㄦ槸緙栬瘧嫻佺▼鐨勮搗鐐癸紝瀹冨皢婧愮▼搴忓垎瑙d負鍙璇嗗埆鐨勫崟鍏冿紙璇嶆硶鍒嗘瀽錛氱紪璇戝熀鐭</錛夛紝騫朵笖閫氬父杈撳嚭浜屽厓寮忋備粠NFA鍒癉FA鐨勮漿鎹錛岄氳繃瀛愰泦娉曟秷闄や笉紜瀹氭э紝浼樺寲鐘舵佽〃紺猴紙NFA鍒癉FA鐨勮漿鎹錛氱簿紜鐘舵佽〃紺虹殑杞鎹</錛夈
LR鍒嗘瀽鍣ㄦ槸寮哄ぇ鐨勫垎鏋愬伐鍏鳳紝瀹冨湪LL鏂囨硶鐨勬墿灞曚笂琛ㄧ幇鍑鴻壊錛屾棤鍥炴函鐨勭Щ榪-褰掔害鏈哄埗浣垮緱閿欒媯嫻嬫洿鍙婃椂錛屽垎鏋愯〃璁捐″嶆潅錛LR鍒嗘瀽錛氶珮鏁堝垎鏋愪笌閿欒媯嫻</錛夈侺R鍒嗘瀽鍣ㄧ敱鍔ㄤ綔琛ㄥ拰杞縐昏〃鏋勬垚錛屾敮鎸佸嶆潅榪愮畻絎﹀拰宸﹂掑綊銆
灞炴ф枃娉曚綔涓虹紪璇戝師鐞嗙殑閲嶈佸垎鏀錛岄氳繃涓烘枃娉曠﹀彿璧嬩簣灞炴э紝濡傜被鍨嬪拰鍊礆紝甯鍔╁勭悊璇涔変俊鎮銆傚畠浠鍦ㄧ紪璇戣繃紼嬩腑鍙戞尌鍏抽敭浣滅敤錛岀壒鍒鏄鍦ㄨ娉曞垎鏋愩佽涔夊勭悊鍜屼腑闂翠唬鐮佺敓鎴愪腑錛灞炴ф枃娉曪細緙栬瘧榪囩▼涓鐨勮涔夊姪鎵</錛夈
緙栬瘧浼樺寲涓昏侀泦涓鍦ㄨ娉曞垎鏋愪箣鍚庯紝鐩鏍囦唬鐮佺敓鎴愪箣鍓嶏紝榪芥眰鐨勬槸楂樻晥銆佺瓑浠蜂笖緇忔祹鐨勪唬鐮佺敓鎴愩傚悎鐞嗙殑絎﹀彿琛ㄧ$悊鍜屼紭鍖栫瓥鐣ュ圭紪璇戞晥鐜囪嚦鍏抽噸瑕侊紙浼樺寲絳栫暐錛氳拷奼傛晥鐜囦笌緇忔祹鎬х殑騫寵</錛夈
6. 編譯原理問題:求解
E是文法開頭。ε代表終結符號(推理中代表終點或結果,程序語言中代表常量等)。E T 這些大寫字母一般代表非終結符號(這些代表中間過程,非結果。程序中代表函數等等)。開始是E。因為有個G(E)。E就是文法開始符號。推導就有E開始,它也是一個非終結符(代表函數、或者一個推導過程,類似於程序中的main(c++)、winmain(vc++)、dllmain(dll)等主函數)。
1算術表達式文法:這個文法是一個遞歸文法。計算機進行邏輯推導時會走很多彎路(類似於遍歷一顆樹的過程)。為了不讓計算機走彎路(提高效率的目的),可以變換為第二種文法。這種文法消除了遞歸(消除了歧義,類似於後綴表達式),使計算機可以一條直線走到底兒推導出結果。
我也很久沒看編譯原理了。 呵呵
7. 在編譯原理中: 文法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*}表示。所以不管常規表達式有多少個運算符,都可以由語言的後綴表達式對應。