main.c: Add repl mode switching
You can now choose, if you want to play around with the tokenizer, parser or evaluator in the repl.
This commit is contained in:
parent
649607ce50
commit
b2c252fbc2
1 changed files with 136 additions and 28 deletions
164
src/main.c
164
src/main.c
|
|
@ -5,6 +5,12 @@
|
|||
|
||||
#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)
|
||||
{
|
||||
|
|
@ -28,55 +34,157 @@ repl_source_reader(void *context, char *buf, size_t *len, bool need)
|
|||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, const char **argv)
|
||||
static int
|
||||
repl_tokenizer(apfl_tokenizer_ptr tokenizer)
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
int rv = 0;
|
||||
|
||||
apfl_tokenizer_ptr tokenizer = NULL;
|
||||
apfl_parser_ptr parser = NULL;
|
||||
|
||||
if ((tokenizer = apfl_tokenizer_new(repl_source_reader, NULL)) == NULL) {
|
||||
fprintf(stderr, "Failed initializing tokenizer\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((parser = apfl_parser_new(apfl_tokenizer_as_token_source(tokenizer))) == NULL) {
|
||||
fprintf(stderr, "Failed initializing parser\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
struct apfl_error err;
|
||||
struct apfl_expr expr;
|
||||
struct apfl_token token;
|
||||
|
||||
switch (apfl_parser_next(parser)) {
|
||||
switch (apfl_tokenizer_next(tokenizer, false)) {
|
||||
case APFL_PARSE_OK:
|
||||
expr = apfl_parser_get_expr(parser);
|
||||
apfl_expr_print(expr, stdout);
|
||||
apfl_expr_deinit(&expr);
|
||||
token = apfl_tokenizer_get_token(tokenizer);
|
||||
apfl_token_print(token, stdout);
|
||||
apfl_token_deinit(&token);
|
||||
|
||||
break;
|
||||
case APFL_PARSE_EOF:
|
||||
goto exit;
|
||||
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;
|
||||
goto exit;
|
||||
*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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue