2010-03-05 9 views
7

Estoy experimentando con los combinadores de analizadores y a menudo me encuentro con lo que parecen recurrencias infinitas. Aquí está el primero con el que me encontré:Combinador de analizador no finalizado - ¿cómo registrar lo que está pasando?

import util.parsing.combinator.Parsers 
import util.parsing.input.CharSequenceReader 

class CombinatorParserTest extends Parsers { 

    type Elem = Char 

    def notComma = elem("not comma", _ != ',') 

    def notEndLine = elem("not end line", x => x != '\r' && x != '\n') 

    def text = rep(notComma | notEndLine) 

} 

object CombinatorParserTest { 

    def main(args:Array[String]): Unit = { 
    val p = new CombinatorParserTest() 
    val r = p.text(new CharSequenceReader(",")) 
    // does not get here 
    println(r) 
    } 

} 

¿Cómo puedo imprimir lo que está pasando? ¿Y por qué esto no termina?

Respuesta

4

Al registrar los intentos de analizar notComma y notEndLine, se muestra que es el final de archivo (se muestra como CTRL-Z en la salida de registro (...) ("mesg") que se analiza repetidamente. Así es como he modificado el programa de análisis para este propósito:

def text = rep(log(notComma)("notComma") | log(notEndLine)("notEndLine")) 

No estoy del todo seguro de lo que está pasando (He intentado muchas variaciones en su gramática), pero creo que es algo como esto: La EOF no es realmente una carácter introducido artificialmente en el flujo de entrada, sino más bien una especie de condición perpetua al final de la entrada. Por lo tanto, este pseudo-carácter EOF nunca consumido se analiza repetidamente como "o bien no es una coma o no es un final de línea".

+0

creo que EOF se introduce artificialmente, pero tienes razón al decir que se analiza en varias ocasiones en que parece estar siempre en repetidas ocasiones, cuando se solicite un carácter adicional cuando la entrada ya está al final de la secuencia. – huynhjl

2

Ok, creo que ya lo descubrí. `CharSequenceReader devuelve '\ 032' como un marcador para el final de la entrada. Así que si modifico mi entrada como esta, funciona:

import util.parsing.combinator.Parsers 
import util.parsing.input.CharSequenceReader 

class CombinatorParserTest extends Parsers { 

    type Elem = Char 

    import CharSequenceReader.EofCh 

    def notComma = elem("not comma", x => x != ',' && x!=EofCh) 

    def notEndLine = elem("not end line", x => x != '\r' && x != '\n' && x!=EofCh) 

    //def text = rep(notComma | notEndLine) 
    def text = rep(log(notComma)("notComma") | log(notEndLine)("notEndLine")) 

} 

object CombinatorParserTest { 

    def main(args:Array[String]): Unit = { 
    val p = new CombinatorParserTest() 
    val r = p.text(new CharSequenceReader(",")) 
    println(r) 
    } 

} 

Ver código fuente de CharSequenceReaderhere. Si el scaladoc lo mencionó, me habría ahorrado mucho tiempo.

+1

Averigüe dónde se debe mencionar y abra un ticket de documentación. Si puede proporcionar un parche con el scaladoc modificado, mucho mejor. –

+0

Enviado https://lampsvn.epfl.ch/trac/scala/ticket/3147. Hay varios archivos que usan 'EofCh', así que no estoy seguro de dónde está el mejor lugar. – huynhjl

0

Encuentro que la función de registro es extremadamente incómoda de escribir. ¿Por qué tengo que hacer log(parser)("string")? ¿Por qué no tener algo tan simple como parser.log("string")? De todas formas, para superar eso, hice este lugar:

trait Logging { self: Parsers => 

    // Used to turn logging on or off 
    val debug: Boolean 

    // Much easier than having to wrap a parser with a log function and type a message 
    // i.e. log(someParser)("Message") vs someParser.log("Message") 
    implicit class Logged[+A](parser: Parser[A]) { 
     def log(msg: String): Parser[A] = 
      if (debug) self.log(parser)(msg) else parser 
    } 
} 

En su programa de análisis, se pueden mezclar en este rasgo de esta manera:

import scala.util.parsing.combinator.Parsers 
import scala.util.parsing.input.CharSequenceReader 


object CombinatorParserTest extends App with Parsers with Logging { 

    type Elem = Char 

    override val debug: Boolean = true 

    def notComma: Parser[Char] = elem("not comma", _ != ',') 
    def notEndLine: Parser[Char] = elem("not end line", x => x != '\r' && x != '\n') 
    def text: Parser[List[Char]] = rep(notComma.log("notComma") | notEndLine.log("notEndLine")) 

    val r = text(new CharSequenceReader(",")) 

    println(r) 
} 

También puede anular el campo debug para apagar el registro si así lo desea.

La ejecución de esta muestra también el segundo analizador analiza correctamente la coma:

trying notComma at [email protected] 
notComma --> [1.1] failure: not comma expected 

, 
^ 
trying notEndLine at [email protected] 
notEndLine --> [1.2] parsed: , 
trying notComma at [email protected] 
notComma --> [1.2] failure: end of input 

, 
^ 
trying notEndLine at [email protected] 
notEndLine --> [1.2] failure: end of input 

, 
^ 
The result is List(,) 

Process finished with exit code 0 
Cuestiones relacionadas