无法在Antlr4中使用自定义分隔符实现q引用字符串

时间:2018-04-11 13:27:04

标签: antlr grammar antlr4 lexer quoted-identifier

我试图为oracle Q引用字符串机制实现词法分析器规则,其中我们有q' $ some string $'

在这里你可以用任何字符代替除空白之外的$,(,{,[,<,但是字符串必须以相同的字符开头和结尾。接受的标记的一些例子是: q'!一些字符串!' q' ssome strings' 请注意s是自定义分隔符,但也可以在字符串中使用它,因为我们只会在s'

结束

以下是我试图实施规则的方法:

Q_QUOTED_LITERAL: Q_QUOTED_LITERAL_NON_TERMINATED . QUOTE-> type(QUOTED_LITERAL); 

Q_QUOTED_LITERAL_NON_TERMINATED:
    Q QUOTE ~[ ({[<'"\t\n\r] { setDelimChar( (char)_input.LA(-1) ); } 
    ( . { !isValidEndDelimChar() }? )* 
;

我已经检查了我得到的值!isValidEndDelimChar()并且我在正确的位置得到了一个假谓词,所以一切都应该有效,但是antlr只是忽略了这个谓词。我也试过移动谓词,把这部分放在一个单独的规则中,以及其他一些东西,经过一天半的研究,我终于提出了这个问题。

我也尝试过以其他方式实现它,但似乎没有一种方法可以在antlr4中实现自定义字符分隔的字符串(用于工作的antlr3版本)。

1 个答案:

答案 0 :(得分:2)

不确定为什么{ ... }动作未被调用,但不需要它。以下语法对我有效(将谓词放在.!前面):

grammar Test;

@lexer::members {
  boolean isValidEndDelimChar() {
    return (_input.LA(1) == getText().charAt(2)) && (_input.LA(2) == '\'');
  }
}

parse
 : .*? EOF
 ;

Q_QUOTED_LITERAL
 : 'q\'' ~[ ({[<'"\t\n\r] ( {!isValidEndDelimChar()}? . )* . '\''
 ;

SPACE
 : [ \t\f\r\n] -> skip
 ;

如果您运行该课程:

import org.antlr.v4.runtime.*;

public class Main {

  public static void main(String[] args) {

    Lexer lexer = new TestLexer(CharStreams.fromString("q'ssome strings' q'!foo!'"));
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    tokens.fill();

    for (Token t : tokens.getTokens()) {
      System.out.printf("%-20s %s\n", TestLexer.VOCABULARY.getSymbolicName(t.getType()), t.getText());
    }
  }
}

将打印以下输出:

Q_QUOTED_LITERAL     q'ssome strings'
Q_QUOTED_LITERAL     q'!foo!'
EOF                  <EOF>