Reputation: 1099
I'm trying to implement an analyzer via a monadic parser combination using FParsec. I also use an indentation module, but it is not important for the current problem.
So I'm trying to parse this branch of my little AST:
type Identifier = string
type Expression =
...
| Call of Identifier * Expression list
...
type Program = Program of Expression list
I have this implementation:
// Identifier parser
let private identifier =
many1Satisfy2L isLetter
(fun c -> isLetter c || isDigit c) "identifier"
// Monadic parser
let call = parse {
let! id = identifier
let! parameters = sepBy parameter spaces1
return Call(id, parameters)
}
and expression =
... // <|>
attempt call // <|>
...
parameter
represents all acceptable expressions in a function call as a parameter:
// All possible parameter
let parameter =
attempt pint32 <|> // A number, for example.
attempt (identifier |>> fun callid -> Call(callid, [])) <|>
attempt (between (pstring "(") (pstring ")") call)
As you can see, there are two elements of the parser that use the "C/call". They correspond to this, in order and for example:
add x 1 // Call the function `add` and passing it another call (`x`) and the simple literal `1`
add (add 8 2) 10 // Call the function `add` and passing it another call (`add 8 2`) and the simple literal `10`
And of course, these elements can also be intertwined:
add (add x 1) 7
The problem, which I obviously can't solve otherwise I won't ask the question, is that the generated tree doesn't look like what is expected:
add x 1
gives:
Success: Program [Call ("add",[Call ("x",[]); Literal (Int 1)])]
In other words, the parser seems to identify the following x
as the arguments of x
.
However, the second way works. add (add 8 2) 10
gives:
Success: Program
[Call
("add",[Call ("add",[Literal (Int 8); Literal (Int 2)]); Literal (Int 10)])]
Could you put me on track?
Upvotes: 1
Views: 49
Reputation: 11577
To me it looks like the following line matches x
:
attempt (identifier |>> fun callid -> Call(callid, [])) <|>
A single identifier is seen as a call
.
It therefore doesn't suprise that you get: [Call ("add",[Call ("x",[]); Literal (Int 1)])
As you think this is wrong what is the expected results for you? I would have expected this to be an identifer dereference expression.
Also a tip, you seem to have opted for the OCaml style of invoking functions like so: f x y
Perhaps you should also go for the OCaml style that a function always takes a single argument and returns a single value.
add x 1
would then be parsed into something like: Apply (Apply (Identifier "add", Identifier "x"), Literal 1)
Upvotes: 1