Simplified calculator 2 example.
This commit is contained in:
parent
11883b06ac
commit
e1534f678e
|
@ -98,11 +98,11 @@ func (c *calculator) expr(p *parsekit.ParseAPI) {
|
||||||
var pc, a = parsekit.C, parsekit.A
|
var pc, a = parsekit.C, parsekit.A
|
||||||
if p.Handle(c.term) {
|
if p.Handle(c.term) {
|
||||||
for p.On(pc.Any(a.Add, a.Subtract)).Skip() {
|
for p.On(pc.Any(a.Add, a.Subtract)).Skip() {
|
||||||
c.interpreter.pushOperator(p.LastMatch)
|
op := p.LastMatch
|
||||||
if !p.Handle(c.term) {
|
if !p.Handle(c.term) {
|
||||||
return
|
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
|
var pc, a = parsekit.C, parsekit.A
|
||||||
if p.Handle(c.factor) {
|
if p.Handle(c.factor) {
|
||||||
for p.On(pc.Any(a.Multiply, a.Divide)).Skip() {
|
for p.On(pc.Any(a.Multiply, a.Divide)).Skip() {
|
||||||
c.interpreter.pushOperator(p.LastMatch)
|
op := p.LastMatch
|
||||||
if !p.Handle(c.factor) {
|
if !p.Handle(c.factor) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.interpreter.eval()
|
c.interpreter.eval(op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,9 +164,8 @@ func (c *calculator) factor(p *parsekit.ParseAPI) {
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
type stackFrame struct {
|
type stackFrame struct {
|
||||||
a float64
|
a float64
|
||||||
b float64
|
b float64
|
||||||
op func(a, b float64) float64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type interpreter struct {
|
type interpreter struct {
|
||||||
|
@ -175,51 +174,38 @@ type interpreter struct {
|
||||||
result float64
|
result float64
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *interpreter) push() *stackFrame {
|
func (i *interpreter) push() {
|
||||||
f := &stackFrame{}
|
f := &stackFrame{}
|
||||||
i.stack = append(i.stack, f)
|
i.top, i.stack = f, append(i.stack, f)
|
||||||
i.top = f
|
|
||||||
i.pushOperator("VAL")
|
|
||||||
return f
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *interpreter) pop() float64 {
|
func (i *interpreter) pop() {
|
||||||
value := i.eval()
|
popped := i.top
|
||||||
i.stack = i.stack[0 : len(i.stack)-1]
|
i.stack = i.stack[0 : len(i.stack)-1]
|
||||||
if len(i.stack) > 0 {
|
if len(i.stack) > 0 {
|
||||||
i.top = i.stack[len(i.stack)-1]
|
i.top = i.stack[len(i.stack)-1]
|
||||||
i.pushValue(value)
|
i.pushValue(popped.b)
|
||||||
} else {
|
} else {
|
||||||
i.result = i.top.b
|
i.result = popped.b
|
||||||
i.top = nil
|
|
||||||
}
|
}
|
||||||
return value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *interpreter) pushValue(value float64) {
|
func (i *interpreter) pushValue(value float64) {
|
||||||
i.top.a, i.top.b = i.top.b, value
|
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 {
|
switch op {
|
||||||
case "VAL":
|
|
||||||
i.top.op = func(a, b float64) float64 { return b }
|
|
||||||
case "+":
|
case "+":
|
||||||
i.top.op = func(a, b float64) float64 { return a + b }
|
value += i.top.b
|
||||||
case "-":
|
case "-":
|
||||||
i.top.op = func(a, b float64) float64 { return a - b }
|
value -= i.top.b
|
||||||
case "*":
|
case "*":
|
||||||
i.top.op = func(a, b float64) float64 { return a * b }
|
value *= i.top.b
|
||||||
case "/":
|
case "/":
|
||||||
i.top.op = func(a, b float64) float64 { return a / b }
|
value /= i.top.b
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("Unhandled op name: %s", op))
|
|
||||||
}
|
}
|
||||||
}
|
i.top.b = value
|
||||||
|
|
||||||
func (i *interpreter) eval() float64 {
|
|
||||||
value := i.top.op(i.top.a, i.top.b)
|
|
||||||
i.pushValue(value)
|
|
||||||
i.pushOperator("VAL")
|
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ func (p *ParseAPI) checkForLoops() {
|
||||||
id := fmt.Sprintf("%s:%d", file, line)
|
id := fmt.Sprintf("%s:%d", file, line)
|
||||||
if _, ok := p.loopCheck[id]; ok {
|
if _, ok := p.loopCheck[id]; ok {
|
||||||
caller := runtime.FuncForPC(pc)
|
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
|
p.loopCheck[id] = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package parsekit_test
|
package parsekit_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.makaay.nl/mauricem/go-parsekit"
|
"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") },
|
func() { parser.Execute("Het houdt niet op, niet vanzelf") },
|
||||||
"Loop detected in parser in git.makaay.nl/mauricem/go-parsekit_test." +
|
"Loop detected in parser in git.makaay.nl/mauricem/go-parsekit_test." +
|
||||||
"(*parserWithLoop).second at /home/ubuntu/Projects/Parsekit/go-parsekit" +
|
"(*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
|
// 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) {
|
func TestGivenLoopingParserDefinition2_ParserPanics(t *testing.T) {
|
||||||
parser := parsekit.NewParser(func(p *parsekit.ParseAPI) {
|
parser := parsekit.NewParser(func(p *parsekit.ParseAPI) {
|
||||||
for p.On(c.Max(5, a.AnyRune)).Accept() {
|
for p.On(c.Max(5, a.AnyRune)).Accept() {
|
||||||
fmt.Printf("Cycle: %s\n", p.BufLiteral())
|
|
||||||
p.BufClear()
|
p.BufClear()
|
||||||
}
|
}
|
||||||
p.Stop()
|
p.Stop()
|
||||||
|
@ -133,5 +131,5 @@ func TestGivenLoopingParserDefinition2_ParserPanics(t *testing.T) {
|
||||||
func() { parser.Execute("This will end soon") },
|
func() { parser.Execute("This will end soon") },
|
||||||
"Loop detected in parser in git.makaay.nl/mauricem/go-parsekit_test." +
|
"Loop detected in parser in git.makaay.nl/mauricem/go-parsekit_test." +
|
||||||
"TestGivenLoopingParserDefinition2_ParserPanics.func1 at " +
|
"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"})
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue