7 #define RD_BLOCK_SZ 4096
19 #define MAKE_ARRAY(arr, arr_sz_var) { \
20 arr = malloc(arr_sz_var * sizeof *arr); \
25 #define GROW_ARRAY(arr, arr_sz) { \
27 arr = realloc(arr, arr_sz * sizeof *arr); \
34 size_t vars_storage_sz
;
37 * queue is implemented as a circularized array with continuously
38 * advancing head/tail pointers. queue_head shall point to the first
39 * position at which a `real' value is stored, queue_tail shall point
40 * to the first position past queue_head at which a `real' value is
46 size_t queue_storage_sz
;
47 size_t queue_elem_num
;
50 * the program source is slurped entirely into this array so that
51 * BEGIN/END jumping may work correctly, though perhaps in the future
52 * an option may be added to do this through fseek() calls instead
55 size_t prog_storage_sz
;
59 * begin and end points are stored, interleaved, in an array (A[2k] a
60 * begin, A[2k+1] its matching end) for faster lookup than a linear
61 * search (about half of the time). jump_pair_num * 2 >
62 * jump_storage_sz is the condition that must be avoided
64 * TODO: it now seems clear that this should be reversed, so that the
65 * ends are in monotonic order, with the begins unordered
68 size_t jump_storage_sz
;
71 /* program handling */
72 int read_in(FILE * input
)
77 prog_storage_sz
= RD_BLOCK_SZ
;
78 MAKE_ARRAY(prog
, prog_storage_sz
);
82 fread(c_prog
, sizeof *prog
, RD_BLOCK_SZ
, input
)) == RD_BLOCK_SZ
) {
83 prog_storage_sz
+= RD_BLOCK_SZ
;
84 prog_len
= prog_storage_sz
;
85 prog
= realloc(prog
, prog_storage_sz
* sizeof *prog
);
88 c_prog
= prog
+ (prog_storage_sz
- RD_BLOCK_SZ
);
91 prog_len
+= read_bytes
;
92 *(prog
+ prog_len
) = '\0';
97 int build_jump_list(void)
99 const char *pc
= prog
;
102 * a stack for where the next end gets stored, so
103 * ends_storage_stack[ends_num - 1 - 2] is a pointer to within
104 * jumps that should be filled by a pointer to within prog that
105 * matches a begin that is two matching levels away from the current
108 const char ***ends_storage_stack
;
110 size_t ends_storage_sz
= 4;
115 MAKE_ARRAY(ends_storage_stack
, ends_storage_sz
);
119 MAKE_ARRAY(jumps
, jump_storage_sz
);
121 while (*pc
!= '\0') {
123 if (ends_num
+ 1 >= ends_storage_sz
) {
124 GROW_ARRAY(ends_storage_stack
, ends_storage_sz
);
127 if (2 * (jump_pair_num
+ 1) >= jump_storage_sz
) {
128 GROW_ARRAY(jumps
, jump_storage_sz
);
132 * store this point as a begin, and record the spot at which to
133 * fill in the matching end
135 *(ends_storage_stack
+ ends_num
) = jumps
+ (2 * jump_pair_num
) + 1;
136 *(jumps
+ 2 * jump_pair_num
) = pc
;
139 } else if (*pc
== END
) {
141 fprintf(stderr
, "Unmatched %c at line %d, char %d\n", END
, lineno
,
146 if (2 * (jump_pair_num
+ 1) >= jump_storage_sz
) {
147 GROW_ARRAY(jumps
, jump_storage_sz
);
151 * store this point as an end in the correct point in the jump
152 * list, which was precomputed when the begin was seen
154 **(ends_storage_stack
+ ends_num
- 1) = pc
;
156 } else if (*pc
== '\n') {
166 fprintf(stderr
, "%lu unmatched %c detected", (unsigned long)ends_num
,
174 const char *matching_end_for(const char *begin
)
181 * quick checks that allow range to be a little sloppy
183 if (jumps
[(2 * 0) + 0] == begin
)
184 return jumps
[(2 * 0) + 1];
185 if (jumps
[(2 * jump_pair_num
) + 0] == begin
)
186 return jumps
[(2 * jump_pair_num
) + 1];
189 * binary search, since it is known that begins are laid out in
190 * increasing order in jump list
192 cur_jump
= jump_pair_num
/ 2;
193 search_incr
= jump_pair_num
/ 4;
195 while (search_incr
>= 0) {
196 diff
= (int)(jumps
[(2 * cur_jump
) + 0] - begin
);
197 if (search_incr
== 0 || diff
== 0)
198 return jumps
[(2 * cur_jump
) + 1];
200 cur_jump
+= search_incr
;
202 cur_jump
-= search_incr
;
210 const char *matching_begin_for(const char *end
)
215 * ends are completely unordered, so nothing for it but linear
217 while (cur_jump
< jump_pair_num
) {
218 if (jumps
[(2 * cur_jump
) + 1] == end
)
222 return jumps
[(2 * cur_jump
) + 0];
227 int enqueue(const char c
)
232 * store value and advance tail pointer, wrapping if needed
235 if (queue_tail
- queue
+ 1 == queue_storage_sz
)
241 * resize the buffer if needed
243 if (queue_elem_num
== queue_storage_sz
) {
245 queue_storage_sz
*= 2;
247 if (queue_head
== queue
) {
249 * in the easy case, re-use existing memory
251 queue
= realloc(queue
, queue_storage_sz
* sizeof *queue
);
255 queue_tail
= queue
+ queue_elem_num
;
258 * in the non-trivial case, neatly re-arrange everything to a
263 MAKE_ARRAY(new_queue
, queue_storage_sz
);
265 memcpy(new_queue
, queue_head
, queue_elem_num
- (queue_head
- queue
));
266 memcpy(new_queue
, queue
, queue_head
- queue
);
267 queue_head
= queue
= new_queue
;
268 queue_tail
= queue_head
+ queue_elem_num
;
277 char to_ret
= *queue_head
;
281 if (queue_head
- queue
+ 1 == queue_storage_sz
)
292 return vars
+ (rand() % vars_num
);
295 /* instruction handling */
298 const char *pc
= prog
;
303 while (*pc
!= '\0') {
306 if (vars_num
>= vars_storage_sz
) {
307 GROW_ARRAY(vars
, vars_storage_sz
);
310 vars
[vars_num
- 1] = 0;
314 if ((ret
= enqueue(*tvar
)) != 0)
334 #ifdef LESS_PROBLEMATIC
339 while (c
== 0 && varidx
< vars_num
)
340 c
= vars
[varidx
++] != 0;
343 pc
= matching_end_for(pc
);
347 pc
= matching_end_for(pc
);
353 * this `- 1' may be an error from a faulty reading of the spec
355 pc
= matching_begin_for(pc
) - 1;
358 if ((ret
= enqueue(0)) != 0)
366 ret
= enqueue((char)c
);
373 if ((ret
= enqueue(*tvar
)) != 0)
385 int main(int argc
, char **argv
)
390 fprintf(stderr
, "Usage: %s INPUT_FILE\n", argv
[0]);
397 vars_storage_sz
= 16;
398 if (!(vars
= calloc(vars_storage_sz
, sizeof *vars
))) {
399 perror("Could not initialize internal state");
403 queue_storage_sz
= 128;
406 (queue_head
= queue_tail
= queue
=
407 malloc(queue_storage_sz
* sizeof *queue
))) {
408 perror("Could not initialize internal state");
414 if (!(jumps
= malloc(jump_storage_sz
* sizeof *jumps
))) {
415 perror("Could not initialize internal state");
419 if (!(input
= fopen(argv
[1], "r"))) {
420 perror("Could not open input file");
424 if (read_in(input
) != 0) {
425 perror("Could not fully read input file");
433 if (build_jump_list() != 0) {
435 * if errno is set, library error, otherwise syntax error
438 perror("Could not initialize jump list");
448 if (execute() != 0) {
449 perror("Error during execution");