2016-05-31 24 views
1

Ich habe ein Jison Stück Code, das wie folgt aussieht: bauenWie erkennt man eine neue Linie in Jison?

%lex 
%options flex 

%{ 
if (!('regions' in yy)) { 
    yy.regions = []; 
} 
%} 

text    [a-zA-Z][a-zA-Z0-9]* 

%% 

\s+     /* skip whitespace */ 
\n+     return 'NL'; 
","     return ','; 
"-"     return '-'; 
"["     return '['; 
"]"     return ']'; 
{text}    return 'TEXT'; 
<<EOF>>    return 'EOF'; 

/lex 

%start expressions 

%% 

expressions 
    : content EOF 
     { 
      console.log(yy.regions); 
      return yy.regions; 
     } 
    | EOF 
     { 
      console.log("empty file"); 
      return yy.regions; 
     } 
    ; 

content 
    : line NL content 
     { console.log("NL"); } 
    | line content 
     { console.log("no NL"); } 
    //| line NL 
    // { console.log("parsing line with NL"); } 
    | line 
     { console.log("parsing line"); } 
    ; 

line 
    : '[' text ']' 
     { yy.regions.push($2); $$ = $2; } 
    ; 

text 
    : TEXT 
     { $$ = $1; } 
    ; 

Dies ist, was meine Eingabe wie im Moment aussieht (ich aus dem grundlegendsten Konstrukt begonnen, die mich mit und ich planen mochte es von dort):

[sectionA] 
[sectionB] 
[sectionC] 

Das Problem, das ich habe, ist, dass die neue Zeile nicht erkannt wird. Es geht immer in die line content und niemals in line NL content. Später würde Ich mag, etwas zu analysieren, die mehr wie folgt aussehen:

[sectionA] 
something1, something2, something3 
something4, something5, something6 

[sectionB] 
something4, something5, something6 

[sectionC] 
something4, something5, something6 
something4, something5, something6 
something4, something5, something6 

In Zukunft wird dies ein wenig komplizierter, aber meine ursprüngliche Idee war, zu Art es brechen zu pro-line-Basis (neue Linie würde in vielen Fällen als Trennzeichen dienen). Ich bin völlig neu in diesem Zeug, also könnte ich eine völlig falsche Vorstellung davon haben, wie man das löst. Meine Frage ist also, wie erkenne ich die neue Linie? Auch wenn es eine bessere Herangehensweise an das gibt, was ich versuche, ist jeder Rat mehr als willkommen. Vielen Dank.

\s+     /* skip whitespace */ 
\n+     return 'NL'; 

Da die erste erste ist, wird es gewinnen:

Antwort

4

Beide dieser Regeln wird ein Newline. (Flex würde Sie warnen, dass die zweite Regel nicht verwendet wird, aber ich glaube nicht, dass jison diese Analyse durchführt.)

Die Reihenfolge der Regeln zu ändern hilft jedoch nicht, weil die erste Regel mit übereinstimmt SPACENL, dabei wird der Zeilenumbruch geschluckt, wenn ihm Leerzeichen vorangestellt sind. Sie müssen die Whitespace-Regel so ändern, dass sie nur Leerzeichen entspricht, die keine Zeilenumbrüche sind.

Eine Möglichkeit wäre:

\n\s*  return 'NL'; 
[^\S\n]+ /* ignore whitespace other than newlines */ 

Das erste Muster wird eine neue Zeile von einer Sequenz von Leerzeichen gefolgt übereinstimmen, was bedeutet, dass es mehrere newlines übereinstimmen. Das vermeidet die Rückgabe von mehr als einem Token NL, wenn in der Eingabe eine Leerzeile vorhanden ist. es sei denn, Leerzeilen sind signifikant, das ist wahrscheinlich das, was Sie wollen.

Das zweite Muster vermeidet die Übereinstimmung mit einer neuen Zeile, sodass es nicht mit dem ersten Muster in Konflikt kommen kann.

Sorge Einige Leute über die Verwendung von Windows-Zeilenenden (\r\n), aber da Javascripts \s\r enthält, gibt es kein wirkliches Problem hier. Die \r wird von der zweiten Regel ignoriert und die \n von der ersten erkannt. Sie könnten die erste Regel in \r?\n\s* für Effizienz ändern, wenn Sie das für notwendig hielten, aber es könnte nicht schneller sein.

+0

Es hat funktioniert. Danke vielmals. Es tut genau das, was ich brauche und die Antwort war im Allgemeinen ziemlich informativ. – pootzko

0

@ ricis Antwort hat geholfen und es hat mich auf den richtigen Weg gebracht. Allerdings tat [ \t]+ nicht, was ich brauchte. Dies sind die beiden Linien, die ich am Ende mit:

(\r?\n)+\s*   return 'NEWLINE'; 
[^\S\r\n]+   ; /* whitespace */ 

Ich fand sie here.

Bearbeiten: @ ricis aktualisierte Antwort ist klarer als diese Antwort und tut genau, was ich brauche, also akzeptiere ich das.

+0

Es wäre genau gleichbedeutend mit '\ r' zu der Liste der Leerraumzeichen, mit Ausnahme eines wichtigen Unterschieds: Ihr Original gibt ein einzelnes NEWLINE-Token für eine beliebige Anzahl von Zeilenumbrüchen zurück (wobei Leerzeilen ignoriert werden), während das in dieser Antwort sendet einen NEWLINE-Token für jede neue Zeile. Wenn ich noch einmal darüber nachdenke, was ich für den Fall empfehlen würde, in dem Sie leere Zeilen ignorieren möchten, ist '\ n \ s *'. – rici

+0

@rici - Ich bin mir nicht sicher, ob ich verstanden habe, was du gerade geschrieben hast. Meinst du, wenn ich \ n \ s * anstelle von \ n + verwenden würde, würde das mehrere aufeinanderfolgende Leerzeilen ignorieren? Im Grunde möchte ich nur wissen, wann eine leere Zeile aufgetreten ist, so dass ich es als Trennzeichen verwenden und dann die nächste Zeile analysieren konnte. Wenn das Sinn macht ... Wenn Sie eine bessere Lösung als die in dieser Antwort haben, werde ich es gerne akzeptieren, wenn es das tut, was ich gerade beschrieben habe. – pootzko

+0

Im Allgemeinen fühle ich mich ein wenig verloren, eine korrekte Dokumentation zu diesen Regeln zu finden, da jede Sprache ihre eigenen Macken hat, wie man diese Art von Regex-Muster-Matching macht und es scheint nicht klar genug zu sein, wie man es in Jison macht/Bison. – pootzko