/* As much of a calculator as I could * write in 20 minutes on my cellphone. * Evaluates postfix integer arithmetic. * Example, print((3 + 4) * (5 - 6)): * * ./postfix 3 4 + 5 6 - . , * * Some limitations/bugs: * - No negative numbers * - No decimals/fractions * - Uses . for multiplication (* is * inconvenient in the Unix shell) * - Only prints out numbers when * explicitly requested with , * - Ignores invalid input instead * of barfing * - No vectors * - No macros * - Fails to detect stack underflow * and overflow * - has an unused variable y and a * copy of argv in s (intended for * macros) * - I think C99 or something added * switch case range values? No, * '0'...'9' is a GCC extension still: * https://gcc.gnu.org/onlinedocs/gcc/Case-Ranges.html * * On looking at the generated * assembly, I have additional * regrets: * - making sp a global prevents GCC * from allocating it to a * register * - using int rather than size_t or * long generates additional * instructions for sign extension * - relying on GCC’s optimization * of the switch() makes the inner * interpreter loop 14 * instructions long, which is * large; a table of &&labels * would be significantly better */ #include #include void say(int n) { printf("• %d\n", n); } int stack[10]; int sp; #define IF break; case #define push(x) stack[sp++] = (x) #define pop(x) stack[--sp] int main(int argc, char **argv) { char **s = argv; int tos = 0, y; while (--argc) { switch(**++s) { IF '+': tos += pop(); IF '.': tos *= pop(); IF '/': tos = pop() / tos; IF '-': tos = pop() - tos; IF ',': say(tos); tos = pop(); IF '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': push(tos); tos = atoi(*s); } } return 0; }