antlr4 - 尝试处理引号的简单 ANTLR 语法打嗝
问题描述
我想解析“ Prolog atom”列表,即在某些情况下必须将其放入单引号中的简单字符串,以免它们与变量名或整数混淆,以允许包含空格以及允许包含单引号本身.
应处理包含数字后跟 olon 后跟 Prolog 原子列表的输入文件。
例如,输入文件可能是:
1: [ foo, bar ]
2: [ alpha, 'THIS IS VARIABLE NAMES WITH BLANKS THUS QUOTES' , '_also_a_variable_name' ]
3: [ empty_atom_follows, '' ]
4: []
5: [ 'the above is an empty list' ]
6: [ 'single quotes \' are possible' ]
我正在 IntellijIDEA 中尝试这个,它有一个很好的插件,您可以在其中试验语法并获得关于词法分析/解析是否成功的即时反馈(非常宝贵!)。
到目前为止的语法如下。
请注意,我不能丢弃空白,因为它们可能出现在引用的原子内,它们很重要。
grammar simple;
file : line ( EOL line )* EOL? ;
line : BLANK* uinteger BLANK* COLON BLANK* list_of_atom BLANK* ;
empty_list : '[' BLANK* ']' ;
list_of_atom : empty_list
| '[' BLANK* atom (BLANK* ',' BLANK* atom)* BLANK* ']'
;
uinteger : DIGIT+ ;
atom : fused_atoms
| quoted_atom
| unquoted_atom
| empty_atom
;
empty_atom : '\'\''; // literally: '', no blanks
unquoted_atom : LOWER atom_char_not_needing_quotation* ;
quoted_atom : '\'' atom_char_any+ '\'' ;
fused_atoms : quoted_atom ( quoted_atom )+ ;
atom_char_not_needing_quotation : LOWER | UPPER | DIGIT | USCORE ;
atom_char_any : LOWER | UPPER | DIGIT | USCORE | DASH | BLANK | quote_escape ;
quote_escape : ('\\\'') ;
LOWER : [a-z] ;
UPPER : [A-Z] ;
DIGIT : [0-9] ;
USCORE : '_' ;
DASH : '-' ;
DOT : '.' ;
SIGN : '+' | '-' ;
COLON : ':' ;
EOL : [\r\n];
BLANK : [\t ];
我正在为fused_atoms
.
在 Prolog 中,(至少)有两种方法可以将单引号插入到原子中:
用退格键将其转义:
?- X = 'a\'b'.
X = 'a\'b'.
用单引号转义它:
?- X = 'a''b'.
X = 'a\'b'.
为了获得相同的效果,我想保留将原子视为“几个融合原子”(实际上是连接引用的原子)的可能性,即
'a''b'
应被解析为两个并排引用的原子,组合成一个“融合原子”。我的想法是,通过后处理,我将在两个字符串之间加上一个单引号。
显然 ANTLR 不喜欢我的规则。
如果我给它
1 : [ 'a''b' , 'a\'\'\'b' , '\' ', ' ']
它变得困惑:
line 1:8 no viable alternative at input ''a'''
解析树表示失败,因为它试图一次抓住两个单引号:
怎么了?
解决方案
通常,您希望将字符串 (ATOM) 解析为单个标记,而不是在解析器规则中汇集的一堆单独标记:
词法分析器规则:
ATOM: '\'' ('\\\'' | '\'\'' | ~'\'')* '\'';
将处理嵌入引号的“'”(斜线引号)和“''”(引号)表示。快速替换所有标记文本将负责将这些后处理为单个嵌入的 ' 引用。
在您的评论中,您提到了未引用ATOM
的 s。您可以像这样修改您的 ATOM Lexer 规则:(基于您问题中的规则)
ATOM:
'\'' ('\\\'' | '\'\'' | ~'\'')* '\''
| LOWER (LOWER | UPPER | DIGIT | USCORE)*;
现在你有一个ATOM
词法分析器规则,它会给你一个ATOM
在你的规则中使用的标记。
这将导致更简单的解析器规则,但也许更重要的是,当您开始处理解析树时,会产生更简单的 ParseTree 和 *Context 类。
修改后的语法将是:
grammar Simple;
file: line ( EOL line)* EOL?;
line: U_INTEGER COLON list_of_atom;
empty_list: '[' ']';
list_of_atom: empty_list | '[' ATOM (',' ATOM)* ']';
U_INTEGER: DIGIT+;
DASH: '-';
DOT: '.';
SIGN: '+' | '-';
COLON: ':';
EOL: [\r\n];
BLANK: [\t ] -> skip;
ATOM:
'\'' ('\\\'' | '\'\'' | ~'\'')* '\''
| LOWER (LOWER | UPPER | DIGIT | USCORE)*;
fragment LOWER: [a-z];
fragment UPPER: [A-Z];
fragment DIGIT: [0-9];
fragment USCORE: '_';
传递这个输入:
1 : [ 'a''b' , 'a\'\'\'b' , '\' ', ' ', 'atom with embedded spaces', ab_c]
给出以下 TokenStream:
[@0,0:0='1',<U_INTEGER>,1:0]
[@1,2:2=':',<':'>,1:2]
[@2,4:4='[',<'['>,1:4]
[@3,6:11=''a''b'',<ATOM>,1:6]
[@4,13:13=',',<','>,1:13]
[@5,16:25=''a\'\'\'b'',<ATOM>,1:16]
[@6,29:29=',',<','>,1:29]
[@7,31:35=''\' '',<ATOM>,1:31]
[@8,36:36=',',<','>,1:36]
[@9,38:40='' '',<ATOM>,1:38]
[@10,41:41=',',<','>,1:41]
[@11,43:69=''atom with embedded spaces'',<ATOM>,1:43]
[@12,70:70=',',<','>,1:70]
[@13,72:75='ab_c',<ATOM>,1:72]
[@14,76:76=']',<']'>,1:76]
[@15,77:76='<EOF>',<EOF>,1:77]
推荐阅读
- javascript - 将 js 对象转换为分层 JSON 结构
- regex - 从出现在特定单词之后的字符串中提取值
- c# - c sharp 类型模式导致编译器错误
- python - Python中的极坐标绘图(没有原点的圆弧)
- python - python - 惩罚游戏如何加速元素
- mysql - Prem MySQL 和 Azure 数据存储之间的数据同步
- android - 将最大视图的左侧与约束布局对齐
- python - Jupyter Notebook 将目录/文件路径添加到 Windows 环境变量
- scilab - 更改 SCILAB 中的输出格式
- asp.net - 如何从 ASP.NET 中的静态文件返回响应?