alec

Abstraction Layer for Escape Codes
git clone git://git.dimitrijedobrota.com/alec.git
Log | Files | Refs | README | LICENSE

generator.c (6589B)


      1 #include "generator.h"
      2 #include "parser.h"
      3 
      4 #define MALLOC(x)                                                                                            \
      5     do {                                                                                                     \
      6         x = malloc(sizeof(*x));                                                                              \
      7         if (!x) yyerror("out of space"), exit(1);                                                            \
      8     } while (0);
      9 
     10 #ifdef YYDEBUG
     11 int yydebug = 1;
     12 #endif
     13 
     14 list_t records = {0};
     15 list_t epilogue = {0};
     16 list_t prologue = {0};
     17 
     18 int main(const int argc, char *argv[]) {
     19     if (argc < 2) {
     20         yyparse();
     21         return 0;
     22     }
     23 
     24     for (int i = 1; i < argc; i++) {
     25         FILE *f = fopen(argv[i], "r");
     26         if (!f) {
     27             perror(argv[1]);
     28             return -1;
     29         }
     30 
     31         yyrestart(f);
     32         yyparse();
     33 
     34         fclose(f);
     35     }
     36 
     37     // print prologue section
     38     for (node_t *p = prologue.head; p; p = p->next) {
     39         printf("%s", p->data);
     40     }
     41 
     42     list_t dupes = {0};
     43     record_dupes(&dupes, &records);
     44 
     45     printf("\n/* Template compile-time variables */\n\n");
     46     record_print_dupes(&dupes);
     47     for (node_t *p = records.head; p; p = p->next) {
     48         const record_t *r = (const record_t *)p->data;
     49         record_print_template(r, list_find(&dupes, r->name, scmp));
     50     }
     51 
     52     printf("\n/* Run-time functions */\n\n");
     53     for (node_t *p = records.head; p; p = p->next) {
     54         const record_t *r = (const record_t *)p->data;
     55         record_print_function(r);
     56     }
     57 
     58     // print epilogue section
     59     for (node_t *p = epilogue.head; p; p = p->next) {
     60         printf("%s", p->data);
     61     }
     62 
     63     list_free(&dupes, 0);
     64 
     65     list_free(&prologue, free);
     66     list_free(&records, record_free);
     67     list_free(&epilogue, free);
     68 
     69     yylex_destroy();
     70 }
     71 
     72 node_t *node_new(char *data) {
     73     node_t *n;
     74 
     75     MALLOC(n);
     76     *n = (node_t){
     77         .data = data,
     78         .next = NULL,
     79     };
     80 
     81     return n;
     82 }
     83 
     84 list_t *list_new(char *data) {
     85     list_t *l;
     86 
     87     MALLOC(l);
     88     *l = (list_t){0};
     89     if (data) list_append(l, node_new(data));
     90 
     91     return l;
     92 }
     93 
     94 void list_free(list_t *l, void (*free_data)(void *)) {
     95     if (!l) return;
     96 
     97     node_t *c = l->head, *t;
     98     while (c) {
     99         t = c;
    100         c = c->next;
    101         if (free_data) free_data((void *)t->data);
    102         free(t);
    103     }
    104 }
    105 
    106 void list_append(list_t *l, node_t *n) {
    107     if (!l->head) l->head = l->tail = n;
    108     else
    109         l->tail = l->tail->next = n;
    110 }
    111 
    112 record_t *record_new(char *name, list_t *args, list_t *rules, list_t *recipe) {
    113     record_t *rec;
    114 
    115     MALLOC(rec);
    116     *rec = (record_t){
    117         .name = name,
    118         .args = args,
    119         .rules = rules,
    120         .recipe = recipe,
    121     };
    122 
    123     return rec;
    124 }
    125 
    126 void record_free(void *rp) {
    127     record_t *r = (record_t *)rp;
    128     if (r->args) list_free(r->args, free), free(r->args);
    129     if (r->rules) list_free(r->rules, free), free(r->rules);
    130     if (r->recipe) list_free(r->recipe, free), free(r->recipe);
    131     free(r->name);
    132     free(r);
    133 }
    134 
    135 int list_find(list_t *l, void *data, cmp_f cmp) {
    136     node_t *c = l->head;
    137     while (c) {
    138         if (!cmp(c->data, data)) return 1;
    139         c = c->next;
    140     }
    141     return 0;
    142 }
    143 
    144 void record_print_dupes(const list_t *l) {
    145     node_t *c = l->head;
    146     while (c) {
    147         printf("template <auto... val> static const char *%s_v;\n", c->data);
    148         c = c->next;
    149     }
    150     printf("\n");
    151 }
    152 
    153 void record_print_function(const record_t *r) {
    154     list_t dummy = {0};
    155 
    156     if (!r->recipe) { // comment
    157         printf("%s\n\n", r->name);
    158         return;
    159     }
    160 
    161     printf("static constexpr auto %s(", r->name);
    162     if (r->args) {
    163         for (node_t *p = r->args->head; p; p = p->next) {
    164             list_append(&dummy, node_new(strchr(p->data, ' ') + 1));
    165             printf("%s", p->data);
    166             if (p->next) printf(", ");
    167         }
    168     }
    169     printf(") {\n");
    170 
    171     if (r->rules) {
    172         for (node_t *p = dummy.head; p; p = p->next) {
    173             printf("\tassert(");
    174             for (node_t *q = r->rules->head; q; q = q->next) {
    175                 printf("%s(%s)", q->data, p->data);
    176                 if (q->next) printf(" && ");
    177             }
    178             printf(");\n");
    179         }
    180     }
    181 
    182     if (r->args) {
    183         printf("\treturn details::helper::make(");
    184         for (node_t *p = r->recipe->head; p; p = p->next) {
    185             printf("%s", p->data);
    186             if (p->next) printf(", ");
    187         }
    188         printf(")");
    189     } else {
    190         printf("\treturn %s_v", r->name);
    191     }
    192     printf(";\n}\n\n");
    193 
    194     list_free(&dummy, NULL);
    195 }
    196 
    197 void record_print_template(const record_t *r, int dup) {
    198     list_t dummy = {0};
    199 
    200     if (!r->recipe) { // comment
    201         printf("%s\n\n", r->name);
    202         return;
    203     }
    204 
    205     if (r->args) {
    206         printf("template <");
    207         for (node_t *p = r->args->head; p; p = p->next) {
    208             list_append(&dummy, node_new(strchr(p->data, ' ') + 1));
    209             printf("%s", p->data);
    210             if (p->next) printf(", ");
    211         }
    212         printf(">\n");
    213     }
    214 
    215     if (r->rules) {
    216         printf("\trequires ");
    217         for (node_t *p = dummy.head; p; p = p->next) {
    218             for (node_t *q = r->rules->head; q; q = q->next) {
    219                 printf("%s_v<%s>", q->data, p->data);
    220                 if (q->next) printf(" && ");
    221             }
    222             if (p->next) printf(" && ");
    223         }
    224         printf("\n");
    225     }
    226 
    227     printf("static constexpr auto %s_v", r->name);
    228     if (dup) {
    229         printf("<");
    230         for (node_t *p = dummy.head; p; p = p->next) {
    231             printf("%s", p->data);
    232             if (p->next) printf(", ");
    233         }
    234         printf(">");
    235     }
    236 
    237     if (r->recipe->head && r->recipe->head->data[0] == '"') {
    238         printf("\n\t = details::escape_literal<%s>;", r->recipe->head->data);
    239     } else {
    240         printf("\n\t = details::escape<");
    241         for (node_t *p = r->recipe->head; p; p = p->next) {
    242             printf("%s", p->data);
    243             if (p->next) printf(", ");
    244         }
    245         printf(">;");
    246     }
    247     printf("\n\n");
    248 
    249     list_free(&dummy, NULL);
    250 }
    251 
    252 int scmp(const void *a, const void *b) { return strcmp((const char *)a, (const char *)b); }
    253 
    254 void record_dupes(list_t *d, list_t *l) {
    255     list_t s = {0};
    256 
    257     for (node_t *p = records.head; p; p = p->next) {
    258         const record_t *r = (const record_t *)p->data;
    259         if (!list_find(&s, r->name, scmp)) list_append(&s, node_new(r->name));
    260         else if (!list_find(d, r->name, scmp))
    261             list_append(d, node_new(r->name));
    262     }
    263 
    264     list_free(&s, NULL);
    265 }