Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/arduino/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
ANTLR4:使用关键字(别名?)清理语法和树_Antlr_Antlr4_Grammar - Fatal编程技术网

ANTLR4:使用关键字(别名?)清理语法和树

ANTLR4:使用关键字(别名?)清理语法和树,antlr,antlr4,grammar,Antlr,Antlr4,Grammar,我正在寻找一个简单问题的解决方案 示例: SELECT date, date(date) FROM date; simple_select : SELECT selected_element (',' selected_element) FROM from_element ';' ; selected_element : function | REGULAR_WORD ; function : REGULAR_WORD '(' functio

我正在寻找一个简单问题的解决方案

示例:

SELECT date, date(date)
FROM date;
simple_select
    : SELECT selected_element (',' selected_element) FROM from_element ';'
    ;

selected_element
    : function
    | REGULAR_WORD
    ;

function
    : REGULAR_WORD '(' function_argument ')'
    ;

function_argument
    : REGULAR_WORD
    ;

from_element
    : REGULAR_WORD
    ;


DATE:     D A T E;
FROM:     F R O M;
SELECT:   S E L E C T;

REGULAR_WORD
    : (SIMPLE_LETTER) (SIMPLE_LETTER | '0'..'9')*
    ;

fragment SIMPLE_LETTER
    : 'a'..'z'
    | 'A'..'Z'
    ;
这是一个相当愚蠢的示例,其中一个表、它的列和一个函数都有名称“date”

我的语法片段(非常简单):

SELECT date, date(date)
FROM date;
simple_select
    : SELECT selected_element (',' selected_element) FROM from_element ';'
    ;

selected_element
    : function
    | REGULAR_WORD
    ;

function
    : REGULAR_WORD '(' function_argument ')'
    ;

function_argument
    : REGULAR_WORD
    ;

from_element
    : REGULAR_WORD
    ;


DATE:     D A T E;
FROM:     F R O M;
SELECT:   S E L E C T;

REGULAR_WORD
    : (SIMPLE_LETTER) (SIMPLE_LETTER | '0'..'9')*
    ;

fragment SIMPLE_LETTER
    : 'a'..'z'
    | 'A'..'Z'
    ;
日期是一个关键字(它在语法中的其他地方使用)。 如果我想让我的语法将其识别为一个普通单词,以下是我的解决方案:

SELECT date, date(date)
FROM date;
simple_select
    : SELECT selected_element (',' selected_element) FROM from_element ';'
    ;

selected_element
    : function
    | REGULAR_WORD
    ;

function
    : REGULAR_WORD '(' function_argument ')'
    ;

function_argument
    : REGULAR_WORD
    ;

from_element
    : REGULAR_WORD
    ;


DATE:     D A T E;
FROM:     F R O M;
SELECT:   S E L E C T;

REGULAR_WORD
    : (SIMPLE_LETTER) (SIMPLE_LETTER | '0'..'9')*
    ;

fragment SIMPLE_LETTER
    : 'a'..'z'
    | 'A'..'Z'
    ;
1)我把它添加到我用过的所有常规单词旁边。 例如:

selected_element
    : function
    | REGULAR_WORD
    | DATE
    ;
word
    : REGULAR_WORD
    | DATE
    ;

selected_element
    : function
    | word
    ;
=>我不想要这个解决方案。我不仅仅把“DATE”作为一个关键字,而且我有很多使用常规单词的规则,所以我需要在许多(20+)语法规则中添加一个包含许多(50+)关键字的列表,比如DATE:这绝对是难看的

优点:做一棵干净的树

缺点:弄脏语法

2)我在两者之间使用一个解析器规则来获取所有这些关键字,然后,我用该解析器规则替换所有出现的常规单词。 例如:

selected_element
    : function
    | REGULAR_WORD
    | DATE
    ;
word
    : REGULAR_WORD
    | DATE
    ;

selected_element
    : function
    | word
    ;
=>我也不想要这个解决方案,因为它在树中又添加了一个解析器规则并污染了信息(我不想知道“date”是一个单词,我想知道它是一个选定的元素、一个函数、一个函数参数或一个from元素

优点:语法清晰

缺点:弄脏一棵树

无论哪种方式,我都有一棵肮脏的树或一条肮脏的语法。难道没有一种方法可以将两者都清理干净吗?

我寻找了别名,解析器片段的等价物,但看起来ANTLR4没有


谢谢,祝您愉快!

中有四种不同的SQL方言语法,它们都使用了您的第二种策略。因此,Antlr4 SQL语法编写者之间似乎达成了共识。鉴于Antlr4 lexer的设计,我不相信有更好的解决方案

正如您所说,这会导致整个解析树中出现一些杂音,但是相关的非终端(
函数
选定的元素
,等等)肯定存在,并且在我看来,将单元产品从解析树中折叠出来并不困难

据我所知,在设计Antlr4时,决定只自动生成完整的解析树,因为压缩(“抽象”)的设计语法树太特殊了,不适合语法DSL。因此,如果您发现AST更方便,您有责任自己生成一个。这通常是直截了当的,尽管它涉及很多样板文件

其他解析器生成器也有处理“半保留关键字”的机制。特别是,作为Sqlite项目的一部分,Lemon解析器生成器包含一个
%回退声明,该声明允许您指定一个或多个令牌应在语法规则不允许使用的上下文中自动重新分类。遗憾的是,Lemon不生成Java解析器


另一个类似的选择是使用支持“无扫描”解析的解析器生成器。这类解析器通常使用Earley/GLL/GLR等算法,能够解析任意CFG,以避开对更多前瞻性的需求,而不是像LALR(1)这样的固定前瞻性算法所能方便地支持的.

这是所谓的关键字作为标识符的问题,以前已经讨论过很多次。例如,我在6年前的中就提出了一个类似的问题。但在Stackoverflow,也有一些问题涉及到这一领域,例如

特伦斯·帕尔(Terence Parr)在2008年写了一篇文章,简要介绍了两种可能的解决方案:

该语法允许“if call;”和“call if;”

通过插入这些字符串,可以进行整数比较,而不是字符串比较,从而提高这些语义谓词的效率

另一种选择是这样做

这是一个集合比较,应该更快

通常,正如@rici已经提到的,人们更喜欢将所有关键字保留在自己的规则中,并将其添加到普通标识符规则中的解决方案(在允许使用此类关键字的情况下)


wiki中的另一个解决方案可以针对任何关键字进行推广,方法是在
ID
lexer规则中的操作中使用查找表/列表,用于检查给定字符串是否为关键字。此解决方案不仅速度较慢,而且还牺牲了解析器语法的清晰度,因为您不能再在解析器规则中使用关键字标记s、

恐怕这个问题没有解决办法。它被称为“上下文敏感词法分析器”。当你想要向后兼容语法时,这是你必须付出的代价(例如Oracle SQL,它们确实区分“关键字”和“保留字”)@ibre5041:谢谢你的回答。这就是我担心的。你说的“关键字”是什么意思它被称为“上下文敏感词缀器”?你的意思是解决我问题的语法应该有一个“上下文敏感词缀器”吗?感谢您提供了完整的答案!在解析后处理中折叠关键字确实不难,但如果您不得不再次梳理树以删除“无用”的关键字,则有点违背了解析的目的节点。我想我现在有了我的答案,但很遗憾ANTLR没有解决这个问题。看到其他解析器生成器提出了解决这个问题的方法,这很有趣。干杯。@louis:你不必修剪解析树,你只需按照你想要的方式来构建它。这在yacc/bison/lemo中很常见例如,基于n的解析器。对于大多数单元产品(
a:b
),AST节点只是通过语义操作传递,而不是构建新节点。传递是默认的yacc操作,但构建AST节点的操作是样板文件-y.Hi,感谢answe