2016-12-10 67 views
0

我正在嘗試編寫一個javacc解析器來讀取GraphViz xdot format文件。這種文件格式有一個非常規律​​的語法,但我很難弄清楚如何爲它的擴展部分獲取令牌。獲取固定長度的令牌

問題是,某些令牌前面有一個長度值,表示令牌的長度,一些參數的長度值指定了如何使用令牌。

下面是一個例子:

graph [_draw_="c 9 -#fffffe00 C 7 -#ffffff P 4 0 0 0 13095 1541.31 13095 1541.31 0 ", 
    bb="0,0,1541.3,13095", 
    rankdir=LR, 
    size="12,12", 
    xdotversion=1.7 
]; 

,我有一個問題,是繼_draw_=令牌引用字符串的延伸部分。在這個字符串中,第一個數字9表示' - '開始字符後面的下一個標記的長度。如果令牌是由空白(容易定義令牌)包圍的一系列字符,但在其他情況下,以下令牌可能具有嵌入的空白,所以我認爲定義一個通用的正則表達式是不可能的。

此外,該字符串中的第一個'P'字符後面是4,表示隨後有4對數字。解析器如何知道使用這個數字來獲得下8個數字標記,或者如果令牌管理器只是以某種方式返回8數字字符串?

我知道我可以抓住字符串的全部內容作爲一個塊,然後使用一些字符串匹配手動解析它在java(不使用javacc)。然而,我想知道是否有一些技術在javacc中做到這一點。

我懷疑閱讀長度令牌後,我需要切換到不同的詞彙狀態,那場比賽中有MORE修改每一個字符,並有一個詞彙動作切換回TOKEN狀態之後所需要的計數滿足。這是否正確?我如何在詞法操作中指出該標記是完整的?

另外,我是否需要擔心LOOKAHEAD? (我認爲不是,如果我在令牌管理器中執行所有這些操作)

我會跟進一些代碼,然後找出該做什麼。

+0

我認爲你使用MORE的想法是完美的。爲什麼不實施它,然後回答自己的問題。沒有必要擔心LOOKAHEAD。 –

+0

要表示令牌的結尾,請使用TOKEN生產。所以當再有一個字符時,切換到任何字符都是TOKEN的狀態。 –

回答

1

好的,我得到它的工作。我決定用詞彙操作而不是用MORE處理來做到這一點,這似乎更直接。另外,我分裂詞法/解析到兩個部分,使事情更爲簡單:

  1. 首先解析出包含擴展語法的字符串,然後
  2. 在第二遍解析這些字符串與擴展的語法。

至於獲得基於長度前綴的令牌,所述第一部分是定義令牌表示的命令:

<Extended> TOKEN : 
{ 
     <LINECOLOR:  "c"> { singleCount = 1; } 
     | <FILLCOLOR:  "C"> { singleCount = 1; } 
     | <FONT:   "F"> { singleCount = 2; } 
     | <TEXT:   "T"> { singleCount = 5; } 
     | <TEXTCHARS:  "t"> 
     | <SPLINE:   "B"> { coordCount = 1; } 
     | <FILLEDSPLINE: "b"> { coordCount = 1; } 
     | <FILLEDELLIPSE: "E"> 
     | <UNFILLEDELLIPSE: "e"> 
     | <POLYLINE:  "L"> { coordCount = 1; } 
     | <FILLEDPOLYGON: "P"> { coordCount = 1; } 
     | <UNFILLEDPOLYGON: "p"> { coordCount = 1; } 
     | <STYLE:   "S"> { singleCount = 1; } 
} 

我加入語句的詞法行動以指示長度標誌將發生在命令令牌之後。在大多數情況下,它是子命令之後的第一個標記,但在某些情況下,還需要先解析其他介入標記。

接下來是定義令牌以匹配長度計數。當被觸發消耗長度指定的標記時,詞法動作會解碼長度計數並從輸入緩衝區中消耗適當數量的字符。獲取正確的數據後,它會根據需要切換令牌圖像和類型。該令牌還匹配默認詞彙狀態中的數字字符串。

/* 
* Special number token. Normally just grabs a number. 
* In the Extended lexical state can grab a fixed length 
* string or a list of coordinate pairs. 
*/ 
<DEFAULT,Extended> TOKEN: 
{ 
     <#NUM: (["0"-"9"]) > 
    | <NUMBER: (<NUM>)+ | (<NUM>)* "." (<NUM>)+ | (<NUM>)+ "." (<NUM>)* > 
    { 
     if (curLexState == Extended && singleCount-- == 1) { 
      // Get a single fixed length parameter 
      int len = Integer.parseInt(matchedToken.image); 
      StringBuilder sb = new StringBuilder(); 
      try { 
       while (input_stream.readChar() != '-') 
        { /* Do nothing */; }; 
       for (int i=0; i<len; i++) 
       sb.append(input_stream.readChar()); 
      } catch (IOException ioe) { 
       throw new TokenMgrError(true, curLexState, input_stream.getLine(), input_stream.getColumn(), sb.toString(), (char)0, TokenMgrError.LEXICAL_ERROR); 
      } 

      matchedToken.image = sb.toString(); 
      matchedToken.endLine = input_stream.getEndLine(); 
      matchedToken.endColumn = input_stream.getEndColumn(); 
      matchedToken.kind = SINGLE; 
     } 
     if (curLexState == Extended && coordCount-- == 1) { 
      // Get a list of coordinate pairs 
      int len = Integer.parseInt(matchedToken.image); 
      StringBuilder sb = new StringBuilder(); 
      try { 
       for (int i=0; i<len*2; i++) { 
       char c; 
       while ((c=input_stream.readChar()) == ' ') 
        { /* Do nothing */; }; 
       if (i>0) sb.append(" "); 
       do 
        {sb.append(c);} 
       while 
        ((c=input_stream.readChar()) != ' '); 
       } 
      } catch (IOException ioe) { 
       throw new TokenMgrError(true, curLexState, input_stream.getLine(), input_stream.getColumn(), sb.toString(), (char)0, TokenMgrError.LEXICAL_ERROR); 
      } 

      matchedToken.image = sb.toString(); 
      matchedToken.endLine = input_stream.getEndLine(); 
      matchedToken.endColumn = input_stream.getEndColumn(); 
      matchedToken.kind = COORDS; 
     } 
    } 
} 

的任何特殊標記必須聲明,以及那舉行的倒計時令牌變量解碼:

/* 
* Special extended token identifiers 
*/ 
<Extended> TOKEN: 
{ 
     <COORDS: <NUMBER>> 
    | <SINGLE: <NUMBER>> 
} 

TOKEN_MGR_DECLS: 
{ 
    /* 
    * These keep track of where the length prefixed strings 
    * and coordinate pairs start in the extended xdot commands. 
    * Set these values in the lexical actions for the sub-command 
    * definitions. 
    */ 
    int singleCount = -1;; 
    int coordCount = -1;; 
} 

這實際上是很容易,一旦我明白詞彙的行動是如何工作的,並令牌管理器API可以做些什麼。

要利用這分析器,切換至增詞法狀態,並使用作品,如:

<LINECOLOR> color=<SINGLE> 

<UNFILLEDPOLYGON> scoords=<COORDS> 

<TEXT> sx=<NUMBER> sy=<NUMBER> sj=<NUMBER> sw=<NUMBER> label=<SINGLE> 

這就是它。它似乎運作良好。

我這樣做的唯一缺點是SKIP處理不會發生在我手動從輸入流中讀取的字符上,所以我必須照顧空格(在我的代碼示例中未完全實現)。