#include #include #include #include "badlib.h" #include "lexer.c" #include "parser.c" typedef enum ExecMode { RUN_NORMAL, PRINT_LEX, PRINT_PARSE, PRINT_SEMANTIC, PRINT_SYMTABLES, } ExecMode; static ExecMode mode = RUN_NORMAL; void init(void) { log_init_default(); } void process_file(Str path) { Arena lexer_arena = arena_create(LEXER_MEM, os_allocator); FileContents file = platform_read_file(path, &lexer_arena); if (file.err) { eprintln("%s: error: %s", path, cstr("WOT")); exit(EXIT_FAILURE); } sz errors = 0; // Lexer. Scanner scanner = {.str = file.data}; Token *tokens = NULL; Token tok = {0}; while (tok.kind != TOK_EOF) { tok = scan_token(&scanner); if (tok.kind == TOK_UNKNOWN) { eprintln("%s:%d:%d:%s %s", path, tok.line, tok.col, token_str[tok.kind], tok.val); errors++; continue; } array_push(tokens, tok, &lexer_arena); } // Only proceed if there are no errors. if (errors) { exit(EXIT_FAILURE); } if (mode == PRINT_LEX) { print_tokens(path, tokens); goto stop; } // Parser. Parser parser = { .tokens = tokens, .storage = &lexer_arena, .file_name = path, }; array_init(parser.nodes, 256, parser.storage); parse_advance(&parser); while (parser.current.kind != TOK_EOF) { #if DEBUG == 1 static sz ctr = 0; println("parsing root: %d", ctr++); #endif parse_expr(&parser, PREC_LOW); if (parser.panic) { break; } } if (parser.err) { exit(EXIT_FAILURE); } if (mode == PRINT_PARSE) { graph_ast(parser.nodes); goto stop; } sz n_roots = array_size(parser.nodes); for (sz i = 0; i < n_roots; i++) { // The parser stores the root nodes as a stack. Node *root = parser.nodes[i]; (void)root; } parse_consume(&parser, TOK_EOF, cstr("expected end of file")); stop: // Free up resources. arena_destroy(&lexer_arena, os_allocator); } #ifndef BIN_NAME #define BIN_NAME "bdl" #endif void print_usage(void) { printf("Usage: %s [options] \n", BIN_NAME); printf("\n"); printf("\t-h \t\tShow usage.\n"); printf( "\t-p [l|p|s|t]\tPrint mode for [l]exing, [p]arsing, " "[s]emantic " "analysis, symbol [t]ables\n"); printf("\n"); } int main(int argc, char *argv[]) { int option; while ((option = getopt(argc, argv, "hp:")) != -1) { switch (option) { case 'h': { print_usage(); goto exit_success; } break; case 'p': { if (optarg[0] == 'l' && optarg[1] == '\0') { mode = PRINT_LEX; } else if (optarg[0] == 'p' && optarg[1] == '\0') { mode = PRINT_PARSE; } else if (optarg[0] == 's' && optarg[1] == '\0') { mode = PRINT_SEMANTIC; } else if (optarg[0] == 't' && optarg[1] == '\0') { mode = PRINT_SYMTABLES; } else { print_usage(); return EXIT_FAILURE; } } break; default: { print_usage(); return EXIT_FAILURE; } break; } } init(); // Run from stdin. if (optind == argc) { // TODO: REPL // repl(); goto exit_success; } // Run from file. while (optind < argc) { char *file_name = argv[optind]; Str file_path = STR(file_name); process_file(file_path); optind++; } exit_success: return EXIT_SUCCESS; }