2016-12-10 5 views
0

Ich versuche, einen Javacc-Parser zu schreiben, um GraphViz xdot format Dateien zu lesen. Dieses Dateiformat hat eine ziemlich regelmäßige Syntax, aber ich habe Schwierigkeiten herauszufinden, wie ich Token für den erweiterten Teil davon bekommen kann.Erhalten einer festen Länge Token

Das Problem ist, dass einigen der Tokens ein Längenwert vorangestellt ist, der angibt, wie lange das Token ist, und einige Parameter haben einen Längenwert, der angibt, wie die folgenden Tokens benötigt werden. Hier

ein Beispiel:

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 
]; 

Der erweiterte Teil, dass ich ein Problem habe mit der Zeichenfolge in Anführungszeichen nach den _draw_= Token. Innerhalb dieser Zeichenfolge gibt die erste Zahl 9 die Länge des nächsten Tokens nach dem Startzeichen "-" an. Wenn das Token eine Reihe von Zeichen ist, die von Leerzeichen umgeben sind (einfach das Token zu definieren), aber in anderen Fällen können diese folgenden Token eingebettete Leerzeichen enthalten, so dass ich es für unmöglich halte, einen Allzweck-Regex zu definieren.

Außerdem folgt dem ersten 'P'-Zeichen innerhalb dieser Zeichenfolge eine 4, was darauf hinweist, dass 4 Zahlenpaare folgen. Wie kann der Parser diese Nummer benutzen, um die nächsten 8-Nummern-Token zu erhalten, oder sollte der Token-Manager die 8-Nummern-Zeichenfolge irgendwie zurückgeben?

Ich weiß, ich kann den gesamten Inhalt der Zeichenfolge als ein einzelner Chunk greifen und dann manuell in Java (nicht mit javacc) mit einigen String-Matching parsen. Allerdings habe ich mich gefragt, ob es eine Technik gibt, dies in javacc zu tun.

Ich vermute, dass die Länge Token nach der Lektüre ich auf einen anderen lexikalischen Zustand wechseln muß, und innerhalb dieses Spiels jedes Zeichen mit einem MORE Modifikator und habe eine lexikalische Aktion auf einen TOKEN Zustand zu wechseln, nachdem die erforderliche Anzahl ist getroffen. Ist das auf dem richtigen Weg? Wie zeige ich an, dass das Token in der lexikalischen Aktion abgeschlossen ist?

Muss ich mich auch um LOOKAHEAD kümmern? (Ich denke nicht, wenn ich das alles in der Token-Manager tun)

Ich werde mit etwas Code folgen, sobald ich herausfinden, was zu tun ist.

+0

Ich denke, Ihre Idee, MEHR zu verwenden, ist perfekt. Warum implementieren Sie es nicht und beantworten Sie Ihre eigene Frage. Um LOOKAHEAD muss man sich keine Sorgen machen. –

+0

Um das Ende eines Tokens anzuzeigen, verwenden Sie eine TOKEN-Produktion. Wenn also ein weiteres Zeichen erwartet wird, wechseln Sie in einen Zustand, in dem ein beliebiges Zeichen ein TOKEN ist. –

Antwort

1

Ok, ich habe es zur Arbeit gebracht. Ich entschied mich dafür, dies in einer lexikalischen Aktion anstatt mit MORE Verarbeitung zu tun, es schien einfach so auf diese Weise. Auch teilte ich das lexing/Parsen in zwei Teile in, um die Dinge einfacher:

  1. Zuerst analysieren, die Saiten die erweiterte Syntax enthalten, und dann
  2. diese Strings mit der erweiterten Syntax in einem zweiten Durchgang analysieren.

Wie für die Token immer auf einer Länge Präfix basiert, war der erste Teil die Tokens, die die Befehle zu definieren:

<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; } 
} 

ich in den lexikalischen Aktionen hinzugefügt Anweisungen, bei denen die Länge Token würde, um anzuzeigen, treten nach dem Befehlstoken auf. In den meisten Fällen war es das erste Token nach dem Unterbefehl, aber in einigen Fällen mussten andere intervenierende Tokens zuerst analysiert werden.

Als Nächstes definieren Sie das Token, um die Länge zu ermitteln.Wenn sie ausgelöst wurde, um das länge spezifizierte Token zu konsumieren, dekodierte die lexikalische Aktion dann die Längenzählung und verbrauchte die entsprechende Anzahl von Zeichen aus dem Eingabepuffer. Nachdem die richtigen Daten abgerufen wurden, wird das Token-Image umgeschaltet und der entsprechende Typ eingegeben. Dieses Token stimmt auch mit Zahlenzeichenfolgen im lexikalischen Standardzustand überein.

/* 
* 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; 
     } 
    } 
} 

Die speziellen Token hatte auch erklärt, werden als die Variablen, die den Countdown zum Token zu entschlüsseln gehalten:

/* 
* 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;; 
} 

Das eigentlich recht einfach war, wenn ich verstanden, wie lexikalischen Aktionen gearbeitet und Was kann mit der Token-Manager-API getan werden?

<LINECOLOR> color=<SINGLE> 

oder

<UNFILLEDPOLYGON> scoords=<COORDS> 

oder

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

Das heißt es:

Um die Verwendung dieser in den Parser, wechseln Sie in den erweiterten lexikalischen Zustand und verwenden Produktionen wie zu machen . Es scheint gut zu funktionieren.

Der einzige Nachteil der Art und Weise, die ich getan habe, ist, dass SKIP Verarbeitung nicht auf die Zeichen auftreten, die ich manuell aus dem Eingangsstrom gelesen, so dass ich Pflege von Leerzeichen nehmen (nicht vollständig in meinem Codebeispiel implementiert).

Verwandte Themen