Parsec: Parsing a list of lists, both with the same delimiter

大憨熊 提交于 2019-12-11 12:22:09

问题


Consider a simple language that's a list of space-delimited commands. Each command takes a single letter as the command name, and a series of space-delimited numbers as its arguments; e.g. a 1 2 3 b 4 5 6 d 7 e f would represent the following commands:

  • a 1 2 3
  • b 4 5 6
  • d 7
  • e
  • f

The problem is that it keeps grabbing items through sepBy, and reaches for another number but fails when it gets to "b".

However, this yields the following error when passed through the code below:

Left "error" (line 1, column 5):
unexpected "b"
expecting space

I realize now that this is likely coming from an error in the way I'm looking at the problem, and would appreciate someone pointing out how to parse something like this.


module Main where

import Control.Applicative hiding (many, optional, (<|>))
import Text.ParserCombinators.Parsec
import Numeric (readSigned, readFloat)

commands = command `sepBy` spaces

command = do
  l <- letter
  ns <- number `sepBy` spaces
  return (l, ns)

main :: IO ()
main = print $ show $ parse commands "error" "a 1 2 3 b 4 5 6 d 7 e f"

number :: CharParser () Double
number = do s <- getInput
            case readSigned readFloat s of
              [(n, s')] -> n <$ setInput s'
              _         -> empty

回答1:


Try consuming the spaces after each non-space token. E.g.

commands = many (command <* spaces)

command = do
  l <- letter
  spaces
  ns <- many (number <* spaces)
  return (l, ns)

Or

command = (,) <$> (letter <* spaces) <*> many (number <* spaces)

The main idea is: after you parse something, the next character should be a non-space starting the next item to be parsed.




回答2:


I would write the parser as @chi has suggested.

The deal with sepBy is that if the separator is matched then sepBy expects to parse another item.



来源:https://stackoverflow.com/questions/33881260/parsec-parsing-a-list-of-lists-both-with-the-same-delimiter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!