1 /*
  2 * Copyright (C) 2014 Nonki Takkahashi. All rights reserved.
  3 *
  4 * History:
  5 *  0.1 2014-01-10 Created.
  6 */
  7 
  8 /**
  9  * @fileOverview Paresr - Mathematic Expression Parser Object
 10  * @version 0.1
 11  * @author Nonki Takahashi
 12  */
 13 
 14 /**
 15  * onCalc Function - Calc Button Handler
 16  */
 17 function onCalc() {
 18 	var input = document.calculator.expression.value;
 19 	var expr = new Expression(input);
 20 	var output = document.getElementById("result");
 21 	output.innerHTML = output.innerHTML + input + "=" + expr.expression() + "<br>";
 22 };
 23 
 24 /**
 25  * Mathematic Expression Parser Object
 26  * @class Represents Parser Object
 27  * @this {Expression}
 28  * @param {String} src source string
 29  * @since 0.1
 30  */
 31 Expression = function(src) {
 32 	this.value = 0;
 33 	/* inherit the methods of class Lex */
 34 	Lex.call(this, src);
 35 };
 36 Expression.prototype = new Lex();
 37 
 38 /**
 39  * Runner for Expression
 40  * @param {String} src source string
 41  * @return {Float} calculated value
 42  * @since 0.1
 43  */
 44 Expression.prototype.run = function(n, match, parser) {
 45 	var retval;
 46 	switch (parser) {
 47 		case "expression" :
 48 			retval = match[0];
 49 			for (var i = 2; i <= n; i += 2)
 50 				switch (match[i - 1]) {
 51 					case "+" :
 52 						retval += match[i];
 53 						break;
 54 					case "-" :
 55 						retval -= match[i];
 56 				}
 57 			break;
 58 		case "term" :
 59 			retval = match[0];
 60 			for (var i = 2; i <= n; i += 2)
 61 				switch (match[i - 1]) {
 62 					case "*" :
 63 						retval *= match[i];
 64 						break;
 65 					case "/" :
 66 						retval /= match[i];
 67 				}
 68 			break;
 69 		case "factor" :
 70 			if (match[0] == "(")
 71 				retval = match[1];
 72 			else
 73 				retval = match[0];
 74 			break;
 75 		case "integer" :
 76 		case "real" :
 77 			retval = new String();
 78 			for (var i = 0; i <= n; i++)
 79 				if (match[i])
 80 					retval += match[i];
 81 			retval = parseFloat(retval);
 82 			break;
 83 	};
 84 	return retval;
 85 };
 86 
 87 /**
 88  * Parse Expression<br>
 89  * expression = term, {('+' | '-'), term};
 90  * @return {Float} calculated value
 91  * @since 0.1
 92  */
 93 Expression.prototype.expression = function() {
 94 	var match = [];
 95 	var n = 0;
 96 	this.push();
 97 	match[n] = this.term();
 98 	if (!match[n]) {
 99 		this.pop(true);
100 		return null;
101 	}
102 	this.pop(false);
103 	while (match[n]) {
104 		this.push();
105 		match[++n] = this.ch("+");
106 		if (!match[n])
107 			match[n] = this.ch("-");
108 		if (match[n])
109 			match[++n] = this.term();
110 		if (match[n])
111 			this.pop(false);
112 		else
113 			this.pop(true);
114 	}
115 	return this.run(n, match, "expression");
116 };
117 
118 /**
119  * Parse Term<br>
120  * term = factor, {('*' | '/'), factor};
121  * @return {Float} calculated value
122  * @since 0.1
123  */
124 Expression.prototype.term = function() {
125 	var match = [];
126 	var n = 0;
127 	this.push();
128 	match[n] = this.factor();
129 	if (!match[n]) {
130 		this.pop(true);
131 		return null;
132 	}
133 	this.pop(false);
134 	while (match[n]) {
135 		this.push();
136 		match[++n] = this.ch("*");
137 		if (!match[n])
138 			match[n] = this.ch("/");
139 		if (match[n])
140 			match[++n] = this.factor();
141 		if (match[n])
142 			this.pop(false);
143 		else
144 			this.pop(true);
145 	}
146 	return this.run(n, match, "term");
147 };
148 
149 /**
150  * Parse Factor<br>
151  * factor = ('(', expression, ')') | real | integer;
152  * @return {Float} calculated value
153  * @since 0.1
154  */
155 Expression.prototype.factor = function() {
156 	var match = [];
157 	var n = 0;
158 	this.push();
159 	match[n] = this.ch("(");
160 	if (match[n])
161 		match[++n] = this.expression();
162 	if (match[n])
163 		match[++n] = this.ch(")");
164 	if (match[n])
165 		this.pop(false);
166 	else {
167 		this.pop(true);
168 		n = 0;
169 		match[n] = this.real();
170 	}
171 	if (!match[n]) {
172 		n = 0;
173 		match[n] = this.integer();
174 	}
175 	if (!match[n])
176 		return null;
177 	return this.run(n, match, "factor");
178 };
179 
180 /**
181  * Parse Real<br>
182  * real = ((integer, '.') | (('.', digit)), {digit};
183  * @return {Float} calculated value
184  * @since 0.1
185  */
186 Expression.prototype.real = function() {
187 	var match = [];
188 	var n = 0;
189 	this.push();
190 	match[n] = this.integer();
191 	if (match[n])
192 		match[++n] = this.ch(".");
193 	if (match[n])
194 		this.pop(false);
195 	else {
196 		this.pop(true);
197 		this.push();
198 		n = 0;
199 		match[n] = this.ch(".");
200 		if (match[n])
201 			match[++n] = this.integer();
202 		if (match[n])
203 			this.pop(false);
204 		else
205 			this.pop(true);
206 	}
207 	if (!match[n])
208 		return null;
209 	while (match[n]) {
210 		match[++n] = this.digit();
211 	}
212 	return this.run(n, match, "real");
213 };
214 
215 /**
216  * Parse Integer<br>
217  * integer = ['-'], digit, {digit};
218  * @return {Float} calculated value
219  * @since 0.1
220  */
221 Expression.prototype.integer = function() {
222 	var match = [];
223 	var n = 0;
224 	this.push();
225 	match[n] = this.ch("-");
226 	match[++n] = this.digit();
227 	if (!match[n]) {
228 		this.pop(true);
229 		return null;
230 	}
231 	this.pop(false);
232 	while (match[n]) {
233 		match[++n] = this.digit();
234 	}
235 	return this.run(n, match, "integer");
236 };
237