[英]Simple YACC grammar with problems
我想實現一個簡單的 YACC 解析器,但我的語法有問題:
%union {
s string
b []byte
t *ASTNode
}
%token AND OR NOT
%token<s> STRING
%token<b> BYTES
%type<t> expr
%left AND
%left OR
%right NOT
%%
expr: '(' expr ')' {{ $$ = $2 }}
| expr AND expr {{ $$ = NewASTComplexNode(OPND_AND, $1, $3) }}
| expr AND NOT expr {{ $$ = NewASTComplexNode(OPND_AND, $1, NewASTComplexNode(OPND_NOT, $4, nil)) }}
| NOT expr AND expr {{ $$ = NewASTComplexNode(OPND_AND, NewASTComplexNode(OPND_NOT, $2, nil), $4) }}
| expr OR expr {{ $$ = NewASTComplexNode(OPND_OR, $1, $3) }}
| STRING {{ $$ = NewASTSimpleNode(OPRT_STRING, $1) }}
| BYTES {{ $$ = NewASTSimpleNode(OPRT_BYTES, $1) }}
;
有人向我解釋為什么它會給我這些錯誤?:
rule expr: NOT expr AND expr never reduced
1 rules never reduced
conflicts: 3 reduce/reduce
在評論中,澄清要求是:
NOT
運算符應僅適用於AND
的操作數,[操作數] 不應同時為NOT
。
該要求的第二部分有點奇怪,因為AND
運算符被定義為左關聯。 那將意味着
a AND NOT b AND NOT c
將是合法的,因為它被分組為(a AND NOT b) AND NOT c
,其中兩個AND
運算符都有一個正項。 但是旋轉參數(這可能根本不會改變語義)會產生:
NOT b AND NOT c AND a
這是非法的,因為第一個分組( NOT b AND NOT c
)包含兩個NOT
表達式。
其意圖可能是任何連詞( AND
運算符的序列)至少包含一個正項。
這兩種約束都是可能的,但不能使用運算符優先級聲明來實現。
運算符優先級可用於解決歧義文法中的歧義(並且expr: expr OR expr
肯定是歧義的,因為它允許OR
在任一方向關聯)。 但它不能用於導入對操作數的附加要求,特別是不能同時考慮兩個操作數的要求 [注 1]。 為了做到這一點,你需要寫出一個明確的語法。 幸運的是,這並不太難。
明確語法的基礎是有時稱為級聯優先風格; 這有效地將優先級編碼為規則,因此不需要優先級聲明。 基本的布爾語法如下所示:
expr: conjunction /* Cascade to the next level */
| expr OR conjunction
conjunction
: term /* Continue the cascade */
| conjunction AND term
term: atom /* NOT is a prefix operator */
| NOT term /* which is not what you want */
atom: '(' expr ')'
| STRING
每個優先級都有一個相應的非終結符,並且這些級別是“級聯”的,意思是除了最后一個級別之外,每個級別都包括下一個級別作為一個單元產品。
為了適應這種的要求,即NOT
被限制的最多一個操作數AND
運算符,我們可以寫出來的可能性或多或少,你在原來的語法一樣,但尊重級聯樣式:
expr: conjunction
| expr OR conjunction
conjunction
: atom /* NOT is integrated, so no need for 'term' */
| conjunction AND atom
| conjunction AND NOT atom /* Can extend with a negative */
| NOT atom AND atom /* Special case for negative at beginning */
atom: '(' expr ')'
| STRING
對於第三個規則conjunction
( conjunction: conjunction AND NOT atom
)允許任意數量的NOT
在操作數的一個列表的末尾將被添加的應用程序,但不允許連續NOT
操作數在列表的開頭。 第四條規則允許在開頭有一個NOT
。
如果您更喜歡連詞必須至少有一個正項的規則,您可以使用以下非常簡單的改編:
expr: conjunction
| expr OR conjunction
conjunction
: atom /* NOT is integrated, so no need for 'term' */
| conjunction AND atom
| conjunction AND NOT atom
| negative AND atom /* Possible initial list of negatives */
negative /* This is not part of the cascade */
: NOT atom
| negative AND NOT atom
atom: '(' expr ')'
| STRING
在這個變體中, negative
將匹配,例如NOT a AND NOT b AND NOT c
。 但是因為它不在級聯中,所以該序列不會自動成為有效的表達式。 為了將它用作表達式,它需要是連接的一部分conjunction: negative AND atom
,這要求序列包含正數。
%nonassoc
優先級聲明可用於拒絕相同優先級的運算符的鏈式使用。 這有點像黑客攻擊,有時會產生意想不到的后果。 預期的用例是像 C 這樣的語言中的運算符<
,它沒有對鏈式比較進行特殊處理; 使用%nonassoc
您可以聲明在比較運算符的優先級中鏈接是非法的。
但是%nonassoc
僅在單個優先級內有效,並且只有在優先級中的所有運算符都需要相同處理時才有效。 如果預期的語法不完全符合這些要求,則有必要 - 與此語法一樣 - 放棄使用優先級聲明並寫出明確的語法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.