diff options
author | nirav <nirav@teisuu.com> | 2021-10-17 10:41:25 +0000 |
---|---|---|
committer | nirav <nirav@teisuu.com> | 2021-10-17 10:41:25 +0000 |
commit | aa51be44817e42871218eb2a341ec894ec7a24c5 (patch) | |
tree | 794473bd3417deb19e1d8b35101db0f54d2848a0 /parser.go | |
download | dc-aa51be44817e42871218eb2a341ec894ec7a24c5.tar.gz dc-aa51be44817e42871218eb2a341ec894ec7a24c5.zip |
Initial commit
Diffstat (limited to 'parser.go')
-rw-r--r-- | parser.go | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/parser.go b/parser.go new file mode 100644 index 0000000..014624f --- /dev/null +++ b/parser.go @@ -0,0 +1,107 @@ +package main + +import ( + "fmt" + "math/big" +) + +type Op int + +const ( + OpInvalid Op = iota + OpAdd + OpSub + OpMul + OpDiv + OpExp +) + +type Expr interface { + Eval() *big.Int +} + +type NumExpr struct { + N *big.Int +} + +func (n *NumExpr) Eval() *big.Int { + return n.N +} + +type NopExpr struct { +} + +func (e *NopExpr) Eval() *big.Int { + return &big.Int{} +} + +type OpExpr struct { + Op Op + L Expr + R Expr +} + +func (o *OpExpr) Eval() *big.Int { + l := o.L.Eval() + r := o.R.Eval() + n := new(big.Int) + switch o.Op { + case OpAdd: + n.Add(l, r) + case OpSub: + n.Sub(l, r) + case OpMul: + n.Mul(l, r) + case OpDiv: + n.Div(l, r) + case OpExp: + n.Exp(l, r, nil) + } + return n +} + +func Parse(d []byte) (e Expr, err error) { + sc := newScanner(d) + t, d := sc.Scan() + switch t { + case NUM: + s := string(d) + n, ok := big.NewInt(0).SetString(s, 10) + if !ok { + return nil, fmt.Errorf("invalid number %s at %d", s, sc.Pos()) + } + l := &NumExpr{N: n} + var op Op + t, d = sc.Scan() + switch t { + case EOF: + return l, nil + case ADD: + op = OpAdd + case SUB: + op = OpSub + case MUL: + op = OpMul + case DIV: + op = OpDiv + case EXP: + op = OpExp + default: + return nil, fmt.Errorf("expected operator at %d", sc.Pos()) + } + t, d = sc.Scan() + if t != NUM { + return nil, fmt.Errorf("expected number at %d", sc.Pos()) + } + s = string(d) + n2, ok := big.NewInt(0).SetString(s, 10) + if !ok { + return nil, fmt.Errorf("invalid nummber %s at %d", s, sc.Pos()) + } + r := &NumExpr{N: n2} + return &OpExpr{Op: op, L: l, R: r}, nil + case EOF: + return &NopExpr{}, nil + } + return nil, fmt.Errorf("invalid token %s at index %d", t, sc.Pos()) +} |