Skip to content

Instantly share code, notes, and snippets.

Last active Apr 5, 2016
What would you like to do?
var util = require("util");
var P = require("parsimmon");
// Throw away whitespace surrounding a string.
function operator(s) {
return P.optWhitespace
// This is where the magic happens. It takes the parser representing the next
// precedence level, and the parser the actually recognizes the operators
// themselves (+-*/), and parses out a list of things separated by these
// operators, and combines them into arrays that look like.
// ["Add",
// ["Multiply",
// ["Number", 3],
// ["Number", 4]],
// ["Number", 10]]
function leftBinaryOperator(next, op) {
// This function takes (a, [operator, b]) and returns [operator, a, b].
function operatorReducer(acc, pair) {
return [pair[0], acc, pair[1]];
// Takes (a, [[op1, b1], [op2, b2], ...]).
// Returns [op2, [op1, a, b1], b2], or simply 'a' if the list is empty.
function combineOperators(first, rest) {
return rest.reduce(operatorReducer, first);
return P.seqMap(next, P.seq(op, next).many(), combineOperators);
// This could be more complicated than just number literals. Variables could go
// here, or function calls, or other data literals.
var Num =
P.regex(/[0-9]+/).map(n => ["Number", +n]);
// Turn the operator symbols into names for the tree structure
var OpMul = operator("*").result("Multiply");
var OpDiv = operator("/").result("Divide");
var OpAdd = operator("+").result("Add");
var OpSub = operator("-").result("Subtract");
// Pair up the operators with same precedence level.
var MulDiv = P.alt(OpMul, OpDiv);
var AddSub = P.alt(OpAdd, OpSub);
// MathParser1 and MathParser2 work exactly the same way. This just shows off an
// explicit naming of each precedence level, vs simply ordering them in a list.
var MathParser1 = (function() {
var Mul = leftBinaryOperator(Num, MulDiv);
var Add = leftBinaryOperator(Mul, AddSub);
return Add;
var MathParser2 =
[MulDiv, AddSub].reduce(leftBinaryOperator, Num);
var input = "2 + 3 * 4 - 3 / 1";
var result = MathParser2.parse(input).value;
var txt = util.inspect(result, {depth: null, colors: true});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment