104 lines
1.8 KiB
Go
104 lines
1.8 KiB
Go
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
|
|
}
|