2013-02-20 2 views
1

Я пытаюсь реализовать парсер для приведенного ниже файла примера. Я хотел бы узнать цитированные строки с '+' между ними как один токен. Поэтому я создал jj-файл, но он не соответствует таким строкам. У меня создалось впечатление, что JavaCC должен соответствовать максимально возможному совпадению для каждой спецификации токена. Но для меня это не похоже.JavaCC lexer не работает должным образом (пробелы не игнорируются)

Что я здесь делаю неправильно? Почему не мой токен <STRING> соответствует '+', хотя он указан там? Почему пробелы не игнорируются?

options { 
    TOKEN_FACTORY = "Token"; 
} 

PARSER_BEGIN(Parser) 

package com.example.parser; 

public class Parser { 

    public static void main(String args[]) throws ParseException { 

     ParserTokenManager manager = new ParserTokenManager(new SimpleCharStream(Parser.class.getResourceAsStream("example"))); 
     Token token = manager.getNextToken(); 
     while (token != null && token.kind != ParserConstants.EOF) { 
      System.out.println(token.toString() + "[" + token.kind + "]"); 
      token = manager.getNextToken(); 
     } 

     Parser parser = new Parser(Parser.class.getResourceAsStream("example")); 
     parser.start(); 
    } 

} 

PARSER_END(Parser) 

// WHITE SPACE 
<DEFAULT, IN_STRING_KEYWORD> 
SKIP : 
{ 
    " " // <-- skipping spaces 
| "\t" 
| "\n" 
| "\r" 
| "\f" 
} 

// TOKENS 
TOKEN : 
{ 
< KEYWORD1 : "keyword1" > : IN_STRING_KEYWORD 
} 

<IN_STRING_KEYWORD> 
TOKEN : {<STRING : <CONCAT_STRING> | <UNQUOTED_STRING> > : DEFAULT 
| <#CONCAT_STRING : <QUOTED_STRING> ("+" <QUOTED_STRING>)+ > 
// <-- CONCAT_STRING never matches "+" part when input is "'smth' +", because whitespace is not ignored!? 
| <#QUOTED_STRING : <SINGLEQUOTED_STRING> | <DOUBLEQUOTED_STRING> > 
| <#SINGLEQUOTED_STRING : "'" (~["'"])* "'" > 
| <#DOUBLEQUOTED_STRING : 
    "\"" 
     (
     (~["\"", "\\"]) | 
     ("\\" ["n", "t", "\"", "\\"]) 
    )* 
    "\"" 
    > 
| <#UNQUOTED_STRING : (~[" ","\t", ";", "{", "}", "/", "*", "'", "\"", "\n", "\r"] | "/" ~["/", "*"] | "*" ~["/"])+ > 
} 

void start() : 
{} 
{ 
    (<KEYWORD1><STRING>";")+ <EOF> 
} 

Вот пример файла, который должен получить разобран:

keyword1 "foo" + ' bar'; 

Я хотел бы, чтобы соответствовать аргумент первого keyword1 как единый <STRING> знак.

Токовый выход:

keyword1[6] 
Exception in thread "main" com.example.parser.TokenMgrError: Lexical error at line 1, column 15. Encountered: " " (32), after : "\"foo\"" 
    at com.example.parser.ParserTokenManager.getNextToken(ParserTokenManager.java:616) 
    at com.example.parser.Parser.main(Parser.java:12) 

Я использую JavaCC 5.0.

+0

Похоже, что это дубликат [неотвеченного вопроса] (http://stackoverflow.com/questions/7800493/javacc-lexical-error-on-any-type-of-whitespace). По-прежнему будет признателен за ответ. Или обходной путь, если это ошибка. – predi

ответ

3

STRING распространяется до самой длинной последовательности, которая может быть сопоставлена, что соответствует "foo", как указывает ошибка. Пространство после закрывающей двойной кавычки не является частью определения частного токена CONCAT_STRING. Значки пропусков не применяются в определении других токенов, поэтому вы должны включить пространство непосредственно в определение по обе стороны от +.

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

<each-state-in-which-the-empty-string-cannot-be-recognized> 
TOKEN : { 
    < ILLEGAL : ~[] > 
} 

Это предотвращает TokenMgrError с от броска и делает отладку немного проще.

+0

Вы говорите, что всякий раз, когда новый токен определен, я не должен ожидать, что пробел будет обрабатываться автоматически через него через SKIP? Какова же цель SKIP, если я не могу воспользоваться ею в своих продуктах ... Можете ли вы передать мне часть документации JavaCC, в которой говорится, что вы утверждаете? – predi

+0

@predi: Правильно, токен пропуска не применяется в определении других токенов. Цель токена пропуска состоит в том, чтобы определить маркеры, которые следует игнорировать при сопоставлении правил BNF (между другими токенами, эффективно, но не в пределах других токенов). Тем не менее, вы можете включить токен пропуска в определении других токенов, как и любой другой токен. Например, дайте вашему токену пропуска имя, например 'WS'. Затем переопределите 'CONCAT_STRING' как' ... ()? («+» ( ...) + '. –

+0

К сожалению, это должно быть ... ... ()? (« + »()? ...) +'. Забыл несколько метасимволов. –