Arithmetic evaluation: Difference between revisions
Content added Content deleted
m (→{{header|J}}) |
Thundergnat (talk | contribs) m (syntax highlighting fixup automation) |
||
Line 25: | Line 25: | ||
=={{header|11l}}== |
=={{header|11l}}== |
||
[[wp:Pratt parser|Pratt parser]] |
[[wp:Pratt parser|Pratt parser]] |
||
< |
<syntaxhighlight lang=11l>T Symbol |
||
String id |
String id |
||
Int lbp |
Int lbp |
||
Line 140: | Line 140: | ||
L(expr_str) [‘-2 / 2 + 4 + 3 * 2’, |
L(expr_str) [‘-2 / 2 + 4 + 3 * 2’, |
||
‘2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10’] |
‘2 * (3 + (4 * 5 + (6 * 7) * 8) - 9) * 10’] |
||
print(expr_str‘ = ’parse(expr_str).eval())</ |
print(expr_str‘ = ’parse(expr_str).eval())</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 154: | Line 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]}} |
{{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}} |
{{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}} |
||
< |
<syntaxhighlight lang=algol68>INT base=10; |
||
MODE FIXED = LONG REAL; # numbers in the format 9,999.999 # |
MODE FIXED = LONG REAL; # numbers in the format 9,999.999 # |
||
Line 295: | Line 295: | ||
index error: |
index error: |
||
printf(("Stack over flow")) |
printf(("Stack over flow")) |
||
)</ |
)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 303: | Line 303: | ||
=={{header|AutoHotkey}}== |
=={{header|AutoHotkey}}== |
||
{{works with|AutoHotkey_L}} |
{{works with|AutoHotkey_L}} |
||
< |
<syntaxhighlight lang=AutoHotkey>/* |
||
hand coded recursive descent parser |
hand coded recursive descent parser |
||
expr : term ( ( PLUS | MINUS ) term )* ; |
expr : term ( ( PLUS | MINUS ) term )* ; |
||
Line 452: | Line 452: | ||
} |
} |
||
#include calclex.ahk</ |
#include calclex.ahk</syntaxhighlight> |
||
calclex.ahk< |
calclex.ahk<syntaxhighlight lang=AutoHotkey>tokenize(string, lexer) |
||
{ |
{ |
||
stringo := string ; store original string |
stringo := string ; store original string |
||
Line 519: | Line 519: | ||
string := "pos= " token.pos "`nvalue= " token.value "`ntype= " token.type |
string := "pos= " token.pos "`nvalue= " token.value "`ntype= " token.type |
||
return string |
return string |
||
}</ |
}</syntaxhighlight> |
||
=={{header|BBC BASIC}}== |
=={{header|BBC BASIC}}== |
||
{{works with|BBC BASIC for Windows}} |
{{works with|BBC BASIC for Windows}} |
||
< |
<syntaxhighlight lang=bbcbasic> Expr$ = "1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10" |
||
PRINT "Input = " Expr$ |
PRINT "Input = " Expr$ |
||
AST$ = FNast(Expr$) |
AST$ = FNast(Expr$) |
||
Line 580: | Line 580: | ||
ENDIF |
ENDIF |
||
UNTIL FALSE |
UNTIL FALSE |
||
= num$</ |
= num$</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 595: | Line 595: | ||
{{libheader|Boost.Spirit|1.8.4}} |
{{libheader|Boost.Spirit|1.8.4}} |
||
< |
<syntaxhighlight lang=cpp> #include <boost/spirit.hpp> |
||
#include <boost/spirit/tree/ast.hpp> |
#include <boost/spirit/tree/ast.hpp> |
||
#include <string> |
#include <string> |
||
Line 710: | Line 710: | ||
} |
} |
||
} |
} |
||
};</ |
};</syntaxhighlight> |
||
=={{header|Clojure}}== |
=={{header|Clojure}}== |
||
< |
<syntaxhighlight lang=Clojure>(def precedence '{* 0, / 0 |
||
+ 1, - 1}) |
+ 1, - 1}) |
||
Line 765: | Line 765: | ||
user> (evaluate "1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1") |
user> (evaluate "1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1") |
||
60</ |
60</syntaxhighlight> |
||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
||
Line 783: | Line 783: | ||
This implementation can read integers, and produce integral and rational values. |
This implementation can read integers, and produce integral and rational values. |
||
< |
<syntaxhighlight lang=lisp>(defun tokenize-stream (stream) |
||
(labels ((whitespace-p (char) |
(labels ((whitespace-p (char) |
||
(find char #(#\space #\newline #\return #\tab))) |
(find char #(#\space #\newline #\return #\tab))) |
||
Line 868: | Line 868: | ||
(loop for token = (tokenize-stream in) |
(loop for token = (tokenize-stream in) |
||
until (null token) |
until (null token) |
||
collect token)))))))</ |
collect token)))))))</syntaxhighlight> |
||
Examples |
Examples |
||
Line 912: | Line 912: | ||
=={{header|D}}== |
=={{header|D}}== |
||
After the AST tree is constructed, a visitor pattern is used to display the AST structure and calculate the expression value. |
After the AST tree is constructed, a visitor pattern is used to display the AST structure and calculate the expression value. |
||
< |
<syntaxhighlight lang=d>import std.stdio, std.string, std.ascii, std.conv, std.array, |
||
std.exception, std.traits; |
std.exception, std.traits; |
||
Line 1,132: | Line 1,132: | ||
immutable exp = (args.length > 1) ? args[1 .. $].join(' ') : exp0; |
immutable exp = (args.length > 1) ? args[1 .. $].join(' ') : exp0; |
||
new AST().parse(exp).CalcVis; // Should be 60. |
new AST().parse(exp).CalcVis; // Should be 60. |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> ........................................................+. |
<pre> ........................................................+. |
||
Line 1,154: | Line 1,154: | ||
=={{header|Dyalect}}== |
=={{header|Dyalect}}== |
||
< |
<syntaxhighlight lang=dyalect>type Expr = Bin(op, Expr left, Expr right) or Literal(Float val) |
||
with Lookup |
with Lookup |
||
Line 1,271: | Line 1,271: | ||
print( eval("(1+33.23)*7") ) |
print( eval("(1+33.23)*7") ) |
||
print( eval("1+33.23*7") )</ |
print( eval("1+33.23*7") )</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,282: | Line 1,282: | ||
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''... |
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''... |
||
< |
<syntaxhighlight lang=e>def eParser := <elang:syntax.makeEParser> |
||
def LiteralExpr := <elang:evm.makeLiteralExpr>.asType() |
def LiteralExpr := <elang:evm.makeLiteralExpr>.asType() |
||
def arithEvaluate(expr :String) { |
def arithEvaluate(expr :String) { |
||
Line 1,299: | Line 1,299: | ||
return evalAST(ast) |
return evalAST(ast) |
||
}</ |
}</syntaxhighlight> |
||
Parentheses are handled by the parser. |
Parentheses are handled by the parser. |
||
< |
<syntaxhighlight lang=e>? arithEvaluate("1 + 2") |
||
# value: 3 |
# value: 3 |
||
Line 1,310: | Line 1,310: | ||
? arithEvaluate("(1 + 2 / 2) * (5 + 5)") |
? arithEvaluate("(1 + 2 / 2) * (5 + 5)") |
||
# value: 20.0</ |
# value: 20.0</syntaxhighlight> |
||
=={{header|Elena}}== |
=={{header|Elena}}== |
||
ELENA 5.0 : |
ELENA 5.0 : |
||
< |
<syntaxhighlight lang=elena>import system'routines; |
||
import extensions; |
import extensions; |
||
import extensions'text; |
import extensions'text; |
||
Line 1,654: | Line 1,654: | ||
text.clear() |
text.clear() |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Emacs Lisp}}== |
=={{header|Emacs Lisp}}== |
||
< |
<syntaxhighlight lang=lisp>#!/usr/bin/env emacs --script |
||
;; -*- mode: emacs-lisp; lexical-binding: t -*- |
;; -*- mode: emacs-lisp; lexical-binding: t -*- |
||
;;> ./arithmetic-evaluation '(1 + 2) * 3' |
;;> ./arithmetic-evaluation '(1 + 2) * 3' |
||
Line 1,750: | Line 1,750: | ||
(terpri))) |
(terpri))) |
||
(setq command-line-args-left nil) |
(setq command-line-args-left nil) |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
Line 1,772: | Line 1,772: | ||
=={{header|ERRE}}== |
=={{header|ERRE}}== |
||
< |
<syntaxhighlight lang=ERRE> |
||
PROGRAM EVAL |
PROGRAM EVAL |
||
Line 2,006: | Line 2,006: | ||
IF NERR>0 THEN PRINT("Internal Error #";NERR) ELSE PRINT("Value is ";DB#) END IF |
IF NERR>0 THEN PRINT("Internal Error #";NERR) ELSE PRINT("Value is ";DB#) END IF |
||
END PROGRAM |
END PROGRAM |
||
</syntaxhighlight> |
|||
</lang> |
|||
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). |
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). |
||
Line 2,013: | Line 2,013: | ||
<code>AbstractSyntaxTree.fs</code>: |
<code>AbstractSyntaxTree.fs</code>: |
||
< |
<syntaxhighlight lang=fsharp>module AbstractSyntaxTree |
||
type Expression = |
type Expression = |
||
Line 2,020: | Line 2,020: | ||
| Minus of Expression * Expression |
| Minus of Expression * Expression |
||
| Times of Expression * Expression |
| Times of Expression * Expression |
||
| Divide of Expression * Expression</ |
| Divide of Expression * Expression</syntaxhighlight> |
||
<code>Lexer.fsl</code>: |
<code>Lexer.fsl</code>: |
||
< |
<syntaxhighlight lang=fsharp>{ |
||
module Lexer |
module Lexer |
||
Line 2,046: | Line 2,046: | ||
| newline { lexbuf.EndPos <- lexbuf.EndPos.NextLine; token lexbuf } |
| newline { lexbuf.EndPos <- lexbuf.EndPos.NextLine; token lexbuf } |
||
| eof { EOF } |
| eof { EOF } |
||
| _ { failwithf "unrecognized input: '%s'" <| lexeme lexbuf }</ |
| _ { failwithf "unrecognized input: '%s'" <| lexeme lexbuf }</syntaxhighlight> |
||
<code>Parser.fsy</code>: |
<code>Parser.fsy</code>: |
||
< |
<syntaxhighlight lang=fsharp>%{ |
||
open AbstractSyntaxTree |
open AbstractSyntaxTree |
||
%} |
%} |
||
Line 2,074: | Line 2,074: | ||
| Expr TIMES Expr { Times ($1, $3) } |
| Expr TIMES Expr { Times ($1, $3) } |
||
| Expr DIVIDE Expr { Divide ($1, $3) } |
| Expr DIVIDE Expr { Divide ($1, $3) } |
||
| LPAREN Expr RPAREN { $2 } </ |
| LPAREN Expr RPAREN { $2 } </syntaxhighlight> |
||
<code>Program.fs</code>: |
<code>Program.fs</code>: |
||
< |
<syntaxhighlight lang=fsharp>open AbstractSyntaxTree |
||
open Lexer |
open Lexer |
||
open Parser |
open Parser |
||
Line 2,097: | Line 2,097: | ||
|> parse |
|> parse |
||
|> eval |
|> eval |
||
|> printfn "%d"</ |
|> printfn "%d"</syntaxhighlight> |
||
=={{header|Factor}}== |
=={{header|Factor}}== |
||
< |
<syntaxhighlight lang=factor>USING: accessors kernel locals math math.parser peg.ebnf ; |
||
IN: rosetta.arith |
IN: rosetta.arith |
||
Line 2,141: | Line 2,141: | ||
: evaluate ( string -- result ) |
: evaluate ( string -- result ) |
||
expr-ast eval-ast ;</ |
expr-ast eval-ast ;</syntaxhighlight> |
||
=={{header|FreeBASIC}}== |
=={{header|FreeBASIC}}== |
||
< |
<syntaxhighlight lang=FreeBASIC> |
||
'Arithmetic evaluation |
'Arithmetic evaluation |
||
' |
' |
||
Line 2,340: | Line 2,340: | ||
if sym <> done_sym then error_msg("unexpected input") |
if sym <> done_sym then error_msg("unexpected input") |
||
loop |
loop |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
Line 2,355: | Line 2,355: | ||
=={{header|Groovy}}== |
=={{header|Groovy}}== |
||
Solution: |
Solution: |
||
< |
<syntaxhighlight lang=groovy>enum Op { |
||
ADD('+', 2), |
ADD('+', 2), |
||
SUBTRACT('-', 2), |
SUBTRACT('-', 2), |
||
Line 2,498: | Line 2,498: | ||
} |
} |
||
return elements[0] instanceof List ? parse(elements[0]) : elements[0] |
return elements[0] instanceof List ? parse(elements[0]) : elements[0] |
||
}</ |
}</syntaxhighlight> |
||
Test: |
Test: |
||
< |
<syntaxhighlight lang=groovy>def testParse = { |
||
def ex = parse(it) |
def ex = parse(it) |
||
print """ |
print """ |
||
Line 2,536: | Line 2,536: | ||
try { testParse('1++') } catch (e) { println e } |
try { testParse('1++') } catch (e) { println e } |
||
try { testParse('*1') } catch (e) { println e } |
try { testParse('*1') } catch (e) { println e } |
||
try { testParse('/ 1 /') } catch (e) { println e }</ |
try { testParse('/ 1 /') } catch (e) { println e }</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 2,605: | Line 2,605: | ||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
< |
<syntaxhighlight lang=haskell>{-# LANGUAGE FlexibleContexts #-} |
||
import Text.Parsec |
import Text.Parsec |
||
Line 2,651: | Line 2,651: | ||
main :: IO () |
main :: IO () |
||
main = print $ solution "(1+3)*7"</ |
main = print $ solution "(1+3)*7"</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
<pre>28</pre> |
<pre>28</pre> |
||
Line 2,667: | Line 2,667: | ||
* Notice that the code looks remarkably like a typical grammar, rather than being an opaque cryptic solution |
* 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 |
* 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 |
||
< |
<syntaxhighlight lang=Icon>procedure main() #: simple arithmetical parser / evaluator |
||
write("Usage: Input expression = Abstract Syntax Tree = Value, ^Z to end.") |
write("Usage: Input expression = Abstract Syntax Tree = Value, ^Z to end.") |
||
repeat { |
repeat { |
||
Line 2,767: | Line 2,767: | ||
procedure exponent() |
procedure exponent() |
||
suspend tab(any('eE')) || =("+" | "-" | "") || digits() | "" |
suspend tab(any('eE')) || =("+" | "-" | "") || digits() | "" |
||
end</ |
end</syntaxhighlight> |
||
{{out|Sample Output}} |
{{out|Sample Output}} |
||
Line 2,799: | Line 2,799: | ||
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): |
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): |
||
< |
<syntaxhighlight lang=j>parse=:parse_parser_ |
||
eval=:monad define |
eval=:monad define |
||
'gerund structure'=:y |
'gerund structure'=:y |
||
Line 2,864: | Line 2,864: | ||
coerase tmp |
coerase tmp |
||
r |
r |
||
)</ |
)</syntaxhighlight> |
||
example use: |
example use: |
||
< |
<syntaxhighlight lang=j> eval parse '1+2*3/(4-5+6)' |
||
2.2</ |
2.2</syntaxhighlight> |
||
You can also display the syntax tree, for example: |
You can also display the syntax tree, for example: |
||
< |
<syntaxhighlight lang=j> parse '2*3/(4-5)' |
||
┌─────────────────────────────────────────────────────┬───────────────────┐ |
┌─────────────────────────────────────────────────────┬───────────────────┐ |
||
│┌───┬───────┬───┬───────┬───┬─┬───────┬───┬───────┬─┐│┌───────┬─┬───────┐│ |
│┌───┬───────┬───┬───────┬───┬─┬───────┬───┬───────┬─┐│┌───────┬─┬───────┐│ |
||
Line 2,879: | Line 2,879: | ||
││ │└─────┘│ │└─────┘│ │ │└─────┘│ │└─────┘│ ││ │ |
││ │└─────┘│ │└─────┘│ │ │└─────┘│ │└─────┘│ ││ │ |
||
│└───┴───────┴───┴───────┴───┴─┴───────┴───┴───────┴─┘│ │ |
│└───┴───────┴───┴───────┴───┴─┴───────┴───┴───────┴─┘│ │ |
||
└─────────────────────────────────────────────────────┴───────────────────┘</ |
└─────────────────────────────────────────────────────┴───────────────────┘</syntaxhighlight> |
||
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. |
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. |
||
Line 2,887: | Line 2,887: | ||
Uses the [[Arithmetic/Rational/Java|BigRational class]] to handle arbitrary-precision numbers (rational numbers since basic arithmetic will result in rational values). |
Uses the [[Arithmetic/Rational/Java|BigRational class]] to handle arbitrary-precision numbers (rational numbers since basic arithmetic will result in rational values). |
||
< |
<syntaxhighlight lang=java>import java.util.Stack; |
||
public class ArithmeticEvaluation { |
public class ArithmeticEvaluation { |
||
Line 3,051: | Line 3,051: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 3,066: | Line 3,066: | ||
Spaces are removed, expressions like <code>5--1</code> are treated as <code>5 - -1</code> |
Spaces are removed, expressions like <code>5--1</code> are treated as <code>5 - -1</code> |
||
< |
<syntaxhighlight lang=javascript>function evalArithmeticExp(s) { |
||
s = s.replace(/\s/g,'').replace(/^\+/,''); |
s = s.replace(/\s/g,'').replace(/^\+/,''); |
||
var rePara = /\([^\(\)]*\)/; |
var rePara = /\([^\(\)]*\)/; |
||
Line 3,120: | Line 3,120: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
Line 3,136: | Line 3,136: | ||
=== PEG operations === |
=== PEG operations === |
||
< |
<syntaxhighlight lang=jq>def star(E): (E | star(E)) // .; |
||
def plus(E): E | (plus(E) // . ); |
def plus(E): E | (plus(E) // . ); |
||
def optional(E): E // .; |
def optional(E): E // .; |
||
def amp(E): . as $in | E | $in; |
def amp(E): . as $in | E | $in; |
||
def neg(E): select( [E] == [] );</ |
def neg(E): select( [E] == [] );</syntaxhighlight> |
||
=== Helper functions === |
=== Helper functions === |
||
< |
<syntaxhighlight lang=jq>def literal($s): |
||
select(.remainder | startswith($s)) |
select(.remainder | startswith($s)) |
||
| .result += [$s] |
| .result += [$s] |
||
Line 3,165: | Line 3,165: | ||
def parseNumber($re): |
def parseNumber($re): |
||
consume($re) |
consume($re) |
||
| .result = .result + [.match|tonumber] ;</ |
| .result = .result + [.match|tonumber] ;</syntaxhighlight> |
||
=== PEG Grammar === |
=== PEG Grammar === |
||
The PEG grammar for arithmetic expressions follows the one given at the Raku entry.< |
The PEG grammar for arithmetic expressions follows the one given at the Raku entry.<syntaxhighlight lang=jq>def Expr: |
||
def ws: consume(" *"); |
def ws: consume(" *"); |
||
Line 3,180: | Line 3,180: | ||
Product | ws | star( (literal("+") // literal("-")) | Product); |
Product | ws | star( (literal("+") // literal("-")) | Product); |
||
Sum;</ |
Sum;</syntaxhighlight> |
||
=== Evaluation === |
=== Evaluation === |
||
< |
<syntaxhighlight lang=jq># Left-to-right evaluation |
||
def eval: |
def eval: |
||
if type == "array" then |
if type == "array" then |
||
Line 3,204: | Line 3,204: | ||
{remainder: String} |
{remainder: String} |
||
| Expr.result |
| Expr.result |
||
| eval;</ |
| eval;</syntaxhighlight> |
||
=== Example === |
=== Example === |
||
Line 3,214: | Line 3,214: | ||
From Javascript entry. |
From Javascript entry. |
||
< |
<syntaxhighlight lang=javascript>/* Arithmetic evaluation, in Jsish */ |
||
function evalArithmeticExp(s) { |
function evalArithmeticExp(s) { |
||
s = s.replace(/\s/g,'').replace(/^\+/,''); |
s = s.replace(/\s/g,'').replace(/^\+/,''); |
||
Line 3,290: | Line 3,290: | ||
evalArithmeticExp('2*-3--4+-0.25') ==> -2.25 |
evalArithmeticExp('2*-3--4+-0.25') ==> -2.25 |
||
=!EXPECTEND!= |
=!EXPECTEND!= |
||
*/</ |
*/</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 3,303: | Line 3,303: | ||
=={{header|Julia}}== |
=={{header|Julia}}== |
||
Julia's homoiconic nature and strong metaprogramming facilities make AST/Expression parsing and creation as accessible and programmatic as other language features |
Julia's homoiconic nature and strong metaprogramming facilities make AST/Expression parsing and creation as accessible and programmatic as other language features |
||
< |
<syntaxhighlight lang=julia>julia> expr="2 * (3 -1) + 2 * 5" |
||
"2 * (3 -1) + 2 * 5" |
"2 * (3 -1) + 2 * 5" |
||
Line 3,343: | Line 3,343: | ||
julia> eval(parse("2 * (3 + ((5) / (7 - 11)))")) |
julia> eval(parse("2 * (3 + ((5) / (7 - 11)))")) |
||
3.5</ |
3.5</syntaxhighlight> |
||
=={{header|Kotlin}}== |
=={{header|Kotlin}}== |
||
{{trans|JavaScript}} |
{{trans|JavaScript}} |
||
< |
<syntaxhighlight lang=scala>// version 1.2.10 |
||
/* if string is empty, returns zero */ |
/* if string is empty, returns zero */ |
||
Line 3,432: | Line 3,432: | ||
"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" |
||
).forEach { println("$it = ${evalArithmeticExp(it)}") } |
).forEach { println("$it = ${evalArithmeticExp(it)}") } |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 3,449: | Line 3,449: | ||
=={{header|Liberty BASIC}}== |
=={{header|Liberty BASIC}}== |
||
<syntaxhighlight lang=lb> |
|||
<lang lb> |
|||
'[RC] Arithmetic evaluation.bas |
'[RC] Arithmetic evaluation.bas |
||
'Buld the tree (with linked nodes, in array 'cause LB has no pointers) |
'Buld the tree (with linked nodes, in array 'cause LB has no pointers) |
||
Line 3,685: | Line 3,685: | ||
addOpNode = newNode |
addOpNode = newNode |
||
end function |
end function |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
Line 3,703: | Line 3,703: | ||
=={{header|Lua}}== |
=={{header|Lua}}== |
||
< |
<syntaxhighlight lang=lua>require"lpeg" |
||
P, R, C, S, V = lpeg.P, lpeg.R, lpeg.C, lpeg.S, lpeg.V |
P, R, C, S, V = lpeg.P, lpeg.R, lpeg.C, lpeg.S, lpeg.V |
||
Line 3,742: | Line 3,742: | ||
end |
end |
||
print(eval{expression:match(io.read())})</ |
print(eval{expression:match(io.read())})</syntaxhighlight> |
||
=={{header|M2000 Interpreter}}== |
=={{header|M2000 Interpreter}}== |
||
Line 3,748: | Line 3,748: | ||
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. |
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 |
y=100 |
||
Module CheckEval { |
Module CheckEval { |
||
Line 3,761: | Line 3,761: | ||
} |
} |
||
Call CheckEval |
Call CheckEval |
||
</syntaxhighlight> |
|||
</lang> |
|||
From BBC BASIC. In M2000 we can't call a user function which isn't a child function, so here we make all functions as members of same group, so now they call each other. A function as a member in a group can use other members, using a dot or This and a dot, so .Ast$() is same as This.Ast$(). |
From BBC BASIC. In M2000 we can't call a user function which isn't a child function, so here we make all functions as members of same group, so now they call each other. A function as a member in a group can use other members, using a dot or This and a dot, so .Ast$() is same as This.Ast$(). |
||
< |
<syntaxhighlight lang=M2000 Interpreter> |
||
Module CheckAst { |
Module CheckAst { |
||
Group Eval { |
Group Eval { |
||
Line 3,819: | Line 3,819: | ||
} |
} |
||
CheckAst |
CheckAst |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Mathematica}} / {{header|Wolfram Language}}== |
=={{header|Mathematica}} / {{header|Wolfram Language}}== |
||
< |
<syntaxhighlight lang=Mathematica>(*parsing:*) |
||
parse[string_] := |
parse[string_] := |
||
Module[{e}, |
Module[{e}, |
||
Line 3,855: | Line 3,855: | ||
evaluate[{"*", a_, b_}] := evaluate[a]*evaluate[b]; |
evaluate[{"*", a_, b_}] := evaluate[a]*evaluate[b]; |
||
evaluate[{"/", a_, b_}] := evaluate[a]/evaluate[b]; |
evaluate[{"/", a_, b_}] := evaluate[a]/evaluate[b]; |
||
evaluate[string_String] := evaluate[parse[string]]</ |
evaluate[string_String] := evaluate[parse[string]]</syntaxhighlight> |
||
Example use: |
Example use: |
||
< |
<syntaxhighlight lang=Mathematica>parse["-1+2(3+4*-5/6)"] |
||
evaluate["-1+2(3+4*-5/6)"]</ |
evaluate["-1+2(3+4*-5/6)"]</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 3,866: | Line 3,866: | ||
=={{header|MiniScript}}== |
=={{header|MiniScript}}== |
||
< |
<syntaxhighlight lang=MiniScript>Expr = {} |
||
Expr.eval = 0 |
Expr.eval = 0 |
||
Line 3,928: | Line 3,928: | ||
print ast.eval |
print ast.eval |
||
end while |
end while |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre>Enter expression: 200*42 |
<pre>Enter expression: 200*42 |
||
Line 3,947: | Line 3,947: | ||
This implementation uses a Pratt parser. |
This implementation uses a Pratt parser. |
||
< |
<syntaxhighlight lang=nim>import strutils |
||
import os |
import os |
||
Line 4,097: | Line 4,097: | ||
# In the end, we print out the result. |
# In the end, we print out the result. |
||
echo ==ast</ |
echo ==ast</syntaxhighlight> |
||
=={{header|OCaml}}== |
=={{header|OCaml}}== |
||
< |
<syntaxhighlight lang=ocaml>type expression = |
||
| Const of float |
| Const of float |
||
| Sum of expression * expression (* e1 + e2 *) |
| Sum of expression * expression (* e1 + e2 *) |
||
Line 4,139: | Line 4,139: | ||
let parse_expression = parser [< e = parse_expr; _ = Stream.empty >] -> e |
let parse_expression = parser [< e = parse_expr; _ = Stream.empty >] -> e |
||
let read_expression s = parse_expression(lexer(Stream.of_string s))</ |
let read_expression s = parse_expression(lexer(Stream.of_string s))</syntaxhighlight> |
||
Using the function <code>read_expression</code> in an interactive loop: |
Using the function <code>read_expression</code> in an interactive loop: |
||
< |
<syntaxhighlight lang=ocaml>let () = |
||
while true do |
while true do |
||
print_string "Expression: "; |
print_string "Expression: "; |
||
Line 4,151: | Line 4,151: | ||
let res = eval expr in |
let res = eval expr in |
||
Printf.printf " = %g\n%!" res; |
Printf.printf " = %g\n%!" res; |
||
done</ |
done</syntaxhighlight> |
||
Compile with: |
Compile with: |
||
Line 4,157: | Line 4,157: | ||
=={{header|ooRexx}}== |
=={{header|ooRexx}}== |
||
< |
<syntaxhighlight 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") |
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 |
loop input over expressions |
||
Line 4,393: | Line 4,393: | ||
raise syntax 98.900 array("Invalid expression") |
raise syntax 98.900 array("Invalid expression") |
||
return expression |
return expression |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 4,410: | Line 4,410: | ||
The <code>Do</code> procedure automatically threads the input state through a sequence of procedure calls. |
The <code>Do</code> procedure automatically threads the input state through a sequence of procedure calls. |
||
< |
<syntaxhighlight lang=oz>declare |
||
fun {Expr X0 ?X} |
fun {Expr X0 ?X} |
||
Line 4,497: | Line 4,497: | ||
{Inspector.configure widgetShowStrings true} |
{Inspector.configure widgetShowStrings true} |
||
{Inspect AST} |
{Inspect AST} |
||
{Inspect {Eval AST}}</ |
{Inspect {Eval AST}}</syntaxhighlight> |
||
To improve performance, the number of choice points should be limited, for example by reading numbers deterministically instead. |
To improve performance, the number of choice points should be limited, for example by reading numbers deterministically instead. |
||
Line 4,506: | Line 4,506: | ||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
< |
<syntaxhighlight lang=perl>sub ev |
||
# Evaluates an arithmetic expression like "(1+3)*7" and returns |
# Evaluates an arithmetic expression like "(1+3)*7" and returns |
||
# its value. |
# its value. |
||
Line 4,566: | Line 4,566: | ||
my ($op, @operands) = @$ast; |
my ($op, @operands) = @$ast; |
||
$_ = ev_ast($_) foreach @operands; |
$_ = ev_ast($_) foreach @operands; |
||
return $ops{$op}->(@operands);}}</ |
return $ops{$op}->(@operands);}}</syntaxhighlight> |
||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
Line 4,573: | Line 4,573: | ||
plus this as asked for has an AST, whereas Phix uses cross-linked flat IL. |
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. |
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: #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: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
||
Line 4,793: | Line 4,793: | ||
<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: #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> |
<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. |
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}} |
{{out}} |
||
Line 4,867: | Line 4,867: | ||
=={{header|Picat}}== |
=={{header|Picat}}== |
||
< |
<syntaxhighlight lang=Picat>main => |
||
print("Enter an expression: "), |
print("Enter an expression: "), |
||
Str = read_line(), |
Str = read_line(), |
||
Line 4,873: | Line 4,873: | ||
Res is Exp, |
Res is Exp, |
||
printf("Result = %w\n", Res). |
printf("Result = %w\n", Res). |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|PicoLisp}}== |
=={{header|PicoLisp}}== |
||
Line 4,879: | Line 4,879: | ||
(numbers and transient symbols). From that, a recursive descendent parser can |
(numbers and transient symbols). From that, a recursive descendent parser can |
||
build an expression tree, resulting in directly executable Lisp code. |
build an expression tree, resulting in directly executable Lisp code. |
||
< |
<syntaxhighlight lang=PicoLisp>(de ast (Str) |
||
(let *L (str Str "") |
(let *L (str Str "") |
||
(aggregate) ) ) |
(aggregate) ) ) |
||
Line 4,901: | Line 4,901: | ||
((= "+" X) (term)) |
((= "+" X) (term)) |
||
((= "-" X) (list '- (term))) |
((= "-" X) (list '- (term))) |
||
((= "(" X) (prog1 (aggregate) (pop '*L)))) ) )</ |
((= "(" X) (prog1 (aggregate) (pop '*L)))) ) )</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
< |
<syntaxhighlight lang=PicoLisp>: (ast "1+2+3*-4/(1+2)") |
||
-> (+ (+ 1 2) (/ (* 3 (- 4)) (+ 1 2))) |
-> (+ (+ 1 2) (/ (* 3 (- 4)) (+ 1 2))) |
||
: (ast "(1+2+3)*-4/(1+2)") |
: (ast "(1+2+3)*-4/(1+2)") |
||
-> (/ (* (+ (+ 1 2) 3) (- 4)) (+ 1 2))</ |
-> (/ (* (+ (+ 1 2) 3) (- 4)) (+ 1 2))</syntaxhighlight> |
||
=={{header|Pop11}}== |
=={{header|Pop11}}== |
||
< |
<syntaxhighlight lang=pop11>/* Scanner routines */ |
||
/* Uncomment the following to parse data from standard input |
/* Uncomment the following to parse data from standard input |
||
Line 5,059: | Line 5,059: | ||
;;; Test it |
;;; Test it |
||
arith_eval(do_expr()) =></ |
arith_eval(do_expr()) =></syntaxhighlight> |
||
=={{header|Prolog}}== |
=={{header|Prolog}}== |
||
{{works with|SWI Prolog 8.1.19}} |
{{works with|SWI Prolog 8.1.19}} |
||
< |
<syntaxhighlight lang=prolog>% Lexer |
||
numeric(X) :- 48 =< X, X =< 57. |
numeric(X) :- 48 =< X, X =< 57. |
||
not_numeric(X) :- 48 > X ; X > 57. |
not_numeric(X) :- 48 > X ; X > 57. |
||
Line 5,113: | Line 5,113: | ||
% Example use |
% Example use |
||
% calculator("(3+50)*7-9", X).</ |
% calculator("(3+50)*7-9", X).</syntaxhighlight> |
||
=={{header|Python}}== |
=={{header|Python}}== |
||
Line 5,119: | Line 5,119: | ||
<br>A subsequent example uses Pythons' ast module to generate the abstract syntax tree. |
<br>A subsequent example uses Pythons' ast module to generate the abstract syntax tree. |
||
< |
<syntaxhighlight lang=python>import operator |
||
class AstNode(object): |
class AstNode(object): |
||
Line 5,234: | Line 5,234: | ||
expr = raw_input("Expression:") |
expr = raw_input("Expression:") |
||
astTree = Lex( expr, Yaccer()) |
astTree = Lex( expr, Yaccer()) |
||
print expr, '=',astTree.eval()</ |
print expr, '=',astTree.eval()</syntaxhighlight> |
||
===ast standard library module=== |
===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. |
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. |
||
< |
<syntaxhighlight lang=python>>>> import ast |
||
>>> |
>>> |
||
>>> expr="2 * (3 -1) + 2 * 5" |
>>> expr="2 * (3 -1) + 2 * 5" |
||
Line 5,261: | Line 5,261: | ||
>>> code_object = compile(node, filename='<string>', mode='eval') |
>>> code_object = compile(node, filename='<string>', mode='eval') |
||
>>> eval(code_object) |
>>> eval(code_object) |
||
16</ |
16</syntaxhighlight> |
||
=={{header|Racket}}== |
=={{header|Racket}}== |
||
< |
<syntaxhighlight lang=racket>#lang racket |
||
(require parser-tools/yacc |
(require parser-tools/yacc |
||
Line 5,300: | Line 5,300: | ||
(displayln (parse (λ () (lex i))))) |
(displayln (parse (λ () (lex i))))) |
||
(calc "(1 + 2 * 3) - (1+2)*-3")</ |
(calc "(1 + 2 * 3) - (1+2)*-3")</syntaxhighlight> |
||
=={{header|Raku}}== |
=={{header|Raku}}== |
||
Line 5,306: | Line 5,306: | ||
{{Works with|rakudo|2018.03}} |
{{Works with|rakudo|2018.03}} |
||
< |
<syntaxhighlight lang=perl6>sub ev (Str $s --> Numeric) { |
||
grammar expr { |
grammar expr { |
||
Line 5,349: | Line 5,349: | ||
say ev '1 + 2 - 3 * 4 / 5'; # 0.6 |
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 '1 + 5*3.4 - .5 -4 / -2 * (3+4) -6'; # 25.5 |
||
say ev '((11+15)*15)* 2 + (3) * -4 *1'; # 768</ |
say ev '((11+15)*15)* 2 + (3) * -4 *1'; # 768</syntaxhighlight> |
||
=={{header|REXX}}== |
=={{header|REXX}}== |
||
Line 5,366: | Line 5,366: | ||
:::* 12.3D+44 ("double" precision) |
:::* 12.3D+44 ("double" precision) |
||
:::* 12.3Q+44 ("extended" or "quad" precision) |
:::* 12.3Q+44 ("extended" or "quad" precision) |
||
< |
<syntaxhighlight lang=rexx>/*REXX program evaluates an infix─type arithmetic expression and displays the result.*/ |
||
nchars = '0123456789.eEdDqQ' /*possible parts of a number, sans ± */ |
nchars = '0123456789.eEdDqQ' /*possible parts of a number, sans ± */ |
||
e='***error***'; $=" "; doubleOps= '&|*/'; z= /*handy─dandy variables.*/ |
e='***error***'; $=" "; doubleOps= '&|*/'; z= /*handy─dandy variables.*/ |
||
Line 5,481: | Line 5,481: | ||
return substr(x, Nj, 1) /* [↑] ignore any blanks in expression*/ |
return substr(x, Nj, 1) /* [↑] ignore any blanks in expression*/ |
||
end /*Nj*/ |
end /*Nj*/ |
||
return $ /*reached end-of-tokens, return $. */</ |
return $ /*reached end-of-tokens, return $. */</syntaxhighlight> |
||
To view a version of the above REXX program, see this version which has much more whitespace: ──► [[Arithmetic_evaluation/REXX]]. <br> |
To view a version of the above REXX program, see this version which has much more whitespace: ──► [[Arithmetic_evaluation/REXX]]. <br> |
||
<br> |
<br> |
||
Line 5,492: | Line 5,492: | ||
=={{header|Ruby}}== |
=={{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 |
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 |
||
< |
<syntaxhighlight lang=ruby>$op_priority = {"+" => 0, "-" => 0, "*" => 1, "/" => 1} |
||
class TreeNode |
class TreeNode |
||
Line 5,591: | Line 5,591: | ||
node_stack.last |
node_stack.last |
||
end</ |
end</syntaxhighlight> |
||
Testing: |
Testing: |
||
< |
<syntaxhighlight lang=ruby>exp = "1 + 2 - 3 * (4 / 6)" |
||
puts("Original: " + exp) |
puts("Original: " + exp) |
||
Line 5,600: | Line 5,600: | ||
puts("Infix: " + tree.to_s(:infix)) |
puts("Infix: " + tree.to_s(:infix)) |
||
puts("Postfix: " + tree.to_s(:postfix)) |
puts("Postfix: " + tree.to_s(:postfix)) |
||
puts("Result: " + tree.eval.to_s)</ |
puts("Result: " + tree.eval.to_s)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>Original: 1 + 2 - 3 * (4 / 6) |
<pre>Original: 1 + 2 - 3 * (4 / 6) |
||
Line 5,609: | Line 5,609: | ||
=={{header|Rust}}== |
=={{header|Rust}}== |
||
< |
<syntaxhighlight lang=rust>//! Simple calculator parser and evaluator |
||
Line 5,782: | Line 5,782: | ||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Scala}}== |
=={{header|Scala}}== |
||
Line 5,788: | Line 5,788: | ||
is practically non-existent, to avoid obscuring the code. |
is practically non-existent, to avoid obscuring the code. |
||
< |
<syntaxhighlight lang=scala> |
||
package org.rosetta.arithmetic_evaluator.scala |
package org.rosetta.arithmetic_evaluator.scala |
||
Line 5,835: | Line 5,835: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
Example: |
Example: |
||
Line 5,864: | Line 5,864: | ||
The parse function uses a recursive-descent parser to follow the precedence rules. |
The parse function uses a recursive-descent parser to follow the precedence rules. |
||
< |
<syntaxhighlight lang=scheme> |
||
(import (scheme base) |
(import (scheme base) |
||
(scheme char) |
(scheme char) |
||
Line 5,960: | Line 5,960: | ||
(newline)) |
(newline)) |
||
'("1 + 2" "20+4*5" "1/2+5*(6-3)" "(1+3)/4-1" "(1 - 5) * 2 / (20 + 1)")) |
'("1 + 2" "20+4*5" "1/2+5*(6-3)" "(1+3)/4-1" "(1 - 5) * 2 / (20 + 1)")) |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
Line 5,974: | Line 5,974: | ||
=={{header|Sidef}}== |
=={{header|Sidef}}== |
||
{{trans|JavaScript}} |
{{trans|JavaScript}} |
||
< |
<syntaxhighlight lang=ruby>func evalArithmeticExp(s) { |
||
func evalExp(s) { |
func evalExp(s) { |
||
Line 6,029: | Line 6,029: | ||
return Number(evalExp(s)) |
return Number(evalExp(s)) |
||
}</ |
}</syntaxhighlight> |
||
Testing the function: |
Testing the function: |
||
< |
<syntaxhighlight lang=ruby>for expr,res in [ |
||
['2+3' => 5], |
['2+3' => 5], |
||
['-4-3' => -7], |
['-4-3' => -7], |
||
Line 6,044: | Line 6,044: | ||
assert_eq(num, res) |
assert_eq(num, res) |
||
"%-45s == %10g\n".printf(expr, num) |
"%-45s == %10g\n".printf(expr, num) |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Standard ML}}== |
=={{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. |
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. |
The parsing is a little bit tricky because the grammar is left recursive. |
||
< |
<syntaxhighlight lang=sml>(* AST *) |
||
datatype expression = |
datatype expression = |
||
Con of int (* constant *) |
Con of int (* constant *) |
||
Line 6,117: | Line 6,117: | ||
case parseE (lex (explode str)) of |
case parseE (lex (explode str)) of |
||
(exp, nil) => eval exp |
(exp, nil) => eval exp |
||
| _ => raise Error "not parseable stuff at the end"</ |
| _ => raise Error "not parseable stuff at the end"</syntaxhighlight> |
||
=={{header|Tailspin}}== |
=={{header|Tailspin}}== |
||
< |
<syntaxhighlight lang=tailspin> |
||
def ops: ['+','-','*','/']; |
def ops: ['+','-','*','/']; |
||
Line 6,147: | Line 6,147: | ||
'$ast -> evaluateArithmetic; |
'$ast -> evaluateArithmetic; |
||
' -> !OUT::write |
' -> !OUT::write |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 6,155: | Line 6,155: | ||
If we don't need to get the AST, we could just evaluate right away: |
If we don't need to get the AST, we could just evaluate right away: |
||
< |
<syntaxhighlight lang=tailspin> |
||
composer calculator |
composer calculator |
||
(<WS>?) <addition|multiplication|term> (<WS>?) |
(<WS>?) <addition|multiplication|term> (<WS>?) |
||
Line 6,173: | Line 6,173: | ||
' |
' |
||
' -> !OUT::write |
' -> !OUT::write |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre>16</pre> |
<pre>16</pre> |
||
Line 6,182: | Line 6,182: | ||
in a form that it can be immediately eval-led, |
in a form that it can be immediately eval-led, |
||
using Tcl's prefix operators. |
using Tcl's prefix operators. |
||
< |
<syntaxhighlight lang=Tcl>namespace import tcl::mathop::* |
||
proc ast str { |
proc ast str { |
||
Line 6,225: | Line 6,225: | ||
} \n] { |
} \n] { |
||
puts "$test ..... [eval $test] ..... [eval [eval $test]]" |
puts "$test ..... [eval $test] ..... [eval [eval $test]]" |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 6,241: | Line 6,241: | ||
Use TXR text pattern matching to parse expression to a Lisp AST, then evaluate with <code>eval</code>: |
Use TXR text pattern matching to parse expression to a Lisp AST, then evaluate with <code>eval</code>: |
||
< |
<syntaxhighlight lang=txr>@(next :args) |
||
@(define space)@/ */@(end) |
@(define space)@/ */@(end) |
||
@(define mulop (nod))@\ |
@(define mulop (nod))@\ |
||
Line 6,293: | Line 6,293: | ||
erroneous suffix "@bad" |
erroneous suffix "@bad" |
||
@ (end) |
@ (end) |
||
@(end)</ |
@(end)</syntaxhighlight> |
||
Run: |
Run: |
||
Line 6,307: | Line 6,307: | ||
=={{header|Ursala}}== |
=={{header|Ursala}}== |
||
with no error checking other than removal of spaces |
with no error checking other than removal of spaces |
||
< |
<syntaxhighlight lang=Ursala>#import std |
||
#import nat |
#import nat |
||
#import flo |
#import flo |
||
Line 6,324: | Line 6,324: | ||
traverse = *^ ~&v?\%ep ^H\~&vhthPX '+-*/'-$<plus,minus,times,div>@dh |
traverse = *^ ~&v?\%ep ^H\~&vhthPX '+-*/'-$<plus,minus,times,div>@dh |
||
evaluate = traverse+ parse+ lex</ |
evaluate = traverse+ parse+ lex</syntaxhighlight> |
||
test program: |
test program: |
||
< |
<syntaxhighlight lang=Ursala>#cast %eL |
||
test = evaluate*t |
test = evaluate*t |
||
Line 6,343: | Line 6,343: | ||
5-3*2 |
5-3*2 |
||
(1+1)*(2+3) |
(1+1)*(2+3) |
||
(2-4)/(3+5*(8-1))]-</ |
(2-4)/(3+5*(8-1))]-</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 6,363: | Line 6,363: | ||
{{trans|Kotlin}} |
{{trans|Kotlin}} |
||
{{libheader|Wren-pattern}} |
{{libheader|Wren-pattern}} |
||
< |
<syntaxhighlight lang=ecmascript>import "/pattern" for Pattern |
||
/* if string is empty, returns zero */ |
/* if string is empty, returns zero */ |
||
Line 6,452: | Line 6,452: | ||
"1 + 2 * (3 + (4 * 5 + 6 * 7 * 8) - 9) / 10", |
"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" |
"1 + 2*(3 - 2*(3 - 2)*((2 - 4)*5 - 22/(7 + 2*(3 - 1)) - 1)) + 1" |
||
].each { |s| System.print("%(s) = %(evalArithmeticExp.call(s))") }</ |
].each { |s| System.print("%(s) = %(evalArithmeticExp.call(s))") }</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 6,470: | Line 6,470: | ||
=={{header|zkl}}== |
=={{header|zkl}}== |
||
In zkl, the compiler stack is part of the language and is written in zkl so ... |
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();</ |
Compiler.Parser.parseText("1+3*7").dump();</syntaxhighlight> |
||
The ASTs look like |
The ASTs look like |
||
{{out}} |
{{out}} |
||
Line 6,493: | Line 6,493: | ||
</pre> |
</pre> |
||
Evaluating them is just moving up the stack: |
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;</ |
Compiler.Compiler.compileText("1+3*7").__constructor(); vm.regX;</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 6,502: | Line 6,502: | ||
=={{header|ZX Spectrum Basic}}== |
=={{header|ZX Spectrum Basic}}== |
||
< |
<syntaxhighlight lang=zxbasic>10 PRINT "Use integer numbers and signs"'"+ - * / ( )"'' |
||
20 LET s$="": REM last symbol |
20 LET s$="": REM last symbol |
||
30 LET pc=0: REM parenthesis counter |
30 LET pc=0: REM parenthesis counter |
||
Line 6,533: | Line 6,533: | ||
300 PRINT FLASH 1;"Invalid symbol ";c$;" detected in pos ";n: BEEP 1,-25 |
300 PRINT FLASH 1;"Invalid symbol ";c$;" detected in pos ";n: BEEP 1,-25 |
||
310 STOP |
310 STOP |
||
</syntaxhighlight> |
|||
</lang> |