interpreter

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

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_