2

我在构建能够解析 Python 3 的 AST 转储格式并将其转换为更易于使用的 AST 格式的语法时遇到问题。我决定为此编写一个 ANTLR 语法,但我在处理关键字块时遇到了问题(但出于某种原因,只有关键字块)。我把关键字语法隔离出来了,如图:

grammar kwds;
options {output=AST;}

keywords:   'keywords=['((', '?)keyword)*']' -> keyword*
    ;

keyword :   'keyword(arg='STRING', value='str')'
    ;
str :   'Str(s='STRING')' -> STRING
    ;

STRING
    :  '\'' ( ESC_SEQ | ~('\\'|'\'') )* '\''
    ;

fragment
ESC_SEQ
    :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
    |   UNICODE_ESC
    |   OCTAL_ESC
    ;

EMPTYBRACKETS
    :   '[]';

fragment
OCTAL_ESC
    :   '\\' ('0'..'3') ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7')
    ;

fragment
UNICODE_ESC
    :   '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
    ;

fragment
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;

这旨在接受关键字列表(0个或更多带有逗号分隔符),其格式显示在关键字规则中。

如果您为上述语法提供以下(有效)输入,

关键字=[关键字(arg='name', value=Str(s='UGA')), 关键字(arg='rank', value=Str(s='2'))]

语法会认识到这一点,因为它应该。

但是,使用我编写的“完整”python 3 AST 格式语法(可在http://pastebin.com/ETrSVXvf找到以节省空间,上述两条规则分别位于第 106 行和第 109 行),它使用几乎完全相同的语法规则,在从上面显示的示例中解析第一个关键字匹配后,令牌流似乎少了几个字符,在针对关键字规则进行解析时产生以下输出:

sample3.txt line 1:52 mismatched character 'e' expecting 'w'
sample3.txt line 1:53 no viable alternative at character 'y'
sample3.txt line 1:54 no viable alternative at character 'w'
sample3.txt line 1:55 no viable alternative at character 'o'
sample3.txt line 1:56 no viable alternative at character 'r'
sample3.txt line 1:57 no viable alternative at character 'd'
sample3.txt line 1:58 no viable alternative at character '('
sample3.txt line 1:59 missing ENDBR at 'arg='

我只能想到发生这种情况的一种可能性:由于语法中的歧义,某些东西被错误地标记,因为我用来检测多个关键字语句的模式适用于其他类型的语句。但是,我完全不知道语法中的歧义实际上在哪里。

此外,任何关于如何提高我的语法的一般改进技巧都将不胜感激!

4

1 回答 1

1

如果添加规则:

parse
 : (t=. {System.out.printf("type=\%-20s text='\%s'\n", tokenNames[$t.type], $t.text);})* EOF
 ;

它只匹配零个或多个标记并打印出这些标记的类型和文本,您将看到词法分析器无法处理, keyword示例中的输入:

keywords=[keyword(arg='name', value=Str(s='UGA')), keyword(arg='rank', value=Str(s='2'))]
                                                 ^^^^^^^^^

因此,您的解析器规则之一没有问题,但是在词汇级别上出现了问题。

我建议您从解析器中删除所有文字标记并为它们创建词法分析器规则。然后添加一条parse我在上面发布的规则,您可以使用它测试词法分析器以查看是否创建了正确的标记。创建正确的标记后,编写解析器规则。

我很确定这里的问题是您没有', keyword'令牌,并且一旦词法分析器“看到” ', k',它就会尝试创建一个', kwargs'失败的令牌,当然。因此,我还建议您不要标记中包含逗号和空格,而是让它们成为自己的标记。

此外,您不希望有这样的重写规则:

stmtlist:       ((', '?) stmt)* -> stmt*
        ;

这可能不匹配任何内容。如果发生这种情况,ANTLR 将在创建 AST 时抛出异常。总是让重写规则产生一些东西

...

tokens {
  ...
  STMTLST;
  ...
}

...

stmtlist:       ((', '?) stmt)* -> ^(STMTLST stmt*)
        ;
于 2012-03-25T11:45:55.027 回答