Add rpn command
This commit is contained in:
parent
dd0f9cba57
commit
6c05518146
@ -2,8 +2,10 @@ package exts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dustinpianalto/disgoman"
|
||||
"strconv"
|
||||
|
||||
"djpianalto.com/goff/djpianalto.com/goff/utils"
|
||||
"github.com/dustinpianalto/disgoman"
|
||||
)
|
||||
|
||||
func interleave(ctx disgoman.Context, args []string) {
|
||||
@ -47,3 +49,11 @@ func deinterleave(ctx disgoman.Context, args []string) {
|
||||
ctx.Send(fmt.Sprintf("(%v, %v)", x, y))
|
||||
}
|
||||
}
|
||||
|
||||
func rpn(ctx disgoman.Context, args []string) {
|
||||
rpn, err := utils.GenerateRPN(args)
|
||||
if err != nil {
|
||||
ctx.Send(err.Error())
|
||||
}
|
||||
ctx.Send(rpn)
|
||||
}
|
||||
|
||||
@ -186,4 +186,13 @@ func AddCommandHandlers(h *disgoman.CommandManager) {
|
||||
RequiredPermissions: 0,
|
||||
Invoke: deinterleave,
|
||||
})
|
||||
_ = h.AddCommand(&disgoman.Command{
|
||||
Name: "rpn",
|
||||
Aliases: []string{"d"},
|
||||
Description: "Convert infix to rpn",
|
||||
OwnerOnly: false,
|
||||
Hidden: false,
|
||||
RequiredPermissions: 0,
|
||||
Invoke: rpn,
|
||||
})
|
||||
}
|
||||
|
||||
156
djpianalto.com/goff/utils/rpn.go
Normal file
156
djpianalto.com/goff/utils/rpn.go
Normal file
@ -0,0 +1,156 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Operator struct {
|
||||
Token string
|
||||
Precedence int
|
||||
Association string
|
||||
}
|
||||
|
||||
func (o Operator) HasHigherPrecedence(t Operator) bool {
|
||||
return o.Precedence < t.Precedence // lower number is higher precedence
|
||||
}
|
||||
|
||||
func (o Operator) HasEqualPrecedence(t Operator) bool {
|
||||
return o.Precedence == t.Precedence
|
||||
}
|
||||
|
||||
func (o Operator) IsLeftAssociative() bool {
|
||||
return o.Association == "left"
|
||||
}
|
||||
|
||||
var operators = map[string]Operator{
|
||||
"+": Operator{
|
||||
Token: "+",
|
||||
Precedence: 4,
|
||||
Association: "left",
|
||||
},
|
||||
"-": Operator{
|
||||
Token: "-",
|
||||
Precedence: 4,
|
||||
Association: "left",
|
||||
},
|
||||
"*": Operator{
|
||||
Token: "*",
|
||||
Precedence: 3,
|
||||
Association: "left",
|
||||
},
|
||||
"/": Operator{
|
||||
Token: "/",
|
||||
Precedence: 3,
|
||||
Association: "left",
|
||||
},
|
||||
"%": Operator{
|
||||
Token: "%",
|
||||
Precedence: 3,
|
||||
Association: "left",
|
||||
},
|
||||
"(": Operator{
|
||||
Token: "(",
|
||||
Precedence: 1,
|
||||
Association: "left",
|
||||
},
|
||||
")": Operator{
|
||||
Token: ")",
|
||||
Precedence: 1,
|
||||
Association: "left",
|
||||
},
|
||||
}
|
||||
|
||||
type Stack []Operator
|
||||
|
||||
func (s *Stack) IsEmpty() bool {
|
||||
return len(*s) == 0
|
||||
}
|
||||
|
||||
func (s *Stack) Push(op Operator) {
|
||||
*s = append(*s, op)
|
||||
}
|
||||
|
||||
func (s *Stack) Pop() (Operator, bool) {
|
||||
if s.IsEmpty() {
|
||||
return Operator{}, false
|
||||
}
|
||||
index := len(*s) - 1
|
||||
element := (*s)[index]
|
||||
*s = (*s)[:index]
|
||||
return element, true
|
||||
}
|
||||
|
||||
func (s *Stack) Top() Operator {
|
||||
if s.IsEmpty() {
|
||||
return Operator{}
|
||||
}
|
||||
return (*s)[len(*s)-1]
|
||||
}
|
||||
|
||||
func GenerateRPN(tokens []string) (string, error) {
|
||||
output := ""
|
||||
s := Stack{}
|
||||
for _, token := range tokens {
|
||||
err := processToken(token, &s, &output)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
for !s.IsEmpty() {
|
||||
ele, _ := s.Pop()
|
||||
output += " " + ele.Token
|
||||
}
|
||||
|
||||
return strings.TrimSpace(output), nil
|
||||
}
|
||||
|
||||
func processToken(t string, s *Stack, o *string) error {
|
||||
if _, err := strconv.Atoi(t); err == nil {
|
||||
*o += " " + t
|
||||
return nil
|
||||
} else if op, ok := operators[t]; ok {
|
||||
if op.Token == "(" {
|
||||
s.Push(op)
|
||||
} else if op.Token == ")" {
|
||||
if s.IsEmpty() {
|
||||
return fmt.Errorf("mismatched parentheses")
|
||||
}
|
||||
for s.Top().Token != "(" {
|
||||
if ele, ok := s.Pop(); ok {
|
||||
*o += " " + ele.Token
|
||||
} else {
|
||||
return fmt.Errorf("mismatched parentheses")
|
||||
}
|
||||
if s.IsEmpty() {
|
||||
break
|
||||
}
|
||||
}
|
||||
s.Pop() // Pop and discard the (
|
||||
} else if !s.IsEmpty() {
|
||||
for {
|
||||
if (s.Top().HasHigherPrecedence(op) ||
|
||||
(s.Top().HasEqualPrecedence(op) &&
|
||||
op.IsLeftAssociative())) &&
|
||||
s.Top().Token != "(" {
|
||||
if ele, ok := s.Pop(); ok {
|
||||
*o += " " + ele.Token
|
||||
if s.IsEmpty() {
|
||||
break
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
s.Push(op)
|
||||
} else {
|
||||
s.Push(op)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("invalid character %s", t)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user