Simplified calculator 2 example.

This commit is contained in:
Maurice Makaay 2019-05-28 23:51:19 +00:00
parent 11883b06ac
commit e1534f678e
3 changed files with 22 additions and 38 deletions

View File

@ -98,11 +98,11 @@ func (c *calculator) expr(p *parsekit.ParseAPI) {
var pc, a = parsekit.C, parsekit.A
if p.Handle(c.term) {
for p.On(pc.Any(a.Add, a.Subtract)).Skip() {
c.interpreter.pushOperator(p.LastMatch)
op := p.LastMatch
if !p.Handle(c.term) {
return
}
c.interpreter.eval()
c.interpreter.eval(op)
}
}
@ -116,11 +116,11 @@ func (c *calculator) term(p *parsekit.ParseAPI) {
var pc, a = parsekit.C, parsekit.A
if p.Handle(c.factor) {
for p.On(pc.Any(a.Multiply, a.Divide)).Skip() {
c.interpreter.pushOperator(p.LastMatch)
op := p.LastMatch
if !p.Handle(c.factor) {
return
}
c.interpreter.eval()
c.interpreter.eval(op)
}
}
@ -166,7 +166,6 @@ func (c *calculator) factor(p *parsekit.ParseAPI) {
type stackFrame struct {
a float64
b float64
op func(a, b float64) float64
}
type interpreter struct {
@ -175,51 +174,38 @@ type interpreter struct {
result float64
}
func (i *interpreter) push() *stackFrame {
func (i *interpreter) push() {
f := &stackFrame{}
i.stack = append(i.stack, f)
i.top = f
i.pushOperator("VAL")
return f
i.top, i.stack = f, append(i.stack, f)
}
func (i *interpreter) pop() float64 {
value := i.eval()
func (i *interpreter) pop() {
popped := i.top
i.stack = i.stack[0 : len(i.stack)-1]
if len(i.stack) > 0 {
i.top = i.stack[len(i.stack)-1]
i.pushValue(value)
i.pushValue(popped.b)
} else {
i.result = i.top.b
i.top = nil
i.result = popped.b
}
return value
}
func (i *interpreter) pushValue(value float64) {
i.top.a, i.top.b = i.top.b, value
}
func (i *interpreter) pushOperator(op string) {
func (i *interpreter) eval(op string) float64 {
value := i.top.a
switch op {
case "VAL":
i.top.op = func(a, b float64) float64 { return b }
case "+":
i.top.op = func(a, b float64) float64 { return a + b }
value += i.top.b
case "-":
i.top.op = func(a, b float64) float64 { return a - b }
value -= i.top.b
case "*":
i.top.op = func(a, b float64) float64 { return a * b }
value *= i.top.b
case "/":
i.top.op = func(a, b float64) float64 { return a / b }
default:
panic(fmt.Sprintf("Unhandled op name: %s", op))
value /= i.top.b
}
}
func (i *interpreter) eval() float64 {
value := i.top.op(i.top.a, i.top.b)
i.pushValue(value)
i.pushOperator("VAL")
i.top.b = value
return value
}

View File

@ -68,7 +68,7 @@ func (p *ParseAPI) checkForLoops() {
id := fmt.Sprintf("%s:%d", file, line)
if _, ok := p.loopCheck[id]; ok {
caller := runtime.FuncForPC(pc)
panic(fmt.Sprintf("Loop detected in parser in %s at %s, line %d", caller.Name(), file, line))
panic(fmt.Sprintf("Loop detected in parser in %s at %s", caller.Name(), id))
}
p.loopCheck[id] = true
}

View File

@ -1,7 +1,6 @@
package parsekit_test
import (
"fmt"
"testing"
"git.makaay.nl/mauricem/go-parsekit"
@ -105,7 +104,7 @@ func TestGivenLoopingParserDefinition_ParserPanics(t *testing.T) {
func() { parser.Execute("Het houdt niet op, niet vanzelf") },
"Loop detected in parser in git.makaay.nl/mauricem/go-parsekit_test." +
"(*parserWithLoop).second at /home/ubuntu/Projects/Parsekit/go-parsekit" +
"/parsehandler_test.go, line 87"})
"/parsehandler_test.go:87"})
}
// This test incorporates an actual loop bug that I dropped on myself and
@ -124,7 +123,6 @@ func TestGivenLoopingParserDefinition_ParserPanics(t *testing.T) {
func TestGivenLoopingParserDefinition2_ParserPanics(t *testing.T) {
parser := parsekit.NewParser(func(p *parsekit.ParseAPI) {
for p.On(c.Max(5, a.AnyRune)).Accept() {
fmt.Printf("Cycle: %s\n", p.BufLiteral())
p.BufClear()
}
p.Stop()
@ -133,5 +131,5 @@ func TestGivenLoopingParserDefinition2_ParserPanics(t *testing.T) {
func() { parser.Execute("This will end soon") },
"Loop detected in parser in git.makaay.nl/mauricem/go-parsekit_test." +
"TestGivenLoopingParserDefinition2_ParserPanics.func1 at " +
"/home/ubuntu/Projects/Parsekit/go-parsekit/parsehandler_test.go, line 126"})
"/home/ubuntu/Projects/Parsekit/go-parsekit/parsehandler_test.go:125"})
}