grammar Solver
;
options {
language = Ruby;
}
tokens {
PLUS = '+'; MINUS = '-'; MULT = '*'; DIV = '/'; MOD = '%'; EXP = '^'; LPAREN = '('; RPAREN = ')';
}
@header {
require 'bigdecimal/math'
}
@members {
attr_accessor :expressionCache attr_accessor :objectCache # Recovery function handling errors def recover( error = $! ) puts "Parser Recovering: #{error}" exit(1) end # Reporting function handling errors def report_error( error = $! ) puts "Parser Reporting: #{error}" exit(1) end
}
@lexer::members {
# Recovery function handling errors def recover( error = $! ) puts "Lexer Recovering: #{error}" exit(1) end # Reporting function handling errors def report_error( error = $! ) puts "Lexer Reporting: #{error}" exit(1) end
}
/*——————————————————————
* PARSER RULES *------------------------------------------------------------------*/
evaluate returns [result]
: r=expression {$result = $r.result } ;
expression returns [result]
: r=mult ( '+' r2=mult { $r.result += $r2.result } | '-' r2=mult { $r.result -= $r2.result } )* { $result = $r.result } ;
mult returns [result]
: r=log ( '*' r2=log { $r.result *= $r2.result } | '/' r2=log { $r.result /= $r2.result } )* { $result = $r.result };
log returns [result]
: 'ln' r=exp { $result = BigMath.log(r, 2)} | r=exp { $result = $r.result } ;
exp returns [result]
: r=atom ( '^' r2=atom { $r.result **= $r2.result.to_i() } )? { $result = $r.result } ;
atom returns [result]
: (a=INT {$result = BigDecimal($a.text)} | a=FLOAT {$result = BigDecimal($a.text)} | LPAREN r=expression { $result = $r.result } RPAREN | a=MODVAR { $result = @objectCache.send($a.text) } | a=UNMODVAR { case $a.text when 'R' $result = @objectCache.runtime when 'U' $result = @objectCache.send($a.text) when 'V' $result = @objectCache.send($a.text) else $result = BigDecimal("0") end } ) ;
/*——————————————————————
* LEXER RULES *------------------------------------------------------------------*/
INT : (DIGIT)+ ; FLOAT : INT ‘.’ INT; MODVAR : ‘A’..‘G’(MODIFIER); UNMODVAR : ( ‘R’ | ‘U’ | ‘V’ ); WHITESPACE : ( ‘t’ | ‘ ’ | ‘r’ | ‘n’| ‘u000C’ )+ { $channel = HIDDEN; };
/*——————————————————————
* Fragment RULES (Only used as part of another Lexer Rule) *------------------------------------------------------------------*/
fragment DIGIT : ‘0’..‘9’; fragment MODIFIER: ‘a’|‘s’;