Как я могу получить доступ к блокам текста как к атрибуту, который сопоставляется с помощью опции greedy = false в ANTLR? - PullRequest
0 голосов
/ 13 января 2011

У меня есть правило в моей грамматике ANTLR:

COMMENT :  '/*' (options {greedy=false;} : . )* '*/' ;

Это правило просто соответствует комментариям в стиле c, поэтому оно будет принимать любую пару / * и * / с любым произвольным текстом между ними, и оно прекрасно работает.

Теперь я хочу захватить весь текст между / * и * /, когда правило совпадает, чтобы сделать его доступным для действия. Как то так:

COMMENT :  '/*' e=((options {greedy=false;} : . )*) '*/' {System.out.println("got: " + $e.text);

Этот подход не работает, во время синтаксического анализа он не дает "жизнеспособной альтернативы" при достижении первого символа после "/ *"

Я не совсем понимаю, если / как это можно сделать - любые предложения или рекомендации приветствуются, спасибо.

Ответы [ 2 ]

4 голосов
/ 13 января 2011

Обратите внимание, что вы можете просто сделать:

getText().substring(2, getText().length()-2)

на COMMENT токене , поскольку первые и последние 2 символа всегда будут /* и */.

Вы также можете удалить options {greedy=false;} :, так как и .*, и .+ являются жадными (хотя без . они являются жадными) (i).

EDIT

Или используйте setText(...) на токене Comment, чтобы немедленно сбросить /* и */. Немного демо:

файл T.g:

grammar T;

@parser::members {
    public static void main(String[] args) throws Exception {
        ANTLRStringStream in = new ANTLRStringStream(
                "/* abc */   \n" +
                "            \n" + 
                "/*          \n" +
                "   DEF      \n" + 
                "*/            "
        );
        TLexer lexer = new TLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        TParser parser = new TParser(tokens);
        parser.parse();
    }
}

parse
  :  ( Comment {System.out.printf("parsed :: >\%s<\%n", $Comment.getText());} )+ EOF
  ;

Comment
  :  '/*' .* '*/' {setText(getText().substring(2, getText().length()-2));}
  ;

Space
  :  (' ' | '\t' | '\r' | '\n') {skip();}
  ;

Затем сгенерируйте парсер и лексер, скомпилируйте все файлы .java и запустите парсер, содержащий основной метод:

java -cp antlr-3.2.jar org.antlr.Tool T.g
javac -cp antlr-3.2.jar *.java
java -cp .:antlr-3.2.jar TParser 
  (or `java -cp .;antlr-3.2.jar TParser` on Windows)

, который выдаст следующий вывод:

parsed :: > abc <
parsed :: >          
   DEF      
<

(i) Полное руководство по ANTLR , глава 4, Расширенные BNF-субрулы, стр. 86.

1 голос
/ 13 января 2011

Попробуйте это:

COMMENT :
  '/*' {StringBuilder comment = new StringBuilder();} ( options {greedy=false;} : c=. {comment.appendCodePoint(c);} )* '*/' {System.out.println(comment.toString());};

Другой способ, который фактически вернет объект StringBuilder, чтобы вы могли использовать его в своей программе:

COMMENT returns [StringBuilder comment]:
  '/*' {comment = new StringBuilder();} ( options {greedy=false;} : c=. {comment.append((char)c);} )* '*/';
...