-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinterpreter.c
More file actions
127 lines (119 loc) · 3.88 KB
/
interpreter.c
File metadata and controls
127 lines (119 loc) · 3.88 KB
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
122
123
124
125
126
127
#include "pawscript.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#define BUFFER_SIZE 8192
char* create_buffer() {
return malloc(BUFFER_SIZE);
}
void buffer_append_byte(char** buffer, int* ptr, char c) {
(*buffer)[(*ptr)++] = c;
if (*ptr % BUFFER_SIZE == 0) *buffer = realloc(*buffer, *ptr + BUFFER_SIZE);
}
void buffer_append(char** buffer, int* ptr, char c) {
buffer_append_byte(buffer, ptr, c);
buffer_append_byte(buffer, ptr, 0);
(*ptr)--;
}
void buffer_read_line(char** buffer, int* ptr) {
char c;
while ((c = getchar()) != EOF && c != '\n') {
buffer_append_byte(buffer, ptr, c);
}
buffer_append_byte(buffer, ptr, '\n');
buffer_append_byte(buffer, ptr, 0);
(*ptr)--;
}
bool can_exec(char* code) {
int depth = 0;
char string_char = 0;
bool backslash = false;
bool valid_end = false;
int ptr = 0;
char c;
while ((c = code[ptr++])) {
valid_end = false;
if (string_char) {
if (!backslash && c == string_char) string_char = 0;
backslash = c == '\\';
}
else {
if (c == '"' || c == '\'') string_char = c;
if (c == '(' || c == '[' || c == '{') depth++;
if (c == ')' || c == ']' || c == '}') depth--;
}
}
return depth <= 0 && string_char == 0;
}
int main(int argc, char** argv) {
bool interactive = false;
if (argc == 1) {
printf("Paws - The PawScript interpreter\n");
printf("Usage:\n");
printf("-f <file> execute a file\n");
printf("-f - run from stdin\n");
printf("-i interactive mode\n");
printf("\n");
printf("When using -i and -f at the same time,\nthe interpreter goes to interactive mode on exit.\n");
printf("You can chain multiple -f's.\n");
return 0;
}
PawScriptContext* context = pawscript_create_context();
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-i") == 0) interactive = true;
else if (strcmp(argv[i], "-f") == 0) {
i++;
if (i == argc) {
fprintf(stderr, "Expected file\n");
return 1;
}
if (strcmp(argv[i], "-") == 0) {
char* buf = create_buffer();
int c, ptr = 0;
while ((c = getchar()) != EOF) {
buffer_append(&buf, &ptr, c);
}
PawScriptError* error;
if ((error = pawscript_run(context, buf))) pawscript_log_error(error, stderr);
else {
printf("<stdin>: ");
pawscript_print_variable(context, stdout, PAWSCRIPT_RESULT);
}
free(buf);
}
else {
PawScriptError* error;
if ((error = pawscript_run_file(context, argv[i]))) pawscript_log_error(error, stderr);
else {
printf("%s: ", argv[i]);
pawscript_print_variable(context, stdout, PAWSCRIPT_RESULT);
}
}
}
else {
fprintf(stderr, "Unknown option: %s\n", argv[i]);
return 1;
}
}
char* buf = create_buffer();
int ptr = 0;
while (interactive) {
if (!isatty(STDIN_FILENO)) {
fprintf(stderr, "stdin is not an interactive terminal. Skipping interactive shell.\n");
return 1;
}
printf("%c ", ptr == 0 ? '>' : '+');
buffer_read_line(&buf, &ptr);
if (can_exec(buf)) {
PawScriptError* error;
if ((error = pawscript_run(context, buf))) pawscript_log_error(error, stderr);
else pawscript_print_variable(context, stdout, PAWSCRIPT_RESULT);
ptr = 0;
}
}
free(buf);
pawscript_destroy_context(context);
return 0;
}