File: calculator.go

package info (click to toggle)
golang-github-pointlander-peg 1.0.0-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, buster, forky, sid, trixie
  • size: 376 kB
  • sloc: makefile: 44
file content (102 lines) | stat: -rw-r--r-- 1,750 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"math/big"
)

type Type uint8

const (
	TypeNumber Type = iota
	TypeNegation
	TypeAdd
	TypeSubtract
	TypeMultiply
	TypeDivide
	TypeModulus
	TypeExponentiation
)

type ByteCode struct {
	T     Type
	Value *big.Int
}

func (code *ByteCode) String() string {
	switch code.T {
	case TypeNumber:
		return code.Value.String()
	case TypeAdd:
		return "+"
	case TypeNegation, TypeSubtract:
		return "-"
	case TypeMultiply:
		return "*"
	case TypeDivide:
		return "/"
	case TypeModulus:
		return "%"
	case TypeExponentiation:
		return "^"
	}
	return ""
}

type Expression struct {
	Code []ByteCode
	Top  int
}

func (e *Expression) Init(expression string) {
	e.Code = make([]ByteCode, len(expression))
}

func (e *Expression) AddOperator(operator Type) {
	code, top := e.Code, e.Top
	e.Top++
	code[top].T = operator
}

func (e *Expression) AddValue(value string) {
	code, top := e.Code, e.Top
	e.Top++
	code[top].Value = new(big.Int)
	code[top].Value.SetString(value, 10)
}

func (e *Expression) Evaluate() *big.Int {
	stack, top := make([]big.Int, len(e.Code)), 0
	for _, code := range e.Code[0:e.Top] {
		switch code.T {
		case TypeNumber:
			stack[top].Set(code.Value)
			top++
			continue
		case TypeNegation:
			a := &stack[top-1]
			a.Neg(a)
			continue
		}
		a, b := &stack[top-2], &stack[top-1]
		top--
		switch code.T {
		case TypeAdd:
			a.Add(a, b)
		case TypeSubtract:
			a.Sub(a, b)
		case TypeMultiply:
			a.Mul(a, b)
		case TypeDivide:
			a.Div(a, b)
		case TypeModulus:
			a.Mod(a, b)
		case TypeExponentiation:
			a.Exp(a, b, nil)
		}
	}
	return &stack[0]
}