I'm using parsimmon
to parse a simple math expression and I'm failing to parse a simple math expression that follows order of operation (i.e. */
has higher precedence than +-
).
Even if you are not familiar with this library please help me solve precedence problem without left recursion and infinite recursion.
Thank you.
I used TypeScript:
"use strict";
// Run me with Node to see my output!
import * as P from "parsimmon";
import {Parser} from "parsimmon";
// @ts-ignore
import util from "util";
///////////////////////////////////////////////////////////////////////
// Use the JSON standard's definition of whitespace rather than Parsimmon's.
let whitespace = P.regexp(/\s*/m);
// JSON is pretty relaxed about whitespace, so let's make it easy to ignore
// after most text.
function token(parser: Parser<string>) {
return parser.skip(whitespace);
}
// Several parsers are just strings with optional whitespace.
function word(str: string) {
return P.string(str).thru(token);
}
let MathParser = P.createLanguage({
expr: r => P.alt(r.sExpr2, r.sExpr1, r.number),
sExpr1: r => P.seqMap(r.iExpr, P.optWhitespace, r.plusOrMinus, P.optWhitespace, r.expr, (a, s1, b, s2, c) => [a, b, c]),
sExpr2: r => P.seqMap(r.iExpr, P.optWhitespace, r.multiplyOrDivide, P.optWhitespace, r.expr, (a, s1, b, s2, c) => [a, b, c]),
iExpr: r => P.alt(r.iExpr, r.number), // Issue here! this causes infinite recursion
// iExpr: r => r.number // this will fix infinite recursion but yields invalid parse
number: () =>
token(P.regexp(/[0-9]+/))
.map(Number)
.desc("number"),
plus: () => word("+"),
minus: () => word("-"),
plusOrMinus: r => P.alt(r.plus, r.minus),
multiply: () => word("*"),
divide: () => word("/"),
multiplyOrDivide: r => P.alt(r.multiply, r.divide),
operator: r => P.alt(r.plusOrMinus, r.multiplyOrDivide)
});
///////////////////////////////////////////////////////////////////////
let text = "3 / 4 - 5 * 6 + 5";
let ast = MathParser.expr.tryParse(text);
console.log(util.inspect(ast, {showHidden: false, depth: null}));
P.alt
order matters. So that's why I usedr.sExpr2
and thenr.sExpr1
– SterileiExpr: r => r.number
which yields invalid parse tree – Sterileexpr
is parsingsExpr1
that tries to mapexpr
, also happens withsExpr2
, andiExpr
is triying to parse itself... Could you please explain what is are results you want to acomplish? – Cuccuckoldr.sExpr2
and thenr.sExpr1
, since you are parsing a Math expression you need number + [plus|minus|multiply|divide], ignoring spaces... could you please clarify that please? – Cuccuckold1 + 2 / 3 => [1, '+', [ '/', 3]]
– Sterile