#include #include #include #include #include #define INPUT_CAP 4096 #define ARENA_CAP 4096*2 #define ARENA_IMPLEMENTATION #include "util/arena.h" static char buf[ARENA_CAP]; static struct arena_ctx global_arena; static void *xalloc(size_t sz) { void *addr = arena_allocate(&global_arena, sz); if(!addr) { fprintf(stderr, "ERROR: Arena empty\n"); exit(1); } return addr; } #include "parts/precedence.h" #include "util/list.h" static inline struct list_head *list_new_head(struct list_head *head, struct list_head *new) { if(head) list_add(new, head); return new; } struct ptr_entry { intptr_t data; struct list_head list; }; struct prec_entry { enum precedence_flag flag; struct list_head *ptrlist; struct list_head list; }; struct strnptr_entry { char *str; struct list_head *ptrlist; struct list_head list; }; #define new_entry(type, entry, __do__) \ { \ type *entry = xalloc(sizeof(type)); \ LIST_EMPTY(&entry->list); \ __do__; \ return &entry->list; \ } struct list_head *ptr_new(void *ptr) new_entry(struct ptr_entry, entry, { entry->data = (intptr_t)ptr; }) struct list_head *num_new(intmax_t num) new_entry(struct ptr_entry, entry, { entry->data = (num << 1) | 0x1; }) struct list_head *prec_new(struct list_head *idenlist, enum precedence_flag flag) new_entry(struct prec_entry, entry, { entry->ptrlist = idenlist; entry->flag = flag; }) struct list_head *action_new(struct list_head *idenlist, char *action) new_entry(struct strnptr_entry, entry, { entry->str = action; entry->ptrlist = idenlist; }) struct list_head *prod_new(char *iden, struct list_head *actionlist) new_entry(struct strnptr_entry, entry, { entry->str = iden; entry->ptrlist = actionlist; }) void handle_type(struct list_head *terminals, struct list_head *nonterminals) { printf("#include \"parts/symbol.h\"\n"); printf("enum symbol { "); list_for_each_entry(struct ptr_entry, entry, list, terminals) printf("%s, ", (char *)entry->data); printf("END_INPUT, "); list_for_each_entry(struct ptr_entry, entry, list, nonterminals) printf("%s, ", (char *)entry->data); printf("SYMBOLS_END };\n"); printf("size_t total_symbols = %zu;\n", list_len(terminals) + list_len(nonterminals) + 2); printf("char **symbol_to_str = (char *([])){ "); list_for_each_entry(struct ptr_entry, entry, list, terminals) printf("\"%s\", ", (char *)entry->data); printf("\"END_INPUT\","); list_for_each_entry(struct ptr_entry, entry, list, nonterminals) printf("\"%s\", ", (char *)entry->data); printf("\"SYMBOLS_END\" };\n"); printf("IMPLEMENT_FUNCPTR(int, symbol_is_terminal, (symbol s)) { return s < %s; }\n", (char *)container_of(nonterminals, struct ptr_entry, list)->data); printf("IMPLEMENT_FUNCPTR(int, symbol_is_input_end, (symbol s)) { return s == END_INPUT; }\n"); printf("IMPLEMENT_FUNCPTR(int, symbol_is_valid, (symbol s)) { return s < SYMBOLS_END; }\n"); } void handle_prec(struct list_head *preclist) { printf("#include \"parts/precedence.h\"\n"); printf("struct precedence_def {\n"); printf(" int flag;\n"); printf(" int *list;\n"); printf(" size_t nlist;\n"); printf("};\n"); if(!preclist) { printf("struct precedence_def *precedence_defs = NULL;\n"); printf("size_t nprecedence_defs = 0;\n"); return; } printf("struct precedence_def *precedence_defs = (struct precedence_def[]){\n"); list_for_each_entry(struct prec_entry, entry, list, preclist) { printf("{ %d, (int[]){", entry->flag); list_for_each_entry(struct ptr_entry, e, list, entry->ptrlist) if((e->data & 0x1) == 0) printf("%s, ", (char *)e->data); else printf("~%ju, ", e->data >> 1); printf("}, %zu}, ", list_len(entry->ptrlist)); } printf("};\n"); printf("size_t nprecedence_defs = %zu;\n", list_len(preclist)); } void handle_prod(struct list_head *prodlist) { size_t productions = 0; printf("#include \"parts/grammar.h\"\n"); printf("struct production *grammar = (struct production[]){\n"); list_for_each_entry(struct strnptr_entry, e1, list, prodlist) { if(productions == 0) list_add(list_get_tail(list_entry(e1->ptrlist, struct strnptr_entry, list)->ptrlist), ptr_new("END_INPUT")); productions += list_len(e1->ptrlist); list_for_each_entry(struct strnptr_entry, e2, list, e1->ptrlist) { printf("{%s, (symbol[]){ ", e1->str); list_for_each_entry(struct ptr_entry, e3, list, e2->ptrlist) printf("%s, ", (char *)e3->data); printf("}, %zu}, \n", list_len(e2->ptrlist)); } } printf("};\n"); printf("size_t total_productions = %zu;\n", productions); printf("char **semantic_action_str = (char *([])){"); list_for_each_entry(struct strnptr_entry, e1, list, prodlist) list_for_each_entry(struct strnptr_entry, e2, list, e1->ptrlist) printf("\"%s\", ", e2->str); // todo: escape the quotes printf("};\n"); } #define list_new_head(head, new) (intptr_t)list_new_head((struct list_head *)head, (struct list_head *)new) #define ptr_new(iden) (intptr_t)ptr_new((void *)iden) #define num_new(num) (intptr_t)num_new(num) #define prec_new(idenlist, flag) (intptr_t)prec_new((struct list_head *)idenlist, flag) #define action_new(idenlist, action) (intptr_t)action_new((struct list_head *)idenlist, (char *)action) #define prod_new(iden, actionlist) (intptr_t)prod_new((char *)iden, (struct list_head *)actionlist) #define handle_type(terminals, nonterminals) handle_type((struct list_head *)terminals, (struct list_head *)nonterminals); #define handle_prec(preclist) handle_prec((struct list_head *)preclist); #define handle_prod(prodlist) handle_prod((struct list_head *)prodlist); // generated #include "bin/gram.h" #include "bin/gram.c" #include "parts/toklist.h" struct token { symbol s; intptr_t v; } tok; static char *next_token(char *str); symbol token_sym(struct token *t) { return t->s; } intptr_t token_val(struct token *t) { return t->v; } static char *input; struct token *toklist_eat() { static struct token t; t = tok; input = next_token(input); return &t; } struct token *toklist_peek() { return &tok; } #include "lr-parser.c" int main(void) { static char input_buf[INPUT_CAP]; if(fread(input_buf, INPUT_CAP, 1, stdin) == INPUT_CAP) { fprintf(stderr, "INPUT_CAP reached\n"); return 1; } global_arena = ARENA_CTX_INIT(buf, ARENA_CAP); input = next_token(input_buf); intptr_t value; if(lr_parser(&value)) { fprintf(stderr, input); return 1; } fprintf(stderr, "OUTPUT: %jd\n", value); return 0; } // STR UTIL #define strdup(...) _strdup(__VA_ARGS__) static inline char *_strdup(char *str) { return memcpy(xalloc(strlen(str) + 1), str, strlen(str)+1); } static inline char *substring(char *str, size_t sub_end) { static char sub[128]; if(sub_end+1 > sizeof(sub)) return NULL; sub[sub_end] = '\0'; return memcpy(sub, str, sub_end); } // LEXER static inline int issep(char c) { return isspace(c) || c == '\0' || c == ':' || c == '|' || c == ';' || c == '.' || c == '-' || c == '{'; } static inline int tillsep(char *str) { size_t i = 0; while(!issep(str[i++])); return i-1; } static char *next_token(char *str) { if(!str) return str; size_t off = 0; char c0 = str[0]; if(c0 == '\0') tok.s = END_INPUT; if(isspace(c0)) return next_token(str+1); else { off = tillsep(str); if(off == 0) { // sep switch(str[off++]) { case ':': tok.s = COLON; break; case '|': tok.s = PIPE; break; case ';': tok.s = SEMICOL; break; case '.': tok.s = DOT; break; case '-': off = tillsep(++str); char *s = substring(str, off); if(strcmp(s, "terminal") == 0) tok.s = TERMINAL; else if(strcmp(s, "nonterminal") == 0) tok.s = NONTERM; else if(strcmp(s, "left") == 0) tok.s = LEFT; else if(strcmp(s, "right") == 0) tok.s = RIGHT; else if(strcmp(s, "noprec") == 0) tok.s = NOPREC; else { fprintf(stderr, "ERROR: Unknown directive '-%s'\n", s); goto fail; } break; case '{': for(int c = 1; c != 0; off++) if(str[off] == '\0') { fprintf(stderr, "ERROR: No closing '{'\n"); goto fail; } else if(str[off] == '{') c++; else if(str[off] == '}') c--; tok.s = ACTION; tok.v = (intptr_t)strdup(substring(str, off)); break; } } else if(isalpha(c0)) { // iden or named symbol tok.s = IDEN; tok.v = (intptr_t)strdup(substring(str, off)); } else if(c0 >= '0' && c0 <= '9') { // num tok.s = NUM; tok.v = (intptr_t)atoi(substring(str, off)); } } return str+off; fail: tok.s = END_INPUT; return NULL; }