почему эта грамматика ошибка 208? - PullRequest
1 голос
/ 24 октября 2011

Я не понимаю, почему следующая грамматика приводит к ошибке 208 с жалобами, если IF никогда не будет соответствовать:

error(208): test.g:11:1: The following token definitions can never be matched because prior tokens match the same input: IF

ANTLRWorks 1.4.3

ANTLT 3.4

grammar test;

@lexer::members {
  private boolean rawAhead() {
  }
}

parse    :    IF*;

RAW    :    ({rawAhead()}?=> . )+;
IF      :    'if';
ID    :    ('A'..'Z'|'a'..'z')+;

Либо удалить правило RAW, либо правило ID решает ошибку ... С моей точки зрения, IF имеет возможность сопоставляться, когда rawAhead () возвращает false.

1 Ответ

0 голосов
/ 24 октября 2011

Bood писал:

Я думаю, что это действительно имеет значение, скажем, если у нас есть и просто "если" за пределами режима, например<# /> если <# />, то если здесь будет совпадать с IF, а не с RAW, оно должно быть (той же длины, соответствует первому), верно?

Да, выправильно, хорошая мысльЕще немного подумав, что - это ожидаемое поведение AFAIK.Но, похоже, все работает немного по-другому: правило RAW имеет приоритет над правилами ID и IF, даже если поместить его в конец грамматики лексера, как вы можете видеть:

freemarker_simple.g

grammar freemarker_simple;

@lexer::members {

  private boolean mmode = false;

  private boolean rawAhead() {
    if(mmode) return false;
    int ch1 = input.LA(1), ch2 = input.LA(2), ch3 = input.LA(3);
    return !(
        (ch1 == '<' && ch2 == '#') ||
        (ch1 == '<' && ch2 == '/' && ch3 == '#') ||
        (ch1 == '$' && ch2 == '{')
    );
  }
}

parse
  :  (t=. {System.out.printf("\%-15s '\%s'\n", tokenNames[$t.type], $t.text);})* EOF
  ;

OUTPUT_START  : '${'  {mmode=true;};
TAG_START     : '<#'  {mmode=true;};
TAG_END_START : '</' ('#' {mmode=true;} | ~'#' {$type=RAW;});

OUTPUT_END    : '}' {mmode=false;};
TAG_END       : '>' {mmode=false;};

EQUALS        : '==';
IF            : 'if';
STRING        : '"' ~'"'* '"';
ID            : ('a'..'z' | 'A'..'Z')+;
SPACE         : (' ' | '\t' | '\r' | '\n')+ {skip();};

RAW           : ({rawAhead()}?=> . )+;

Main.java

import org.antlr.runtime.*;

public class Main {
  public static void main(String[] args) throws Exception {
    freemarker_simpleLexer lexer = new freemarker_simpleLexer(new ANTLRStringStream("<#/if>if<#if>foo<#if>"));
    freemarker_simpleParser parser = new freemarker_simpleParser(new CommonTokenStream(lexer));
    parser.parse();
  }
}

выведет на консоль следующее:

TAG_START       '<#'
IF              'if'
TAG_END         '>'
RAW             'if'
TAG_START       '<#'
IF              'if'
TAG_END         '>'
RAW             'foo'
TAG_START       '<#'
IF              'if'
TAG_END         '>'

Как видите, 'if' и'foo' маркированы как RAW на входе:

<#/if>if<#if>foo<#if>
      ^^     ^^^
...