diff options
author | Alexander Kiryukhin <i@neonxp.dev> | 2022-07-01 02:16:07 +0300 |
---|---|---|
committer | Alexander Kiryukhin <i@neonxp.dev> | 2022-07-01 02:16:07 +0300 |
commit | cc4c01c69c238c92602b393ed87575ba5edad352 (patch) | |
tree | 12416835a04c98dba8450d6e799754fb32c7ca0f /infixrpn.go |
first commit
Diffstat (limited to 'infixrpn.go')
-rw-r--r-- | infixrpn.go | 104 |
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 +} |