1#include <stdio.h>
2#include <semaphore.h>
3#include <pthread.h>
4#include <unistd.h>
5
6#include <sys/queue.h>
7
8#include "env.h"
9#include "scanner.h"
10#include "parser.h"
11#include "eval.h"
12
13evalerr eval(env *e, statement **s);
14
15evalerr
16evalop(binop op, int arg1, int arg2, int *dest)
17{
18 switch (op) {
19 case OP_PLUS:
20 if (__builtin_sadd_overflow(arg1, arg2, dest))
21 return ERR_PRECISION;
22 break;
23 case OP_MINUS:
24 if (__builtin_ssub_overflow(arg1, arg2, dest))
25 return ERR_PRECISION;
26 break;
27 case OP_MULTI:
28 if (__builtin_smul_overflow(arg1, arg2, dest))
29 return ERR_PRECISION;
30 break;
31 case OP_DIVIDE:
32 if (arg2 == 0)
33 return ERR_DIVBYZERO;
34
35 *dest = arg1 / arg2;
36 break;
37 }
38
39 return EVAL_OK;
40}
41
42evalerr
43evaluate(env *vars, expr *exp, int *dest)
44{
45 evalerr ret;
46 int ee1, ee2;
47 expr *exp1, *exp2;
48
49 switch (exp->type) {
50 case EXP_LIT:
51 *dest = exp->d.literal.num;
52 break;
53 case EXP_VAR:
54 if (getval(vars, exp->d.variable.var, dest))
55 return ERR_UNDEFVAR;
56 else
57 break;
58 case EXP_BIN:
59 exp1 = exp->d.operation.expr1;
60 exp2 = exp->d.operation.expr2;
61
62 if ((ret = evaluate(vars, exp1, &ee1)) != EVAL_OK ||
63 (ret = evaluate(vars, exp2, &ee2)) != EVAL_OK)
64 return ret;
65
66 if ((ret = evalop(exp->d.operation.op, ee1, ee2, dest))
67 != EVAL_OK)
68 return ret;
69
70 break;
71 }
72
73 return EVAL_OK;
74}
75
76evalerr
77execdefine(env *vars, statement *stmt)
78{
79 evalerr ret;
80 int value;
81
82 if ((ret = evaluate(vars, stmt->d.define.exp, &value))
83 != EVAL_OK)
84 return ret;
85
86 if (setval(vars, stmt->d.define.var, value))
87 return ERR_VARDEFINED;
88
89 return EVAL_OK;
90}
91
92evalerr
93execassign(env *vars, statement *stmt)
94{
95 evalerr ret;
96 int value;
97
98 if ((ret = evaluate(vars, stmt->d.assign.exp, &value))
99 != EVAL_OK)
100 return ret;
101
102 if (updval(vars, stmt->d.assign.var, value))
103 return ERR_UNINITVAR;
104
105 return EVAL_OK;
106}
107
108evalerr
109execread(env *vars, statement *stmt)
110{
111 int input;
112
113 if (isatty(0) && printf("Input: ") <= 0)
114 return ERR_PRINTF;
115 if (fflush(stdout))
116 return ERR_FLUSH;
117
118 if (scanf("%d", &input) == EOF)
119 return ERR_SCANF;
120 if (updval(vars, stmt->d.read.var, input))
121 return ERR_UNINITVAR;
122
123 return EVAL_OK;
124}
125
126evalerr
127execwrite(env *vars, statement *stmt)
128{
129 evalerr ret;
130 int value;
131
132 if ((ret = evaluate(vars, stmt->d.write.exp, &value))
133 != EVAL_OK)
134 return ret;
135
136 if (isatty(0)) {
137 if (printf("Value: %d\n", value) <= 0)
138 return ERR_PRINTF;
139 } else {
140 printf("%d\n", value);
141 }
142
143 return EVAL_OK;
144}
145
146evalerr
147execcond(env *vars, statement *stmt)
148{
149 evalerr ret;
150 int value;
151
152 if ((ret = evaluate(vars, stmt->d.cond.cond, &value))
153 != EVAL_OK)
154 return ret;
155
156 if (value == 0)
157 return eval(vars, stmt->d.cond.brn2);
158 else
159 return eval(vars, stmt->d.cond.brn1);
160}
161
162evalerr
163execloop(env *vars, statement *stmt)
164{
165 evalerr ret;
166 int value;
167
168 if ((ret = evaluate(vars, stmt->d.loop.cond, &value))
169 != EVAL_OK)
170 return ret;
171
172 while (value != 0) {
173 if ((ret = eval(vars, stmt->d.loop.brn)) != EVAL_OK)
174 return ret;
175
176 if ((ret = evaluate(vars, stmt->d.loop.cond, &value))
177 != EVAL_OK)
178 return ret;
179 }
180
181 return EVAL_OK;
182}
183
184evalerr
185execute(env *vars, statement *stmt)
186{
187 switch (stmt->type) {
188 case STMT_ERROR:
189 break; /* Never reached */
190 case STMT_DEFINE:
191 return execdefine(vars, stmt);
192 case STMT_ASSIGN:
193 return execassign(vars, stmt);
194 case STMT_READ:
195 return execread(vars, stmt);
196 case STMT_WRITE:
197 return execwrite(vars, stmt);
198 case STMT_COND:
199 return execcond(vars, stmt);
200 case STMT_LOOP:
201 return execloop(vars, stmt);
202 }
203
204 /* Never reached. */
205 return EVAL_OK;
206}
207
208evalerr
209eval(env *vars, statement **cmds)
210{
211 evalerr ret;
212 statement *stmt;
213
214 while ((stmt = *cmds++))
215 if ((ret = execute(vars, stmt)) != EVAL_OK)
216 return ret;
217
218 return EVAL_OK;
219}