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