#include #include #include #include #include "apfl.h" enum repl_mode { REPL_TOKENIZER, REPL_PARSER, REPL_EVAL, }; static bool repl_source_reader(void *context, char *buf, size_t *len, bool need) { (void)context; printf(need ? "... " : "> "); fflush(stdout); size_t maxlen = *len; if (fgets(buf, maxlen, stdin) == NULL) { if (feof(stdin)) { *len = 0; return true; } else { return false; } } *len = strlen(buf); return true; } static int repl_tokenizer(apfl_tokenizer_ptr tokenizer) { while (true) { struct apfl_error err; struct apfl_token token; switch (apfl_tokenizer_next(tokenizer, false)) { case APFL_PARSE_OK: token = apfl_tokenizer_get_token(tokenizer); apfl_token_print(token, stdout); apfl_token_deinit(&token); break; case APFL_PARSE_EOF: return 0; case APFL_PARSE_ERROR: err = apfl_tokenizer_get_error(tokenizer); apfl_error_print(err, stderr); if (APFL_ERROR_IS_FATAL(err)) { return 1; } break; } } } static bool repl_parser_generic(apfl_parser_ptr parser, struct apfl_expr *expr, int *rv) { while (true) { struct apfl_error err; switch (apfl_parser_next(parser)) { case APFL_PARSE_OK: *expr = apfl_parser_get_expr(parser); return true; case APFL_PARSE_EOF: *rv = 0; return false; case APFL_PARSE_ERROR: err = apfl_parser_get_error(parser); apfl_error_print(err, stderr); if (APFL_ERROR_IS_FATAL(err)) { *rv = 1; return false; } break; } } } static int repl_parser(apfl_parser_ptr parser) { struct apfl_expr expr; int rv; while (repl_parser_generic(parser, &expr, &rv)) { apfl_expr_print(expr, stdout); apfl_expr_deinit(&expr); } return rv; } static int repl_eval(apfl_parser_ptr parser, apfl_ctx ctx) { struct apfl_expr expr; int rv; while (repl_parser_generic(parser, &expr, &rv)) { struct apfl_result result = apfl_eval(ctx, expr); switch (result.type) { case APFL_RESULT_OK: apfl_value_print(result.value, stdout); apfl_value_deinit(&result.value); break; case APFL_RESULT_ERR: fprintf(stderr, "Error occurred during evaluation.\n"); break; case APFL_RESULT_ERR_FATAL: fprintf(stderr, "Fatal error occurred during evaluation.\n"); return 1; } } return rv; } int main(int argc, const char **argv) { int rv = 0; enum repl_mode mode = REPL_PARSER; if (argc > 1) { if (apfl_string_eq(argv[1], "tokenizer")) { mode = REPL_TOKENIZER; } else if (apfl_string_eq(argv[1], "parser")) { mode = REPL_PARSER; } else if (apfl_string_eq(argv[1], "eval")) { mode = REPL_EVAL; } else { fprintf(stderr, "Unknown mode: %s\n", argv[1]); return 1; } } apfl_tokenizer_ptr tokenizer = NULL; apfl_parser_ptr parser = NULL; apfl_ctx ctx = NULL; if ((tokenizer = apfl_tokenizer_new(repl_source_reader, NULL)) == NULL) { fprintf(stderr, "Failed initializing tokenizer\n"); rv = 1; goto exit; } if (mode >= REPL_PARSER) { if ((parser = apfl_parser_new(apfl_tokenizer_as_token_source(tokenizer))) == NULL) { fprintf(stderr, "Failed initializing parser\n"); rv = 1; goto exit; } } if (mode >= REPL_EVAL) { if ((ctx = apfl_ctx_new()) == NULL) { fprintf(stderr, "Failed initializing context\n"); rv = 1; goto exit; } } switch (mode) { case REPL_TOKENIZER: rv = repl_tokenizer(tokenizer); break; case REPL_PARSER: rv = repl_parser(parser); break; case REPL_EVAL: rv = repl_eval(parser, ctx); break; } exit: apfl_tokenizer_destroy(tokenizer); apfl_parser_destroy(parser); apfl_ctx_destroy(ctx); return rv; }