-
Notifications
You must be signed in to change notification settings - Fork 0
/
fishjit.c
121 lines (105 loc) · 3.16 KB
/
fishjit.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
#include "fish-cache.h"
#include "fish-codebox.h"
#include "fish-compiler.h"
#include "fish-stack.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
/* seed PRNG */
srand(time(NULL));
/* disable input echo (for 'i' instruction) */
struct termios t;
tcgetattr(STDOUT_FILENO, &t);
t.c_lflag &= ~ECHO;
tcsetattr(STDOUT_FILENO, TCSANOW, &t);
/* enable non-canonical input */
tcgetattr(STDIN_FILENO, &t);
t.c_lflag &= ~ICANON;
tcsetattr(STDIN_FILENO, TCSANOW, &t);
/* disable output buffering */
setbuf(stdout, NULL);
/* validate command-line arguments */
if (argc < 2)
{
fputs("No input file provided", stderr);
exit(EXIT_FAILURE);
}
/* open script file */
FILE *script_file = fopen(argv[1], "r");
if (script_file == NULL)
{
perror("Could not open input file");
exit(EXIT_FAILURE);
}
/* read script file */
struct fish_codebox codebox = {0};
char line[CODEBOX_WIDTH];
size_t row = 0;
while (fgets(line, sizeof line, script_file))
{
/* read and discard until end of line, if necessary */
/* TODO: don't do this */
while (!strchr(line, '\n'))
fgets(line, sizeof line, script_file);
/* store line into codebox, excluding the newline character */
size_t len = strlen(line) - 1;
for (size_t column = 0; column < len; ++column)
{
fish_set(&codebox, row, column, line[column]);
}
++row;
}
if (ferror(script_file))
{
perror("Could not read from input file");
exit(EXIT_FAILURE);
}
if (fclose(script_file) == EOF)
{
perror("Could not close input file");
exit(EXIT_FAILURE);
}
/* initialize instruction cache and VM state */
struct fish_cache *cache = NULL;
struct fish_state state = {.row = 0, .column = 0, .direction = RIGHT};
struct fish_stack *stack = fish_alloc_stack();
/* main loop */
do
{
/* get cached code for current state or (re)compile it */
struct fish_code *code = fish_get_or_compile(&cache, &state, &codebox);
if (code == NULL)
{
/* no code means it could not be assembled (invalid instruction) */
fputs("something smells fishy...\n", stderr);
exit(EXIT_FAILURE);
}
else
{
/* grow stack to twice the size if an overflow is possible */
size_t potential_items = stack->num_items + code->max_stack_change;
if (!fish_resize_stack(stack, potential_items))
{
perror("realloc");
exit(EXIT_FAILURE);
}
/* execute code, updating state */
int ret = code->entry(&state, stack, &codebox);
if (ret != 0)
{
fputs("something smells fishy...\n", stderr);
exit(EXIT_FAILURE);
}
}
} while (state.direction != FINISHED);
/* clean up */
fish_free_cache(cache);
fish_free_stack(stack);
return 0;
}