Przeglądaj źródła

Bills Calculate: billsPrice Mode

MaiXinRong 7 lat temu
rodzic
commit
e0bc11ce13

+ 337 - 0
lib/JSExpressionEval_src/Date.js

@@ -0,0 +1,337 @@
+// ===================================================================
+// Author: Matt Kruse <matt@mattkruse.com>
+// WWW: http://www.mattkruse.com/
+//
+// NOTICE: You may use this code for any purpose, commercial or
+// private, without any further permission from the author. You may
+// remove this notice from your final code if you wish, however it is
+// appreciated by the author if at least my web site address is kept.
+//
+// You may *NOT* re-distribute this code in any way except through its
+// use. That means, you can include it in your product, or your web
+// site, or any other form where the code is actually being used. You
+// may not put the plain javascript up on your site for download or
+// include it in your javascript libraries for download. 
+// If you wish to share this code with others, please just point them
+// to the URL instead.
+// Please DO NOT link directly to my .js files from your site. Copy
+// the files to your server and use them there. Thank you.
+// ===================================================================
+
+// HISTORY
+// ------------------------------------------------------------------
+// May 17, 2003: Fixed bug in parseDate() for dates <1970
+// March 11, 2003: Added parseDate() function
+// March 11, 2003: Added "NNN" formatting option. Doesn't match up
+//                 perfectly with SimpleDateFormat formats, but 
+//                 backwards-compatability was required.
+
+// ------------------------------------------------------------------
+// These functions use the same 'format' strings as the 
+// java.text.SimpleDateFormat class, with minor exceptions.
+// The format string consists of the following abbreviations:
+// 
+// Field        | Full Form          | Short Form
+// -------------+--------------------+-----------------------
+// Year         | yyyy (4 digits)    | yy (2 digits), y (2 or 4 digits)
+// Month        | MMM (name or abbr.)| MM (2 digits), M (1 or 2 digits)
+//              | NNN (abbr.)        |
+// Day of Month | dd (2 digits)      | d (1 or 2 digits)
+// Day of Week  | EE (name)          | E (abbr)
+// Hour (1-12)  | hh (2 digits)      | h (1 or 2 digits)
+// Hour (0-23)  | HH (2 digits)      | H (1 or 2 digits)
+// Hour (0-11)  | KK (2 digits)      | K (1 or 2 digits)
+// Hour (1-24)  | kk (2 digits)      | k (1 or 2 digits)
+// Minute       | mm (2 digits)      | m (1 or 2 digits)
+// Second       | ss (2 digits)      | s (1 or 2 digits)
+// AM/PM        | a                  |
+//
+// NOTE THE DIFFERENCE BETWEEN MM and mm! Month=MM, not mm!
+// Examples:
+//  "MMM d, y" matches: January 01, 2000
+//                      Dec 1, 1900
+//                      Nov 20, 00
+//  "M/d/yy"   matches: 01/20/00
+//                      9/2/00
+//  "MMM dd, yyyy hh:mm:ssa" matches: "January 01, 2000 12:30:45AM"
+// ------------------------------------------------------------------
+
+var MONTH_NAMES=new Array('January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
+var DAY_NAMES=new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat');
+function LZ(x) {return(x<0||x>9?"":"0")+x}
+
+// ------------------------------------------------------------------
+// isDate ( date_string, format_string )
+// Returns true if date string matches format of format string and
+// is a valid date. Else returns false.
+// It is recommended that you trim whitespace around the value before
+// passing it to this function, as whitespace is NOT ignored!
+// ------------------------------------------------------------------
+function isDate(val,format) {
+	var date=getDateFromFormat(val,format);
+	if (date==0) { return false; }
+	return true;
+	}
+
+// -------------------------------------------------------------------
+// compareDates(date1,date1format,date2,date2format)
+//   Compare two date strings to see which is greater.
+//   Returns:
+//   1 if date1 is greater than date2
+//   0 if date2 is greater than date1 of if they are the same
+//  -1 if either of the dates is in an invalid format
+// -------------------------------------------------------------------
+function compareDates(date1,dateformat1,date2,dateformat2) {
+	var d1=getDateFromFormat(date1,dateformat1);
+	var d2=getDateFromFormat(date2,dateformat2);
+	if (d1==0 || d2==0) {
+		return -1;
+		}
+	else if (d1 > d2) {
+		return 1;
+		}
+	return 0;
+	}
+
+// ------------------------------------------------------------------
+// formatDate (date_object, format)
+// Returns a date in the output format specified.
+// The format string uses the same abbreviations as in getDateFromFormat()
+// ------------------------------------------------------------------
+function formatDate(date,format) {
+	format=format+"";
+	var result="";
+	var i_format=0;
+	var c="";
+	var token="";
+	var y=date.getYear()+"";
+	var M=date.getMonth()+1;
+	var d=date.getDate();
+	var E=date.getDay();
+	var H=date.getHours();
+	var m=date.getMinutes();
+	var s=date.getSeconds();
+	var yyyy,yy,MMM,MM,dd,hh,h,mm,ss,ampm,HH,H,KK,K,kk,k;
+	// Convert real date parts into formatted versions
+	var value=new Object();
+	if (y.length < 4) {y=""+(y-0+1900);}
+	value["y"]=""+y;
+	value["yyyy"]=y;
+	value["yy"]=y.substring(2,4);
+	value["M"]=M;
+	value["MM"]=LZ(M);
+	value["MMM"]=MONTH_NAMES[M-1];
+	value["NNN"]=MONTH_NAMES[M+11];
+	value["d"]=d;
+	value["dd"]=LZ(d);
+	value["E"]=DAY_NAMES[E+7];
+	value["EE"]=DAY_NAMES[E];
+	value["H"]=H;
+	value["HH"]=LZ(H);
+	if (H==0){value["h"]=12;}
+	else if (H>12){value["h"]=H-12;}
+	else {value["h"]=H;}
+	value["hh"]=LZ(value["h"]);
+	if (H>11){value["K"]=H-12;} else {value["K"]=H;}
+	value["k"]=H+1;
+	value["KK"]=LZ(value["K"]);
+	value["kk"]=LZ(value["k"]);
+	if (H > 11) { value["a"]="PM"; }
+	else { value["a"]="AM"; }
+	value["m"]=m;
+	value["mm"]=LZ(m);
+	value["s"]=s;
+	value["ss"]=LZ(s);
+	while (i_format < format.length) {
+		c=format.charAt(i_format);
+		token="";
+		while ((format.charAt(i_format)==c) && (i_format < format.length)) {
+			token += format.charAt(i_format++);
+			}
+		if (value[token] != null) { result=result + value[token]; }
+		else { result=result + token; }
+		}
+	return result;
+	}
+	
+// ------------------------------------------------------------------
+// Utility functions for parsing in getDateFromFormat()
+// ------------------------------------------------------------------
+function _isInteger(val) {
+	var digits="1234567890";
+	for (var i=0; i < val.length; i++) {
+		if (digits.indexOf(val.charAt(i))==-1) { return false; }
+		}
+	return true;
+	}
+function _getInt(str,i,minlength,maxlength) {
+	for (var x=maxlength; x>=minlength; x--) {
+		var token=str.substring(i,i+x);
+		if (token.length < minlength) { return null; }
+		if (_isInteger(token)) { return token; }
+		}
+	return null;
+	}
+	
+// ------------------------------------------------------------------
+// getDateFromFormat( date_string , format_string )
+//
+// This function takes a date string and a format string. It matches
+// If the date string matches the format string, it returns the 
+// getTime() of the date. If it does not match, it returns 0.
+// ------------------------------------------------------------------
+function getDateFromFormat(val,format) {
+	val=val+"";
+	format=format+"";
+	var i_val=0;
+	var i_format=0;
+	var c="";
+	var token="";
+	var token2="";
+	var x,y;
+	var now=new Date();
+	var year=now.getYear();
+	var month=now.getMonth()+1;
+	var date=1;
+	var hh=now.getHours();
+	var mm=now.getMinutes();
+	var ss=now.getSeconds();
+	var ampm="";
+	
+	while (i_format < format.length) {
+		// Get next token from format string
+		c=format.charAt(i_format);
+		token="";
+		while ((format.charAt(i_format)==c) && (i_format < format.length)) {
+			token += format.charAt(i_format++);
+			}
+
+		// Extract contents of value based on format token
+		if (token=="yyyy" || token=="yy" || token=="y") {
+			if (token=="yyyy") { x=4;y=4; }
+			if (token=="yy")   { x=2;y=2; }
+			if (token=="y")    { x=2;y=4; }
+			year=_getInt(val,i_val,x,y);
+
+			if (year==null) { return 0; }
+			i_val += year.length;
+			if (year.length==2) {
+				if (year > 70) { year=1900+(year-0); }
+				else { year=2000+(year-0); }
+				}
+			}
+		else if (token=="MMM"||token=="NNN"){
+			month=0;
+			for (var i=0; i<MONTH_NAMES.length; i++) {
+				var month_name=MONTH_NAMES[i];
+				if (val.substring(i_val,i_val+month_name.length).toLowerCase()==month_name.toLowerCase()) {
+					if (token=="MMM"||(token=="NNN"&&i>11)) {
+						month=i+1;
+						if (month>12) { month -= 12; }
+						i_val += month_name.length;
+						break;
+						}
+					}
+				}
+			if ((month < 1)||(month>12)){return 0;}
+			}
+		else if (token=="EE"||token=="E"){
+			for (var i=0; i<DAY_NAMES.length; i++) {
+				var day_name=DAY_NAMES[i];
+				if (val.substring(i_val,i_val+day_name.length).toLowerCase()==day_name.toLowerCase()) {
+					i_val += day_name.length;
+					break;
+					}
+				}
+			}
+		else if (token=="MM"||token=="M") {
+			month=_getInt(val,i_val,token.length,2);
+			if(month==null||(month<1)||(month>12)){return 0;}
+			i_val+=month.length;}
+		else if (token=="dd"||token=="d") {
+			date=_getInt(val,i_val,token.length,2);
+			if(date==null||(date<1)||(date>31)){return 0;}
+			i_val+=date.length;}
+		else if (token=="hh"||token=="h") {
+			hh=_getInt(val,i_val,token.length,2);
+			if(hh==null||(hh<1)||(hh>12)){return 0;}
+			i_val+=hh.length;}
+		else if (token=="HH"||token=="H") {
+			hh=_getInt(val,i_val,token.length,2);
+			if(hh==null||(hh<0)||(hh>23)){return 0;}
+			i_val+=hh.length;}
+		else if (token=="KK"||token=="K") {
+			hh=_getInt(val,i_val,token.length,2);
+			if(hh==null||(hh<0)||(hh>11)){return 0;}
+			i_val+=hh.length;}
+		else if (token=="kk"||token=="k") {
+			hh=_getInt(val,i_val,token.length,2);
+			if(hh==null||(hh<1)||(hh>24)){return 0;}
+			i_val+=hh.length;hh--;}
+		else if (token=="mm"||token=="m") {
+			mm=_getInt(val,i_val,token.length,2);
+			if(mm==null||(mm<0)||(mm>59)){return 0;}
+			i_val+=mm.length;}
+		else if (token=="ss"||token=="s") {
+			ss=_getInt(val,i_val,token.length,2);
+			if(ss==null||(ss<0)||(ss>59)){return 0;}
+			i_val+=ss.length;}
+		else if (token=="a") {
+			if (val.substring(i_val,i_val+2).toLowerCase()=="am") {ampm="AM";}
+			else if (val.substring(i_val,i_val+2).toLowerCase()=="pm") {ampm="PM";}
+			else {return 0;}
+			i_val+=2;}
+		else {
+			if (val.substring(i_val,i_val+token.length)!=token) {return 0;}
+			else {i_val+=token.length;}
+			}
+		}
+	// If there are any trailing characters left in the value, it doesn't match
+	if (i_val != val.length) { return 0; }
+	// Is date valid for month?
+	if (month==2) {
+		// Check for leap year
+		if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
+			if (date > 29){ return 0; }
+			}
+		else { if (date > 28) { return 0; } }
+		}
+	if ((month==4)||(month==6)||(month==9)||(month==11)) {
+		if (date > 30) { return 0; }
+		}
+	// Correct hours value
+	if (hh<12 && ampm=="PM") { hh=hh-0+12; }
+	else if (hh>11 && ampm=="AM") { hh-=12; }
+	var newdate=new Date(year,month-1,date,hh,mm,ss);
+	return newdate.getTime();
+	}
+
+// ------------------------------------------------------------------
+// parseDate( date_string [, prefer_euro_format] )
+//
+// This function takes a date string and tries to match it to a
+// number of possible date formats to get the value. It will try to
+// match against the following international formats, in this order:
+// y-M-d   MMM d, y   MMM d,y   y-MMM-d   d-MMM-y  MMM d
+// M/d/y   M-d-y      M.d.y     MMM-d     M/d      M-d
+// d/M/y   d-M-y      d.M.y     d-MMM     d/M      d-M
+// A second argument may be passed to instruct the method to search
+// for formats like d/M/y (european format) before M/d/y (American).
+// Returns a Date object or null if no patterns match.
+// ------------------------------------------------------------------
+function parseDate(val) {
+	var preferEuro=(arguments.length==2)?arguments[1]:false;
+	generalFormats=new Array('y-M-d','MMM d, y','MMM d,y','y-MMM-d','d-MMM-y','MMM d');
+	monthFirst=new Array('M/d/y','M-d-y','M.d.y','MMM-d','M/d','M-d');
+	dateFirst =new Array('d/M/y','d-M-y','d.M.y','d-MMM','d/M','d-M');
+	var checkList=new Array('generalFormats',preferEuro?'dateFirst':'monthFirst',preferEuro?'monthFirst':'dateFirst');
+	var d=null;
+	for (var i=0; i<checkList.length; i++) {
+		var l=window[checkList[i]];
+		for (var j=0; j<l.length; j++) {
+			d=getDateFromFormat(val,l[j]);
+			if (d!=0) { return new Date(d); }
+			}
+		}
+	return null;
+	}

Plik diff jest za duży
+ 1050 - 0
lib/JSExpressionEval_src/Evaluator.js


+ 129 - 0
lib/JSExpressionEval_src/ExpressionTester.htm

@@ -0,0 +1,129 @@
+   <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=windows-1250">
+<meta name="generator" content="PSPad editor, www.pspad.com">
+<title>Expression Converter</title>
+<style>
+body     {font-family: Verdana,Tahoma; font-size: 8px; font-weight: normal;}
+input    {font-family: Verdana,Tahoma; font-size: 8px; font-weight: normal;}
+textarea {font-family: Verdana,Tahoma; font-size: 8px; font-weight: normal;}
+button   {font-family: Verdana,Tahoma; font-size: 9px; font-weight: normal; height: 24px;}
+table, td {font-family: Verdana,Tahoma; font-size: 8px; font-weight: normal;}
+
+</style>
+<script src="Date.js" type="text/javascript"></script>
+<script src="Stack.js" type="text/javascript"></script>
+<script src="Tokanizer.js" type="text/javascript"></script>
+<script src="Evaluator.js" type="text/javascript"></script>
+<script language="vbscript">
+'5*log(1000)*-2/3+MAX(4,6 MOD 7) 
+'5*log(1000)*-2/3+6 
+'5*6.90775527898214*-2/3+6 
+'34.5387763949107*-2/3+6 
+'-69.0775527898214/3+6 
+'-23.0258509299405+6 
+'-17.0258509299405
+'-17.025850929940457
+'InputBox "6 Mod 7", "Result", (6 Mod 7)
+</script>
+<script language="javascript">
+//alert (6 % 7);
+
+var exp = new Expression("");
+
+function Convert()
+{
+    var frm = document.frmMain;
+    var arrToks;
+    var arrPFix;
+    var strExp;
+    var intCntr;
+
+    strExp = frm.txtExp.value;
+    if (strExp == null || strExp == undefined)
+    {
+        alert ("No expression is specified!");
+        return false;
+    }
+
+    exp.Expression(strExp);
+    frm.txtResult.value = exp.Parse();
+    return false;
+}
+
+function Compute()
+{
+    var frm;
+    var strExp;
+
+    frm = document.frmMain;
+    strExp = frm.txtExp.value;
+    exp.Expression(strExp);
+    frm.txtResult.value = exp.Evaluate();
+}
+
+function AddVar()
+{
+    var frm;
+
+    frm = document.frmMain;
+    exp.AddVariable(frm.txtVarName.value, frm.txtVarValue.value);
+    return true;
+}
+
+function Reset()
+{
+	exp.Reset();
+}
+</script>
+</head>
+<body>
+<form id="frmMain" name="frmMain">
+	<table>
+    	<tr>
+        	<td>
+        		<table>
+            		<tr>
+                		<td>Expression : </td>
+                		<td><input type="text" size="50" name="txtExp" id="txtExp" /></td>
+            		</tr>
+            		<tr>
+                		<td>&nbsp;</td>
+                		<td><textarea cols="58" rows="5" name="txtResult" id="txtResult"></textarea></td>
+            		</tr>
+            		<tr>
+                		<td colspan="2" align="right">
+                    		<a href="#" name="btnConvert" id="btnConvert" onClick="javascript:Convert();">PostFix</a>
+                    		&nbsp;
+                    		<a href="#" name="btnCompute" id="btnCompute" onClick="javascript:Compute();">Evaluate</a>
+                    		&nbsp;
+                    		<a href="#" name="btnReset" id="btnReset" onClick="javascript:Reset();">Reset</a>
+                		</td>
+            		</tr>
+        		</table>
+			</td>
+		</tr>
+		<tr>
+			<td>
+        		<table>
+            		<tr>
+                		<td>Variable Name : </td>
+                		<td><input type="text" size="50" name="txtVarName" id="txtVarName" /></td>
+            		</tr>
+            		<tr>
+                		<td>Variable Value : </td>
+                		<td><input type="text" size="50" name="txtVarValue" id="txtVarVal" /></td>
+            		</tr>
+            		<tr>
+                		<td colspan="2" align="right">
+                    		<a href="#" name="btnAdd" id="btnAdd" onClick="AddVar();">Add Variable</a>
+                		</td>
+            		</tr>
+        		</table>
+			</td>
+		</tr>
+	</table>
+</form>
+</body>
+</html>

+ 141 - 0
lib/JSExpressionEval_src/JsHashMap.js

@@ -0,0 +1,141 @@
+/////////////////////////////////////////////
+/////       Js Object                 //////
+///////////////////////////////////////////
+// Author: NHM TAnveer Hossain Khan (Hasan)
+// http://hasan.we4tech.com
+// mail:admin at we4tech.com
+
+// hashmap internal data object
+JsObject=function(key, value) {
+  this._key=key;
+  this._value=value;
+}
+
+// set some methods for JsObject
+JsObject.prototype.getKey=function() {
+  return this._key;
+}
+
+// get value
+JsObject.prototype.getValue=function() {
+  return this._value;
+}
+
+
+/////////////////////////////////////////////
+////        Iterator                 ///////
+///////////////////////////////////////////
+JsIterator=function(array) {
+  // set internal array
+  this._array=array;
+
+  // create inernal index counter
+  this._counter=0;
+  
+  // set _hasNext value
+  if(array.length>0)
+    this._hasNext=true;
+  else
+    this._hasNext=false;
+}
+
+// return boolean value
+JsIterator.prototype.hasNext=function() {
+  return this._hasNext;
+}
+
+// return object in next method
+JsIterator.prototype.next=function() {
+    if(this._array.length>this._counter)
+    {
+        // get object
+        var rtnObj=this._array[this._counter];
+        // increment counter value;
+        this._counter++;
+        // check is has next true of flase
+        if(this._array.length>this._counter)
+            this._hasNext=true;
+        else
+            this._hasNext=false;
+
+        // return data
+        return rtnObj;
+    }
+    else
+    {
+        this._hasNext=false;
+    }
+}
+
+// remove object
+JsIterator.prototype.remove=function() {
+    this._array.splice(this._counter,1);
+    if(this._array.length > this._counter)
+        this._hasNext=false;
+}
+
+
+/////////////////////////////////////////////
+////        HashMap Object           ///////
+///////////////////////////////////////////
+
+// create JsHashMap class object
+JsHashMap=function() {
+    // init. internal array
+    this._array=new Array();
+    // set internal counter value as 0
+    // this counter will keep track the current index
+    // of array
+    this._counter=0;
+}
+
+// create add method
+// put key and value
+JsHashMap.prototype.put=function(key, value) {
+    // add new value
+    var newJsObj=new JsObject(key, value);
+    // add in internal array
+    this._array[this._counter]=newJsObj;
+    // increment the internal index counter
+    this._counter++;
+}
+
+// retrive data based on iterator
+JsHashMap.prototype.iterator=function() {
+    // create iterator
+    var it=new JsIterator(this._array);
+    // return iterator
+    return it;
+}
+
+// retrive data based on keyword
+JsHashMap.prototype.get=function(key) {
+    // create iterator object
+    var it=this.iterator();
+  
+    // iterate untile get success
+    while(it.hasNext())
+    {
+        // fetch object
+        var getObj=it.next();
+        // check is found or not
+        if(getObj.getKey()==key)
+            return getObj.getValue();
+    }
+}
+
+// remove key and object
+JsHashMap.prototype.remove=function(key) {
+    // create iterator object
+    var it=this.iterator();
+  
+    // iterate untile get success
+    while(it.hasNext())
+    {
+        // fetch object
+        var getObj=it.next();
+        // check is found or not
+        if(getObj.getKey()==key)
+            it.remove();
+    }
+}

+ 133 - 0
lib/JSExpressionEval_src/License.txt

@@ -0,0 +1,133 @@
+KIS Public License 1.0
+Terms & Conditions Of Use
+February, 2005
+Copyright (c) 2005. Khan Information Systems. All Rights Reserved
+
+
+PLEASE READ THIS DOCUMENT CAREFULLY. BY DOWNLOADING OR USING THE CODE BASE AND
+DOCUMENTATION ACCOMPANYING THIS LICENSE (THE "License"), YOU AGREE TO THE
+FOLLOWING TERMS AND CONDITIONS OF THIS LICENSE.
+
+Section One: Your Rights
+Subject to these terms and conditions of this License, Khan Information
+Systems (KIS) (the "Original Contributor") and each subsequent contributor
+(collectively with the Original Contributor, the "Contributors") hereby grants
+you a non-exclusive, worldwide, no-charge, transferable, copyright license to
+execute, prepare derivative works of, and distribute (internally and externally),
+for commercial and noncommercial purposes, the original code contributed by
+Original Contributor and all Modifications (collectively called the "Program").
+
+This non-exclusive license (with respect to the grant from a particular
+Contributor) automatically terminates for any entity that initiates legal action
+for intellectual property infringement against such Contributor as of the
+initiation of such action.
+
+Section Two: Your License Grant
+If you make a Modification and distribute it externally you are a Contributor,
+and you must provide such Modification in source code form to the Original
+Contributor within thirty (30) days of such distribution under the terms of the
+license in Section 1 above in accordance with the instructions below.
+A "Modification" to the Program is any addition to or deletion from the contents
+of any file of the Program or of any Modifications and any new file that contains
+any part of the Program or of any Modifications.
+
+As a Contributor you represent that your contributions are your original
+creation(s) and, to the best of your knowledge, no third party has any claim
+(including but not limited to intellectual property claims) relating to your
+Modification. You represent that your contribution submission includes complete
+details of any license or other restriction associated with any part of your
+Modification (including a copy of any applicable license agreement).
+
+If, after submitting your contribution, you learn of a third party claim or other
+restriction relating to your contribution, you shall promptly modify your
+contribution submission and take all reasonable steps to inform those who may
+have received the Program containing such Modification.
+
+Section Three: Redistribution
+If you distribute the Program or any derivative work of the Program in a form to
+which the recipient can make Modifications, you must ensure that the recipient
+of the Program or derivative work of the Program accepts the terms of this
+License with respect to the Program and any Modifications included your
+distribution. In addition, in each source and data file of the Program and any
+Modification you distribute must contain the following:
+
+	"The contents of this file, as updated from time to time by Khan Information
+	Systems (KIS), are subject to the KIS Public License Version 1.0
+	(the "License"); you may not use this file except in compliance with the
+	License.
+
+	Software distributed under the License is distributed on an "AS IS" basis,
+	WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
+	the specific language governing rights and limitations under the License.
+
+	This software consists of voluntary contributions made by many individuals
+	on behalf of the Khan Information Systems.
+
+	The Original Code is ______________________________________________________.
+	The Initial Developer of the Original Code is _____________________________.
+	Portions created by _______________________________________________________
+	are Copyright (C) ______ _______________________. All Rights Reserved.
+	Contributor(s): __________________________________________________________."
+
+If you redistribute the Program or any derivative work of the Program in a form
+to which the recipient can not make Modifications, you must include the
+following in appropriate and conspicuous locations:
+
+	"Includes software, which is Copyright (c) 2005 - (insert then current year)
+	Khan Information Systems (KIS) and others. All rights reserved."
+
+Any redistribution must be made without any further restriction on the
+recipient's exercise of the rights granted herein.
+
+Section Four: Termination
+If you fail to comply with this License, your rights (but not your obligations)
+under this License shall terminate automatically unless you cure such breach
+within thirty days of becoming aware of the noncompliance. All sublicenses
+granted by you which preexist such termination and are properly granted shall
+survive such termination.
+
+Section Five: Other Terms
+Except for the copyright notices required above or as otherwise agreed in writing,
+you may not use any trademark of any of the Contributors.
+
+All transfers of the Program or any part thereof shall be made in compliance
+with U.S. Trade regulations or other restrictions of the U.S. Department of
+Commerce, as well as other similar trade or commerce restrictions which might
+apply.
+
+Any patent obtained by any party covering the Program or any part thereof must
+include a provision providing for the free, perpetual and unrestricted commercial
+and noncommercial use by any third party.
+
+If, as a consequence of a court judgment or allegation of patent infringement or
+for any other reason (not limited to patent issues), conditions are imposed on
+you (whether by court order, agreement or otherwise) that contradict the
+conditions of this License, they do not excuse you from the conditions of this
+License. If you cannot distribute so as to satisfy simultaneously your obligations
+under this License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent license would not
+permit royalty-free redistribution of the Program by all those who receive copies
+directly or indirectly through you, then the only way you could satisfy both it
+and this License would be to refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply and the
+section as a whole is intended to apply in other circumstances.
+
+YOU AGREE THAT THE PROGRAM IS PROVIDED AS-IS, WITHOUT WARRANTY OF ANY KIND
+(EITHER EXPRESS OR IMPLIED) INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTY 
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND ANY WARRANTY OF NON
+INFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE PROGRAM, EVEN IF ADVISED
+OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The Original Contributor from time to time may change this License, and the
+amended license will apply to all copies of the Program downloaded after the new
+license is posted. This License provides you no implied rights or licenses to the
+intellectual property of any Contributor.
+
+								Created 01/01/2005

+ 105 - 0
lib/JSExpressionEval_src/Stack.js

@@ -0,0 +1,105 @@
+/*------------------------------------------------------------------------------
+ * NAME    : Stack.js
+ * PURPOSE : Stack dta structure using java script
+ * AUTHOR  : Prasad P. Khandekar
+ * CREATED : August 21, 2005 
+ *------------------------------------------------------------------------------
+ * Copyright (c) 2005. Khan Information Systems. All Rights Reserved
+ * The contents of this file are subject to the KIS Public License 1.0
+ * (the "License"); you may not use this file except in compliance with the 
+ * License. You should have received a copy of the KIS Public License along with 
+ * this library; if not, please ask your software vendor to provide one.
+ * 
+ * YOU AGREE THAT THE PROGRAM IS PROVIDED AS-IS, WITHOUT WARRANTY OF ANY KIND
+ * (EITHER EXPRESS OR IMPLIED) INCLUDING, WITHOUT LIMITATION, ANY IMPLIED 
+ * WARRANTY OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND ANY 
+ * WARRANTY OF NON INFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE 
+ * PROGRAM, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * See the License for the specific language governing rights and limitations 
+ * under the License.
+ *-----------------------------------------------------------------------------*/
+// Stack object constructor
+function Stack()
+{
+    this.arrStack = new Array();
+    this.intIndex = 0;
+
+    this.Size     = getSize;
+    this.IsEmpty  = isStackEmpty;
+    this.Push     = pushElement;
+    this.Pop      = popElement;
+    this.Get      = getElement;
+    this.toString = dumpStack;
+}
+
+// Converts stack contents into a comma seperated string
+function dumpStack()
+{
+    var intCntr = 0;
+    var strRet  =  "";
+    if (this.intIndex == 0) return null;
+    for (intCntr = 0; intCntr < this.intIndex; intCntr++)
+    {
+        if (strRet.length == 0)
+            strRet += this.arrStack[intCntr];
+        else
+            strRet += "," + this.arrStack[intCntr];
+    }
+    return strRet;
+}
+
+// Returns size of stack
+function getSize()
+{
+    return this.intIndex;
+}
+
+// This method tells us if this Stack object is empty
+function isStackEmpty()
+{
+	if (this.intIndex == 0)
+		return true;
+	else
+		return false;
+}
+
+// This method pushes a new element onto the top of the stack
+function pushElement(newData)
+{
+	// Assign our new element to the top
+	debugAssert ("Pushing " + newData);
+	this.arrStack[this.intIndex] = newData;
+	this.intIndex++;
+}
+
+// This method pops the top element off of the stack
+function popElement()
+{
+    var retVal;
+
+    retVal = null;
+    if (this.intIndex > 0)
+    {
+	   // Assign our new element to the top
+	   this.intIndex--;
+	   retVal = this.arrStack[this.intIndex];
+	}
+	return retVal;
+}
+
+// Gets an element at a particular offset from top of the stack
+function getElement(intPos)
+{
+    var retVal;
+
+    //alert ("Size : " + this.intIndex + ", Index " + intPos);
+    if (intPos >= 0 && intPos < this.intIndex)
+        retVal = this.arrStack[this.intIndex - intPos - 1];
+    return retVal;
+}

+ 108 - 0
lib/JSExpressionEval_src/StackImpl.htm

@@ -0,0 +1,108 @@
+<HTML>
+<HEAD>
+<TITLE>Simple Stack Object Example</TITLE>
+<SCRIPT LANGUAGE="JavaScript">
+<!-
+// This is the constructor for our stack object
+// If the "length" instance variable is 0, the stack is empty
+function oStack() {
+	this.top = null;
+	this.length = 0;
+	this.isEmpty = oStackIsEmpty;
+	this.push = oStackPush;
+	this.pop = oStackPop;
+	}
+
+// This method tells us if this oStack object is empty
+function oStackIsEmpty() {
+	if (this.length == 0)
+		return true;
+	else
+		return false;
+	}
+
+// This method pushes a new element onto the top of the stack
+function oStackPush( newData) {
+	// Create the new element
+	var newElement = new oStackElement();
+	// Add the data to it
+	newElement.setData( newData);
+	// Put the current top in our next field
+	newElement.setNext( this.top);
+	// Assign our new element to the top
+	this.top = newElement;
+	this.length++;
+	}
+	
+// This method pops the top element off of the stack
+function oStackPop() {
+	// Put old top away for safe keeping
+	var oldTop = this.top;
+	// Get the new top
+	this.top = this.top.getNext();
+	this.length-;
+	return oldTop;
+	}
+
+// This is the constructor for an element in our stack object
+// The "data" variable holds our actual data (whatever it may be)
+// and the "next" variable holds the oStackElement object that is
+// 'underneath' this oStackElement object.
+function oStackElement() {
+	this.data = 0;
+	this.next = null;
+	this.setData = oStackElementSetData;
+	this.getData = oStackElementGetData;
+	this.setNext = oStackElementSetNext;
+	this.getNext = oStackElementGetNext;
+	}
+
+// This method sets the data field of this oStackElement
+function oStackElementSetData( newData) {
+	this.data = newData;
+	}
+
+// This method returns the data field of this oStackElement
+function oStackElementGetData() {
+	return this.data;
+	}
+
+// This method sets the next field of this oStackElement
+function oStackElementSetNext( newNext) {
+	this.next = newNext;
+	}
+
+// This method returns the next field of this oStackElement
+function oStackElementGetNext() {
+	return this.next;
+	}
+
+// create a new oStack object
+var stack1 = new oStack();
+
+// Fill it with something interesting
+// In this case, the names of my cats
+stack1.push( "Puddin' Head")
+stack1.push( "Sunshine")
+stack1.push( "Shadow")
+stack1.push( "Sassy")
+stack1.push( "Toby")
+stack1.push( "Sandy")
+stack1.push( "Pixie")
+stack1.push( "Edi")
+stack1.push( "Gizmo")
+
+// Get the number of items in the stack
+var numElements = stack1.length;
+
+// Print out the contents of the stack
+for (var i = 0; i < numElements; i++)
+	document.write( stack1.length + " - " + stack1.pop().getData() 
++ "<br>");
+//->
+</SCRIPT>
+</HEAD>
+<BODY>
+</BODY>
+</HTML>
+

+ 119 - 0
lib/JSExpressionEval_src/StackTester.htm

@@ -0,0 +1,119 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=windows-1250">
+<meta name="generator" content="PSPad editor, www.pspad.com">
+<title>Stack Tester</title>
+<script language="javascript" type="text/javascript" src="Stack.js"></script>
+<style>
+body {font-family: Verdana, Tahoma; font-size: 8pt; font-weight: normal}
+button {font-family: Verdana, Tahoma; font-size: 8pt; font-weight: bold; width: 100px; height: 24px;}
+textarea {font-family: Verdana, Tahoma; font-size: 8pt; font-weight: normal; border: 1px solid;}
+input {font-family: Verdana, Tahoma; font-size: 8pt; font-weight: normal; border: 1px solid;}
+</style>
+<script language="javascript">
+var myStack = new Stack();
+
+function pushValue()
+{
+    var objFrm;
+    var strVal;
+
+    objFrm = document.frmMain;
+    if (objFrm) strVal = objFrm.txtValue.value;
+    if (strVal) myStack.Push(strVal);
+    objFrm.txtValue.value = "";
+}
+
+function popValue()
+{
+    var objFrm;
+    var strVal;
+
+    objFrm = document.frmMain;
+    if (!myStack.IsEmpty())
+    {
+        strVal = myStack.Pop();
+        objFrm.txtValue.value = strVal;
+    }
+}
+
+function getValue()
+{
+    var objFrm;
+    var strVal;
+    var intIndex = NaN;
+
+    objFrm = document.frmMain;
+    if (objFrm) intIndex = parseInt(objFrm.txtIndex.value);
+    if (!isNaN(intIndex))
+    {
+        strVal = myStack.Get(intIndex);
+        objFrm.txtValue.value = strVal;
+    }
+}
+
+function showStack()
+{
+    var objFrm;
+    var strVal, strTemp;
+    var intCntr = 0;
+
+    if (myStack.IsEmpty())
+    {
+        alert ("No values stored on stack!");
+        return;
+    }
+
+    strTemp = "";
+    objFrm = document.frmMain;
+    for (intCntr = 0; intCntr < myStack.Size(); intCntr++)
+    {
+        strVal = myStack.Get(intCntr);
+        if (intCntr == 0)
+            strTemp += "Stack[Top] = " + strVal + "\r\n";
+        else
+            strTemp += "Stack[Top + " + intCntr + "] = " + strVal + "\r\n";
+        strVal = "";
+    }
+    objFrm.txtStack.value = strTemp;
+}
+</script>
+</head>
+<body>
+    <form name="frmMain" id="frmMain" method="POST">
+        <table>
+            <tr>
+                <td valign="top">
+                    <table>
+                        <tr>
+                            <td>Value : </td>
+                            <td><input type="text" name="txtValue" id="txtValue" size="20" /></td>
+                        </tr>
+                        <tr>
+                            <td colspan="2">
+                                <button id="btnPush" name="btnPush" onClick="javascript:pushValue()">Push</button>
+                                <button id="btnPop" name="btnPop" onClick="javascript:popValue()">Pop</button>
+                            </td>
+                        </tr>
+                        <tr>
+                            <td colspan="2">
+                                <button id="btnGet" name="btnGet" onClick="getValue()">Get</button>
+                                @&nbsp;<input type="text" size="2" maxlength="2" id="txtIndex" name="txtIndex" />
+                            </td>
+                        </tr>
+                        <tr>
+                            <td colspan="2">
+                                <button name="btnWalk" id="btnWalk" onClick="javascript:showStack()">Walk</button>
+                            </td>
+                        </tr>
+                    </table>
+                </td>
+                <td>
+                    <textarea id="txtStack" name="txtStack" cols="30" rows="10"></textarea>
+                </td>
+            </tr>
+        </table>
+    </form>
+</body>
+</html>

+ 54 - 0
lib/JSExpressionEval_src/TokanTester.htm

@@ -0,0 +1,54 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=windows-1250">
+<meta name="generator" content="PSPad editor, www.pspad.com">
+<title>Tokanizer Tester</title>
+<script language="javascript" type="text/javascript" src="Tokanizer.js"></script>
+<script language="javascript">
+<!--//
+function getTokens()
+{
+    var intCntr;
+    var form = document.frmMain;
+    var arrTokens = Tokanize(form.txtExp.value);
+    var strTemp = "";
+    var strTmp = "";
+    if (arrTokens.length > 0)
+    {
+        for (intCntr = 0; intCntr < arrTokens.length; intCntr++)
+        {
+            strTemp += arrTokens[intCntr];
+            strTmp += "Token " + intCntr + " : " + arrTokens[intCntr] + "\r\n";
+        }
+        form.txtResult.value = strTemp + "\r\n" + strTmp     ;
+    }
+    else
+        alert ("No Tokens");
+}
+//-->
+</script>
+</head>
+<body>
+    <form name="frmMain" id="frmMain" method="POST">
+        <table>
+        <tbody>
+            <tr>
+                <td>Enter an Expression : </td>
+                <td><input type="text" size="60" name="txtExp" id="txtExp"></input></td>
+            </tr>
+            <tr>
+                <td colspan="2">
+                    <textarea name="txtResult" id="txtResult" cols="60" rows="10"></textarea>
+                </td>
+            </tr>
+            <tr>
+                <td colspan="2">
+                    <button name="btnTokanize" id="btnTokanize" onClick="javascript:getTokens();">Tokanize</button>
+                </td>
+            </tr>
+        </tbody>
+        </table>
+    </form>
+</body>
+</html>

+ 493 - 0
lib/JSExpressionEval_src/Tokanizer.js

@@ -0,0 +1,493 @@
+/*------------------------------------------------------------------------------
+ * NAME    : Tokanizer.js
+ * PURPOSE : Parse a string a make an array of tokens. The following tokens are
+ *           reconized.
+ *           () 
+ *           ^ * / % + -  
+ *           ! & | TRUE FALSE
+ *           < <= > >= <> =
+ *           AVG ABS ACOS ASC ASIN ATAN CDATE CHR COS DATE FIX HEX IIF 
+ *           LCASE LEFT LOG MAX MID MIN RIGHT ROUND SIN SQRT TAN UCASE 
+ *           , ' "
+ * AUTHOR  : Prasad P. Khandekar
+ * CREATED : August 19, 2005
+ *------------------------------------------------------------------------------
+ * -3              // Negative 3 - is the first token
+ * 3+-2            // Negative 2 - previous token is an operator and next is a digit
+ * 3*-(2)          // Negative 2 - previous token is an operator and next is an opening brace
+ * 3*ABS(-2)       // Negative 2 - previous token is an opening brace and next is a digit
+ * 3+-SQR(4)       // Negative SQR - previous token is an operator and next is a alpha
+ *
+ * 3-2             // Positive 2 - previous token is a digit and next is a digit
+ * 3 - 2           // Positive 2 - previous token is a digit or space and next is a space
+ * ABS(3.4)-2      // Positive 2 - previous token is a closing brace and next is a digit
+ * ABS(3.4)- 2     // Positive 2 - previous token is a digit and next is a space
+ * ABS(3.4) - 2    // Positive 2 - previous token is a closing brace or space and next is a space
+ *------------------------------------------------------------------------------
+ * Copyright (c) 2005. Khan Information Systems. All Rights Reserved
+ * The contents of this file are subject to the KIS Public License 1.0
+ * (the "License"); you may not use this file except in compliance with the 
+ * License. You should have received a copy of the KIS Public License along with 
+ * this library; if not, please ask your software vendor to provide one.
+ * 
+ * YOU AGREE THAT THE PROGRAM IS PROVIDED AS-IS, WITHOUT WARRANTY OF ANY KIND
+ * (EITHER EXPRESS OR IMPLIED) INCLUDING, WITHOUT LIMITATION, ANY IMPLIED 
+ * WARRANTY OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND ANY 
+ * WARRANTY OF NON INFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE 
+ * PROGRAM, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * See the License for the specific language governing rights and limitations 
+ * under the License.
+ *-----------------------------------------------------------------------------*/
+ var lstAlpha    = "a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,uv,w,x,y,z";
+ var lstDigits   = "0,1,2,3,4,5,6,7,8,9";
+ var lstArithOps = "^,*,/,%,+,-";
+ var lstLogicOps = "!,&,|";
+ var lstCompaOps = "<,<=,>,>=,<>,=";
+ var lstFuncOps  = ["AVG","ABS","ACOS","ASC","ASIN","ATAN","CDATE","CHR","COS","DATE","FIX","HEX","IIF","LCASE","LEFT","LOG","MAX","MID","MIN","RIGHT","ROUND","SIN","SQRT","TAN","UCASE"];
+
+/*------------------------------------------------------------------------------
+ * NAME       : Tokanize
+ * PURPOSE    : Breaks the string into a token array. It also checks whether the
+ *              parenthesis, single quotes and double quotes are balanced or not.
+ * PARAMETERS : pstrExpression - The string from which token array is to be 
+ *              constructed.
+ * RETURNS    : An array of tokens.
+ * THROWS     : Unterminated string constant - Single/Double quotes are not 
+ *                                             properly terminated
+ *              Unbalanced parenthesis - Opening/closing braces are not balanced
+ *----------------------------------------------------------------------------*/
+ function Tokanize(pstrExpression)
+ {
+    var intCntr, intBraces;
+    var arrTokens;
+    var intIndex, intPos;
+    var chrChar, chrNext;
+    var strToken, prevToken;
+
+    intCntr   = 0;
+    intBraces = 0;
+    intIndex  = 0;
+    strToken  = "";
+    arrTokens = new Array();
+    pstrExpression = Trim(pstrExpression);
+    while (intCntr < pstrExpression.length)
+    {
+        prevToken = "";
+        chrChar = pstrExpression.substr(intCntr, 1);
+        if (window)
+            if (window.status)
+                window.status = "Processing " + chrChar;
+        switch (chrChar)
+        {
+            case " " :
+                if (strToken.length > 0)
+                {
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                }
+                break;
+            case "(":
+                intBraces++;
+                if (strToken.length > 0)
+                {
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                }
+                arrTokens[intIndex] = chrChar;
+                intIndex++;
+                break;
+            case ")" :
+                intBraces--;
+                if (strToken.length > 0)
+                {
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                }
+                arrTokens[intIndex] = chrChar;
+                intIndex++;
+                break;
+            case "^" :
+                if (strToken.length > 0)
+                {
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                }
+                arrTokens[intIndex] = chrChar;
+                intIndex++;
+                break;
+            case "*" :
+                if (strToken.length > 0)
+                {
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                }
+                arrTokens[intIndex] = chrChar;
+                intIndex++;
+                break;
+            case "/" :
+                if (strToken.length > 0)
+                {
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                }
+                arrTokens[intIndex] = chrChar;
+                intIndex++;
+                break;
+            case "%" :
+                if (strToken.length > 0)
+                {
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                }
+                arrTokens[intIndex] = chrChar;
+                intIndex++;
+                break;
+            case "&" :
+                if (strToken.length > 0)
+                {
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                }
+                arrTokens[intIndex] = chrChar;
+                intIndex++;
+                break;
+            case "|" :
+                if (strToken.length > 0)
+                {
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                }
+                arrTokens[intIndex] = chrChar;
+                intIndex++;
+                break;
+            case "," :
+                if (strToken.length > 0)
+                {
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                }
+                arrTokens[intIndex] = chrChar;
+                intIndex++;
+                break;
+            case "-" :
+                if (strToken.length > 0)
+                {
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                }
+                chrNext = pstrExpression.substr(intCntr + 1, 1);
+                if (arrTokens.length > 0)
+                    prevToken = arrTokens[intIndex - 1];
+                if (intCntr == 0 || ((IsOperator(prevToken) ||
+                    prevToken == "(" || prevToken == ",") && 
+                    (IsDigit(chrNext) || chrNext == "(")))
+                {
+                    // Negative Number
+                    strToken += chrChar;
+                }
+                else
+                {
+                    arrTokens[intIndex] = chrChar;
+                    intIndex++;
+                    strToken = "";
+                }
+                break;
+            case "+" :
+                if (strToken.length > 0)
+                {
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                }
+                chrNext = pstrExpression.substr(intCntr + 1, 1);
+                if (arrTokens.length > 0)
+                    prevToken = arrTokens[intIndex - 1];
+                if (intCntr == 0 || ((IsOperator(prevToken) ||
+                    prevToken == "(" || prevToken == ",") && 
+                    (IsDigit(chrNext) || chrNext == "(")))
+                {
+                    // positive Number
+                    strToken += chrChar;
+                }
+                else
+                {
+                    arrTokens[intIndex] = chrChar;
+                    intIndex++;
+                    strToken = "";
+                }
+                break;
+            case "<" :
+                chrNext = pstrExpression.substr(intCntr + 1, 1);
+                if (strToken.length > 0)
+                {
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                }
+                if (chrNext == "=")
+                {
+                    arrTokens[intIndex] = chrChar + "=";
+                    intIndex++;
+                    intCntr++;
+                }
+                else if (chrNext == ">")
+                {
+                    arrTokens[intIndex] = chrChar + ">";
+                    intIndex++;
+                    intCntr++;
+                }
+                else
+                {
+                    arrTokens[intIndex] = chrChar;
+                    intIndex++;
+                }
+                break;
+            case ">" :
+                chrNext = pstrExpression.substr(intCntr + 1, 1);
+                if (strToken.length > 0)
+                {
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                }
+                if (chrNext == "=")
+                {
+                    arrTokens[intIndex] = chrChar + "=";
+                    intIndex++;
+                    intCntr++;
+                }
+                else
+                {
+                    arrTokens[intIndex] = chrChar;
+                    intIndex++;
+                }
+                break;
+            case "=" :
+                if (strToken.length > 0)
+                {
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                }
+                arrTokens[intIndex] = chrChar;
+                intIndex++;
+                break;
+            case "'" :
+                if (strToken.length > 0)
+                {
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                }
+
+                intPos = pstrExpression.indexOf(chrChar, intCntr + 1);
+                if (intPos < 0) 
+                    throw "Unterminated string constant";
+                else
+                {
+                    strToken += pstrExpression.substring(intCntr + 1, intPos);
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                    intCntr = intPos;
+                }
+                break;
+            case "\"" :
+                if (strToken.length > 0)
+                {
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                }
+
+                intPos = pstrExpression.indexOf(chrChar, intCntr + 1);
+                if (intPos < 0)
+                {
+                    throw "Unterminated string constant";
+                }
+                else
+                {
+                    strToken += pstrExpression.substring(intCntr + 1, intPos);
+                    arrTokens[intIndex] = strToken;
+                    intIndex++;
+                    strToken = "";
+                    intCntr = intPos;
+                }
+                break;
+            default :
+                strToken += chrChar;
+                break;
+        }
+        intCntr++;
+    }
+    if (intBraces > 0)
+        throw "Unbalanced parenthesis!";
+
+    if (strToken.length > 0)
+        arrTokens[intIndex] = strToken;
+    return arrTokens;
+}
+
+/*------------------------------------------------------------------------------
+ * NAME       : IsDigit
+ * PURPOSE    : Checks whether the character specified by chrArg is a numeric 
+ *              character.
+ * PARAMETERS : chrArg - The character to be checked
+ * RETURNS    : False - If chrArg is not a numeric character
+ *              True - Otherwise 
+ *----------------------------------------------------------------------------*/
+function IsDigit(chrArg)
+{
+    if (lstDigits.indexOf(chrArg) >= 0)
+        return true;
+    return false;
+}
+
+/*------------------------------------------------------------------------------
+ * NAME       : IsAlpha
+ * PURPOSE    : Checks whether the character specified by chrArg is a alphabet 
+ * PARAMETERS : chrArg - The character to be checked
+ * RETURNS    : False - If chrArg is not a alphabet
+ *              True - Otherwise 
+ *----------------------------------------------------------------------------*/
+function IsAlpha(chrArg)
+{
+    if (lstAlpha.indexOf(chrArg) >= 0 || 
+        lstAlpha.toUpperCase().indexOf(chrArg) >= 0)
+        return true;
+    return false;
+}
+
+/*------------------------------------------------------------------------------
+ * NAME       : IsOperator
+ * PURPOSE    : Checks whether the string specified by strArg is an operator
+ * PARAMETERS : strArg - The string to be checked
+ * RETURNS    : False - If strArg is not an operator symbol
+ *              True - Otherwise 
+ *----------------------------------------------------------------------------*/
+function IsOperator(strArg)
+{
+    if (lstArithOps.indexOf(strArg) >= 0 || lstCompaOps.indexOf(strArg) >= 0)
+        return true;
+    return false;
+}
+
+/*------------------------------------------------------------------------------
+ * NAME       : IsFunction
+ * PURPOSE    : Checks whether the string specified by strArg is a function name
+ * PARAMETERS : strArg - The string to be checked
+ * RETURNS    : False - If strArg is not a valid built-in function name.
+ *              True - Otherwise 
+ *----------------------------------------------------------------------------*/
+function IsFunction(strArg)
+{
+	var idx = 0;
+
+	strArg = strArg.toUpperCase();
+	for (idx = 0; idx < lstFuncOps.length; idx++)
+	{
+	    if (strArg == lstFuncOps[idx])
+	        return true;
+	}
+	return false;
+}
+
+/*------------------------------------------------------------------------------
+ * NAME       : Trim
+ * PURPOSE    : Removes trailing and leading spaces from a string.
+ * PARAMETERS : pstrVal - The string from which leading and trailing spaces are 
+ *              to be removed.
+ * RETURNS    : A string with leading and trailing spaces removed.
+ *----------------------------------------------------------------------------*/
+function Trim(pstrVal)
+{
+    if (pstrVal.length < 1) return "";
+
+    pstrVal = RTrim(pstrVal);
+    pstrVal = LTrim(pstrVal);
+    if (pstrVal == "")
+		return "";
+    else
+        return pstrVal;
+}
+
+/*------------------------------------------------------------------------------
+ * NAME       : RTrim
+ * PURPOSE    : Removes trailing spaces from a string.
+ * PARAMETERS : pstrValue - The string from which trailing spaces are to be removed.
+ * RETURNS    : A string with trailing spaces removed.
+ *----------------------------------------------------------------------------*/
+function RTrim(pstrValue)
+{
+    var w_space = String.fromCharCode(32);
+    var v_length = pstrValue.length;
+    var strTemp = "";
+    if(v_length < 0)
+    {
+        return"";
+    }
+    var iTemp = v_length - 1;
+
+    while(iTemp > -1)
+    {
+        if(pstrValue.charAt(iTemp) == w_space)
+        {
+        }
+        else
+        {
+            strTemp = pstrValue.substring(0, iTemp + 1);
+            break;
+        }
+        iTemp = iTemp - 1;
+    }
+    return strTemp;
+}
+
+/*------------------------------------------------------------------------------
+ * NAME       : LTrim
+ * PURPOSE    : Removes leading spaces from a string.
+ * PARAMETERS : pstrValue - The string from which leading spaces are to be removed.
+ * RETURNS    : A string with leading spaces removed.
+ *----------------------------------------------------------------------------*/
+function LTrim(pstrValue)
+{
+    var w_space = String.fromCharCode(32);
+    if(v_length < 1)
+    {
+        return "";
+    }
+    var v_length = pstrValue.length;
+    var strTemp = "";
+    var iTemp = 0;
+
+    while(iTemp < v_length)
+    {
+        if(pstrValue.charAt(iTemp) == w_space)
+        {
+        }
+        else
+        {
+            strTemp = pstrValue.substring(iTemp, v_length);
+            break;
+        }
+        iTemp = iTemp + 1;
+    }
+    return strTemp;
+}

+ 47 - 0
lib/JSExpressionEval_src/VBEval.htm

@@ -0,0 +1,47 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=windows-1250">
+<meta name="generator" content="PSPad editor, www.pspad.com">
+<style>
+body {font-family: Verdana,Tahoma; font-size: 9pt; font-weight: normal;}
+table {font-family: Verdana,Tahoma; font-size: 9pt; font-weight: normal;}
+input {font-family: Verdana,Tahoma; font-size: 10pt; font-weight: normal; border: 1px solid;}
+textarea {font-family: Verdana,Tahoma; font-size: 10pt; font-weight: normal; border: 1px solid;}
+button {font-family: Verdana,Tahoma; font-size: 8pt; font-weight: bold; width: 125px; height: 24px;}
+</style>
+<title>VB Eval</title>
+<script language="vbscript">
+Sub Calculate()
+    Dim frm
+    Dim strExp
+    Dim strResult
+
+    Set frm = document.frmMain
+    strExp = frm.txtExp.Value
+    strResult = Eval(strExp)
+    frm.txtResult.Value = strResult
+End Sub
+</script>
+</head>
+<body>
+    <form name="frmMain" id="frmMain" method="POST">
+        <table>
+            <tr>
+                <td>Expression : </td>
+                <td><input type="text" size="50" name="txtExp" id="txtExp" /></td>
+            </tr>
+            <tr>
+                <td colspan="2">
+                    <textarea name="txtResult" id="txtResult" cols="61" rows="5"></textarea>
+                </td>
+            </tr>
+            <tr>
+                <td colspan="2" align ="center">
+                    <button name="btnCalc" id="btnCalc" onClick="vbscript:Calculate()">Calculate</button>
+                </td>
+            </tr>
+        </table>
+    </form>
+</body>
+</html>

+ 123 - 0
lib/JSExpressionEval_src/postfix.txt

@@ -0,0 +1,123 @@
+(           99
+-!          10
+Functions   9
+^           7
+*/%         6
++-          5
+&|          3
+><=<><=>=   4
+
+
+10/Abs(3) + 2 > 2 & 3 >= 2
+--------------------------------------
+10      (       10
+/       (/      10
+Abs     (/Abs   10
+(       (/Abs(  10
+3       (/Abs(  10 3
+)       (/Abs   10 3
++       (+      10 3 Abs /
+2       (+      10 3 Abs / 2
+>       (>      10 3 Abs / 2 +
+2       (>      10 3 Abs / 2 + 2
+&       (&      10 3 Abs / 2 + 2 >
+3       (&      10 3 Abs / 2 + 2 > 3
+>=      (&>=    10 3 Abs / 2 + 2 > 3
+2       (&>=    10 3 Abs / 2 + 2 > 3 2
+--------------------------------------
+10 3 Abs / 2 + 2 > 3 2 >= & 
+10 3 Abs / 2 + 2 > 3 2 >= &
+
+10/Abs(3) + 2
+----------------------------------
+10      (       10
+/       (/      10
+Abs     (/Abs   10
+(       (/Abs(  10
+3       (/Abs(  10 3
+)       (/Abs   10 3
++       (+      10 3 Abs /
+2       (+      10 3 Abs / 2
+-----------------------------------
+10 3 Abs / 2 +
+10 3 Abs / 2 +
+
+
+2+3.4*56/MAX(3,4,5)
+---------------------------------
+2	(	2
++	(+	2
+3.4	(+	2 3.4
+*	(+*	2 3.4
+56	(+*	2 3.4 56
+/	(+/	2 3.4 56 *
+MAX	(+/MAX	2 3.4 56 *
+(	(+/MAX(	2 3.4 56 *
+3	(+/MAX(	2 3.4 56 * 3
+,	(+/MAX(	2 3.4 56 * 3
+4	(+/MAX(	2 3.4 56 * 3 4
+,	(+/MAX(	2 3.4 56 * 3 4
+5	(+/MAX(	2 3.4 56 * 3 4 5
+)	(+/MAX	2 3.4 56 * 3 4 5
+--------------------------------
+2 3.4 56 * 3 4 5 MAX / +
+2 3.4 56 * 3 4 5 MAX / +
+
+
+2+3.4*56^AVG(3,4,5)
+--------------------------------------
+2	(		2
++	(+		2
+3.4	(+		2 3.4
+*	(+*		2 3.4
+56	(+*		2 3.4 56
+^	(+*^		2 3.4 56
+AVG	(+*^AVG		2 3.4 56
+(	(+*^AVG(	2 3.4 56
+3	(+*^AVG(	2 3.4 56 3
+,	(+*^AVG(	2 3.4 56 3
+4	(+*^AVG(	2 3.4 56 3 4
+,	(+*^AVG(	2 3.4 56 3 4
+5	(+*^AVG(	2 3.4 56 3 4 5
+)	(+*^AVG		2 3.4 56 3 4 5
+---------------------------------------
+2 3.4 56 3 4 5 AVG ^ * +
+
+
+3+MAX(3*4,6,7)
+--------------------------------------------
+3	(		3
++	(+		3
+MAX	(+MAX		3
+(	(+MAX(		3
+3	(+MAX(		3 3
+*	(+MAX(*		3 3
+4	(+MAX(*		3 3 4
+,	(+MAX(		3 3 4 *
+6	(+MAX(		3 3 4 * 6
+,	(+MAX(		3 3 4 * 6
+7	(+MAX(		3 3 4 * 6 7
+)	(+MAX		3 3 4 * 6 7
+--------------------------------------------
+3 3 4 * 6 7 MAX
+
+
+3+MAX(3+2*4,6,7)
+------------------------------------------
+3	(		3
++	(+		3
+MAX	(+MAX		3
+(	(+MAX(		3
+3	(+MAX(		3 3
++	(+MAX(+		3 3
+2	(+MAX(+		3 3 2
+*	(+MAX(+*	3 3 2
+4	(+MAX(+*	3 3 2 4
+,	(+MAX(		3 3 2 4 * +
+6	(+MAX(		3 3 2 4 * + 6
+,	(+MAX(		3 3 2 4 * + 6
+7	(+MAX(		3 3 2 4 * + 6 7
+)	(+MAX		3 3 2 4 * + 6 7
+--------------------------------------------
+3 3 2 4 * + 6 7 MAX +
+3 3 2 4 * + 6 7 MAX +

+ 2 - 1
test/tmp_data/bills_grid_setting.js

@@ -96,7 +96,8 @@ var BillsGridSetting ={
                 "field":"name",
                 "vAlign":1,
                 "hAlign":0,
-                "font":"Arial"
+                "font":"Arial",
+                "wordWrap": true
             }
         },
         {

+ 11 - 20
test/tmp_data/test_ration_calc/ration_calc_base.js

@@ -1,8 +1,9 @@
 /**
  * Created by Mai on 2017/7/21.
  */
+"use strict";
 
-const baseCalc = 0, adjustCalc = 1, budgetCalc = 2, offerCalc = 3;
+const baseCalc = 0, adjustCalc = 1, budgetCalc = 2, diffCalc = 3,  offerCalc = 4;
 
 const gljType = {
     // 人工
@@ -55,34 +56,24 @@ let rationCalcBase = [
         'calcType': baseCalc,
         'gljTypes': [gljType.MACHINE_COMPOSITION]
     },{
-        'dispName': '定额基价人工费(调整后)',
-        'calcFun': 'adjust',
-        'calcType': adjustCalc,
-        'gljTypes': [gljType.LABOUR]
-    },{
-        'dispName': '定额基价机上人工费(调整后)',
-        'calcFun': 'adjust',
-        'calcType': adjustCalc,
-        'gljTypes': [gljType.MACHINE_COMPOSITION]
-    },{
-        'dispName': '市场价格人工费',
-        'calcFun': 'budget',
+        'dispName': '人工费价差',
+        'calcFun': 'diff',
         'calcType': budgetCalc,
         'gljTypes': [gljType.LABOUR]
     },{
-        'dispName': '市场价格材料费',
-        'calcFun': 'budget',
-        'calcType': budgetCalc,
+        'dispName': '材料费价差',
+        'calcFun': 'diff',
+        'calcType': diffCalc,
         'gljTypes': [gljType.GENERAL_MATERIAL, gljType.CONCRETE, gljType.MORTAR, gljType.MIX_RATIO, gljType.COMMERCIAL_CONCRETE, gljType.COMMERCIAL_MORTAR]
     },{
-        'dispName': '市场价格机械费',
-        'calcFun': 'budget',
-        'calcType': budgetCalc,
+        'dispName': '机械费价差',
+        'calcFun': 'diff',
+        'calcType': diffCalc,
         'gljTypes': [gljType.GENERAL_MACHINE]
     },{
         'dispName': '主材费',
         'calcFun': 'budget',
-        'calcType': budgetCalc,
+        'calcType': diffCalc,
         'gljTypes': [gljType.MAIN_MATERIAL]
     },{
         'dispName': '设备费',

+ 9 - 1
web/building_saas/main/html/main.html

@@ -462,6 +462,12 @@
 
     <script src="/lib/tether/tether.min.js"></script>
     <script src="/lib/bootstrap/bootstrap.min.js"></script>
+    <!--expression calculate-->
+    <script src="/lib/JSExpressionEval_src/Date.js"></script>
+    <script src="/lib/JSExpressionEval_src/Stack.js"></script>
+    <script src="/lib/JSExpressionEval_src/Tokanizer.js"></script>
+    <script src="/lib/JSExpressionEval_src/Evaluator.js"></script>
+    <!--end expression calculate-->
     <!--<script type="text/javascript" src="/lib/bootstrap/bootstrap-select.min.js"></script>-->
     <script type="text/javascript" src="/lib/jquery-contextmenu/jquery.contextMenu.js"></script>
     <script type="text/javascript" src="/lib/jquery-contextmenu/jquery.ui.position.js"></script>
@@ -489,9 +495,11 @@
     <script type="text/javascript" src="/web/building_saas/main/js/models/ration_ass.js"></script>
 
     <script type="text/javascript" src="/public/web/id_tree.js"></script>
+    <script type="text/javascript" src="/test/tmp_data/test_ration_calc/ration_calc_base.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/models/cache_tree.js"></script>
+    <script type="text/javascript" src="/web/building_saas/main/js/calc/calc_fees.js"></script>
+    <script type="text/javascript" src="/web/building_saas/main/js/calc/ration_calc.js"></script>
     <script type="text/javascript" src="/web/building_saas/main/js/calc/bills_calc.js"></script>
-    <script type="text/javascript" src="/web/building_saas/main/js/models/ration_calc.js"></script>
     <!-- Controller -->
     <script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_controller.js"></script>
     <script type="text/javascript" src="/public/web/tree_sheet/tree_sheet_helper.js"></script>

+ 16 - 57
web/building_saas/main/js/calc/bills_calc.js

@@ -36,57 +36,7 @@ let nodeCalcObj = {
     node: null,
     digit: 2,
     field: null,
-    findFee: function (fieldName) {
-        if (!this.node.data.fees) {
-            this.node.data.fees = [];
-        }
-        for (let fee of this.node.data.fees) {
-            if (fee.fieldName === fieldName) {
-                return fee;
-            }
-        }
-        return null;
-    },
-    AddFee: function (fieldName) {
-        let fee = {
-            'fieldName': fieldName,
-            'unitFee': 0,
-            'totalFee': 0,
-            'tenderUnitFee': 0,
-            'tenderTotalFee': 0
-        };
-        this.node.data.fees.push(fee);
-        this.node.data.feesIndex[fieldName] = fee;
-    },
-    checkFields: function (fields) {
-        for (let field of fields) {
-            if (!this.findFee(field.type)) {
-                this.AddFee(field.type);
-            }
-        }
-    },
-    getFee: function (data, fullField) {
-        let fields = fullField.split('.'), value = data;
-        for (let field of fields) {
-            if (value[field]) {
-                value = value[field];
-            } else {
-                return 0;
-            }
-        }
-        return value;
-    },
-    getFeeSplit: function (data, fullFields) {
-        let value = data;
-        for (let field of fullFields) {
-            if (value[field]) {
-                value = value[field];
-            } else {
-                return 0;
-            }
-        }
-        return value;
-    },
+    getFee: calcFees.getFee,
     sumTotalFee: function() {
         let result = 0, child;
         for (child of this.node.children) {
@@ -145,8 +95,17 @@ class BillsCalc {
     calcLeaf (node, fields) {
         nodeCalcObj.node = node;
         nodeCalcObj.digit = this.digit;
-        nodeCalcObj.checkFields(fields);
-        let nodeCalc = nodeCalcObj;
+        calcFees.checkFields(node.data, fields);
+        let nodeCalc = nodeCalcObj, virData= null;
+
+        // 清单单价:套用定额计算程序
+        if (this.CalcFlag === billsPrice) {
+            let rations = this.project.Ration.getBillsSortRation(node.source.getID());
+            rationCalcObj.calcGljs = this.project.ration_glj.getGatherGljArrByRations(rations);
+            rationCalcObj.calcFields = rationCalcFields;
+            virData = rationCalcObj.calculate();
+        }
+
         for (let field of fields) {
             nodeCalcObj.field = field;
             switch (field.unitFeeFlag) {
@@ -156,9 +115,9 @@ class BillsCalc {
                 case averageQtyUnitFeeFlag:
                     node.data.feesIndex[field.type].unitFee = nodeCalcObj.averageQty().toDecimal(this.digit);
                     break;
-                // to do billsPriceUnitFeeFlag(套用定额计算程序)
-                // case billsPriceUnitFeeFlag:
-                //     break;
+                 case billsPriceUnitFeeFlag:
+                     node.data.feesIndex[field.type].unitFee = virData[field.type];
+                     break;
                 default:
                     node.data.feesIndex[field.type].unitFee = 0;
             }
@@ -176,7 +135,7 @@ class BillsCalc {
     };
     calcParent (node, fields) {
         nodeCalcObj.node = node;
-        nodeCalcObj.checkFields(fields);
+        calcFees.checkFields(node.data, fields);
         for (let field of fields) {
             nodeCalcObj.field = field;
             node.data.feesIndex[field.type].totalFee = nodeCalcObj.sumTotalFee().toDecimal(this.digit);

+ 265 - 54
web/building_saas/main/js/calc/ration_calc.js

@@ -2,78 +2,197 @@
  * Created by Mai on 2017/7/13.
  */
 
+/*
 let rationCalcFields = [
     {
         type: 'baseDirect', code: "1", name: "基价直接工程费",
-        dispExpr: "1.1+1.2+1.3+1.4", expression: "@('1.1') + @('1.2') + @('1.3') + @('1.4')", compiledExpr: "",
+        dispExpr: "1.1+1.2+1.3+1.4", expression: "at('1.1') + at('1.2') + at('1.3') + at('1.4')", compiledExpr: "",
         statement: "基价人工费+基价材料费+基价机械费+未计价材料费"
-    },{
+    },
+    {
         type: 'baseLabour', code: "1.1", name: "基价人工费",
-        dispExpr: "1.1.1+1.1.2", expression: "@('1.1.1') + @('1.1.2')", compiledExpr: "",
+        dispExpr: "1.1.1+1.1.2", expression: "at('1.1.1') + at('1.1.2')", compiledExpr: "",
         statement: "定额基价人工费+定额人工单价(基价)调整"
-    },{
+    },
+    {
         type: 'rationBaseLabour', code: "1.1.1", name: "定额基价人工费",
-        dispExpr: "定额基价人工费", expression: "base('定额基价人工费').toFixed(2)", compiledExpr: "",
+        dispExpr: "定额基价人工费", expression: "定额基价人工费", compiledExpr: "",
         statement: "定额基价人工费"
-    },{
-        type: 'rationAdjustLabour', code: "1.1.2", name: "定额人工单价(基价)调整",
-        dispExpr: "1.1.1*[1.89-1]", expression: "@('1.1.1') * fee('3')", compiledExpr: "",
-        statement: "定额基价人工费*[定额人工单价(基价)调整系数-1]"
-    },{
+    },
+    {
+        type: 'rationAdjustLabour', code: "1.1.2", name: "定额基价人工费(调整后)",
+        dispExpr: "定额基价人工费(调整后)", expression: "定额基价人工费(调整后)", compiledExpr: "",
+        statement: "定额基价人工费(调整后)"
+    },
+    {
         type: 'baseMaterial', code: "1.2", name: "基价材料费",
-        dispExpr: "定额基价材料费", expression: "base('定额基价材料费')", compiledExpr: "",
+        dispExpr: "定额基价材料费", expression: "定额基价材料费", compiledExpr: "",
         statement: "定额基价材料费"
-    },{
+    },
+    {
         type: 'baseMachine', code: "1.3", name: "基价机械费",
-        dispExpr: "1.3.1+1.3.2", expression: "@('1.3.1') + @('1.3.2')", compiledExpr: "",
-        statement: "定额基价机械费+定额机上人工单价(基价)调整"
-    },{
+        dispExpr: "1.3.1+1.3.2", expression: "at('1.3.1') + at('1.3.2')", compiledExpr: "",
+        statement: "定额基价机械费+定额基价机上人工费(调整后)"
+    },
+    {
         type: 'rationBaseMachine', code: "1.3.1", name: "定额基价机械费",
-        dispExpr: "定额基价机械费", expression: "base('定额基价机械费')", compiledExpr: "",
+        dispExpr: "定额基价机械费", expression: "定额基价机械费", compiledExpr: "",
         statement: "定额基价机械费"
-    },{
+    },
+    {
         type: 'rationBaseMachineLabour', code: "1.3.1.1", name: "其中:定额基价机上人工费",
-        dispExpr: "定额基价机上人工费", expression: "base('定额基价机上人工费')", compiledExpr: "",
+        dispExpr: "定额基价机上人工费", expression: "定额基价机上人工费", compiledExpr: "",
         statement: "定额基价机上人工费"
-    },{
-        type: 'rationBaseMachineLabourFixed', code: "1.3.2", name: "定额机上人工单价(基价)调整",
-        dispExpr: "1.3.1.1*[1.89-1]", expression: "@('1.3.1.1') * fee('30')", compiledExpr: "",
-        statement: "定额基价机上人工费*[定额人工单价(基价)调整系数-1]"
-    },{
+    },
+    {
+        type: 'rationBaseMachineLabourFixed', code: "1.3.2", name: "定额基价机上人工费(调整后)",
+        dispExpr: "定额基价机上人工费(调整后)", expression: "定额基价机上人工费(调整后)", compiledExpr: "",
+        statement: "定额基价机上人工费(调整后)"
+    },
+    {
         type: 'unPriceMaterial', code: "1.4", name: "未计价材料费",
-        dispExpr: "主材费+设备费", expression: "base('主材费') + base('设备费')", compiledExpr: "",
+        dispExpr: "主材费+设备费", expression: "主材费+设备费", compiledExpr: "",
         statement: "主材费+设备费"
-    },{
+    },
+    {
         type: 'management', code: "2", name: "企业管理费",
-        dispExpr: "1.1.1", expression: "@('1.1.1')", compiledExpr: "",
+        dispExpr: "1.1.1", expression: "at('1.1.1')", compiledExpr: "",
         statement: "定额基价人工费"
-    },{
+    },
+    {
         type: 'profit', code: "3", name: "利润",
-        dispExpr: "1.1.1", expression: "@('1.1.1')", compiledExpr: "",
+        dispExpr: "1.1.1", expression: "at('1.1.1')", compiledExpr: "",
         statement: "定额基价人工费"
-    },{
+    },
+    {
         type: 'risk', code: "4", name: "风险因素",
         dispExpr: "", expression: "0", compiledExpr: "",
         statement: ""
-    },{
+    },
+    {
         type: 'gljDiff', code: "5", name: "人材机价差",
-        dispExpr: "5.1+5.2+5.3", expression: "@('5.1') + @('5.2') + @('5.3')", compiledExpr: "",
+        dispExpr: "5.1+5.2+5.3", expression: "at('5.1') + at('5.2') + at('5.3')", compiledExpr: "",
         statement: "人工费价差+材料费价差+机械费价差"
-    },{
+    },
+    {
         type: 'labourDiff', code: "5.1", name: "人工费价差",
-        dispExpr: "信息价或市场价格-调整后的定额人工费(基价)", expression: "base('市场价格人工费') - base('定额基价人工费(调整后)')", compiledExpr: "",
-        statement: "市场价格人工费-调整后的定额人工费(基价)"
-    },{
+        dispExpr: "市场价格人工费-定额基价人工费(调整后)", expression: "市场价格人工费-定额基价人工费(调整后)", compiledExpr: "",
+        statement: "市场价格人工费-定额基价人工费(调整后)"
+    },
+    {
         type: 'materialDiff', code: "5.2", name: "材料费价差",
-        dispExpr: "信息价或市场价格-定额基价材料费", expression: "base('市场价格材料费') - base('定额基价材料费(调整后)')", compiledExpr: "",
+        dispExpr: "市场价格材料费-定额基价材料费", expression: "budget('材料') - base('材料')", compiledExpr: "",
         statement: "市场价格材料费-定额基价材料费"
-    },{
+    },
+    {
         type: 'machineDiff', code: "5.3", name: "机械费价差",
-        dispExpr: "信息价或市场价格-调整后的定额基价机械费(基价)", expression: "base('市场价格机械费') - base('定额基价机械费(调整后)')", compiledExpr: "",
-        statement: "市场价格机械费-调整后的定额基价机械费(基价)"
-    },{
+        dispExpr: "市场价格机械费-定额基价机械费-定额基价机上人工费(调整后)", expression: "市场价格机械费-定额基价机械费-定额基价机上人工费(调整后)", compiledExpr: "",
+        statement: "市场价格机械费-定额基价机械费-定额基价机上人工费(调整后)"
+    },
+    {
         type: 'common', code: "6", name: "综合单价",
-        dispExpr: "1+2+3+4+5", expression: "@('1') + @('2') + @('3') + @('4') + @('5')", compiledExpr: "",
+        dispExpr: "1+2+3+4+5", expression: "at('1') + at('2') + at('3') + at('4') + at('5')", compiledExpr: "",
+        statement: "基价直接工程费+企业管理费+利润+风险因素+人材机价差"
+    }
+];
+*/
+"use strict";
+
+let calcEvaluate = function (expr) {
+    let exp = new Expression('');
+    exp.Expression(expr);
+    return exp.Evaluate();
+}
+
+let rationCalcFields = [
+    {
+        type: 'rationBaseLabour', code: "1.1.1", name: "定额基价人工费",
+        dispExpr: "定额基价人工费", expression: "定额基价人工费", compiledExpr: "",
+        statement: "定额基价人工费"
+    },
+    {
+        type: 'rationAdjustLabour', code: "1.1.2", name: "定额基价人工费(调整后)",
+        dispExpr: "定额基价人工费(调整后)", expression: "at('1.1.1')*(1.89-1)", compiledExpr: "",
+        statement: "定额基价人工费(调整后)"
+    },
+    {
+        type: 'baseLabour', code: "1.1", name: "基价人工费",
+        dispExpr: "1.1.1+1.1.2", expression: "at('1.1.1') + at('1.1.2')", compiledExpr: "",
+        statement: "定额基价人工费+定额人工单价(基价)调整"
+    },
+    {
+        type: 'baseMaterial', code: "1.2", name: "基价材料费",
+        dispExpr: "定额基价材料费", expression: "定额基价材料费", compiledExpr: "",
+        statement: "定额基价材料费"
+    },
+    {
+        type: 'rationBaseMachine', code: "1.3.1", name: "定额基价机械费",
+        dispExpr: "定额基价机械费", expression: "定额基价机械费", compiledExpr: "",
+        statement: "定额基价机械费"
+    },
+    {
+        type: 'rationBaseMachineLabour', code: "1.3.1.1", name: "其中:定额基价机上人工费",
+        dispExpr: "定额基价机上人工费", expression: "定额基价机上人工费", compiledExpr: "",
+        statement: "定额基价机上人工费"
+    },
+    {
+        type: 'rationBaseMachineLabourFixed', code: "1.3.2", name: "定额基价机上人工费(调整后)",
+        dispExpr: "定额基价机上人工费(调整后)", expression: "定额基价机上人工费*(1.89-1)", compiledExpr: "",
+        statement: "定额基价机上人工费(调整后)"
+    },
+    {
+        type: 'baseMachine', code: "1.3", name: "基价机械费",
+        dispExpr: "1.3.1+1.3.2", expression: "at('1.3.1') + at('1.3.2')", compiledExpr: "",
+        statement: "定额基价机械费+定额基价机上人工费(调整后)"
+    },
+    {
+        type: 'unPriceMaterial', code: "1.4", name: "未计价材料费",
+        dispExpr: "主材费+设备费", expression: "主材费+设备费", compiledExpr: "",
+        statement: "主材费+设备费"
+    },
+    {
+        type: 'baseDirect', code: "1", name: "基价直接工程费",
+        dispExpr: "1.1+1.2+1.3+1.4", expression: "at('1.1') + at('1.2') + at('1.3') + at('1.4')", compiledExpr: "",
+        statement: "基价人工费+基价材料费+基价机械费+未计价材料费"
+    },
+    {
+        type: 'management', code: "2", name: "企业管理费",
+        dispExpr: "1.1.1", expression: "at('1.1.1')", compiledExpr: "",
+        statement: "定额基价人工费"
+    },
+    {
+        type: 'profit', code: "3", name: "利润",
+        dispExpr: "1.1.1", expression: "at('1.1.1')", compiledExpr: "",
+        statement: "定额基价人工费"
+    },
+    {
+        type: 'risk', code: "4", name: "风险因素",
+        dispExpr: "", expression: "0", compiledExpr: "",
+        statement: ""
+    },
+    {
+        type: 'labourDiff', code: "5.1", name: "人工费价差",
+        dispExpr: "市场价格人工费-定额基价人工费(调整后)", expression: "人工费价差", compiledExpr: "",
+        statement: "市场价格人工费-定额基价人工费(调整后)"
+    },
+    {
+        type: 'materialDiff', code: "5.2", name: "材料费价差",
+        dispExpr: "市场价格材料费-定额基价材料费", expression: "材料费价差", compiledExpr: "",
+        statement: "市场价格材料费-定额基价材料费"
+    },
+    {
+        type: 'machineDiff', code: "5.3", name: "机械费价差",
+        dispExpr: "市场价格机械费-定额基价机械费-定额基价机上人工费(调整后)", expression: "机械费价差", compiledExpr: "",
+        statement: "市场价格机械费-定额基价机械费-定额基价机上人工费(调整后)"
+    },
+    {
+        type: 'gljDiff', code: "5", name: "人材机价差",
+        dispExpr: "5.1+5.2+5.3", expression: "at('5.1') + at('5.2') + at('5.3')", compiledExpr: "",
+        statement: "人工费价差+材料费价差+机械费价差"
+    },
+    {
+        type: 'common', code: "6", name: "综合单价",
+        dispExpr: "1+2+3+4+5", expression: "at('1') + at('2') + at('3') + at('4') + at('5')", compiledExpr: "",
         statement: "基价直接工程费+企业管理费+利润+风险因素+人材机价差"
     }
 ];
@@ -81,40 +200,132 @@ let rationCalcFields = [
 let rationCalcObj = {
     calcGljs: [],
     calcFields: null,
-    base: function () {
-
+    baseFields: rationCalcBase,
+    getFee: calcFees.getFee,
+    base: function (type) {
+        let value = 0;
+        for (let glj of this.calcGljs) {
+            if (type.indexOf(glj.type) >= 0) {
+                value = value + this.getFee(glj, 'quantity') * this.getFee(glj, 'basePrice');
+            }
+            glj = null;
+        }
+        return value;
+    },
+    adjust: function (type) {
+        let value = 0;
+        for (let glj of this.calcGljs) {
+            if (type.indexOf(glj.type) >= 0) {
+                value = value + this.getFee(glj, 'quantity') * this.getFee(glj, 'adjustPrice');
+            }
+            glj = null;
+        }
+        return value;
     },
-    adjust: function () {
-        
+    budget: function (type) {
+        let value = 0;
+        for (let glj of this.calcGljs) {
+            if (type.indexOf(glj.type) >= 0) {
+                value = value + this.getFee(glj, 'quantity') * this.getFee(glj, 'marketPrice');
+            }
+            glj = null;
+        }
+        return value;
     },
-    budget: function () {
-
+    diff: function (type) {
+        let value = 0;
+        for (let glj of this.calcGljs) {
+            if (type.indexOf(glj.type) >= 0) {
+                value = value + (this.getFee(glj, 'quantity') * this.getFee(glj, 'marketPrice')).toDecimal(2) - (this.getFee(glj, 'quantity') * this.getFee(glj, 'adjustPrice')).toDecimal(2);
+            }
+            glj = null;
+        }
+        return value;
+    },
+    at: function (calcCode) {
+        for (let field of this.calcFields) {
+            if (field.code === calcCode) {
+                return field.fee;
+            }
+        }
+        return 0;
+    },
+    initFields: function () {
+        for (let field of this.calcFields) {
+            field.fee = 0;
+        }
+    },
+    getCalcExpr: function (expression) {
+        let calcExpr = expression, reg;
+        for (let base of this.baseFields) {
+            reg = new RegExp(base.dispName);
+            if (reg.test(calcExpr)) {
+                let value = 0;
+                switch (base.calcType) {
+                    case baseCalc:
+                        value = this.base(base.gljTypes);
+                        break;
+                    case adjustCalc:
+                        value = this.adjust(base.gljTypes);
+                        break;
+                    case budgetCalc:
+                        value = this.budget(base.gljTypes);
+                        break;
+                    case diffCalc:
+                        value = this.diff(base.gljTypes);
+                        break;
+                    case offerCalc:
+                        value = this.offer(base.gljTypes);
+                        break;
+                }
+                calcExpr = calcExpr.replace(reg, value);
+            }
+            base = null;
+        }
+        reg = null;
+        let atReg = /at\('([0-9\.]+)'\)/i, strs;
+        while (strs = calcExpr.match(atReg)) {
+            calcExpr = calcExpr.replace(strs[0], this.at(strs[1]));
+        }
+        atReg = null;
+        strs = null;
+        return calcExpr;
     },
     calculate () {
         let result = {};
-
+        for (let field of this.calcFields) {
+            let calcExpr = this.getCalcExpr(field.expression);
+            field.fee = calcEvaluate(calcExpr).toDecimal(2);
+            result[field.type] = field.fee;
+        }
+        return result;
     }
 };
 
 class RationCalc {
     constructor (project) {
         this.project = project;
-    };
+    }
 
     calculate (ration) {
         rationCalcObj.calcGljs = this.project.ration_glj.getGljArrByRation(ration.ID);
         rationCalcObj.calcFields = rationCalcFields;
-        let virData = rationCalcObj.calculate();
         calcFees.checkFields(ration, rationCalcFields);
         for (let field of rationCalcFields) {
-            ration.feesIndex[field.type].unitFee = virData[field.type].unitFee;
-            ration.feesIndex[field.type].totalFee = virData[field.type].totalFee;
+            let calcExpr = rationCalcObj.getCalcExpr(field.expression);
+            field.fee = calcEvaluate(calcExpr).toDecimal(2);
+            ration.feesIndex[field.type].unitFee = field.fee;
+            ration.feesIndex[field.type].totalFee = (field.fee * calcFees.getFee(ration, 'quantity')).toDecimal(2);
+            calcExpr = null;
         }
     }
 
     calculateAll () {
-        for (let rationData of project.ration.data) {
-            this.calculate(rationData);
+        for (let rationData of this.project.Ration.datas) {
+            let cnt = 1;
+            for (let i = 0 ; i< cnt; i++) {
+                this.calculate(rationData);
+            }
         }
     };
 }

+ 4 - 0
web/building_saas/main/js/controllers/project_controller.js

@@ -69,7 +69,11 @@ ProjectController = {
         }
     },
     calculateAll: function (project, sheetController, CalcType) {
+        let date0 = new Date();
+        let ration_calc = new RationCalc(project);
+        ration_calc.calculateAll();
         let date1 = new Date();
+        console.log(date1 - date0);
         let calc = new BillsCalc(project, CalcType);
         calc.calcAll();
         calc = null;

+ 1 - 1
web/building_saas/main/js/main_ajax.js

@@ -86,4 +86,4 @@ var GetRations = function (proj_id, callback) {
             alert('error ' + textStatus + " " + errorThrown);
         }
     });
-};
+};

+ 24 - 1
web/building_saas/main/js/models/ration_glj.js

@@ -43,8 +43,31 @@ var ration_glj = {
 
         ration_glj.prototype.getGljArrByRation = function (rationID) {
             return this.datas.filter(function (data) {
-                return data.rationID = rationID;
+                return data.rationID === rationID;
             })
+        };
+        ration_glj.prototype.getGatherGljArrByRations = function (rations) {
+            let result = [];
+            let findGlj = function (sourceGlj, gljArr) {
+                gljArr.forEach(function (glj) {
+                    if (glj.projectGLJID === sourceGlj.projectGLJID) {
+                        return glj
+                    }
+                });
+                return null;
+            }
+            for (let ration of rations) {
+                let rationGljs = this.getGljArrByRation(ration.ID);
+                for (let glj of rationGljs) {
+                    let sameGlj = findGlj(glj, result);
+                    if (!sameGlj) {
+                        result.push(glj);
+                    } else {
+                        sameGlj.quantity = sameGlj.quantity + (glj.quantity * ration.quantity).toDecimal(4);
+                    }
+                }
+            }
+            return result;
         }
 
         // 提交数据后返回数据处理