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 ;
							 |