[編譯原理讀書筆記][第2章 一個簡單的語法制導程序

[編譯原理讀書筆記][第2章 一個簡單的語法制導程序]

標籤(空格分隔): 未分類前端


本章內容是對本書第3章至第六章中介紹的編譯技術的綜合介紹.web

  • 經過將一個語句轉換爲三地址代碼的過程來說解
  • 重點是:詞法分析,語法分析和中間代碼生成.
  • 第7章,第8章將講述如何將三地址代碼轉換爲機器指令

2.1 引言

  • 2.2:給出一個普遍使用的表示方法來描述語法,叫作上下文無關法或者BNF(Backus-Naur範式).api

  • 2.3:面向文法的編譯技術:語法指導翻譯數組

  • 2.4:語法分析數據結構

  • 2.5:一箇中綴轉後綴的過程app

  • 2.6:詞法分析koa

  • 2.8:構造語法樹ssh

2.2 語法定義

介紹一種用於描述程序設計語言語法的表示方法---"上下文無關法"或簡稱文法.被用於組織編譯器前端.函數

  • 何爲上下文無關文法?
    • V 總能夠被字符w 自由替換,而無需考慮字符V出現的上下文
  • Java的if-else工具

    image_1b0314h07lc21a3l1fhp1hq4qsd9.png-6.5kB

  • 文法

    image_1b031klcn15romi0s9c1gdr1hfam.png-57.7kB

2.2.1 文法定義

一個上下文無關法(context-free grammar)由4個元素組成:

  • 一個終結符號集合,有時也稱作"詞法單元".
  • 一個非終結符號集合,有時也稱作"語法變量"
    • 每一個非終結符號表示一個終結符號串的結合.(後面介紹)
  • 一個產生式集合:表示某個構造的某種書寫形式.
    • 產生式頭或左部: 非終結符號 .
    • 一個箭頭
    • 產生式體或右部: 終結符號與非終結符號組成的序列
    • 若是產生式頭表明一個構造,那麼產生式體表明該構造的一種書寫形式.
  • 指定一個非終結符號爲開始符號

2.2.2 推導

根據文法推倒符號串時.首先從開始符號出發,不斷地將某個非終結符號替換爲該非終結符號的某個產生式的體.直到所有爲終結符號.

  • 能夠從開始符號推倒獲得的全部終結符號串的集合稱爲該文法定義的語言.

語法分析的任務

  • parsing的任務是: 接受一個終結符號串做爲輸入,找出從文法的開始符號推倒出該串的方法.

  • 若是不能推倒出,則報告語法錯誤.

  • 主要語法分析方法,在第四章中介紹

2.2.3 語法分析樹

語法分析樹用圖形方法展示了從文法的開始符號推倒出對應語言中的符號串的過程.

image_1b0amdp20k8v13uaocb4q9mhj9.png-34.9kB

parse tree有如下性質

  • 根節點的標號爲文法的開始字符.
  • 葉子節點爲一個終結符號或 e
  • 內部節點爲一個非終結符號
  • 若是非終結符號A它的子節點從左至右有X1,X2..XN,那麼必然有產生式A->X1X2X3..XN.

例子

文法:

image_1b0amsage11291nvp1feg1b7t1varm.png-16kB

須要推倒的語句: 9 - 5 + 2

語法樹:

image_1b0an8nfo1fr615s7108ocg017s313.png-10.7kB

一個文法的語言的另外一個定義是任何可以由某顆語法分析樹生成的符號串的集合.

爲一個給點的終結符號串構建一顆語法分析樹的過程稱爲對該符號穿進行語法分析

2.2.4 二義性

某些語法若是不嚴謹會產生二義性.好比將上述例子的語法改爲

image_1b0anioej1op51p8a1apn1ml4g001g.png-10.9kB

那麼對以前的終結符號串的解釋能夠用兩種語法樹

image_1b0anjlan104n1c762hk1io340o1t.png-24kB

前者的結果是6, 後者是2

顯然有問題.因此一個好的文法不該該有二義性.

2.2.5 運算符結合性

  • 左結合運算向左下端延伸
  • 右結合運算向右下端延伸

image_1b0aoacvd4pi5tl1coe1ik91bgv2a.png-31kB

等號的文法:

image_1b0aoasea7a4mtbbc714ppari2n.png-6.9kB

2.2.6 運算符的優先級

結合性規則只能做用於同一級別的運算

當具備+,-,*,\,(,)時的文法

image_1b0aoq9lp1i15lguqvkck9ikh34.png-131.1kB

  • factor不可被分開.
  • 一個(不是因子)的term可能被高優先級的運算符*/分開
  • 一個expr能夠被任意優先級分開
  • 根據這種思想,咱們能夠用多個非終結字符來肯定n個優先級的語法.

image_1b0aqplnf1ji662l1qq5gm51jqv3h.png-31.9kB

2.2.7 2.2節的練習

image_1b0atcjlj18bt18e819mamdr95b4b.png-25.3kB
從如下代碼能看出如何增長一個優先級.

image_1b0atdu96ql11otvcr7vna14lg4o.png-14.2kB

2.3 語法指導翻譯

語法制導翻譯是經過向一個文法的產生式附加一些規則或程序片斷而獲得的.

image_1b0de43p41ble1f07aruluu1hu89.png-152kB

看不懂

2.3.1 後綴表示

image_1b0de644tkuls42gaq1jsv25qm.png-85.8kB

2.3.2 綜合屬性

image_1b0deqf3a15it13q22h8t4qe7n13.png-31.5kB

  • 語法制導定義(syntax-directed definition)把每一個文法符號和一個屬性集合相關聯,而且把每一個產生式和一組語義規則(semantic rule)相關聯,這些規則用於計算與該產生式相關聯的屬性值.

  • 註釋語法分析樹:若是一顆語法分析樹的各個結點上標記了相應的屬性值,那麼這顆語法分析樹就稱爲註釋語法分析樹,簡稱註釋分析樹.

    image_1b0dfk1jo6s1gdm1u5hlqggf1g.png-24.5kB

  • 綜合屬性:若是某個屬性在語法分析樹結點N上的值由N的子節點和N自己的屬性值肯定,那麼這個屬性叫作綜合屬性
    • 性質: 只須要對語法分析樹進行一次自底向上的遍歷,既能夠算出屬性的值.
  • 5.1.1節將會講述一種繼承屬性:繼承屬性在某個語法分析樹的結點的值由其自己,兄弟,父節點屬性值決定.

##關於語法制導一個十分不錯的例子

image_1b0dg18p01unu1m8vk6deiijm1t.png-237.5kB
image_1b0dg1m6r133f3521o1u164a1ira2a.png-22.8kB

2.3.3 簡單語法制導定義

上述例子的語法制導定義具備如下重要性質:
image_1b0dgjn0a155b1n1f1pc510171uf62n.png-60kB

2.3.4 樹的遍歷

關於樹的遍歷就再也不贅述了

image_1b0dgs91iupt1ogm14e81m4g1n3834.png-98.4kB

  • 若是隻有綜合屬性,和繼承屬性單一一種,那麼求值問題很好解決,不然很難求值.

2.3.5 翻譯方案(語法制導翻譯方案)

以前上述的語法翻譯的例子將字符串做爲屬性值附加在結點上,從而獲得翻譯結果.

咱們來考慮一種不須要操做字符串的方法,經過運行程序片斷,逐步生成相同的翻譯結果.

語義動做

image_1b0fjmv381aqmrkm1vg418kh34u9.png-37.5kB

image_1b0fjr19o10kv1dq98dr1km6169m.png-18.8kB

例子

image_1b0fk7j9n12kl18r611j11dofbeo13.png-125.8kB
image_1b0fk82ne75mbh5g1q10ct1tse1g.png-30.9kB

2.4 語法分析

  • 語法分析是決定如何使用一個文法生成一個終結符號串的過程.

  • 本書將會介紹一種叫作遞歸降低的語法分析方法,該方法用於語法分析和實現語法制導翻譯器.
    • 下一節會給出一個完整實現例子的JAVA程序
    • 4.9會介紹一種Yacc的工具直接根據方案生成一個翻譯器.
  • 對於任何上下文無關法,都能構造出一個O(n^3)的語法分析器,可是對於實際的語言設計,基本都是線性時間構造出來的.

  • 大部分的語法分析方法能夠分爲兩類: 自頂向上,自底向上.
    • 這兩個術語指的是語法分析節點的構造順序.
    • 自頂向上語法,構造過程從根節點開始,逐步向葉子節點進行.
      • 更容易手工構造出高效的語法分析器
    • 自底向上語法則相反
      • 能夠處理更多種文法和翻譯方案,因此文法生成語法分析器的軟件工具經常使用這種.

2.4.1 自頂向下分析方法

image_1b0fp83cu1sdo15dbkvq16kpmmn1t.png-26.3kB

image_1b0fp98jmfvu1uf1f5m7nj1jot2a.png-74.1kB

向前看(lookahead)

  • 輸入中當前被掃描的終結符號一般稱爲向前看(lookahead)符號.
    • 在開始時,向前看符號是輸入串的第一個終結符號.

例子

image_1b0fpkp7c1f681t6r14jm1f3v1o6s2n.png-85.4kB

  • 爲一個非終結符號 選擇產生式是一個嘗試並犯錯的過程,咱們首先選擇一個產生式,若是這個產生式不合適將會進行回溯,再嘗試另外一個產生式.

  • 預測語法分析的特殊狀況不須要回溯.

2.4.2 預測分析法

遞歸降低分析方法(recursive-descent parsing)是一種自頂向下的語法分析方法,他使用一組遞歸過程來處理輸入.

這裏咱們考慮遞歸降低方法的一個簡單形式,稱爲預測分析法(predictive parsing)

  • 預測分析法中,各個非終結符對應的過程當中的控制流能夠由向前看無二義的肯定.在分析輸入串時出現的過程調用序列隱式地定義了該輸入串的一顆語法分析樹.

image_1b0fs0vv4sesg8v15553mgpi434.png-83kB

FIRST(α)

image_1b0fs7mithme1g5r1ek1bgt1ju3h.png-54.5kB

  • 關於計算的方法在4.2.2中介紹

  • image_1b0fsag0g9uraqv19u96icgmg3u.png-25.9kB

  • 預測分析法要求image_1b0g0vkt71hqg1p0iq7v5ih1mdg4b.png-2.5kBimage_1b0g101pi1ncsp97ndpfe08i84o.png-6kB

2.4.3 什麼時候使用ε 產生式

  • 若是向前看符號不在其餘產生式中,就用ε 產生式
  • 更加深刻了解什麼時候使用ε 產生式,參見4.4.3節中關於 LL(1)文法的討論.

2.4.4 設計一個預測分析器

當知足可以使用預測分析器時:
image_1b0g3jnt687o96f1ejikos14aj55.png-163.2kB

  • 對於語法動做如何處理

    image_1b0g3kmpv1ol11shk1jou1evj1cui5i.png-29.5kB
    image_1b0g3s6bo1cs1sgv1d5j1v5su7c5v.png-31.9kB

2.4.5 左遞歸

image_1b0hdrlgfinv1vng11he1i2ktrg9.png-117.4kB

image_1b0he5elk1ubdjqgvrd19581kptm.png-11.7kB

左遞歸:
image_1b0he9j6f14s81iuh1oj31lo9o4j1g.png-2.1kB
image_1b0he96331r8a1plv1ptl14te13ng13.png-8.5kB

右遞歸:

image_1b0hea0emvq310ap3a116s31ris1t.png-3.8kB
image_1b0heafbt3m9l211vfu1t5u1afh2a.png-11.2kB

  • 右遞歸對於左結合運算的翻譯會變得困難

  • 4.3.3節將考慮更通常的左遞歸形式

2.4.6 練習

image_1b0hend93ct91bch13ni1htrogq2n.png-21.9kB

  • (1)

    void S(){
        swithch( lookahead )
        {
            case +:
            match(+);S();S();break;
            case -:
            match(-);S();S();break;
            case a;
            match(a);break;
            default: report("syntax error");
        }
    }
  • (2)要注意最終的結果,並消除左遞歸

    void S(){
    if(lookahead == "("){
    match("("); S(); match(")"); S();
    }
    }
  • (3)兩個產生式的FIRST都是0,須要注意

    void S()  
    {  
        if(lookahead==0)  
        {  
             match(0);  
             if(lookahead!=1)  
                S();  
             match(1);  
        }  
        else  
        report("syntax error");  
    }

2.5 簡單表達式的翻譯器

使用前三節技術,咱們將使用Java語言編寫一個語法制導翻譯器.

image_1b0hi7bgj3oeusgv0410tlvii34.png-21.2kB

如今咱們處於矛盾中:

  • 一方面,咱們須要一個可以支持翻譯規約的文法;
  • 另外一方面,咱們須要一個明顯不一樣的可以支持語法分析過程的文法;

  • 因此先使用易於翻譯的文法,而後當心的轉換,使之可以語法分析.

咱們將消除2-21的左遞歸,獲得一個適用於預測遞歸降低翻譯器的文法.

2.5.1 抽象語法和具體語法

  • 設計一個翻譯器是,名爲抽象語法樹(abstract syntax tree)的數據結構是一個很好的起點.

    image_1b0hkgeprt4lnas1b08usd1kv93h.png-3.2kB

  • 語法分析樹叫作具體語法樹(concrete syn-tax tree),相應的文法叫作該語言的具體文法(concrete syntax)

2.5.2 調整翻譯方案

2個左遞歸產生式和一個非左遞歸產生式 image_1b0hkndns1pv21md2lekmr5gbh3u.png-2.5kB

image_1b0hknrnuqtj13g21t7a19ga17gq4b.png-12.7kB

  • 咱們要轉換的不僅是終結符號和非終結符號,還包括內嵌動做.
  • 嵌入在產生式中的語義動做在轉換時被當作終結符號直接進行復制.

例子

image_1b0hlo1johu91qneo3g15pfc984o.png-4kB
image_1b0hlonm19901n6m1e4o7gh1h0m55.png-24.6kB
image_1b0hlp88draarppvkf16galcb5i.png-55.4kB

2.5.3 非終結符號的過程

image_1b0hltvgkb4ib84uvq1t1ruv25v.png-65.3kB

2.5.4 翻譯器的簡化

image_1b0hmj5qkl8u32u6uf142pov46p.png-31.2kB
image_1b0hmibbo1iej1ce814f4e717mh6c.png-42.2kB

2.5.5 完整代碼

image_1b0hms7761hio1ac21nmq1klrcgn76.png-91.8kB
image_1b0hmsn5becq1rns1rkd15m3mrb7j.png-39.7kB

2.6 詞法分析

image_1b0hnjlm0ani1dj01a8fdoc7db80.png-43.8kB

2.6.1 剔除空白和註釋

image_1b0hnlr9suo21a3e1ms81u9k125s8d.png-26.2kB

  • 統計行號有利於定位錯誤

2.6.2 預讀

通常都會預讀一些字符放在緩衝區.有兩個好處

  • 緩衝區的效率問題,csapp有介紹就很少說了
  • 有利於詞法分析,判斷是>仍是>=
  • 一般在簡單的狀況,只須要預讀一個

本節的詞法分析器會預讀一個字符,本節中的詞法分析器不變式斷言以下:
當詞法分析器返回一個詞法單元時:

  • 變量peek要麼保存當前詞法單元詞素後的那個字符,要麼保存空白

2.6.3 常量

image_1b0holjc77qufofeoj19c24a8q.png-30.7kB

當在輸入流出現一個數位序列時,詞法分析器將向語法分析器傳送一個詞法單元.

  • 該詞法單元包括終結符num和根據數位計算出來的值 如:<num,31>

2.6.4 識別關鍵詞和標識符

  • 關鍵詞(keyword):大多數程序使用for,do,if這樣的固定字符串做爲標點符號,或者用於某種構造,這些字符串加作關鍵詞.

  • 字符串還能做爲標識符爲變量,數組,函數等命名.
    • 爲了簡化語法分析器,語言的文法一般把標識符當作終結符號處理.
    • image_1b0hpbito1m7b1j085ot54ortb9k.png-7.4kB
  • 關鍵詞一般也知足標識符的組成規則,當將關鍵詞做爲保留字時,相對容易解決.

對於本節中的詞法分析器

使用一個字符串表來保存字符串.

image_1b0l1vjkj40clof1ja912dv18kb9.png-97.5kB
image_1b0l2jl80mik2cjq031j2q11q9m.png-41kB

2.6.5 詞法分析器

image_1b0l2t2bg17451o1k1vukq9j1clp13.png-39.8kB

image_1b0l3s14hbbe1jvi14jr1j0e1s5t1g.png-20.9kB
image_1b0l3sfnj4hc1ss614o01crc3q71t.png-18.3kB
image_1b0l3sn5u1jvkifiapijukk7q2a.png-17.8kB
image_1b0l3sshqtv7als1pe419373bo2n.png-47.8kB

image_1b0l3tcndb8a7vs1clb1llj1ajv34.png-103.8kB
image_1b0l3tsr9qbn5p41pjr1tt41hid3h.png-64.2kB

2.7 符號表

符號表(symbol table)是一種供編譯器用於保存有關源程序構造的各類信息的數據結構.

  • 在編譯器分析階段逐步收集
  • 在綜合階段用於生成目標代碼
  • 標識符的字符串,詞素,類型,存儲位置,其餘相關信息.

2.7.1 爲每一個做用域設置一個符號表

image_1b0l56809n80ec1584bsabok3u.png-174.7kB

image_1b0l58fuf1jrop60sk7aguar4b.png-31.2kB
image_1b0l58p7tp3i1lcg11fgpv0jc74o.png-21.6kB

類Env

一顆 有前向邊的樹

支持三種操做

  • 建立一個新符號表
  • 加入新條目
  • 獲得標識符的條目

image_1b0l5tk1p3bcukubg31e85c9s5i.png-69.3kB

2.7.2 符號表的使用

image_1b0l9h383nuh187omqp27l1s375v.png-56.8kB
image_1b0l9hjnr1op01n9if3655f1jef6c.png-68kB

2.8 生成中間代碼

2.8.1 兩種中間表現形式

兩種最重要的中間表現形式

  • 樹形結構,包括語法分析樹和(抽象)語法樹
  • 線性表現形式,特別是"三地址代碼".

2.8.2 語法樹的構造

image_1b0nk7h52fov1njghbthn81umd9.png-97kB

image_1b0nkeba1h7tcu71f3sefk1klim.png-91.4kB

  • 能夠發現從下到上的運算,運算級從高到低

語句的抽象語法樹

在抽象語法樹中表示語句塊

表達式的語法樹

2.8.3 靜態檢查

image_1b0nleeq915211rqg8sn1llo1oq713.png-79.1kB

左值右值問題

image_1b0nlgtqf15rb1ms589s1r1c1kjp1g.png-79.7kB

類型檢查

指望<=,>=以後的結構是boolean

  • 自動類型轉換
  • 重載

2.8.4 三地址碼

咱們將說明如何經過遍歷語法樹來生成三地址代碼.

具體來講,咱們將顯示如何編寫一個抽象語法樹的函數,並同時生成必要的三地址代碼.

三地址指令

image_1b0nn0tj1vl81mm5hvc1asonop1t.png-105.7kB

語句的翻譯

image_1b0nn2t83r73hrj12edltu1jcd2a.png-4.4kB
image_1b0nn36vj1ar818iso8u6sf31a2n.png-15.7kB
image_1b0nn53a480chn6ot5j7jdb34.png-33.1kB

  • If是類Stmt的一個子類.
  • Stmt的子類都有一個構造函數和一個gen
  • gen是一個生成三地址代碼的函數.

表達式的翻譯

咱們將考慮包含二目運算符op,數組訪問,和賦值運算,幷包含常量及標識符的表達式,以此來講明對錶達式的翻譯.

兩個函數lvalue,rvalue

image_1b0no86qq4pl1t51rn4ga42183h.png-23.8kB

image_1b0noiihb1dlj1n1e1a3l176p1qcl3u.png-61.6kB
image_1b0nqchg01f7s1658ks1s871gh64b.png-174.2kB

相關文章
相關標籤/搜索