#include <stdio.h> #include <stdlib.h> #include <string.h> #define TOK_NUMBER 1 #define TOK_VARIABLE 2 #define TOK_OPERATOR 3 #define TOK_WHITESPACE 4 #define TOK_NEWLINE 5 #define TOK_EOF 6 #define OPERATORS "+-*/^" static int toktype[256]; /* all default to 0 */ char *get_tok(void) { static char buff[128]; // TODO: remember to add length check later static int pend = -2; int initc, c; char *s = buff; c = initc = (pend >= -1 ? pend : getchar()); pend = -2; if (c != EOF) { for (;;) { if (isalpha(c) && islower(c)) c = toupper(c); *s++ = c; c = getchar(); if ((!isalpha(c) && !isdigit(c)) || (toktype[c] != toktype[initc])) break; } pend = c; } *s = '\0'; return strdup(buff); } char *op[4]; int top = -1, nest = -1; void operate(char *op) { char *s; switch (*op) { case '+': s = "ADD"; break; case '-': s = "SUB"; break; case '*': s = "MUL"; break; case '/': s = "DIV"; break; case '^': s = "EXP"; break; default: fprintf(stderr, "Bad operator %s\n", op); exit(1); } fprintf(stdout, " %s\n", s); } void operand(char *s) { if ((nest+1 > 0) && (top != nest)) {fprintf(stderr, "Missing operator before %s\n", s); exit(1);} nest += 1; fprintf(stdout, " PUSH%s%s\n", (isdigit(*s) ? " #":" "), s); } void operator(char *s) { if (top+1 != nest) { if (top < 0) { fprintf(stderr, "Missing initial operand before %s\n", s); } else { fprintf(stderr, "Missing operand between %s and %s\n", op[top], s); } exit(1); } // RULE 2: a * b + c => (a*b) + c ... do it before we push the next operand while ((top > 0) && (prec(op[top]) > prec(s))) { // stack is now just ... + a*b nest -= 1; /* pop 2 operands, push 1 */ operate(op[top--]); } // RULE 1: a + b + c => (a+b) + c ... do it before we push the next operand if ((top >= 0) && (prec(op[top]) == prec(s))) { // stack is now just a + b nest -= 1; /* pop 2 operands, push 1 */ operate(op[top--]); } op[++top] = s; } void evaluate(void) { if (nest <0 && top < 0) return; /* nothing entered */ if (nest == top) {fprintf(stderr, "Missing operand after final %s\n", op[top]); exit(1);} while (top >= 0) { operate(op[top--]); } fprintf(stdout, " PRINT\n"); nest = top = -1; } int prec(char *op) { return (strchr(OPERATORS, *op)-OPERATORS)/2; /* slightly hacky tweak for '+'='-' and '*'='/' */ } int main(int argc, char **argv) { char *tok, *s; int i; toktype[0] = TOK_EOF; toktype['\n'] = TOK_NEWLINE; toktype[' '] = TOK_WHITESPACE; toktype['\t'] = TOK_WHITESPACE; for (i = 'A'; i <= 'Z'; i++) toktype[i] = TOK_VARIABLE; for (i = '0'; i <= '9'; i++) toktype[i] = TOK_NUMBER; for (s = OPERATORS; *s != '\0'; s++) toktype[*s] = TOK_OPERATOR; for (;;) { tok = get_tok(); switch (toktype[*tok]) { case TOK_NUMBER: operand(tok); break; case TOK_VARIABLE: operand(tok); break; case TOK_OPERATOR: operator(tok); break; case TOK_WHITESPACE: continue; case TOK_NEWLINE: evaluate(); break; case TOK_EOF: evaluate(); exit(0); default: fprintf(stderr, "Bad character in input: %s\n", tok); exit(1); } } exit(0); return(0); }