Yacc優先規則並不是真正關於表達式的優先級,儘管它們可以用於此。相反,它們是明確解決轉變/減少衝突(並且僅僅轉移/減少衝突)的一種方式。
瞭解它是如何工作的,需要了解移位/縮小(自下而上)解析是如何工作的。基本的想法是,您從輸入中讀取令牌符號並將這些令牌推送(「移位」)到堆棧上。當堆棧頂部的符號與語法中某條規則的右側相匹配時,您可以「減少」規則,從堆棧中彈出符號並用規則左側的單個符號替換它們。重複這個過程,移動令牌並減少規則,直到讀完整個輸入並將其縮減爲開始符號的單個實例,此時您已成功解析了整個輸入。
上述問題(以及解析器生成器的整個機制正在解決什麼問題)是知道何時可以減少規則與何時移動令牌(如果兩者都可能的話)。解析器生成器(yacc或bison)構建了一個狀態機器,用於跟蹤哪些符號已被移位,從而知道當前可能有哪些「部分匹配」規則,並且限制只能移動到那些可以匹配更多此類規則的標記。如果所討論的語法不是LALR(1),那麼這不起作用,所以在這種情況下,yacc/bsion報告會移動/減少或減少/減少衝突。
該優先規則解決轉移減少衝突的工作是通過爲語法中的某些標記和規則分配優先級。每當一個要移動的標記和一個要減少的規則之間有一個移位/減少衝突,並且BOTH具有優先級時,它將執行具有更高優先級的任何一個。如果它們具有相同的優先級,則它查看與優先級相關聯的標記%left
/%nonassoc
-%left
意味着減少,%right
意味着移位,並且%nonassoc
意味着既不做也將它視爲語法錯誤。
唯一棘手的剩餘位是令牌和規則如何獲得它們的優先級。令牌從它們所在的%left
/%right
/%nonassoc
指令中獲得它們,這也設置了排序。規則優先於%prec
指令或優先於右側最右側的終端。因此,當您有:
%left '*'
%left '+'
expr: expr '+' expr
| expr '*' expr
;
您設置的'*'
和'+'
與%left
指令的優先級,並且這兩個規則得到這些令牌的優先級。
當你有:
%left MULTIPLY
%left PLUS
expr: expr '+' expr %prec PLUS
| expr '*' expr %prec MULTIPLY
;
你設置的令牌MULTIPLY
和的優先級,然後制定明確的規則有那些優先級。但是,您沒有爲令牌'*'
和'+'
設置任何優先級。因此,當兩個規則中的一個與'*'
或'+'
之間存在轉換/減少衝突時,由於令牌沒有優先級,因此優先級不會解決它。