Stanford CS143 Compiler Fall2014 個人筆記

introduction

  1. Deference between Compilers with Interpreters
    Compiler is off-line, and it’s imput is “program” then compiler it to exec witch can coculate Data to Output.
    Interpreters is on-line, and it’s input is Program and Data, it interpreter the Program line by line, and excute the code.
  2. History
    1954 IBM develops the 704. In this time, software is more expensive than hardware.
  3. Speedcoding
    1954 John Backus.today’s interperters. very slow.
    than he invented Fortran1(1954-1957). It’s the first compiler.
    (好吧,英語記筆記有點慢)並且編譯的核心由此確定爲“理論(Theory)+練習(Pratice)”
  4. 編譯原理分爲:lexical analysis, parsing, sematic analysis, optimization, code generation
    lexical analysis和parsing注重句法分析,sematic注重語義

1.1 編譯器的結構

人類是如何理解一段英語的

理解語句 對應編譯過程
This is a sentence. if x == y then z = 1; else z = 2;
理解單詞
將句子分割成單詞集
{‘This’, ‘is’, ‘a’, ‘sentence’}
詞法分析
將獨立的程序文本分割成單詞或tokens(標記)
可以識別出關鍵字{‘if’, ‘and’, ‘else’}、變量名{‘x’, ‘y’, ‘z’}、常量{‘1’, ‘2’}、操作符{’==’, ‘’=’, ‘=’}
理解句子結構
在這裏插入圖片描述
語法分析(語法樹)在這裏插入圖片描述
理解句子意思
這是會有歧義的在這裏插入圖片描述
語義分析
強制規定,避免模糊語言在這裏插入圖片描述
簡化語言表示在這裏插入圖片描述 自動代碼優化在這裏插入圖片描述
但當Y==NaN時不能這麼做
翻譯成其他語言 code生成

1.2 經濟型程序語言
問1:爲什麼有這麼多程序語言?
如,科學計算→Fortran,商業程序→SQL,系統程序→C/C++
答:不同程序所解決的領域(application domains)是不同的

問2:爲什麼有新的程序語言出現?
答:對編程語言來說,需要投入的前期編程教育佔據了支出的主要部分。
且現在主流語言之間的差距並不大。
創建一個新編程語言很容易。當新語言帶來的生產力大於培訓成本時,選擇創建新語言。
編程語言嘗試填補空缺

問3:好的程序語言是什麼?

3. 詞法分析Lexical Analysis

3.1 詞法分析的目的

將源碼分解爲<Identifier, token>對和詞彙表

3.1.1 名詞釋義

名詞 詞義
Identifier 字符串或由字符開始的數字串
Integer 非空數字組成的字符串
Keyword “else” or “if” or “begin” or …
Witespace 非空字符串,這個字符串由空格、換行符、製表符構成
Operator 運算符

3.1.2 詞法分析概要

  1. 將源碼的字串歸類成Tocken class
  2. 通過Tocken與語法分析溝通

3.1.3 詞素例子

在這裏插入圖片描述

3.2 詞法分析例子

3.2.1 FORTRAN

FORTRAN規則:空格是無影響的(“var1” == “va r1”)
向前看規則在這裏插入圖片描述
這說明了詞法分析的任務:

  1. 分割文本。從左向右讀源程序,生成Tocken,一次個狀態識別一個Tocken
  2. “向前看”用來解決一個Tocken的終止和另一個Tocken的開始

3.2.2 PL/1

(PL/1是一個IBM設計的編程語言)

特點:

  1. 關鍵字不保留
    在這裏插入圖片描述
  2. DECLARE二義性
    在這裏插入圖片描述

3.2.3 C++

在<>和>>、<<之間的問題
如:Foo<Bar> ,這裏出現了>>,會和流>>混淆。所以需要將這裏的>>改成> >(加了個空格)

3.3 正規語言

Lexical structure = token classes

3.3.1 正規表達式

3.3.1.1 正規表達式Regular Expressions

正規表達式由{單個字符,空字符}構成
 空字符用"ε\varepsilon"表示

在這裏插入圖片描述

3.3.1.2 正規表達式的操作

操作名 方法示意
Union 在這裏插入圖片描述
Concatenation 在這裏插入圖片描述
Iteration 在這裏插入圖片描述

定義:Σ\Sigma 是一個正規表達式中各正規式的組成元素集合
在這裏插入圖片描述
上圖中,都是在給定的Σ\Sigma(即正規表達式構成元素)組成的語法RR(grammer)
舉例說明:在這裏插入圖片描述

3.3.2 正規語言Formal Languages

定義:設Σ\Sigma是一個字符集。一個在Σ\Sigma上產生的語法是,從Σ\Sigma上產生的字符串集。(主要部分:語法是字符串集,其他定語自己看懂)
就像英文字母表是英語字符構成的,而英文語言是由英文句子構成的
Alphabet = ASCII
Language = C programs

3.3.2.? Meaning Function L

Meaning Function L將語法(Syntax)映射到語義(Semantics)上去
在這裏插入圖片描述
(上圖exp爲expression縮寫)
使用Meaning Function的意義:

  1. 分清語法和語義
  2. 有利於將符號(notation)看做成一個獨立的問題
  3. 表達式和語義並不是一一對應的

在這裏插入圖片描述
上圖展示了,不同語法通過Meaning Function可能映射到相同語義上去。這有助於我們將相同功能、不同語法寫成的程序,用高效的程序代替低效的程序。
並且,語法不會映射到多個語義上去。(無二義性)

3.3.3 正規表達式如何說明編程語言中的不同方向

注:A+=AA=i>0AA^{+}=AA^{*}=\bigcup\limits_{i>0}A

要描述的類型 描述方法
Keyword ‘if’+‘else’+then’…
Interger digit = ‘0’+‘1’+…+‘9’
digitdigit^{*}
Identifier letter=[a-zA-Z] ([a-z](a到z求並))
letter(letter+digit)letter(letter+digit)^{*}
Whitespace ’ ‘+’\n’+’\t’
在這裏插入圖片描述

例子:識別email地址的正規表達式
[email protected]
正規式表達:letter+@letter+.+letter+.+letterletter+'@'|letter+'.'+letter+'.'+letter

PASCAL語言中的正規表達式例子:
在這裏插入圖片描述
(這裏的+表示連接,在往上的文章中有用(1+0)這樣表示的正規式中的+表示或,因爲課件中用的是+表示或,十分有歧義,並且龍書中用的也是|。下面我儘量使用|,用以區分+,請注意)如下圖所示。。。這老師用的跟我校用的那本清華的編譯原理講的也不一樣,真討厭
在這裏插入圖片描述
在這裏插入圖片描述

3.4 詞法規範(lexical specification)

詞法檢測過程:

  1. 根據詞素寫出Tocken類
    在這裏插入圖片描述
  2. 構建一個符合所有詞素和Token的R
    在這裏插入圖片描述
  3. 輸入
    在這裏插入圖片描述

  4. 在這裏插入圖片描述

  5. 在這裏插入圖片描述

CTMD垃圾CSDN,Ctrl+S不能保存,寫了1000多字全沒了。。。。Scheiße!

4 語法分析

4.1 上下文無關文法

4.1.1 結構

在這裏插入圖片描述
左優先和右優先
規範推導爲右優先

4.1.2 二義文法

在這裏插入圖片描述
在這裏插入圖片描述
解決方法:將二義文法改寫成非二義文法
在這裏插入圖片描述
改寫成:(消除左遞歸)

在這裏插入圖片描述
注意:在這裏插入圖片描述

4.2 處理問題

4.2.1 問題的種類

在這裏插入圖片描述

4.2.2 處理問題需要做的事

  1. 準確且清晰地報告錯誤
  2. 快速地從錯誤中恢復過來(狀態)

4.2.3 處理問題的方法

4.2.3.1 恐慌模式Panic mode

處理方式:一直接着喫,直到找到了一個正確的role
尋找同步token
z.B.
在這裏插入圖片描述
在這裏插入圖片描述
可以使用一個特殊的終結符"error"來描述有多少輸入需要略過
在這裏插入圖片描述

4.2.3.2 錯誤產生式 Error Productions

只能知道語法中簡單的錯誤
z.B.

在這裏插入圖片描述

4.2.3.3 自動的局部或全局矯正 Automatic local or global correction

現在並不常用這種

在這裏插入圖片描述
在這裏插入圖片描述

4.2.3.4 過去和現在比較

在這裏插入圖片描述

4.3 語法樹

編譯器剩下一部分需要一個能代替程序的結構。
抽象語法樹:近似語法樹但忽略一些細節、簡單地描述成AST(Abstract Syntax Tree)
在這裏插入圖片描述
改寫成這樣
在這裏插入圖片描述

4.4遞歸下降的語法分析(自頂向下的語法分析)

語法樹構建方法:自頂向下,從左到右
先序遍歷地生成Terminals
z.B.
在這裏插入圖片描述
生成過程,注意有迴歸
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
accept

4.4.2 舉一個RD algorithm例子

對於語法E:{
E → T | T+E
T → int | int*T | (E)

}
Token有:INT, OPEN, CLOSE, PLUS, TIMES
global next指向下一輸入的token

  1. 定義一個返回值是bool值的檢測函數,它檢測將要輸入的token是不是一個token。
// 返回當前token是否符合選擇的token,並將指針移到下一個輸入上去
bool term(Token tok){
	return *next++==tok;
}

定義一系列的代表產生式的函數S " bool Sn() { … } ",只有在相同時才返回爲真。
定義一個包含所有產生式的函數S " bool S() { … } "

// z.B. 對於產生式 "E→T"有函數
bool E1() { return T(); }
// z.B. 2: "E→T+E":
bool E2() { return T() && term(PLUS) && E(); }
bool E(){
	Token *save = next; // 在嘗試任何匹配前,先把**接下來**要從哪去token的位置記錄下來。
	return (next = save, E1()) 
		|| (next = save, E2());
}
  1. 定義接下來的T的函數
// 對於 T→int
bool T1() { return term(INT); }
// 對於 T→int * T
bool T2() { return term(INT) && term(TIMES) && T(); }
// 對於 T→(E)
bool T3() { return term(OPEN) && E() && term(CLOSE); }

// T → int | int*T | (E)
bool T(){
	TOKEN *save = next;
	return (next = save, T1()) || (next = save, T2()) || (next = save, T3()); 
}
  1. 開始語法分析
    初始化next指向輸入字符串的第一個字符,調用函數E()

問題: 這對於輸入"int * int "會reject,因爲第一次使用的是E→int進行推導,如果使用E→int*T就不會出錯。所以有問題”如果一個產生非終結符的產生式被使用了,則不再有回溯回來檢測此時使用別的產生式的可能“
通常上,自頂向下遞歸分析需要支持全回溯,纔可以進行完整的語法檢測。
雖然正常情況下不使用這種算法,但這算法容易手工實現。在一個非終結符只能推導出一個終結符情況下是可用的。消除例子中的公共前綴left factoring就可以用了:)。

4.4.3 消除左遞歸(left recursion)

舉個例子:

// S → Sa
bool S1() { return S() && term(a); }
bool S() {return S1();}

這裏的S會產生無窮的遞歸。一個左遞歸語法要求沒有這樣的S,這樣的非終結符S使得S可以加步推導出Sα\alpha
考慮這樣的語法:
SSαβS→S\alpha|\beta
它會產生這樣的語言:在這裏插入圖片描述
這導致最後生成了β\beta,它從右向左依次生成,因此可以右遞歸地生成。在這裏插入圖片描述
上式也可寫成右遞歸式:(從左向右生成)
在這裏插入圖片描述
更多的消除左遞歸式的例子:
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章