climp

Dirty interpreter for the limp programming language in C

git clone https://git.8pit.net/climp.git

  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}