aboutsummaryrefslogtreecommitdiff
path: root/infixrpn.go
diff options
context:
space:
mode:
authorAlexander Kiryukhin <i@neonxp.dev>2022-07-01 02:16:07 +0300
committerAlexander Kiryukhin <i@neonxp.dev>2022-07-01 02:16:07 +0300
commitcc4c01c69c238c92602b393ed87575ba5edad352 (patch)
tree12416835a04c98dba8450d6e799754fb32c7ca0f /infixrpn.go
first commit
Diffstat (limited to 'infixrpn.go')
-rw-r--r--infixrpn.go104
1 files changed, 104 insertions, 0 deletions
diff --git a/infixrpn.go b/infixrpn.go
new file mode 100644
index 0000000..18dde39
--- /dev/null
+++ b/infixrpn.go
@@ -0,0 +1,104 @@
+package expression
+
+import (
+ "fmt"
+ "go/token"
+)
+
+func (e *Evaluator) ToPRN(in <-chan Token) chan Token {
+ out := make(chan Token)
+ stack := &Stack{}
+
+ go func() {
+ defer func() {
+ for !stack.Empty() {
+ tok := stack.Pop()
+ if tok.LP() {
+ out <- Token{
+ Token: token.ILLEGAL,
+ Literal: "no closing parenthesis",
+ Pos: tok.Pos,
+ }
+ } else {
+ out <- tok
+ }
+ }
+ close(out)
+ }()
+ for tok := range in {
+ switch {
+ case tok.Token == token.ILLEGAL:
+ return
+ case tok.IsNumber():
+ out <- tok
+ case tok.IsFunc():
+ stack.Push(tok)
+ case tok.IsSeparator():
+ for {
+ if stack.Empty() {
+ out <- Token{
+ Token: token.ILLEGAL,
+ Literal: "no opening parenthesis",
+ Pos: tok.Pos,
+ }
+ return
+ }
+ if stack.Head().LP() {
+ break
+ }
+ out <- tok
+ }
+ case tok.IsOperator():
+ op1 := e.operators[tok.Token]
+ for {
+ if stack.Empty() {
+ break
+ }
+ if stack.Head().IsOperator() {
+ op2, hasOp := e.operators[stack.Head().Token]
+ if !hasOp {
+ out <- Token{
+ Token: token.ILLEGAL,
+ Literal: fmt.Sprintf("unknown operator: %s", stack.Head().Literal),
+ Pos: tok.Pos,
+ }
+ return
+ }
+ if op2.priority > op1.priority {
+ out <- stack.Pop()
+ continue
+ } else {
+ break
+ }
+ } else {
+ break
+ }
+ }
+ stack.Push(tok)
+ case tok.LP():
+ stack.Push(tok)
+ case tok.RP():
+ for {
+ if stack.Empty() {
+ out <- Token{
+ Token: token.ILLEGAL,
+ Literal: "no opening parenthesis",
+ Pos: tok.Pos,
+ }
+ return
+ }
+ if stack.Head().LP() {
+ break
+ }
+ out <- tok
+ }
+ stack.Pop()
+ if stack.Head().IsFunc() {
+ out <- stack.Pop()
+ }
+ }
+ }
+ }()
+
+ return out
+}