1/* vi: set sw=4 ts=4: */ 2#include <ctype.h> 3#include <stdio.h> 4#include <stdlib.h> 5#include <string.h> 6#include <unistd.h> 7#include <math.h> 8#include "busybox.h" 9 10/* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */ 11 12static double stack[100]; 13static unsigned int pointer; 14 15static void push(double a) 16{ 17 if (pointer >= (sizeof(stack) / sizeof(*stack))) 18 error_msg_and_die("stack overflow"); 19 stack[pointer++] = a; 20} 21 22static double pop() 23{ 24 if (pointer == 0) 25 error_msg_and_die("stack underflow"); 26 return stack[--pointer]; 27} 28 29static void add() 30{ 31 push(pop() + pop()); 32} 33 34static void sub() 35{ 36 double subtrahend = pop(); 37 38 push(pop() - subtrahend); 39} 40 41static void mul() 42{ 43 push(pop() * pop()); 44} 45 46static void divide() 47{ 48 double divisor = pop(); 49 50 push(pop() / divisor); 51} 52 53static void and() 54{ 55 push((unsigned int) pop() & (unsigned int) pop()); 56} 57 58static void or() 59{ 60 push((unsigned int) pop() | (unsigned int) pop()); 61} 62 63static void eor() 64{ 65 push((unsigned int) pop() ^ (unsigned int) pop()); 66} 67 68static void not() 69{ 70 push(~(unsigned int) pop()); 71} 72 73static void print() 74{ 75 printf("%g\n", pop()); 76} 77 78struct op { 79 const char *name; 80 void (*function) (); 81}; 82 83static const struct op operators[] = { 84 {"+", add}, 85 {"add", add}, 86 {"-", sub}, 87 {"sub", sub}, 88 {"*", mul}, 89 {"mul", mul}, 90 {"/", divide}, 91 {"div", divide}, 92 {"and", and}, 93 {"or", or}, 94 {"not", not}, 95 {"eor", eor}, 96 {0, 0} 97}; 98 99static void stack_machine(const char *argument) 100{ 101 char *endPointer = 0; 102 double d; 103 const struct op *o = operators; 104 105 if (argument == 0) { 106 print(); 107 return; 108 } 109 110 d = strtod(argument, &endPointer); 111 112 if (endPointer != argument) { 113 push(d); 114 return; 115 } 116 117 while (o->name != 0) { 118 if (strcmp(o->name, argument) == 0) { 119 (*(o->function)) (); 120 return; 121 } 122 o++; 123 } 124 error_msg_and_die("%s: syntax error.", argument); 125} 126 127/* return pointer to next token in buffer and set *buffer to one char 128 * past the end of the above mentioned token 129 */ 130static char *get_token(char **buffer) 131{ 132 char *start = NULL; 133 char *current = *buffer; 134 135 while (isspace(*current)) { current++; } 136 if (*current != 0) { 137 start = current; 138 while (!isspace(*current) && current != 0) { current++; } 139 *buffer = current; 140 } 141 return start; 142} 143 144/* In Perl one might say, scalar m|\s*(\S+)\s*|g */ 145static int number_of_tokens(char *buffer) 146{ 147 int i = 0; 148 char *b = buffer; 149 while (get_token(&b)) { i++; } 150 return i; 151} 152 153int dc_main(int argc, char **argv) 154{ 155 /* take stuff from stdin if no args are given */ 156 if (argc <= 1) { 157 int i, len; 158 char *line = NULL; 159 char *cursor = NULL; 160 char *token = NULL; 161 while ((line = get_line_from_file(stdin))) { 162 cursor = line; 163 len = number_of_tokens(line); 164 for (i = 0; i < len; i++) { 165 token = get_token(&cursor); 166 *cursor++ = 0; 167 stack_machine(token); 168 } 169 free(line); 170 } 171 } else { 172 if (*argv[1]=='-') 173 show_usage(); 174 while (argc >= 2) { 175 stack_machine(argv[1]); 176 argv++; 177 argc--; 178 } 179 } 180 stack_machine(0); 181 return EXIT_SUCCESS; 182} 183