2013-02-20 27 views
1

我想爲下面列出的示例文件實現解析器。我想識別它們之間帶有'+'的引用字符串作爲單個令牌。所以我創建了一個jj文件,但它不匹配這樣的字符串。我的印象是JavaCC應該匹配每個令牌規範的最長匹配。但這似乎並不適合我。JavaCC詞法分析器不能按預期工作(空白不被忽略)

我在這裏做錯了什麼?爲什麼我的<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 2013-02-20 14:35:14

回答

3

STRING正在擴展到可匹配的最長序列,即錯誤指示的"foo"。結束雙引號之後的空格不是私人令牌CONCAT_STRING定義的一部分。跳過標記不適用於其他標記的定義,因此您必須將空間直接納入定義中,在+的任一側。

順便說一句,我建議有一個最終令牌定義,像這樣:

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

這樣可以防止被甩出TokenMgrError S和使調試有點容易。

+0

你是說每當一個新的標記被定義時,我不應該指望通過SKIP自動處理空白?那麼,如果我不能在我的作品中利用它,那麼SKIP的目的是什麼......你可以把我引用到JavaCC文檔中說明你聲稱的內容的部分嗎? – predi 2013-02-20 15:38:09

+0

@predi:沒錯,跳過標記不適用於其他標記的定義。跳過令牌的目的是定義在匹配BNF規則時(在其他令牌之間有效地,但不在其他令牌中),應該忽略的令牌。但是,您可以將其跳過令牌合併到其他令牌的定義中,就像使用其他令牌一樣。例如,給你的skip標記一個名字,比如'WS'。然後將'CONCAT_STRING'重新定義爲'...()? (「+」( ...)+'。 – 2013-02-20 16:56:43

+0

糟糕,那應該是......()?(「+」()?...)+'。忘記了一些元字符 – 2013-02-20 17:07:55