]> git.draconx.ca Git - cdecl99.git/commitdiff
cdecl99: Combine all the main command implementations.
authorNick Bowler <nbowler@draconx.ca>
Fri, 28 Jul 2023 06:01:53 +0000 (02:01 -0400)
committerNick Bowler <nbowler@draconx.ca>
Fri, 28 Jul 2023 06:01:53 +0000 (02:01 -0400)
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
src/commands.c
src/execute.gperf

index d96a410ad71af826e9a2462ab273c8d0b9d7de23..d5928d4b8e3bd189879826c3d33459f973e8cad5 100644 (file)
 #include <gettext.h>
 #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, ...);
 
index faaf60785d1f69beb64005619292b0559121c38e..429ba852efff70b67470722e2cd8b012a68c9fde 100644 (file)
 #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
  *
  * 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;
 }
index ddebd5d08867d246ef5fea503da0fc33936bd315..bf9a080748764b886117152b01fbaa9cb36c1c8d 100644 (file)
@@ -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);