1/* I eventually need to split this file before it gets too big, i'll keep this comment here as a mental reminder,.,
2ooooo get off your ass dani ooooo go work ooooo dani you're a bum oooooo oooooo you suckkk oooooooo,., sorry me.., */
3
4#include "cotton.h"
5#include "interpreter.h"
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <ctype.h>
10
11static void word_add
12(Cotton *c)
13{
14 int b = pop(c);
15 int a = pop(c);
16
17 push(c, a + b);
18}
19
20static void word_sub
21(Cotton *c)
22{
23 int b = pop(c);
24 int a = pop(c);
25
26 push(c, a - b);
27}
28
29static void word_mul
30(Cotton *c)
31{
32 int b = pop(c);
33 int a = pop(c);
34
35 push(c, a * b);
36}
37
38static void word_div
39(Cotton *c)
40{
41 int b = pop(c);
42 int a = pop(c);
43
44 // Now, i doubt anyone will really be dividing stuff by zero but you never know.., talk about le safety amirite.., heh
45 if (b == 0) {
46 fprintf(stderr, "cotton: you cant divide by zero, you dummy :P\n");
47 return;
48 }
49
50 push(c, a / b);
51}
52
53static void word_dot
54(Cotton *c)
55{
56 printf("%d\n", pop(c));
57}
58
59// while forth does use ! and @, im quirky and #notlikeothergirls so im changing ! to -> bc i think it makes more sense :P
60static void word_store
61(Cotton *c)
62{
63 int slot = pop(c);
64 int num = pop(c);
65
66 if (slot >= 0 && slot < VARS_SIZE) {
67 c->vars[slot] = num;
68 }
69
70 else {
71 fprintf(stderr, "cotton: i tried to store somewhere that don't exist,, its in the void now.., :(\n");
72 }
73}
74
75static void word_fetch
76(Cotton *c)
77{
78 int slot = pop(c);
79
80 if (slot >= 0 && slot < VARS_SIZE) {
81 push(c, c->vars[slot]);
82 }
83
84 else {
85 fprintf(stderr, "cotton: i tried to fetch from somewhere that seemingly don't exist,, erm.,.\n");
86 }
87}
88
89static void word_dup
90(Cotton *c)
91{
92 int a = pop(c);
93
94 push(c, a);
95 push(c, a);
96}
97
98static void word_drop
99(Cotton *c)
100{
101 pop(c);
102}
103
104static void word_swap
105(Cotton *c)
106{
107 int b = pop(c);
108 int a = pop(c);
109
110 push(c, b);
111 push(c, a);
112}
113
114static void word_equal
115(Cotton *c)
116{
117 int b = pop(c);
118 int a = pop(c);
119
120 push(c, a == b ? 1 : 0);
121}
122
123static void word_lssr
124(Cotton *c)
125{
126 int b = pop(c);
127 int a = pop(c);
128
129 push(c, a < b ? 1 : 0);
130}
131
132static void word_grtr
133(Cotton *c)
134{
135 int b = pop(c);
136 int a = pop(c);
137
138 push(c, a > b ? 1 : 0);
139}
140
141static Word builtins[] = {
142 {"+", word_add},
143 {"-", word_sub},
144 {"*", word_mul},
145 {"/", word_div},
146 {".", word_dot},
147 {"->", word_store},
148 {"@", word_fetch},
149 {"dup", word_dup},
150 {"drop", word_drop},
151 {"swap", word_swap},
152 {"=", word_equal},
153 {"<", word_lssr},
154 {">", word_grtr},
155 {NULL, NULL}
156};
157
158/* this comment serves as a separator to split the words above from the words below, the words below run straight away while compiling
159instead of waiting to be ran later, forth calls these "immediate words" so thats what im calling them too :P (if it aint broke dont fix it as they say) */
160
161static void word_if
162(Cotton *c)
163{
164 if (c->jmp_stack_p >= JMP_STACK_SIZE) {
165 fprintf(stderr, "cotton: there are too many nested ifs, calm down!! D:\n");
166 return;
167 }
168
169 c->mem[c->mem_len++] = OP_FJMP;
170 c->jmp_stack[c->jmp_stack_p++] = c->mem_len;
171 c->mem[c->mem_len++] = 0;
172}
173
174static void word_else
175(Cotton *c)
176{
177 if (c->jmp_stack_p <= 0) {
178 fprintf(stderr, "cotton: i found an else without an if,., where'd that come from??\n");
179 return;
180 }
181
182 int if_target = c->jmp_stack[--c->jmp_stack_p];
183
184 c->mem[c->mem_len++] = OP_JMP;
185 c->jmp_stack[c->jmp_stack_p++] = c->mem_len;
186 c->mem[c->mem_len++] = 0;
187
188 c->mem[if_target] = c->mem_len;
189}
190
191static void word_end
192(Cotton *c)
193{
194 if (c->jmp_stack_p <= 0) {
195 fprintf(stderr, "cotton: i found an end without an if,., where'd that come from??\n");
196 return;
197 }
198
199 int target = c->jmp_stack[--c->jmp_stack_p];
200 c->mem[target] = c->mem_len;
201}
202
203static Word immediates[] = {
204 {"if", word_if},
205 {"else", word_else},
206 {"end", word_end},
207 {NULL, NULL}
208};
209
210/* Another comment just so i can separate the immediates from the compiler and runtime functions blehhhhhh
211words words words words more words SO many words OH MY GOD THERE ARE SO MANY WORDS WORDS WORDS WORDS AAAAAA*/
212
213void cotton_compile
214(Cotton *c, char *line)
215{
216 line[strcspn(line, "\r\n")] = 0;
217 if (line[0] == '\0' || (line[0] == '/' && line[1] == '/')) return;
218
219 char *tok = strtok(line, " ");
220
221 while (tok) {
222
223 if (c->mem_len >= MEM_SIZE - 2) {
224 fprintf(stderr, "cotton: i ran out of memory,., can't compile anymore :<\n");
225 return;
226 }
227
228 /* This is subjective to change but i thought that using ? for conditionals so stuff reads out as
229 "is this happening? if so, then, blah blah blah" was a good idea, atleast sounded good in my head :P*/
230
231 if (strcmp(tok, "?") == 0) {
232 // oh yeah, also, this doesn't really do anything, its just here to make if statements look nicer x3
233 }
234
235 else {
236
237 int found_immediate = 0;
238
239 for (int i = 0; immediates[i].name != NULL; i++) {
240
241 if (strcmp(tok, immediates[i].name) == 0) {
242 immediates[i].code(c);
243 found_immediate = 1;
244 break;
245 }
246 }
247
248 if (!found_immediate) {
249
250 int is_num = 1;
251
252 for (int i = 0; tok[i]; i++) {
253
254 if (!isdigit(tok[i]) && !(i == 0 && tok[i] == '-')) {
255 is_num = 0;
256 break;
257 }
258 }
259
260 if (is_num) {
261 c->mem[c->mem_len++] = OP_PUSH;
262 c->mem[c->mem_len++] = atoi(tok);
263 }
264
265 else {
266
267 int found = 0;
268
269 for (int i = 0; builtins[i].name != NULL; i++) {
270
271 if (strcmp(tok, builtins[i].name) == 0) {
272 c->mem[c->mem_len++] = OP_CALL;
273 c->mem[c->mem_len++] = i;
274 found = 1;
275 break;
276 }
277 }
278
279 if (!found) {
280 fprintf(stderr, "cotton: sorry, i don't know what \"%s\" means :(\n", tok);
281 }
282 }
283 }
284 }
285
286 tok = strtok(NULL, " ");
287 }
288}
289
290void cotton_run
291(Cotton *c)
292{
293 c->instruct_p = 0;
294
295 while (c->instruct_p < c->mem_len) {
296
297 int op = c->mem[c->instruct_p++];
298
299 if (op == OP_PUSH) {
300 push(c, c->mem[c->instruct_p++]);
301 }
302
303 else if (op == OP_CALL) {
304
305 int idx = c->mem[c->instruct_p++];
306 builtins[idx].code(c);
307 }
308
309 else if (op == OP_JMP) {
310 c->instruct_p = c->mem[c->instruct_p];
311 }
312
313 else if (op == OP_FJMP) {
314
315 int target = c->mem[c->instruct_p++];
316
317 if (pop(c) == 0) {
318 c->instruct_p = target;
319 }
320 }
321
322 else if (op == OP_KILL) {
323 break;
324 }
325 }
326}