【问题标题】:How can I detect whitespace in my parse tree in Antlr4?如何在 Antlr4 的解析树中检测空格?
【发布时间】:2018-04-10 11:46:13
【问题描述】:

当一个规则在 antlr4 中匹配,并且你得到该规则的文本时,词法分析器通常会用

去除空格
WS: [ \n\t\r]+ -> skip;

是否可以在解析树访问者中询问“这条规则是否跳过了任何空白?”

例如

WS: [ \n\t\r]+ -> skip;
ALPHA: [a-z];
NUMERIC: [0-9];

myrule: (ALPHA | NUMERIC)+;

然后在访问者中(我使用的是 C++):

antlrcpp::Any MyVisitor::visitMyrule(dlParser::MyruleContext *ctx) {
    if (ctx->didSkipSomeWhitespace()) {
        /* There was whitespace */
    } else {
        /* There was no whitespace */
    }
    return false;
}

所以:

f56fhj => no whitespace
o9f g66ff o => whitespace

我已经尝试获取标记的开始/停止索引,以便我可以将文本长度与进入其中的字符数进行比较,但停止标记并不总是可用,如果是则值不要与我期望的索引对齐,访问形成令牌的原始输入字符似乎并不简单。

【问题讨论】:

    标签: c++ parsing antlr grammar antlr4


    【解决方案1】:

    在这种情况下,您不应该skip 这些空间标记。这样解析器就不知道它们了。相反,您应该将这些空间令牌放在不同的通道上(例如HIDDEN)。这样,解析器就不会使用这些 HIDDEN 标记,但标记存在于标记流中并且可以在您的代码中访问。

    Java 的快速演示(我没有运行 C++):

    grammar IntList;
    
    list
     : '[' ( list_item ( ',' list_item )* )? ']' EOF
     ;
    
    list_item
     : INT
     ;
    
    INT
     : '0'
     | [1-9] [0-9]*
     ;
    
    SPACES
     : [ \t\f\r\n] -> channel(HIDDEN)
     ;
    

    运行课程:

    import org.antlr.v4.runtime.*;
    
    public class Main {
    
      public static void main(String[] args) {
    
        String source = "[1,    2,3,\t4,5]";
    
        IntListLexer lexer = new IntListLexer(CharStreams.fromString(source));
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        IntListParser parser = new IntListParser(tokens);
    
        new SpaceInspectionVisitor(tokens).visit(parser.list());
      }
    }
    
    class SpaceInspectionVisitor extends IntListBaseVisitor<Object> {
    
      private final CommonTokenStream tokens;
    
      SpaceInspectionVisitor(CommonTokenStream tokens) {
        this.tokens = tokens;
      }
    
      @Override
      public Object visitList_item(IntListParser.List_itemContext ctx) {
        Token previous = tokens.get(ctx.start.getTokenIndex() - 1);
        System.out.printf("token: '%s', previous == SPACES: %s\n", ctx.getText(), previous.getType() == IntListLexer.SPACES);
        return null;
      }
    }
    

    会将以下内容打印到您的控制台:

    token: '1', previous == SPACES: false
    token: '2', previous == SPACES: true
    token: '3', previous == SPACES: false
    token: '4', previous == SPACES: true
    token: '5', previous == SPACES: false
    

    【讨论】:

      猜你喜欢
      • 2016-03-18
      • 1970-01-01
      • 1970-01-01
      • 2018-08-31
      • 2014-06-16
      • 2018-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多