我正在努力理解这个SQL语法如何用于从解析器中解析下面提供的SQL语句。我被困在'表引用'和'加入'构造之后找到WHERE标记。
BNF:http://www.contrib.andrew.cmu.edu/~shadow/sql/sql2bnf.aug92.txt
<table reference> ::=
<table name> [ <correlation specification> ]
| <derived table> <correlation specification>
| <joined table>
<joined table> ::=
<cross join>
| <qualified join>
| <left paren> <joined table> <right paren>
<cross join> ::=
<table reference> CROSS JOIN <table reference>
<qualified join> ::=
<table reference> [ NATURAL ] [ <join type> ] JOIN <table reference> [ <join specification> ]
<join type> ::=
INNER
| <outer join type> [ OUTER ]
| UNION
<outer join type> ::= LEFT | RIGHT | FULL
<join specification> ::= <join condition> | <named columns join>
<join condition> ::= ON <search condition>
<named columns join> ::= USING <left paren> <join column list> <right paren>
SQL:
SELECT p.Name, v.Name
FROM Production.Product p
JOIN Purchasing.ProductVendor pv
ON p.ProductID = pv.ProductID
JOIN Purchasing.Vendor v
ON pv.BusinessEntityID = v.BusinessEntityID
WHERE ProductSubcategoryID = 15
ORDER BY v.Name;
跳转到FROM caluse。这里有一个TableName,后跟两个JOIN。
如果您查看“表格引用”,那么您会看到它包含“表格名称”。这是我能理解的。
<table reference> ::=
**<table name> [ <correlation specification> ]**
| <derived table> <correlation specification>
| <joined table>
但是为了获得连接,解析器必须到达它不能的'Joined table',因为它已经准备好读取'table name'。
要达到加入,解析器必须达到“合格加入”,但不能,因为BNF中没有重复。如果它以某种方式到达'Join table'元素,那么如果会非常失望,因为下一次读取将再次是'Table reference'然后它将再次达到'Qualifed join',然后......然后你得到一个堆栈溢出。
<joined table> ::=
<cross join>
| <**qualified join>**
| <left paren> <joined table> <right paren>
**<qualified join>** ::=
<table reference> [ NATURAL ] [ <join type> ] JOIN <table reference> [ <join specification> ]
我没有到这里来的?我确信它有一个技巧,但我只是没有看到它。
我希望你的一些才华横溢的家伙可以向我解释这对我的impossibel语法有什么影响。
如何构建一个让我们说一个递归的正确解析器来解决这个语法?
解析器需要遵循哪些步骤和/或规则?
祝你好运, 布莱恩安德森
答案 0 :(得分:1)
该语法不是LL(1),这是构建递归下降解析器所需的。我怀疑SQL是否有LL(1)语法,特别是如果有一个可以生成正确的解析树的语法。幸运的是,这并不重要,因为有更强大的解析技术。
很可能您可以使用该语法来构建LALR(1)解析器,使用像bison / yacc这样的工具。或者查看sqlite source code,其中包括LALR(1)语法和名为&#34; lemon&#34;的LALR(1)解析器生成器。
答案 1 :(得分:0)
问这个问题已经有一段时间了,但是由于ANTLR的性能/内存问题,我正在考虑将ANTLR4 SQL解析器重写为RDP。
因此,我(在思想上)解决JOIN问题的方式是,我将它们像运算符一样对待,因为这就是它们的本质(至少这是我的印象)。
基本表达语法既适合常用表达又适合于联接:
ex
: '(' ex ')'
| ex OPERATOR ex
| TERMINAL
;
在JOIN情况下,您的OPERATOR变为JOIN,而TERMINAL成为表引用。
现在,这种左递归语法不是LL语法,但可以将其转换为ANTLR4自动执行的语法。