#include #include #include #include #include #include "shorthand.h" #include "string_view.c" #include "readline.c" #include "lexer.c" #include "objects.c" #include "parser.c" #include "environment.c" #include "primitives.c" // FIXME: We are not worried right now about freeing memory, but we should in // the future. // TODO: Better error messages. #define REPL_PROMPT "bdl> " void init(void) { // Clear env. for (size_t i = 0; i < ENV_SIZE; i++) { environment[i] = (EnvSymbol){0}; } // Initialize singletons. obj_nil = make_empty_list(); obj_true = make_boolean(true); obj_false = make_boolean(false); // Add primitive functions. environment[env_n++] = (EnvSymbol){MAKE_SYM("+"), make_procedure(proc_add)}; environment[env_n++] = (EnvSymbol){MAKE_SYM("-"), make_procedure(proc_sub)}; environment[env_n++] = (EnvSymbol){MAKE_SYM("*"), make_procedure(proc_mul)}; environment[env_n++] = (EnvSymbol){MAKE_SYM("/"), make_procedure(proc_div)}; environment[env_n++] = (EnvSymbol){MAKE_SYM("boolean?"), make_procedure(proc_is_boolean)}; environment[env_n++] = (EnvSymbol){MAKE_SYM("not"), make_procedure(proc_not)}; environment[env_n++] = (EnvSymbol){MAKE_SYM("and"), make_procedure(proc_and)}; environment[env_n++] = (EnvSymbol){MAKE_SYM("or"), make_procedure(proc_or)}; environment[env_n++] = (EnvSymbol){MAKE_SYM("if"), make_procedure(proc_if)}; environment[env_n++] = (EnvSymbol){MAKE_SYM("else"), obj_true}; environment[env_n++] = (EnvSymbol){MAKE_SYM("cond"), make_procedure(proc_cond)}; environment[env_n++] = (EnvSymbol){MAKE_SYM("display"), make_procedure(proc_display)}; environment[env_n++] = (EnvSymbol){MAKE_SYM("print"), make_procedure(proc_print)}; } void eval_line(FILE *fd, char delimiter) { StringView line = read_line(fd, delimiter); Tokens tokens = tokenize(line); #if DEBUG printf("N_TOKENS: %ld\n", tokens.n); for (size_t i = 0; i < tokens.n; i++) { printf("\tTYPE: %3d ", tokens.start[i].type); printf("N: %3ld ", tokens.start[i].value.n); printf("VALUE: "); sv_write(tokens.start[i].value); printf("\n"); } #endif while (tokens.n > 0) { Object *ast = parse(&tokens); if (ast) { #if DEBUG printf("AST: "); display(ast); printf("\n"); printf("EVAL: "); #endif if (display(eval(ast))) { printf("\n"); }; } } } void run_repl(void) { printf("BDL REPL (Press Ctrl-C to exit)\n"); while (true) { printf(REPL_PROMPT); eval_line(stdin, '\n'); } } void run_file(char *file_name) { #if DEBUG printf("Executing file: %s\n", file_name); #endif FILE *fd = fopen(file_name, "r"); if (!fd) { fprintf(stderr, "couldn't open file: %s\n", file_name); exit(EXIT_FAILURE); } eval_line(fd, EOF); fclose(fd); } void print_usage(void) { printf("Usage: %s [options] \n", BIN_NAME); printf("\n"); printf("\t-i\tInteractive mode (REPL).\n"); printf("\t-x\tExecute expression from stdin.\n"); printf("\n"); } int main(int argc, char *argv[]) { init(); int option; while ((option = getopt(argc, argv, "ix")) != -1) { switch (option) { case 'i': { // Interactive mode. run_repl(); return EXIT_SUCCESS; } break; case 'x': { // Execute expression from stdin. eval_line(stdin, EOF); return EXIT_SUCCESS; } break; default: { print_usage(); return EXIT_FAILURE; } break; } } // Run from file. if (optind != argc - 1) { fprintf(stderr, "%s: No input file given.\n", BIN_NAME); print_usage(); return EXIT_FAILURE; } char *file_name = argv[optind]; run_file(file_name); return EXIT_SUCCESS; }