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 }