shithub: rpn

Download patch

ref: 0f675d0b71518d0acdc49dd9b60d937566446140
parent: d398196a5516713c0821925cc6b088ed6542c67b
author: Scott Flowers <flowerss@cranky.ca>
date: Wed Oct 22 15:04:05 EDT 2025

basic functionality working

--- a/README
+++ b/README
@@ -1,0 +1,17 @@
+This is an rpn calculator with basic trigonometric functions. It runs in the terminal, which acts like a ticker tape of the state of the calculations througout the session.
+
+There is a four position stack as in HP RPN calculators, labeled x, y, z, t from bottom to top. Trigonometric functions act on x, and algebraic functions act on y and x. It should be familiar to users of RPN calculators.
+
+Entering pi loads the constant pi into x.
+
+There are also exponentiation and logarithmic functions.
+
+Enter r to roll, which drops the stack and puts x into t. 
+
+Enter d to drop, which drops the bottom value off the stack and duplicates t into z.
+
+Enter x to swap x and y on the stack.
+
+Hitting enter will re-enter the last x value.
+
+To exit, enter q, to clear the stack to all zeros, enter cls.
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,10 @@
+</$objtype/mkfile
+
+rpn: rpn.$O
+	$LD -o rpn rpn.$O
+
+rpn.$O: rpn.c
+	$CC $CFLAGS rpn.c
+
+clean:
+	rm *.[67] rpn
--- /dev/null
+++ b/rpn.c
@@ -1,0 +1,204 @@
+#include <u.h>
+#include <libc.h>
+
+#define STACKSIZE 4
+
+double stack[STACKSIZE];
+int sp = 0;
+char *stacklabel = "tzyx";
+void push(double val) {
+    if(sp < STACKSIZE)
+        stack[sp++] = val;
+    else {
+        memmove(stack, stack + 1, (STACKSIZE - 1) * sizeof(double));
+        stack[STACKSIZE - 1] = val;
+    }
+}
+
+void initstack(void) {
+	int i;
+	for(i=0; i<STACKSIZE; i++)
+		push(0);
+}
+
+double pop(void) {
+/*    if(sp == 0){
+        print("stack underflow\n");
+        return 0;
+    } */
+	double val = stack[3];
+	double top = stack[0];
+	memmove(stack + 1, stack, (STACKSIZE - 1) * sizeof(double));
+	stack[0] = top;
+    return val;
+}
+
+void showstack(void) {
+    int i;
+    print("stack:\n");
+    for(i = 0; i < sp; i++)
+        print("%c: %g\n", stacklabel[(4-sp)+i], stack[i]);
+}
+
+void swap(void) {
+    if(sp < 2){
+        print("not enough values to swap\n");
+        return;
+    }
+    double tmp = stack[sp - 1];
+    stack[sp - 1] = stack[sp - 2];
+    stack[sp - 2] = tmp;
+}
+
+void drop(void) {
+	pop();
+}
+
+void roll(void) {
+	double tmp = stack[3];
+	pop();
+	stack[0] = tmp;
+}
+
+void clear(void) {
+    push(0);
+    push(0);
+    push(0);
+    push(0);
+}
+
+void help(void) {
+    print("Enter numbers or + - * /, 'q' to quit\n");
+	print("x swaps bottom of stack\n");
+	print("d drops bottom of stack\n");
+	print("r rolls stack\n");
+	print("cls clears stack\n");
+	print("trig functions are in degrees\n");
+	print("pi enters the value of pi\n");
+	print("s, S are sin / asin\n");
+	print("c, C are cos / acos\n");
+	print("t, T are tan / atan\n");
+	print("yx raises y to the power of x\n");
+}
+
+void main(void) {
+    char buf[128];
+    int n;
+    double x;
+
+    print("RPN calculator\n");
+	initstack();
+	showstack();
+    for(;;) {
+        print("> ");
+        n = read(0, buf, sizeof(buf));
+        if(n <= 0)
+            break;
+
+        // Trim newline and null-terminate
+        if(buf[n-1] == '\n')
+            buf[n-1] = 0;
+        else
+            buf[n] = 0;
+			
+        if((strcmp(buf, "exit") == 0) || (strcmp(buf, "q") == 0))
+            break;
+
+		if((strcmp(buf, "") == 0) && (sp > 0)) {
+			double a = pop();
+			push(a);
+			push(a);
+		} else if(strcmp(buf, "+") == 0)
+            push(pop() + pop());
+		else if(strcmp(buf, "-") == 0) {
+	   		double b = pop();
+	  	 	double a = pop();
+	    	push(a - b);
+		}
+        else if(strcmp(buf, "*") == 0)
+            push(pop() * pop());
+        else if(strcmp(buf, "/") == 0) {
+            double b = pop();
+            double a = pop();
+            if(b == 0)
+                print("division by zero\n");
+            else
+                push(a / b);
+        } else if(strcmp(buf, "s") ==0) {
+			if(sp < 1) {
+				print("stack underflow\n");
+			} else {
+				float deg = pop();
+				float rad = deg * (PI / 180.0);
+				push(sin(rad));
+			}
+		} else if(strcmp(buf, "S") ==0) {
+			if(sp < 1) {
+				print("stack underflow\n");
+			} else {
+				float val = pop();
+				float rad = asin(val);
+				float deg = rad / (PI / 180.0);
+				push(deg);
+			}
+		} else if(strcmp(buf, "c") ==0) {
+			if(sp < 1) {
+				print("stack underflow\n");
+			} else {
+				float deg = pop();
+				float rad = deg * (PI / 180.0);
+				push(cos(rad));
+			}
+		} else if(strcmp(buf, "C") ==0) {
+			if(sp < 1) {
+				print("stack underflow\n");
+			} else {
+				float val = pop();
+				float rad = acos(val);
+				float deg = rad / (PI / 180.0);
+				push(deg);
+			}
+		} else if(strcmp(buf, "t") ==0) {
+			if(sp < 1) {
+				print("stack underflow\n");
+			} else {
+				float deg = pop();
+				float rad = deg * (PI / 180.0);
+				push(tan(rad));
+			}
+		} else if(strcmp(buf, "T") ==0) {
+			if(sp < 1) {
+				print("stack underflow\n");
+			} else {
+				float val = pop();
+				float rad = atan(val);
+				float deg = rad / (PI / 180.0);
+				push(deg);
+			}
+		} else if(strcmp(buf, "pi") == 0)
+			push (PI);
+		else if(strcmp(buf, "yx") == 0) {
+	   		double b = pop();
+	  	 	double a = pop();
+	    	push(pow(a, b));
+		}
+
+
+		else if(strcmp(buf, "x") == 0)
+   			swap();
+		else if(strcmp(buf, "d") == 0)
+   			drop();
+		else if(strcmp(buf, "r") == 0)
+			roll();
+		else if((strcmp(buf, "cls") == 0) || (strcmp(buf, "clear") == 0))
+			clear();
+		else if(strcmp(buf, "help") == 0)
+			help();
+ 		else {
+            x = atof(buf);
+            push(x);
+        }
+        showstack();
+    }
+    exits(nil);
+}
--