latest soggy/cotton / src / interpreter.c
  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}