-
-
Save jdavidw13/2156565 to your computer and use it in GitHub Desktop.
Revisions
-
Josiah Wilkerson revised this gist
Mar 22, 2012 . 1 changed file with 23 additions and 6 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -39,14 +39,23 @@ var operators = { }, 'd' : { precedence : 3, exec : function ( rolls, sides, rollsSoFar, range ) { if ( rolls > 100 ) { throw new Error( 'Maximum roll count is 100' ); } var ret = 0, roll; while ( rolls-- ) { roll = Math.floor( Math.random() * sides ) + 1; if (range != null && range.toLowerCase) { if ('min' == range.toLowerCase()) { roll = 1; } else if ('max' == range.toLowerCase()) { roll = sides; } } ret += roll; rollsSoFar.push( roll ); @@ -68,11 +77,13 @@ var parser = { pos : 0, len : 0, lookahead : '', range : '', parse : function ( source, range ) { this.source = source; this.pos = 0; this.len = source.length; this.range = range; this.numberStack = []; this.operatorStack = []; @@ -212,7 +223,13 @@ var parser = { //we remove the index-th item from the operatorStack and grab its // "value", which is the operator symbol (+, * etc) //when we have that value, we grab the corresponding operator object var operator = this.operatorStack.splice(index, 1)[0].value; var op = operators[ operator ]; //need to tell the dice operator to use the min or max values if ( 'd' == operator ) { couplet.push(this.range); } //arr.splice, as well as removing items, can also add items //so, we slice-n-dice at the two numbers, grab the result of executing @@ -250,7 +267,7 @@ var parser = { //returns an object: // total => result of all dice rolls and arithmetic operations // rolls => array of results of each individual dice roll return function ( source, range ) { return parser.parse( source, range ); }; }()); -
Titani revised this gist
Mar 17, 2012 . 1 changed file with 21 additions and 8 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -140,7 +140,6 @@ var parser = { function execute ( token, index ) { var last = this.operatorStack[ index + 1 ]; //last one is more important than we are if ( last && last.precedence > token.precedence ) { @@ -198,16 +197,30 @@ var parser = { }, operate : function ( index ) { //grab the two numbers we care about //since the source string looks like: 2 + 1 // and the index param is actually the index of the operator to use, // we grab the index-th number and the index-th+1 number //in the above example, index = 0, we grab numberStack[0] and // numberStack[1] var couplet = this.numberStack.slice( index, index + 2 ); //in addition to the numbers we operate on, there's also a dice-roll // operator, so we take it into consideration couplet.push( this.rolls ); //arr.splice removes items and returns the removed items as an array //we remove the index-th item from the operatorStack and grab its // "value", which is the operator symbol (+, * etc) //when we have that value, we grab the corresponding operator object var op = operators[ this.operatorStack.splice(index, 1)[0].value ]; //arr.splice, as well as removing items, can also add items //so, we slice-n-dice at the two numbers, grab the result of executing // the operator, and add that result where we finished slicing //for example: // [0, 1, 2].splice( 0, 2, 42 ) //will make the array look like // [42, 2] this.numberStack.splice( index, 2, op.exec.apply(null, couplet) ); }, @@ -240,4 +253,4 @@ var parser = { return function ( source ) { return parser.parse( source ); }; }()); -
Titani revised this gist
Mar 17, 2012 . 1 changed file with 161 additions and 95 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -1,158 +1,228 @@ //infix operator-precedence parser //also supports a d operator - a dice roll var parsePrecedence = (function () { //we don't care about whitespace. well, most whitespace var whitespace = { ' ' : true, '\t' : true }; //the operators we deal with var operators = { '+' : { precedence : 1, exec : function ( a, b ) { return a + b; } }, '-' : { precedence : 1, exec : function ( a, b ) { return a - b; } }, '*' : { precedence : 2, exec : function ( a, b ) { return a * b; } }, '/' : { precedence : 2, exec : function ( a, b ) { if ( b === 0 ) { throw new Error( 'Division by 0' ); } return a / b; } }, 'd' : { precedence : 3, exec : function ( rolls, sides, rollsSoFar ) { if ( rolls > 100 ) { throw new Error( 'Maximum roll count is 100' ); } var ret = 0, roll; while ( rolls-- ) { roll = Math.floor( Math.random() * sides ) + 1; ret += roll; rollsSoFar.push( roll ); } return ret; } } }; var parser = { //not exactly stacks, but meh numberStack : null, operatorStack : null, rolls : null, //the source string and some metadata source : null, pos : 0, len : 0, lookahead : '', parse : function ( source ) { this.source = source; this.pos = 0; this.len = source.length; this.numberStack = []; this.operatorStack = []; this.rolls = []; this.tokenize(); this.execute(); //garbage collection, important for gianormo strings this.source = source = null; return { //the remaining number on the "stack" is the result total : this.numberStack[ 0 ], //we execute right->left, so the rolls array will be "backwards" rolls : this.rolls.reverse() }; }, //take the source string, and break it down into tokens tokenize : function () { var token, last; for ( ; this.pos < this.len; this.pos++ ) { this.lookahead = this.source[ this.pos ]; if ( whitespace.hasOwnProperty(this.lookahead) ) { continue; } token = this.nextToken(); if ( token.type === 'number' ) { this.numberStack.push( token.value ); } else if ( token.type === 'operator' ) { last = this.operatorStack[ this.operatorStack.length - 1 ]; //check for things like 1d2d3, which aren't valid if ( last && token.value === 'd' && last.value === 'd' ) { var itOnTheGround = new Error( 'Unexpected unchainable operator d' ); itOnTheGround.column = this.pos; throw itOnTheGround; //I'M AN ADULT! } this.operatorStack.push( token ); } } }, execute : function () { var idx; while ( (idx = this.operatorStack.length) ) { //execute, BACKWARDS! OH THE INSANITY while ( 0 <=-- idx ) { execute.call( this, this.operatorStack[idx], idx ); } } function execute ( token, index ) { var last = this.operatorStack[ index + 1 ]; console.log( token, last, index ); //last one is more important than we are if ( last && last.precedence > token.precedence ) { //execute it this.operate( index + 1 ); } //we're about to finish and the last one isn't as all-mighty as we // thought else if ( !index ) { //execute za operator! this.operate( index ); } } }, //fetch le token! nextToken : function () { var ch = this.lookahead; var ret = { type : null, value : ch }, res; //have we overflowed, while looking for something else? if ( this.pos >= this.len ) { throw new Error( 'Unexpected end of input' ); } //is it a digit? else if ( ch >= 0 && ch < 10 ) { ret.type = 'number'; res = this.fetchNumber(); this.pos += res.length - 1; ret.value = res.value; } //is it an operator? else if ( operators.hasOwnProperty(ch) ) { ret.type = 'operator'; ret.precedence = operators[ ch ].precedence; } //Y U TROLLZ!?!? else { var chuckNorris = new Error( 'Invalid character ' + ch ); chuckNorris.column = this.pos; throw chuckNorris; } return ret; }, operate : function ( index ) { if ( typeof index === 'undefined' ) { index = this.operatorStack.length - 1; } var couplet = this.numberStack.slice( index, index + 2 ); console.log( couplet.slice(), index, this.numberStack.slice() ); couplet.push( this.rolls ); var op = operators[ this.operatorStack.splice(index, 1)[0].value ]; this.numberStack.splice( index, 2, op.exec.apply(null, couplet) ); }, fetchNumber : function () { var offset = 0, num = '', ch; //keep eating digits until we find a non-digit while ( (ch = this.source[this.pos+offset]) >= 0 && ch < 10 ) { num += ch; offset++; } if ( num.length === 0 ) { throw new Error( 'Incomplete operation: Expected number at ' + this.pos ); } @@ -162,16 +232,12 @@ return function ( source ) { }; } }; //returns an object: // total => result of all dice rolls and arithmetic operations // rolls => array of results of each individual dice roll return function ( source ) { return parser.parse( source ); }; }()); -
Titani revised this gist
Feb 10, 2012 . 1 changed file with 55 additions and 40 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -1,28 +1,40 @@ //infix operator-precedence parser //also supports a d operator - a dice roll var parse = (function () { //we don't care about whitespace. well, most whitespace var whitespace = { ' ' : true, '\t' : true }; //the operators we deal with and their precedence var operators = { '+' : 1, '-' : 1, '*' : 2, '/' : 2, 'd' : 3 }; var callbacks = { '+' : function ( a, b ) { return a + b; }, '-' : function ( a, b ) { return a - b; }, '*' : function ( a, b ) { return a * b; }, '/' : function ( a, b ) { return a / b; }, 'd' : function ( rolls, sides, rollsSoFar ) { if ( rolls > 100 || sides > 100 ) { throw new Error( 'Maximum roll and side count is 100' ); } var ret = 0, roll; while ( rolls-- ) { roll = Math.floor( Math.random() * sides ) + 1; @@ -43,6 +55,7 @@ return function ( source ) { operatorStack = [], rolls = []; //the tokenizer var token, last; for ( var pos = 0, len = source.length; pos < len; ++pos ) { //skip teh noobz whitespace @@ -61,26 +74,32 @@ return function ( source ) { //check for things like 1d2d3, which aren't valid if ( last && token.value === 'd' && last.value === 'd' ) { throw new Error( 'Unexpected unchainable operator d at ' + pos ); } operatorStack.push( token ); } } //the "executer" while ( operatorStack.length ) { operatorStack.forEach(function ( token, index ) { last = operatorStack[ index - 1 ]; //last one is more important than we are if ( last && last.precedence > token.precedence ) { //execute it operate( index - 1 ); } //we're about to finish and the last one isn't as all-mighty as we // thought else if ( index + 1 === operatorStack.length ) { //execute za operator! operate( index ); } }); } //the last number in the stack is the result @@ -127,36 +146,32 @@ return function ( source ) { //keep eating digits until we find a non-digit while ( (ch = source[pos+offset]) >= 0 && ch < 10 ) { num += ch; offset++; } if ( num.length === 0 ) { throw new Error( 'Incomplete operation: Expected number at ' + pos ); } return { value : Number( num ), length : offset }; } function operate ( index ) { if ( typeof index === 'undefined' ) { index = operatorStack.length - 1; } var couplet = numberStack.slice( index, index + 2 ); couplet.push( rolls ); var method = callbacks[ operatorStack.splice(index, 1)[0].value ]; numberStack.splice( index, 2, method.apply(null, couplet) ); } }; }()); -
Titani revised this gist
Feb 8, 2012 . 1 changed file with 9 additions and 17 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -8,11 +8,7 @@ var operators = { '-' : 1, 'd' : 2 }; //we don't care about whitespace. well, most whitespace var whitespace = { ' ' : true, @@ -47,17 +43,13 @@ return function ( source ) { operatorStack = [], rolls = []; var token, last; for ( var pos = 0, len = source.length; pos < len; ++pos ) { //skip teh noobz whitespace if ( whitespace.hasOwnProperty(source[pos]) ) { continue; } token = nextToken(); if ( token.type === 'number' ) { @@ -112,7 +104,7 @@ return function ( source ) { } //is it a digit? else if ( ch >= 0 && ch < 10 ) { ret.type = 'number'; res = getNumber(); @@ -131,10 +123,10 @@ return function ( source ) { } function getNumber () { var offset = 0, num = '', ch; //keep eating digits until we find a non-digit while ( (ch = source[pos+offset]) >= 0 && ch < 10 ) { num += source[ pos+offset ]; offset++; } -
Titani revised this gist
Feb 8, 2012 . 1 changed file with 21 additions and 5 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -26,19 +26,26 @@ var callbacks = { '-' : function ( a, b ) { return a - b; }, 'd' : function ( rolls, sides, rollsSoFar ) { var ret = 0, roll; while ( rolls-- ) { roll = Math.floor( Math.random() * sides ) + 1; ret += roll; rollsSoFar.push( roll ); } return ret; } }; //returns an object: // total => result of all dice rolls and arithmetic operations // rolls => array of results of each individual dice roll return function ( source ) { var numberStack = [], operatorStack = [], rolls = []; //remove ALL whitespace! //could be achieved by: @@ -60,6 +67,11 @@ return function ( source ) { else if ( token.type === 'operator' ) { last = operatorStack[ operatorStack.length - 1 ]; //check for things like 1d2d3, which aren't valid if ( last && token.value === 'd' && last.value === 'd' ) { throw new Error( 'Unexpected unchainable-operator d' ); } if ( //previous operator is more important than us (last && token.precedence < last.precedence) || @@ -80,7 +92,10 @@ return function ( source ) { } //the last number in the stack is the result return { total : numberStack[ 0 ], rolls : rolls }; //get the next token function nextToken () { @@ -132,6 +147,7 @@ return function ( source ) { function operate () { var couplet = popTwo(); couplet.push( rolls ); if ( couplet.indexOf(undefined) > -1 ) { throw new Error( 'Incomplete expression - expected number' ); -
Titani revised this gist
Feb 8, 2012 . 1 changed file with 7 additions and 9 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -50,6 +50,7 @@ return function ( source ) { var token, last; for ( var pos = 0, len = source.length; pos < len; ++pos ) { console.log( operatorStack.slice(), numberStack.slice() ); token = nextToken(); if ( token.type === 'number' ) { @@ -100,7 +101,7 @@ return function ( source ) { ret.type = 'number'; res = getNumber(); pos += res.length - 1; ret.value = res.value; } @@ -115,25 +116,22 @@ return function ( source ) { } function getNumber () { var offset = 0, num = ''; //keep eating digits until we find a non-digit while ( digits.hasOwnProperty(source[pos+offset]) ) { num += source[ pos+offset ]; offset++; } return { value : Number( num ), length : offset }; } function operate () { var couplet = popTwo(); if ( couplet.indexOf(undefined) > -1 ) { throw new Error( 'Incomplete expression - expected number' ); -
Titani revised this gist
Feb 7, 2012 . 1 changed file with 1 addition and 3 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -78,7 +78,6 @@ return function ( source ) { operate(); } //the last number in the stack is the result return numberStack[ 0 ]; @@ -111,7 +110,6 @@ return function ( source ) { ret.precedence = operators[ ch ]; } return ret; } @@ -142,7 +140,7 @@ return function ( source ) { } numberStack.push( callbacks[ operatorStack.pop().value ].apply( null, couplet ) ); } -
Titani created this gist
Feb 7, 2012 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,158 @@ //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(); } console.log( numberStack ); //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 ]; } console.log( ) 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( callback[ 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(); } }; }());