2010-01-25 10 views
22

que quieren hacer una regla en la flexión de consumir un comentario estilo C como/* */dificultades para obtener los comentarios de c-estilo en flexión/lex

Tengo el siguiente

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

Pero nunca se empareja. ¿Alguna idea de por qué? si necesita más de mi código, por favor hágamelo saber y lo enviaré todo. Gracias a cualquiera que responda

+1

No estoy seguro de por qué no se obtiene ningún partido, pero su expresión va a comer todo en el archivo entre el primer " /*" y el último "*/". Su expresión para que coincida con el contenido del comentario debe evitar que se consuma "* /". Una forma de hacerlo: http://flex.sourceforge.net/manual/How-can-I-match-C_002dstyle-comments_003f.html –

+1

gracias, ese sitio fue útil – adhanlon

Respuesta

35

Le sugiero que utilice start conditions en su lugar.

%x C_COMMENT 

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

hacer la nota que hay no debe ser ningún espacio en blanco entre el <condition> y el Estado.

%x C_COMMENT define el estado C_COMMENT, y la regla /* lo tiene iniciado. Una vez que se ha iniciado, */ lo hará volver al estado inicial (INITIAL está predefinido), y todos los demás caracteres serán consumidos sin ninguna acción particular. Cuando dos reglas coinciden, Flex desambigua al tomar la que tiene la coincidencia más larga, por lo que la regla de puntos no impide que */ coincida. La regla \n es necesaria porque a dot matches everything except a newline.

La definición %x hace C_COMMENT un estado exclusiva, lo que significa que el analizador léxico sólo igualará reglas que están "etiquetados" <C_COMMENT> una vez que se entra en el estado.

Aquí hay un tiny example lexer que implementa esta respuesta imprimiendo todo excepto lo que está adentro /* comments */.

+0

gracias por la ayuda, eso es lo que hice y Funcionó – adhanlon

+2

Entiendo que ya es demasiado tarde para la fiesta, pero esta expresión regular identificaría incorrectamente '/ * basura */* /' como un comentario de bloque completo (de '/ *' a 2nd '* /'), en contraposición a los comentarios de bloque de estilo C en los que la apertura '/ *' termina con el cierre '* /' más cercano y el otro '* /' se identifica como carácter perdido en el programa. La siguiente expresión regular (por flexión/lex) maneja este caso, así ' "/ *"((("*"[^ /])) |? [^ *]) * "* /"' Fuente - [enlace] (http://stackoverflow.com/questions/16160190/regular-expression-to-find-c-style-block-comments) – Shobhit

+0

El problema aquí fue con '. {} ', Si @zneak hubiera usado follopwing, se habría resuelto' [^ * \ n] * "*" + [^ */\ n] * '. se comería todo menos el * seguido de /. Entonces, en este caso, terminaría primero * seguido de /. entonces '/ * basura */foolosh * /', comentaría '/ * basura * /' y seguiría el siguiente token para 'tonto * /' –

6

No estoy seguro de por qué no está siendo recogido, pero sí sé que un patrón de ese tipo puede producir elementos léxicos grandes. Es más eficiente detectar solo el marcador de comentario de inicio y arrojar todo en el bitbucket hasta que encuentre el marcador final.

This site tiene código que hará que:

"/*" { 
    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

No estoy seguro de que sea realmente bueno consumir datos de esa manera. =/¿No es eso una mezcla de preocupaciones? – zneak

+0

Normalmente me inclino por el pragmatismo más que por el dogmatismo :-) – paxdiablo

+0

Solo veo una preocupación aquí, y eso es consumir el comentario para que pueda continuar con lexing tokens reales. Sin embargo, podría argumentar que este ejemplo no aprovecha los mecanismos de abstracción que ofrece flex para hacer que lo que está haciendo sea más claro. –

2

Creo que esta solución es más simple:

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

Incluso si es correcto (me resulta difícil verlo), es ineficiente dado que un lexema bastante largo podría necesitar ser almacenado en 'yytext'. – wcochran

8

He aquí un ejemplo por si alguien está confundido acerca de cómo trabajar la respuesta de zneak:

(Básicamente, pones "% x C_COMMENT" en la primera sección y el resto en la segunda sección, como se explica en su útil enlace)

foo.l 

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

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

%% 
// c code.. 

Espero que ayude a alguien! Tiff

0

El trabajó ejemplo es:

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

que encontró en ostermiller.org

+0

En Flex, '[^ *]' incluye tanto '\ r' como' \ n' (y cualquier otro código de 8 bits excepto '' ') por lo que' | [\ r \ n] 'no es necesario. (Al igual que la mayoría de los otros entornos de expresiones regulares en el artículo vinculado, con la excepción de 'nedit'.) – rici

0

He intentado varias de las soluciones propuestas y aquí están los resultados.

  • no pude conseguir la solución C_COMMENT, que tiene la información más votos y se ve muy bien, trabajar en absoluto en la práctica (uno de los comentarios que se explica, al menos, una de las razones por qué). Debería ser downvoted y ciertamente no debería ser la solución más votada
  • La solución de Mugen parecía funcionar en todo el código que ejecuté en
  • No se pudo obtener la solución de Andrey incluso compilar en lex . Miré el sitio web al que se hace referencia y el uso de patrones de allí no ayudó
  • la respuesta de paxdiablo funcionó y tenía la ventaja de ser fácil de leer. He modificado adicionalmente como sigue:

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

No tengo muy claro por qué la solución de mi respuesta no funciona para usted. En caso de que dos reglas flexibles coincidan, la regla más larga tiene precedencia. Esto significa que la regla '.' nunca debe consumir el' * 'de un token' */'. [Este lexer] (http://pastebin.com/8WT5i2nZ) no sufre del problema que usted describe: la entrada '/ * hello */world * /' produce la salida 'world * /' como se esperaba. – zneak

+0

He agregado un comentario a tu respuesta que explica el problema que tuve, que está relacionado con líneas nuevas incrustadas en el bloque de comentarios – mwag

-2

"/*"(.|\n)"*/" cambio su expresión regular a esto, se trabajará con seguridad.

1

Hay un ejemplo práctico en the Flex manual, que consiga los casos extremos retorcidos derecha:

<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++; 
Cuestiones relacionadas