Контекстные токены в ANTLR? - PullRequest
0 голосов
/ 20 июня 2011

Я пытаюсь интегрировать язык в NetBeans с помощью ANTLR, и для выделения синтаксиса это включает генерацию токенов для каждого типа текста, который я хочу выделить.

Есть ли способ создания токенов для контекстных слов?То есть предположим, что я хочу выделить все строки, которые идут после «function»:

function foo

, где «foo» выделяется.

как я могу определить правило токена:

FUNCTION_IDENTIFIER
    :    //match anything after "function"

чтобы токен соответствовал тому, что я хочу?

1 Ответ

1 голос
/ 20 июня 2011

Вы можете сделать это, переопределив метод emit() из лексера и отследив последний выпущенный токен. Затем в вашем правиле IDENTIFIER вы проверяете, был ли последний токен FUNCTION, и в этом случае вы устанавливаете другой $type для указанного токена.

Демо:

grammar T;

tokens {
  FUNCTION_IDENTIFIER;
}

@lexer::members {

  private Token last = null;

  @Override
  public Token emit() {
    last = super.emit();
    return last;
  }
}

parse
  :  (t=. {System.out.printf("\%-20s -> '\%s'\n", tokenNames[$t.type], $t.text);})* EOF
  ;

FUNCTION
  :  'function'
  ;

IDENTIFIER
  :  ('a'..'z' | 'A'..'Z')+ 
     {
       if(last != null && last.getType() == FUNCTION) $type=FUNCTION_IDENTIFIER;
     }
  ;

SPACE
  :  ' ' {skip();}
  ;

А если вы запустите этот класс:

import org.antlr.runtime.*;

public class Main {
  public static void main(String[] args) throws Exception {
    TLexer lexer = new TLexer(new ANTLRStringStream("a function b c"));
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    TParser parser = new TParser(tokens);
    parser.parse();
  }
}

вы увидите:

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 Main
IDENTIFIER           -> 'a'
FUNCTION             -> 'function'
FUNCTION_IDENTIFIER  -> 'b'
IDENTIFIER           -> 'c'

EDIT

Обратите внимание, что если у вас есть токены, записанные на канал HIDDEN, вам нужно немного изменить содержимое emit(). Примерно так (не проверено!):

@lexer::members {

  private Token last = null;

  @Override
  public Token emit() {
    Token temp = super.emit();
    if(temp.getType() != HIDDEN) {
      last = temp;
    }
    return temp;
  }
}

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

это нарушит другие правила, которые у меня были? Предположим, у меня есть правило, которое принимает все токены IDENTIFIER, и я добавил этот контекстный токен. Будет ли правило, которое у меня ранее было, теперь игнорировать все FUNCTION_IDENTIFIERS, из-за чего мне пришлось бы явно отлавливать FUNCTION_IDENTIFIER и IDENTIFIER в этом правиле?

Да, любое правило, ссылающееся на IDENTIFIER, будет не соответствовать токену FUNCTION_IDENTIFIER. Если вы хотите этого, просто создайте производство (правило синтаксического анализатора) следующим образом:

identifier
  :  IDENTIFIER
  |  FUNCTION_IDENTIFIER
  ;

и замените все значения IDENTIFIER в правилах синтаксического анализатора на identifier.

...