Парсер ANTLR, могу ли я остановиться на первом матче? - PullRequest
0 голосов
/ 28 декабря 2011

Я играю с ANTLR, чтобы написать анализатор для структуры объектов PDF, но у меня возникла проблема с анализом потока строк, смешанного с PDF Reference и Integer.

По сути, PDF Reference - это строка типа: «10 0 R» (INTEGER SPACE INTEGER SPACE ‘R’).

Вот мой файл грамматики (упрощенный):

grammar Pdf;

options {
language=CSharp3;
backtrack=true;
}

public r returns [string val]
    :   ref {$val = $r.text;}
    |   INTEGER {$val = $r.text;}
    ;

ref
    :   INTEGER SPACE INTEGER SPACE 'R';

INTEGER
    :   DIGIT+;

SPACE: ' ';

fragment DIGIT
    :   '0'..'9'
    ;

Вот тестовый код (в C #):

byte[] bytes = Encoding.ASCII.GetBytes("97 98 10 0 R 100 101");
MemoryStream stream = new MemoryStream(bytes);

ANTLRInputStream inputStream = new ANTLRInputStream(stream);
PdfLexer lexer = new PdfLexer(inputStream);
CommonTokenStream tokens = new CommonTokenStream(lexer);

PdfParser parser = new PdfParser(tokens);
string result = parser.r();

Я ожидаю, что результатом будет первое правило, соответствующее правилу r (будь то ref или INTEGER).

Например:

  • если вход = "97 98 10 0 R 100 101": результат = "97"

  • если вход = "10 0 R 100 101": результат = "10 0 R"

Нет необходимости проходить весь поток строк. Просто сопоставьте первое правило, затем остановитесь.

Я новичок в ANTLR и не могу понять, как это сделать. Я использую ANTLRWorks 1.4.3 и antlr-dotnet-csharpruntime-3.4.1.9004.

Любая помощь приветствуется!

1 Ответ

1 голос
/ 28 декабря 2011

backtrack=true применяется только к правилам парсера: не к правилам лексера.Поэтому, когда лексер натыкается на INTEGER SPACE, за которым следует что-то другое , чем INTEGER, лексер выдаст ошибку / исключение: он не вернется назадREF и создайте вместо него токен INTEGER и SPACE.

Но REF не должно быть правилом лексера, а правилом синтаксического анализатора:

ref
 : INTEGER SPACE INTEGER SPACE 'R'
 ;

Edit

Я нахожусь в Linux и поэтому не могу проверить цель C # (по крайней мере, мне никогда не удавалось заставить цель CSharp3 работать внутри MonoDevelop).Но вот демонстрационная версия Java:

grammar Pdf;

public r
 : ( ref     {System.out.println("ref     = '" + $ref.text + "'");}
   | INTEGER {System.out.println("INTEGER = '" + $INTEGER.text + "'");}
   | SPACE   {System.out.println("SPACE   = '" + $SPACE.text + "'");}
   )*
   EOF
 ;

ref
 : INTEGER SPACE INTEGER SPACE 'R'
 ;

INTEGER
 : DIGIT+;

SPACE
 : ' '
 ;

fragment DIGIT
 : '0'..'9'
 ;

Вы можете протестировать анализатор с помощью класса:

import org.antlr.runtime.*;

public class Main {
  public static void main(String[] args) throws Exception {
    PdfLexer lexer = new PdfLexer(new ANTLRStringStream("97 98 10 0 R 100 101"));
    PdfParser parser = new PdfParser(new CommonTokenStream(lexer));
    parser.r();
  }
}

, и если вы запустите этот класс, будет напечатано следующее:

INTEGER = '97'
SPACE   = ' '
INTEGER = '98'
SPACE   = ' '
ref     = '10 0 R'
SPACE   = ' '
INTEGER = '100'
SPACE   = ' '
INTEGER = '101'

, что именно так, как я ожидал.

...