summaryrefslogtreecommitdiff
path: root/ex4-3.c
blob: ca5739ab0d9134a170a55ef78a94b42752176873 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

#define NUMBER '0'
#define MAXOP 100
#define MAXVAL 100

int getop(char[]);

void push(double);
double pop(void);
void clear(void);
double peek(void);

// Naïve implementation of remainder operation
double frem(double f1, double f2) {
    return f1 - (f2 * (int)(f1 / f2));
}

/**
 * Reverse polish notation calculator
 */
int main(void) {
    int type;
    double op2;
    char s[MAXOP];
    while ((type = getop(s)) != EOF) {
        switch (type) {
            case NUMBER:
                push(atof(s));
                break;
            case '+':
                push(pop() + pop());
                break;
            case '*':
                push(pop() * pop());
                break;
            case '-':
                op2 = pop();
                push(pop() - op2);
                break;
            case '/':
                op2 = pop();
                if (op2 != 0.0)
                    push(pop() / op2);
                else
                    printf("error: zero division attempted!\n");
                break;
            case '%':
                op2 = pop();
                if (op2 != 0.0) 
                    push(frem(pop(), op2));
                else 
                    printf("error: zero division attempted!\n");
                break;
            case '~':
                clear();
            case '\n':
                printf("\t%.8g\n", peek());
                break;
            default:
                printf("unknown command %s\n", s);
                break;
        }
    }
    return 0;
}

int sp; // Stack position
double val[MAXVAL]; // Value stack
void push(double f) {
    if (sp < MAXVAL) {
        val[sp++] = f;
    } else {
        printf("error, stack full\n");
    }
}

double pop(void) {
    if (sp >= 0) {
        return val[--sp];
    } else {
        printf("error, empty stack\n");
        return 0.0;
    }
}

double peek(void) {
    if (sp >= 0) {
        return val[sp-1];
    } else {
        printf("error, empty stack\n");
        return 0.0;
    }   
}

void clear(void) {
    sp = 0;
}

int getch(void);
void ungetch(int);

int getop(char s[]) {
    int i,c;
    // Skip to teh first non-space or tab character
    while ((s[0] = c = getch()) == ' ' || c == '\t');
    // Then add a null for some reason?
    s[1] = '\0';
    // if it's not a part of a number, it's an operation
    if (!isdigit(c) && c != '.') 
        return c;
    // Integer part
    i = 0;
    if (isdigit(c)) 
        while (isdigit(s[++i] = c = getch()));
    // fraction part
    if (c == '.')
        while (isdigit(s[++i] = c = getch()));
    s[i] = '\0';
    if (c != EOF) 
        ungetch(c);
    return NUMBER;
}

#define BUFSIZE 100

int buf = -2;

int getch(void) {
    if (buf != -2) {
        int z = buf;
        buf = -2;
        return z;
    }
    return getchar();
}

void ungetch(int c) {
    if (buf != -2) 
        printf("ungetch: buffer full\n");
    else
        buf = c;
}