/** * @file main.c * @brief The standalone driver. * * Everything that belongs to a program rather than to a library lives here: argv * handling, sink selection, the unbounded run loop, and the one FINISH_NORETURN * in the tree. The interpreter library itself never terminates the process. * * The runtime is static rather than automatic because it carries every pool the * interpreter owns -- several megabytes -- and that will not fit on a default * stack. An embedding game would place it in its own state for the same reason. */ #include #include #include #include #include #include #include static akbasic_Runtime RUNTIME; static akbasic_TextSink SINK; static akbasic_StdioSink SINKSTATE; int main(int argc, char **argv) { PREPARE_ERROR(errctx); FILE *program = NULL; int rc = EXIT_SUCCESS; ATTEMPT { if ( argc > 1 ) { /* * A file argument: read the program from it in RUNSTREAM mode, which * files each line under its line number and then switches to RUN. */ CATCH(errctx, aksl_fopen(argv[1], "r", &program)); CATCH(errctx, akbasic_sink_init_stdio(&SINK, &SINKSTATE, stdout, program)); CATCH(errctx, akbasic_runtime_init(&RUNTIME, &SINK)); CATCH(errctx, akbasic_runtime_start(&RUNTIME, AKBASIC_MODE_RUNSTREAM)); } else { CATCH(errctx, akbasic_sink_init_stdio(&SINK, &SINKSTATE, stdout, stdin)); CATCH(errctx, akbasic_runtime_init(&RUNTIME, &SINK)); CATCH(errctx, akbasic_runtime_start(&RUNTIME, AKBASIC_MODE_REPL)); } /* Unbounded: this is the driver, and it has nothing else to do. */ CATCH(errctx, akbasic_runtime_run(&RUNTIME, 0)); } CLEANUP { if ( program != NULL ) { IGNORE(aksl_fclose(program)); } } PROCESS(errctx) { } HANDLE_DEFAULT(errctx) { LOG_ERROR_WITH_MESSAGE(errctx, "akbasic terminated on an unhandled error"); rc = EXIT_FAILURE; } FINISH_NORETURN(errctx); return rc; }