2010-01-25 5 views
22

Ich mag flex eine Regel, um einen c-style Kommentar wie/* */Schwierigkeiten, c-Stil Kommentare in flex/lex

i den folgenden

c_comment "/*"[\n.]*"*/" 

Aber es habe zu konsumieren wird nie gefunden. Irgendeine Idee warum? Wenn Sie mehr von meinem Code benötigen, lassen Sie es mich wissen und ich werde das Ganze einreichen. Danke an alle, die antworten.

+1

Ich bin mir nicht sicher, warum Sie keine Übereinstimmung gibt, aber Ihr Ausdruck alles in der Datei zwischen dem ersten essen " /*" und der letzte "*/". Ihr Ausdruck, der dem Inhalt des Kommentars entspricht, muss "* /" davon abhalten, konsumiert zu werden. Ein Weg, dies zu tun: http://flex.sourceforge.net/manual/How-can-I-match-C_002dstyle-comments_003f.html –

+1

Danke, diese Seite war hilfreich – adhanlon

Antwort

35

Ich schlage vor, dass Sie stattdessen start conditions verwenden.

%x C_COMMENT 

"/*"   { BEGIN(C_COMMENT); } 
<C_COMMENT>"*/" { BEGIN(INITIAL); } 
<C_COMMENT>\n { } 
<C_COMMENT>. { } 

Sie beachten, dass es nicht jedes Leerzeichen zwischen den <condition> und der Regel sein muss.

%x C_COMMENT definiert den C_COMMENT-Status, und die Regel /* startet es. Sobald es gestartet wird, */ wird es zurück in den Ausgangszustand (INITIAL ist vordefiniert), und alle anderen Zeichen werden nur ohne besondere Maßnahmen verbraucht werden. Wenn zwei Regeln übereinstimmen, unterscheidet sich Flex von demjenigen, der die längste Übereinstimmung aufweist. Daher verhindert die Punktregel nicht, dass */ übereinstimmt. Die \n Regel ist notwendig, weil .

Die %x Definition macht C_COMMENT einen exklusiven Zustand, die die Lexer bedeutet nur Regeln übereinstimmen, die „getaggt“ werden <C_COMMENT>, sobald es den Zustand eintritt.

Hier ist eine tiny example lexer, die diese Antwort implementiert, indem Sie alles drucken, außer was drin ist /* comments */.

+0

danke für die Hilfe, das ist, was ich getan habe und es funktionierte – adhanlon

+2

Ich verstehe, dass ich zu spät zur Party bin, aber diese Regex würde '/ * Quatsch */* /' fälschlicherweise als kompletten Blockkommentar (von '/ *' zu 2. '* /') im Gegensatz identifizieren zu den C-Stil-Blockkommentaren, in denen das Öffnen von '/ *' durch das nächste Schließen '* /' beendet wird und das andere '* /' im Programm als Streuzeichen identifiziert wird. Die folgende regex (für flex/lex) behandelt diesen Fall auch ' "/ *"((("*"[^ /])) | [^ *]) * "* /"' Quelle - [link] (http://stackoverflow.com/questions/16160190/regular-expression-to-find-c-style-block-comments) – Shobhit

+0

Das Problem hier war mit '. {} ', Wenn @zneak follopwing verwendet hätte, wäre es aufgelöst worden: [^ * \ n] * " * "+ [^ */\ n] *'. es würde alles auffressen außer dem * gefolgt von /. In diesem Fall würde es also zuerst * gefolgt von/enden. so '/ * Müll */Nilpferd * /', würde es kommentieren/* Müll */'und folgen nächsten Token für' dumm */' –

6

Nicht sicher, warum es nicht abgeholt wird, aber ich weiß, dass ein Muster dieser Art große lexikalische Elemente erzeugen kann. Es ist effizienter, nur den Startkommentar zu erkennen und alles im Bitbucket zu werfen, bis Sie den Endmarker gefunden haben.

This site hat Code, der das tun:

"/*" { 
    for (;;) { 
     while ((c = input()) != '*' && c != EOF) 
      ; /* eat up text of comment */ 
     if (c == '*') { 
      while ((c = input()) == '*') 
       ; 
      if (c == '/') 
       break; /* found the end */ 
     } 
     if (c == EOF) { 
      error ("EOF in comment"); 
      break; 
     } 
    } 
} 
+1

Ich bin mir nicht sicher, ob es wirklich gut ist, Input auf diese Weise zu konsumieren. =/Ist das nicht eine Mischung aus Bedenken? – zneak

+0

Normalerweise tendiere ich zum Pragmatismus als Dogmatismus :-) – paxdiablo

+0

Ich sehe hier nur eine Sorge, und das ist der Verzehr des Kommentars, damit Sie mit dem Lexing echter Tokens fortfahren können. Sie könnten jedoch argumentieren, dass dieses Beispiel nicht die Abstraktionsmechanismen nutzt, die flex bietet, um das, was Sie tun, klarer zu machen. –

2

Ich glaube, diese Lösung ist einfacher:

"/*"((\*+[^/*])|([^*]))*\**"*/" 
+0

Auch wenn es korrekt ist (schwierig für mich), ist es ineffizient, da ein ziemlich langes Lexem in 'yytext' gepuffert werden muss. – wcochran

8

Hier ein Beispiel ist für den Fall, jemand verwirrt ist, wie zneak Antwort zu arbeiten:

(Im Grunde setzen Sie "% x C_COMMENT" in den ersten Abschnitt und den Rest in den zweiten Abschnitt, wie durch seinen hilfreichen Link erläutert)

foo.l 

%{ 
// c code.. 
%} 
%x C_COMMENT 

%% 
"/*"   { BEGIN(C_COMMENT); } 
<C_COMMENT>"*/" { BEGIN(INITIAL); } 
<C_COMMENT>. { } 

%% 
// c code.. 

Hoffe, dass jemand hilft! Tiff

0

Das Beispiel gearbeitet ist:

\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\/ 

die

+0

In Flex enthält '[^ *]' sowohl '\ r' als auch' \ n' (und jeden anderen 8-Bit-Code außer '*'), so dass das '| [\ r \ n]' unnötig ist. (Genau wie die meisten anderen Regex-Umgebungen im verknüpften Artikel, mit Ausnahme von 'nedit'.) – rici

0

in ostermiller.org fand ich habe einige der vorgeschlagenen Lösungen ausprobiert und hier sind die Ergebnisse.

  • ich nicht die C_COMMENT Lösung bekommen könnte, die die meisten up-Stimmen haben und sehen gut aus, zu arbeiten, überhaupt in der Praxis (einen der Kommentare, um es zumindest einen Grund, warum erklärt). Es sollte downvoted werden und sicherlich nicht die am besten gewählte Lösung sein.
  • Die Lösung von Mugen schien in allen Code zu funktionieren Ich lief es auf
  • Konnte nicht die Lösung von Andrey überhaupt überhaupt in Lex kompilieren . Ich schaute auf die referenzierte Website und die Verwendung von Mustern von dort nicht geholfen
  • die Antwort von paxdiablo arbeitete und hatte den Vorteil, einfach zu lesen. I weiter modifiziert wie folgt:

     
    "/*" { int c1 = 0, c2 = input(); 
         for(;;) { 
         if(c2 == EOF) break; 
         if(c1 == '*' && c2 == '/') 
          break; 
         c1 = c2; 
         c2 = input(); 
         } 
        } 
    
+0

Es ist mir nicht ganz klar, warum die Lösung in meiner Antwort nicht für Sie arbeitet. Wenn zwei Flex-Regeln übereinstimmen, hat die längste Regel Vorrang. Das bedeutet, dass die '.'-Regel niemals das' * 'eines' */'-Tokens konsumieren darf. [Dieser Lexer] (http://pastebin.com/8WT5i2nZ) leidet nicht unter dem von Ihnen beschriebenen Problem: Die Eingabe '/ * hallo */world * /' erzeugt die Ausgabe 'world * /' wie erwartet. – zneak

+0

Ich habe Ihrer Antwort einen Kommentar hinzugefügt, der das Problem mit eingebetteten Zeilenumbrüchen im Kommentarblock erläutert – mwag

-2

"/*"(.|\n)"*/" Änderung Ihrer regulären Ausdruck kommt, wird es sicher funktionieren.

1

Es gibt ein ausgearbeitetes Beispiel in the Flex manual, die die knorrigen Rand Fällen richtig macht:

<INITIAL>"/*"   BEGIN(IN_COMMENT); 
<IN_COMMENT>"*/"  BEGIN(INITIAL); 
<IN_COMMENT>[^*\n]+ // eat comment in chunks 
<IN_COMMENT>"*"  // eat the lone star 
<IN_COMMENT>\n  yylineno++;