Question

All,

I'm trying to write a parser using parsec. The goal is to eventually be able to parse a toy language.

Right now I'm struggling to make parsec recognise two different possible options, for example assignment and function invocation.

How would one write a "parseCode" function to parse the following:

x = 3
y = 4
plus(x,y)

into:

(Assignment "x" "3")
(Assignment "y" "4")
(Invocation "plus" ["x","y"])

Thanks

EDIT:

** omitted for brevity **

EDIT 2:

I built a bit upon your suggestions and now have the following problem Running parse parseTester "bla" "{plus(3,4)\nmin(2,3)\nx=3\n" gives the expected solution: Right (Body [Invocation "plus",Invocation "min",Assignment "x" "3"]).

But running the functionally (almost) equivalent parse parseBody "bla" "{plus(3,4)\nmin(2,3)\nx=3\n}" results in an error:

Left "bla" (line 4, column 2):
unexpected end of input
expecting white space or "="

I don't see the problem. Is the parser suddenly looking for an assignment where it should be looking for an invocation? Any suggestions?

Code:

data Body = Body [Statement]
    deriving (Show)

data Arguments = Arguments [String]
    deriving (Show)

data Statement = Assignment String String
               | Invocation String
    deriving (Show)


parseBody :: Parser Body
parseBody = do
    char '{'
    statements <- many1 parseStatement
    char '}'
    return $ Body statements

parseTester :: Parser Body
parseTester = do 
    char '{'
    x <- many1 parseStatement
    return $ Body x

parseStatement :: Parser Statement
parseStatement = do
        x <- try parseInvocation <|> parseAssignment <?> "statement"
        return x

parseInvocation :: Parser Statement
parseInvocation = do
    spaces
    name <- many1 (noneOf " (")
    spaces
    char '('
    spaces
    bla <- many1 (noneOf " )")
    spaces
    char ')'
    char '\n'
    return $ Invocation name

parseAssignment :: Parser Statement
parseAssignment = do
    spaces
    var <- many1 (noneOf " =")
    spaces
    char '=' <?> "equal in assignment"
    spaces
    value <- many1 (noneOf "\n")
    char '\n'
    spaces
    return $ Assignment var value
Was it helpful?

Solution

If we need to parse some choices, you could use choice from Text.ParserCombinators.Parsec.Combinator

choice [parseInvocation, parseAssignmen]

or much simplier: try parseInvocation <|> try parseAssignmen

P.S.

You could use form Text.ParserCombinators.Parsec.Char:

many (oneOf " ") == spaces

oneOf " " == space
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top