我正在使用ANTLR 3来执行以下操作。
假设我有一个SQL查询。我知道通常它的WHERE,ORDER BY和GROUP BY子句是可选的。就ANTLR的语法而言,我会这样描述:
query : select_clause from_clause where_clause? group_by_clause? order_by_clause?
每个子句的规则显然都以相应的关键字开头。
我真正需要的是将每个子句的内容作为字符串提取而不处理其内部结构。
为此,我开始使用以下语法:
query : select_clause from_clause where_clause? group_by_clause? order_by_clause? EOF; select_clause : SELECT_CLAUSE ; from_clause : FROM_CLAUSE ; where_clause : WHERE_CLAUSE ; group_by_clause : GROUP_BY_CLAUSE ; order_by_clause : ORDER_BY_CLAUSE ; SELECT_CLAUSE : 'select' ANY_CHAR*; FROM_CLAUSE : 'from' ANY_CHAR*; WHERE_CLAUSE : 'where' ANY_CHAR*; GROUP_BY_CLAUSE : 'group by' ANY_CHAR*; ORDER_BY_CLAUSE : 'order by' ANY_CHAR*; ANY_CHAR : .; WS : ' '+ {skip();};
这个没有用。我进一步尝试编写正确的语法但没有成功。我怀疑这个任务对ANTLR3是可行的,但我只是错过了。
更一般地说,我希望能够将输入流中的字符收集到单个令牌中,直到遇到指示新令牌开头的特定关键字。此关键字应该是新令牌的一部分。
你能帮我吗?
答案 0 :(得分:2)
为什么不将ANY_CHAR*
移到解析器规则中而不是将它们添加到令牌中?您甚至可以使用重写规则将这些单个令牌“粘合”在一起。
快速演示:
grammar T;
options { output=AST; }
tokens { QUERY; ANY; }
query : select_clause from_clause where_clause? group_by_clause? order_by_clause? EOF
-> ^(QUERY select_clause from_clause where_clause? group_by_clause? order_by_clause?)
;
select_clause : SELECT_CLAUSE^ any;
from_clause : FROM_CLAUSE^ any;
where_clause : WHERE_CLAUSE^ any;
group_by_clause : GROUP_BY_CLAUSE^ any;
order_by_clause : ORDER_BY_CLAUSE^ any;
any : ANY_CHAR* -> ANY[$text];
SELECT_CLAUSE : 'select';
FROM_CLAUSE : 'from';
WHERE_CLAUSE : 'where';
GROUP_BY_CLAUSE : 'group' S+ 'by';
ORDER_BY_CLAUSE : 'order' S+ 'by';
ANY_CHAR : . ;
WS : S+ {skip();};
fragment S : ' ' | '\t' | '\r' | '\n';
如果你现在解析输入:
select JUST ABOUT ANYTHING from YOUR BASEMENT order by WHATEVER
将创建以下AST:
尝试在你的词法分析器中做类似的事情会很混乱,并且意味着一些自定义代码(或谓词)在char-stream中提前检查关键字(两者都不漂亮!)。