Created
May 1, 2014 05:43
-
-
Save darbicus/c22743620340c8c23167 to your computer and use it in GitHub Desktop.
PEMDAS parser made using pegjs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = (function() { | |
/* | |
* Generated by PEG.js 0.8.0. | |
* | |
* http://pegjs.majda.cz/ | |
*/ | |
function peg$subclass(child, parent) { | |
function ctor() { this.constructor = child; } | |
ctor.prototype = parent.prototype; | |
child.prototype = new ctor(); | |
} | |
function SyntaxError(message, expected, found, offset, line, column) { | |
this.message = message; | |
this.expected = expected; | |
this.found = found; | |
this.offset = offset; | |
this.line = line; | |
this.column = column; | |
this.name = "SyntaxError"; | |
} | |
peg$subclass(SyntaxError, Error); | |
function parse(input) { | |
var options = arguments.length > 1 ? arguments[1] : {}, | |
peg$FAILED = {}, | |
peg$startRuleFunctions = { start: peg$parsestart }, | |
peg$startRuleFunction = peg$parsestart, | |
peg$c0 = peg$FAILED, | |
peg$c1 = "+", | |
peg$c2 = { type: "literal", value: "+", description: "\"+\"" }, | |
peg$c3 = function(left, right) { return left + right; }, | |
peg$c4 = "-", | |
peg$c5 = { type: "literal", value: "-", description: "\"-\"" }, | |
peg$c6 = function(left, right) { return left-right;}, | |
peg$c7 = "*", | |
peg$c8 = { type: "literal", value: "*", description: "\"*\"" }, | |
peg$c9 = function(left, right) { return left * right; }, | |
peg$c10 = "(", | |
peg$c11 = { type: "literal", value: "(", description: "\"(\"" }, | |
peg$c12 = ")", | |
peg$c13 = { type: "literal", value: ")", description: "\")\"" }, | |
peg$c14 = function(left, inside) {return left*inside;}, | |
peg$c15 = "/", | |
peg$c16 = { type: "literal", value: "/", description: "\"/\"" }, | |
peg$c17 = function(left, right) { return left / right;}, | |
peg$c18 = "^", | |
peg$c19 = { type: "literal", value: "^", description: "\"^\"" }, | |
peg$c20 = function(left, right) { return Math.pow(left,right);}, | |
peg$c21 = function(inside) { return inside; }, | |
peg$c22 = { type: "other", description: "real" }, | |
peg$c23 = [], | |
peg$c24 = /^[0-9.]/, | |
peg$c25 = { type: "class", value: "[0-9.]", description: "[0-9.]" }, | |
peg$c26 = function(digits) { return parseFloat(digits.join("")); }, | |
peg$c27 = function(right) {return parseFloat("-"+right);}, | |
peg$currPos = 0, | |
peg$reportedPos = 0, | |
peg$cachedPos = 0, | |
peg$cachedPosDetails = { line: 1, column: 1, seenCR: false }, | |
peg$maxFailPos = 0, | |
peg$maxFailExpected = [], | |
peg$silentFails = 0, | |
peg$cache = {}, | |
peg$result; | |
if ("startRule" in options) { | |
if (!(options.startRule in peg$startRuleFunctions)) { | |
throw new Error("Can't start parsing from rule \"" + options.startRule + "\"."); | |
} | |
peg$startRuleFunction = peg$startRuleFunctions[options.startRule]; | |
} | |
function text() { | |
return input.substring(peg$reportedPos, peg$currPos); | |
} | |
function offset() { | |
return peg$reportedPos; | |
} | |
function line() { | |
return peg$computePosDetails(peg$reportedPos).line; | |
} | |
function column() { | |
return peg$computePosDetails(peg$reportedPos).column; | |
} | |
function expected(description) { | |
throw peg$buildException( | |
null, | |
[{ type: "other", description: description }], | |
peg$reportedPos | |
); | |
} | |
function error(message) { | |
throw peg$buildException(message, null, peg$reportedPos); | |
} | |
function peg$computePosDetails(pos) { | |
function advance(details, startPos, endPos) { | |
var p, ch; | |
for (p = startPos; p < endPos; p++) { | |
ch = input.charAt(p); | |
if (ch === "\n") { | |
if (!details.seenCR) { details.line++; } | |
details.column = 1; | |
details.seenCR = false; | |
} else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") { | |
details.line++; | |
details.column = 1; | |
details.seenCR = true; | |
} else { | |
details.column++; | |
details.seenCR = false; | |
} | |
} | |
} | |
if (peg$cachedPos !== pos) { | |
if (peg$cachedPos > pos) { | |
peg$cachedPos = 0; | |
peg$cachedPosDetails = { line: 1, column: 1, seenCR: false }; | |
} | |
advance(peg$cachedPosDetails, peg$cachedPos, pos); | |
peg$cachedPos = pos; | |
} | |
return peg$cachedPosDetails; | |
} | |
function peg$fail(expected) { | |
if (peg$currPos < peg$maxFailPos) { return; } | |
if (peg$currPos > peg$maxFailPos) { | |
peg$maxFailPos = peg$currPos; | |
peg$maxFailExpected = []; | |
} | |
peg$maxFailExpected.push(expected); | |
} | |
function peg$buildException(message, expected, pos) { | |
function cleanupExpected(expected) { | |
var i = 1; | |
expected.sort(function(a, b) { | |
if (a.description < b.description) { | |
return -1; | |
} else if (a.description > b.description) { | |
return 1; | |
} else { | |
return 0; | |
} | |
}); | |
while (i < expected.length) { | |
if (expected[i - 1] === expected[i]) { | |
expected.splice(i, 1); | |
} else { | |
i++; | |
} | |
} | |
} | |
function buildMessage(expected, found) { | |
function stringEscape(s) { | |
function hex(ch) { return ch.charCodeAt(0).toString(16).toUpperCase(); } | |
return s | |
.replace(/\\/g, '\\\\') | |
.replace(/"/g, '\\"') | |
.replace(/\x08/g, '\\b') | |
.replace(/\t/g, '\\t') | |
.replace(/\n/g, '\\n') | |
.replace(/\f/g, '\\f') | |
.replace(/\r/g, '\\r') | |
.replace(/[\x00-\x07\x0B\x0E\x0F]/g, function(ch) { return '\\x0' + hex(ch); }) | |
.replace(/[\x10-\x1F\x80-\xFF]/g, function(ch) { return '\\x' + hex(ch); }) | |
.replace(/[\u0180-\u0FFF]/g, function(ch) { return '\\u0' + hex(ch); }) | |
.replace(/[\u1080-\uFFFF]/g, function(ch) { return '\\u' + hex(ch); }); | |
} | |
var expectedDescs = new Array(expected.length), | |
expectedDesc, foundDesc, i; | |
for (i = 0; i < expected.length; i++) { | |
expectedDescs[i] = expected[i].description; | |
} | |
expectedDesc = expected.length > 1 | |
? expectedDescs.slice(0, -1).join(", ") | |
+ " or " | |
+ expectedDescs[expected.length - 1] | |
: expectedDescs[0]; | |
foundDesc = found ? "\"" + stringEscape(found) + "\"" : "end of input"; | |
return "Expected " + expectedDesc + " but " + foundDesc + " found."; | |
} | |
var posDetails = peg$computePosDetails(pos), | |
found = pos < input.length ? input.charAt(pos) : null; | |
if (expected !== null) { | |
cleanupExpected(expected); | |
} | |
return new SyntaxError( | |
message !== null ? message : buildMessage(expected, found), | |
expected, | |
found, | |
pos, | |
posDetails.line, | |
posDetails.column | |
); | |
} | |
function peg$parsestart() { | |
var s0; | |
var key = peg$currPos * 10 + 0, | |
cached = peg$cache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$parseadditive(); | |
peg$cache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parseadditive() { | |
var s0, s1, s2, s3; | |
var key = peg$currPos * 10 + 1, | |
cached = peg$cache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = peg$parsemultiplicative(); | |
if (s1 !== peg$FAILED) { | |
if (input.charCodeAt(peg$currPos) === 43) { | |
s2 = peg$c1; | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c2); } | |
} | |
if (s2 !== peg$FAILED) { | |
s3 = peg$parseadditive(); | |
if (s3 !== peg$FAILED) { | |
peg$reportedPos = s0; | |
s1 = peg$c3(s1, s3); | |
s0 = s1; | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$parsesubtractive(); | |
} | |
peg$cache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parsesubtractive() { | |
var s0, s1, s2, s3; | |
var key = peg$currPos * 10 + 2, | |
cached = peg$cache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = peg$parsemultiplicative(); | |
if (s1 !== peg$FAILED) { | |
if (input.charCodeAt(peg$currPos) === 45) { | |
s2 = peg$c4; | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c5); } | |
} | |
if (s2 !== peg$FAILED) { | |
s3 = peg$parsesubtractive(); | |
if (s3 !== peg$FAILED) { | |
peg$reportedPos = s0; | |
s1 = peg$c6(s1, s3); | |
s0 = s1; | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$parsemultiplicative(); | |
} | |
peg$cache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parsemultiplicative() { | |
var s0, s1, s2, s3; | |
var key = peg$currPos * 10 + 3, | |
cached = peg$cache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = peg$parseexponent(); | |
if (s1 !== peg$FAILED) { | |
if (input.charCodeAt(peg$currPos) === 42) { | |
s2 = peg$c7; | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c8); } | |
} | |
if (s2 !== peg$FAILED) { | |
s3 = peg$parsemultiplicative(); | |
if (s3 !== peg$FAILED) { | |
peg$reportedPos = s0; | |
s1 = peg$c9(s1, s3); | |
s0 = s1; | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$parsem2(); | |
} | |
peg$cache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parsem2() { | |
var s0, s1, s2, s3, s4; | |
var key = peg$currPos * 10 + 4, | |
cached = peg$cache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = peg$parseexponent(); | |
if (s1 !== peg$FAILED) { | |
if (input.charCodeAt(peg$currPos) === 40) { | |
s2 = peg$c10; | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c11); } | |
} | |
if (s2 !== peg$FAILED) { | |
s3 = peg$parsem2(); | |
if (s3 !== peg$FAILED) { | |
if (input.charCodeAt(peg$currPos) === 41) { | |
s4 = peg$c12; | |
peg$currPos++; | |
} else { | |
s4 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c13); } | |
} | |
if (s4 !== peg$FAILED) { | |
peg$reportedPos = s0; | |
s1 = peg$c14(s1, s3); | |
s0 = s1; | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$parsedivide(); | |
} | |
peg$cache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parsedivide() { | |
var s0, s1, s2, s3; | |
var key = peg$currPos * 10 + 5, | |
cached = peg$cache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = peg$parseexponent(); | |
if (s1 !== peg$FAILED) { | |
if (input.charCodeAt(peg$currPos) === 47) { | |
s2 = peg$c15; | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c16); } | |
} | |
if (s2 !== peg$FAILED) { | |
s3 = peg$parsedivide(); | |
if (s3 !== peg$FAILED) { | |
peg$reportedPos = s0; | |
s1 = peg$c17(s1, s3); | |
s0 = s1; | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$parseexponent(); | |
} | |
peg$cache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parseexponent() { | |
var s0, s1, s2, s3; | |
var key = peg$currPos * 10 + 6, | |
cached = peg$cache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
s1 = peg$parseprimary(); | |
if (s1 !== peg$FAILED) { | |
if (input.charCodeAt(peg$currPos) === 94) { | |
s2 = peg$c18; | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c19); } | |
} | |
if (s2 !== peg$FAILED) { | |
s3 = peg$parseexponent(); | |
if (s3 !== peg$FAILED) { | |
peg$reportedPos = s0; | |
s1 = peg$c20(s1, s3); | |
s0 = s1; | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
if (s0 === peg$FAILED) { | |
s0 = peg$parseprimary(); | |
} | |
peg$cache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parseprimary() { | |
var s0, s1, s2, s3; | |
var key = peg$currPos * 10 + 7, | |
cached = peg$cache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$parsereal(); | |
if (s0 === peg$FAILED) { | |
s0 = peg$currPos; | |
if (input.charCodeAt(peg$currPos) === 40) { | |
s1 = peg$c10; | |
peg$currPos++; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c11); } | |
} | |
if (s1 !== peg$FAILED) { | |
s2 = peg$parseadditive(); | |
if (s2 !== peg$FAILED) { | |
if (input.charCodeAt(peg$currPos) === 41) { | |
s3 = peg$c12; | |
peg$currPos++; | |
} else { | |
s3 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c13); } | |
} | |
if (s3 !== peg$FAILED) { | |
peg$reportedPos = s0; | |
s1 = peg$c21(s2); | |
s0 = s1; | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
} | |
peg$cache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parsereal() { | |
var s0, s1, s2; | |
var key = peg$currPos * 10 + 8, | |
cached = peg$cache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
peg$silentFails++; | |
s0 = peg$currPos; | |
s1 = []; | |
if (peg$c24.test(input.charAt(peg$currPos))) { | |
s2 = input.charAt(peg$currPos); | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c25); } | |
} | |
if (s2 !== peg$FAILED) { | |
while (s2 !== peg$FAILED) { | |
s1.push(s2); | |
if (peg$c24.test(input.charAt(peg$currPos))) { | |
s2 = input.charAt(peg$currPos); | |
peg$currPos++; | |
} else { | |
s2 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c25); } | |
} | |
} | |
} else { | |
s1 = peg$c0; | |
} | |
if (s1 !== peg$FAILED) { | |
peg$reportedPos = s0; | |
s1 = peg$c26(s1); | |
} | |
s0 = s1; | |
if (s0 === peg$FAILED) { | |
s0 = peg$parsenegative(); | |
} | |
peg$silentFails--; | |
if (s0 === peg$FAILED) { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c22); } | |
} | |
peg$cache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
function peg$parsenegative() { | |
var s0, s1, s2; | |
var key = peg$currPos * 10 + 9, | |
cached = peg$cache[key]; | |
if (cached) { | |
peg$currPos = cached.nextPos; | |
return cached.result; | |
} | |
s0 = peg$currPos; | |
if (input.charCodeAt(peg$currPos) === 45) { | |
s1 = peg$c4; | |
peg$currPos++; | |
} else { | |
s1 = peg$FAILED; | |
if (peg$silentFails === 0) { peg$fail(peg$c5); } | |
} | |
if (s1 !== peg$FAILED) { | |
s2 = peg$parsereal(); | |
if (s2 !== peg$FAILED) { | |
peg$reportedPos = s0; | |
s1 = peg$c27(s2); | |
s0 = s1; | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
} else { | |
peg$currPos = s0; | |
s0 = peg$c0; | |
} | |
peg$cache[key] = { nextPos: peg$currPos, result: s0 }; | |
return s0; | |
} | |
peg$result = peg$startRuleFunction(); | |
if (peg$result !== peg$FAILED && peg$currPos === input.length) { | |
return peg$result; | |
} else { | |
if (peg$result !== peg$FAILED && peg$currPos < input.length) { | |
peg$fail({ type: "end", description: "end of input" }); | |
} | |
throw peg$buildException(null, peg$maxFailExpected, peg$maxFailPos); | |
} | |
} | |
return { | |
SyntaxError: SyntaxError, | |
parse: parse | |
}; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment