[英]Solving a parsing conflict in SQLite grammar
我試圖在某一點擴展 SQLite 的 SQL 語言(文件 parse.y)。 我有一個解析沖突,但是檸檬解析器除了隨機的“1 解析沖突”之外沒有顯示任何內容。 錯誤信息。
問題出在 create_table 可以簡化為“CREATE”或“CREATE OR REPLACE”的位置,然后是 temp,也可以簡化為空令牌。
cmd ::= create_table create_table_args table_properties_args.
create_table ::= createorreplace(C) temp(T) TABLE ifnotexists(E) nm(X) dbnm(Y). {
// ...
}
%type createorreplace {int}
createorreplace(A) ::= CREATE. {disableLookaside(pParse); A = 0;}
createorreplace(A) ::= CREATE OR REPLACE. {disableLookaside(pParse); A = 1;}
%type temp {int}
temp(A) ::= TEMP. {A = pParse->db->init.busy==0;}
temp(A) ::= . {A = 0;}
我怎樣才能使“OR REPLACE”可選地減少,同時保留它可以跟隨 TEMP?
由於我只能猜測您可能如何以及在何處更改了 SQLite 的 SQL 語法,因此這個答案必然有些試探性。 但無論如何它可能是有用的。
原始 SQL 語法包含以下產生式(我省略了這些操作,因為它們與診斷沖突無關):
cmd ::= create_table create_table_args.
create_table ::= createkw temp(T) TABLE
ifnotexists(E) nm(Y) dbnm(Z).
createkw(A) ::= CREATE(A).
temp(A) ::= TEMP.
temp(A) ::= .
cmd ::= createkw(X) temp(T) VIEW
ifnotexists(E) nm(Y) dbnm(Z) eidlist_opt(C) AS select(S).
您似乎已將create_table
修改為改為:
create_table ::= createorreplace(C) temp(T) TABLE
ifnotexists(E) nm(X) dbnm(Y).
createorreplace(A) ::= CREATE.
createorreplace(A) ::= CREATE OR REPLACE.
這種變化確實會產生沖突,但它與temp
可以為空無關。 事實上,它與非終端temp
幾乎沒有關系。 您可以將temp
替換為TEMP
(從而使其成為強制性而不是可選的),並且您仍然會遇到 shift-reduce 沖突。
開始CREATE TEMP
的輸入會發生沖突。 該輸入可能是開始
CREATE TEMP TABLE ...
CREATE TEMP VIEW ...
這些顯然是不同的語法,並且沒有歧義但是當終端CREATE
剛剛被讀取並且終端TEMP
是前瞻令牌時,這兩種可能性仍然可用。 這不一定是問題。 自下而上的解析器不需要解析將使用哪個可能的生產,直到它到達生產的末尾。 所以原始語法工作正常,沒有沖突。
但請注意,原始語法沒有以終端CREATE
開頭的cmd
產生。 它有幾個以非終端createkw
開頭的cmd
產品。 但是那里也沒有混淆的可能性。 終端CREATE
在兩個cmd
產品(以及我未列出的其他cmd
產品,它們也以createkw
)中都簡化為createkw
。
但是,在您修改后的語法中,這兩個產生式並非都以createkw
。 其中一個已更改為以createorreplace
。
不包含可選關鍵字TEMP
的輸入仍然可以毫無問題地解析。 如果TEMP
不存在,則前瞻標記將是create_table
命令中的TABLE
,而前瞻標記將是 create view 命令中的VIEW
。 由於前瞻標記不同,解析器可以毫不費力地決定是歸createkw
還是歸createorreplace
。 類似地,如果輸入實際上是CREATE OR REPLACE ...
,則前瞻標記將是OR
,這明確地強制減少到createorreplace
。
但如上所示,有問題的輸入會啟動CREATE TEMP
。 現在,解析器必須在沒有看到終端TEMP
之后的任何內容的情況下決定是將CREATE
簡化為createkw
還是將其簡化為createorreplace
。 由於無法做出該確定,因此報告了沖突。 (通過查看 Lemon 報告文件parse.out
,您會發現有關該沖突的更多信息。)
解決方案(如果我對您的語法修改的猜測是正確的)是避免強迫解析器做出不必要的決定。 這需要一點語法重復:
cmd ::= create_table create_table_args.
create_table ::= createkw temp(T) TABLE ifnotexists(E) nm(Y) dbnm(Z).
create_table ::= createorreplace temp(T) TABLE ifnotexists(E) nm(Y) dbnm(Z).
createkw(A) ::= CREATE(A).
createorreplace(A) ::= CREATE OR REPLACE.
temp(A) ::= TEMP.
temp(A) ::= .
cmd ::= createkw(X) temp(T) VIEW ifnotexists(E) nm(Y) dbnm(Z)
eidlist_opt(C) AS select(S).
現在,不跟隨OR REPLACE
的終端CREATE
始終簡化為createkw
,而序列CREATE OR REPLACE
始終簡化為createorreplace
。 這是有效的,因為除了CREATE OR REPLACE
之外,沒有可能解析開始CREATE OR
的cmd
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.