Как я могу получить доступ к блокам текста в качестве атрибута, который сопоставляется с использованием опции greedy=false в ANTLR?

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

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

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

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

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

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

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


person mpobrien    schedule 13.01.2011    source источник


Ответы (2)


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

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);} )* '*/';
person helloworld922    schedule 13.01.2011

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

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

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

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

РЕДАКТИРОВАТЬ

Или используйте 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.

person Bart Kiers    schedule 13.01.2011