-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcalc.c
144 lines (122 loc) · 2.35 KB
/
calc.c
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
#include "calc.h"
#include <ctype.h>
#include <stdio.h> /* TODO */
#define FLAG_APPEND 0x1
#define FLAG_ERR 0x2
#define FLAG_PENDING_EQ 0x8
#define FLAG_PREV_EQ 0x10
int copy_x (struct calc *c);
int eq (struct calc *c);
int is_operation (char c);
void swap_xy (struct calc *c);
int is_flag_on (struct calc *c, int flag);
int set_flag (struct calc *c, int flag, int on);
void calc_init (struct calc *c)
{
c->x = c->y = 0;
c->op = '+';
c->flags = FLAG_APPEND;
}
int
calc_process_line (struct calc *calc, char *line)
{
char c;
int res;
while ((c = *line++) != '\0')
res = calc_process_cmd (calc, c);
return res;
}
int
calc_process_cmd (struct calc *c, char cmd)
{
if (is_flag_on (c, FLAG_ERR))
return 0;
if (isdigit (cmd))
{
if (!set_flag (c, FLAG_APPEND, 1))
{
c->x = cmd - '0';
set_flag (c, FLAG_PENDING_EQ, 1);
}
else
c->x = c->x * 10 + (cmd - '0');
}
else if (is_operation (cmd))
{
if (is_flag_on (c, FLAG_PENDING_EQ))
eq (c);
c->y = c->x;
c->op = cmd;
set_flag (c, FLAG_APPEND, 0);
set_flag (c, FLAG_PREV_EQ, 0);
}
else if (cmd == '=')
{
eq (c);
set_flag (c, FLAG_APPEND, 0);
}
/* printf ("cmd=%c, x=%d, y=%d\n", cmd, c->x, c->y); */
return c->x;
}
int
copy_x (struct calc *c)
{
c->tmp = c->y;
c->y = c->x;
return c->tmp;
}
int
eq (struct calc *c)
{
if (c->op == '*')
c->x *= c->y;
else if (c->op == '+')
c->x += !set_flag (c, FLAG_PREV_EQ, 1) ? copy_x (c) : c->y;
else if (c->op == '-')
{
if (!set_flag (c, FLAG_PREV_EQ, 1))
swap_xy (c);
c->x -= c->y;
}
else if (c->op == '/')
{
if (!set_flag (c, FLAG_PREV_EQ, 1))
swap_xy (c);
if (c->y == 0)
set_flag (c, FLAG_ERR, 1);
else
c->x /= c->y;
}
set_flag (c, FLAG_PENDING_EQ, 0);
return c->x;
}
int
is_operation (char c)
{
return c == '*' || c == '+' || c == '-' || c == '/';
}
void
swap_xy (struct calc *c)
{
c->tmp = c->x;
c->x = c->y;
c->y = c->tmp;
}
/*********/
/* Flags */
/*********/
int
is_flag_on (struct calc *c, int flag)
{
return !!(c->flags & flag);
}
int
set_flag (struct calc *c, int flag, int on)
{
int prev = is_flag_on (c, flag);
if (on)
c->flags |= flag;
else
c->flags &= ~flag;
return prev;
}