Skip to content

Instantly share code, notes, and snippets.

@windwp
Last active January 7, 2016 14:57
Show Gist options
  • Save windwp/92d26ee17d5f87b0ee01 to your computer and use it in GitHub Desktop.
Save windwp/92d26ee17d5f87b0ee01 to your computer and use it in GitHub Desktop.
mat
/* description: Parses end executes mathematical expressions. */
/* lexical grammar */
%lex
%%
\s+ /* skip whitespace */
[0-9]+("."[0-9]+)?\b return 'NUMBER'
"*" return '*'
"/" return '/'
"-" return '-'
"+" return '+'
"^" return '^'
"!" return '!'
"%" return '%'
"(" return '('
")" return ')'
"sqrt" return 'sqrt'
"PI" return 'PI'
"E" return 'E'
<<EOF>> return 'EOF'
. return 'INVALID'
/lex
/* operator associations and precedence */
%left '+' '-'
%left '*' '/'
%left '^'
%left 'sqrt'
%right '!'
%right '%'
%left UMINUS
%start expressions
%% /* language grammar */
expressions
: e EOF
{ typeof console !== 'undefined' ? console.log($1) : print($1);
return $1; }
;
e
: e '+' e
{$$ = $1+$3;}
| e '-' e
{$$ = $1-$3;}
| e '*' e
{$$ = $1*$3;}
| e '/' e
{$$ = $1/$3;}
| e '^' e
{$$ = Math.pow($1, $3);}
| 'sqrt' e
{$$ = Math.sqrt($2);}
| e '!'
{{
$$ = (function fact (n) { return n==0 ? 1 : fact(n-1) * n })($1);
}}
| e '%'
{$$ = $1/100;}
| '-' e %prec UMINUS
{$$ = -$2;}
| '(' e ')'
{$$ = $2;}
| NUMBER
{$$ = Number(yytext);}
| E
{$$ = Math.E;}
| PI
{$$ = Math.PI;}
;
// // khi client co' su. thay doi? thi` thuong` la` co' 2 doi' tuong thay doi cung luc'
// // dung` time out de cha.n su. thay doi? cua? doi' tuong. dau` tien doi. khi co' 2 su. thay doi?
// // thi` moi' tinh' toan' lai.
// if (that.isExcute) {
// if (that.timeOutFunc === undefined) {
// console.log("time out call");
// that.timeOutFunc = setTimeout(() => {
// that.startReCalculate();
// that.timeOutFunc = undefined;
// }, 500);
// }else{
// console.log("have time out call");
// }
// }else{
//}
function main(arg){
var exp=getParseString(arg.input[0],arg.input.slice(1, arg.input.length));
var parser=new Parser();
arg.output[0]=parser.parse(exp);
arg.outputText= exp+" = "+arg.output[0];
return true;
}
function getParseString(exp,arg){
return exp.replace(/\{\{(\d+)\}\}/gi,function(match,p1){
p1=parseInt(p1)-1;
return (p1<arg.length)?arg[p1]:'Error';
});
};
function Parser(){this.yy={}}var parser={trace:function(){},yy:{},symbols_:{error:2,expressions:3,e:4,EOF:5,"+":6,"-":7,"*":8,"/":9,"^":10,"(":11,")":12,NUMBER:13,E:14,PI:15,$accept:0,$end:1},terminals_:{2:"error",5:"EOF",6:"+",7:"-",8:"*",9:"/",10:"^",11:"(",12:")",13:"NUMBER",14:"E",15:"PI"},productions_:[0,[3,2],[4,3],[4,3],[4,3],[4,3],[4,3],[4,2],[4,3],[4,1],[4,1],[4,1]],performAction:function(t,e,i,s,n,r,h){var l=r.length-1;switch(n){case 1:return r[l-1];case 2:this.$=r[l-2]+r[l];break;case 3:this.$=r[l-2]-r[l];break;case 4:this.$=r[l-2]*r[l];break;case 5:this.$=r[l-2]/r[l];break;case 6:this.$=Math.pow(r[l-2],r[l]);break;case 7:this.$=-r[l];break;case 8:this.$=r[l-1];break;case 9:this.$=Number(t);break;case 10:this.$=Math.E;break;case 11:this.$=Math.PI}},table:[{3:1,4:2,7:[1,3],11:[1,4],13:[1,5],14:[1,6],15:[1,7]},{1:[3]},{5:[1,8],6:[1,9],7:[1,10],8:[1,11],9:[1,12],10:[1,13]},{4:14,7:[1,3],11:[1,4],13:[1,5],14:[1,6],15:[1,7]},{4:15,7:[1,3],11:[1,4],13:[1,5],14:[1,6],15:[1,7]},{5:[2,9],6:[2,9],7:[2,9],8:[2,9],9:[2,9],10:[2,9],12:[2,9]},{5:[2,10],6:[2,10],7:[2,10],8:[2,10],9:[2,10],10:[2,10],12:[2,10]},{5:[2,11],6:[2,11],7:[2,11],8:[2,11],9:[2,11],10:[2,11],12:[2,11]},{1:[2,1]},{4:16,7:[1,3],11:[1,4],13:[1,5],14:[1,6],15:[1,7]},{4:17,7:[1,3],11:[1,4],13:[1,5],14:[1,6],15:[1,7]},{4:18,7:[1,3],11:[1,4],13:[1,5],14:[1,6],15:[1,7]},{4:19,7:[1,3],11:[1,4],13:[1,5],14:[1,6],15:[1,7]},{4:20,7:[1,3],11:[1,4],13:[1,5],14:[1,6],15:[1,7]},{5:[2,7],6:[2,7],7:[2,7],8:[2,7],9:[2,7],10:[2,7],12:[2,7]},{6:[1,9],7:[1,10],8:[1,11],9:[1,12],10:[1,13],12:[1,21]},{5:[2,2],6:[2,2],7:[2,2],8:[1,11],9:[1,12],10:[1,13],12:[2,2]},{5:[2,3],6:[2,3],7:[2,3],8:[1,11],9:[1,12],10:[1,13],12:[2,3]},{5:[2,4],6:[2,4],7:[2,4],8:[2,4],9:[2,4],10:[1,13],12:[2,4]},{5:[2,5],6:[2,5],7:[2,5],8:[2,5],9:[2,5],10:[1,13],12:[2,5]},{5:[2,6],6:[2,6],7:[2,6],8:[2,6],9:[2,6],10:[2,6],12:[2,6]},{5:[2,8],6:[2,8],7:[2,8],8:[2,8],9:[2,8],10:[2,8],12:[2,8]}],defaultActions:{8:[2,1]},parseError:function(t,e){if(!e.recoverable)throw new Error(t);this.trace(t)},parse:function(t){function e(){var t;return t=i.lexer.lex()||u,"number"!=typeof t&&(t=i.symbols_[t]||t),t}var i=this,s=[0],n=[null],r=[],h=this.table,l="",o=0,c=0,a=0,y=2,u=1,p=r.slice.call(arguments,1);this.lexer.setInput(t),this.lexer.yy=this.yy,this.yy.lexer=this.lexer,this.yy.parser=this,"undefined"==typeof this.lexer.yylloc&&(this.lexer.yylloc={});var f=this.lexer.yylloc;r.push(f);var g=this.lexer.options&&this.lexer.options.ranges;"function"==typeof this.yy.parseError?this.parseError=this.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var _,m,x,d,k,b,E,v,I,S={};;){if(x=s[s.length-1],this.defaultActions[x]?d=this.defaultActions[x]:((null===_||"undefined"==typeof _)&&(_=e()),d=h[x]&&h[x][_]),"undefined"==typeof d||!d.length||!d[0]){var $="";I=[];for(b in h[x])this.terminals_[b]&&b>y&&I.push("'"+this.terminals_[b]+"'");$=this.lexer.showPosition?"Parse error on line "+(o+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+I.join(", ")+", got '"+(this.terminals_[_]||_)+"'":"Parse error on line "+(o+1)+": Unexpected "+(_==u?"end of input":"'"+(this.terminals_[_]||_)+"'"),this.parseError($,{text:this.lexer.match,token:this.terminals_[_]||_,line:this.lexer.yylineno,loc:f,expected:I})}if(d[0]instanceof Array&&d.length>1)throw new Error("Parse Error: multiple actions possible at state: "+x+", token: "+_);switch(d[0]){case 1:s.push(_),n.push(this.lexer.yytext),r.push(this.lexer.yylloc),s.push(d[1]),_=null,m?(_=m,m=null):(c=this.lexer.yyleng,l=this.lexer.yytext,o=this.lexer.yylineno,f=this.lexer.yylloc,a>0&&a--);break;case 2:if(E=this.productions_[d[1]][1],S.$=n[n.length-E],S._$={first_line:r[r.length-(E||1)].first_line,last_line:r[r.length-1].last_line,first_column:r[r.length-(E||1)].first_column,last_column:r[r.length-1].last_column},g&&(S._$.range=[r[r.length-(E||1)].range[0],r[r.length-1].range[1]]),k=this.performAction.apply(S,[l,c,o,this.yy,d[1],n,r].concat(p)),"undefined"!=typeof k)return k;E&&(s=s.slice(0,-1*E*2),n=n.slice(0,-1*E),r=r.slice(0,-1*E)),s.push(this.productions_[d[1]][0]),n.push(S.$),r.push(S._$),v=h[s[s.length-2]][s[s.length-1]],s.push(v);break;case 3:return!0}}return!0}},lexer=function(){var t={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t){return this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t;var e=t.match(/(?:\r\n?|\n).*/g);return e?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,i=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e-1),this.offset-=e;var s=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),i.length-1&&(this.yylineno-=i.length-1);var n=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:i?(i.length===s.length?this.yylloc.first_column:0)+s[s.length-i.length].length-i[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[n[0],n[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var i,s,n;if(this.options.backtrack_lexer&&(n={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(n.yylloc.range=this.yylloc.range.slice(0))),s=t[0].match(/(?:\r\n?|\n).*/g),s&&(this.yylineno+=s.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:s?s[s.length-1].length-s[s.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],i=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),i)return i;if(this._backtrack){for(var r in n)this[r]=n[r];return!1}return!1},next:function(){if(this.done)return this.EOF;this._input||(this.done=!0);var t,e,i,s;this._more||(this.yytext="",this.match="");for(var n=this._currentRules(),r=0;r<n.length;r++)if(i=this._input.match(this.rules[n[r]]),i&&(!e||i[0].length>e[0].length)){if(e=i,s=r,this.options.backtrack_lexer){if(t=this.test_match(i,n[r]),t!==!1)return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?(t=this.test_match(e,n[s]),t!==!1?t:!1):""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var t=this.next();return t?t:this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){var t=this.conditionStack.length-1;return t>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return t=this.conditionStack.length-1-Math.abs(t||0),t>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{},performAction:function(t,e,i,s){switch(i){case 0:break;case 1:return 13;case 2:return 8;case 3:return 9;case 4:return 7;case 5:return 6;case 6:return 10;case 7:return 11;case 8:return 12;case 9:return 15;case 10:return 14;case 11:return 5;case 12:return"INVALID"}},rules:[/^(?:\s+)/,/^(?:[0-9]+(\.[0-9]+)?\b)/,/^(?:\*)/,/^(?:\/)/,/^(?:-)/,/^(?:\+)/,/^(?:\^)/,/^(?:\()/,/^(?:\))/,/^(?:PI\b)/,/^(?:E\b)/,/^(?:$)/,/^(?:.)/],conditions:{INITIAL:{rules:[0,1,2,3,4,5,6,7,8,9,10,11,12],inclusive:!0}}};return t}();parser.lexer=lexer,Parser.prototype=parser,parser.Parser=Parser;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment