2016-12-10 22 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处理不会发生在我手动从输入流中读取的字符上,所以我必须照顾空格(在我的代码示例中未完全实现)。