diff --git a/README.md b/README.md index a60f2d4..9f736a9 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,10 @@ This is probably the mode you'll want to use. It's like the `python` shell or `i -15 > 3pi^2 29.608813203268074 +> @+1 +30.608813203268074 +> @@@*2 +-30 > ln(-1) NaN ``` @@ -46,6 +50,9 @@ calc supports all the standard stuff, and I'm definitely adding more later (also ##### Constants `e`, `pi`, `π` +##### History +Previous results can be accessed with the `@` symbol. A single `@` returns the result of the last computation, while multiple `@` gets the nth last result, where n is the number of `@`s used (for example, `@@` returns the second-last result, `@@@@@` returns the fifth-last result). + ### Why not use ...? - Google - Doesn't work without an internet connection diff --git a/compute/compute.go b/compute/compute.go index 891a882..c04126b 100644 --- a/compute/compute.go +++ b/compute/compute.go @@ -14,19 +14,33 @@ import ( "github.com/alfredxing/calc/operators/functions" ) +var resHistory = []float64{} + func Evaluate(in string) (float64, error) { floats := NewFloatStack() ops := NewStringStack() s := initScanner(in) var prev token.Token = token.ILLEGAL + var back int = -1 ScanLoop: for { _, tok, lit := s.Scan() + + if lit != "@" && back > -1 { + floats.Push(getHistory(back)) + if prev == token.RPAREN || constants.IsConstant(prev.String()) { + evalUnprecedenced("*", ops, floats) + } + back = -1 + } + switch { case tok == token.EOF: break ScanLoop + case lit == "@": + back += 1 case constants.IsConstant(lit): floats.Push(constants.GetValue(lit)) if prev == token.RPAREN || isOperand(prev) { @@ -99,6 +113,7 @@ ScanLoop: if err != nil { return 0, errors.New("Expression could not be parsed!") } + pushHistory(res) return res, nil } @@ -169,6 +184,14 @@ func parseOperator(lit string) *operators.Operator { return operators.FindOperatorFromString(lit) } +func getHistory(back int) float64 { + return resHistory[back] +} + +func pushHistory(res float64) { + resHistory = append([]float64{res}, resHistory...) +} + func initScanner(in string) scanner.Scanner { var s scanner.Scanner src := []byte(in)