Как переписать токен с текстом в древовидной грамматике?

#java #antlr #antlr3

#java #antlr #antlr3

Вопрос:

Это моя древовидная грамматика:

 grammar t;
options{
  output = AST;
}
type
  :
  'NVARCHAR' -> "VARCHAR"
  ;
  

ANTLR3 3.1.3 гласит:

 syntax error: antlr: t.g:12:5: unexpected token: 'NVARCHAR'
  

Что здесь не так? Я взял это из этой статьи.

ps. Я использую эту грамматику позже, чтобы извлечь из нее AST. Как только AST извлекается, я просматриваю его и добавляю текст каждого токена в некоторый строковый буфер. Идея переписывания выше заключается в замене определенных токенов. Я делаю сопоставление языка с языком (SQL с диалектом SQL, чтобы быть более конкретным).

Ответ №1:

Обратите внимание на первое предложение, с которого начинается Теренс: «только что пришло несколько классных идей о языке спецификации семантических правил …». Вот что такое первый пример: идея. Это недопустимый синтаксис.

Для вас есть (как минимум) два варианта:


1. немедленно перепишите текст в токене

 grammar T;

options{
  output=AST;
}

@parser::members {
  public static void main(String[] args) throws Exception {
    TLexer lexer = new TLexer(new ANTLRStringStream("NVARCHAR"));
    TParser parser = new TParser(new CommonTokenStream(lexer));
    parser.type();
  }
}

type
  :  NVARCHAR {System.out.println("token="   $NVARCHAR.text);}
  ;

NVARCHAR
  :  'NVARCHAR' {setText("VARCHAR");}
  ;
  

Но это только корректирует text , а не type токен, который остается NVARCHAR типом.


2. используйте воображаемый токен:

 grammar T;

options{
  output=AST;
}

tokens {
  VARCHAR='VARCHAR';
}

@parser::members {
  public static void main(String[] args) throws Exception {
    TLexer lexer = new TLexer(new ANTLRStringStream("NVARCHAR"));
    TParser parser = new TParser(new CommonTokenStream(lexer));
    parser.type();
  }
}

type
  :  NVARCHAR -> VARCHAR
  ;

NVARCHAR
  :  'NVARCHAR'
  ;
  

которое изменяет text и type токена.


Как вы можете видеть, в обеих демонстрациях token=VARCHAR выводится на консоль:

bart@hades:~/Programming/ANTLR/Demos/T$ java -cp antlr-3.3.jar org.antlr.Tool T.g 
bart@hades:~/Programming/ANTLR/Demos/T$ javac -cp antlr-3.3.jar *.java 
bart@hades:~/Programming/ANTLR/Demos/T$ java -cp .:antlr-3.3.jar TParser 
токен = VARCHAR

Комментарии:

1. @Bart Мне нравится первый вариант (с setText() ), но он не работает. ANTLR генерирует .java класс, который не компилируется: cannot find symbol method setText(java.lang.String) in TParser . Есть идеи?

2. @yegor256, это действительно работает. Посмотрите демо, которое я добавил. Я предполагаю, что вы пытаетесь вызвать этот метод внутри правила синтаксического анализа (мое предложение показывает это в правиле лексера).

3. @Bart У меня есть древовидная грамматика, как в вопросе выше. Не могли бы вы, пожалуйста, внести исправления в мой пример?

4. @yegor256, нет, ты опубликовал комбинированную грамматику, которая выводит AST. Древовидная грамматика начинается с tree grammar T; вместо grammar T; . Или вы не включили свою древовидную грамматику? Вы сказали, что хотите изменить текст токена. Тип токена просто останется NVARCHAR (с текстом: "VARCHAR" ). Возможно, пришло время отредактировать ваш вопрос и добавить еще немного информации.

5. @Bart Я добавил некоторые детали к своему вопросу, надеюсь, что они лучше объяснят ситуацию. Вы правы, это грамматика, которая выводит AST. Мне нужно получить AST с «уже замененными» токенами. Имеет смысл?

Ответ №2:

в antlr4 замена текста и типа может быть достигнута с помощью type действия:

 OldTokenType: 
    ('Token1' | 'Token2' | 'Token3' ) {setText("New Token");} 
    -> type(NewTokenType);