70 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Factor
		
	
	
			
		
		
	
	
			70 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Factor
		
	
	
| USING: accessors kernel locals math math.parser peg.ebnf ;
 | |
| IN: rosetta-code.arithmetic-evaluation
 | |
| 
 | |
| ! http://rosettacode.org/wiki/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.
 | |
| 
 | |
| ! Note
 | |
| 
 | |
| ! For those who don't remember, mathematical precedence is as
 | |
| ! follows:
 | |
| 
 | |
| ! * Parentheses
 | |
| ! * Multiplication/Division (left to right)
 | |
| ! * Addition/Subtraction (left to right)
 | |
| 
 | |
| 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 ;
 |