Yes this is possible. The easiest way is by using the eval();
.
HTML
<input type="text" id="calculator" />
<div id="result"></div>
javascript
var input = document.getElementById('calculator');
var result = document.getElementById('result');
input.addEventListener('keyup', calcular);
function calcular(){
var conta = eval(this.value);
result.innerHTML = conta;
}
The example above grabs an event receiver keyup
and runs a function each time a key is released (keyup).
This function runs the eval()
that in the background runs this string as code.
There are other safer and more laborious ways, this implies regex to detect operators like division, multiplication, etc. But I think this example answers the question.
Without eval()
:
I have to leave a parentesis: Eval() is one of the most powerful tools of Javascript and may be very useful, but in some cases raises security problems.
(More on that in this answer)
If you want to do the same without Eval, the code is much more extensive. Out of curiosity I made by hand a code to solve this. You may be able to save a few lines but it won’t be much smaller without using Eval(). However, this example (http://jsfiddle.net/n34PT/) is Eval-free:
var input = document.getElementById('calculator');
input.addEventListener('keyup', calcular);
function calcular(e) {
calculadora(e.target.value);
}
var conta = 0;
var operadores = ['*', '/', '+', '-', ];
var operacoes = [
function (a, b) {
return a * b;
},
function (a, b) {
return a / b;
},
function (a, b) {
return a + b;
},
function (a, b) {
return a - b;
}];
var stop = 0;
function resolverParentesis(eq) {
return eq.replace(/\(.*\)/, function (match) {
return calculadora(match.substring(1, match.length - 1));
});
}
function calculadora(pedido) {
if (pedido.match(/[*\/+\-]$/)) return;
var pedido = pedido.replace(/\s/g, '');
pedido = resolverParentesis(pedido);
if (!/[*\/+\-]/.test(pedido)) return resultado(pedido);
var regex = /[*\/]/.test(pedido) ? new RegExp("([^\/*+\-]*[*\/][^\/*+\-]*)") : new RegExp("([^\/*+\-]*[+\-][^\/*+\-]*)");
pedido = processar(pedido, regex);
if (/[*\/+\-]/.test(pedido)) return calculadora(pedido);
return resultado(pedido);
}
function processar(input, regex) {
return input.replace(regex, function (str) {
var op = str.match(/([*\/+\-])/)[0];
var pedacos = str.split(op);
var fn = operacoes[operadores.indexOf(op)];
return fn(pedacos[0] * 1, pedacos[1] * 1);
});
}
function resultado(conta){
var result = document.getElementById('result');
result.innerHTML = conta
}
About the syntax tree, this other issue here from SOPT has some information that may be useful. It does not use the same language, but the question and answer reading may provide some intuitions important about the workaround @hugomg suggested. :)
– Luiz Vieira
Hugo, the Eval can be very useful as in the case of this question. But to complete the my answer I put together a version without.
– Sergio
In case you create a parser as suggested here in this answer, it is worth a look at the following tools: jison, esprima and Peg.
– bfavaretto