From 49dcbd9216f3513ec11731a41d4b73acaacb5949 Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Fri, 28 Jul 2023 02:01:53 -0400 Subject: [PATCH] cdecl99: Combine all the main command implementations. The explain, simplify and declare (or type) commands are all virtually identical. The primary difference is just which parser mode to use, and which output mode to use, with the various combinations giving the various commands. Other than some very slight tweak to the formatting to handle "simplify" with multiple full declarators, we can just implement one function that does all three operations: a pretty nice cleanup. --- src/cdecl99.h | 7 +-- src/commands.c | 121 ++++++++++++++++------------------------------ src/execute.gperf | 15 ++++-- 3 files changed, 56 insertions(+), 87 deletions(-) diff --git a/src/cdecl99.h b/src/cdecl99.h index d96a410..d5928d4 100644 --- a/src/cdecl99.h +++ b/src/cdecl99.h @@ -22,10 +22,11 @@ #include #define _(x) gettext(x) +enum { INPUT_C, INPUT_ENGLISH }; +enum { OUTPUT_C, OUTPUT_ENGLISH }; + int run_command(const char *line, int batch); -int run_command_simplify(const char *arg); -int run_command_explain(const char *arg); -int run_command_declare(const char *cmdarg); +int run_command_cdecl(const char *s, int input_mode, int output_mode); void print_error(const char *fmt, ...); diff --git a/src/commands.c b/src/commands.c index faaf607..429ba85 100644 --- a/src/commands.c +++ b/src/commands.c @@ -23,6 +23,21 @@ #include "cdecl99.h" #include "cdecl.h" +static struct cdecl *do_parse(const char *s, int input_mode) +{ + struct cdecl *parse; + + if (input_mode == INPUT_C) + parse = cdecl_parse_decl(s); + else + parse = cdecl_parse_english(s); + + if (!parse) + print_error("%s", cdecl_get_error()->str); + + return parse; +} + /* * Format a declaration according to the given function and return a pointer * to the formatted string. The returned pointer remains valid until the @@ -30,16 +45,18 @@ * * Returns NULL on failure. */ -static const char * -do_format(size_t func(char *, size_t, struct cdecl *), struct cdecl *decl) +static const char *do_render(struct cdecl *decl, int output_mode) { static size_t bufsz; static char *buf; - size_t rc; retry: - rc = func(buf, bufsz, decl); + if (output_mode == OUTPUT_C) + rc = cdecl_declare(buf, bufsz, decl); + else + rc = cdecl_explain(buf, bufsz, decl); + if (rc >= bufsz) { char *tmp; @@ -57,93 +74,39 @@ retry: return buf; } -int run_command_explain(const char *arg) -{ - struct cdecl *decl; - const char *str; - int ret = -1; - - decl = cdecl_parse_decl(arg); - if (!decl) { - print_error("%s", cdecl_get_error()->str); - goto out; - } - - for (struct cdecl *i = decl; i; i = i->next) { - str = do_format(cdecl_explain, i); - if (!str) - goto out; - - printf("%s\n", str); - } - - ret = 0; -out: - cdecl_free(decl); - return ret; -} - -int run_command_simplify(const char *arg) +/* + * Parse the given string as either C or English (based on input_mode), + * then print the result as either C or English (based on output_mode). + */ +int run_command_cdecl(const char *s, int input_mode, int output_mode) { - struct cdecl *decl; - const char *str; + struct cdecl *i, *parse; int ret = -1; - decl = cdecl_parse_decl(arg); - if (!decl) { - print_error("%s", cdecl_get_error()->str); + if (!(parse = do_parse(s, input_mode))) goto out; - } - - for (struct cdecl *i = decl; i; i = i->next) { - struct cdecl_declspec *s = i->specifiers; - if (i != decl) { - i->specifiers = NULL; - printf(", "); - } - - str = do_format(cdecl_declare, i); - i->specifiers = s; + for (i = parse; i; i = i->next) { + const char *str; + int no_nl = 0; - if (!str) + if (!(str = do_render(i, output_mode))) goto out; - printf("%s", str); - } - - putchar('\n'); - - ret = 0; -out: - cdecl_free(decl); - return ret; -} - -int run_command_declare(const char *cmd) -{ - struct cdecl *decl; - const char *str; - int ret = -1; + /* + * In C output, only the first declarator needs specifiers + * printed, and only the last declarator needs a newline. + */ + if (output_mode == OUTPUT_C && i->next) { + i->next->specifiers = NULL; + no_nl = 1; + } - /* The name of the command is significant here. */ - decl = cdecl_parse_english(cmd); - if (!decl) { - print_error("%s", cdecl_get_error()->str); - goto out; + printf(", %s%s" + 2*!!i->specifiers, str, "\n" + no_nl); } - /* - * English parses have at most one full declarator, so no loop is - * needed here. - */ - str = do_format(cdecl_declare, decl); - if (!str) - goto out; - - printf("%s\n", str); ret = 0; out: - cdecl_free(decl); + cdecl_free(parse); return ret; } diff --git a/src/execute.gperf b/src/execute.gperf index ddebd5d..bf9a080 100644 --- a/src/execute.gperf +++ b/src/execute.gperf @@ -104,11 +104,16 @@ int run_command(const char *line, int batch) } switch (c->cmd) { - case cmd_help: return run_cmd_help(); - case cmd_declare: case cmd_type: return run_command_declare(cmd); - case cmd_simplify: return run_command_simplify(arg); - case cmd_explain: return run_command_explain(arg); - case cmd_quit: return 1; + case cmd_help: + return run_cmd_help(); + case cmd_declare: case cmd_type: + return run_command_cdecl(cmd, INPUT_ENGLISH, OUTPUT_C); + case cmd_simplify: + return run_command_cdecl(arg, INPUT_C, OUTPUT_C); + case cmd_explain: + return run_command_cdecl(arg, INPUT_C, OUTPUT_ENGLISH); + case cmd_quit: + return 1; } assert(0); -- 2.43.2