我遇到了一个构建语法的问题,该语法能够解析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或更多逗号分隔符),格式显示在关键字规则中。
如果您给上述语法提供以下(有效)输入,
keywords = [keyword(arg ='name',value = Str(s ='UGA')),keyword(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='
我只能想到这种情况发生的一种可能性:由于语法含糊不清,某些东西被错误地标记化,因为我用来检测多个关键字语句的模式适用于其他类型的语句。但是,我完全不知道语法中的歧义究竟在哪里。
此外,任何关于如何提高我的语法的一般改进提示将不胜感激!
答案 0 :(得分: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'
,它就会尝试创建一个{{1}当然,令牌失败了。所以我也建议你不在你的标记中包含逗号和空格,但让它们成为自己的标记。
此外,您不希望有这样的重写规则:
', kwargs'
可能没有任何匹配。如果发生这种情况,ANTLR将在创建AST时抛出异常。始终让重写规则生成某事:
stmtlist: ((', '?) stmt)* -> stmt*
;