diff --git a/README.md b/README.md
index 4e2b14e..f825992 100644
--- a/README.md
+++ b/README.md
@@ -136,6 +136,31 @@ sub stack of before.
Every operation which modifies the stack can be reversed by entering
the u command. There's only one level of undo and no redo.
+## Functions
+
+You can define functions anytime directly on the cli or in a file called
+`~/.rpnc`. A function has a name (which must not collide with existing
+functions and commands) and a body of commands.
+
+Example:
+
+ f res2vcc 1.22 R1 R2 + R2 / 1 + *
+
+Which calculates:
+
+ (((R1 + R2) / R2) + 1) * 1.22 = ??
+
+To use it later, just enter the variables into the stack followed by the
+function name:
+
+ 470
+ 220
+ res2vcc
+
+You can also put the function definition in the config file
+`~/.rpnc`. Empty lines and lines beginning with `#` will be ignored.
+
+
## Using STDIN via a PIPE
If the commandline includes any operator, commands will be read from
@@ -150,18 +175,22 @@ Examples:
Both commands will print 4 to STDOUT.
+
## Complete list of all supported commands:
-* c clear stack
+### Stack Management
+
* s show the stack
-* d toggle debugging (current setting: 0)
-* r reverse the stack
-* R rotate the stack
-* ( enter collect mode
-* ) leave collect mode
-* u undo last operation
-* q finish (C-d works as well)
-* ? print help
+* ss show the whole stack
+* sc clear stack
+* scx clear last stack element
+* sr reverse the stack
+* srt rotate the stack
+
+## Configuration
+
+* td toggle debugging (-d)
+* ts toggle display of the stack (-n)
## Supported mathematical operators:
@@ -171,10 +200,47 @@ Both commands will print 4 to STDOUT.
* * multiply
* ^ expotentiate
* % percent
+* %+ add percent
+* %- substract percent
+* %d percentual difference
* & bitwise AND
* | bitwise OR
* x bitwise XOR
-* V pull root (2nd if stack==1)
+* m median
+* a average
+* v pull root (2nd if stack==1)
+* ( enter collect mode
+* ) leave collect mode
+
+## Register Commands
+
+* r put element into register
+* rc clear register
+* rcx clear last register element
+
+## Various Commands
+
+* u undo last operation
+* q finish (C-d works as well)
+* h show history of past operations
+* ? print help
+
+## Converters
+
+* tl gallons to liters
+* tk miles to kilometers
+* tm yards to meters
+* tc inches to centimeters
+* tkb bytes to kilobytes
+* tmb bytes to megabytes
+* tgb bytes to gigabytes
+* ttb bytes to terabytes
+
+## Function Comands
+
+* f NAME CODE define a functions (see ab above)
+* fs show list of defined functions
+
## Copyleft
diff --git a/rpnc b/rpnc
index 3424361..e56ceb3 100755
--- a/rpnc
+++ b/rpnc
@@ -106,6 +106,7 @@ my %func = (
return 0;
}
},
+
'%d' => sub {
# percentual difference
if (scalar @_ == 2) {
@@ -118,6 +119,7 @@ my %func = (
return 0;
}
},
+
'%+' => sub {
# Y + (X $ of Y)
if (scalar @_ == 2) {
@@ -130,6 +132,7 @@ my %func = (
return 0;
}
},
+
'%-' => sub {
# Y - (X $ of Y)
if (scalar @_ == 2) {
@@ -142,6 +145,7 @@ my %func = (
return 0;
}
},
+
'v' => sub {
if (scalar @_ == 2) {
my ($a, $b) = @_;
@@ -152,11 +156,13 @@ my %func = (
return "$a ** (1 / 2)";
}
},
+
'pr' => sub {
# parallel resistance, maybe add ~/.rpncrc support
# where to add such custom functions...
return "1 / (" . join(' + ', map { "1 / $_"} @_) . ")";
},
+
'm' => sub {
# median
if (scalar @_ >= 2) {
@@ -175,10 +181,12 @@ my %func = (
undo(); return 0;
}
},
+
'a' => sub {
# average
return "(" . join(' + ', @_) . ") / " . scalar @_;
},
+
# converters:
# gallons to liters
'tl' => sub { return $_[-1] * 3.785 },
@@ -193,6 +201,9 @@ my %func = (
'tmb' => sub { return $_[-1] / 1000 / 1000},
'tgb' => sub { return $_[-1] / 1000 / 1000 / 1000 },
'ttb' => sub { return $_[-1] / 1000 / 1000 / 1000 / 1000 },
+
+ # alias
+ 'x' => sub { return join "^", @_ },
);
# math constants, always upper case letters, usable via eval{}
@@ -540,6 +551,21 @@ sub defun {
my $code = shift;
my ($op, $name, @tokens) = split /\s\s*/, $code;
+ if ($name !~ /^[a-zA-Z0-9_]+$/) {
+ print "invalid function name (a-z0-9_)!\n";
+ return;
+ }
+
+ if (grep {$name eq $_} keys %commands) {
+ print "reserved function name (command)!\n";
+ return;
+ }
+
+ if (grep {$name eq $_} keys %func) {
+ print "reserved function name (function)!\n";
+ return;
+ }
+
$custom{$name} = "@tokens";
$func{$name} = sub {
@@ -549,13 +575,14 @@ sub defun {
# replace N1..NN with actual args
my @body;
foreach my $item (@tokens) {
- if ($item =~ /^N(\d+)$/) {
- my $i = $1;
+ if ($item =~ /^([A-Z])(\d+)$/) {
+ my $letter = $1;
+ my $i = $2;
if ($i <= $max) {
push @body, $args[$i-1];
}
else {
- print "undefined variable N$i!\n";
+ print "undefined variable ${letter}${i}!\n";
push @body, 0;
}
}