Спасибо большое за помощь! Мне было бы трудно понять свои ошибки ... Я не пишу эту грамматику (только) для изучения ANTLR, я пытаюсь написать код для плагина IDE для Eclipse. И для этого мне нужна грамматика;) PS: я отредактировал свой первоначальный вопрос, извините за дополнительный пост.

й поток вопросов

Привет всем,

Это может быть продолжение этого вопроса:Приоритеты правил Antlr

Я пытаюсь написать грамматику ANTLR дляreStructuredText разметка языка.

Основная проблема, с которой я сталкиваюсь:«Как сопоставить любую последовательность символов (обычный текст) без маскировки других правил грамматики?»

Давайте рассмотрим пример с абзацем со встроенной разметкой:

In `Figure 17-6`_, we have positioned ``before_ptr`` so that it points to the element 
*before* the insert point. The variable ``after_ptr`` points to the element *after* the 
insert. In other words, we are going to put our new element **in between** ``before_ptr`` 
and ``after_ptr``.

Я думал, что написание правил для встроенного текста разметки будет легко. Итак, я написал простую грамматику:

grammar Rst;

options {
    output=AST;
    language=Java;
    backtrack=true;
    //memoize=true;
}

@members {
boolean inInlineMarkup = false;
}

// PARSER

text
    : inline_markup (WS? inline_markup)* WS? EOF
    ;


inline_markup
@after {
inInlineMarkup = false;
}
    : {!inInlineMarkup}? (emphasis|strong|litteral|link)
    ;

emphasis
@init {
inInlineMarkup = true;
}
    : '*' (~'*')+ '*' {System.out.println("emphasis: " + $text);}
    ;

strong
@init {
inInlineMarkup = true;
}
    : '**' (~'*')+ '**' {System.out.println("bold: " + $text);}
    ;

litteral
@init {
inInlineMarkup = true;
}
    : '``' (~'`')+ '``' {System.out.println("litteral: " + $text);}
    ;

link
@init {
inInlineMarkup = true;
}
    : inline_internal_target
    | footnote_reference
    | hyperlink_reference
    ;

inline_internal_target
    : '_`' (~'`')+ '`' {System.out.println("inline_internal_target: " + $text);}
    ;

footnote_reference
    : '[' (~']')+ ']_' {System.out.println("footnote_reference: " + $text);}
    ;


hyperlink_reference
    : ~(' '|'\t'|'\u000C'|'_')+ '_' {System.out.println("hyperlink_reference: " + $text);}
    |   '`' (~'`')+ '`_' {System.out.println("hyperlink_reference (long): " + $text);}
    ;

// LEXER

WS  
  : (' '|'\t'|'\u000C')+
  ; 

NEWLINE
  : '\r'? '\n'
  ;

Эта простая грамматика не работает. И я даже не пытался соответствоватьрегулярный текст...

Мои вопросы:

Может ли кто-то указать на мои ошибки и, возможно, дать мне подсказку о том, как соответствоватьрегулярный текст?Есть ли способ установить приоритет для правил грамматики? Может быть, это может быть ведущим.

Заранее спасибо за вашу помощь :-)

Робин

Второй поток вопросов

Спасибо большое за помощь! Мне было бы трудно понять свои ошибки ... Я не пишу эту грамматику (только) для изучения ANTLR, я пытаюсь написать код для плагина IDE для Eclipse. И для этого мне нужна грамматика;)

Мне удалось пойти дальше в грамматике и написалtext правило:

grammar Rst;

options {
    output=AST;
    language=Java;
}



@members {
boolean inInlineMarkup = false;
}

//////////////////
// PARSER RULES //
//////////////////

file
  : line* EOF
  ;


line
  : text* NEWLINE
  ;

text
    : inline_markup
    | normal_text
    ;

inline_markup
@after {
inInlineMarkup = false;
}
    : {!inInlineMarkup}? {inInlineMarkup = true;} 
  (
  | STRONG
  | EMPHASIS
  | LITTERAL
  | INTERPRETED_TEXT
  | SUBSTITUTION_REFERENCE
  | link
  )
    ;


link
    : INLINE_INTERNAL_TARGET
    | FOOTNOTE_REFERENCE
    | HYPERLINK_REFERENCE
    ;

normal_text
  : {!inInlineMarkup}? 
   ~(EMPHASIS
      |SUBSTITUTION_REFERENCE
      |STRONG
      |LITTERAL
      |INTERPRETED_TEXT
      |INLINE_INTERNAL_TARGET
      |FOOTNOTE_REFERENCE
      |HYPERLINK_REFERENCE
      |NEWLINE
      )
  ;
//////////////////
// LEXER TOKENS //
//////////////////

EMPHASIS
    : STAR ANY_BUT_STAR+ STAR {System.out.println("EMPHASIS: " + $text);}
    ;

SUBSTITUTION_REFERENCE
  : PIPE ANY_BUT_PIPE+ PIPE  {System.out.println("SUBST_REF: " + $text);}
  ;

STRONG
    : STAR STAR ANY_BUT_STAR+ STAR STAR {System.out.println("STRONG: " + $text);}
    ;

LITTERAL
    : BACKTICK BACKTICK ANY_BUT_BACKTICK+ BACKTICK BACKTICK {System.out.println("LITTERAL: " + $text);}
    ;
INTERPRETED_TEXT
  : BACKTICK ANY_BUT_BACKTICK+ BACKTICK {System.out.println("LITTERAL: " + $text);}
  ;

INLINE_INTERNAL_TARGET
    : UNDERSCORE BACKTICK ANY_BUT_BACKTICK+ BACKTICK {System.out.println("INLINE_INTERNAL_TARGET: " + $text);}
    ;

FOOTNOTE_REFERENCE
    : L_BRACKET ANY_BUT_BRACKET+ R_BRACKET UNDERSCORE {System.out.println("FOOTNOTE_REFERENCE: " + $text);}
    ;


HYPERLINK_REFERENCE
  : BACKTICK ANY_BUT_BACKTICK+ BACKTICK UNDERSCORE {System.out.println("HYPERLINK_REFERENCE (long): " + $text);}
  | ANY_BUT_ENDLINK+ UNDERSCORE {System.out.println("HYPERLINK_REFERENCE (short): " + $text);}
  ;

WS  
  : (' '|'\t')+ {$channel=HIDDEN;}
  ; 

NEWLINE
  : '\r'? '\n' {$channel=HIDDEN;}
  ;


///////////////
// FRAGMENTS //
///////////////

fragment ANY_BUT_PIPE
  : ESC PIPE
  | ~(PIPE|'\n'|'\r')
  ;
fragment ANY_BUT_BRACKET
  : ESC R_BRACKET
  | ~(R_BRACKET|'\n'|'\r')
  ;
fragment ANY_BUT_STAR
  : ESC STAR
  | ~(STAR|'\n'|'\r')
  ;
fragment ANY_BUT_BACKTICK
  : ESC BACKTICK
  | ~(BACKTICK|'\n'|'\r')
  ;
fragment ANY_BUT_ENDLINK
  : ~(UNDERSCORE|' '|'\t'|'\n'|'\r')
  ;



fragment ESC
  : '\\'
  ;
fragment STAR
  : '*'
  ;
fragment BACKTICK
  : '`'
  ;
fragment PIPE
  : '|'
  ;
fragment L_BRACKET
  : '['
  ;
fragment R_BRACKET
  : ']'
  ;
fragment UNDERSCORE
  : '_'
  ;

Грамматика отлично работает для inline_markup, но normal_text не совпадает.

Вот мой тестовый класс:

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;

import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.Tree;

public class Test {

    public static void main(String[] args) throws RecognitionException, IOException {

        InputStream is = Test.class.getResourceAsStream("test.rst");
        Reader r = new InputStreamReader(is);
        StringBuilder source = new StringBuilder();
        char[] buffer = new char[1024];
        int readLenght = 0;
        while ((readLenght = r.read(buffer)) > 0) {
            if (readLenght < buffer.length) {
                source.append(buffer, 0, readLenght);
            } else {
                source.append(buffer);
            }
        }
        r.close();
        System.out.println(source.toString());

        ANTLRStringStream in = new ANTLRStringStream(source.toString());
        RstLexer lexer = new RstLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        RstParser parser = new RstParser(tokens);
        RstParser.file_return out = parser.file();
        System.out.println(((Tree)out.getTree()).toStringTree());
    }
}

И входной файл, который я использую:

In `Figure 17-6`_, we have positioned ``before_ptr`` so that it points to the element 
*before* the insert point. The variable ``after_ptr`` points to the |element| *after* the 
insert. In other words, `we are going`_ to put_ our new element **in between** ``before_ptr`` 
and ``after_ptr``.

И я получаю этот вывод:

HYPERLINK_REFERENCE (short): 7-6`_
line 1:2 mismatched character ' ' expecting '_'
line 1:10 mismatched character ' ' expecting '_'
line 1:18 mismatched character ' ' expecting '_'
line 1:21 mismatched character ' ' expecting '_'
line 1:26 mismatched character ' ' expecting '_'
line 1:37 mismatched character ' ' expecting '_'
LITTERAL: `before_ptr`
line 1:86 no viable alternative at character '\r'
line 1:55 mismatched character ' ' expecting '_'
line 1:60 mismatched character ' ' expecting '_'
line 1:63 mismatched character ' ' expecting '_'
line 1:70 mismatched character ' ' expecting '_'
line 1:73 mismatched character ' ' expecting '_'
line 1:77 mismatched character ' ' expecting '_'
line 1:85 mismatched character ' ' expecting '_'
EMPHASIS: *before*
line 2:12 mismatched character ' ' expecting '_'
line 2:19 mismatched character ' ' expecting '_'
line 2:26 mismatched character ' ' expecting '_'
LITTERAL: `after_ptr`
line 2:30 mismatched character ' ' expecting '_'
line 2:39 mismatched character ' ' expecting '_'
line 2:90 no viable alternative at character '\r'
line 2:60 mismatched character ' ' expecting '_'
line 2:63 mismatched character ' ' expecting '_'
line 2:67 mismatched character ' ' expecting '_'
line 2:77 mismatched character ' ' expecting '_'
line 2:85 mismatched character ' ' expecting '_'
line 2:89 mismatched character ' ' expecting '_'
line 3:7 mismatched character ' ' expecting '_'
line 3:10 mismatched character ' ' expecting '_'
line 3:16 mismatched character ' ' expecting '_'
line 3:23 mismatched character ' ' expecting '_'
line 3:27 mismatched character ' ' expecting '_'
line 3:31 mismatched character ' ' expecting '_'
line 3:42 mismatched character ' ' expecting '_'
line 3:51 mismatched character ' ' expecting '_'
line 3:55 mismatched character ' ' expecting '_'
line 3:63 mismatched character ' ' expecting '_'
line 3:94 mismatched character '\r' expecting '*'
line 4:3 mismatched character ' ' expecting '_'
line 4:18 no viable alternative at character '\r'
line 4:18 mismatched character '\r' expecting '_'
HYPERLINK_REFERENCE (short): oing`_
HYPERLINK_REFERENCE (short): ut_
EMPHASIS: *in between*
LITTERAL: `after_ptr`
BR.recoverFromMismatchedToken
line 0:-1 mismatched input '<EOF>' expecting NEWLINE
null

Можете ли вы указать на мои ошибки? (синтаксический анализатор работает для встроенной разметки без ошибок, когда я добавляю filter = true; опция к грамматике)

Робин

Ответы на вопрос(2)

Робин написал:

Я думал, что написание правил для встроенного текста разметки будет легко

Я должен признать, что я не знаком с этим языком разметки, но он, похоже, напоминает разметку BB-Code или Wiki, которую нелегко перевести в (ANTLR) грамматику! Эти языки не позволяют легко быть токенизированными, так как это зависит от того, где эти токены встречаются. Пробелы иногда имеют особое значение (со списками определений). Так что нет, это совсем не легко, ИМО. Так что, если это просто упражнение для знакомства с ANTLR (или генераторами синтаксических анализаторов в целом), яочень рекомендую выбрать что-то еще для разбора.

Робин написал:

Может ли кто-то указать на мои ошибки и, возможно, дать мне подсказку о том, как сопоставить обычный текст?

Сначала вы должны понять, что ANTLR создает лексер (токенизатор) и парсер. Правила Lexer начинаются с заглавной буквы, а правила синтаксического анализатора начинаются со строчной буквы. Парсер может работать только с токенами (объектами, созданными по правилам лексера). Чтобы держать вещи в порядке, выдолжен не использовать токены-литералы внутри правил парсера (см. правилоq в грамматике ниже). Так же~ (отрицание) метасимвол имеет различное значение в зависимости от того, где он используется (в правиле парсера или лексера).

Возьмите следующую грамматику:

p : T;
q : ~'z';

T : ~'x';
U : 'y';

ANTLR сначала «переместит»'z' буквально к правилу лексера, как это:

p : T;
q : ~RANDOM_NAME;

T : ~'x';
U : 'y';
RANDOM_NAME : 'z';

(названиеRANDOM_NAME не используется, но это не имеет значения). Теперь правило парсераq делаетне соответствовать любому символу, кроме'z'! Отрицание внутри правила синтаксического анализатора отменяет токен (или правило лексера). Так~RANDOM_NAME будет соответствовать любому правилу лексераT или правило лексераU.

Внутри правил лексера,~ отрицает (одиночные!) символы. Итак, правило лексераT будет соответствовать любому символу в диапазоне\u0000..\uFFFF Кроме'x', Обратите внимание, что следующее:~'ab' недопустимо в правиле лексера: вы можете отрицать только один набор символов.

Итак, все эти~'???' внутри вашего синтаксического анализатора правила неверны (неправильно, как в: они ведут себя не так, как вы ожидаете).

Робин написал:

Есть ли способ установить приоритет для правил грамматики? Может быть, это может быть ведущим.

Да, порядок сверху вниз в правилах как лексера, так и парсера (где верх имеет наивысший приоритет). Скажемparse является точкой входа вашей грамматики:

parse
  :  p
  |  q
  ;

тогдаp будет сначала судиться, и если это не удастся,q пытается соответствовать.

Что касается правил лексера, то правила, которые являются ключевыми словами, например, сопоставляются перед правилом, которое могло бы соответствовать указанным ключевым словам:

// first keywords:
WHILE : 'while';
IF    : 'if'
ELSE  : 'else';

// and only then, the identifier rule: 
ID    : ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')*;
 Robin01 июн. 2011 г., 13:38
Спасибо большое за помощь! Мне было бы трудно понять свои ошибки ... Я не пишу эту грамматику (только) для изучения ANTLR, я пытаюсь написать код для плагина IDE для Eclipse. И для этого мне нужна грамматика;) PS: я отредактировал свой первоначальный вопрос, извините за дополнительный пост.
Решение Вопроса

Вот краткое демо, как вымог проанализировать этот reStructeredText. Обратите внимание, что он просто обрабатывает второстепенный набор всех доступных синтаксисов разметки, и, добавив к нему больше, выбудем влиять на существующие правила синтаксического анализатора / лексера: так много,много больше работы предстоит сделать!

демонстрация
grammar RST;

options {
  output=AST;
  backtrack=true;
  memoize=true;
}

tokens {
  ROOT;
  PARAGRAPH;
  INDENTATION;
  LINE;
  WORD;
  BOLD;
  ITALIC;
  INTERPRETED_TEXT;
  INLINE_LITERAL;
  REFERENCE;
}

parse
  :  paragraph+ EOF -> ^(ROOT paragraph+)
  ;

paragraph
  :  line+ -> ^(PARAGRAPH line+)
  |  Space* LineBreak -> /* omit line-breaks between paragraphs from AST */
  ;

line
  :  indentation text+ LineBreak -> ^(LINE text+)
  ;

indentation
  :  Space* -> ^(INDENTATION Space*)
  ;

text
  :  styledText
  |  interpretedText
  |  inlineLiteral
  |  reference
  |  Space
  |  Star
  |  EscapeSequence
  |  Any
  ;

styledText
  :  bold
  |  italic
  ;

bold
  :  Star Star boldAtom+ Star Star -> ^(BOLD boldAtom+)
  ;  

italic
  :  Star italicAtom+ Star -> ^(ITALIC italicAtom+)
  ;

boldAtom
  :  ~(Star | LineBreak)
  |  italic
  ;

italicAtom
  :  ~(Star | LineBreak)
  |  bold
  ;

interpretedText
  :  BackTick interpretedTextAtoms BackTick -> ^(INTERPRETED_TEXT interpretedTextAtoms)
  ;

interpretedTextAtoms
  :  ~BackTick+
  ;

inlineLiteral
  :  BackTick BackTick inlineLiteralAtoms BackTick BackTick -> ^(INLINE_LITERAL inlineLiteralAtoms)
  ;

inlineLiteralAtoms
  :  inlineLiteralAtom+
  ;

inlineLiteralAtom
  :  ~BackTick
  |  BackTick ~BackTick
  ;

reference
  :  Any+ UnderScore -> ^(REFERENCE Any+)
  ;

UnderScore
  :  '_'
  ;

BackTick
  :  '`'
  ;

Star
  :  '*'
  ;

Space
  :  ' ' 
  |  '\t'
  ;

EscapeSequence
  :  '\\' ('\\' | '*')
  ;

LineBreak
  :  '\r'? '\n'
  |  '\r'
  ;

Any
  :  .
  ;

Когда вы генерируете синтаксический анализатор и лексер из приведенного выше, и позволяете ему анализировать следующий входной файл:

***x*** **yyy** *zz* *
a b c

P2 ``*a*`b`` `q`
Python_

(обратите внимание на разрыв задней линии!)

парсер выдаст следующий AST:

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

График можно создать, запустив этот класс:

import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;

public class Main {
  public static void main(String[] args) throws Exception {
    String source =
        "***x*** **yyy** *zz* *\n" +
        "a b c\n" +
        "\n" +
        "P2 ``*a*`b`` `q`\n" +
        "Python_\n";
    RSTLexer lexer = new RSTLexer(new ANTLRStringStream(source));
    RSTParser parser = new RSTParser(new CommonTokenStream(lexer));
    CommonTree tree = (CommonTree)parser.parse().getTree();
    DOTTreeGenerator gen = new DOTTreeGenerator();
    StringTemplate st = gen.toDOT(tree);
    System.out.println(st);
  }
}

или если ваш источник взят из файла, выполните:

RSTLexer lexer = new RSTLexer(new ANTLRFileStream("test.rst"));

или же

RSTLexer lexer = new RSTLexer(new ANTLRFileStream("test.rst", "???"));

где"???" это кодировка вашего файла.

Класс выше будет печатать AST в виде файла DOT на консоли. Вы можете использовать DOT Viewer для отображения AST. В этом случае я разместил изображение, созданноеkgraphviewer, Но естьнамного больше зрителей вокруг, Хороший онлайнэтот, который, кажется, используетkgraphviewer под капотом". Удачи!

 Bart Kiers06 июн. 2011 г., 21:19
@ Робин, пожалуйста.
 Robin06 июн. 2011 г., 21:17
Хорошо, я нашел это :) Спасибо
 Robin06 июн. 2011 г., 19:58
Привет Барт :-) Спасибо за помощь! Быстрый вопрос: как вы генерируете AST? ANTLRWorks завершается ошибкой из-за "backtrack = true;" вариант.
 Bart Kiers06 июн. 2011 г., 20:26
@ Робин, даже безbacktrack=trueANTLRWorks не отображал бы AST, созданный правилами синтаксического анализатора. ANTLRWorks генерирует дерево разбора (если вы не уверены, в чем разница между ними, см.этот предыдущий Q & A). УвидетьРЕДАКТИРОВАТЬ для создания образа AST. И пожалуйста.
 Lex Li15 дек. 2017 г., 05:26
Просто уведомление для будущих читателей. Я намерен использовать эту грамматику в качестве отправной точки для серьезной грамматики reStructuredText и, конечно, обновлю ее для ANTLR v4,github.com/lextm/restructuredtext-antlr

Ваш ответ на вопрос