/** * rpn - a simple reverse-polish-notation calculator. * Based on code from Section 4.3 of Kernighan and Ritchie's "The * C Programming Language", 2nd edition. */ // +---------+-------------------------------------------------------- // | Headers | // +---------+ #include // For printf #include // For atof #include // For isdigit and isspace #include "myio.h" // For getch and ungetch #include "dstack.h" // For dpush and dpop // +-----------+------------------------------------------------------ // | Constants | // +-----------+ #define MAXOP 128 // One more than the maximum number of characters // in the textual representation of the largest // number. #define NUMBER '0' // A special value returned by get_token to indicate // that it found a number. // +---------+-------------------------------------------------------- // | Helpers | // +---------+ /** * get_token: Get the next 'token' from the input and store its * string representation in s. If the next token is a number, * returns NUMBER. If the next token is a single-character * operator, returns that operator. (Essentially assumes that * all single-character things that aren't numbers are operators.) */ int get_token (char s[]) { int i; // Index into s. int c; // Next character read. int d; // Another character to read // Skip over opening spaces while (isspace(c = getch ())) ; // Store into the string s[0] = c; s[1] = '\0'; // Non-numbers: We're done. if ( (! isdigit (c)) && (c != '.') && (c != '-') ) return c; // Missing issues: ., ungetting // Negative signs: Might be operators, might start a number. if (c == '-') { d = getch (); if (isdigit (d)) { // Must be a negative number ungetch (d); } // if isdigit (d) else if (d == '.') { // Check that the thing after it is a number. d = getch (); if (isdigit (d)) { // Ooh ... -.num ungetch (d); ungetch ('.'); } else { // It's an operator ungetch (d); ungetch ('.'); return c; } } else // neither digit nor period { // It's an operator, so return it ungetch (d); return c; } // if d is not a digit } // if (c == '-') // Everything else is a number, so we'll need to gather the digits. i = 1; // Collect the digits before the decimal point. while (isdigit (c = getch ())) s[i++] = c; // Handle optional fractional part if (c == '.') { s[i++] = c; while (isdigit (c = getch ())) s[i++] = c; } // if there's a decimal point // We're done, so mark the end of the string s[i] = '\0'; // We may have read an extra character, so "unread" it. if (c != EOF) ungetch (c); // In case you've forgotten, we're in the "it's a number" part. // Notify the caller that it's a number. return NUMBER; } // get_token // +------+----------------------------------------------------------- // | Main | // +------+ int main () { int type; // The type of the next "thing" read. double left; // The left operand for the next operation. double right; // The right operand for the next operation. char s[MAXOP]; // A string in which we store things read. ungetch ('p'); ungetch ('+'); ungetch ('4'); ungetch (' '); ungetch ('3'); // Repeatedly read tokens until you hit the end of the input. while ((type = get_token (s)) != EOF) { switch (type) { // Numbers get pushed on the stack case NUMBER: dpush (atof (s)); break; // Binary operators: Pop two values, apply the operator, and // push the result. case '+': case '-': case '*': case '/': right = dpop (); left = dpop (); switch (type) { case '+': dpush (left + right); break; case '-': dpush (left - right); break; case '*': dpush (left * right); break; case '/': dpush (left / right); break; } // inner switch break; // Print the value at the op of the stack. case 'p': left = dpop (); dpush (left); printf ("\t%.8g\n", left); break; // Square the top thing on the stack (mostly so that I can // make sure that pow compiles correctly. case 's': dpush (pow (dpop(), 2.0)); break; // Everything else is an unknown command. default: printf ("error: unknown command %s\n", s); break; } // switch } // while // We're done. return 0; } // main