解析具有嵌入式多行控制字符序列的字符串

时间:2019-06-29 14:37:33

标签: antlr antlr4

我正在为实时编程语言PEARL编写编译器。 PEARL支持具有嵌入式控制字符序列的字符串,例如

'some text'\1B 1B 1B\'some more text'.

控制字符序列以'\为前缀,以\'结尾。 控制序列内部有两位数字,用于指定控制字符。

在上面的示例中,结果字符串为

'some textESCESCESCsome more text'

ESC代表不可打印的ASCII转义字符。

此外,控制字符序列内部还允许换行符来构建多行字符串,例如

'some text'\1B 
1B 
1B\'some more text'.

与上面的字符串相同。

grammar stringliteral;

tokens {
    CHAR,CHARS,CTRLCHARS,ESC,WHITESPACE,NEWLINE
}

stringLiteral:  '\'' CHARS? '\'' ;

fragment
CHARS: CHAR+ ;

fragment
CHAR: CTRLCHARS | ~['\n\r] ;

fragment
ESC: '\'\\' ;

fragment
CTRLCHARS: ESC ~['] ESC;

WHITESPACE: (' ' | '\t')+ -> channel(HIDDEN);

NEWLINE: ( '\r' '\n'? | '\n' ) -> channel(HIDDEN);

上面的词法分析器/解析器的行为非常奇怪,因为它仅接受 字符串,格式为“ x”,并忽略多个字符和控制字符序列。

我可能正在监督一些显而易见的事情。欢迎任何提示或想法解决此问题!

我现在已经根据迈克的提示纠正了语法:

grammar stringliteral;

tokens {
     STRING
}

stringLiteral: STRING;
STRING: '\'' ( '\'' '\\' | '\\' '\'' | . )*? '\'';

识别控制字符序列的末尾仍然存在问题:

输入'A STRING'\ CTRL \''会产生错误

Line 1:10 token recognition error at: '\'
line 1:11 token recognition error at: 'C'
line 1:12 token recognition error at: 'T'
line 1:13 token recognition error at: 'R'
line 1:14 token recognition error at: 'L'
line 1:15 token recognition error at: '\'

有什么主意吗?顺便说一句:我们正在使用antlr v 4.5。

2 个答案:

答案 0 :(得分:0)

此语法有多个问题:

  1. 您不能在解析器规则中使用片段词法分析器规则。
  2. 您的字符串规则是一个解析器规则,因此它受您用WHITESPACENEWLINE规则定义的自动空格删除的约束。
  3. 您没有规则接受\1B 1B 1B之类的控制字符序列。

尤其是第三点是一个实际的问题,因为您不知道控制序列在哪里结束(除非这只是一个错字,而您实际上的意思是:\1B \1B \1B

无论如何,不​​要在词法分析器中处理转义序列(除非使规则起作用所需的最低限度处理,即\'序列的处理。您的规则只需要解析整个文本并您可以在语义阶段找出转义序列:

STRING: '\' ('\\' '\'' | . )*? '\''; 

注意*?是非贪心运算符,用于在第一个结束引号char处停止。否则,词法分析器将继续匹配同一字符串规则(贪婪行为)中的所有以下(转义和非转义)引号字符。此外,字符串规则现在是词法分析器规则,不受空白跳的影响。

答案 1 :(得分:0)

我通过修改最新的Java语法示例中的适当规则,解决了该语法片段的问题:

StringLiteral
    :   '\'' StringCharacters? '\''
    ;

fragment
StringCharacters
    :   StringCharacter+
    ;

fragment
StringCharacter
    :   ~['\\\r\n]
    |   EscapeSequence
    ;

fragment
EscapeSequence
    : '\'\\' (HexEscape| ' ' | [\r\n])* '\\\''
    ;

fragment
HexEscape
    :  B4Digit B4Digit
    ;

fragment
B4Digit
    : '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | 'A' | 'B' |     'C' | 'D' | 'E' | 'F'
    ;