aboutsummaryrefslogtreecommitdiff
path: root/calc.y
diff options
context:
space:
mode:
Diffstat (limited to 'calc.y')
-rw-r--r--calc.y162
1 files changed, 36 insertions, 126 deletions
diff --git a/calc.y b/calc.y
index e45e4e3..bac526c 100644
--- a/calc.y
+++ b/calc.y
@@ -2,154 +2,64 @@
package main
-import (
- "fmt"
- "math"
-)
+import "math"
-type Number float64
-
-type Interval struct {
- lo Number
- hi Number
+var reg = map[string]float64{
+ "pi": math.Pi,
+ "e": math.E,
}
-var nreg = make(map[rune]Number)
-var ireg = make(map[rune]Interval)
+const last = "_"
%}
%union{
- dval Number
- vval Interval
- rval rune
+ fval float64
sval string
}
-%token <rval> DREG VREG
-%token <dval> NUMBER
-%token <sval> STRING
-%token EQ LBR RBR COM
+%token <fval> NUMBER
+%token <sval> WORD
-%type <dval> dexp
-%type <vval> vexp
+%type <fval> exp
-%left SUM SUB
-%left MUL DIV
+%left '+' '-'
+%left '*' '/' '%'
+%left '^'
%left UMINUS
%%
line
- : dexp { fmt.Println($1) }
- | vexp { fmt.Println($1) }
- | DREG EQ dexp { $3.Set($1) }
- | VREG EQ vexp { $3.Set($1) }
- | STRING { fmt.Println($1) }
+ : /* empty */
+ | exp {
+ reg[last] = $1
+ yylex.(*yyLex).result = $1
+ yylex.(*yyLex).ok = true
+ }
+ | WORD '=' exp { reg[$1] = $3 }
;
-dexp
+exp
: NUMBER
- | DREG { $$.Get($1) }
- | dexp SUM dexp { $$ = $1 + $3 }
- | dexp SUB dexp { $$ = $1 - $3 }
- | dexp MUL dexp { $$ = $1 * $3 }
- | dexp DIV dexp { $$ = $1 / $3 }
- | SUB dexp %prec UMINUS { $$ = -$2 }
- | LBR dexp RBR { $$ = $2 }
- | error { $$ = Number(math.NaN()) }
- ;
-
-vexp
- : LBR dexp COM dexp RBR {
- if $2 > $4 {
- $$ = Interval{$4, $2}
- } else {
- $$ = Interval{$2, $4}
- }
- }
- | VREG { $$.Get($1) }
- | vexp SUM vexp { $$ = $3.vadd($1) }
- | dexp SUM vexp { $$ = $3.vadd(Interval{$1, $1}) }
- | vexp SUM dexp { $$ = Interval{$3, $3}.vadd($1) }
- | vexp SUB vexp { $$ = $3.vsub($1) }
- | dexp SUB vexp { $$ = $3.vsub(Interval{$1, $1}) }
- | vexp SUB dexp { $$ = Interval{$3, $3}.vsub($1) }
- | vexp MUL vexp { $$ = $3.vmul($1) }
- | dexp MUL vexp { $$ = $3.vmul(Interval{$1, $1}) }
- | vexp MUL dexp { $$ = Interval{$3, $3}.vmul($1) }
- | vexp DIV vexp {
- if $3.dcheck() {
- yylex.Error("divisor interval contains 0")
- }
- $$ = $3.vdiv($1)
- }
- | dexp DIV vexp {
- if $3.dcheck() {
- yylex.Error("divisor interval contains 0")
- }
- $$ = $3.vdiv(Interval{$1, $1})
- }
- | vexp DIV dexp {
- if $3 == 0 {
- yylex.Error("divisor interval contains 0")
- }
- $$ = Interval{$3, $3}.vdiv($1)
- }
- | SUB vexp %prec UMINUS { $$ = $2.vneg() }
- | LBR vexp RBR { $$ = $2 }
+ | WORD { $$ = reg[$1] }
+ | '_' { $$ = reg[last] }
+ | exp '+' exp { $$ = $1 + $3 }
+ | exp '-' exp { $$ = $1 - $3 }
+ | exp '*' exp { $$ = $1 * $3 }
+ | exp '/' exp { $$ = $1 / $3 }
+ | exp '%' exp { $$ = math.Mod($1, $3) }
+ | exp '^' exp { $$ = math.Pow($1, $3) }
+ | '-' exp %prec UMINUS { $$ = -$2 }
+ | '(' exp ')' { $$ = $2 }
+ | '|' exp '|' { $$ = math.Abs($2) }
+ | error { $$ = math.NaN() }
;
%%
-func (i Interval) String() string {
- return fmt.Sprint("(", i.lo, ",", i.hi, ")")
-}
-
-func hilo(a, b, c, d Number) (v Interval) {
- if a > b {
- v.hi = a
- v.lo = b
- } else {
- v.hi = b
- v.lo = a
- }
- if c > d {
- if c > v.hi { v.hi = c }
- if d < v.lo { v.lo = d }
- } else {
- if d > v.hi { v.hi = d }
- if c < v.lo { v.lo = c }
- }
- return
+func Parse(input string) (float64, bool) {
+ l := lex(input)
+ yyParse(l)
+ return l.result, l.ok
}
-
-func (v Interval) vmul(a Interval) Interval {
- return hilo(a.lo*v.hi, a.lo*v.lo, a.hi*v.hi, a.hi*v.lo)
-}
-
-func (v Interval) dcheck() bool {
- return v.hi >= 0 && v.lo <= 0
-}
-
-func (v Interval) vdiv(a Interval) Interval {
- return hilo(a.lo/v.hi, a.lo/v.lo, a.hi/v.hi, a.hi/v.lo)
-}
-
-func (v Interval) vadd(a Interval) Interval {
- return Interval{a.lo + v.lo, a.hi + v.hi}
-}
-
-func (v Interval) vsub(a Interval) Interval {
- return Interval{a.lo - v.lo, a.hi - v.hi}
-}
-
-func (v Interval) vneg() Interval {
- return Interval{lo: -v.hi, hi: -v.lo}
-}
-
-func (n *Number) Set(key rune) { nreg[key] = *n }
-func (n *Number) Get(key rune) { *n = nreg[key] }
-
-func (n *Interval) Set(key rune) { ireg[key] = *n }
-func (n *Interval) Get(key rune) { *n = ireg[key] }