2010-04-29 2 views
1

Мне нужно, чтобы JavaCC знала о контексте (текущий родительский токен), и в зависимости от этого контекста ожидайте появления разных токенов.JavaCC: Как я могу указать, какой токен (ы) ожидается в определенном контексте?

Рассмотрим следующий псевдокод:

TOKEN <abc> { "abc*" } // recognizes "abc", "abcd", "abcde", ... 
TOKEN <abcd> { "abcd*" } // recognizes "abcd", "abcde", "abcdef", ... 

TOKEN <element1> { "element1" "[" expectOnly(<abc>) "]" } 
TOKEN <element2> { "element2" "[" expectOnly(<abcd>) "]" } 
... 

Итак, когда сгенерированный анализатор «внутри» знак с именем "element1" и сталкиваются "abcdef" он распознает его как <abc>, но когда его «внутри» знак с именем "element2" он распознает ту же строку, что и <abcd>.

element1 [ abcdef ] // aha! it can only be <abc> 
element2 [ abcdef ] // aha! it can only be <abcd> 

Если я не ошибается, он будет вести себя аналогичное более сложное определение DTD из файла XML.

Итак, как можно указать, в каком «контексте», который токены (ы) действительны/ожидаются?

Примечание: Было бы не достаточно для моего реального случая, чтобы определить своего рода «иерархии» лексемы, так что «ABCDEF» всегда первым сопоставляется <abcd> и чем <abc>. Мне действительно нужны токены с контекстом.

+0

Я узнал, что 'JavaCC' позволяет указать лексические контексты. К сожалению, это делает все очень сложным, когда у вас много * токенов, в которых большинство из них нуждается в собственном * состоянии. Я уже разработал парсер детерминированного состояния-машины и в настоящее время улучшаю его, чтобы принять недетерминированные состояния-машины. Должен признаться, мое дело очень особенное. –

ответ

2

ОК, похоже, вам нужна техническая техника, называемая lookahead. Вот очень хороший учебник: Lookahead tutorial

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

Предположим, мы хотим иметь какой-либо язык разметки. Все, что мы хотим "разметки" являются:

  • Выражения, состоящие из букв (ABC ... ZABC ... Z) и непечатаемых -> Слова
  • выражения, состоящие из цифр (0-9) - > numbers

Мы хотим заключить слова в теги и цифры в тегах. Поэтому, если я правильно понял, что вы хотите сделать: если вы находитесь в контексте слова (между тегами слов), компилятор должен ожидать буквы и пробелы, в числовом контексте он ожидает числа.

Я создал файл WordNumber.jj, который определяет грамматику и парсер генерироваться:

options 
{ 
    LOOKAHEAD= 1; 

    CHOICE_AMBIGUITY_CHECK = 2; 
    OTHER_AMBIGUITY_CHECK = 1; 
    STATIC = true; 
    DEBUG_PARSER = false; 
    DEBUG_LOOKAHEAD = false; 
    DEBUG_TOKEN_MANAGER = false; 
    ERROR_REPORTING = true; 
    JAVA_UNICODE_ESCAPE = false; 
    UNICODE_INPUT = false; 
    IGNORE_CASE = false; 
    USER_TOKEN_MANAGER = false; 
    USER_CHAR_STREAM = false; 
    BUILD_PARSER = true; 
    BUILD_TOKEN_MANAGER = true; 
    SANITY_CHECK = true; 
    FORCE_LA_CHECK = false; 
} 

PARSER_BEGIN(WordNumberParser) 

/** Model-tree Parser */ 
public class WordNumberParser 
{ 
    /** Main entry point. */ 
    public static void main(String args []) throws ParseException 
    { 
     WordNumberParser parser = new WordNumberParser(System.in); 
     parser.Input(); 
    } 
} 

PARSER_END(WordNumberParser) 

SKIP : 
{ 
    " " 
| "\n" 
| "\r" 
| "\r\n" 
| "\t" 
} 

TOKEN : 
{ 
    < WORD_TOKEN : (["a"-"z"] | ["A"-"Z"] | " " | "." | ",")+ > | 
    < NUMBER_TOKEN : (["0"-"9"])+ > 
} 


/** Root production. */ 
void Input() : 
{} 
{ 
    (WordContext() | NumberContext())* <EOF> 
} 

/** WordContext production. */ 
void WordContext() : 
{} 
{ 
    "<WORDS>" (<WORD_TOKEN>)+ "</WORDS>" 
} 

/** NumberContext production. */ 
void NumberContext() : 
{} 
{ 
    "<NUMBER>" (<NUMBER_TOKEN>)+ "</NUMBER>" 
} 

Вы можете протестировать его с файлом, как что:

<WORDS>This is a sentence. As you can see the parser accepts it.</WORDS> 
<WORDS>The answer to life, universe and everything is</WORDS><NUMBER>42</NUMBER> 
<NUMBER>This sentence will make the parser sad. Do not make the parser sad.</NUMBER> 

Последняя строка вызвать парсер, чтобы бросить исключение, как это:

Exception in thread "main" ParseException: Encountered " <WORD_TOKEN> "This sentence will make the parser sad. Do not make the parser sad. "" at line 3, column 9. Was expecting: <NUMBER_TOKEN> ...

Это потому, что парсер не нашел ожидаемого.

Я надеюсь, что это поможет.

Cheers!

P.S .: Парсер не может «быть» внутри токена, поскольку токен является символом терминала (исправьте меня, если я ошибаюсь), который не может быть заменен производственными правилами дальше. Таким образом, все контекстные аспекты должны быть помещены внутри производственного правила (non terminal), такого как «WordContext» в моем примере.

+0

Большое спасибо за пример, но это не моя проблема. Нет никакой проблемы, когда используемые токены различаются, как в вашем случае (один заключен в ' ...', другой заключен в ' ...'). В отличие от этого, в моем случае у меня есть значки, которые * оба * соответствуют определенному вводу. –

+0

@ java.is.for.desktop: Ах, ну, извините. Я думаю, вы можете использовать «lookahead». Проверьте мой отредактированный пост для ссылки; o) –

1

Вам нужно использовать лексеровские состояния. Ваш пример становится чем-то вроде:

<DEFAULT> TOKEN: {< element1: "element1" >: IN_ELEMENT1}
<DEFAULT> ЗНАК: {< ELEMENT2: "element2" >: IN_ELEMENT2}
<IN_ELEMENT1> ЗНАК: {< ABC: "абв" (...) * >: DEFAULT}
<IN_ELEMENT2> ЗНАК: {< ABCD: "ABCD" (...) * >: DEFAULT}

Пожалуйста, обратите внимание, что (...)* не правильный синтаксис JavaCC, но ваш пример не так как я могу только догадываться.

 Смежные вопросы

  • Нет связанных вопросов^_^