Сканер (лексирование ключевых слов с помощью ANTLR) - PullRequest
1 голос
/ 02 сентября 2011

Я работал над написанием сканера для моей программы, и большинство онлайн-уроков включают в себя синтаксический анализатор и сканер. Кажется невозможным написать лексер без написания парсера одновременно. Я только пытаюсь генерировать токены, а не интерпретировать их. Я хочу распознавать токены INT, плавающие токены и некоторые токены, такие как «начало» и «конец»

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

KEYWORD : KEY1 | KEY2;

KEY1 : {input.LT(1).getText().equals("BEGIN")}? LETTER+ ;
KEY2 : {input.LT(1).getText().equals("END")}? LETTER+ ;

FLOATLITERAL_INTLITERAL
  : DIGIT+ 
  ( 
    { input.LA(2) != '.' }? => '.' DIGIT* { $type = FLOATLITERAL; }
    | { $type = INTLITERAL; }
  )
  | '.'  DIGIT+ {$type = FLOATLITERAL}
;

fragment LETTER : ('a'..'z' | 'A'..'Z');
fragment DIGIT  : ('0'..'9');

IDENTIFIER 
 : LETTER 
   | LETTER DIGIT (LETTER|DIGIT)+ 
   | LETTER LETTER (LETTER|DIGIT)*
 ;

WS  //Whitespace
  : (' ' | '\t' | '\n' | '\r' | '\f')+  {$channel = HIDDEN;}
;  

Ответы [ 2 ]

2 голосов
/ 02 сентября 2011

Если вам нужен только лексер, начните грамматику с:

lexer grammar FooLexer; // creates: FooLexer.java

LT(int): Token можно использовать только в правилах синтаксического анализатора (для TokenStream).Внутри правил лексера вы можете использовать только LA(int): int, который получает следующий int (символ) из IntStream.Но нет необходимости для всего руководства смотреть в будущее.Просто сделайте что-то вроде этого:

lexer grammar FooLexer;

BEGIN
  :  'BEGIN'
  ;

END
  :  'END'
  ;

FLOAT
  :  DIGIT+ '.' DIGIT+
  ;

INT
  :  DIGIT+
  ;

IDENTIFIER 
  :  LETTER (LETTER | DIGIT)*
  ;

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

fragment LETTER : ('a'..'z' | 'A'..'Z');
fragment DIGIT  : ('0'..'9');

Я не вижу необходимости создавать токен KEYWORD, который соответствует всем ключевым словам: вы захотите провести различие между BEGIN и END токен, верно?Но если вы действительно этого хотите, просто выполните:

KEYWORD
  :  'BEGIN'
  |  'END'
  ;

и удалите правила BEGIN и END.Просто убедитесь, что KEYWORD определено до IDENTIFIER.

EDIT

Проверьте лексер с помощью следующего класса:

import org.antlr.runtime.*;

public class Main {
  public static void main(String[] args) throws Exception {
    String src = "BEGIN END 3.14159 42 FOO";
    FooLexer lexer = new FooLexer(new ANTLRStringStream(src));
    while(true) {
      Token token = lexer.nextToken();
      if(token.getType() == FooLexer.EOF) {
        break;
      }
      System.out.println(token.getType() + " :: " + token.getText());
    }
  }
}

Если вы сгенерируете лексер, скомпилируйтеисходные файлы .java и запустите класс Main следующим образом:

java -cp antlr-3.3.jar org.antlr.Tool FooLexer.g
javac -cp antlr-3.3.jar *.java
java -cp .:antlr-3.3.jar Main

следующий вывод будет выведен на консоль:

4 :: BEGIN
11 ::  
5 :: END
11 ::  
7 :: 3.14159
11 ::  
8 :: 42
11 ::  
10 :: FOO
1 голос
/ 02 сентября 2011

[От парня, который делает собственный инструмент лексера и все еще пытается выучить ANTLR]

Скучный исчерпывающий ответ:

Вы правы.Многие книги и курсы смешивают оба инструмента.И иногда «генерация / обнаружение токенов» и «интерпретация токенов» могут смешиваться.

Иногда разработчик пытается сделать сканер и все же смешивает сканирование и анализ в своем уме; -)

Обычно при обнаружении токенов также необходимо выполнить действие («интерпретация»), столь же простое, как печать сообщения или найденного токена в строку.Пример: "{cout <<" Привет, я нашел целочисленную константу "<<" \ n "}" </p>

В некоторых темах сканирование может быть затруднено для начинающего.

В одном случае несколько текстов могут использоваться для разных токенов.

Пример:

"-" в качестве бинарного оператора вычитания, а "-" в качествеоператор отрицательного префикса.Или, рассматривая 5 как целое число и число с плавающей точкой.В сканерах «-» можно рассматривать как один и тот же токен, а в синтаксических анализаторах вы можете рассматривать его как разные токены.

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

Быстрый ответ:

Как упоминалось в предыдущих ответах,начните с создания грамматики, на самом деле, я предлагаю попробовать ее на доске или в тетради, а позже - в своем любимом (ANTLRL, другом) инструменте сканирования.

Рассмотрим те особые случаи, когда могут быть некоторые наложения токенов.

Удачи.

...