Remove globals capfuck_std{in,out,err}
[ilari-esolangs.git] / capfuck.c
blob7ed5048924820fd29247fec521d5d84b31c271ca
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "sane-ctype.h"
5 struct context;
6 struct message;
8 #define CARRIAGE_RETURN 13
9 #define SPACE 32
10 #define LINEFEED 10
11 #define BACKSLASH 92
12 #define HASH 35
13 #define ZERO 48
14 #define NINE 57
16 /* Object marked for garbage collection. */
17 #define OF_MARKED_FOR_GC 1
18 /* Already execuing message handler. */
19 #define OF_EXECUTING 2
20 /* on line, no non-whitespace yet. */
21 #define PS_INITIAL 0
22 /* Last was non-whitespace. */
23 #define PS_LAST_NOT_WS 1
24 /* Last was whitespace, non-ws seen. */
25 #define PS_WHITESPACE 2
26 /* Last was newline. */
27 #define PS_NEWLINE 3
28 /* Last was Carriage return. */
29 #define PS_LAST_CR 4
30 /* Start of line. */
31 #define PS2_INITIAL 0
32 /* On non-comment line. */
33 #define PS2_NOT_COMMENT 1
34 /* On comment line. */
35 #define PS2_COMMENT 2
37 /* Lock */
38 struct lock
42 /* Class table entry. */
43 struct class
45 /* Class number. */
46 size_t c_class_number;
47 /* Number of fields. */
48 size_t c_fields;
49 /* Number of locals. */
50 size_t c_locals;
51 /* Body text. */
52 unsigned char* c_body;
53 /* Body text length. */
54 size_t c_body_length;
55 /* Next entry. */
56 struct class* c_next;
59 /* Object. */
60 struct object
62 /* Flags. */
63 unsigned o_flags;
64 /* Class of object. */
65 struct class* o_class;
66 /* Special receiver. */
67 void (*o_special)(struct context* ctx, struct message* msg);
68 /* Previous object. */
69 struct object* o_prev;
70 /* Next object. */
71 struct object* o_next;
72 /* Fields. */
73 struct object* o_fields[0];
76 /* Message. */
77 struct message
79 /* Target object. */
80 struct object* m_target;
81 /* Previous message in queue. */
82 struct message* m_prev;
83 /* Next message in queue. */
84 struct message* m_next;
85 /* Number of parameters in message. */
86 size_t m_parameter_count;
87 /* Parameters contained. */
88 struct object* m_parameters[0];
91 /* Stack slot. */
92 struct stack
94 /* Object reference held. */
95 struct object* s_object;
96 /* Next stack slot. */
97 struct stack* s_next;
100 /* Vat. */
101 struct vat
103 /* Object list head. */
104 struct object* v_object_list;
105 /* Message queue head. */
106 struct message* v_msgq_head;
107 /* Message queue tail. */
108 struct message* v_msgq_tail;
109 /* Greatest locals count for any class. */
110 size_t v_max_locals;
111 /* Message queue lock. */
112 struct lock v_msgq_lock;
115 /* Context. */
116 struct context
118 /* Vat used. */
119 struct vat* c_vat;
120 /* Message being handled. */
121 struct message* c_message;
122 /* Stack top pointer. */
123 struct stack* c_stacktop;
124 /* Instruction pointer. */
125 size_t c_ip;
126 /* Number register value. */
127 size_t c_numreg;
128 /* Alternative mode flag. */
129 unsigned c_alt_flag;
130 /* Context lock. */
131 struct lock c_lock;
132 /* Locals. */
133 struct object* c_locals[0];
136 /* Parse context. */
137 struct parser
139 /* Line number. */
140 unsigned p_line;
141 /* Main parser status. */
142 unsigned p_status;
143 /* Secondary parser status. */
144 unsigned p_status2;
145 /* Backslash flag. */
146 unsigned p_backslash;
147 /* Number of class to parse. */
148 size_t p_classnum;
149 /* Number of fields. */
150 size_t p_fields;
151 /* Number of locals. */
152 size_t p_locals;
153 /* Max number of locals. */
154 size_t p_maxlocals;
155 /* Allocated size of instructions. */
156 size_t p_ins_allocated;
157 /* Real size of instructions. */
158 size_t p_ins_size;
159 /* Instructions. */
160 unsigned char* p_ins;
161 /* Field number. */
162 unsigned p_field;
163 /* Have value for field. 0 = no, 1 = zero, 2 = nonzero. */
164 unsigned p_have_field_value;
167 struct class* c_list_head = NULL;
168 struct class* c_list_tail = NULL;
170 /*****************************************************************************/
171 static void mutex_lock(struct lock* lock);
172 static void mutex_unlock(struct lock* lock);
174 /*****************************************************************************/
175 static struct class* search_class(size_t number);
176 static void parse_input(struct parser* parser, char input);
177 static void parse_input2(struct parser* parser, char input);
178 static void parse_input3(struct parser* parser, char input);
179 static void parse_eof(struct parser* parser);
180 static unsigned prepare_context(struct context* ctx);
181 static void unprepare_context(struct context* ctx);
182 static unsigned execute_msghandler(struct context* ctx);
183 static struct object* pop_stack(struct context* ctx);
184 static void push_stack(struct context* ctx, struct object* obj);
185 static void queue_message(struct vat* vat, struct message* message);
186 static void recursive_mark_live(struct object* object);
187 static void mark_messages_live(struct message* queue);
188 static unsigned perform_gc(struct vat* vat);
189 static void singlestep_context(struct context* ctx, struct message* msg,
190 struct object* t, struct class* tc);
192 /*****************************************************************************/
193 static void mutex_lock(struct lock* lock)
197 /*****************************************************************************/
198 static void mutex_unlock(struct lock* lock)
202 /*****************************************************************************/
203 static struct class* search_class(size_t number)
205 struct class* cur = c_list_head;
207 while(cur) {
208 if(number == cur->c_class_number)
209 return cur;
210 cur = cur->c_next;
212 /* No match. */
213 return NULL;
216 /*****************************************************************************/
217 static void parse_input(struct parser* parser, char input)
219 /* We need to clean up input so that whitespaces are normalized. */
220 unsigned is_space = sane_isspace((unsigned char)input);
221 unsigned is_newline = sane_isnewline((unsigned char)input);
223 switch(parser->p_status) {
224 case PS_INITIAL:
225 if(is_newline) {
226 parser->p_status = ((input == CARRIAGE_RETURN) ?
227 PS_LAST_CR : PS_NEWLINE);
228 parser->p_line++;
229 } else if(is_space) {
230 /* Keep state. */
231 } else {
232 parser->p_status = PS_LAST_NOT_WS;
233 parse_input2(parser, input);
235 break;
236 case PS_LAST_NOT_WS:
237 if(is_newline) {
238 parse_input2(parser, LINEFEED);
239 parser->p_status = ((input == CARRIAGE_RETURN) ?
240 PS_LAST_CR : PS_NEWLINE);
241 parser->p_line++;
242 } else if(is_space) {
243 parser->p_status = PS_WHITESPACE;
244 } else {
245 parse_input2(parser, input);
247 break;
248 case PS_WHITESPACE:
249 if(is_newline) {
250 parse_input2(parser, LINEFEED);
251 parser->p_status = ((input == CARRIAGE_RETURN) ?
252 PS_LAST_CR : PS_NEWLINE);
253 parser->p_line++;
254 } else if(is_space) {
255 /* Keep state. */
256 } else {
257 parser->p_status = PS_LAST_NOT_WS;
258 parse_input2(parser, SPACE);
259 parse_input2(parser, input);
261 break;
262 case PS_NEWLINE:
263 if(is_newline) {
264 parser->p_status = ((input == CARRIAGE_RETURN) ?
265 PS_LAST_CR : PS_NEWLINE);
266 parser->p_line++;
267 } else if(is_space) {
268 parser->p_status = PS_INITIAL;
269 } else {
270 parser->p_status = PS_LAST_NOT_WS;
271 parse_input2(parser, input);
273 break;
274 case PS_LAST_CR:
275 if(is_newline) {
276 parser->p_status = ((input == CARRIAGE_RETURN) ?
277 PS_LAST_CR : PS_NEWLINE);
278 if(input != LINEFEED)
279 parser->p_line++;
280 } else if(is_space) {
281 parser->p_status = PS_INITIAL;
282 } else {
283 parser->p_status = PS_LAST_NOT_WS;
284 parse_input2(parser, input);
286 break;
290 /*****************************************************************************/
291 static void parse_input2(struct parser* parser, char input)
293 /* Here, we got to handle comments and backslashes. */
294 if(parser->p_backslash && (input == LINEFEED || input == SPACE))
295 return;
296 parser->p_backslash = (input == BACKSLASH);
297 if(input == BACKSLASH)
298 return;
300 switch(parser->p_status2) {
301 case PS2_INITIAL:
302 if(input == HASH)
303 parser->p_status2 = PS2_COMMENT;
304 else {
305 parser->p_status2 = PS2_NOT_COMMENT;
306 parse_input3(parser, input);
308 break;
309 case PS2_NOT_COMMENT:
310 parse_input3(parser, input);
311 /* Fallthrough. */
312 case PS2_COMMENT:
313 if(input == LINEFEED)
314 parser->p_status2 = PS2_INITIAL;
315 break;
319 /*****************************************************************************/
320 static void parse_input3(struct parser* parser, char input)
322 if(input == SPACE) {
323 if(parser->p_field == 2) {
324 fprintf(stderr, "Line %zu: Illegal character <%02X> "
325 "in class body.\n", parser->p_line, input);
326 exit(1);
328 parser->p_field++;
329 parser->p_have_field_value = 0;
330 } else if(input == LINEFEED) {
331 if(parser->p_field < 1) {
332 fprintf(stderr, "Line %zu: Truncated class "
333 "description.\n", parser->p_line);
334 exit(1);
336 /* Parsed class. */
337 if(parser->p_locals > parser->p_maxlocals)
338 parser->p_maxlocals = parser->p_locals;
340 struct class* class = malloc(sizeof(struct class));
341 if(!class) {
342 fprintf(stderr, "Out of memory.\n");
343 exit(1);
345 class->c_class_number = parser->p_classnum++;
346 class->c_fields = parser->p_fields;
347 class->c_locals = parser->p_locals;
348 class->c_body = parser->p_ins;
349 class->c_body_length = parser->p_ins_size;
350 class->c_next = NULL;
351 if(c_list_head)
352 c_list_tail = c_list_tail->c_next = class;
353 else
354 c_list_tail = c_list_head = class;
356 parser->p_ins = NULL;
357 parser->p_ins_allocated = 0;
358 parser->p_ins_size = 0;
359 parser->p_have_field_value = 0;
360 parser->p_field = 0;
361 parser->p_fields = 0;
362 parser->p_locals = 0;
363 } else if(parser->p_field < 2) {
364 if(input < ZERO && input > NINE) {
365 fprintf(stderr, "Line %zu: Illegal character <%02X> "
366 "in numeric value.\n", parser->p_line,
367 input);
368 exit(1);
370 if(input == ZERO) {
371 if(parser->p_have_field_value == 1) {
372 fprintf(stderr, "Line %zu: Invalid numeric "
373 "value.\n", parser->p_line);
374 exit(1);
379 if(parser->p_field == 0)
380 parser->p_fields = 10 * parser->p_fields +
381 (input - ZERO);
382 else
383 parser->p_locals = 10 * parser->p_locals +
384 (input - ZERO);
386 } else {
387 switch(input) {
388 case '+':
389 case '-':
390 case 'E':
391 case 'f':
392 case 'F':
393 case 'l':
394 case 'L':
395 case 'p':
396 case 'P':
397 case 's':
398 case 'S':
399 case 'N':
400 break;
401 default:
402 fprintf(stderr, "Line %zu: Invalid instruction "
403 "<%02X>.\n", parser->p_line, input);
404 exit(1);
406 if(parser->p_ins_size == parser->p_ins_allocated) {
407 if(parser->p_ins_allocated == 0)
408 parser->p_ins_allocated = 2;
409 parser->p_ins_allocated = parser->p_ins_allocated *
410 3 / 2;
411 parser->p_ins = realloc(parser->p_ins,
412 parser->p_ins_allocated);
413 if(!parser->p_ins) {
414 fprintf(stderr, "Out of memory.\n");
415 exit(1);
418 parser->p_ins[parser->p_ins_size++] = input;
422 /*****************************************************************************/
423 static void parse_eof(struct parser* parser)
425 if(parser->p_status == PS_LAST_NOT_WS ||
426 parser->p_status == PS_WHITESPACE)
427 parse_input2(parser, LINEFEED);
430 /*****************************************************************************/
431 static struct object* pop_stack(struct context* ctx)
433 if(!ctx->c_stacktop)
434 return NULL;
436 struct stack* tmp = ctx->c_stacktop;
437 struct object* obj = tmp->s_object;
438 ctx->c_stacktop = tmp->s_next;
439 free(tmp);
440 return obj;
445 /*****************************************************************************/
446 static unsigned prepare_context(struct context* ctx)
448 /* Grab message queue lock and context lock. */
449 mutex_lock(&ctx->c_vat->v_msgq_lock);
450 mutex_lock(&ctx->c_lock);
452 /* Find suitable message. */
453 ctx->c_message = ctx->c_vat->v_msgq_head;
454 while(ctx->c_message && ctx->c_message->m_target->o_flags ==
455 OF_EXECUTING)
456 ctx->c_message = ctx->c_message->m_next;
457 if(!ctx->c_message)
458 return 0;
460 /* Unlink message. */
461 if(ctx->c_message->m_prev)
462 ctx->c_message->m_prev->m_next = ctx->c_message->m_next;
463 if(ctx->c_message->m_next)
464 ctx->c_message->m_next->m_prev = ctx->c_message->m_prev;
465 if(ctx->c_message == ctx->c_vat->v_msgq_head)
466 ctx->c_vat->v_msgq_head = ctx->c_message->m_next;
467 if(ctx->c_message == ctx->c_vat->v_msgq_tail)
468 ctx->c_vat->v_msgq_tail = ctx->c_message->m_prev;
469 ctx->c_message->m_prev = NULL;
470 ctx->c_message->m_next = NULL;
472 /* Mark object as being executed. */
473 ctx->c_message->m_target->o_flags |= OF_EXECUTING;
475 /* Set fields. */
476 ctx->c_stacktop = NULL;
477 ctx->c_ip = 0;
478 ctx->c_numreg = 0;
479 ctx->c_alt_flag = 0;
480 for(size_t i = 0; i < ctx->c_vat->v_max_locals; i++)
481 ctx->c_locals[i] = NULL;
483 mutex_unlock(&ctx->c_lock);
484 mutex_unlock(&ctx->c_vat->v_msgq_lock);
485 return 1;
488 /*****************************************************************************/
489 static void unprepare_context(struct context* ctx)
491 /* Grab message queue lock and context lock. */
492 mutex_lock(&ctx->c_vat->v_msgq_lock);
493 mutex_lock(&ctx->c_lock);
495 ctx->c_message->m_target->o_flags &= ~OF_EXECUTING;
497 /* Kill the message. It is now handled. */
498 free(ctx->c_message);
500 /* Kill all the locals. */
501 for(size_t i = 0; i < ctx->c_vat->v_max_locals; i++)
502 ctx->c_locals[i] = NULL;
503 /* Kill stack. */
504 while(ctx->c_stacktop)
505 pop_stack(ctx);
507 mutex_unlock(&ctx->c_lock);
508 mutex_unlock(&ctx->c_vat->v_msgq_lock);
512 /*****************************************************************************/
513 static void singlestep_context(struct context* ctx, struct message* msg,
514 struct object* t, struct class* tc)
516 struct object* tmp1;
517 struct object* tmp2;
518 struct stack* tmp3;
519 struct message* tmp4;
520 struct class* tmp5;
521 size_t parameters;
522 size_t fields;
524 /* Grab context lock. */
525 mutex_lock(&ctx->c_lock);
527 if(ctx->c_alt_flag) {
528 switch(tc->c_body[ctx->c_ip]) {
529 case 'f':
530 case 'F':
531 case 'l':
532 case 'L':
533 case 'p':
534 case 'P':
535 case 's':
536 case 'S':
537 case 'N':
538 /* Just clear the alternative mode. */
539 ctx->c_alt_flag = 0;
540 ctx->c_ip++;
541 mutex_unlock(&ctx->c_lock);
542 return;
546 switch(tc->c_body[ctx->c_ip]) {
547 case '\\':
548 while(1) {
549 if(ctx->c_ip >= tc->c_body_length)
550 break;
551 if(!sane_isspace(tc->c_body[ctx->c_ip]))
552 break;
553 ctx->c_ip++;
555 break;
556 case '+':
557 ctx->c_numreg++;
558 break;
559 case '-':
560 ctx->c_numreg--;
561 break;
562 case 'E':
563 tmp1 = pop_stack(ctx);
564 tmp2 = pop_stack(ctx);
565 if(tmp1 != tmp2)
566 ctx->c_alt_flag = 1;
567 break;
568 case 'f':
569 tmp1 = pop_stack(ctx);
570 if(ctx->c_numreg < tc->c_fields)
571 t->o_fields[ctx->c_numreg] = tmp1;
572 break;
573 case 'F':
574 if(ctx->c_numreg < tc->c_fields)
575 tmp1 = t->o_fields[ctx->c_numreg];
576 else
577 tmp1 = NULL;
578 push_stack(ctx, tmp1);
579 break;
580 case 'l':
581 tmp1 = pop_stack(ctx);
582 if(ctx->c_numreg < tc->c_locals)
583 ctx->c_locals[ctx->c_numreg] = tmp1;
584 break;
585 case 'L':
586 if(ctx->c_numreg < tc->c_locals)
587 tmp1 = ctx->c_locals[ctx->c_numreg];
588 else
589 tmp1 = NULL;
590 push_stack(ctx, tmp1);
591 break;
592 case 'p':
593 tmp1 = pop_stack(ctx);
594 if(ctx->c_numreg < msg->m_parameter_count)
595 msg->m_parameters[ctx->c_numreg] = tmp1;
596 break;
597 case 'P':
598 if(ctx->c_numreg < msg->m_parameter_count)
599 tmp1 = msg->m_parameters[ctx->c_numreg];
600 else
601 tmp1 = NULL;
602 push_stack(ctx, tmp1);
603 break;
604 case 's':
605 tmp1 = pop_stack(ctx);
606 if(!tmp1)
607 break;
608 parameters = 0;
609 tmp3 = ctx->c_stacktop;
610 while(tmp3) {
611 parameters++;
612 tmp3 = tmp3->s_next;
614 /* Allocate it. */
615 tmp4 = malloc(sizeof(struct message) + parameters *
616 sizeof(struct object*));
617 if(!tmp4) {
618 fprintf(stderr, "Out of memory!\n");
619 exit(1);
621 tmp4->m_target = tmp1;
622 tmp4->m_prev = NULL;
623 tmp4->m_next = NULL;
624 tmp4->m_parameter_count = parameters;
625 for(size_t i = 0; i < parameters; i++)
626 tmp4->m_parameters[i] = pop_stack(ctx);
627 queue_message(ctx->c_vat, tmp4);
628 break;
629 case 'S':
630 push_stack(ctx, t);
631 break;
632 case 'N':
633 fields = 0;
634 tmp5 = search_class(ctx->c_numreg);
635 if(tmp5)
636 fields = tmp5->c_fields;
637 tmp1 = malloc(sizeof(struct object) + fields *
638 sizeof(struct object*));
639 if(!tmp1) {
640 fprintf(stderr, "Out of memory!\n");
641 exit(1);
643 tmp1->o_flags = 0;
644 tmp1->o_class = tmp5;
645 tmp1->o_special = NULL;
646 tmp1->o_prev = NULL;
647 tmp1->o_next = ctx->c_vat->v_object_list;
648 ctx->c_vat->v_object_list->o_prev = tmp1;
649 ctx->c_vat->v_object_list = tmp1;
650 for(size_t i = 0; i < fields; i++)
651 tmp1->o_fields[i] = NULL;
652 push_stack(ctx, tmp1);
653 break;
654 default:
655 /* Can't happen! */
658 ctx->c_ip++;
659 mutex_unlock(&ctx->c_lock);
662 /*****************************************************************************/
663 static unsigned execute_msghandler(struct context* ctx)
666 if(!prepare_context(ctx))
667 return 0;
669 struct message* m = ctx->c_message;
670 struct object* t = m->m_target;
671 struct class* tc = t->o_class;
673 if(t->o_special) {
674 t->o_special(ctx, m);
675 unprepare_context(ctx);
676 return 1;
677 } else if(!tc) {
678 /* Should not happen... */
679 unprepare_context(ctx);
680 return 1;
683 while(ctx->c_ip < tc->c_body_length) {
684 singlestep_context(ctx, m, t, tc);
687 unprepare_context(ctx);
688 return 1;
692 /*****************************************************************************/
693 static void push_stack(struct context* ctx, struct object* obj)
695 struct stack* newslot = malloc(sizeof(struct stack));
696 if(!newslot) {
697 fprintf(stderr, "Out of memory!\n");
698 exit(1);
700 newslot->s_next = ctx->c_stacktop;
701 newslot->s_object = obj;
702 ctx->c_stacktop = newslot;
705 /*****************************************************************************/
706 static void queue_message(struct vat* vat, struct message* message)
708 struct message* prev = vat->v_msgq_tail;
710 if(vat->v_msgq_tail) {
711 vat->v_msgq_tail = vat->v_msgq_tail->m_next = message;
712 } else {
713 vat->v_msgq_tail = vat->v_msgq_head = message;
716 struct message* itr = message;
717 while(itr) {
718 vat->v_msgq_tail = itr;
719 itr->m_prev = prev;
720 prev = itr;
721 itr = itr->m_next;
725 /*****************************************************************************/
726 static void recursive_mark_live(struct object* object)
728 /* Don't recurse twice to same object. */
729 if(!object || !(object->o_flags & OF_MARKED_FOR_GC))
730 return;
732 /* Clear the gc flag. */
733 object->o_flags &= ~OF_MARKED_FOR_GC;
735 /* These are pretty special. */
736 if(!object->o_class)
737 return;
739 /* Recurse. */
740 for(size_t i = 0; i < object->o_class->c_fields; i++)
741 recursive_mark_live(object->o_fields[i]);
744 /*****************************************************************************/
745 static void mark_messages_live(struct message* queue)
747 while(queue) {
748 recursive_mark_live(queue->m_target);
749 for(size_t i = 0; i < queue->m_parameter_count; i++)
750 recursive_mark_live(queue->m_parameters[i]);
751 queue = queue->m_next;
755 /*****************************************************************************/
756 static unsigned perform_gc(struct vat* vat)
758 struct object* object = vat->v_object_list;
759 struct object* tmp;
761 while(object) {
762 object->o_flags |= OF_MARKED_FOR_GC;
763 object = object->o_next;
765 mark_messages_live(vat->v_msgq_head);
767 object = vat->v_object_list;
768 while(object) {
769 if((object->o_flags & OF_MARKED_FOR_GC) == 0) {
770 object = object->o_next;
771 break;
774 tmp = object;
775 object = object->o_next;
776 if(tmp->o_prev)
777 tmp->o_prev->o_next = tmp->o_next;
778 if(tmp->o_next)
779 tmp->o_next->o_prev = tmp->o_prev;
780 if(vat->v_object_list == tmp)
781 vat->v_object_list = tmp->o_next;
782 free(tmp);
785 return (vat->v_object_list != NULL);
789 /*****************************************************************************/
790 struct object capfuck_dummy = {
791 0, /* No flags. */
792 NULL, /* No class. */
793 NULL, /* Handler. */
794 NULL, /* Prev. */
795 NULL, /* Next. */
799 /*****************************************************************************/
800 void capfuck_stdin_h(struct context* ctx, struct message* msg)
802 if(msg->m_parameter_count == 0 || !msg->m_parameters[0])
803 return;
805 struct message* message = malloc(sizeof(struct message) + 9 *
806 sizeof(struct object*));
807 message->m_next = NULL;
808 message->m_parameter_count = 9;
809 message->m_target = msg->m_parameters[0];
810 int c = getchar();
812 if(c == -1) {
813 for(unsigned i = 0; i < 9; i++)
814 message->m_parameters[i] = NULL;
815 } else {
816 message->m_parameters[0] = &capfuck_dummy;
817 for(unsigned i = 0; i < 8; i++)
818 message->m_parameters[i + 1] = ((c >> (7 - i)) & 1) ?
819 &capfuck_dummy : NULL;
821 queue_message(ctx->c_vat, message);
824 /*****************************************************************************/
825 void capfuck_stdout_h(struct context* ctx, struct message* msg)
827 unsigned char value = 0;
828 for(unsigned i = 0; i < 8; i++)
829 if(msg->m_parameter_count > i && msg->m_parameters[i])
830 value = value * 2 + 1;
831 else
832 value = value * 2;
834 fprintf(stdout, "%c", value);
837 /*****************************************************************************/
838 void capfuck_stderr_h(struct context* ctx, struct message* msg)
840 unsigned char value = 0;
841 for(unsigned i = 0; i < 8; i++)
842 if(msg->m_parameter_count > i && msg->m_parameters[i])
843 value = value * 2 + 1;
844 else
845 value = value * 2;
847 fprintf(stdout, "%c", value);
850 /*****************************************************************************/
851 int main(int argc, char** argv)
853 int x;
854 struct parser parser;
855 parser.p_line = 1;
856 parser.p_status = PS_INITIAL;
857 parser.p_status2 = PS2_INITIAL;
858 parser.p_backslash = 0;
859 parser.p_classnum = 0;
860 parser.p_fields = 0;
861 parser.p_locals = 0;
862 parser.p_maxlocals = 0;
863 parser.p_ins_allocated = 0;
864 parser.p_ins_size = 0;
865 parser.p_ins = NULL;
866 parser.p_field = 0;
867 parser.p_have_field_value = 0;
868 FILE* input;
870 input = fopen(argv[1], "rb");
871 if(input == NULL) {
872 fprintf(stderr, "Can't open output file \"%s\".\n",
873 argv[1]);
874 return 1;
876 while((x = fgetc(input)) >= 0) {
877 parse_input(&parser, (char)x);
879 parse_eof(&parser);
880 fclose(input);
882 struct class* class = search_class(0);
883 if(!class) {
884 fprintf(stderr, "No classes defined.\n");
885 exit(1);
887 struct object* object = malloc(sizeof(struct object) +
888 class->c_fields * sizeof(struct object*));
889 struct message* message = malloc(sizeof(struct message) +
890 3 * sizeof(struct object*));
891 struct vat* vat = malloc(sizeof(struct vat));
892 struct context* context = malloc(sizeof(struct context) +
893 parser.p_maxlocals * sizeof(struct object*));
894 struct object* capfuck_stdin = malloc(sizeof(struct object));
895 struct object* capfuck_stdout = malloc(sizeof(struct object));
896 struct object* capfuck_stderr = malloc(sizeof(struct object));
898 if(!object || !message || !vat || !context || !capfuck_stdin ||
899 !capfuck_stdout || !capfuck_stderr) {
900 fprintf(stderr, "Out of memory.\n");
901 return 1;
904 /* Initialize fields. */
905 object->o_flags = 0;
906 object->o_class = class;
907 object->o_special = NULL;
908 object->o_prev = NULL;
909 object->o_next = capfuck_stdin;
910 for(size_t i = 0; i < class->c_fields; i++)
911 object->o_fields[i] = NULL;
912 capfuck_stdin->o_flags = 0;
913 capfuck_stdin->o_class = NULL;
914 capfuck_stdin->o_special = capfuck_stdin_h;
915 capfuck_stdin->o_prev = object;
916 capfuck_stdin->o_next = capfuck_stdout;
917 capfuck_stdout->o_flags = 0;
918 capfuck_stdout->o_class = NULL;
919 capfuck_stdout->o_special = capfuck_stdout_h;
920 capfuck_stdout->o_prev = capfuck_stdin;
921 capfuck_stdout->o_next = capfuck_stderr;
922 capfuck_stderr->o_flags = 0;
923 capfuck_stderr->o_class = NULL;
924 capfuck_stderr->o_special = capfuck_stderr_h;
925 capfuck_stderr->o_prev = capfuck_stdout;
926 capfuck_stderr->o_next = NULL;
927 message->m_target = object;
928 message->m_next = NULL;
929 message->m_parameter_count = 3;
930 message->m_parameters[0] = capfuck_stdin;
931 message->m_parameters[1] = capfuck_stdout;
932 message->m_parameters[2] = capfuck_stderr;
933 vat->v_object_list = object;
934 vat->v_msgq_head = NULL;
935 vat->v_msgq_tail = NULL;
936 vat->v_max_locals = parser.p_maxlocals;
937 queue_message(vat, message);
938 context->c_vat = vat;
939 context->c_stacktop = NULL;
940 context->c_ip = 0;
941 context->c_numreg = 0;
942 context->c_alt_flag = 0;
943 for(size_t i = 0; i < vat->v_max_locals; i++)
944 context->c_locals[i] = NULL;
946 while(1) {
947 if(vat->v_msgq_head)
948 execute_msghandler(context);
949 mutex_lock(&context->c_lock);
950 if(!vat->v_msgq_head && !perform_gc(vat))
951 break;
952 mutex_unlock(&context->c_lock);
955 mutex_unlock(&context->c_lock);
956 free(vat);
957 free(context);
959 /* Free the classes. */
960 while(c_list_head) {
961 class = c_list_head;
962 c_list_head = c_list_head->c_next;
963 free(class->c_body);
964 free(class);
966 fflush(stdout);
967 return 0;