diff --git a/calc.go b/calc.go index b32cc9f..398a3ab 100644 --- a/calc.go +++ b/calc.go @@ -62,6 +62,8 @@ const Help string = ` Operators: basic operators: + - x * / ^ (* is an alias of x) +Bitwise operators: and or xor < (left shift) > (right shift) + Percent functions: % percent %- substract percent @@ -235,6 +237,15 @@ func (c *Calc) Eval(line string) { c.stack.Backup() c.stack.Push(num) } else { + // try hex + var i int + _, err := fmt.Sscanf(item, "0x%x", &i) + if err == nil { + c.stack.Backup() + c.stack.Push(float64(i)) + continue + } + if contains(c.Constants, item) { // put the constant onto the stack c.stack.Backup() diff --git a/calc_test.go b/calc_test.go index a5e0958..dd38780 100644 --- a/calc_test.go +++ b/calc_test.go @@ -241,6 +241,45 @@ func TestCalc(t *testing.T) { cmd: `4 4 + undo *`, exp: 16, }, + + // bit tests + { + name: "bit and", + cmd: `1 3 and`, + exp: 1, + }, + { + name: "bit or", + cmd: `1 3 or`, + exp: 3, + }, + { + name: "bit xor", + cmd: `1 3 xor`, + exp: 2, + }, + + // converters + { + name: "inch-to-cm", + cmd: `111 inch-to-cm`, + exp: 281.94, + }, + { + name: "gallons-to-liters", + cmd: `111 gallons-to-liters`, + exp: 420.135, + }, + { + name: "meters-to-yards", + cmd: `111 meters-to-yards`, + exp: 1.2139107611548556, + }, + { + name: "miles-to-kilometers", + cmd: `111 miles-to-kilometers`, + exp: 178.599, + }, } for _, tt := range tests { diff --git a/command.go b/command.go index 69328c5..d3a82d0 100644 --- a/command.go +++ b/command.go @@ -117,6 +117,15 @@ func (c *Calc) SetCommands() { } }, ), + + "hex": NewCommand( + "show last stack item in hex form (converted to int)", + func(c *Calc) { + if c.stack.Len() > 0 { + fmt.Printf("0x%x\n", int(c.stack.Last()[0])) + } + }, + ), } c.StackCommands = Commands{ diff --git a/funcs.go b/funcs.go index 0b23e0d..0033113 100644 --- a/funcs.go +++ b/funcs.go @@ -387,6 +387,85 @@ func DefineFunctions() Funcalls { return NewR(math.Hypot(arg[0], arg[1]), nil) }, 2), + + // converters of all kinds + "cm-to-inch": NewFuncall( + func(arg Numbers) R { + return NewR(arg[0]/2.54, nil) + }, + 1), + + "inch-to-cm": NewFuncall( + func(arg Numbers) R { + return NewR(arg[0]*2.54, nil) + }, + 1), + + "gallons-to-liters": NewFuncall( + func(arg Numbers) R { + return NewR(arg[0]*3.785, nil) + }, + 1), + + "liters-to-gallons": NewFuncall( + func(arg Numbers) R { + return NewR(arg[0]/3.785, nil) + }, + 1), + + "yards-to-meters": NewFuncall( + func(arg Numbers) R { + return NewR(arg[0]*91.44, nil) + }, + 1), + + "meters-to-yards": NewFuncall( + func(arg Numbers) R { + return NewR(arg[0]/91.44, nil) + }, + 1), + + "miles-to-kilometers": NewFuncall( + func(arg Numbers) R { + return NewR(arg[0]*1.609, nil) + }, + 1), + + "kilometers-to-miles": NewFuncall( + func(arg Numbers) R { + return NewR(arg[0]/1.609, nil) + }, + 1), + + "or": NewFuncall( + func(arg Numbers) R { + return NewR(float64(int(arg[0])|int(arg[1])), nil) + }, + 2), + + "and": NewFuncall( + func(arg Numbers) R { + return NewR(float64(int(arg[0])&int(arg[1])), nil) + }, + 2), + + "xor": NewFuncall( + func(arg Numbers) R { + return NewR(float64(int(arg[0])^int(arg[1])), nil) + }, + 2), + + "<": NewFuncall( + func(arg Numbers) R { + return NewR(float64(int(arg[0])<": NewFuncall( + func(arg Numbers) R { + return NewR(float64(int(arg[0])>>int(arg[1])), nil) + }, + 2), } // aliases diff --git a/main.go b/main.go index 1f5c28a..b549427 100644 --- a/main.go +++ b/main.go @@ -30,7 +30,7 @@ import ( lua "github.com/yuin/gopher-lua" ) -const VERSION string = "2.0.9" +const VERSION string = "2.0.10" const Usage string = `This is rpn, a reverse polish notation calculator cli. diff --git a/rpn.go b/rpn.go index 937f0f9..ed91a5e 100644 --- a/rpn.go +++ b/rpn.go @@ -105,6 +105,9 @@ DESCRIPTION If the first parameter to rpn is a math operator or function, batch mode is enabled automatically, see last example. + You can enter integers, floating point numbers (positive or negative) or + hex numbers (prefixed with 0x). + STACK MANIPULATION There are lots of stack manipulation commands provided. The most important one is undo which goes back to the stack before the last math diff --git a/rpn.pod b/rpn.pod index 79a5ffd..aae8858 100644 --- a/rpn.pod +++ b/rpn.pod @@ -109,6 +109,9 @@ Example of batch mode usage: If the first parameter to rpn is a math operator or function, batch mode is enabled automatically, see last example. +You can enter integers, floating point numbers (positive or negative) +or hex numbers (prefixed with 0x). + =head2 STACK MANIPULATION There are lots of stack manipulation commands provided. The most @@ -136,6 +139,14 @@ Basic operators: x multiply (alias: *) ^ power +Bitwise operators: + + and bitwise and + or bitwise or + xor bitwise xor + < left shift + > right shift + Percent functions: % percent @@ -157,19 +168,40 @@ Math functions: log10 log1p log2 logb pow round roundtoeven sin sinh tan tanh trunc y0 y1 copysign dim hypot -Commands: +Conversion functions: + + cm-to-inch + inch-to-cm + gallons-to-liters + liters-to-gallons + yards-to-meters + meters-to-yards + miles-to-kilometers + kilometers-to-miles + +Configuration Commands: [no]batch toggle batch mode (nobatch turns it off) [no]debug toggle debug output (nodebug turns it off) [no]showstack show the last 5 items of the stack (noshowtack turns it off) + +Show commands: dump display the stack contents + hex show last stack item in hex form (converted to int) + history display calculation history + vars show list of variables + +Stack manipulation commands: clear clear the whole stack shift remove the last element of the stack reverse reverse the stack elements swap exchange the last two stack elements dup duplicate last stack item - history display calculation history + undo undo last operation + +Other commands: help|? show this message + manual show manual quit|exit|c-d|c-c exit program