-
-
Save jdavidw13/2156565 to your computer and use it in GitHub Desktop.
A parser for DnD dice rolls, with support for min/max rolls.
This file contains hidden or 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
| //infix operator-precedence parser, supporting d, + and -, where d is a dice | |
| // roll | |
| var parse = (function () { | |
| //the operators we deal with and their precedence | |
| var operators = { | |
| '+' : 1, | |
| '-' : 1, | |
| 'd' : 2 | |
| }; | |
| //object with keys 0-9 set to true | |
| var digits = [ | |
| true, true, true, true, true, | |
| true, true, true, true, true | |
| ]; | |
| //we don't care about whitespace. well, most whitespace | |
| var whitespace = { | |
| ' ' : true, | |
| '\t' : true | |
| }; | |
| var callbacks = { | |
| '+' : function ( a, b ) { | |
| return a + b; | |
| }, | |
| '-' : function ( a, b ) { | |
| return a - b; | |
| }, | |
| 'd' : function ( rolls, sides ) { | |
| var ret = 0; | |
| while ( rolls-- ) { | |
| ret += Math.floor( Math.random() * sides ) + 1; | |
| } | |
| return ret; | |
| } | |
| }; | |
| return function ( source ) { | |
| var numberStack = [], | |
| operatorStack = []; | |
| //remove ALL whitespace! | |
| //could be achieved by: | |
| // source = source.replace( /\s/g, '' ) | |
| //but who cares? | |
| Object.keys( whitespace ).forEach(function ( whitey ) { | |
| source = source.replace( whitey, '' ); | |
| }); | |
| var token, last; | |
| for ( var pos = 0, len = source.length; pos < len; ++pos ) { | |
| token = nextToken(); | |
| if ( token.type === 'number' ) { | |
| numberStack.push( token.value ); | |
| } | |
| else if ( token.type === 'operator' ) { | |
| last = operatorStack[ operatorStack.length - 1 ]; | |
| if ( | |
| //previous operator is more important than us | |
| (last && token.precedence < last.precedence) || | |
| //or, we're about to finish | |
| pos + 1 === len | |
| ) { | |
| operate(); | |
| } | |
| operatorStack.push( token ); | |
| } | |
| } | |
| //by now, operatorStack will only have operators of equal, lowest | |
| // precedence, so we just need to go over the operator stack and execute | |
| while ( operatorStack.length ) { | |
| operate(); | |
| } | |
| //the last number in the stack is the result | |
| return numberStack[ 0 ]; | |
| //get the next token | |
| function nextToken () { | |
| var ch = source[ pos ]; | |
| var ret = { | |
| type : null, | |
| value : ch | |
| }, | |
| res; | |
| //have we overflowed, while looking for something else? | |
| if ( pos >= len ) { | |
| throw new Error( 'Unexpected end of input' ); | |
| } | |
| //is it a digit? | |
| else if ( digits.hasOwnProperty(ch) ) { | |
| ret.type = 'number'; | |
| res = getNumber(); | |
| pos += res.length; | |
| ret.value = res.value; | |
| } | |
| //is it an operator? | |
| else if ( operators.hasOwnProperty(ch) ) { | |
| ret.type = 'operator'; | |
| ret.precedence = operators[ ch ]; | |
| } | |
| return ret; | |
| } | |
| function getNumber () { | |
| var offset = 0, num = 0; | |
| //keep eating digits until we find a non-digit | |
| while ( digits.hasOwnProperty(source[pos+offset]) ) { | |
| num *= 10; | |
| num += Number( source[pos+offset] ); | |
| offset++; | |
| } | |
| return { | |
| value : num, | |
| length : offset - 1 | |
| }; | |
| } | |
| function operate () { | |
| var operator = operatorStack.pop().value, | |
| method = callbacks[ operator ], | |
| couplet = popTwo(); | |
| if ( couplet.indexOf(undefined) > -1 ) { | |
| throw new Error( 'Incomplete expression - expected number' ); | |
| } | |
| numberStack.push( | |
| callbacks[ operatorStack.pop().value ].apply( null, couplet ) | |
| ); | |
| } | |
| function popTwo () { | |
| //because we're going left->right, something like: | |
| // 4 + 1 | |
| //will be displayed in the stack like: | |
| // [1, 4] | |
| //so after grabbing the topmost numbers, we need to flip them | |
| return [ numberStack.pop(), numberStack.pop() ].reverse(); | |
| } | |
| }; | |
| }()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment