若是你敲累了代碼,想喝喝咖啡,順便看點兒能夠當佐料的文章那本文應該比較適合如今的你。(•̀ᴗ•́)و ̑̑算法
咱們一每天都在和代碼打交道,可是你瞭解代碼的運行原理麼?爲何你的一行代碼就能被執行出五花八門的效果嘞?編程
其實代碼這玩意兒就是一門語言。是的,你能夠當作和中文、英文等語言平等的存在。是語言就得有語言的解析規則,不懂得規則天然沒法理解語言的意思。就跟看沒字幕的美劇同樣,真是痛苦。╮(╯﹏╰)╭編程語言
中文有中文的語義、語法、句子、句法、文法,那麼編程語言也有本身的語言系統。spa
咱們知道,咱們寫的代碼被編譯器或者解釋器所執行,那它們是按照什麼文法來理解你的代碼呢?這就是文法。3d
本文也不會深刻去解析文法,否則能夠直接轉語言學了(笑~)。本文只是簡單介紹文法的一些概念。若是您喝着咖啡,看完以後,能有些許收穫,微微一笑,那本文的目的也就達到了。^_^blog
工欲善其事必先利其器。在談文法以前,咱們先介紹幾個概念。遞歸
一.文法涉及的幾個簡單概念編譯器
假設Σ是一個有限的字母表集合,它的每一元素都是一個符號。Σ上的一個符號串就是指由Σ中的符號組成的一個有限序列。若是一個符號串不包含任何符號,就叫它空串,記爲ε。如今再定義一個集合U和V的鏈接積的概念:編譯
UV = {αβ | α∈U,β∈V}變量
好比A = {a,b},B = {1,2},則AB={a1,a2,b1,b2}。很簡單的概念,是否是?
那麼相信你也能知道V1,V2等的冪的概念了。
還有幾個:
ok,定義結束,如今來談談我們本次的主角——文法。一個比較拗口的定義,
文法是描述語言的語法結構的形式規則(即語法規則)。
這啥意思啊?可能你一臉黑人問號……
其實,就是指怎麼由一堆符號組成一個有含義的句子的規則和協議。
所謂的上下文無關文法就是文法的一種,它所定義的語法單位是徹底上下文無關的。好比咱們在程序語言 中,碰到一個算數表達式時,咱們徹底能夠對它「就事論事」,不用去考慮它上下有啥東西。固然,在天然語言(中文、英文等)中,一個語法單位(字、詞、句子)確定和上下文環境有關,否則當年咱們中文考試的閱讀理解題也就不會出現「根據上下文,解釋xx句子的含意」了。(ˇˍˇ) 想~
因此說,上下文無關文法不能用來描述天然語言,可是對於當今的程序語言來講,上下文無關文法基本夠用了。下文中的「文法」,若是沒有特殊說明,都是之指「上下文無關文法」。
下面類比天然語言的具體例子,談談咱們今天要說的文法。
一個英文句子:
He gave me a book.
這個句子知足英語的語法規則,是一個語法正確的句子。若是咱們用「→」表示「由...組成」或者「定義爲」,按照咱們中學的語法,能夠分解一下這個句子:
這樣,經過這樣的一個個規則(又叫「產生式」),就把一個句子分解到了單詞的層次。或者這麼說,有了這些規則,咱們能夠這麼幹:
咱們能夠畫一個更形象的圖(語法分析樹)來講明這種推導。
上面定義英文句子的規則就能夠說是一個上下文無關文法。其中,<句子>被稱爲開始符號,<主語><謂語><代詞>之類的被稱爲非終結符號,He、gave之類的被稱爲終結符號。
概括起來,一個上下文無關文法G包括四個部分:終結符號,非終結符號,開始符號,產生式。
終結符號就是一門語言中最基本的符號。在程序語言中,基本字、標識符、常數、運算符號等都算終結符號。
非終結符號更像一個抽象的集合,好比「算數表達式」、「賦值句」均可以看作非終結符號。
產生式就是推導規則。
下面上精肯定義:
二.遞歸定義的例子
有時候,只用一個產生式是不足以定義一個語法單位的,須要幾個產生式的相互配合。有時候會須要遞歸的形式。舉個栗子:
假設要定義一類含有+、*的算術表達式,這個定義能夠這麼說:
咱們用產生式的形式描述它:
其中 E 表明算術表達式, i 表明變量。這四個產生式的全體才定義了什麼是「算術表達式」。後三個都是遞歸的形式。
還能夠簡化爲:E→i | E+E | E*E | (E)。其中的「|」表明「或」,是一種元語言符號。
三.文法與語言的推導
假設G是一個文法,S是開始符號,若是S通過零步或者若干步推出α,那麼稱α是一個句型。只包含終結符號的句型是一個句子。文法G產生的全部句子構成一門語言,記爲L(G)。
那麼怎麼從文法推導出它表明的語言嘞?
爲了方便,咱們引入一些符號。
方法:把產生式當作替換規則,把當前符號串中的非終結符號用其產生式右邊的符號來替換。
再看有文法G2->語言L(G2)例子。
推導過程以下:
語言L(G2)-> G2 的例子。
由上面的兩個例子咱們能夠知道,一個文法能夠惟一肯定一個語言,可是一個語言不必定惟一對應一個文法。
四.語法分析樹與二義性
咱們發現從一個句型到另外一個句型的推導過程不是惟一的。例如從E+E->i+i,存在兩個推導過程:
固然爲了對句子的結構進行一個肯定性的分析,咱們通常只考慮最左推導或者最右推導。
前面咱們提到過用一種樹形的圖示來表示這個句型的推導過程,這棵樹就被稱爲」語法分析樹「,簡稱」語法樹「。
好比從E->(i+i) 的過程:
對於一個文法,若是它的某些句子對應兩棵不一樣的語法樹,這個文法就屬於「二義性文法」。
注意,文法的二義性和咱們一般所說的語言的二義性不一樣,咱們可能有兩個不一樣的文法G1,G2,一個是二義性,一個是非二義性,可是可能L(G1) = L(G2)。對於程序語言來講,咱們經常但願它的文法是非二義性的,可是,只要咱們可以控制和駕馭文法的二義性,文法二義性的存在也不必定是壞事。
如今已經證實了,文法二義性是不可斷定的。也就是說不存在一個算法,在有限步驟內算出一個文法是否是二義性的。咱們能作的事兒,就是找一組充分條件來講明非二義性。好比,規定運算符號的優先級和結合性。
對於咱們上面使用的那個文法:E->E+E | (E) | E*E | i
若是限定*的優先級高於+,而且都是左結合的,那麼上述文法就變成了非二義性文法。讀者大大能夠試試推導E->(i*i+i)。