Arithmetic evaluation: Difference between revisions

m
→‎{{header|FutureBasic}}: Update image file
m (→‎{{header|REXX}}: removed extra blanks at the top of the REXX section header. -- ~~~~)
m (→‎{{header|FutureBasic}}: Update image file)
 
(151 intermediate revisions by 54 users not shown)
Line 1:
{{task}}[[Category:Recursion]]
{{task}}Create a program which parses and evaluates arithmetic expressions.
 
;Requirements:
Line 8:
* The four symbols + - * / must be supported as binary operators with conventional precedence rules.
* Precedence-control parentheses must also be supported.
<br>
 
;Note:
Line 14 ⟶ 15:
* Multiplication/Division (left to right)
* Addition/Subtraction (left to right)
<br>
 
 
;C.f:
Line 20 ⟶ 21:
* [[Parsing/RPN calculator algorithm]].
* [[Parsing/RPN to infix conversion]].
<br><br>
 
=={{header|11l}}==
[[wp:Pratt parser|Pratt parser]]
<syntaxhighlight lang="11l">T Symbol
String id
Int lbp
Int nud_bp
Int led_bp
(ASTNode -> ASTNode) nud
((ASTNode, ASTNode) -> ASTNode) led
 
F set_nud_bp(nud_bp, nud)
.nud_bp = nud_bp
.nud = nud
 
F set_led_bp(led_bp, led)
.led_bp = led_bp
.led = led
 
T ASTNode
Symbol& symbol
Int value
ASTNode? first_child
ASTNode? second_child
 
F eval()
S .symbol.id
‘(number)’
R .value
‘+’
R .first_child.eval() + .second_child.eval()
‘-’
R I .second_child == N {-.first_child.eval()} E .first_child.eval() - .second_child.eval()
‘*’
R .first_child.eval() * .second_child.eval()
‘/’
R .first_child.eval() / .second_child.eval()
‘(’
R .first_child.eval()
E
assert(0B)
R 0
 
[String = Symbol] symbol_table
[String] tokens
V tokeni = -1
ASTNode token_node
 
F advance(sid = ‘’)
I sid != ‘’
assert(:token_node.symbol.id == sid)
:tokeni++
:token_node = ASTNode()
I :tokeni == :tokens.len
:token_node.symbol = :symbol_table[‘(end)’]
R
V token = :tokens[:tokeni]
:token_node.symbol = :symbol_table[I token.is_digit() {‘(number)’} E token]
I token.is_digit()
:token_node.value = Int(token)
 
F expression(rbp = 0)
ASTNode t = move(:token_node)
advance()
V left = t.symbol.nud(move(t))
L rbp < :token_node.symbol.lbp
t = move(:token_node)
advance()
left = t.symbol.led(t, move(left))
R left
 
F parse(expr_str) -> ASTNode
:tokens = re:‘\s*(\d+|.)’.find_strings(expr_str)
:tokeni = -1
advance()
R expression()
 
F symbol(id, bp = 0) -> &
I !(id C :symbol_table)
V s = Symbol()
s.id = id
s.lbp = bp
:symbol_table[id] = s
R :symbol_table[id]
 
F infix(id, bp)
F led(ASTNode self, ASTNode left)
self.first_child = left
self.second_child = expression(self.symbol.led_bp)
R self
symbol(id, bp).set_led_bp(bp, led)
 
F prefix(id, bp)
F nud(ASTNode self)
self.first_child = expression(self.symbol.nud_bp)
R self
symbol(id).set_nud_bp(bp, nud)
 
infix(‘+’, 1)
infix(‘-’, 1)
infix(‘*’, 2)
infix(‘/’, 2)
prefix(‘-’, 3)
 
F nud(ASTNode self)
R self
symbol(‘(number)’).nud = nud
symbol(‘(end)’)
 
F nud_parens(ASTNode self)
V expr = expression()
advance(‘)’)
R expr
symbol(‘(’).nud = nud_parens
symbol(‘)’)
 
L(expr_str) [‘-2 / 2 + 4 + 3 * 2’,
‘2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10’]
print(expr_str‘ = ’parse(expr_str).eval())</syntaxhighlight>
{{out}}
<pre>
-2 / 2 + 4 + 3 * 2 = 9
2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10 = 7000
</pre>
 
=={{header|Ada}}==
Line 28 ⟶ 154:
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-1.18.0/algol68g-1.18.0-9h.tiny.el5.centos.fc11.i386.rpm/download 1.18.0-9h.tiny]}}
{{wont work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d] - A68RS has not implemented forward declarations}}
<langsyntaxhighlight lang="algol68">INT base=10;
MODE FIXED = LONG REAL; # numbers in the format 9,999.999 #
 
Line 169 ⟶ 295:
index error:
printf(("Stack over flow"))
)</langsyntaxhighlight>
{{out}}
Output:
<pre>
euler's number is about: 2.71828182845899446428546958
</pre>
 
=={{header|Amazing Hopper}}==
Hopper no soporta números muy grandes, por decisión de diseño, pero es posible realizar una aproximación aplicando el Límite de Euler para calcular un factorial de un número real, hecho para uno de los ejemplos.
<syntaxhighlight lang="c">
#include <basico.h>
 
#proto verificarconstante(_X_)
#synon _verificarconstante se verifica constante en
 
#proto verificarfunción(_X_)
#synon _verificarfunción se verifica función en
 
algoritmo
 
pila de trabajo 50
 
números (largo de datos)
decimales '13'
preparar datos(DATA_EXPRESIONES)
obtener tamaño de datos, guardar en 'largo de datos'
imprimir ("Negativos deben escribirse entre parentesis\nEjemplo: (-3)\n\n")
iterar
matrices ( pila, p, q )
cadenas (expresión)
obtener dato, copiar en 'expresión'
ir a subs ( convierte a matriz --> convierte a notación polaca \
--> evalúa expresión --> despliega resultados )
--largo de datos
mientras ' largo de datos'
 
terminar
 
subrutinas
 
convierte a matriz:
 
argumentos 'expr'
transformar(" ","",\
transformar("(-","(0-",expr)), guardar en 'expr'
 
l=0, #( l = len(expr) )
v="", num="", cte=""
para cada caracter (v, expr, l)
cuando ( #(typechar(v,"digit") || v==".")){
num, v, concatenar esto, guardar en 'num'
continuar
}
cuando ( #(typechar(v,"alpha") )){
cte, v, concatenar esto, guardar en 'cte'
continuar
}
cuando (num) {num, meter en 'q', num=""}
cuando (cte) {cte, meter en 'q', cte=""}
v, meter en 'q'
siguiente
cuando (num) {num, meter en 'q'}
cuando (cte) {cte, meter en 'q'}
"(", meter en 'pila'
")", meter en 'q'
// imprimir( "Q = {", q, "}\n" )
retornar
 
convierte a notación polaca:
 
l="", m=""
iterar mientras '#( not(is empty(q)) )'
sw = 1
 
///imprimir("P = ",p,"\nQ = ",q,"\nPILA = ",pila,NL)
 
extraer tope 'q' para 'l'
// ¿es un operando?
cuando ' #(not( occurs(l,"+-*^/)(%") )) ' {
si ' se verifica constante en (l) '
meter en 'p'
sino si ' se verifica función en (l) '
l, meter en 'pila'
sino
#( number(l) ), meter en 'p'
fin si
continuar
}
// es un simbolo...
 
// es un parentesis izquierdo?
cuando ( #( l=="(" ) ) {
l, meter en 'pila'
continuar
}
// es un operador?
cuando ( #( occurs(l,"+-*^/%")) ) {
iterar mientras ' sw '
extraer cabeza 'pila' para 'm'
 
cuando ' #(m=="(") '{
m,l, apilar en 'pila'
sw=0, continuar
}
cuando ' #(l=="^") '{
si ' #(m=="^") '
//m,l, apilar en 'p'
m, meter en 'p'
sino
m,l, apilar en 'pila'
sw=0
fin si, continuar
}
cuando ' #(l=="*") ' {
si ' #(occurs(m, "^*/%"))'
m, meter en 'p'
sino
m,l, apilar en 'pila'
sw=0
fin si, continuar
}
//cuando ' #(l=="/") ' {
// decisión de diseño para resto módulo
cuando ' #( occurs(l,"/%")) ' {
si ' #( occurs(m, "/^*%") )'
m, meter en 'p'
l, meter en 'pila'
sino
m,l, apilar en 'pila'
fin si
sw=0, continuar
}
 
cuando ' #(occurs(l, "+-"))' {
m, meter en 'p'
// saber si ya hay un símbolo "-" en pila
tmp=0
tope(pila), mover a 'tmp'
si ' #( occurs(tmp,"+-") ) '
extraer cabeza (pila)
meter en 'p'
fin si
l, meter en 'pila'
sw=0
}
reiterar
si ' #( length (pila)==0 ) '
"(", meter en 'pila'
fin si
continuar
}
// es un paréntesis derecho?
cuando( #(l==")") ) {
extraer cabeza (pila) para 'm'
iterar mientras ' #( m<>"(") '
m, meter en 'p'
extraer cabeza 'pila' para 'm'
reiterar
}
reiterar
retornar
 
evalúa expresión:
 
l = " ", a=0, b=0
iterar mientras ' #( not(is empty(p)) ) '
extraer tope 'p' para 'l'
si ' es numérico (l) '
l, meter en 'pila'
sino
si ' se verifica función en (l) '
extraer cabeza 'pila' para 'b'
seleccionar 'l'
caso ("sqrt"){ #(sqrt(b)), salir }
caso ("log"){ #(log10(b)), salir }
caso ("ln"){ #(log(b)), salir }
caso ("fact"){
si ' #(int(b)<>b) ' // límite de Euler
x=0,i=2, xb=1,
// aproximación muy burda.
#basic{
b = b + 1
x = fact(163)*(163^b)
xb = b*(b+1)
while( i<=163 )
xb = xb * ( i+b )
i+=1
wend
x/xb
}
sino // normal
#(fact(b))
fin si
salir
}
fin seleccionar
sino
extraer cabeza 'pila' para 'b'
extraer cabeza 'pila' para 'a'
seleccionar 'l'
caso ("+"){ #(a+b), salir }
caso ("-"){ #(a-b), salir }
caso ("*"){ #(a*b), salir }
// n/0 = inf, no es necesario detectar esto:
caso ("/"){ #(a/b), salir }
caso ("^"){ #(a^b), salir }
caso ("%"){ #(a%b), salir }
fin seleccionar
fin si
meter en 'pila'
fin si
 
reiterar
 
retornar
 
despliega resultados:
 
imprimir(expresión," : ", \
tomar si( #(length(pila)==1),pila, \
#(utf8("expresión mal formada!"))), NL)
retornar
 
verificar constante (x)
seleccionar 'x'
caso ("pi"){ M_PI, 1, salir }
caso ("e") { M_E, 1, salir }
caso ("phi"){ M_PHI, 1, salir }
// etcétera...
caso por defecto{ 0, salir }
fin seleccionar
retornar
 
verificar función (f)
seleccionar 'f'
caso ("sqrt"){ '1', salir }
caso ("log"){ '1', salir }
caso ("ln"){ '1', salir }
caso ("fact"){ '1', salir }
// etcétera...
caso por defecto { '0', salir }
fin seleccionar
retornar
 
DATA_EXPRESIONES:
datos("((30+4.5) * ( 7 / 9.67 )+3)-4*(-1)") //31.9741468459168
datos("1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1") // 60!
datos("(1 - 5) * 2 / (20 + 1)") // -8/21
datos("(3 * 2) - (1 + 2) / (4") // error!
datos("(3 * 2) a - (1 + 2) / 4") // error!
datos("(6^2)*2/3") //24
datos("6^2*2/3") //24
datos("(6^2)*2/0") //inf
datos("2 * (3 + ((5) / (7 - 11)))") // 3.5
datos("1 - 5 * 2 / 20 + 1") //1,5!
datos ("(1 + 2) * 10 / 100") // 0.3
datos("1+3.78") // 4.78
datos("2.5 * 2 + 2 * pi") // 11.28
datos("1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10") // 71
datos("1+1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+1/15)/14)/13)/12)/11)/10)/9)/8)/7)/6)/5)/4)/3)/2") // 2.7182818284589946
datos("((11+15)*15)*2-(3)*4*1") // 768
datos(" 2*(-3)-(-4)+(-0.25)") //-2.25
datos(" 2-25 % 3+1") // 2
datos(" 2-(25 % 3)+1") // 2
datos(" (2-25) % (3+1)") // -3
datos(" 2- 25 % 3 % 2") // 1
datos(" 2- 25 / 3 % 2") // 1.66666
datos(" 2- ((25 / 3) % 2)") // 1.66666
datos(" 2- 25 / 3 / 2") // 2.166666
datos(" (-23) %3") // -2
datos(" (6*pi-1)^0.5-e") // 1,506591651...
datos("2^2^3^4")
datos("(4-2*phi)*pi") // 2,3999632297286
datos("( (1+sqrt(5))/2)^(2/pi)") // 1.3584562741830
datos("1-(1+ln(ln(2)))/ln(2)") // 0.0860713320559
datos("pi / (2 * ln(1+sqrt(2)))") // 1,7822139781 ....
datos("( (e^(pi/8)) * sqrt(pi)) /(4 * (2^(3/4)) * (fact(1/4))^2) ") //0,47494 93799...
datos(" fact(1/2)") // 0.906402477055...
back
</syntaxhighlight>
{{out}}
<pre>
Negativos deben escribirse entre parentesis
Ejemplo: (-3)
 
((30+4.5) * ( 7 / 9.67 )+3)-4*(-1) : 31.9741468459168
1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1 : 60.0000000000000
(1 - 5) * 2 / (20 + 1) : -0.3809523809524
(3 * 2) - (1 + 2) / (4 : expresión mal formada!
(3 * 2) a - (1 + 2) / 4 : expresión mal formada!
(6^2)*2/3 : 24.0000000000000
6^2*2/3 : 24.0000000000000
(6^2)*2/0 : inf
2 * (3 + ((5) / (7 - 11))) : 3.5000000000000
1 - 5 * 2 / 20 + 1 : 1.5000000000000
(1 + 2) * 10 / 100 : 0.3000000000000
1+3.78 : 4.7800000000000
2.5 * 2 + 2 * pi : 11.2831853071796
1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10 : 71.0000000000000
1+1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+1/15)/14)/13)/12)/11)/10)/9)/8)/7)/6)/5)/4)/3)/2 : 2.7182818284590
((11+15)*15)*2-(3)*4*1 : 768.0000000000000
2*(-3)-(-4)+(-0.25) : -2.2500000000000
2-25 % 3+1 : 2.0000000000000
2-(25 % 3)+1 : 2.0000000000000
(2-25) % (3+1) : -3.0000000000000
2- 25 % 3 % 2 : 1.0000000000000
2- 25 / 3 % 2 : 1.6666666666667
2- ((25 / 3) % 2) : 1.6666666666667
2- 25 / 3 / 2 : -2.1666666666667
(-23) %3 : -2.0000000000000
(6*pi-1)^0.5-e : 1.5065916514856
2^2^3^4 : 16777216.0000000000000
(4-2*phi)*pi : 2.3999632297286
( (1+sqrt(5))/2)^(2/pi) : 1.3584562741830
1-(1+ln(ln(2)))/ln(2) : 0.0860713320559
pi / (2 * ln(1+sqrt(2))) : 1.7822139781915
( (e^(pi/8)) * sqrt(pi)) /(4 * (2^(3/4)) * (fact(1/4))^2) : 0.4831858606252
fact(1/2) : 0.8761319893678
 
</pre>
 
=={{header|AutoHotkey}}==
{{works with|AutoHotkey_L}}
<syntaxhighlight lang="autohotkey">/*
<lang AutoHotkey>/*
hand coded recursive descent parser
expr : term ( ( PLUS | MINUS ) term )* ;
Line 326 ⟶ 782:
}
 
#include calclex.ahk</langsyntaxhighlight>
calclex.ahk<langsyntaxhighlight AutoHotkeylang="autohotkey">tokenize(string, lexer)
{
stringo := string ; store original string
Line 393 ⟶ 849:
string := "pos= " token.pos "`nvalue= " token.value "`ntype= " token.type
return string
}</langsyntaxhighlight>
 
=={{header|BBC BASIC}}==
{{works with|BBC BASIC for Windows}}
<langsyntaxhighlight lang="bbcbasic"> Expr$ = "1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10"
PRINT "Input = " Expr$
AST$ = FNast(Expr$)
Line 454 ⟶ 910:
ENDIF
UNTIL FALSE
= num$</langsyntaxhighlight>
{{out}}
Output:
<pre>
Input = 1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10
Line 466 ⟶ 922:
 
=={{header|C++}}==
{{works with|g++|clang++}}
This version does not require boost.
It works by:
- converting infix strings to postfix strings using shunting yard algorithm
- converting postfix expression to list of tokens
- builds AST bottom up from list of tokens
- evaluates expression tree by performing postorder traversal.
 
<syntaxhighlight lang="cpp">
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
 
template <class T>
class stack {
private:
vector<T> st;
T sentinel;
public:
stack() { sentinel = T(); }
bool empty() { return st.empty(); }
void push(T info) { st.push_back(info); }
T& top() {
if (!st.empty()) {
return st.back();
}
return sentinel;
}
T pop() {
T ret = top();
if (!st.empty()) st.pop_back();
return ret;
}
};
 
//determine associativity of operator, returns true if left, false if right
bool leftAssociate(char c) {
switch (c) {
case '^': return false;
case '*': return true;
case '/': return true;
case '%': return true;
case '+': return true;
case '-': return true;
default:
break;
}
return false;
}
 
//determins precedence level of operator
int precedence(char c) {
switch (c) {
case '^': return 7;
case '*': return 5;
case '/': return 5;
case '%': return 5;
case '+': return 3;
case '-': return 3;
default:
break;
}
return 0;
}
 
//converts infix expression string to postfix expression string
string shuntingYard(string expr) {
stack<char> ops;
string output;
for (char c : expr) {
if (c == '(') {
ops.push(c);
} else if (c == '+' || c == '-' || c == '*' || c == '/' || c == '^' || c == '%') {
if (precedence(c) < precedence(ops.top()) ||
(precedence(c) == precedence(ops.top()) && leftAssociate(c))) {
output.push_back(' ');
output.push_back(ops.pop());
output.push_back(' ');
ops.push(c);
} else {
ops.push(c);
output.push_back(' ');
}
} else if (c == ')') {
while (!ops.empty()) {
if (ops.top() != '(') {
output.push_back(ops.pop());
} else {
ops.pop();
break;
}
}
} else {
output.push_back(c);
}
}
while (!ops.empty())
if (ops.top() != '(')
output.push_back(ops.pop());
else ops.pop();
cout<<"Postfix: "<<output<<endl;
return output;
}
 
struct Token {
int type;
union {
double num;
char op;
};
Token(double n) : type(0), num(n) { }
Token(char c) : type(1), op(c) { }
};
 
//converts postfix expression string to vector of tokens
vector<Token> lex(string pfExpr) {
vector<Token> tokens;
for (int i = 0; i < pfExpr.size(); i++) {
char c = pfExpr[i];
if (isdigit(c)) {
string num;
do {
num.push_back(c);
c = pfExpr[++i];
} while (i < pfExpr.size() && isdigit(c));
tokens.push_back(Token(stof(num)));
i--;
continue;
} else if (c == '+' || c == '-' || c == '*' || c == '/' || c == '^' || c == '%') {
tokens.push_back(Token(c));
}
}
return tokens;
}
 
//structure used for nodes of expression tree
struct node {
Token token;
node* left;
node* right;
node(Token tok) : token(tok), left(nullptr), right(nullptr) { }
};
 
//builds expression tree from vector of tokens
node* buildTree(vector<Token> tokens) {
cout<<"Building Expression Tree: "<<endl;
stack<node*> sf;
for (int i = 0; i < tokens.size(); i++) {
Token c = tokens[i];
if (c.type == 1) {
node* x = new node(c);
x->right = sf.pop();
x->left = sf.pop();
sf.push(x);
cout<<"Push Operator Node: "<<sf.top()->token.op<<endl;
} else
if (c.type == 0) {
sf.push(new node(c));
cout<<"Push Value Node: "<<c.num<<endl;
continue;
}
}
return sf.top();
}
 
//evaluate expression tree, while anotating steps being performed.
int recd = 0;
double eval(node* x) {
recd++;
if (x == nullptr) {
recd--;
return 0;
}
if (x->token.type == 0) {
for (int i = 0; i < recd; i++) cout<<" ";
cout<<"Value Node: "<<x->token.num<<endl;
recd--;
return x->token.num;
}
if (x->token.type == 1) {
for (int i = 0; i < recd; i++) cout<<" ";
cout<<"Operator Node: "<<x->token.op<<endl;
double lhs = eval(x->left);
double rhs = eval(x->right);
for (int i = 0; i < recd; i++) cout<<" ";
cout<<lhs<<" "<<x->token.op<<" "<<rhs<<endl;
recd--;
switch (x->token.op) {
case '^': return pow(lhs, rhs);
case '*': return lhs*rhs;
case '/':
if (rhs == 0) {
cout<<"Error: divide by zero."<<endl;
} else
return lhs/rhs;
case '%':
return (int)lhs % (int)rhs;
case '+': return lhs+rhs;
case '-': return lhs-rhs;
default:
break;
}
}
return 0;
}
 
int main() {
string expr = "3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3";
cout<<eval(buildTree(lex(shuntingYard(expr))))<<endl;
return 0;
}
 
Output:
Postfix: 3 4 2 * 1 5 - 2 3^^/+
Building Expression Tree:
Push Value Node: 3
Push Value Node: 4
Push Value Node: 2
Push Operator Node: *
Push Value Node: 1
Push Value Node: 5
Push Operator Node: -
Push Value Node: 2
Push Value Node: 3
Push Operator Node: ^
Push Operator Node: ^
Push Operator Node: /
Push Operator Node: +
Operator Node: +
Value Node: 3
Operator Node: /
Operator Node: *
Value Node: 4
Value Node: 2
4 * 2
Operator Node: ^
Operator Node: -
Value Node: 1
Value Node: 5
1 - 5
Operator Node: ^
Value Node: 2
Value Node: 3
2 ^ 3
-4 ^ 8
8 / 65536
3 + 0.00012207
3.00012
</syntaxhighlight>
 
{{Works with|g++|4.1.2 20061115 (prerelease) (SUSE Linux)}}
 
{{libheader|Boost.Spirit|1.8.4}}
<langsyntaxhighlight lang="cpp"> #include <boost/spirit.hpp>
#include <boost/spirit/tree/ast.hpp>
#include <string>
Line 584 ⟶ 1,291:
}
}
};</langsyntaxhighlight>
 
=={{header|Clojure}}==
<langsyntaxhighlight Clojurelang="clojure">(def precedence '{* 0, / 0
+ 1, - 1})
 
Line 639 ⟶ 1,346:
 
user> (evaluate "1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1")
60</langsyntaxhighlight>
 
=={{header|Common Lisp}}==
Line 657 ⟶ 1,364:
This implementation can read integers, and produce integral and rational values.
 
<langsyntaxhighlight lang="lisp">(defun tokenize-stream (stream)
(labels ((whitespace-p (char)
(find char #(#\space #\newline #\return #\tab)))
Line 668 ⟶ 1,375:
finally (return (parse-integer (coerce digits 'string))))))
(consume-whitespace)
(let* ((c (peek-char nil stream nil nil)))
(let ( (token (case c
((nil) nil)
((#\() :lparen)
((#\)) :rparen)
((#\*) '*)
((#\/) '/)
((#\+) '+)
((#\-) '-)
(otherwise
(unless (digit-char-p c)
Line 686 ⟶ 1,393:
(unless (or (null token) (integerp token))
(read-char stream))
token))))
 
(defun group-parentheses (tokens &optional (delimited nil))
Line 696 ⟶ 1,403:
(let ((token (pop tokens)))
(case token
((:lparen)
(multiple-value-bind (group remaining-tokens)
(group-parentheses tokens t)
(setf new-tokens (cons group new-tokens)
tokens remaining-tokens)))
((:rparen)
(if (not delimited)
(cerror "Ignore it." "Unexpected right parenthesis.")
Line 742 ⟶ 1,449:
(loop for token = (tokenize-stream in)
until (null token)
collect token)))))))</langsyntaxhighlight>
Examples
Line 786 ⟶ 1,493:
=={{header|D}}==
After the AST tree is constructed, a visitor pattern is used to display the AST structure and calculate the expression value.
<langsyntaxhighlight lang="d">import std.stdio, std.string, std.ascii, std.conv, std.array,
std.exception, std.traits;
 
Line 792 ⟶ 1,499:
T[] data;
alias data this;
void push(T top) pure nothrow @safe { data ~= top; }
 
T pop(bool discard = true)() pure @nogc @safe {
immutable static exc = new immutable(Exception)("Stack Empty");
if (data.empty)
throw new Exception("Stack Empty")exc;
auto top = data.back[$ - 1];
static if (discard)
data.popBack();
return top;
}
Line 808 ⟶ 1,516:
immutable opPrec = [ 0, -9, -9, 1, 1, 2, 2];
 
abstract class Visitor { void visit(XP e) pure @safe; }
 
final class XP {
immutable Type type;
immutable string str;
immutable int pos; // Optional, to dispalydisplay AST struct.
XP LHS, RHS;
 
this(string s=")", int p = -1) pure nothrow @safe {
str = s;
pos = p;
typeauto localType = Type.Num;
foreach_reverse (immutable t; [EnumMembers!Type[1 .. $]])
if (opChar[t] == s)
typelocalType = t;
this.type = localType;
}
 
override int opCmp(Object other) pure @safe {
auto rhs = cast(XP)other;
enforce(rhs !is null);
Line 831 ⟶ 1,540:
}
 
void accept(Visitor v) pure @safe { v.visit(this); }
}
 
Line 840 ⟶ 1,549:
int xpHead, xpTail;
 
void joinXP(XP x) pure @safe {
x.RHS = num.pop();
x.LHS = num.pop();
num.push(x);
}
 
string nextToken() pure @safe {
while (xpHead < xpr.length && xpr[xpHead] == ' ')
xpHead++; // Skip spc.
Line 857 ⟶ 1,566:
return token;
default: // Should be number.
if (token[0].isDigit()) {
while (xpTail < xpr.length && xpr[xpTail].isDigit())
xpTail++;
Line 869 ⟶ 1,578:
} // End nextToken.
 
AST parse(in string s) /*@safe*/ {
bool expectingOP;
xpr = s;
Line 877 ⟶ 1,586:
root = null;
opr.push(new XP); // CBkt, prevent evaluate null OP precedence.
while ((token = nextToken()) !is null) {
XP tokenXP = new XP(token, xpHead);
if (expectingOP) { // Process OP-alike XP.
switch (token) {
case ")":
while (opr.pop!false().type != Type.OBkt)
joinXP(opr.pop());
opr.pop();
expectingOP = true;
break;
case "+", "-", "*", "/":
while (tokenXP <= opr.pop!false())
joinXP(opr.pop());
opr.push(tokenXP);
Line 915 ⟶ 1,624:
 
while (opr.length > 1) // Join pending Op.
joinXP(opr.pop());
} catch(Exception e) {
writefln("%s\n%s\n%s^", e.msg, xpr, " ".replicate(xpHead));
Line 923 ⟶ 1,632:
 
if (num.length != 1) { // Should be one XP left.
writefln("Parse Error...").writefln;
root = null;
} else {
root = num.pop();
}
return this;
Line 934 ⟶ 1,643:
// To display AST fancy struct.
void ins(ref char[][] s, in string v, in int p, in int l)
pure nothrow @safe {
if (l + 1 > s.length)
s.length++;
while (s[l].length < p + v.length + 1)
s[l] ~= " ";
s[l][p .. p + v.length] = v[];
}
 
Line 947 ⟶ 1,656:
char[][] Tree;
 
static void opCall(AST a) @safe {
if (a && a.root) {
auto c = new CalcVis;
Line 967 ⟶ 1,676:
}
foreach (const t; c.Tree)
writefln(t).writefln;
writefln("\n%s ==>\n%s = %s", a.xpr, c.resultStr, c.result);
} else
writefln("Evalute invalid or null Expression.").writefln;
}
 
// Calc. the value, display AST struct and eval order.
override void visit(XP xp) @safe {
ins(Tree, xp.str, xp.pos, level);
level++;
if (xp.type == Type.Num) {
resultStr ~= xp.str;
result = to!int(xp.str).to!int;
} else {
resultStr ~= "(";
Line 999 ⟶ 1,708:
}
 
void main(string[] args) /*@safe*/ {
immutable exp0 = "1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5" ~
" - 22/(7 + 2*(3 - 1)) - 1)) + 1";
immutable exp = (args.length > 1) ? args[1 .. $].join("' "') : exp0;
(new AST().parse(exp).CalcVis(); // Should be 60.
}</langsyntaxhighlight>
{{out}}
<pre> ........................................................+.
Line 1,021 ⟶ 1,730:
1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1 ==>
((1+(2*(3-((2*(3-2))*((((2-4)*5)-(22/(7+(2*(3-1)))))-1)))))+1) = 60</pre>
=={{header|Delphi}}==
Adaptation of [[Arithmetic Evaluator/Pascal]] for run in Delphi. See [[Arithmetic_evaluation/Delphi]].
 
=={{header|Dyalect}}==
 
<syntaxhighlight lang="dyalect">type Expr = Bin(op, Expr left, Expr right) or Literal(Float val)
with Lookup
 
type Token(val, Char kind) with Lookup
func Token.ToString() => this.val.ToString()
func tokenize(str) {
func isSep(c) =>
c is '+' or '-' or '*' or '/' or ' ' or '\t' or '\n' or '\r' or '(' or ')' or '\0'
var idx = -1
let len = str.Length()
let tokens = []
func next() {
idx += 1
return '\0' when idx >= len
str[idx]
}
while true {
let c = next()
match c {
'\0' => { break },
'+' => tokens.Add(Token(c, '+')),
'-' => tokens.Add(Token(c, '-')),
'*' => tokens.Add(Token(c, '*')),
'/' => tokens.Add(Token(c, '/')),
'(' => tokens.Add(Token(c, '(')),
')' => tokens.Add(Token(c, ')')),
_ => {
let i = idx
while !isSep(next()) { }
idx -= 1
tokens.Add(Token(Float.Parse(str[i..idx]), 'F'))
}
}
}
tokens
}
func parse(tokens) {
var idx = -1
let len = tokens.Length()
let eol = Token(val: nil, kind: 'E')
func pop() {
idx += 1
return eol when idx == len
tokens[idx]
}
func peek() {
let t = pop()
idx -=1
t
}
func expect(kind) {
peek().kind == kind
}
var add_or_sub1
func literal() {
return false when !expect('F')
Expr.Literal(pop().val)
}
func group() {
return false when !expect('(')
pop()
var ret = add_or_sub1()
throw "Invalid group" when !expect(')')
pop()
ret
}
func mul_or_div() {
var fst = group()
fst = literal() when !fst
return fst when !expect('*') && !expect('/')
let op = pop().val
var snd = group()
snd = literal() when !snd
Expr.Bin(op, fst, snd)
}
func add_or_sub() {
let fst = mul_or_div()
return fst when !expect('+') && !expect('-')
let op = pop().val
let snd = mul_or_div()
Expr.Bin(op, fst, snd)
}
add_or_sub1 = add_or_sub
add_or_sub()
}
func exec(ast) {
match ast {
Bin(op, left, right) => {
return exec(left) + exec(right) when op == '+'
return exec(left) - exec(right) when op == '-'
return exec(left) * exec(right) when op == '*'
return exec(left) / exec(right) when op == '/'
},
Literal(value) => value
}
}
func eval(str) {
let tokens = tokenize(str)
let ast = parse(tokens)
exec(ast)
}
print( eval("(1+33.23)*7") )
print( eval("1+33.23*7") )</syntaxhighlight>
 
{{out}}
 
<pre>239.60999999999999
233.60999999999999</pre>
 
=={{header|E}}==
Line 1,026 ⟶ 1,863:
While the task requirements specify not evaluating using the language's built-in eval, they don't say that you have to write your own ''parser''...
 
<langsyntaxhighlight lang="e">def eParser := <elang:syntax.makeEParser>
def LiteralExpr := <elang:evm.makeLiteralExpr>.asType()
def arithEvaluate(expr :String) {
Line 1,043 ⟶ 1,880:
return evalAST(ast)
}</langsyntaxhighlight>
 
Parentheses are handled by the parser.
 
<langsyntaxhighlight lang="e">? arithEvaluate("1 + 2")
# value: 3
 
Line 1,054 ⟶ 1,891:
 
? arithEvaluate("(1 + 2 / 2) * (5 + 5)")
# value: 20.0</langsyntaxhighlight>
 
=={{header|ElenaEasyLang}}==
<syntaxhighlight lang="easylang">
<lang elena>#define std'dictionary'*.
subr nch
#define std'basic'*.
if inp_ind > len inp$[]
#define std'patterns'*.
ch$ = strchar 0
#define ext'io'*.
else
#define ext'convertors'*.
ch$ = inp$[inp_ind]
inp_ind += 1
.
ch = strcode ch$
.
#
subr ntok
while ch$ = " "
nch
.
if ch >= 48 and ch <= 58
tok$ = "n"
s$ = ""
while ch >= 48 and ch <= 58 or ch$ = "."
s$ &= ch$
nch
.
tokv = number s$
elif ch = 0
tok$ = "end of text"
else
tok$ = ch$
nch
.
.
subr init0
astop$[] = [ ]
astleft[] = [ ]
astright[] = [ ]
err = 0
.
proc init s$ . .
inp$[] = strchars s$
inp_ind = 1
nch
ntok
init0
.
proc ast_print nd . .
write "AST:"
for i to len astop$[]
write " ( "
write astop$[i] & " "
write astleft[i] & " "
write astright[i]
write " )"
.
print " Start: " & nd
.
func node .
astop$[] &= ""
astleft[] &= 0
astright[] &= 0
return len astop$[]
.
#
funcdecl parse_expr .
#
func parse_factor .
if tok$ = "n"
nd = node
astop$[nd] = "n"
astleft[nd] = tokv
ntok
elif tok$ = "("
ntok
nd = parse_expr
if tok$ <> ")"
err = 1
print "error: ) expected, got " & tok$
.
ntok
else
err = 1
print "error: factor expected, got " & tok$
.
return nd
.
func parse_term .
ndx = parse_factor
while tok$ = "*" or tok$ = "/"
nd = node
astleft[nd] = ndx
astop$[nd] = tok$
ntok
astright[nd] = parse_factor
ndx = nd
.
return ndx
.
func parse_expr .
ndx = parse_term
while tok$ = "+" or tok$ = "-"
nd = node
astleft[nd] = ndx
astop$[nd] = tok$
ntok
astright[nd] = parse_term
ndx = nd
.
return ndx
.
func parse s$ .
init s$
return parse_expr
.
func eval nd .
if astop$[nd] = "n"
return astleft[nd]
.
le = eval astleft[nd]
ri = eval astright[nd]
a$ = astop$[nd]
if a$ = "+"
return le + ri
elif a$ = "-"
return le - ri
elif a$ = "*"
return le * ri
elif a$ = "/"
return le / ri
.
.
repeat
inp$ = input
until inp$ = ""
print "Inp: " & inp$
nd = parse inp$
ast_print nd
if err = 0
print "Eval: " & eval nd
.
print ""
.
input_data
4 *
4.2 * ((5.3+8)*3 + 4)
2.5 * 2 + 2 * 3.14
</syntaxhighlight>
 
{{out}}
#subject parse_order.
<pre>
Inp: 4 * 6
AST: 2 ( n 4 0 ) ( * 1 3 ) ( n 6 0 )
Eval: 24
 
Inp: 4.2 * ((5.3+8)*3 + 4)
#class Token
AST: 2 ( n 4.20 0 ) ( * 1 8 ) ( n 5.30 0 ) ( + 3 5 ) ( n 8 0 ) ( * 4 7 ) ( n 3 0 ) ( + 6 9 ) ( n 4 0 )
Eval: 184.38
 
Inp: 2.5 * 2 + 2 * 3.14
AST: 4 ( n 2.50 0 ) ( * 1 3 ) ( n 2 0 ) ( + 2 6 ) ( n 2 0 ) ( * 5 7 ) ( n 3.14 0 )
Eval: 11.28
</pre>
 
=={{header|Elena}}==
ELENA 6.x :
<syntaxhighlight lang="elena">import system'routines;
import extensions;
import extensions'text;
 
class Token
{
object _value;
#field theValue.
int Level : rprop;
#initializer
[
theValue := String.
]
constructor new(int level)
#method parse_order'get = 0.
{
_value := new StringWriter();
Level := level + 9;
}
append(ch)
#method += aChar
[{
_value.write(ch)
theValue += aChar.
]}
Number = _value.toReal();
#method + aNode
[
^ aNode += self.
]
#method numeric = Real64Value &&literal:theValue &:erealformatter.
}
 
class Node
 
#class Node
{
object Left : prop;
#field theLeft.
object Right : prop;
#field theRight.
int Level : rprop;
#role LeftAssigned
{
#method += aNode
[
theRight := aNode.
#shift.
]
}
#role Empty
{
#method += aNode
[
theLeft := aNode.
#shift LeftAssigned.
]
}
#initializer
[
#shift Empty.
]
 
constructor new(int level)
#method + aNode
[{
Level := level
#if (self parse_order > aNode parse_order)?
[}
self += aNode.
]
| [
aNode += self.
^ aNode.
].
]
#method += aNode
[
#if (theRight parse_order > aNode parse_order)?
[
theRight += aNode.
]
| [
theRight := aNode += theRight.
].
]
}
 
#class SummaryNode (: Node)
{
constructor new(int level)
#method parse_order'get = 2.
<= super new(level + 1);
Number = Left.Number + Right.Number;
#method numeric = theLeft numeric + theRight numeric.
}
 
#class DifferenceNode (Node)
class DifferenceNode : Node
{
constructor new(int level)
#method parse_order'get = 2.
<= super new(level + 1);
Number = Left.Number - Right.Number;
#method numeric = theLeft numeric - theRight numeric.
}
 
#class ProductNode (Node)
class ProductNode : Node
{
constructor new(int level)
#method parse_order'get = 1.
<= super new(level + 2);
Number = Left.Number * Right.Number;
#method numeric = theLeft numeric * theRight numeric.
}
 
#class FractionNode (Node)
class FractionNode : Node
{
constructor new(int level)
#method parse_order'get = 1.
<= super new(level + 2);
Number = Left.Number / Right.Number;
#method numeric = theLeft numeric / theRight numeric.
}
 
#class SubExpression
class Expression
{
int #fieldLevel theParser. :rprop;
object Top :prop;
#field theCounter.
constructor new(int level)
#role EOF
{
Level := level
#method available'is [ control fail. ]
}
object Right
{
get() = Top;
set(object node)
#method += aChar [ $self fail. ]
} {
Top := node
}
}
get Number() => Top;
#initializer
}
[
 
theParser := arithmeval'Parser.
singleton operatorState
theCounter := Integer << 1.
{
]
eval(ch)
{
ch =>
$40 { // (
^ weak self.newBracket().gotoStarting()
}
! {
^ weak self.newToken().append(ch).gotoToken()
}
}
}
 
singleton tokenState
{
eval(ch)
{
ch =>
$41 { // )
^ weak self.closeBracket().gotoToken()
}
$42 { // *
^ weak self.newProduct().gotoOperator()
}
$43 { // +
^ weak self.newSummary().gotoOperator()
}
$45 { // -
^ weak self.newDifference().gotoOperator()
}
$47 { // /
^ weak self.newFraction().gotoOperator()
}
! {
^ weak self.append(ch)
}
}
}
 
singleton startState
{
eval(ch)
{
ch =>
$40 { // (
^ weak self.newBracket().gotoStarting()
}
$45 { // -
^ weak self.newToken().append("0").newDifference().gotoOperator()
}
! {
^ weak self.newToken().append(ch).gotoToken()
}
}
}
 
class Scope
{
object _state;
int _level;
object _parser;
object _token;
object _expression;
constructor new(parser)
#method available'is []
{
_state := startState;
_level := 0;
_expression := Expression.new(0);
_parser := parser
}
newToken()
{
_token := _parser.appendToken(_expression, _level)
}
newSummary()
#method parse_order'get = 0.
{
_token := nil;
_parser.appendSummary(_expression, _level)
}
newDifference()
#method + aNode
[{
_token ^ aNode +:= self.nil;
]
_parser.appendDifference(_expression, _level)
}
newProduct()
{
_token := nil;
_parser.appendProduct(_expression, _level)
}
newFraction()
#method append : aChar
[{
_token #if control if:(aChar == 41)nil;
[
theCounter -= 1.
]
| if:(aChar == 40)
[
theCounter += 1.
].
_parser.appendFraction(_expression, _level)
#if (theCounter == 0)?
} [ #shift EOF. ^ $self. ].
 
newBracket()
{
_token := nil;
_level := theParser_level evaluate:aChar.+ 10;
]
_parser.appendSubexpression(_expression, _level)
}
 
closeBracket()
{
if (_level < 10)
{ InvalidArgumentException.new("Invalid expression").raise() };
_level := _level - 10
}
append(ch)
{
if(ch >= $48 && ch < $58)
{
_token.append(ch)
}
else
{
InvalidArgumentException.new("Invalid expression").raise()
}
}
append(string s)
{
s.forEach::(ch){ self.append(ch) }
}
gotoStarting()
{
_state := startState
}
gotoToken()
{
_state := tokenState
}
gotoOperator()
{
_state := operatorState
}
get Number() => _expression;
#method numeric = theParser numeric.
dispatch() => _state;
}
 
#class Parser
class Parser
{
appendToken(object expression, int level)
#field theToken.
{
#field theTopNode.
var token := Token.new(level);
#role Brackets
expression.Top := self.append(expression.Top, token);
{
#method evaluate : aChar
^ [token
}
theToken += aChar.
 
appendSummary(object expression, int level)
{
var t := expression.Top;
 
expression.Top := self.append(/*expression.Top*/t, SummaryNode.new(level))
}
 
appendDifference(object expression, int level)
{
expression.Top := self.append(expression.Top, DifferenceNode.new(level))
}
 
appendProduct(object expression, int level)
{
expression.Top := self.append(expression.Top, ProductNode.new(level))
}
 
appendFraction(object expression, int level)
{
expression.Top := self.append(expression.Top, FractionNode.new(level))
}
 
appendSubexpression(object expression, int level)
{
expression.Top := self.append(expression.Top, Expression.new(level))
}
 
append(object lastNode, object newNode)
{
if(nil == lastNode)
{ ^ newNode };
if (newNode.Level <= lastNode.Level)
{ newNode.Left := lastNode; ^ newNode };
var parent := lastNode;
#if theToken available'is
var current := | [lastNode.Right;
while (nil != current && newNode.Level > #shiftcurrent.Level)
{ parent := ]current; current := current.Right };
]
} if (nil == current)
#role Start {
parent.Right := newNode
{
}
#method evaluate : aChar
[else
{ #if (40 == aChar)?
newNode.Left := current; parent.Right := newNode [
};
theToken := SubExpression.
theTopNode := theToken.
#shift Brackets.
]
| [
theToken := Token.
theTopNode := theToken.
theToken += aChar.
#shift.
].
]
}
#role Operator
{
#method evaluate : aChar
[
#if Control if:(48 < aChar) if:(58 > aChar)
[
theToken := (Token += aChar).
theTopNode += theToken.
#shift.
]
| if:(40 == aChar)
[
theToken := SubExpression.
theTopNode += theToken.
#shift Brackets.
]
| [ $self fail. ].
]
}
#initializer
[
#shift Start.
]
#method numeric = theTopNode numeric.
#method evaluate : aChar
[
#if Control if:(48 < aChar) if:(58 > aChar)
[
theToken += aChar.
]
| if:(42 == aChar) // *
[
theTopNode := theTopNode + ProductNode.
#shift Operator.
]
| if:(47 == aChar) // /
[
theTopNode := theTopNode + FractionNode.
#shift Operator.
]
| if:(43 == aChar) // +
[
theTopNode := theTopNode + SummaryNode.
#shift Operator.
]
| if:(45 == aChar) // -
[
theTopNode := theTopNode + DifferenceNode.
#shift Operator.
]
| if:(40 == aChar)
[
theToken := SubExpression.
theTopNode := theToken.
^ #shift Brackets.lastNode
]}
| [ $self fail. ].
]
run(text)
#method start : aProcess
[{
var scope aProcess run:self= Scope.new(self);
 
text.forEach::(ch){ scope.eval(ch) };
^ self numeric.
 
]
^ scope.Number
}
}
 
public program()
#symbol Program =
{
[
#var aTexttext := String.new StringWriter();
var parser := new Parser();
#while ((Console >> aText) length > 0)?
[
#var aParser := Parser.
 
while (console.readLine().writeTo(text).Length > 0)
Console << "=" << aParser start:Scan::aText | ^^"Invalid Expression".
{
try
{
console.printLine("=",parser.run(text))
}
catch(Exception e)
{
console.writeLine("Invalid Expression")
};
Console << "%n"text.clear()
].}
}</syntaxhighlight>
].
</lang>
 
=={{header|Elixir}}==
=== ELENA VM script ===
In Elixir AST is a built-in feature.
<lang elena>number ::= $numeric;
numeric ::= "(" sub_expr;
numeric ::= number;
factor ::= number factor_r;
factor ::= "(" sub_expr;
sum ::= "+" factor ;
difference ::= "-" factor ;
multiply ::= "*" numeric;
divide ::= "/" numeric;
factor_r ::= multiply factor_r;
factor_r ::= divide factor_r;
factor_r ::= $eps;
expr_r ::= sum expr_r;
expr_r ::= difference expr_r;
expr_r ::= $eps;
neg_r ::= factor_r expr_r;
sub_expr ::= expression sub_expr_r;
sub_expr_r ::= ")" factor_r;
neg_expression ::= $numeric neg_r;
expression ::= factor expr_r;
expression ::= "-" neg_expression;
print ::= "?" expression;
start ::= print;
print => &nil 'program'output $body ^write;
multiply => $body ^multiply;
divide => $body ^divide;
sum => $body ^add;
difference => $body ^subtract;
neg_expression => 0 $terminal ^subtract $body;
number => $terminal $body;</lang>
 
<syntaxhighlight lang="elixir">
=={{header|Factor}}==
defmodule Ast do
<lang factor>USING: accessors kernel locals math math.parser peg.ebnf ;
def main do
IN: rosetta.arith
expr = IO.gets("Give an expression:\n") |> String.Chars.to_string |> String.trim
case Code.string_to_quoted(expr) do
{:ok, ast} ->
IO.puts("AST is: " <> inspect(ast))
{result, _} = Code.eval_quoted(ast)
IO.puts("Result = #{result}")
{:error, {_meta, message_info, _token}} ->
IO.puts(message_info)
end
end
end
</syntaxhighlight>
 
{{out}}
TUPLE: operator left right ;
<pre>
TUPLE: add < operator ; C: <add> add
>elixir -e Ast.main()
TUPLE: sub < operator ; C: <sub> sub
Give an expression:
TUPLE: mul < operator ; C: <mul> mul
2*(4 - 1)
TUPLE: div < operator ; C: <div> div
AST is: {:*, [line: 1], [2, {:-, [line: 1], [4, 1]}]}
Result = 6
 
>elixir -e Ast.main()
EBNF: expr-ast
Give an expression:
spaces = [\n\t ]*
2*(4 - 1) + (
digit = [0-9]
missing terminator: ) (for "(" starting at line 1)
number = (digit)+ => [[ string>number ]]
</pre>
 
=={{header|Emacs Lisp}}==
value = spaces number:n => [[ n ]]
<syntaxhighlight lang="lisp">#!/usr/bin/env emacs --script
| spaces "(" exp:e spaces ")" => [[ e ]]
;; -*- mode: emacs-lisp; lexical-binding: t -*-
;;> ./arithmetic-evaluation '(1 + 2) * 3'
 
(defun advance ()
fac = fac:a spaces "*" value:b => [[ a b <mul> ]]
(let ((rtn (buffer-substring-no-properties (point) (match-end 0))))
| fac:a spaces "/" value:b => [[ a b <div> ]]
(goto-char (match-end 0))
| value
rtn))
(defvar current-symbol nil)
 
(defun next-symbol ()
exp = exp:a spaces "+" fac:b => [[ a b <add> ]]
(when (looking-at "[ \t\n]+")
| exp:a spaces "-" fac:b => [[ a b <sub> ]]
(goto-char (match-end 0)))
| fac
 
(cond
main = exp:e spaces !(.) => [[ e ]]
((eobp)
;EBNF
(setq current-symbol 'eof))
((looking-at "[0-9]+")
(setq current-symbol (string-to-number (advance))))
((looking-at "[-+*/()]")
(setq current-symbol (advance)))
((looking-at ".")
(error "Unknown character '%s'" (advance)))))
 
(defun accept (sym)
GENERIC: eval-ast ( ast -- result )
(when (equal sym current-symbol)
(next-symbol)
t))
(defun expect (sym)
(unless (accept sym)
(error "Expected symbol %s, but found %s" sym current-symbol))
t)
 
(defun p-expression ()
M: number eval-ast ;
" expression = term { ('+' | '-') term } . "
(let ((rtn (p-term)))
(while (or (equal current-symbol "+") (equal current-symbol "-"))
(let ((op current-symbol)
(left rtn))
(next-symbol)
(setq rtn (list op left (p-term)))))
rtn))
 
(defun p-term ()
: recursive-eval ( ast -- left-result right-result )
" term [= left>>factor eval-ast ]{ [('*' right>>| eval-ast'/') ]factor bi} ;. "
(let ((rtn (p-factor)))
(while (or (equal current-symbol "*") (equal current-symbol "/"))
(let ((op current-symbol)
(left rtn))
(next-symbol)
(setq rtn (list op left (p-factor)))))
rtn))
 
(defun p-factor ()
M: add eval-ast recursive-eval + ;
" factor = constant | variable | '(' expression ')' . "
M: sub eval-ast recursive-eval - ;
(let (rtn)
M: mul eval-ast recursive-eval * ;
(cond
M: div eval-ast recursive-eval / ;
((numberp current-symbol)
(setq rtn current-symbol)
(next-symbol))
((accept "(")
(setq rtn (p-expression))
(expect ")"))
(t (error "Syntax error")))
rtn))
 
(defun ast-build (expression)
: evaluate ( string -- result )
(let (rtn)
expr-ast eval-ast ;</lang>
(with-temp-buffer
(insert expression)
(goto-char (point-min))
(next-symbol)
(setq rtn (p-expression))
(expect 'eof))
rtn))
 
(defun ast-eval (v)
(pcase v
((pred numberp) v)
(`("+" ,a ,b) (+ (ast-eval a) (ast-eval b)))
(`("-" ,a ,b) (- (ast-eval a) (ast-eval b)))
(`("*" ,a ,b) (* (ast-eval a) (ast-eval b)))
(`("/" ,a ,b) (/ (ast-eval a) (float (ast-eval b))))
(_ (error "Unknown value %s" v))))
 
(dolist (arg command-line-args-left)
(let ((ast (ast-build arg)))
(princ (format " ast = %s\n" ast))
(princ (format " value = %s\n" (ast-eval ast)))
(terpri)))
(setq command-line-args-left nil)
</syntaxhighlight>
 
{{out}}
<pre>
$ ./arithmetic-evaluation '(1 + 2) * 3'
ast = (* (+ 1 2) 3)
value = 9
 
$ ./arithmetic-evaluation '1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10'
ast = (+ 1 (/ (* 2 (- (+ 3 (+ (* 4 5) (* (* 6 7) 8))) 9)) 10))
value = 71.0
 
$ ./arithmetic-evaluation '1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1'
ast = (+ (+ 1 (* 2 (- 3 (* (* 2 (- 3 2)) (- (- (* (- 2 4) 5) (/ 22 (+ 7 (* 2 (- 3 1))))) 1))))) 1)
value = 60.0
 
$ ./arithmetic-evaluation '(1 + 2) * 10 / 100'
ast = (/ (* (+ 1 2) 10) 100)
value = 0.3
</pre>
 
=={{header|ERRE}}==
<syntaxhighlight lang="erre">
PROGRAM EVAL
 
!
! arithmetic expression evaluator
!
 
!$KEY
 
LABEL 98,100,110
 
DIM STACK$[50]
 
PROCEDURE DISEGNA_STACK
!$RCODE="LOCATE 3,1"
!$RCODE="COLOR 0,7"
PRINT(TAB(35);"S T A C K";TAB(79);)
!$RCODE="COLOR 7,0"
FOR TT=1 TO 38 DO
IF TT>=20 THEN
!$RCODE="LOCATE 3+TT-19,40"
ELSE
!$RCODE="LOCATE 3+TT,1"
END IF
IF TT=NS THEN PRINT(">";) ELSE PRINT(" ";) END IF
PRINT(RIGHT$(STR$(TT),2);"³ ";STACK$[TT];" ")
END FOR
REPEAT
GET(Z$)
UNTIL LEN(Z$)<>0
END PROCEDURE
 
PROCEDURE COMPATTA_STACK
IF NS>1 THEN
R=1
WHILE R<NS DO
IF INSTR(OP_LIST$,STACK$[R])=0 AND INSTR(OP_LIST$,STACK$[R+1])=0 THEN
FOR R1=R TO NS-1 DO
STACK$[R1]=STACK$[R1+1]
END FOR
NS=NS-1
END IF
R=R+1
END WHILE
END IF
DISEGNA_STACK
END PROCEDURE
 
PROCEDURE CALC_ARITM
L=NS1
WHILE L<=NS2 DO
IF STACK$[L]="^" THEN
IF L>=NS2 THEN GOTO 100 END IF
N1#=VAL(STACK$[L-1]) N2#=VAL(STACK$[L+1]) NOP=NOP-1
IF STACK$[L]="^" THEN
RI#=N1#^N2#
END IF
STACK$[L-1]=STR$(RI#)
N=L
WHILE N<=NS2-2 DO
STACK$[N]=STACK$[N+2]
N=N+1
END WHILE
NS2=NS2-2
L=NS1-1
END IF
L=L+1
END WHILE
 
L=NS1
WHILE L<=NS2 DO
IF STACK$[L]="*" OR STACK$[L]="/" THEN
IF L>=NS2 THEN GOTO 100 END IF
N1#=VAL(STACK$[L-1]) N2#=VAL(STACK$[L+1]) NOP=NOP-1
IF STACK$[L]="*" THEN RI#=N1#*N2# ELSE RI#=N1#/N2# END IF
STACK$[L-1]=STR$(RI#)
N=L
WHILE N<=NS2-2 DO
STACK$[N]=STACK$[N+2]
N=N+1
END WHILE
NS2=NS2-2
L=NS1-1
END IF
L=L+1
END WHILE
 
L=NS1
WHILE L<=NS2 DO
IF STACK$[L]="+" OR STACK$[L]="-" THEN
EXIT IF L>=NS2
N1#=VAL(STACK$[L-1]) N2#=VAL(STACK$[L+1]) NOP=NOP-1
IF STACK$[L]="+" THEN RI#=N1#+N2# ELSE RI#=N1#-N2# END IF
STACK$[L-1]=STR$(RI#)
N=L
WHILE N<=NS2-2 DO
STACK$[N]=STACK$[N+2]
N=N+1
END WHILE
NS2=NS2-2
L=NS1-1
END IF
L=L+1
END WHILE
100:
IF NOP<2 THEN ! operator priority
DB#=VAL(STACK$[NS1])
ELSE
IF NOP<3 THEN
DB#=VAL(STACK$[NS1+2])
ELSE
DB#=VAL(STACK$[NS1+4])
END IF
END IF
END PROCEDURE
 
PROCEDURE SVOLGI_PAR
NPA=NPA-1
FOR J=NS TO 1 STEP -1 DO
EXIT IF STACK$[J]="("
END FOR
IF J=0 THEN
NS1=1 NS2=NS CALC_ARITM
NERR=7
ELSE
FOR R=J TO NS-1 DO
STACK$[R]=STACK$[R+1]
END FOR
NS1=J NS2=NS-1 CALC_ARITM
IF NS1=2 THEN NS1=1 STACK$[1]=STACK$[2] END IF
NS=NS1
COMPATTA_STACK
END IF
END PROCEDURE
 
BEGIN
OP_LIST$="+-*/^("
NOP=0 NPA=0 NS=1 K$=""
STACK$[1]="@" ! init stack
 
PRINT(CHR$(12);)
INPUT(LINE,EXPRESSION$)
 
FOR W=1 TO LEN(EXPRESSION$) DO
LOOP
CODE=ASC(MID$(EXPRESSION$,W,1))
IF (CODE>=48 AND CODE<=57) OR CODE=46 THEN
K$=K$+CHR$(CODE)
W=W+1 IF W>LEN(EXPRESSION$) THEN GOTO 98 END IF
ELSE
EXIT IF K$=""
IF NS>1 OR (NS=1 AND STACK$[1]<>"@") THEN NS=NS+1 END IF
IF FLAG=0 THEN STACK$[NS]=K$ ELSE STACK$[NS]=STR$(VAL(K$)*FLAG) END IF
K$="" FLAG=0
EXIT
END IF
END LOOP
IF CODE=43 THEN K$="+" END IF
IF CODE=45 THEN K$="-" END IF
IF CODE=42 THEN K$="*" END IF
IF CODE=47 THEN K$="/" END IF
IF CODE=94 THEN K$="^" END IF
 
CASE CODE OF
43,45,42,47,94->
IF MID$(EXPRESSION$,W+1,1)="-" THEN FLAG=-1 W=W+1 END IF
IF INSTR(OP_LIST$,STACK$[NS])<>0 THEN
NERR=5
ELSE
NS=NS+1 STACK$[NS]=K$ NOP=NOP+1
IF NOP>=2 THEN
FOR J=NS TO 1 STEP -1 DO
IF STACK$[J]<>"(" THEN
CONTINUE FOR
END IF
IF J<NS-2 THEN
EXIT
ELSE
GOTO 110
END IF
END FOR
NS1=J+1 NS2=NS CALC_ARITM
NS=NS2 STACK$[NS]=K$
REGISTRO_X#=VAL(STACK$[NS-1])
END IF
END IF
110:
END ->
 
40->
IF NS>1 OR (NS=1 AND STACK$[1]<>"@") THEN NS=NS+1 END IF
STACK$[NS]="(" NPA=NPA+1
IF MID$(EXPRESSION$,W+1,1)="-" THEN FLAG=-1 W=W+1 END IF
END ->
 
41->
SVOLGI_PAR
IF NERR=7 THEN
NERR=0 NOP=0 NPA=0 NS=1
ELSE
IF NERR=0 OR NERR=1 THEN
DB#=VAL(STACK$[NS])
REGISTRO_X#=DB#
ELSE
NOP=0 NPA=0 NS=1
END IF
END IF
END ->
 
OTHERWISE
NERR=8
END CASE
K$=""
DISEGNA_STACK
END FOR
 
98:
IF K$<>"" THEN
IF NS>1 OR (NS=1 AND STACK$[1]<>"@") THEN NS=NS+1 END IF
IF FLAG=0 THEN STACK$[NS]=K$ ELSE STACK$[NS]=STR$(VAL(K$)*FLAG) END IF
END IF
DISEGNA_STACK
IF INSTR(OP_LIST$,STACK$[NS])<>0 THEN
NERR=6
ELSE
WHILE NPA<>0 DO
SVOLGI_PAR
END WHILE
IF NERR<>7 THEN NS1=1 NS2=NS CALC_ARITM END IF
END IF
NS=1 NOP=0 NPA=0
!$RCODE="LOCATE 23,1"
IF NERR>0 THEN PRINT("Internal Error #";NERR) ELSE PRINT("Value is ";DB#) END IF
END PROGRAM
</syntaxhighlight>
This solution is based on a stack: as a plus there is a power (^) operator. Unary operator "-" is accepted. Program shows the stack after every operation and you must press a key to go on (this feature can be avoided by removing the final REPEAT..UNTIL loop at the end of "DISEGNA_STACK" procedure).
 
=={{header|F_Sharp|F#}}==
Line 1,424 ⟶ 2,790:
 
<code>AbstractSyntaxTree.fs</code>:
<langsyntaxhighlight lang="fsharp">module AbstractSyntaxTree
type Expression =
Line 1,431 ⟶ 2,797:
| Minus of Expression * Expression
| Times of Expression * Expression
| Divide of Expression * Expression</langsyntaxhighlight>
 
<code>Lexer.fsl</code>:
<langsyntaxhighlight lang="fsharp">{
module Lexer
 
Line 1,457 ⟶ 2,823:
| newline { lexbuf.EndPos <- lexbuf.EndPos.NextLine; token lexbuf }
| eof { EOF }
| _ { failwithf "unrecognized input: '%s'" <| lexeme lexbuf }</langsyntaxhighlight>
 
<code>Parser.fsy</code>:
<langsyntaxhighlight lang="fsharp">%{
open AbstractSyntaxTree
%}
Line 1,485 ⟶ 2,851:
| Expr TIMES Expr { Times ($1, $3) }
| Expr DIVIDE Expr { Divide ($1, $3) }
| LPAREN Expr RPAREN { $2 } </langsyntaxhighlight>
 
<code>Program.fs</code>:
<langsyntaxhighlight lang="fsharp">open AbstractSyntaxTree
open Lexer
open Parser
Line 1,508 ⟶ 2,874:
|> parse
|> eval
|> printfn "%d"</langsyntaxhighlight>
 
=={{header|Factor}}==
<syntaxhighlight lang="factor">USING: accessors kernel locals math math.parser peg.ebnf ;
IN: rosetta.arith
 
TUPLE: operator left right ;
TUPLE: add < operator ; C: <add> add
TUPLE: sub < operator ; C: <sub> sub
TUPLE: mul < operator ; C: <mul> mul
TUPLE: div < operator ; C: <div> div
 
EBNF: expr-ast
spaces = [\n\t ]*
digit = [0-9]
number = (digit)+ => [[ string>number ]]
 
value = spaces number:n => [[ n ]]
| spaces "(" exp:e spaces ")" => [[ e ]]
 
fac = fac:a spaces "*" value:b => [[ a b <mul> ]]
| fac:a spaces "/" value:b => [[ a b <div> ]]
| value
 
exp = exp:a spaces "+" fac:b => [[ a b <add> ]]
| exp:a spaces "-" fac:b => [[ a b <sub> ]]
| fac
 
main = exp:e spaces !(.) => [[ e ]]
;EBNF
 
GENERIC: eval-ast ( ast -- result )
 
M: number eval-ast ;
 
: recursive-eval ( ast -- left-result right-result )
[ left>> eval-ast ] [ right>> eval-ast ] bi ;
 
M: add eval-ast recursive-eval + ;
M: sub eval-ast recursive-eval - ;
M: mul eval-ast recursive-eval * ;
M: div eval-ast recursive-eval / ;
 
: evaluate ( string -- result )
expr-ast eval-ast ;</syntaxhighlight>
 
=={{header|FreeBASIC}}==
<syntaxhighlight lang="freebasic">
'Arithmetic evaluation
'
'Create a program which parses and evaluates arithmetic expressions.
'
'Requirements
'
' * An abstract-syntax tree (AST) for the expression must be created from parsing the
' input.
' * The AST must be used in evaluation, also, so the input may not be directly evaluated
' (e.g. by calling eval or a similar language feature.)
' * The expression will be a string or list of symbols like "(1+3)*7".
' * The four symbols + - * / must be supported as binary operators with conventional
' precedence rules.
' * Precedence-control parentheses must also be supported.
'
'Standard mathematical precedence should be followed:
'
' Parentheses
' Multiplication/Division (left to right)
' Addition/Subtraction (left to right)
'
' test cases:
' 2*-3--4+-0.25 : returns -2.25
' 1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10 : returns 71
 
enum
false = 0
true = -1
end enum
 
enum Symbol
unknown_sym
minus_sym
plus_sym
lparen_sym
rparen_sym
number_sym
mul_sym
div_sym
unary_minus_sym
unary_plus_sym
done_sym
eof_sym
end enum
 
type Tree
as Tree ptr leftp, rightp
op as Symbol
value as double
end type
 
dim shared sym as Symbol
dim shared tokenval as double
dim shared usr_input as string
 
declare function expr(byval p as integer) as Tree ptr
 
function isdigit(byval ch as string) as long
return ch <> "" and Asc(ch) >= Asc("0") and Asc(ch) <= Asc("9")
end function
 
sub error_msg(byval msg as string)
print msg
system
end sub
 
' tokenize the input string
sub getsym()
do
if usr_input = "" then
line input usr_input
usr_input += chr(10)
endif
dim as string ch = mid(usr_input, 1, 1) ' get the next char
usr_input = mid(usr_input, 2) ' remove it from input
 
sym = unknown_sym
select case ch
case " ": continue do
case chr(10), "": sym = done_sym: return
case "+": sym = plus_sym: return
case "-": sym = minus_sym: return
case "*": sym = mul_sym: return
case "/": sym = div_sym: return
case "(": sym = lparen_sym: return
case ")": sym = rparen_sym: return
case else
if isdigit(ch) then
dim s as string = ""
dim dot as integer = 0
do
s += ch
if ch = "." then dot += 1
ch = mid(usr_input, 1, 1) ' get the next char
usr_input = mid(usr_input, 2) ' remove it from input
loop while isdigit(ch) orelse ch = "."
if ch = "." or dot > 1 then error_msg("bogus number")
usr_input = ch + usr_input ' prepend the char to input
tokenval = val(s)
sym = number_sym
end if
return
end select
loop
end sub
 
function make_node(byval op as Symbol, byval leftp as Tree ptr, byval rightp as Tree ptr) as Tree ptr
dim t as Tree ptr
 
t = callocate(len(Tree))
t->op = op
t->leftp = leftp
t->rightp = rightp
return t
end function
 
function is_binary(byval op as Symbol) as integer
select case op
case mul_sym, div_sym, plus_sym, minus_sym: return true
case else: return false
end select
end function
 
function prec(byval op as Symbol) as integer
select case op
case unary_minus_sym, unary_plus_sym: return 100
case mul_sym, div_sym: return 90
case plus_sym, minus_sym: return 80
case else: return 0
end select
end function
 
function primary as Tree ptr
dim t as Tree ptr = 0
 
select case sym
case minus_sym, plus_sym
dim op as Symbol = sym
getsym()
t = expr(prec(unary_minus_sym))
if op = minus_sym then return make_node(unary_minus_sym, t, 0)
if op = plus_sym then return make_node(unary_plus_sym, t, 0)
case lparen_sym
getsym()
t = expr(0)
if sym <> rparen_sym then error_msg("expecting rparen")
getsym()
return t
case number_sym
t = make_node(sym, 0, 0)
t->value = tokenval
getsym()
return t
case else: error_msg("expecting a primary")
end select
end function
 
function expr(byval p as integer) as Tree ptr
dim t as Tree ptr = primary()
 
while is_binary(sym) andalso prec(sym) >= p
dim t1 as Tree ptr
dim op as Symbol = sym
getsym()
t1 = expr(prec(op) + 1)
t = make_node(op, t, t1)
wend
return t
end function
 
function eval(byval t as Tree ptr) as double
if t <> 0 then
select case t->op
case minus_sym: return eval(t->leftp) - eval(t->rightp)
case plus_sym: return eval(t->leftp) + eval(t->rightp)
case mul_sym: return eval(t->leftp) * eval(t->rightp)
case div_sym: return eval(t->leftp) / eval(t->rightp)
case unary_minus_sym: return -eval(t->leftp)
case unary_plus_sym: return eval(t->leftp)
case number_sym: return t->value
case else: error_msg("unexpected tree node")
end select
end if
return 0
end function
 
do
getsym()
if sym = eof_sym then exit do
if sym = done_sym then continue do
dim t as Tree ptr = expr(0)
print"> "; eval(t)
if sym = eof_sym then exit do
if sym <> done_sym then error_msg("unexpected input")
loop
</syntaxhighlight>
 
{{out}}
<pre>
>calc
1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10
> 71
</pre>
 
=={{header|FutureBasic}}==
<syntaxhighlight lang="futurebasic">
_window = 1
begin enum 1
_expressionLabel
_expressionFld
_resultLabel
end enum
 
void local fn BuildUI
editmenu 1
window _window, @"Arithmetic Evaluation", (0,0,522,61)
textlabel _expressionLabel, @"Expression:", (18,23,74,16)
textfield _expressionFld,,, (98,20,300,21)
textlabel _resultLabel,, (404,23,100,16)
WindowMakeFirstResponder( _window, _expressionFld )
end fn
 
void local fn EvaluateExpression( string as CFStringRef )
ExpressionRef expression = fn ExpressionWithFormat( string )
textlabel _resultlabel, fn StringWithFormat( @"= %@", fn ExpressionValueWithObject( expression, NULL, NULL ) )
end fn
 
void local fn DoDialog( ev as long, tag as long )
select ( ev )
case _btnClick : fn EvaluateExpression( textfield(tag) )
end select
end fn
 
fn BuildUI
 
on dialog fn DoDialog
 
HandleEvents
</syntaxhighlight>
[[file:Arithmetic evaluation FB.png]]
 
=={{header|Go}}==
 
See [[Arithmetic Evaluator/Go]]
 
 
=={{header|Groovy}}==
Solution:
<langsyntaxhighlight lang="groovy">enum Op {
ADD('+', 2),
SUBTRACT('-', 2),
Line 1,660 ⟶ 3,312:
}
return elements[0] instanceof List ? parse(elements[0]) : elements[0]
}</langsyntaxhighlight>
 
Test:
<langsyntaxhighlight lang="groovy">def testParse = {
def ex = parse(it)
print """
Line 1,698 ⟶ 3,350:
try { testParse('1++') } catch (e) { println e }
try { testParse('*1') } catch (e) { println e }
try { testParse('/ 1 /') } catch (e) { println e }</langsyntaxhighlight>
 
{{out}}
Output:
<pre style="height:30ex;overflow:scroll;">Input: 1+1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+(1+1/15)/14)/13)/12)/11)/10)/9)/8)/7)/6)/5)/4)/3)/2
AST: (+ (+ 1 1) (/ (+ 1 (/ (+ 1 (/ (+ 1 (/ (+ 1 (/ (+ 1 (/ (+ 1 (/ (+ 1 (/ (+ 1 (/ (+ 1 (/ (+ 1 (/ (+ 1 (/ (+ 1 (/ (+ 1 (/ 1 15)) 14)) 13)) 12)) 11)) 10)) 9)) 8)) 7)) 6)) 5)) 4)) 3)) 2))
Line 1,767 ⟶ 3,419:
 
=={{header|Haskell}}==
<syntaxhighlight lang="haskell">{-# LANGUAGE FlexibleContexts #-}
<lang haskell>import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Expr
 
import Text.Parsec
data Exp = Num Int
import Text.Parsec.Expr
| Add Exp Exp
import Text.Parsec.Combinator
| Sub Exp Exp
import Data.Functor
| Mul Exp Exp
import Data.Function (on)
| Div Exp Exp
 
data Exp
expr = buildExpressionParser table factor
= Num Int
| Add Exp
Exp
| Sub Exp
Exp
| Mul Exp
Exp
| Div Exp
Exp
 
expr
table = [[op "*" (Mul) AssocLeft, op "/" (Div) AssocLeft]
:: Stream s m Char
,[op "+" (Add) AssocLeft, op "-" (Sub) AssocLeft]]
=> ParsecT s u m Exp
where op s f assoc = Infix (do string s; return f) assoc
expr = buildExpressionParser table factor
where
table =
[ [op "*" Mul AssocLeft, op "/" Div AssocLeft]
, [op "+" Add AssocLeft, op "-" Sub AssocLeft]
]
op s f = Infix (f <$ string s)
factor = (between `on` char) '(' ')' expr <|> (Num . read <$> many1 digit)
 
eval
factor = do char '(' ; x <- expr ; char ')'
:: Integral a
return x
<|=> doExp ds <-> many1 digita
eval (Num x) = fromIntegral x
return $ Num (read ds)
eval (Add a b) = eval a + eval b
eval (Sub a b) = eval a - eval b
eval (Mul a b) = eval a * eval b
eval (Div a b) = eval a `div` eval b
 
solution
evaluate (Num x) = fromIntegral x
:: Integral a
evaluate (Add a b) = (evaluate a) + (evaluate b)
=> String -> a
evaluate (Sub a b) = (evaluate a) - (evaluate b)
solution = either (const (error "Did not parse")) eval . parse expr ""
evaluate (Mul a b) = (evaluate a) * (evaluate b)
evaluate (Div a b) = (evaluate a) `div` (evaluate b)
 
main :: IO ()
solution exp = case parse expr [] exp of
main = print $ solution "(1+3)*7"</syntaxhighlight>
Right expr -> evaluate expr
{{Out}}
Left _ -> error "Did not parse"</lang>
<pre>28</pre>
 
=={{header|Icon}} and {{header|Unicon}}==
Line 1,809 ⟶ 3,481:
* Notice that the code looks remarkably like a typical grammar, rather than being an opaque cryptic solution
* Does not rely on any library to silently solve 1/2 the problem; in fact, this code would probably suit being put into a library almost verbatim
<langsyntaxhighlight Iconlang="icon">procedure main() #: simple arithmetical parser / evaluator
write("Usage: Input expression = Abstract Syntax Tree = Value, ^Z to end.")
repeat {
Line 1,909 ⟶ 3,581:
procedure exponent()
suspend tab(any('eE')) || =("+" | "-" | "") || digits() | ""
end</langsyntaxhighlight>
 
{{out|Sample Output:}}
<pre>#matheval.exe
 
Line 1,939 ⟶ 3,611:
Nevertheless, this task deals only with simple arithmetic, so this kind of precedence is an arguably appropriate choice for this task.
 
The implementation here uses a shift/reduce parser to build a tree structure for evaluation (a tree structure which J happens to support for evaluation):
 
<langsyntaxhighlight lang="j">parse=:parse_parser_
eval=:monad define
'gerund structure'=:y
Line 2,006 ⟶ 3,678:
coerase tmp
r
)</langsyntaxhighlight>
example use:
<langsyntaxhighlight lang="j"> eval parse '1+2*3/(4-5+6)'
2.2</langsyntaxhighlight>
 
You can also display the syntax tree, for example:
<langsyntaxhighlight lang="j"> parse '2*3/(4-5)'
┌─────────────────────────────────────────────────────┬───────────────────┐
│┌───┬───────┬───┬───────┬───┬─┬───────┬───┬───────┬─┐│┌───────┬─┬───────┐│
Line 2,021 ⟶ 3,693:
││ │└─────┘│ │└─────┘│ │ │└─────┘│ │└─────┘│ ││ │
│└───┴───────┴───┴───────┴───┴─┴───────┴───┴───────┴─┘│ │
└─────────────────────────────────────────────────────┴───────────────────┘</langsyntaxhighlight>
 
At the top level, the first box is a list of terminals, and the second box represents their parsed structure within the source sentence, with numbers indexing the respective terminals. Within the list of terminals - each terminal is contained with a box. Operators are strings inside of boxes (the leading $ "operator" in this example is not really an operator - it's just a placeholder that was used to help in the parsing). Punctuation is simply the punctuation string (left or right parenthesis - these are also not really operators and are just placeholders which were used during parsing). Numeric values are a box inside of a box where the inner box carries two further boxes. The first indicates syntactic data type ('0' for arrays - here that means numbers) and the second carries the value.
 
=={{header|Java}}==
Line 2,029 ⟶ 3,701:
Uses the [[Arithmetic/Rational/Java|BigRational class]] to handle arbitrary-precision numbers (rational numbers since basic arithmetic will result in rational values).
 
<langsyntaxhighlight lang="java">import java.util.Stack;
 
public class ArithmeticEvaluation {
 
{
public staticinterface enum ParenthesesExpression { LEFT, RIGHT }
BigRational eval();
public static enum BinaryOperator
{
ADD('+', 1) {
public BigRational eval(BigRational leftValue, BigRational rightValue) { return leftValue.add(rightValue); }
},
SUB('-', 1) {
public BigRational eval(BigRational leftValue, BigRational rightValue) { return leftValue.subtract(rightValue); }
},
MUL('*', 2) {
public BigRational eval(BigRational leftValue, BigRational rightValue) { return leftValue.multiply(rightValue); }
},
DIV('/', 2) {
public BigRational eval(BigRational leftValue, BigRational rightValue) { return leftValue.divide(rightValue); }
};
public final char symbol;
public final int precedence;
BinaryOperator(char symbol, int precedence)
{
this.symbol = symbol;
this.precedence = precedence;
}
 
public enum Parentheses {LEFT}
public abstract BigRational eval(BigRational leftValue, BigRational rightValue);
 
}
public enum BinaryOperator {
ADD('+', 1),
public static class BinaryExpression
SUB('-', 1),
{
MUL('*', 2),
public Object leftOperand = null;
DIV('/', 2);
public BinaryOperator operator = null;
 
public Object rightOperand = null;
public final char symbol;
public final int precedence;
public BinaryExpression(Object leftOperand, BinaryOperator operator, Object rightOperand)
 
{
BinaryOperator(char symbol, int precedence) {
this.leftOperand = leftOperand;
this.operatorsymbol = operatorsymbol;
this.rightOperandprecedence = rightOperandprecedence;
}
 
public BigRational eval(BigRational leftValue, BigRational rightValue) {
switch (this) {
case ADD:
return leftValue.add(rightValue);
case SUB:
return leftValue.subtract(rightValue);
case MUL:
return leftValue.multiply(rightValue);
case DIV:
return leftValue.divide(rightValue);
}
throw new IllegalStateException();
}
 
public static BinaryOperator forSymbol(char symbol) {
for (BinaryOperator operator : values()) {
if (operator.symbol == symbol) {
return operator;
}
}
throw new IllegalArgumentException(String.valueOf(symbol));
}
}
 
public BigRationalstatic eval()class Number implements Expression {
private final BigRational number;
{
 
BigRational leftValue = (leftOperand instanceof BinaryExpression) ? ((BinaryExpression)leftOperand).eval() : (BigRational)leftOperand;
public Number(BigRational number) {
BigRational rightValue = (rightOperand instanceof BinaryExpression) ? ((BinaryExpression)rightOperand).eval() : (BigRational)rightOperand;
this.number = number;
return operator.eval(leftValue, rightValue);
}
 
@Override
public BigRational eval() {
return number;
}
 
@Override
public String toString() {
return number.toString();
}
}
 
public static class BinaryExpression implements Expression {
public String toString()
public final Expression leftOperand;
{ return "(" + leftOperand + " " + operator.symbol + " " + rightOperand + ")"; }
public final BinaryOperator operator;
}
public final Expression rightOperand;
 
public static void createNewOperand(BinaryOperator operator, Stack<Object> operands)
public BinaryExpression(Expression leftOperand, BinaryOperator operator, Expression rightOperand) {
{
this.leftOperand = leftOperand;
Object rightOperand = operands.pop();
this.operator = operator;
operands.push(new BinaryExpression(operands.pop(), operator, rightOperand));
this.rightOperand = rightOperand;
return;
}
public static Object createExpression(String inputString)
{
int curIndex = 0;
boolean afterOperand = false;
Stack<Object> operands = new Stack<Object>();
Stack<Object> operators = new Stack<Object>();
inputStringLoop:
while (curIndex < inputString.length())
{
int startIndex = curIndex;
char c = inputString.charAt(curIndex++);
if (Character.isWhitespace(c))
continue;
if (afterOperand)
{
if (c == ')')
{
Object operator = null;
while (!operators.isEmpty() && ((operator = operators.pop()) != Parentheses.LEFT))
createNewOperand((BinaryOperator)operator, operands);
continue;
}
 
afterOperand = false;
@Override
for (BinaryOperator operator : BinaryOperator.values())
public BigRational eval() {
if (c =BigRational leftValue = operatorleftOperand.symboleval();
BigRational rightValue = rightOperand.eval();
{
return operator.eval(leftValue, rightValue);
while (!operators.isEmpty() && (operators.peek() != Parentheses.LEFT) && (((BinaryOperator)operators.peek()).precedence >= operator.precedence))
}
createNewOperand((BinaryOperator)operators.pop(), operands);
 
operators.push(operator);
continue inputStringLoop;@Override
public String }toString() {
return "(" + leftOperand + " " + operator.symbol + " " + rightOperand + ")";
}
throw new IllegalArgumentException();
}
if (c == '(')
{
operators.push(Parentheses.LEFT);
continue;
}
afterOperand = true;
while (curIndex < inputString.length())
{
c = inputString.charAt(curIndex);
if (((c < '0') || (c > '9')) && (c != '.'))
break;
curIndex++;
}
operands.push(BigRational.valueOf(inputString.substring(startIndex, curIndex)));
}
 
private static void createNewOperand(BinaryOperator operator, Stack<Expression> operands) {
while (!operators.isEmpty())
Expression rightOperand = operands.pop();
{
Object operator Expression leftOperand = operatorsoperands.pop();
operands.push(new BinaryExpression(leftOperand, operator, rightOperand));
if (operator == Parentheses.LEFT)
throw new IllegalArgumentException();
createNewOperand((BinaryOperator)operator, operands);
}
 
Object expression = operands.pop();
public static Expression parse(String input) {
if (!operands.isEmpty())
throw new IllegalArgumentException()int curIndex = 0;
boolean afterOperand = false;
return expression;
Stack<Expression> operands = new Stack<>();
}
Stack<Object> operators = new Stack<>();
while (curIndex < input.length()) {
public static void main(String[] args)
int startIndex = curIndex;
{
char c = input.charAt(curIndex++);
String[] testExpressions = { "2+3", "2+3/4", "2*3-4", "2*(3+4)+5/6", "2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10", "2*-3--4+-.25" };
 
for (String testExpression : testExpressions)
if (Character.isWhitespace(c))
{
continue;
Object expression = createExpression(testExpression);
 
System.out.println("Input: \"" + testExpression + "\", AST: \"" + expression + "\", eval=" + (expression instanceof BinaryExpression ? ((BinaryExpression)expression).eval() : expression));
if (afterOperand) {
if (c == ')') {
Object operator;
while (!operators.isEmpty() && ((operator = operators.pop()) != Parentheses.LEFT))
createNewOperand((BinaryOperator) operator, operands);
continue;
}
afterOperand = false;
BinaryOperator operator = BinaryOperator.forSymbol(c);
while (!operators.isEmpty() && (operators.peek() != Parentheses.LEFT) && (((BinaryOperator) operators.peek()).precedence >= operator.precedence))
createNewOperand((BinaryOperator) operators.pop(), operands);
operators.push(operator);
continue;
}
 
if (c == '(') {
operators.push(Parentheses.LEFT);
continue;
}
 
afterOperand = true;
while (curIndex < input.length()) {
c = input.charAt(curIndex);
if (((c < '0') || (c > '9')) && (c != '.'))
break;
curIndex++;
}
operands.push(new Number(BigRational.valueOf(input.substring(startIndex, curIndex))));
}
 
while (!operators.isEmpty()) {
Object operator = operators.pop();
if (operator == Parentheses.LEFT)
throw new IllegalArgumentException();
createNewOperand((BinaryOperator) operator, operands);
}
 
Expression expression = operands.pop();
if (!operands.isEmpty())
throw new IllegalArgumentException();
return expression;
}
}
}</lang>
 
public static void main(String[] args) {
Output:
String[] testExpressions = {
<pre>Input: "2+3", AST: "(2 + 3)", eval=5
"2+3",
Input: "2+3/4", AST: "(2 + (3 / 4))", eval=11/4
"2+3/4",
Input: "2*3-4", AST: "((2 * 3) - 4)", eval=2
"2*3-4",
Input: "2*(3+4)+5/6", AST: "((2 * (3 + 4)) + (5 / 6))", eval=89/6
Input: "2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10", AST: "((2 * ((3 + ((4 * 5) + ((5/6 * 7) * 8))) - 9)) * 10)", eval=7000
Input: "2 *- (3--4 +-.25", AST: "(4 * 5 + ((26 * -37) -* -48) + -1/4 9) * 10", eval=-9/4</pre>
"2*-3--4+-.25"};
for (String testExpression : testExpressions) {
Expression expression = parse(testExpression);
System.out.printf("Input: \"%s\", AST: \"%s\", value=%s%n", testExpression, expression, expression.eval());
}
}
}</syntaxhighlight>
 
{{out}}
<pre>Input: "2+3", AST: "(2 + 3)", value=5
Input: "2+3/4", AST: "(2 + (3 / 4))", value=11/4
Input: "2*3-4", AST: "((2 * 3) - 4)", value=2
Input: "2*(3+4)+5/6", AST: "((2 * (3 + 4)) + (5 / 6))", value=89/6
Input: "2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10", AST: "((2 * ((3 + ((4 * 5) + ((6 * 7) * 8))) - 9)) * 10)", value=7000
Input: "2*-3--4+-.25", AST: "(((2 * -3) - -4) + -1/4)", value=-9/4</pre>
 
=={{header|JavaScript}}==
Line 2,181 ⟶ 3,880:
Spaces are removed, expressions like <code>5--1</code> are treated as <code>5 - -1</code>
 
<langsyntaxhighlight lang="javascript">function evalArithmeticExp(s) {
s = s.replace(/\s/g,'').replace(/^\+/,'');
var rePara = /\([^\(\)]*\)/;
Line 2,235 ⟶ 3,934:
}
}
}</langsyntaxhighlight>
 
 
{{out|Sample output:Output}}
<pre>evalArithmeticExp('2+3') // 5
evalArithmeticExp('2+3/4') // 2.75
Line 2,245 ⟶ 3,944:
evalArithmeticExp('2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10') // 7000
evalArithmeticExp('2*-3--4+-0.25' // -2.25</pre>
 
=={{header|jq}}==
[[Category:PEG]]
This entry highlights the use of a [[:Category:PEG|PEG]] grammar expressed in jq.
 
=== PEG operations ===
<syntaxhighlight lang="jq">def star(E): (E | star(E)) // .;
def plus(E): E | (plus(E) // . );
def optional(E): E // .;
def amp(E): . as $in | E | $in;
def neg(E): select( [E] == [] );</syntaxhighlight>
 
 
=== Helper functions ===
<syntaxhighlight lang="jq">def literal($s):
select(.remainder | startswith($s))
| .result += [$s]
| .remainder |= .[$s | length :] ;
 
def box(E):
((.result = null) | E) as $e
| .remainder = $e.remainder
| .result += [$e.result] # the magic sauce
;
 
# Consume a regular expression rooted at the start of .remainder, or emit empty;
# on success, update .remainder and set .match but do NOT update .result
def consume($re):
# on failure, match yields empty
(.remainder | match("^" + $re)) as $match
| .remainder |= .[$match.length :]
| .match = $match.string ;
 
def parseNumber($re):
consume($re)
| .result = .result + [.match|tonumber] ;</syntaxhighlight>
 
=== PEG Grammar ===
The PEG grammar for arithmetic expressions follows the one given at the Raku entry.<syntaxhighlight lang="jq">def Expr:
 
def ws: consume(" *");
 
def Number: ws | parseNumber( "-?[0-9]+([.][0-9]*)?" );
def Sum:
def Parenthesized: ws | consume("[(]") | ws | box(Sum) | ws | consume("[)]");
def Factor: Parenthesized // Number;
def Product: box(Factor | star( ws | (literal("*") // literal("/")) | Factor));
Product | ws | star( (literal("+") // literal("-")) | Product);
 
Sum;</syntaxhighlight>
 
=== Evaluation ===
<syntaxhighlight lang="jq"># Left-to-right evaluation
def eval:
if type == "array" then
if length == 0 then null
else .[-1] |= eval
| if length == 1 then .[0]
else (.[:-2] | eval) as $v
| if .[-2] == "*" then $v * .[-1]
elif .[-2] == "/" then $v / .[-1]
elif .[-2] == "+" then $v + .[-1]
elif .[-2] == "-" then $v - .[-1]
else tostring|error
end
end
end
else .
end;
 
def eval(String):
{remainder: String}
| Expr.result
| eval;</syntaxhighlight>
 
=== Example ===
eval("2 * (3 -1) + 2 * 5")
 
produces: 14
 
=={{header|Jsish}}==
From Javascript entry.
 
<syntaxhighlight lang="javascript">/* Arithmetic evaluation, in Jsish */
function evalArithmeticExp(s) {
s = s.replace(/\s/g,'').replace(/^\+/,'');
var rePara = /\([^\(\)]*\)/;
var exp;
function evalExp(s) {
s = s.replace(/[\(\)]/g,'');
var reMD = /[0-9]+\.?[0-9]*\s*[\*\/]\s*[+-]?[0-9]+\.?[0-9]*/;
var reM = /\*/;
var reAS = /-?[0-9]+\.?[0-9]*\s*[\+-]\s*[+-]?[0-9]+\.?[0-9]*/;
var reA = /[0-9]\+/;
var exp;
 
function multiply(s, b=0) {
b = s.split('*');
return b[0] * b[1];
}
function divide(s, b=0) {
b = s.split('/');
return b[0] / b[1];
}
function add(s, b=0) {
s = s.replace(/^\+/,'').replace(/\++/,'+');
b = s.split('+');
return Number(b[0]) + Number(b[1]);
}
function subtract(s, b=0) {
s = s.replace(/\+-|-\+/g,'-');
if (s.match(/--/)) {
return add(s.replace(/--/,'+'));
}
b = s.split('-');
return b.length == 3 ? -1 * b[1] - b[2] : b[0] - b[1];
}
 
while (exp = s.match(reMD)) {
s = exp[0].match(reM) ? s.replace(exp[0], multiply(exp[0]).toString()) : s.replace(exp[0], divide(exp[0]).toString());
}
while (exp = s.match(reAS)) {
s = exp[0].match(reA)? s.replace(exp[0], add(exp[0]).toString()) : s.replace(exp[0], subtract(exp[0]).toString());
}
 
return '' + s;
}
 
while (exp = s.match(rePara)) {
s = s.replace(exp[0], evalExp(exp[0]));
}
 
return evalExp(s);
}
 
if (Interp.conf('unitTest')) {
; evalArithmeticExp('2+3');
; evalArithmeticExp('2+3/4');
; evalArithmeticExp('2*3-4');
; evalArithmeticExp('2*(3+4)+5/6');
; evalArithmeticExp('2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10');
; evalArithmeticExp('2*-3--4+-0.25');
}
 
/*
=!EXPECTSTART!=
evalArithmeticExp('2+3') ==> 5
evalArithmeticExp('2+3/4') ==> 2.75
evalArithmeticExp('2*3-4') ==> 2
evalArithmeticExp('2*(3+4)+5/6') ==> 14.8333333333333
evalArithmeticExp('2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10') ==> 7000
evalArithmeticExp('2*-3--4+-0.25') ==> -2.25
=!EXPECTEND!=
*/</syntaxhighlight>
 
{{out}}
<pre>prompt$ jsish --U arithmeticEvaluation.jsi
evalArithmeticExp('2+3') ==> 5
evalArithmeticExp('2+3/4') ==> 2.75
evalArithmeticExp('2*3-4') ==> 2
evalArithmeticExp('2*(3+4)+5/6') ==> 14.8333333333333
evalArithmeticExp('2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10') ==> 7000
evalArithmeticExp('2*-3--4+-0.25') ==> -2.25</pre>
 
=={{header|Julia}}==
Julia's homoiconic nature and strong metaprogramming facilities make AST/Expression parsing and creation as accessible and programmatic as other language features
<langsyntaxhighlight lang="julia">julia> expr="2 * (3 -1) + 2 * 5"
"2 * (3 -1) + 2 * 5"
 
Line 2,288 ⟶ 4,157:
 
julia> eval(parse("2 * (3 + ((5) / (7 - 11)))"))
3.5</langsyntaxhighlight>
 
=={{header|Kotlin}}==
{{trans|JavaScript}}
<syntaxhighlight lang="scala">// version 1.2.10
 
/* if string is empty, returns zero */
fun String.toDoubleOrZero() = this.toDoubleOrNull() ?: 0.0
 
fun multiply(s: String): String {
val b = s.split('*').map { it.toDoubleOrZero() }
return (b[0] * b[1]).toString()
}
 
fun divide(s: String): String {
val b = s.split('/').map { it.toDoubleOrZero() }
return (b[0] / b[1]).toString()
}
 
fun add(s: String): String {
var t = s.replace(Regex("""^\+"""), "").replace(Regex("""\++"""), "+")
val b = t.split('+').map { it.toDoubleOrZero() }
return (b[0] + b[1]).toString()
}
 
fun subtract(s: String): String {
var t = s.replace(Regex("""(\+-|-\+)"""), "-")
if ("--" in t) return add(t.replace("--", "+"))
val b = t.split('-').map { it.toDoubleOrZero() }
return (if (b.size == 3) -b[1] - b[2] else b[0] - b[1]).toString()
}
 
fun evalExp(s: String): String {
var t = s.replace(Regex("""[()]"""), "")
val reMD = Regex("""\d+\.?\d*\s*[*/]\s*[+-]?\d+\.?\d*""")
val reM = Regex( """\*""")
val reAS = Regex("""-?\d+\.?\d*\s*[+-]\s*[+-]?\d+\.?\d*""")
val reA = Regex("""\d\+""")
 
while (true) {
val match = reMD.find(t)
if (match == null) break
val exp = match.value
val match2 = reM.find(exp)
t = if (match2 != null)
t.replace(exp, multiply(exp))
else
t.replace(exp, divide(exp))
}
 
while (true) {
val match = reAS.find(t)
if (match == null) break
val exp = match.value
val match2 = reA.find(exp)
t = if (match2 != null)
t.replace(exp, add(exp))
else
t.replace(exp, subtract(exp))
}
 
return t
}
 
fun evalArithmeticExp(s: String): Double {
var t = s.replace(Regex("""\s"""), "").replace("""^\+""", "")
val rePara = Regex("""\([^()]*\)""")
while(true) {
val match = rePara.find(t)
if (match == null) break
val exp = match.value
t = t.replace(exp, evalExp(exp))
}
return evalExp(t).toDoubleOrZero()
}
 
fun main(arsg: Array<String>) {
listOf(
"2+3",
"2+3/4",
"2*3-4",
"2*(3+4)+5/6",
"2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10",
"2*-3--4+-0.25",
"-4 - 3",
"((((2))))+ 3 * 5",
"1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10",
"1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1"
).forEach { println("$it = ${evalArithmeticExp(it)}") }
}</syntaxhighlight>
 
{{out}}
<pre>
2+3 = 5.0
2+3/4 = 2.75
2*3-4 = 2.0
2*(3+4)+5/6 = 14.833333333333334
2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10 = 7000.0
2*-3--4+-0.25 = -2.25
-4 - 3 = -7.0
((((2))))+ 3 * 5 = 17.0
1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10 = 71.0
1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1 = 60.0
</pre>
 
=={{header|Liberty BASIC}}==
<syntaxhighlight lang="lb">
'[RC] Arithmetic evaluation.bas
'Buld the tree (with linked nodes, in array 'cause LB has no pointers)
'applying shunting yard algorythm.
'Then evaluate tree
 
global stack$ 'operator/brakets stack
stack$=""
 
maxStack = 100
dim stack(maxStack) 'nodes stack
global SP 'stack pointer
SP = 0
 
'-------------------
global maxNode,curFree
global FirstOp,SecondOp,isNumber,NodeCont
global opList$
opList$ = "+-*/^"
 
maxNode=100
FirstOp=1 'pointers to other nodes; 0 means no pointer
SecondOp=2
isNumber=3 'like, 1 is number, 0 is operator
NodeCont=4 'number if isNumber; or mid$("+-*/^", i, 1) for 1..5 operator
 
dim node(NodeCont, maxNode)
'will be used from 1, 0 plays null pointer (no link)
 
curFree=1 'first free node
'-------------------
 
in$ = " 1 + 2 ^ 3 * 4 - 12 / 6 "
print "Input: "
print in$
 
'read tokens
token$ = "#"
while 1
i=i+1
token$ = word$(in$, i)
if token$ = "" then i=i-1: exit while
 
select case
case token$ = "("
'If the token is a left parenthesis, then push it onto the stack.
call stack.push token$
 
case token$ = ")"
'If the token is a right parenthesis:
'Until the token at the top of the stack is a left parenthesis, pop operators off the stack onto the output queue.
'Pop the left parenthesis from the stack, but not onto the output queue.
'If the stack runs out without finding a left parenthesis, then there are mismatched parentheses.
while stack.peek$() <> "("
'if stack is empty
if stack$="" then print "Error: no matching '(' for token ";i: end
'add operator node to tree
child2=node.pop()
child1=node.pop()
call node.push addOpNode(child1,child2,stack.pop$())
wend
discard$=stack.pop$() 'discard "("
 
case isOperator(token$)
'If the token is an operator, o1, then:
'while there is an operator token, o2, at the top of the stack, and
'either o1 is left-associative and its precedence is equal to that of o2,
'or o1 has precedence less than that of o2,
' pop o2 off the stack, onto the output queue;
'push o1 onto the stack
op1$=token$
while(isOperator(stack.peek$()))
op2$=stack.peek$()
if (op2$<>"^" and precedence(op1$) = precedence(op2$)) _
OR (precedence(op1$) < precedence(op2$)) then
'"^" is the only right-associative operator
'add operator node to tree
child2=node.pop()
child1=node.pop()
call node.push addOpNode(child1,child2,stack.pop$())
else
exit while
end if
wend
call stack.push op1$
 
case else 'number
'actually, wrohg operator could end up here, like say %
'If the token is a number, then
'add leaf node to tree (number)
call node.push addNumNode(val(token$))
end select
 
wend
 
'When there are no more tokens to read:
'While there are still operator tokens in the stack:
' If the operator token on the top of the stack is a parenthesis, then there are mismatched parentheses.
' Pop the operator onto the output queue.
while stack$<>""
if stack.peek$() = "(" then print "no matching ')'": end
'add operator node to tree
child2=node.pop()
child1=node.pop()
call node.push addOpNode(child1,child2,stack.pop$())
wend
 
root = node.pop()
'call dumpNodes
print "Tree:"
call drawTree root, 1, 0, 3
locate 1, 10
print "Result: ";evaluate(root)
 
end
 
'------------------------------------------
function isOperator(op$)
isOperator = instr(opList$, op$)<>0 AND len(op$)=1
end function
 
function precedence(op$)
if isOperator(op$) then
precedence = 1 _
+ (instr("+-*/^", op$)<>0) _
+ (instr("*/^", op$)<>0) _
+ (instr("^", op$)<>0)
end if
end function
 
'------------------------------------------
sub stack.push s$
stack$=s$+"|"+stack$
end sub
 
function stack.pop$()
'it does return empty on empty stack or queue
stack.pop$=word$(stack$,1,"|")
stack$=mid$(stack$,instr(stack$,"|")+1)
end function
 
function stack.peek$()
'it does return empty on empty stack or queue
stack.peek$=word$(stack$,1,"|")
end function
 
'---------------------------------------
sub node.push s
stack(SP)=s
SP=SP+1
end sub
 
function node.pop()
'it does return -999999 on empty stack
if SP<1 then pop=-999999: exit function
SP=SP-1
node.pop=stack(SP)
end function
 
'=======================================
sub dumpNodes
for i = 1 to curFree-1
print i,
for j = 1 to 4
print node(j, i),
next
print
next
print
end sub
 
function evaluate(node)
if node=0 then exit function
if node(isNumber, node) then
evaluate = node(NodeCont, node)
exit function
end if
'else operator
op1 = evaluate(node(FirstOp, node))
op2 = evaluate(node(SecondOp, node))
select case node(NodeCont, node) 'opList$, "+-*/^"
case 1
evaluate = op1+op2
case 2
evaluate = op1-op2
case 3
evaluate = op1*op2
case 4
evaluate = op1/op2
case 5
evaluate = op1^op2
end select
end function
 
sub drawTree node, level, leftRight, offsetY
if node=0 then exit sub
call drawTree node(FirstOp, node), level+1, leftRight-1/2^level, offsetY
 
'print node
'count on 80 char maiwin
x = 40*(1+leftRight)
y = level+offsetY
locate x, y
'print x, y,">";
if node(isNumber, node) then
print node(NodeCont, node)
else
print mid$(opList$, node(NodeCont, node),1)
end if
 
call drawTree node(SecondOp, node), level+1, leftRight+1/2^level, offsetY
end sub
 
function addNumNode(num)
'returns new node
newNode=curFree
curFree=curFree+1
node(isNumber,newNode)=1
node(NodeCont,newNode)=num
 
addNumNode = newNode
end function
 
function addOpNode(firstChild, secondChild, op$)
'returns new node
'FirstOrSecond ignored if parent is 0
newNode=curFree
curFree=curFree+1
node(isNumber,newNode)=0
node(NodeCont,newNode)=instr(opList$, op$)
 
node(FirstOp,newNode)=firstChild
node(SecondOp,newNode)=secondChild
 
addOpNode = newNode
end function
</syntaxhighlight>
 
{{out}}
<pre>
Input:
1 + 2 ^ 3 * 4 - 12 / 6
Tree:
-
+ /
1 * 12 6
^ 4
2 3
 
Result: 31
</pre>
 
=={{header|Lua}}==
 
<langsyntaxhighlight lang="lua">require"lpeg"
 
P, R, C, S, V = lpeg.P, lpeg.R, lpeg.C, lpeg.S, lpeg.V
Line 2,331 ⟶ 4,556:
end
 
print(eval{expression:match(io.read())})</langsyntaxhighlight>
 
=={{header|MathematicaM2000 Interpreter}}==
There is a function called EVAL which has many variants, one of them is the Expression Evaluation (when we pass a string as parameter).
<lang Mathematica>(*parsing:*)
All visible variables can be used, and all known functions, internal and user (if they are visible at that point). Global variables and functions are always visible.
 
<syntaxhighlight lang="m2000 interpreter">
y=100
Module CheckEval {
A$="1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10"
Print Eval(A$)
x=10
Print Eval("x+5")=x+5
Print Eval("A$=A$")=True
Try {
Print Eval("y") ' error: y is uknown here
}
}
Call CheckEval
</syntaxhighlight>
 
New version of the task program. Based on BBC Basic. Exclude the final use of Eval() function (we use it for test only)
The Ast is a stack object which have strings and numbers. String are operators. This stack has all members in a RPN form. So it is easy to extract numbers and push them to reg (a stack also), and process the operators as they pop from the stack. There is no unary operator.
 
So the Ast isn't a tree here, it is a flat list.
 
<syntaxhighlight lang="m2000 interpreter">
Module CheckAst {
class EvalAst {
private:
Function Ast(&in$) {
object Ast=stack, op=stack
Do
stack Ast {stack .Ast1(&in$)}
in$=Trim$(in$)
oper$=left$(in$,1)
if Instr("+-", oper$)>0 else exit
if len(oper$)>0 then stack op {push oper$}
in$=Mid$(in$, 2)
until len(in$)=0
stack Ast {stack op} // dump op to end of stack Ast
=Ast
}
Function Ast1(&in$) {
object Ast=stack, op=stack
Do
stack Ast {stack .Ast2(&in$)}
in$=Trim$(in$)
oper$=left$(in$,1)
if Instr("*/", oper$)>0 else exit
if len(oper$)>0 then stack op {push oper$}
in$=Mid$(in$, 2)
until len(in$)=0
stack Ast {stack op}
=Ast
}
Function Ast2(&in$) {
in$=Trim$(in$)
if Asc(in$)<>40 then =.GetNumber(&in$) : exit
in$=Mid$(in$, 2)
=.Ast(&in$)
in$=Mid$(in$, 2)
}
Function GetNumber (&in$) {
Def ch$, num$
Do
ch$=left$(in$,1)
if instr("0123456789", ch$)>0 else exit
num$+=ch$
in$=Mid$(in$, 2)
until len(in$)=0
=stack:=val(num$)
}
public:
value () {
=.Ast(![])
}
}
Ast=EvalAst()
Expr$ = "1+2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10"
// Expr$="1/2+(4-3)/2+1/2"
print "Result through eval$:";eval(Expr$)
print "Expr :";Expr$
mres=Ast(&Expr$)
print "RPN :";array(stack(mres))#str$()
reg=stack
stack mres {
while not empty
if islet then
read op$
stack reg {
select case op$
case "+"
push number+number
case "-"
shift 2:push number-number
case "*"
push number*number
case "/"
shift 2:push number/number // shif 2 swap top 2 values
end select
}
else
read v
stack reg {push v}
end if
end while
}
if len(reg)<>1 then Error "Wrong Evaluation"
print "Result :";stackitem(reg)
}
CheckAst
</syntaxhighlight>
 
{{out}}
<pre>
Result through eval$:71
Expr : 1+2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10
RPN : 1 2 3 4 5 * 6 7 8 * * + 9 - + 10 / * +
Result :71
</pre>
 
=={{header|Mathematica}} / {{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">(*parsing:*)
parse[string_] :=
Module[{e},
Line 2,367 ⟶ 4,712:
evaluate[{"*", a_, b_}] := evaluate[a]*evaluate[b];
evaluate[{"/", a_, b_}] := evaluate[a]/evaluate[b];
evaluate[string_String] := evaluate[parse[string]]</langsyntaxhighlight>
 
Example use:
<langsyntaxhighlight Mathematicalang="mathematica">parse["-1+2(3+4*-5/6)"]
evaluate["-1+2(3+4*-5/6)"]</langsyntaxhighlight>
 
{{out}}
Output:
<pre>{"+", {"-", 1}, {"*", 2, {"-", 3, {"/", {"*", 4, {"-", 5}}, 6}}}}
35/3</pre>
 
=={{header|MiniScript}}==
<syntaxhighlight lang="miniscript">Expr = {}
Expr.eval = 0
 
BinaryExpr = new Expr
BinaryExpr.eval = function()
if self.op == "+" then return self.lhs.eval + self.rhs.eval
if self.op == "-" then return self.lhs.eval - self.rhs.eval
if self.op == "*" then return self.lhs.eval * self.rhs.eval
if self.op == "/" then return self.lhs.eval / self.rhs.eval
end function
binop = function(lhs, op, rhs)
e = new BinaryExpr
e.lhs = lhs
e.op = op
e.rhs = rhs
return e
end function
 
parseAtom = function(inp)
tok = inp.pull
if tok >= "0" and tok <= "9" then
e = new Expr
e.eval = val(tok)
while inp and inp[0] >= "0" and inp[0] <= "9"
e.eval = e.eval * 10 + val(inp.pull)
end while
else if tok == "(" then
e = parseAddSub(inp)
inp.pull // swallow closing ")"
return e
else
print "Unexpected token: " + tok
exit
end if
return e
end function
 
parseMultDiv = function(inp)
next = @parseAtom
e = next(inp)
while inp and (inp[0] == "*" or inp[0] == "/")
e = binop(e, inp.pull, next(inp))
end while
return e
end function
 
parseAddSub = function(inp)
next = @parseMultDiv
e = next(inp)
while inp and (inp[0] == "+" or inp[0] == "-")
e = binop(e, inp.pull, next(inp))
end while
return e
end function
 
while true
s = input("Enter expression: ").replace(" ","")
if not s then break
inp = split(s, "")
ast = parseAddSub(inp)
print ast.eval
end while
</syntaxhighlight>
{{out}}
<pre>Enter expression: 200*42
8400
Enter expression: 2+2+2
6
Enter expression: 2 + 3 * 4
14
Enter expression: (2+3)*4
20
Enter expression:
</pre>
 
=={{header|Nim}}==
 
{{works with|Nim|0.19.0}}
 
This implementation uses a Pratt parser.
 
<syntaxhighlight lang="nim">import strutils
import os
 
#--
# Lexer
#--
 
type
TokenKind = enum
tokNumber
tokPlus = "+", tokMinus = "-", tokStar = "*", tokSlash = "/"
tokLPar, tokRPar
tokEnd
Token = object
case kind: TokenKind
of tokNumber: value: float
else: discard
 
proc lex(input: string): seq[Token] =
# Here we go through the entire input string and collect all the tokens into
# a sequence.
var pos = 0
while pos < input.len:
case input[pos]
of '0'..'9':
# Digits consist of three parts: the integer part, the delimiting decimal
# point, and the decimal part.
var numStr = ""
while pos < input.len and input[pos] in Digits:
numStr.add(input[pos])
inc(pos)
if pos < input.len and input[pos] == '.':
numStr.add('.')
inc(pos)
while pos < input.len and input[pos] in Digits:
numStr.add(input[pos])
inc(pos)
result.add(Token(kind: tokNumber, value: numStr.parseFloat()))
of '+': inc(pos); result.add(Token(kind: tokPlus))
of '-': inc(pos); result.add(Token(kind: tokMinus))
of '*': inc(pos); result.add(Token(kind: tokStar))
of '/': inc(pos); result.add(Token(kind: tokSlash))
of '(': inc(pos); result.add(Token(kind: tokLPar))
of ')': inc(pos); result.add(Token(kind: tokRPar))
of ' ': inc(pos)
else: raise newException(ArithmeticError,
"Unexpected character '" & input[pos] & '\'')
# We append an 'end' token to the end of our token sequence, to mark where the
# sequence ends.
result.add(Token(kind: tokEnd))
 
#--
# Parser
#--
 
type
ExprKind = enum
exprNumber
exprBinary
Expr = ref object
case kind: ExprKind
of exprNumber: value: float
of exprBinary:
left, right: Expr
operator: TokenKind
 
proc `$`(ex: Expr): string =
# This proc returns a lisp representation of the expression.
case ex.kind
of exprNumber: $ex.value
of exprBinary: '(' & $ex.operator & ' ' & $ex.left & ' ' & $ex.right & ')'
 
var
# The input to the program is provided via command line parameters.
tokens = lex(commandLineParams().join(" "))
pos = 0
 
# This table stores the precedence level of each infix operator. For tokens
# this does not apply to, the precedence is set to 0.
const Precedence: array[low(TokenKind)..high(TokenKind), int] = [
tokNumber: 0,
tokPlus: 1,
tokMinus: 1,
tokStar: 2,
tokSlash: 2,
tokLPar: 0,
tokRPar: 0,
tokEnd: 0
]
 
# We use a Pratt parser, so the two primary components are the prefix part, and
# the infix part. We start with a prefix token, and when we're done, we continue
# with an infix token.
 
proc parse(prec = 0): Expr
 
proc parseNumber(token: Token): Expr =
result = Expr(kind: exprNumber, value: token.value)
 
proc parseParen(token: Token): Expr =
result = parse()
if tokens[pos].kind != tokRPar:
raise newException(ArithmeticError, "Unbalanced parenthesis")
inc(pos)
 
proc parseBinary(left: Expr, token: Token): Expr =
result = Expr(kind: exprBinary, left: left, right: parse(),
operator: token.kind)
 
proc parsePrefix(token: Token): Expr =
case token.kind
of tokNumber: result = parseNumber(token)
of tokLPar: result = parseParen(token)
else: discard
 
proc parseInfix(left: Expr, token: Token): Expr =
case token.kind
of tokPlus, tokMinus, tokStar, tokSlash: result = parseBinary(left, token)
else: discard
 
proc parse(prec = 0): Expr =
# This procedure is the heart of a Pratt parser, it puts the whole expression
# together into one abstract syntax tree, properly dealing with precedence.
var token = tokens[pos]
inc(pos)
result = parsePrefix(token)
while prec < Precedence[tokens[pos].kind]:
token = tokens[pos]
if token.kind == tokEnd:
# When we hit the end token, we're done.
break
inc(pos)
result = parseInfix(result, token)
 
let ast = parse()
 
proc `==`(ex: Expr): float =
# This proc recursively evaluates the given expression.
result =
case ex.kind
of exprNumber: ex.value
of exprBinary:
case ex.operator
of tokPlus: ==ex.left + ==ex.right
of tokMinus: ==ex.left - ==ex.right
of tokStar: ==ex.left * ==ex.right
of tokSlash: ==ex.left / ==ex.right
else: 0.0
 
# In the end, we print out the result.
echo ==ast</syntaxhighlight>
 
=={{header|OCaml}}==
 
<langsyntaxhighlight lang="ocaml">type expression =
| Const of float
| Sum of expression * expression (* e1 + e2 *)
Line 2,417 ⟶ 4,996:
let parse_expression = parser [< e = parse_expr; _ = Stream.empty >] -> e
 
let read_expression s = parse_expression(lexer(Stream.of_string s))</langsyntaxhighlight>
 
Using the function <code>read_expression</code> in an interactive loop:
 
<langsyntaxhighlight lang="ocaml">let () =
while true do
print_string "Expression: ";
Line 2,429 ⟶ 5,008:
let res = eval expr in
Printf.printf " = %g\n%!" res;
done</langsyntaxhighlight>
 
Compile with:
Line 2,435 ⟶ 5,014:
 
=={{header|ooRexx}}==
<syntaxhighlight lang="oorexx">
<lang ooRexx>
expressions = .array~of("2+3", "2+3/4", "2*3-4", "2*(3+4)+5/6", "2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10", "2*-3--4+-.25")
loop input over expressions
Line 2,671 ⟶ 5,250:
raise syntax 98.900 array("Invalid expression")
return expression
</syntaxhighlight>
</lang>
{{out}}
Output:
<pre>
Expression "2+3" parses to "(2 + 3)" and evaluates to "5"
Line 2,681 ⟶ 5,260:
Expression "2*-3--4+-.25" parses to "(((2 * -3) - -4) + -.25)" and evaluates to "-2.25"
</pre>
 
=={{header|Oz}}==
We can create a simple, but slow parser using logic programming.
Line 2,687 ⟶ 5,267:
The <code>Do</code> procedure automatically threads the input state through a sequence of procedure calls.
 
<langsyntaxhighlight lang="oz">declare
 
fun {Expr X0 ?X}
Line 2,774 ⟶ 5,354:
{Inspector.configure widgetShowStrings true}
{Inspect AST}
{Inspect {Eval AST}}</langsyntaxhighlight>
 
To improve performance, the number of choice points should be limited, for example by reading numbers deterministically instead.
Line 2,783 ⟶ 5,363:
 
=={{header|Perl}}==
<langsyntaxhighlight lang="perl">sub ev
# Evaluates an arithmetic expression like "(1+3)*7" and returns
# its value.
Line 2,843 ⟶ 5,423:
my ($op, @operands) = @$ast;
$_ = ev_ast($_) foreach @operands;
return $ops{$op}->(@operands);}}</langsyntaxhighlight>
 
=={{header|Perl 6Phix}}==
This is really just a simplification of the one in the heart of Phix,
{{works with|Rakudo|#22 "Thousand Oaks"}}
which of course by now is thousands of lines spread over several files,
plus this as asked for has an AST, whereas Phix uses cross-linked flat IL.
See also [[Arithmetic_evaluation/Phix]] for a translation of the D entry.
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">-- demo\rosetta\Arithmetic_evaluation.exw</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">opstack</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span> <span style="color: #000080;font-style:italic;">-- atom elements are literals,
-- sequence elements are subexpressions
-- on completion length(opstack) should be 1</span>
<span style="color: #004080;">object</span> <span style="color: #000000;">token</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">op_p_p</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- 1: expressions stored as op,p1,p2
-- p_op_p -- 0: expressions stored as p1,op,p2
-- p_p_op -- -1: expressions stored as p1,p2,op</span>
<span style="color: #004080;">object</span> <span style="color: #000000;">op</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span> <span style="color: #000080;font-style:italic;">-- 0 if none, else "+", "-", "*", "/", "^", "%", or "u-"</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">s</span> <span style="color: #000080;font-style:italic;">-- the expression being parsed</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">ch</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">sidx</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">err</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%s\n%s^ %s\n\nPressEnter..."</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">s</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">),</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">})</span>
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">abort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">nxtch</span><span style="color: #0000FF;">(</span><span style="color: #004080;">object</span> <span style="color: #000000;">msg</span><span style="color: #0000FF;">=</span><span style="color: #008000;">"eof"</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">sidx</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">sidx</span><span style="color: #0000FF;">></span><span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">if</span> <span style="color: #004080;">string</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #000000;">err</span><span style="color: #0000FF;">(</span><span style="color: #000000;">msg</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">ch</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">skipspaces</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">while</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\t'</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\r'</span><span style="color: #0000FF;">,</span><span style="color: #008000;">'\n'</span><span style="color: #0000FF;">})!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">do</span> <span style="color: #000000;">nxtch</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">get_token</span><span style="color: #0000FF;">()</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">fraction</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">dec</span>
<span style="color: #000000;">skipspaces</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #000000;">token</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"eof"</span> <span style="color: #008080;">return</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">>=</span><span style="color: #008000;">'0'</span> <span style="color: #008080;">and</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;"><=</span><span style="color: #008000;">'9'</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">-</span><span style="color: #008000;">'0'</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">nxtch</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;"><</span><span style="color: #008000;">'0'</span> <span style="color: #008080;">or</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">></span><span style="color: #008000;">'9'</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">*</span><span style="color: #000000;">10</span><span style="color: #0000FF;">+</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">-</span><span style="color: #008000;">'0'</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'.'</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">dec</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #000000;">fraction</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">nxtch</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;"><</span><span style="color: #008000;">'0'</span> <span style="color: #008080;">or</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">></span><span style="color: #008000;">'9'</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">fraction</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">fraction</span><span style="color: #0000FF;">*</span><span style="color: #000000;">10</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">-</span><span style="color: #008000;">'0'</span>
<span style="color: #000000;">dec</span> <span style="color: #0000FF;">*=</span> <span style="color: #000000;">10</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #000000;">n</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">fraction</span><span style="color: #0000FF;">/</span><span style="color: #000000;">dec</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000080;font-style:italic;">-- if find(ch,"eE") then -- you get the idea
-- end if</span>
<span style="color: #000000;">token</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">n</span>
<span style="color: #008080;">return</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ch</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"+-/*()^%"</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #000000;">err</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"syntax error"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">token</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">..</span><span style="color: #000000;">sidx</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">nxtch</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">return</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">Match</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">t</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">token</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">t</span> <span style="color: #008080;">then</span> <span style="color: #000000;">err</span><span style="color: #0000FF;">(</span><span style="color: #000000;">t</span><span style="color: #0000FF;">&</span><span style="color: #008000;">" expected"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">get_token</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">PopFactor</span><span style="color: #0000FF;">()</span>
<span style="color: #004080;">object</span> <span style="color: #000000;">p1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">p2</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">opstack</span><span style="color: #0000FF;">[$]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">op</span><span style="color: #0000FF;">=</span><span style="color: #008000;">"u-"</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">p1</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">opstack</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">opstack</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..$-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">p1</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">opstack</span><span style="color: #0000FF;">[$]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">op_p_p</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">opstack</span><span style="color: #0000FF;">[$]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">op</span><span style="color: #0000FF;">,</span><span style="color: #000000;">p1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">p2</span><span style="color: #0000FF;">}</span> <span style="color: #000080;font-style:italic;">-- op_p_p</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">op_p_p</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">opstack</span><span style="color: #0000FF;">[$]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">p1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">op</span><span style="color: #0000FF;">,</span><span style="color: #000000;">p2</span><span style="color: #0000FF;">}</span> <span style="color: #000080;font-style:italic;">-- p_op_p</span>
<span style="color: #008080;">else</span> <span style="color: #000080;font-style:italic;">-- -1</span>
<span style="color: #000000;">opstack</span><span style="color: #0000FF;">[$]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">p1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">p2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">op</span><span style="color: #0000FF;">}</span> <span style="color: #000080;font-style:italic;">-- p_p_op</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">op</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">PushFactor</span><span style="color: #0000FF;">(</span><span style="color: #004080;">atom</span> <span style="color: #000000;">t</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">op</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #000000;">PopFactor</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">opstack</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">append</span><span style="color: #0000FF;">(</span><span style="color: #000000;">opstack</span><span style="color: #0000FF;">,</span><span style="color: #000000;">t</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">PushOp</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">t</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">op</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #000000;">PopFactor</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">op</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">t</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">forward</span> <span style="color: #008080;">procedure</span> <span style="color: #000000;">Expr</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">Factor</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">if</span> <span style="color: #004080;">atom</span><span style="color: #0000FF;">(</span><span style="color: #000000;">token</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">PushFactor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">token</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">ch</span><span style="color: #0000FF;">!=-</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">get_token</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">token</span><span style="color: #0000FF;">=</span><span style="color: #008000;">"+"</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- (ignore)</span>
<span style="color: #000000;">nxtch</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">Factor</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">token</span><span style="color: #0000FF;">=</span><span style="color: #008000;">"-"</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">get_token</span><span style="color: #0000FF;">()</span>
<span style="color: #000080;font-style:italic;">-- Factor()</span>
<span style="color: #000000;">Expr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">3</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- makes "-3^2" yield -9 (ie -(3^2)) not 9 (ie (-3)^2).</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">op</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #000000;">PopFactor</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #004080;">integer</span><span style="color: #0000FF;">(</span><span style="color: #000000;">opstack</span><span style="color: #0000FF;">[$])</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">opstack</span><span style="color: #0000FF;">[$]</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">opstack</span><span style="color: #0000FF;">[$]</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">PushOp</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"u-"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">token</span><span style="color: #0000FF;">=</span><span style="color: #008000;">"("</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">get_token</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">Expr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">Match</span><span style="color: #0000FF;">(</span><span style="color: #008000;">")"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">else</span>
<span style="color: #000000;">err</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"syntax error"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">constant</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">operators</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">precedence</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">associativity</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">columnize</span><span style="color: #0000FF;">({{</span><span style="color: #008000;">"^"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"%"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"*"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"/"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"+"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"-"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">$})</span>
<span style="color: #008080;">procedure</span> <span style="color: #000000;">Expr</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">--
-- Parse an expression, using precedence climbing.
--
-- p is the precedence level we should parse to, eg/ie
-- 4: Factor only (may as well just call Factor)
-- 3: "" and ^
-- 2: "" and *,/,%
-- 1: "" and +,-
-- 0: full expression (effectively the same as 1)
-- obviously, parentheses override any setting of p.
--</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">thisp</span>
<span style="color: #000000;">Factor</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">find</span><span style="color: #0000FF;">(</span><span style="color: #000000;">token</span><span style="color: #0000FF;">,</span><span style="color: #000000;">operators</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- *,/,+,-</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">k</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">thisp</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">precedence</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">thisp</span><span style="color: #0000FF;"><</span><span style="color: #000000;">p</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #000000;">get_token</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">Expr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">thisp</span><span style="color: #0000FF;">+</span><span style="color: #000000;">associativity</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">])</span>
<span style="color: #000000;">PushOp</span><span style="color: #0000FF;">(</span><span style="color: #000000;">operators</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">])</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">evaluate</span><span style="color: #0000FF;">(</span><span style="color: #004080;">object</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">object</span> <span style="color: #000000;">lhs</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">rhs</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">op</span>
<span style="color: #008080;">if</span> <span style="color: #004080;">atom</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">s</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">op_p_p</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- op_p_p</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">op</span><span style="color: #0000FF;">,</span><span style="color: #000000;">lhs</span><span style="color: #0000FF;">,</span><span style="color: #000000;">rhs</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">op_p_p</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- p_op_p</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">lhs</span><span style="color: #0000FF;">,</span><span style="color: #000000;">op</span><span style="color: #0000FF;">,</span><span style="color: #000000;">rhs</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span>
<span style="color: #008080;">else</span> <span style="color: #000080;font-style:italic;">-- -1 -- p_p_op</span>
<span style="color: #0000FF;">{</span><span style="color: #000000;">lhs</span><span style="color: #0000FF;">,</span><span style="color: #000000;">rhs</span><span style="color: #0000FF;">,</span><span style="color: #000000;">op</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">s</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #004080;">sequence</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lhs</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #000000;">lhs</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">evaluate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lhs</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #004080;">sequence</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rhs</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">then</span> <span style="color: #000000;">rhs</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">evaluate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rhs</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">op</span><span style="color: #0000FF;">=</span><span style="color: #008000;">"+"</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">lhs</span><span style="color: #0000FF;">+</span><span style="color: #000000;">rhs</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">op</span><span style="color: #0000FF;">=</span><span style="color: #008000;">"-"</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">lhs</span><span style="color: #0000FF;">-</span><span style="color: #000000;">rhs</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">op</span><span style="color: #0000FF;">=</span><span style="color: #008000;">"*"</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">lhs</span><span style="color: #0000FF;">*</span><span style="color: #000000;">rhs</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">op</span><span style="color: #0000FF;">=</span><span style="color: #008000;">"/"</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">lhs</span><span style="color: #0000FF;">/</span><span style="color: #000000;">rhs</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">op</span><span style="color: #0000FF;">=</span><span style="color: #008000;">"^"</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lhs</span><span style="color: #0000FF;">,</span><span style="color: #000000;">rhs</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">op</span><span style="color: #0000FF;">=</span><span style="color: #008000;">"%"</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">remainder</span><span style="color: #0000FF;">(</span><span style="color: #000000;">lhs</span><span style="color: #0000FF;">,</span><span style="color: #000000;">rhs</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">elsif</span> <span style="color: #000000;">op</span><span style="color: #0000FF;">=</span><span style="color: #008000;">"u-"</span> <span style="color: #008080;">then</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">rhs</span>
<span style="color: #008080;">else</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">9</span><span style="color: #0000FF;">/</span><span style="color: #000000;">0</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #000000;">s</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"3+4+5+6*7/1*5^2^3"</span> <span style="color: #000080;font-style:italic;">-- 16406262</span>
<span style="color: #000000;">sidx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0</span>
<span style="color: #000000;">nxtch</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">get_token</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">Expr</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">op</span><span style="color: #0000FF;">!=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span> <span style="color: #000000;">PopFactor</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">opstack</span><span style="color: #0000FF;">)!=</span><span style="color: #000000;">1</span> <span style="color: #008080;">then</span> <span style="color: #000000;">err</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"some error"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"expression: \"%s\"\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">s</span><span style="color: #0000FF;">})</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"AST (flat): "</span><span style="color: #0000FF;">)</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">opstack</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"AST (tree):\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">ppEx</span><span style="color: #0000FF;">(</span><span style="color: #000000;">opstack</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],{</span><span style="color: #004600;">pp_Nest</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9999</span><span style="color: #0000FF;">})</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"result: "</span><span style="color: #0000FF;">)</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">evaluate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">opstack</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">])</span>
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
I added a flag (for this task) to store the ast nodes as op_p_p, p_op_p, or p_p_op, whichever you prefer.
{{out}}
For "3+4+5+6*7/1*5^2^3", the fully parenthesised Phix equivalent being ((3+4)+5)+(((6*7)/1)*power(5,power(2,3)))
<pre>
with op_p_p:
AST (flat): {"+",{"+",{"+",3,4},5},{"*",{"/",{"*",6,7},1},{"^",5,{"^",2,3}}}}
AST (tree):
{"+",
{"+",
{"+",
3,
4},
5},
{"*",
{"/",
{"*",
6,
7},
1},
{"^",
5,
{"^",
2,
3}}}}
result: 16406262
 
with p_op_p:
<lang perl6>sub ev (Str $s --> Num) {
AST (flat): {{{3,"+",4},"+",5},"+",{{{6,"*",7},"/",1},"*",{5,"^",{2,"^",3}}}}
AST (tree):
{{{3,
"+",
4},
"+",
5},
"+",
{{{6,
"*",
7},
"/",
1},
"*",
{5,
"^",
{2,
"^",
3}}}}
result: 16406262
 
and lastly with p_p_op:
grammar expr {
16406262
token TOP { ^ <sum> $ }
AST (flat): {{{3,4,"+"},5,"+"},{{{6,7,"*"},1,"/"},{5,{2,3,"^"},"^"},"*"},"+"}
token sum { <product> (('+' || '-') <product>)* }
AST (tree):
token product { <factor> (('*' || '/') <factor>)* }
{{{3,
token factor { <unary_minus>? [ <parens> || <literal> ] }
4,
token unary_minus { '-' }
"+"},
token parens { '(' <sum> ')' }
5,
token literal { \d+ ['.' \d+]? || '.' \d+ }
"+"},
{{{6,
7,
my sub minus ($b) { $b ?? -1 !! +1 }
"*"},
1,
"/"},
{5,
{2,
3,
"^"},
"^"},
"*"},
"+"}
result: 16406262
</pre>
 
=={{header|Picat}}==
my sub sum ($x) {
<syntaxhighlight lang="picat">main =>
[+] product($x<product>), map
print("Enter an expression: "),
{ minus($^y[0] eq '-') * product $^y<product> },
Str = |read_line($x[0] or []),
Exp = parse_term(Str),
}
Res is Exp,
myprintf("Result sub= product%w\n", ($xRes) {.
</syntaxhighlight>
[*] factor($x<factor>), map
{ factor($^y<factor>) ** minus($^y[0] eq '/') },
|($x[0] or [])
}
my sub factor ($x) {
minus($x<unary_minus>) * ($x<parens>
?? sum $x<parens><sum>
!! $x<literal>)
}
 
expr.parse([~] split /\s+/, $s);
$/ or fail 'No parse.';
sum $/<sum>;
 
}</lang>
 
Testing:
 
<lang perl6>say ev '5'; # 5
say ev '1 + 2 - 3 * 4 / 5'; # 0.6
say ev '1 + 5*3.4 - .5 -4 / -2 * (3+4) -6'; # 25.5
say ev '((11+15)*15)* 2 + (3) * -4 *1'; # 768</lang>
 
=={{header|PicoLisp}}==
Line 2,897 ⟶ 5,736:
(numbers and transient symbols). From that, a recursive descendent parser can
build an expression tree, resulting in directly executable Lisp code.
<langsyntaxhighlight PicoLisplang="picolisp">(de ast (Str)
(let *L (str Str "")
(aggregate) ) )
Line 2,919 ⟶ 5,758:
((= "+" X) (term))
((= "-" X) (list '- (term)))
((= "(" X) (prog1 (aggregate) (pop '*L)))) ) ) )</langsyntaxhighlight>
{{out}}
Output:
<langsyntaxhighlight PicoLisplang="picolisp">: (ast "1+2+3*-4/(1+2)")
-> (+ (+ 1 2) (/ (* 3 (- 4)) (+ 1 2)))
 
: (ast "(1+2+3)*-4/(1+2)")
-> (/ (* (+ (+ 1 2) 3) (- 4)) (+ 1 2))</langsyntaxhighlight>
 
=={{header|Pop11}}==
 
<langsyntaxhighlight lang="pop11">/* Scanner routines */
/* Uncomment the following to parse data from standard input
 
Line 3,077 ⟶ 5,916:
 
;;; Test it
arith_eval(do_expr()) =></langsyntaxhighlight>
 
=={{header|Prolog}}==
{{works with|SWI Prolog 8.1.19}}
<langsyntaxhighlight lang="prolog">% Lexer
numeric(X) :- 48 =< X, X =< 57.
not_numeric(X) :- 48 > X ; X > 57.
Line 3,124 ⟶ 5,963:
% Solution
calculator(String, Value) :-
lex1string_codes(String, Tokens1Codes),
lex1(Codes, Tokens1),
lex2(Tokens1, Tokens2),
parse(Tokens2, Expression),
Line 3,130 ⟶ 5,970:
% Example use
% calculator("(3+50)*7-9", X).</langsyntaxhighlight>
 
=={{header|Python}}==
Line 3,136 ⟶ 5,976:
<br>A subsequent example uses Pythons' ast module to generate the abstract syntax tree.
 
<langsyntaxhighlight lang="python">import operator
 
class AstNode(object):
Line 3,251 ⟶ 6,091:
expr = raw_input("Expression:")
astTree = Lex( expr, Yaccer())
print expr, '=',astTree.eval()</langsyntaxhighlight>
 
===ast standard library module===
Python comes with its own [http://docs.python.org/3.1/library/ast.html#module-ast ast] module as part of its standard libraries. The module compiles Python source into an AST tree that can in turn be compiled to bytecode then executed.
<langsyntaxhighlight lang="python">>>> import ast
>>>
>>> expr="2 * (3 -1) + 2 * 5"
Line 3,278 ⟶ 6,118:
>>> code_object = compile(node, filename='<string>', mode='eval')
>>> eval(code_object)
16</langsyntaxhighlight>
 
=={{header|Racket}}==
 
<syntaxhighlight lang="racket">#lang racket
<lang Racket>
#lang racket
 
(require parser-tools/yacc parser-tools/lex
parser-tools/lex
(prefix-in ~ parser-tools/lex-sre))
 
Line 3,297 ⟶ 6,137:
["(" 'OPEN]
[")" 'CLOSE]
[(~: (~+ numeric) (~? (~: #\. (~* numeric))))
(token-NUM (string->number lexeme))]))
 
Line 3,315 ⟶ 6,155:
(define (calc str)
(define i (open-input-string str))
(displayln (parse (λ () (lex i)))))
 
(calc "(1 + 2 * 3) - (1+2)*-3")</syntaxhighlight>
 
</lang>
=={{header|Raku}}==
(formerly Perl 6)
{{Works with|rakudo|2018.03}}
 
<syntaxhighlight lang="raku" line>sub ev (Str $s --> Numeric) {
 
grammar expr {
token TOP { ^ <sum> $ }
token sum { <product> (('+' || '-') <product>)* }
token product { <factor> (('*' || '/') <factor>)* }
token factor { <unary_minus>? [ <parens> || <literal> ] }
token unary_minus { '-' }
token parens { '(' <sum> ')' }
token literal { \d+ ['.' \d+]? || '.' \d+ }
}
my sub minus ($b) { $b ?? -1 !! +1 }
 
my sub sum ($x) {
[+] flat product($x<product>), map
{ minus($^y[0] eq '-') * product $^y<product> },
|($x[0] or [])
}
my sub product ($x) {
[*] flat factor($x<factor>), map
{ factor($^y<factor>) ** minus($^y[0] eq '/') },
|($x[0] or [])
}
my sub factor ($x) {
minus($x<unary_minus>) * ($x<parens>
?? sum $x<parens><sum>
!! $x<literal>)
}
 
expr.parse([~] split /\s+/, $s);
$/ or fail 'No parse.';
sum $/<sum>;
 
}
 
# Testing:
 
say ev '5'; # 5
say ev '1 + 2 - 3 * 4 / 5'; # 0.6
say ev '1 + 5*3.4 - .5 -4 / -2 * (3+4) -6'; # 25.5
say ev '((11+15)*15)* 2 + (3) * -4 *1'; # 768</syntaxhighlight>
 
=={{header|REXX}}==
Several additional operators are supported as well as several forms of exponentiated numbers:
:::* &nbsp; '''^''' &nbsp; &nbsp; &nbsp; exponentiation, &nbsp; as well as &nbsp; '''**'''
:::* &nbsp; '''//''' &nbsp; &nbsp; &nbsp; remainder division
:::* &nbsp; '''%''' &nbsp; &nbsp; integer division
:::* &nbsp; '''<big>÷</big>''' &nbsp; &nbsp; &nbsp; in addition to &nbsp; '''<big>/</big>'''
:::* &nbsp; '''&amp;''' &nbsp; &nbsp; for logical &nbsp; '''andAND'''
:::* &nbsp; '''|''' &nbsp; &nbsp; &nbsp; for logical &nbsp; '''orOR'''
:::* &nbsp; '''&amp;&amp;''' &nbsp; &nbsp; for logical &nbsp; '''XOR'''
:::* &nbsp; '''||''' &nbsp; &nbsp; &nbsp; for concatenation
:::* &nbsp; '''[ &nbsp; ] &nbsp; &nbsp; { &nbsp; }''' &nbsp; &nbsp; as grouping symbols, &nbsp; as well as &nbsp; '''( &nbsp; )'''
:::* &nbsp; 12.3e+44 &nbsp; &nbsp; &nbsp; ("single" precision)
:::* &nbsp; 12.3E+44 &nbsp; &nbsp; &nbsp; ("single" precision)
:::* &nbsp; 12.3D+44 &nbsp; &nbsp; &nbsp; ("double" precision)
:::* &nbsp; 12.3Q+44 &nbsp; &nbsp; &nbsp; ("extended" or "quad" precision)
<langsyntaxhighlight lang="rexx">/*REXX pgmprogram evaluates an infix-type infix─type arithmetic expression & showsand displays the result.*/
nchars = '0123456789.eEdDqQ' /*possible parts of a #number, sans ± */
e='***error!***'; $='" '"; doubleOps= '&|*/'; z= /*handy─dandy variables.*/
parse arg x 1 ox1; if x='' then call serr '"no input was specified.'"
x=space(x); L=length(x); x=translate(x, '()()', "[]{}")
j=0
 
j=0; do forever; j=j+1; if j>L then leave; _=substr(x, j, 1); _2=getX()
newT=pos(_,' ()[]{}^÷')\==0; if newT then do; z=z _ $; iterate; end
possDouble=pos(_,doubleOps)\==0 /*is _ a possible double operator?*/
if possDouble then do /*is " this a possible" " " " double oper?*/
if _2==_ then do /*yupyupper, it's one of 'em.a double operator*/
_=_ || _ /*create and use a double char operator*/
x=overlay($, x, Nj) /*blank out the2nd symbol.*/
end /* 2nd symbol.*/
z=z _ $; iterate
end
if _=='+' | _=="-" then do; p_=word(z, max(1,words(z))) /*last Z token. */
if p_=='(' then z=z 0 /*handle a unary ± */
z=z _ $; iterate
end
lets=0; sigs=0; #=_
 
do j=j+1 to L; _=substr(x,j,1) /*build a valid number.*/
if lets==1 & sigs==0 then if _=='+' | _=='"-'" then do; sigs=1
#=# || _
iterate
end /*exp*/
if pos(_,nchars)==0 then leave
lets=lets+datatype(_,'M') /*keep track of #the number of exponents. */
#=# || translate(_,'EEEEE',' "eDdQq'") /*keep buildingthebuilding numthe number. */
end /*j*/
j=j-1
if \datatype(#,'N') then call serr ' "invalid number: '" #
z=z # $
end /*forever*/
 
_=word(z,1); if _=='+' | _=='"-'" then z=0 z /*handle the unary cases. /*handle unary cases.*/
x='(' space(z) '") '"; tokens=words(x) /*force stacking for the expression. */
do i=1 for tokens; @.i=word(x,i); end /*i*/ /*assign input tokens. */
L=max(20,length(x)) /*use 20 for the minminimum showdisplay width. */
op= ')(-+/*^'; rOp Rop=substr(op,3); p.=; s.=; n=length(op); epr=; stack=
 
do i=1 for n; _=substr(op,i,1); s._=(i+1)%2; p._=s._ + (i==n); end /*i*/
/* [↑] assign the operator priorities.*/
do #=1 for tokens; ?=@.# /*process each token from the @. list.*/
if ?=='**' then ?="^" /*convert to REXX-type exponentationexponentiation. */
select /*@.# is: (, operator, ), operand*/
when ?=='(' then stack='"('" stack
when isOp(?) then do /*is the token an operator ? */
!=word(stack,1) /*get token from stack.*/
do while !\==')' & s.!>=p.?; epr=epr ! /*addaddition.*/
stack=subword(stack, 2); /*del token from stack.*/
!= word(stack, 1) /*get token from stack.*/
end /*while ···)*/
stack=? stack /*add token to stack.*/
end
when ?==')' then do; !=word(stack, 1) /*get token from stack.*/
do while !\=='('; epr=epr ! /*addappend to epr.expression*/
stack=subword(stack, 2) /*del token from stack.*/
!= word(stack, 1) /*get token from stack.*/
end /*while ···( */
stack=subword(stack, 2) /*del token from stack.*/
end
otherwise epr=epr ? /*add operand to epr. */
end /*select*/
end /*#*/
 
epr=space(epr stack); tokens=words(epr); x=epr; z=; stack=
do i=1 for tokens; @.i=word(epr,i); end /*i*/ /*assign input tokens.*/
dopDop='/ // % ÷'; bopBop='"& | &&'" /*division opsoperands; binary operands.*/
aopAop='- + * ^ **' dopDop bopBop; lopLop=aopAop '"||'" /*arithmetic opsoperands; legal operands.*/
 
do #=1 for tokens; ?=@.#; ??=? /*process each token from @. list. */
w=words(stack); b=word(stack, max(1, w)) ) ) /*stack count; the last entry. */
a=word(stack, max(1, w-1) ) /*stack's "first" operand. */
division =wordpos(?,dop Dop)\==0 /*flag: doing a division operation. */
arith =wordpos(?,aop Aop)\==0 /*flag: doing arithmetic operation. */
bitOp =wordpos(?,bop Bop)\==0 /*flag: doing binary mathmathematics. */
if datatype(?, 'N') then do; stack=stack ?; iterate; end
if wordpos(?,lopLop)==0 then do; z=e ' "illegal operator:'" ?; leave; end
if w<2 then do; z=e ' "illegal epr expression.'"; leave; end
if ?=='^' then ??="**" /*REXXify ^ ──► ** (make it legal).*/
if ?=='÷' then ??="/" /*REXXify ÷ ──► / (make it legal).*/
if division & b=0 then do; z=e ' "division by zero:" ' b; leave; end
if bitOp & \isBit(a) then do; z=e "token isn't logical: " a; leave; end
if bitOp & \isBit(b) then do; z=e "token isn't logical: " b; leave; end
select select /*perform arith.an arithmetic operation. */
when ??=='+' then y = a + b
when ??=='-' then y = a - b
when ??=='*' then y = a * b
when ??=='/' | ??=="÷" then y = a / b
when ??=='//' then y = a // b
when ??=='%' then y = a % b
when ??=='^' | ??=="**" then y = a ** b
when ??=='||' then y = a || b
otherwise otherwise z=e 'invalid operator:' ?; leave
end /*select*/
if datatype(y, 'W') then y=y/1 /*normalize the number with ÷ by 1. */
_=subword(stack, 1, w-2); stack=_ y /*rebuild the stack with the answer. */
end /*#*/
 
if word(z, 1)==e then stack= /*handle the special case of errors. */
z=space(z stack) /*append any residual entries. */
say 'answer──►' z /*display the answer (result). */
parse source upper . how . /*invoked via C.L. or REXX pgmprogram ? */
if how=='COMMAND' | \datatype(z, 'W') then exit /*stick a fork in it, we're all done. */
return z \datatype(z,'W') then exit /*stickreturn a forkZ in──► it,invoker we're done(the RESULT). */
/*──────────────────────────────────────────────────────────────────────────────────────*/
return z /*return Z ──► invoker (RESULT).*/
isBit: return arg(1)==0 | arg(1) == 1 /*returns 1 if 1st argument is binary*/
/*──────────────────────────────────subroutines─────────────────────────*/
isBitisOp: return pos(arg(1), rOp) \== 0 | arg(1)==1 /*returnsis argument 1 a if arg1"real" operator? is bin bit.*/
isOpserr: returnsay; say e pos(arg(1),rOp)\==0; say; exit 13 /*isissue an error argument1message awith "real"some operator?text*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
serr: say; say e arg(1); say; exit 13 /*issue an error message with txt*/
getX: do Nj=j+1 to length(x); _n=substr(x, Nj, 1); if _n==$ then iterate
/*──────────────────────────────────GETX subroutine─────────────────────*/
getX: do Nj=j+1 to length(x); _n= return substr(x, Nj, 1); if _n==$ then iterate /* [↑] ignore any blanks in expression*/
if _n==$ then iterate; return substr(x,Nj,1) end /*ignore blanksNj*/
return $ /*reached end-of-tokens, return $. */</syntaxhighlight>
end /*Nj*/
To view a version of the above REXX program, see this version which has much more whitespace: &nbsp; ──► &nbsp; [[Arithmetic_evaluation/REXX]]. <br>
return $ /*reached end-of-tokens, return $*/</lang>
<br>
'''output''' when using the input of: <tt> + 1+2.0-003e-00*[4/6] </tt>
 
<pre style="overflow:scroll">
'''output''' &nbsp; when using the input of: &nbsp; <tt> + 1+2.0-003e-00*[4/6] </tt>
<pre>
answer──► 1
</pre>
 
=={{header|RPL}}==
This expression evaluator generates the AST through an RPN converter based on the shunting-yard algorithm.
 
<code>LEXER</code> is defined at [[Parsing/Shunting-yard algorithm#RPL|Parsing/Shunting-yard algorithm]]
{{works with|HP|48}}
≪ '''IF''' OVER '''THEN'''
"^*/+-" DUP 5 PICK POS SWAP ROT POS
{ 4 3 3 2 2 } { 1 0 0 0 0 }
→ o2 o1 prec rasso
≪ '''IF''' o2 '''THEN'''
prec o1 GET prec o2 GET
'''IF''' rasso o1 GET '''THEN''' < '''ELSE''' ≤ '''END'''
'''ELSE''' 0 '''END'''
'''ELSE''' DROP 0 '''END'''
≫ ‘<span style="color:blue>POPOP?</span>’ STO
<span style="color:grey>@ ''( op → Boolean )''</span>
≪ { } "" → infix postfix token
≪ 0
1 infix SIZE '''FOR''' j
infix j GET 'token' STO
1 SF
'''CASE'''
"^*/+-" token →STR POS '''THEN'''
1 CF
'''WHILE''' token <span style="color:blue>POPOP?</span> '''REPEAT'''
'postfix' ROT STO+ 1 - '''END'''
token SWAP 1 + '''END'''
"(" token == '''THEN'''
token SWAP 1 + '''END'''
")" token == '''THEN'''
'''WHILE''' DUP 1 FS? AND '''REPEAT'''
'''IF''' OVER "(" ≠ '''THEN'''
'postfix' ROT STO+
'''ELSE''' SWAP DROP 1 CF '''END'''
1 -
'''END'''
'''END'''
1 FS? '''THEN''' 'postfix' token STO+ '''END'''
'''END'''
'''NEXT'''
'''WHILE''' DUP '''REPEAT'''
'postfix' ROT STO+ 1 - '''END'''
DROP
≫ ≫ ‘<span style="color:blue>→RPN</span>’ STO
<span style="color:grey>@ ''( { infixed tokens } → { postfixed tokens )''</span>
≪ DUP SIZE → len
≪ '''IF''' len '''THEN'''
DUP len GET SWAP
'''IF''' len 1 ≠ '''THEN''' 1 len 1 - SUB '''ELSE''' DROP { } '''END'''
'''IF''' OVER TYPE '''THEN'''
<span style="color:blue>→AST</span> <span style="color:blue>→AST</span>
4 ROLLD ROT ROT 3 →LIST SWAP
'''END'''
'''ELSE''' "Err" SWAP '''END'''
≫ ≫ ‘<span style="color:blue>→AST</span>’ STO
<span style="color:grey>@ ''( { postfixed tokens } → { AST } )''</span>
≪ DUP 1 GET
'''IF''' DUP TYPE '''THEN''' <span style="color:blue>AST→N</span> '''END'''
OVER 3 GET
'''IF''' DUP TYPE '''THEN''' <span style="color:blue>AST→N</span> '''END'''
ROT 2 GET "≪" SWAP + "≫" + STR→ EVAL
≫ ‘<span style="color:blue>AST→N</span>' STO
<span style="color:grey>@ ''( { AST } → value )''</span>
≪ <span style="color:blue>LEXER</span> <span style="color:blue>→RPN</span>
<span style="color:blue>→AST</span> DROP DUP <span style="color:grey>@ DUP is just here to leave the AST in the stack</span>
<span style="color:blue>AST→N</span>
≫ ‘<span style="color:blue>AEVAL</span>’ STO
 
"3 + 4 * 2 / ( 1 - 5 ) ^ 2 ^ 3" <span style="color:blue>AEVAL</span>
{{out}}
<pre>
2: { 3 "+" { { 4 "*" 2 } "/" { { 1 "-" 5 } "^" { 2 "^" 3 } } } }
1: 3.00012207031
</pre>
 
=={{header|Ruby}}==
Function to convert infix arithmetic expression to binary tree. The resulting tree knows how to print and evaluate itself. Assumes expression is well-formed (matched parens, all operators have 2 operands). Algorithm: http://www.seas.gwu.edu/~csci131/fall96/exp_to_tree.html
<langsyntaxhighlight lang="ruby">$op_priority = {"+" => 0, "-" => 0, "*" => 1, "/" => 1}
$op_function = {
"+" => lambda {|x, y| x + y},
"-" => lambda {|x, y| x - y},
"*" => lambda {|x, y| x * y},
"/" => lambda {|x, y| x / y}}
 
class TreeNode
OP_FUNCTION = {
"+" => lambda {|x, y| x + y},
"-" => lambda {|x, y| x - y},
"*" => lambda {|x, y| x * y},
"/" => lambda {|x, y| x / y}}
attr_accessor :info, :left, :right
 
def initialize(info)
@info = info
end
 
def leaf?
@left.nil? and @right.nil?
end
 
def to_s(order)
if leaf?
Line 3,482 ⟶ 6,452:
else
left_s, right_s = @left.to_s(order), @right.to_s(order)
 
strs = case order
when :prefix then [@info, left_s, right_s]
when :infix then [left_s, @info, right_s]
when :postfix then [left_s, right_s, @info]
else []
end
Line 3,493 ⟶ 6,463:
end
end
 
def eval
if !leaf? and operator?(@info)
$op_functionOP_FUNCTION[@info].call(@left.eval, @right.eval)
else
@info.to_f
Line 3,507 ⟶ 6,477:
.gsub('(', ' ( ')
.gsub(')', ' ) ')
.gsub('+', ' + ')
.gsub('-', ' - ')
.gsub('*', ' * ')
.gsub('/', ' / ')
.split(' ')
end
Line 3,524 ⟶ 6,498:
tokens = tokenize(exp)
op_stack, node_stack = [], []
 
tokens.each do |token|
if operator?(token)
Line 3,533 ⟶ 6,507:
pop_connect_push(op_stack, node_stack)
end
 
op_stack.push(TreeNode.new(token))
elsif token == "("
Line 3,541 ⟶ 6,515:
pop_connect_push(op_stack, node_stack)
end
 
# throw away the '('
op_stack.pop
Line 3,548 ⟶ 6,522:
end
end
 
until op_stack.empty?
pop_connect_push(op_stack, node_stack)
end
 
node_stack.last
end</langsyntaxhighlight>
Testing:
<langsyntaxhighlight lang="ruby">exp = "1 + 2 - 3 * (4 / 6)"
puts("Original: " + exp)
 
Line 3,563 ⟶ 6,537:
puts("Infix: " + tree.to_s(:infix))
puts("Postfix: " + tree.to_s(:postfix))
puts("Result: " + tree.eval.to_s)</langsyntaxhighlight>
{{out}}
Output:
<pre>Original: 1 + 2 - 3 * (4 / 6)
Prefix: (- (+ 1 2) (* 3 (/ 4 6)))
Line 3,570 ⟶ 6,544:
Postfix: ((1 2 +) (3 (4 6 /) *) -)
Result: 1.0</pre>
 
=={{header|Rust}}==
<syntaxhighlight lang="rust">//! Simple calculator parser and evaluator
 
 
/// Binary operator
#[derive(Debug)]
pub enum Operator {
Add,
Substract,
Multiply,
Divide
}
 
/// A node in the tree
#[derive(Debug)]
pub enum Node {
Value(f64),
SubNode(Box<Node>),
Binary(Operator, Box<Node>,Box<Node>),
}
 
/// parse a string into a node
pub fn parse(txt :&str) -> Option<Node> {
let chars = txt.chars().filter(|c| *c != ' ').collect();
parse_expression(&chars, 0).map(|(_,n)| n)
}
 
/// parse an expression into a node, keeping track of the position in the character vector
fn parse_expression(chars: &Vec<char>, pos: usize) -> Option<(usize,Node)> {
match parse_start(chars, pos) {
Some((new_pos, first)) => {
match parse_operator(chars, new_pos) {
Some((new_pos2,op)) => {
if let Some((new_pos3, second)) = parse_expression(chars, new_pos2) {
Some((new_pos3, combine(op, first, second)))
} else {
None
}
},
None => Some((new_pos,first)),
}
},
None => None,
}
}
 
/// combine nodes to respect associativity rules
fn combine(op: Operator, first: Node, second: Node) -> Node {
match second {
Node::Binary(op2,v21,v22) => if precedence(&op)>=precedence(&op2) {
Node::Binary(op2,Box::new(combine(op,first,*v21)),v22)
} else {
Node::Binary(op,Box::new(first),Box::new(Node::Binary(op2,v21,v22)))
},
_ => Node::Binary(op,Box::new(first),Box::new(second)),
}
}
 
/// a precedence rank for operators
fn precedence(op: &Operator) -> usize {
match op{
Operator::Multiply | Operator::Divide => 2,
_ => 1
}
}
 
/// try to parse from the start of an expression (either a parenthesis or a value)
fn parse_start(chars: &Vec<char>, pos: usize) -> Option<(usize,Node)> {
match start_parenthesis(chars, pos){
Some (new_pos) => {
let r = parse_expression(chars, new_pos);
end_parenthesis(chars, r)
},
None => parse_value(chars, pos),
}
}
 
/// match a starting parentheseis
fn start_parenthesis(chars: &Vec<char>, pos: usize) -> Option<usize>{
if pos<chars.len() && chars[pos] == '(' {
Some(pos+1)
} else {
None
}
}
 
/// match an end parenthesis, if successful will create a sub node contained the wrapped expression
fn end_parenthesis(chars: &Vec<char>, wrapped :Option<(usize,Node)>) -> Option<(usize,Node)>{
match wrapped {
Some((pos, node)) => if pos<chars.len() && chars[pos] == ')' {
Some((pos+1,Node::SubNode(Box::new(node))))
} else {
None
},
None => None,
}
}
 
/// parse a value: an decimal with an optional minus sign
fn parse_value(chars: &Vec<char>, pos: usize) -> Option<(usize,Node)>{
let mut new_pos = pos;
if new_pos<chars.len() && chars[new_pos] == '-' {
new_pos = new_pos+1;
}
while new_pos<chars.len() && (chars[new_pos]=='.' || (chars[new_pos] >= '0' && chars[new_pos] <= '9')) {
new_pos = new_pos+1;
}
if new_pos>pos {
if let Ok(v) = dbg!(chars[pos..new_pos].iter().collect::<String>()).parse() {
Some((new_pos,Node::Value(v)))
} else {
None
}
} else {
None
}
 
}
 
/// parse an operator
fn parse_operator(chars: &Vec<char>, pos: usize) -> Option<(usize,Operator)> {
if pos<chars.len() {
let ops_with_char = vec!(('+',Operator::Add),('-',Operator::Substract),('*',Operator::Multiply),('/',Operator::Divide));
for (ch,op) in ops_with_char {
if chars[pos] == ch {
return Some((pos+1, op));
}
}
}
None
}
 
/// eval a string
pub fn eval(txt :&str) -> f64 {
match parse(txt) {
Some(t) => eval_term(&t),
None => panic!("Cannot parse {}",txt),
}
}
 
/// eval a term, recursively
fn eval_term(t: &Node) -> f64 {
match t {
Node::Value(v) => *v,
Node::SubNode(t) => eval_term(t),
Node::Binary(Operator::Add,t1,t2) => eval_term(t1) + eval_term(t2),
Node::Binary(Operator::Substract,t1,t2) => eval_term(t1) - eval_term(t2),
Node::Binary(Operator::Multiply,t1,t2) => eval_term(t1) * eval_term(t2),
Node::Binary(Operator::Divide,t1,t2) => eval_term(t1) / eval_term(t2),
}
}
 
#[cfg(test)]
mod tests {
use super::*;
 
#[test]
fn test_eval(){
assert_eq!(2.0,eval("2"));
assert_eq!(4.0,eval("2+2"));
assert_eq!(11.0/4.0, eval("2+3/4"));
assert_eq!(2.0, eval("2*3-4"));
assert_eq!(3.0, eval("1+2*3-4"));
assert_eq!(89.0/6.0, eval("2*(3+4)+5/6"));
assert_eq!(14.0, eval("2 * (3 -1) + 2 * 5"));
assert_eq!(7000.0, eval("2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10"));
assert_eq!(-9.0/4.0, eval("2*-3--4+-.25"));
assert_eq!(1.5, eval("1 - 5 * 2 / 20 + 1"));
assert_eq!(3.5, eval("2 * (3 + ((5) / (7 - 11)))"));
}
}
 
</syntaxhighlight>
 
=={{header|Scala}}==
Line 3,575 ⟶ 6,725:
is practically non-existent, to avoid obscuring the code.
 
<langsyntaxhighlight lang="scala">
package org.rosetta.arithmetic_evaluator.scala
 
Line 3,622 ⟶ 6,772:
}
}
</syntaxhighlight>
</lang>
 
Example:
Line 3,644 ⟶ 6,794:
 
This example was made rather more complex by the requirement of generating an AST tree. With a Scala distribution there are many examples of arithmetic parsers, as small as half a dozen lines.
 
=={{header|Scheme}}==
 
This works in three stages: string->tokens turns the input string into a list of tokens, parse converts this into an AST, which is eventually evaluated into a number result. Only positive integers are read, though output can be a rational, positive or negative.
 
The parse function uses a recursive-descent parser to follow the precedence rules.
 
<syntaxhighlight lang="scheme">
(import (scheme base)
(scheme char)
(scheme cxr)
(scheme write)
(srfi 1 lists))
 
;; convert a string into a list of tokens
(define (string->tokens str)
(define (next-token chars)
(cond ((member (car chars) (list #\+ #\- #\* #\/) char=?)
(values (cdr chars)
(cdr (assq (car chars) ; convert char for op into op procedure, using a look up list
(list (cons #\+ +) (cons #\- -) (cons #\* *) (cons #\/ /))))))
((member (car chars) (list #\( #\)) char=?)
(values (cdr chars)
(if (char=? (car chars) #\()
'open
'close)))
(else ; read a multi-digit positive integer
(let loop ((rem chars)
(res 0))
(if (and (not (null? rem))
(char-numeric? (car rem)))
(loop (cdr rem)
(+ (* res 10)
(- (char->integer (car rem))
(char->integer #\0))))
(values rem
res))))))
;
(let loop ((chars (remove char-whitespace? (string->list str)))
(tokens '()))
(if (null? chars)
(reverse tokens)
(let-values (((remaining-chars token) (next-token chars)))
(loop remaining-chars
(cons token tokens))))))
 
;; turn list of tokens into an AST
;; -- using recursive descent parsing to obey laws of precedence
(define (parse tokens)
(define (parse-factor tokens)
(if (number? (car tokens))
(values (car tokens) (cdr tokens))
(let-values (((expr rem) (parse-expr (cdr tokens))))
(values expr (cdr rem)))))
(define (parse-term tokens)
(let-values (((left-expr rem) (parse-factor tokens)))
(if (and (not (null? rem))
(member (car rem) (list * /)))
(let-values (((right-expr remr) (parse-term (cdr rem))))
(values (list (car rem) left-expr right-expr)
remr))
(values left-expr rem))))
(define (parse-part tokens)
(let-values (((left-expr rem) (parse-term tokens)))
(if (and (not (null? rem))
(member (car rem) (list + -)))
(let-values (((right-expr remr) (parse-part (cdr rem))))
(values (list (car rem) left-expr right-expr)
remr))
(values left-expr rem))))
(define (parse-expr tokens)
(let-values (((expr rem) (parse-part tokens)))
(values expr rem)))
;
(let-values (((expr rem) (parse-expr tokens)))
(if (null? rem)
expr
(error "Misformed expression"))))
 
;; evaluate the AST, returning a number
(define (eval-expression ast)
(cond ((number? ast)
ast)
((member (car ast) (list + - * /))
((car ast)
(eval-expression (cadr ast))
(eval-expression (caddr ast))))
(else
(error "Misformed expression"))))
 
;; parse and evaluate the given string
(define (interpret str)
(eval-expression (parse (string->tokens str))))
 
;; running some examples
(for-each
(lambda (str)
(display
(string-append str
" => "
(number->string (interpret str))))
(newline))
'("1 + 2" "20+4*5" "1/2+5*(6-3)" "(1+3)/4-1" "(1 - 5) * 2 / (20 + 1)"))
</syntaxhighlight>
 
{{out}}
 
<pre>
1 + 2 => 3
20+4*5 => 40
1/2+5*(6-3) => 31/2
(1+3)/4-1 => 0
(1 - 5) * 2 / (20 + 1) => -8/21
</pre>
 
=={{header|Sidef}}==
{{trans|JavaScript}}
<syntaxhighlight lang="ruby">func evalArithmeticExp(s) {
 
func evalExp(s) {
 
func operate(s, op) {
s.split(op).map{|c| Number(c) }.reduce(op)
}
 
func add(s) {
operate(s.sub(/^\+/,'').sub(/\++/,'+'), '+')
}
 
func subtract(s) {
s.gsub!(/(\+-|-\+)/,'-')
 
if (s ~~ /--/) {
return(add(s.sub(/--/,'+')))
}
 
var b = s.split('-')
b.len == 3 ? (-1*Number(b[1]) - Number(b[2]))
: operate(s, '-')
}
 
s.gsub!(/[()]/,'').gsub!(/-\+/, '-')
 
var reM = /\*/
var reMD = %r"(\d+\.?\d*\s*[*/]\s*[+-]?\d+\.?\d*)"
 
var reA = /\d\+/
var reAS = /(-?\d+\.?\d*\s*[+-]\s*[+-]?\d+\.?\d*)/
 
while (var match = reMD.match(s)) {
match[0] ~~ reM
? s.sub!(reMD, operate(match[0], '*').to_s)
: s.sub!(reMD, operate(match[0], '/').to_s)
}
 
while (var match = reAS.match(s)) {
match[0] ~~ reA
? s.sub!(reAS, add(match[0]).to_s)
: s.sub!(reAS, subtract(match[0]).to_s)
}
 
return s
}
 
var rePara = /(\([^\(\)]*\))/
s.split!.join!('').sub!(/^\+/,'')
 
while (var match = s.match(rePara)) {
s.sub!(rePara, evalExp(match[0]))
}
 
return Number(evalExp(s))
}</syntaxhighlight>
 
Testing the function:
<syntaxhighlight lang="ruby">for expr,res in [
['2+3' => 5],
['-4-3' => -7],
['-+2+3/4' => -1.25],
['2*3-4' => 2],
['2*(3+4)+2/4' => 2/4 + 14],
['2*-3--4+-0.25' => -2.25],
['2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10' => 7000],
] { 
var num = evalArithmeticExp(expr)
assert_eq(num, res)
"%-45s == %10g\n".printf(expr, num)
}</syntaxhighlight>
 
=={{header|Standard ML}}==
This implementation uses a [https://en.wikipedia.org/wiki/Recursive_descent_parser recursive descent parser]. It first lexes the input. The parser builds a Abstract Syntax Tree (AST) and the evaluator evaluates it. The parser uses sub categories.
The parsing is a little bit tricky because the grammar is left recursive.
<syntaxhighlight lang="sml">(* AST *)
datatype expression =
Con of int (* constant *)
| Add of expression * expression (* addition *)
| Mul of expression * expression (* multiplication *)
| Sub of expression * expression (* subtraction *)
| Div of expression * expression (* division *)
 
(* Evaluator *)
fun eval (Con x) = x
| eval (Add (x, y)) = (eval x) + (eval y)
| eval (Mul (x, y)) = (eval x) * (eval y)
| eval (Sub (x, y)) = (eval x) - (eval y)
| eval (Div (x, y)) = (eval x) div (eval y)
 
(* Lexer *)
datatype token =
CON of int
| ADD
| MUL
| SUB
| DIV
| LPAR
| RPAR
 
fun lex nil = nil
| lex (#"+" :: cs) = ADD :: lex cs
| lex (#"*" :: cs) = MUL :: lex cs
| lex (#"-" :: cs) = SUB :: lex cs
| lex (#"/" :: cs) = DIV :: lex cs
| lex (#"(" :: cs) = LPAR :: lex cs
| lex (#")" :: cs) = RPAR :: lex cs
| lex (#"~" :: cs) = if null cs orelse not (Char.isDigit (hd cs)) then raise Domain
else lexDigit (0, cs, ~1)
| lex (c :: cs) = if Char.isDigit c then lexDigit (0, c :: cs, 1)
else raise Domain
 
and lexDigit (a, cs, s) = if null cs orelse not (Char.isDigit (hd cs)) then CON (a*s) :: lex cs
else lexDigit (a * 10 + (ord (hd cs))- (ord #"0") , tl cs, s)
 
(* Parser *)
exception Error of string
 
fun match (a,ts) t = if null ts orelse hd ts <> t
then raise Error "match"
else (a, tl ts)
 
fun extend (a,ts) p f = let val (a',tr) = p ts in (f(a,a'), tr) end
 
fun parseE ts = parseE' (parseM ts)
and parseE' (e, ADD :: ts) = parseE' (extend (e, ts) parseM Add)
| parseE' (e, SUB :: ts) = parseE' (extend (e, ts) parseM Sub)
| parseE' s = s
 
and parseM ts = parseM' (parseP ts)
and parseM' (e, MUL :: ts) = parseM' (extend (e, ts) parseP Mul)
| parseM' (e, DIV :: ts) = parseM' (extend (e, ts) parseP Div)
| parseM' s = s
 
and parseP (CON c :: ts) = (Con c, ts)
| parseP (LPAR :: ts) = match (parseE ts) RPAR
| parseP _ = raise Error "parseP"
 
 
(* Test *)
fun lex_parse_eval (str:string) =
case parseE (lex (explode str)) of
(exp, nil) => eval exp
| _ => raise Error "not parseable stuff at the end"</syntaxhighlight>
 
=={{header|Tailspin}}==
<syntaxhighlight lang="tailspin">
def ops: ['+','-','*','/'];
 
data binaryExpression <{left: <node>, op: <?($ops <[<=$::raw>]>)>, right: <node>}>
data node <binaryExpression|"1">
 
composer parseArithmetic
(<WS>?) <addition|multiplication|term> (<WS>?)
rule addition: {left:<addition|multiplication|term> (<WS>?) op:<'[+-]'> (<WS>?) right:<multiplication|term>}
rule multiplication: {left:<multiplication|term> (<WS>?) op:<'[*/]'> (<WS>?) right:<term>}
rule term: <INT"1"|parentheses>
rule parentheses: (<'\('> <WS>?) <addition|multiplication|term> (<WS>? <'\)'>)
end parseArithmetic
 
templates evaluateArithmetic
<´node´ {op: <='+'>}> ($.left -> evaluateArithmetic) + ($.right -> evaluateArithmetic) !
<´node´ {op: <='-'>}> ($.left -> evaluateArithmetic) - ($.right -> evaluateArithmetic) !
<´node´ {op: <='*'>}> ($.left -> evaluateArithmetic) * ($.right -> evaluateArithmetic) !
<´node´ {op: <='/'>}> ($.left -> evaluateArithmetic) ~/ ($.right -> evaluateArithmetic) !
otherwise $ !
end evaluateArithmetic
 
def ast: '(100 - 5 * (2+3*4) + 2) / 2' -> parseArithmetic;
'$ast;
' -> !OUT::write
'$ast -> evaluateArithmetic;
' -> !OUT::write
</syntaxhighlight>
{{out}}
<pre>
{left={left={left=100"1", op=-, right={left=5"1", op=*, right={left=2"1", op=+, right={left=3"1", op=*, right=4"1"}}}}, op=+, right=2"1"}, op=/, right=2"1"}
16"1"
</pre>
 
If we don't need to get the AST, we could just evaluate right away:
<syntaxhighlight lang="tailspin">
composer calculator
(<WS>?) <addition|multiplication|term> (<WS>?)
rule addition: [<addition|multiplication|term> (<WS>?) <'[+-]'> (<WS>?) <multiplication|term>] ->
\(when <?($(2) <='+'>)> do $(1) + $(3) !
otherwise $(1) - $(3) !
\)
rule multiplication: [<multiplication|term> (<WS>?) <'[*/]'> (<WS>?) <term>] ->
\(when <?($(2) <='*'>)> do $(1) * $(3) !
otherwise $(1) ~/ $(3) !
\)
rule term: <INT|parentheses>
rule parentheses: (<'\('> <WS>?) <addition|multiplication|term> (<WS>? <'\)'>)
end calculator
 
'(100 - 5 * (2+3*4) + 2) / 2' -> calculator -> !OUT::write
'
' -> !OUT::write
</syntaxhighlight>
{{out}}
<pre>16</pre>
 
=={{header|Tcl}}==
{{works with|Tcl|8.5}}
The code below delivers the AST for an expression in a form that it can be immediately eval-led, using Tcl's prefix operators.
in a form that it can be immediately eval-led,
<lang Tcl>namespace import tcl::mathop::*
using Tcl's prefix operators.
<syntaxhighlight lang="tcl">namespace import tcl::mathop::*
 
proc ast str {
Line 3,691 ⟶ 7,162:
} \n] {
puts "$test ..... [eval $test] ..... [eval [eval $test]]"
}</langsyntaxhighlight>
{{out}}
Output:<pre>
<pre>
ast 2-2 ..... - 2 2 ..... 0
ast 1-2-3 ..... - [- 1 2] 3 ..... -4
Line 3,706 ⟶ 7,178:
Use TXR text pattern matching to parse expression to a Lisp AST, then evaluate with <code>eval</code>:
 
<langsyntaxhighlight lang="txr">@(next :args)
@(define space)@/ */@(end)
@(define mulop (nod))@\
Line 3,758 ⟶ 7,230:
erroneous suffix "@bad"
@ (end)
@(end)</langsyntaxhighlight>
 
Run:
Line 3,768 ⟶ 7,240:
 
 
{{omit from|gnuplot}}
 
=={{header|Ursala}}==
with no error checking other than removal of spaces
<langsyntaxhighlight Ursalalang="ursala">#import std
#import nat
#import flo
Line 3,789 ⟶ 7,260:
traverse = *^ ~&v?\%ep ^H\~&vhthPX '+-*/'-$<plus,minus,times,div>@dh
 
evaluate = traverse+ parse+ lex</langsyntaxhighlight>
 
test program:
<langsyntaxhighlight Ursalalang="ursala">#cast %eL
 
test = evaluate*t
Line 3,808 ⟶ 7,279:
5-3*2
(1+1)*(2+3)
(2-4)/(3+5*(8-1))]-</langsyntaxhighlight>
{{out}}
output:
<pre>
<
Line 3,824 ⟶ 7,295:
1.000000e+01,
-5.263158e-02></pre>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-pattern}}
<syntaxhighlight lang="wren">import "./pattern" for Pattern
 
/* if string is empty, returns zero */
var toDoubleOrZero = Fn.new { |s|
var n = Num.fromString(s)
return n ? n : 0
}
 
var multiply = Fn.new { |s|
var b = s.split("*").map { |t| toDoubleOrZero.call(t) }.toList
return (b[0] * b[1]).toString
}
 
var divide = Fn.new { |s|
var b = s.split("/").map { |t| toDoubleOrZero.call(t) }.toList
return (b[0] / b[1]).toString
}
 
var add = Fn.new { |s|
var p1 = Pattern.new("/+", Pattern.start)
var p2 = Pattern.new("+1/+")
var t = p1.replaceAll(s, "")
t = p2.replaceAll(t, "+")
var b = t.split("+").map { |u| toDoubleOrZero.call(u) }.toList
return (b[0] + b[1]).toString
}
 
var subtract = Fn.new { |s|
var p = Pattern.new("[/+-|-/+]")
var t = p.replaceAll(s, "-")
if (t.contains("--")) return add.call(t.replace("--", "+"))
var b = t.split("-").map { |u| toDoubleOrZero.call(u) }.toList
return ((b.count == 3) ? -b[1] - b[2] : b[0] - b[1]).toString
}
 
var evalExp = Fn.new { |s|
var p = Pattern.new("[(|)|/s]")
var t = p.replaceAll(s, "")
var i = "*/"
var pMD = Pattern.new("+1/f/i~/n+1/f", Pattern.within, i)
var pM = Pattern.new("*")
var pAS = Pattern.new("~-+1/f+1/n+1/f")
var pA = Pattern.new("/d/+")
 
while (true) {
var match = pMD.find(t)
if (!match) break
var exp = match.text
var match2 = pM.find(exp)
t = match2 ? t.replace(exp, multiply.call(exp)) : t.replace(exp, divide.call(exp))
}
 
while (true) {
var match = pAS.find(t)
if (!match) break
var exp = match.text
var match2 = pA.find(exp)
t = match2 ? t.replace(exp, add.call(exp)) : t.replace(exp, subtract.call(exp))
}
return t
}
 
var evalArithmeticExp = Fn.new { |s|
var p1 = Pattern.new("/s")
var p2 = Pattern.new("/+", Pattern.start)
var t = p1.replaceAll(s, "")
t = p2.replaceAll(t, "")
var i = "()"
var pPara = Pattern.new("(+0/I)", Pattern.within, i)
while (true) {
var match = pPara.find(t)
if (!match) break
var exp = match.text
t = t.replace(exp, evalExp.call(exp))
}
return toDoubleOrZero.call(evalExp.call(t))
}
 
[
"2+3",
"2+3/4",
"2*3-4",
"2*(3+4)+5/6",
"2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10",
"2*-3--4+-0.25",
"-4 - 3",
"((((2))))+ 3 * 5",
"1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10",
"1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1"
].each { |s| System.print("%(s) = %(evalArithmeticExp.call(s))") }</syntaxhighlight>
 
{{out}}
<pre>
2+3 = 5
2+3/4 = 2.75
2*3-4 = 2
2*(3+4)+5/6 = 14.833333333333
2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10 = 7000
2*-3--4+-0.25 = -2.25
-4 - 3 = -7
((((2))))+ 3 * 5 = 17
1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10 = 71
1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1 = 60
</pre>
 
=={{header|XPL0}}==
<syntaxhighlight lang "XPL0">def \Node\ Left, Data, Right;
def IntSize = 4;
int Stack(16);
int SP; \stack pointer
 
proc Push(N);
int N;
[Stack(SP):= N; SP:= SP+1];
 
func Pop;
[SP:= SP-1; return Stack(SP)];
 
func Precedence(Op);
int Op;
case Op of
^+, ^-: return 2;
^*, ^/: return 3;
^^: return 4
other [];
 
proc PostOrder(Node); \Traverse tree at Node in postorder, and
int Node, Top; \ return its evaluation on the stack
[if Node # 0 then
[PostOrder(Node(Left));
PostOrder(Node(Right));
case Node(Data) of
^+: [Top:= Pop; Push(Pop+Top)];
^-: [Top:= Pop; Push(Pop-Top)];
^*: [Top:= Pop; Push(Pop*Top)];
^/: [Top:= Pop; Push(Pop/Top)]
other Push(Node(Data) - ^0); \convert ASCII to binary
];
];
 
char Str;
int Token, Op1, Op2, Node;
[Str:= "3 + 4 * 2 / ( 1 - 5 ) "; \RPN: 342*15-/+
Text(0, Str);
\Convert infix expression to RPN (postfix) using shunting-yard algorithm
SP:= 0;
OpenO(8); \discard (overwrite) arguments in RPi's command line
loop [repeat Token:= Str(0); Str:= Str+1;
until Token # ^ ; \strip out space characters
case Token of
^+, ^-, ^*, ^/, ^^:
[Op1:= Token;
loop [if SP <= 0 then quit; \stack is empty
Op2:= Stack(SP-1);
if Op2 = ^( then quit;
if Precedence(Op2) < Precedence(Op1) then quit;
if Precedence(Op2) = Precedence(Op1) then
if Op1 = ^^ then quit;
ChOut(8, Pop);
];
Push(Op1);
];
^(: Push(Token);
^): [while SP > 0 and Stack(SP-1) # ^( do
ChOut(8, Pop);
Pop; \discard left parenthesis
];
$A0: quit \terminating space with its MSB set
other ChOut(8, Token); \output the single-digit number
];
while SP > 0 do ChOut(8, Pop); \output any remaining operators
\Build AST from RPN expression
OpenI(8); \(for safety)
loop [Token:= ChIn(8);
if Token = $1A\EOF\ then quit
else if Token >= ^0 and Token <= ^9 then
[Node:= Reserve(3*IntSize);
Node(Data):= Token;
Node(Left):= 0;
Node(Right):= 0;
Push(Node);
]
else \must be an operator
[Node:= Reserve(3*IntSize);
Node(Data):= Token;
Node(Right):= Pop;
Node(Left):= Pop;
Push(Node);
];
];
\Evaluate expression in AST
PostOrder(Pop);
Text(0, "= ");
IntOut(0, Pop);
]</syntaxhighlight>
{{out}}
<pre>
t.txt"a</pre>
 
=={{header|zkl}}==
In zkl, the compiler stack is part of the language and is written in zkl so ...
<syntaxhighlight lang="zkl">Compiler.Parser.parseText("(1+3)*7").dump();
Compiler.Parser.parseText("1+3*7").dump();</syntaxhighlight>
The ASTs look like
{{out}}
<pre>
class RootClass# Input source: "<text>"
Attributes: static createReturnsSelf
...
{ Block(Class) <Line 1>
Exp(
(,1,+,3,),*,7
)
}
 
class RootClass# Input source: "<text>"
...
{ Block(Class) <Line 1>
Exp(
1,+,3,*,7
)
}
</pre>
Evaluating them is just moving up the stack:
<syntaxhighlight lang="zkl">Compiler.Compiler.compileText("(1+3)*7").__constructor(); vm.regX;
Compiler.Compiler.compileText("1+3*7").__constructor(); vm.regX;</syntaxhighlight>
{{out}}
<pre>
28
22
</pre>
 
=={{header|ZX Spectrum Basic}}==
<syntaxhighlight lang="zxbasic">10 PRINT "Use integer numbers and signs"'"+ - * / ( )"''
20 LET s$="": REM last symbol
30 LET pc=0: REM parenthesis counter
40 LET i$="1+2*(3+(4*5+6*7*8)-9)/10"
50 PRINT "Input = ";i$
60 FOR n=1 TO LEN i$
70 LET c$=i$(n)
80 IF c$>="0" AND c$<="9" THEN GO SUB 170: GO TO 130
90 IF c$="+" OR c$="-" THEN GO SUB 200: GO TO 130
100 IF c$="*" OR c$="/" THEN GO SUB 200: GO TO 130
110 IF c$="(" OR c$=")" THEN GO SUB 230: GO TO 130
120 GO TO 300
130 NEXT n
140 IF pc>0 THEN PRINT FLASH 1;"Parentheses not paired.": BEEP 1,-25: STOP
150 PRINT "Result = ";VAL i$
160 STOP
170 IF s$=")" THEN GO TO 300
180 LET s$=c$
190 RETURN
200 IF (NOT (s$>="0" AND s$<="9")) AND s$<>")" THEN GO TO 300
210 LET s$=c$
220 RETURN
230 IF c$="(" AND ((s$>="0" AND s$<="9") OR s$=")") THEN GO TO 300
240 IF c$=")" AND ((NOT (s$>="0" AND s$<="9")) OR s$="(") THEN GO TO 300
250 LET s$=c$
260 IF c$="(" THEN LET pc=pc+1: RETURN
270 LET pc=pc-1
280 IF pc<0 THEN GO TO 300
290 RETURN
300 PRINT FLASH 1;"Invalid symbol ";c$;" detected in pos ";n: BEEP 1,-25
310 STOP
</syntaxhighlight>
{{omit from|gnuplot}}
416

edits