parser.h (4716B)
1 #ifndef AWA_PARSER_H_ 2 #define AWA_PARSER_H_ 3 4 #include "common.h" 5 6 static void awa_skip_to_next_valid(awa_parser_t* parser) 7 { 8 while (!strchr(" AWaw\0", parser->awatalk[parser->pos])) parser->pos++; 9 } 10 11 // returns true on error 12 static bool awa_parse_bits(awa_parser_t* parser, uint8_t bits, uint8_t* out) 13 { 14 *out = 0; 15 16 for (int bit_iter = 0; bit_iter < bits; bit_iter++) { 17 const char* awa_values[2] = {" awa", "wa"}; 18 int awa_v = 0; 19 bool found = false; 20 21 for (; awa_v < 2; awa_v++) { 22 for (int i = 0; i < strlen(awa_values[awa_v]); i++) { 23 awa_skip_to_next_valid(parser); 24 if (tolower(parser->awatalk[parser->pos]) != awa_values[awa_v][i]) { 25 if (i == 0) goto continue_awa_v; 26 else goto break_awa_v; 27 } 28 parser->pos++; 29 } 30 found = true; 31 break; 32 continue_awa_v:; 33 } 34 break_awa_v:; 35 36 if (!found) { 37 awa_line_info_t line = awa_get_line_and_col(*parser); 38 if (parser->pos == parser->total_size) 39 awa_debug_printf("%d:%d error: awa parser reached end of input\n", line.line+1, line.col); 40 else 41 awa_debug_printf("%d:%d error: awa parser got unexpected input starting here\n", line.line+1, line.col); 42 awa_print_line(line); 43 for (int i = 0; i<line.col;i++) awa_debug_printf(" "); 44 awa_debug_printf("^~~\n"); 45 return true; 46 } 47 48 *out <<= 1; 49 *out |= awa_v; 50 } 51 52 return false; 53 } 54 55 static awa_program_t awatalk_to_program(char* awatalk_string, bool print_program) 56 { 57 awa_program_t res = {.source = awatalk_string}; 58 if (!awatalk_string) { 59 awa_debug_printf("awatalk string was null!\n"); 60 res.failed_parse = true; 61 return res; 62 } 63 64 awa_parser_t parser = { 65 .awatalk = awatalk_string, 66 .total_size = strlen(awatalk_string), 67 }; 68 69 const char* awa_start = "awa"; 70 for (int i = 0; i < 3; i++) { 71 awa_skip_to_next_valid(&parser); 72 if (tolower(parser.awatalk[parser.pos]) != awa_start[i]) { 73 awa_debug_printf("awatalk string does not start with \"awa\"!\n"); 74 res.failed_parse = true; 75 return res; 76 } 77 parser.pos++; 78 } 79 80 parser.pos = 3; 81 while (parser.pos < parser.total_size) { 82 awa_skip_to_next_valid(&parser); 83 awatism_t awatism = {.current_pos_bytes = parser.pos}; 84 bool opcode_err = awa_parse_bits(&parser, 5, &awatism.opcode); 85 if (opcode_err) { 86 awa_debug_printf("NOTE: awa parser error above happened while parsing an opcode\n"); 87 res.failed_parse = true; 88 break; 89 } 90 if (awatism_opcode_names[awatism.opcode] == NULL) { 91 awa_line_info_t line = awa_get_line_and_col((awa_parser_t){res.source, awatism.current_pos_bytes}); 92 awa_debug_printf("%d:%d error: opcode is invalid\n", line.line+1, line.col); 93 awa_print_line(line); 94 awa_debug_printf("^~~\n"); 95 res.failed_parse = true; 96 break; 97 } 98 bool parameter_err = awa_parse_bits(&parser, awatism_param_sizes_bits[awatism.opcode], &awatism.u8); 99 if (parameter_err) { 100 awa_debug_printf("NOTE: awa parser error above happened while parsing a paramter of %s\n", awatism_opcode_names[awatism.opcode]); 101 res.failed_parse = true; 102 break; 103 } 104 if (print_program) { 105 awa_print_awatism(awatism); awa_debug_printf("\n"); 106 } 107 awa_skip_to_next_valid(&parser); 108 109 awatism_t* n = malloc(sizeof(*n)); 110 *n = awatism; 111 llist_queue_push(res.awatism_first, res.awatism_last, n); 112 if (n->opcode == AWA_LABEL) 113 res.awalabel_table[n->u8] = n; 114 } 115 116 return res; 117 } 118 119 awa_program_t awatalk_file_to_program(const char* filename, bool print_program) { 120 char* buffer = 0; 121 FILE* fp = fopen(filename, "rb"); 122 size_t sz = 0; 123 if (fp) { 124 fseek(fp, 0, SEEK_END); 125 sz = ftell(fp); 126 fseek(fp, 0, SEEK_SET); 127 buffer = malloc(sz + 1); 128 if (buffer) fread(buffer, 1, sz, fp); 129 fclose(fp); 130 buffer[sz] = '\0'; 131 } else { 132 fprintf(stderr, "unable to open file %s: %s\n", filename, strerror(errno)); 133 } 134 return awatalk_to_program(buffer, print_program); 135 } 136 137 void awa_program_free(awa_program_t* prog) { 138 free(prog->source); 139 for (awatism_t *next, *a = prog->awatism_first; a; a = next) { 140 next = a->next; 141 free(a); 142 } 143 *prog = (awa_program_t){0}; 144 } 145 146 #endif // AWA_PARSER_H_