2012-07-17 14 views
6

Estoy intentando escribir un analizador en Haskell usando Parsec. Actualmente tengo un programa que puede analizarAnalizador Haskell Parsec para encontrar [...]

test x [1,2,3] end 

El código que hace esto se da como sigue

testParser = do { 
    reserved "test"; 
    v <- identifier; 
    symbol "["; 
    l <- sepBy natural commaSep; 
    symbol "]"; 
    p <- pParser; 
    return $ Test v (List l) p 
} <?> "end" 

donde commaSep se define como

commaSep  = skipMany1 (space <|> char ',') 

Ahora hay alguna manera para mí para analizar una declaración similar, específicamente:

test x [1...3] end 

Al ser nuevo en Haskell, y en Parsec en este sentido, estoy seguro de que hay una forma bastante concisa de hacer esto que no conozco. Cualquier ayuda sería apreciada.

Gracias de nuevo.

+0

¿El número de períodos debe ser constante o variable? ¿Se permiten espacios entre los números y los períodos, y entre los períodos? Por cierto, tu primer analizador coincide con 'test x [1,, 2, ,, 3] end'; tal vez eso no es lo que quieres. – dflemstr

+0

El número de períodos debe ser constante, es decir, [1 ... 3] debe constar de exactamente 3 períodos para cualquier caso. Los espacios en blanco intermedios, como [1 ... 3], deben ignorarse. Espero que eso aclare lo que estoy buscando un poco más. –

Respuesta

14

Voy a utilizar algunas funciones desde Control.Applicative como (*>). Estas funciones son útiles si desea evitar la interfaz monádica de Parsec y prefiere la interfaz de aplicación, porque los analizadores sintácticos se vuelven más fáciles de leer de esa manera, en mi opinión.

Si no está familiarizado con las funciones básicas de aplicación, deje un comentario y las explicaré. Puede buscarlos en Hoogle si no está seguro.


Como he entendido su problema, usted quiere un analizador por alguna estructura de datos como esto:

data Test = Test String Numbers 
data Numbers = List [Int] | Range Int Int 

Un analizador que puede analizar una estructura de este tipo de datos se vería así (he no compiló el código, pero debería funcionar):

-- parses "test <identifier> [<numbers>] end" 
testParser :: Parser Test 
testParser = 
    Test <$> reserved "test" *> identifier 
     <*> symbol "[" *> numbersParser <* symbol "]" 
     <* reserved "end" 
     <?> "test" 

numbersParser :: Parser Numbers 
numbersParser = try listParser <|> rangeParser 

-- parses "<natural>, <natural>, <natural>" etc 
listParser :: Parser Numbers 
listParser = 
    List <$> sepBy natural (symbol ",") 
     <?> "list" 

-- parses "<natural> ... <natural>" 
rangeParser :: Parser Numbers 
rangeParser = 
    Range <$> natural <* symbol "..." 
     <*> natural 
     <?> "range" 
+0

Ah, muchas gracias, eso es precisamente lo que necesitaba. ¡Gracias de nuevo! –

+1

@VincentRusso es un sinónimo de 'fmap'. – phg

+0

Muy bien, una última cosa que todavía intento hacer bien. ¿Puedo hacer algo como l <- try (sepBy commaSep natural <|> símbolo natural "..." natural); Solo que mi implementación aquí no funciona, ¿hay algo similar que pueda hacer? Su ejemplo es excelente, pero la forma en que el analizador se implementa actualmente parece no funcionar tan bien con el ejemplo anterior. Gracias de nuevo por toda su ayuda. –

Cuestiones relacionadas