-
Notifications
You must be signed in to change notification settings - Fork 30
/
snek-parse.c
291 lines (250 loc) · 6.49 KB
/
snek-parse.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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
/*
* Copyright © 2019 Keith Packard <keithp@keithp.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
#include "snek.h"
bool snek_interactive;
bool snek_parse_middle;
uint8_t snek_parse_nformal;
uint8_t snek_parse_nnamed;
snek_id_t snek_parse_formals[SNEK_MAX_FORMALS];
snek_token_val_t snek_token_val;
#ifdef SNEK_NO_SLICE
#define snek_no_slice SNEK_NO_SLICE
#else
#define snek_no_slice 0
#endif
#ifdef SNEK_NO_DICT
#define snek_no_dict SNEK_NO_DICT
#else
#define snek_no_dict 0
#endif
#define PARSE_TOP \
uint8_t for_depth = 0; \
bool snek_print_val = 0;
#define GRAMMAR_TABLE
#ifdef PARSE_DEBUG
#define TOKEN_NAMES
#endif
#include "snek-gram.h"
#ifndef VALUE_STACK_SIZE
#define VALUE_STACK_SIZE 127
#endif
#if VALUE_STACK_SIZE < 128
typedef int8_t snek_value_stack_p_t;
#else
typedef int16_t snek_value_stack_p_t;
#endif
typedef union {
bool bools;
uint8_t indent;
snek_op_t op;
snek_id_t id;
snek_offset_t offset;
} snek_parse_val_t;
static snek_parse_val_t value_stack[VALUE_STACK_SIZE];
static snek_value_stack_p_t value_stack_p = 0;
//#define VALUE_DEBUG
static snek_parse_val_t
_value_pop(const char *file, int line)
{
(void) file; (void) line;
#ifdef VALUE_DEBUG
printf("value pop %d from %s:%d\n", value_stack_p - 1, file, line);
#endif
#if SNEK_DEBUG
if (value_stack_p == 0) {
snek_error_0("value stack underflow");
return (snek_parse_val_t) { .offset = 0 };
}
#endif
return value_stack[--value_stack_p];
}
static bool
_value_push(snek_parse_val_t value, const char *file, int line)
{
(void) file; (void) line;
if (value_stack_p >= VALUE_STACK_SIZE)
return false;
#ifdef VALUE_DEBUG
printf("\tpush %d from %s:%d\n", value_stack_p, file, line);
#endif
value_stack[value_stack_p++] = value;
return true;
}
static bool
_value_push_offset(snek_offset_t value, const char *file, int line)
{
(void) file; (void) line;
#ifdef VALUE_DEBUG
printf("value push offset %u\n", (unsigned) value);
#endif
return _value_push((snek_parse_val_t) { .offset = value }, file, line);
}
static bool
_value_push_indent(uint8_t value, const char *file, int line)
{
(void) file; (void) line;
#ifdef VALUE_DEBUG
printf("value push indent %d\n", value);
#endif
return _value_push((snek_parse_val_t) { .indent = value }, file, line);
}
static bool
_value_push_op(snek_op_t op, const char *file, int line)
{
(void) file; (void) line;
#ifdef VALUE_DEBUG
printf("value push op %d\n", op);
#endif
return _value_push((snek_parse_val_t) { .op = op }, file, line);
}
static bool
_value_push_id(snek_id_t id, const char *file, int line)
{
(void) file; (void) line;
#ifdef VALUE_DEBUG
printf("value push id %s\n", snek_name_string(id));
#endif
return _value_push((snek_parse_val_t) { .id = id }, file, line);
}
#define value_pop() _value_pop(__FILE__, __LINE__)
#define value_push_int(i) _value_push_int(i, __FILE__, __LINE__)
#define value_push_indent(i) _value_push_indent(i, __FILE__, __LINE__)
#define value_push_op(o) _value_push_op(o, __FILE__, __LINE__)
#define value_push_offset(o) _value_push_offset(o, __FILE__, __LINE__)
#define value_push_id(o) _value_push_id(o, __FILE__, __LINE__)
#ifndef PARSE_STACK_SIZE
#define PARSE_STACK_SIZE 128
#endif
#define lex(context) ({ \
(void) context; \
token_t __token__ = snek_lex(); \
if (snek_abort) \
return parse_return_error; \
snek_line = snek_lex_line; \
snek_parse_middle = true; \
__token__; \
})
static inline void binop_first(void)
{
snek_code_set_push(snek_code_prev_insn());
value_push_op(snek_token_val.op);
}
static inline void binop_second(void)
{
snek_code_add_op(value_pop().op);
}
static inline void add_op_lvalue(void)
{
snek_op_t op = value_pop().offset;
snek_id_t id = value_pop().id;
/* add the assignment operator */
snek_code_add_op_id(op, id);
}
static inline void patch_loop(void)
{
snek_offset_t while_else_stat_off = value_pop().offset;
snek_offset_t loop_end_off = value_pop().offset;
snek_offset_t while_off = value_pop().offset;
snek_offset_t top_off = value_pop().offset;
snek_code_patch_branch(while_off, while_else_stat_off);
snek_code_patch_branch(loop_end_off, top_off);
snek_code_patch_forward(while_off, loop_end_off, snek_forward_continue, top_off);
snek_code_patch_forward(while_off, loop_end_off, snek_forward_break, snek_code_current());
}
static inline void short_second(void)
{
snek_code_patch_branch(value_pop().offset, snek_code_current());
snek_code_add_op(snek_op_nop);
}
static inline void unop_first(void)
{
value_push_op(snek_token_val.op);
}
static inline void unop_second(void)
{
snek_code_add_op(value_pop().op);
}
static inline void bool_branch(snek_op_t op)
{
snek_code_add_op_offset(op, 0);
value_push_offset(snek_compile_prev);
}
#define PARSE_CODE
#include "snek-gram.h"
snek_parse_ret_t
snek_parse(void)
{
for (;;) {
/* Reset lex state */
snek_current_indent = 0;
snek_lex_indent = 0;
snek_ignore_nl = 0;
snek_lex_midline = false;
snek_lex_exdent = false;
/* Reset parse state */
snek_parse_middle = false;
value_stack_p = 0;
/* Reset codegen state */
snek_code_reset();
/* Reset error state */
snek_abort = false;
parse_return_t ret = parse(NULL);
switch (ret) {
case parse_return_success:
return snek_parse_success;
case parse_return_end:
snek_error_syntax("EOF");
return snek_parse_error;
case parse_return_error:
if (snek_interactive)
break;
return snek_parse_error;
case parse_return_oom:
snek_error_0("Out of Memory");
goto error_recover;
case parse_return_syntax:
default:
snek_error_syntax(snek_lex_text);
error_recover:
if (!snek_interactive)
return snek_parse_error;
{
/* Skip input until we get back to
* zero indent
*/
token_t token;
for (;;) {
snek_ignore_nl = 0;
token = snek_lex();
switch(token) {
case END:
return snek_parse_success;
case NL:
if (snek_current_indent == 0)
break;
continue;
case EXDENT:
snek_current_indent = snek_token_val.indent;
continue;
default:
continue;
}
snek_parse_middle = false;
break;
}
}
break;
}
}
}