From 1620e2c385bc0509fd72cbcbd76ce2eaf2954df7 Mon Sep 17 00:00:00 2001 From: Mike Lowis Date: Fri, 11 Dec 2015 12:52:49 +0000 Subject: [PATCH] Switched to posix/plan9 style option parser --- Makefile | 1 - source/main.c | 77 ++++----- source/opt.h | 102 ++++++++++++ source/opts.c | 369 -------------------------------------------- source/opts.h | 172 --------------------- source/sclpl.h | 2 +- spec/spec_helper.rb | 6 +- 7 files changed, 137 insertions(+), 592 deletions(-) create mode 100644 source/opt.h delete mode 100644 source/opts.c delete mode 100644 source/opts.h diff --git a/Makefile b/Makefile index ee0869b..281ffba 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,6 @@ SRCS = source/main.c \ source/grammar.c \ source/lexer.c \ source/parser.c \ - source/opts.c \ source/pprint.c \ source/gc.c \ source/vec.c \ diff --git a/source/main.c b/source/main.c index b6c5ad7..39c20ba 100644 --- a/source/main.c +++ b/source/main.c @@ -1,26 +1,21 @@ #include +char* ARGV0; +bool verbose = false; +char* artifact = "bin"; + /* Command Line Options *****************************************************************************/ -const char Usage[] = "Usage: sclpl [OPTION]... MODE [FILE]...\n"; - -opts_cfg_t Options_Config[] = { - {"tokens", false, "mode", "Emit the token output of lexical analysis for the given file"}, - {"ast", false, "mode", "Emit the abstract syntax tree for the given file"}, - {"csource", false, "mode", "Emit the intermediate C source file for the given file"}, - {"repl", false, "mode", "Execute the application in a REPL"}, - {"object", false, "mode", "Compile the source as an object file"}, - {"staticlib", false, "mode", "Compile the application as a static library"}, - {"sharedlib", false, "mode", "Compile the application as a shared library"}, - {"program", false, "mode", "Compile the application as an executable"}, - {"verbose", false, "verbose", "Enable verbose status messages"}, - {"v", false, "verbose", "Enable verbose status messages"}, - {NULL, false, NULL, NULL } -}; +const char Usage[] = + "Usage: sclpl [OPTION]... MODE [FILE]...\n" + "\n-A Emit the given type of artifact" + "\n-h Print help information" + "\n-v Enable verbose status messages" + "\n" +; -void print_usage(void) { - puts(Usage); - opts_print_help(stdout, Options_Config); +void usage(void) { + fprintf(stderr, "%s", Usage); exit(1); } @@ -46,10 +41,6 @@ static int emit_csource(void) { return 0; } -static int exec_repl(void) { - return 0; -} - static int emit_object(void) { return 0; } @@ -58,10 +49,6 @@ static int emit_staticlib(void) { return 0; } -static int emit_sharedlib(void) { - return 0; -} - static int emit_program(void) { return 0; } @@ -75,28 +62,26 @@ static int emit_program(void) { */ int user_main(int argc, char **argv) { - opts_parse( Options_Config, NULL, argc, argv ); - atexit(&opts_reset); - if (!opts_is_set(NULL,"mode")) { - print_usage(); - } else if (opts_equal(NULL, "mode", "tokens")) { - return emit_tokens(); - } else if(opts_equal(NULL, "mode", "repl")) { - return exec_repl(); - } else if (opts_equal(NULL, "mode", "ast")) { - return emit_tree(); - } else if (opts_equal(NULL, "mode", "csource")) { - return emit_csource(); - } else if (opts_equal(NULL, "mode", "object")) { - return emit_object(); - } else if (opts_equal(NULL, "mode", "staticlib")) { - return emit_staticlib(); - } else if (opts_equal(NULL, "mode", "sharedlib")) { - return emit_sharedlib(); - } else if (opts_equal(NULL, "mode", "program")) { + OPTBEGIN { + case 'A': artifact = EOPTARG(usage()); break; + case 'v': verbose = true; break; + default: usage(); + } OPTEND; + + /* Execute the main compiler process */ + if (0 == strcmp("bin", artifact)) { return emit_program(); + } else if (0 == strcmp("lib", artifact)) { + return emit_staticlib(); + } else if (0 == strcmp("src", artifact)) { + return emit_csource(); + } else if (0 == strcmp("ast", artifact)) { + return emit_tree(); + } else if (0 == strcmp("tok", artifact)) { + return emit_tokens(); } else { - print_usage(); + fprintf(stderr, "Unknonwn artifact type: '%s'\n\n", artifact); + usage(); } return 1; } diff --git a/source/opt.h b/source/opt.h new file mode 100644 index 0000000..126fcbe --- /dev/null +++ b/source/opt.h @@ -0,0 +1,102 @@ +/* This file implements a simple POSIX-style option parsing implementation as + * a set of macros. The file is heavily influenced and inspired by the arg.h + * file from suckless.org (http://git.suckless.org/libsl/tree/arg.h). That file + * is in turn inspired by the corresponding macros defined in plan9. + * + * The interface in this file assumes that the main function will have the + * following prototype: + * + * int main(int argc, char** argv); + * + * An example usage of the interface would look something like the follwoing: + * + * char* ARGV0; + * int main(int argc, char** argv) { + * OPTBEGIN { + * case 'a': printf("Simple option\n"); break; + * case 'b': printf("Option with arg: %s\n", OPTARG()); break; + * default: printf("Unknown option!\n"); + * } OPTEND; + * return 0; + * } + */ +#ifndef OPT_H +#define OPT_H + +/* This variable contains the value of argv[0] so that it can be referenced + * again once the option parsing is done. This variable must be defined by the + * program. + * + * NOTE: Ensure that you define this variable with external linkage (i.e. not + * static) + */ +extern char* ARGV0; + +/* This is a helper function used by the macros in this file to parse the next + * option from the command line. + */ +static inline char* getopt(int* p_argc, char*** p_argv) { + if (!(*p_argv)[0][1] && !(*p_argv)[1]) { + return (char*)0; + } else if ((*p_argv)[0][1]) { + return &(*p_argv)[0][1]; + } else { + *p_argv = *p_argv + 1; + *p_argc = *p_argc - 1; + return (*p_argv)[0]; + } +} + +/* This macro is almost identical to the ARGBEGIN macro from suckless.org. If + * it ain't broke, don't fix it. */ +#define OPTBEGIN \ + for ( \ + ARGV0 = *argv, argc--, argv++; \ + argv[0] && argv[0][1] && argv[0][0] == '-'; \ + argc--, argv++ \ + ) { \ + int brk_; char argc_ , **argv_, *optarg_; \ + if (argv[0][1] == '-' && !argv[0][2]) { \ + argv++, argc--; break; \ + } \ + for (brk_=0, argv[0]++, argv_=argv; argv[0][0] && !brk_; argv[0]++) { \ + if (argv_ != argv) break; \ + argc_ = argv[0][0]; \ + switch (argc_) + +/* Terminate the option parsing. */ +#define OPTEND }} + +/* Get the current option chracter */ +#define OPTC() (argc_) + +/* Get an argument from the command line and return it as a string. If no + * argument is available, this macro returns NULL */ +#define OPTARG() \ + (optarg_ = getopt(&argc,&argv), brk_ = (optarg_!=0), optarg_) + +/* Get an argument from the command line and return it as a string. If no + * argument is available, this macro executes the provided code. If that code + * returns, then abort is called. */ +#define EOPTARG(code) \ + (optarg_ = getopt(&argc,&argv), \ + (!optarg_ ? ((code), abort(), (char*)0) : (brk_ = 1, optarg_))) + +/* Helper macro to recognize number options */ +#define OPTNUM \ + case '0': \ + case '1': \ + case '2': \ + case '3': \ + case '4': \ + case '5': \ + case '6': \ + case '7': \ + case '8': \ + case '9' + +/* Helper macro to recognize "long" options ala GNU style. */ +#define OPTLONG \ + case '-' + +#endif diff --git a/source/opts.c b/source/opts.c deleted file mode 100644 index d061049..0000000 --- a/source/opts.c +++ /dev/null @@ -1,369 +0,0 @@ -#include -#include -#include -#include "opts.h" - -/* Type and Function Declarations - *****************************************************************************/ -typedef struct { - char* name; - char* tag; - char* value; -} option_t; - -typedef struct entry_t { - void* value; - struct entry_t* next; -} entry_t; - -typedef enum { LONG, SHORT } opt_type_t; - -typedef struct { - unsigned int line_idx; - unsigned int col_idx; - unsigned int arg_count; - char** arg_vect; - int current; - opts_cfg_t* options; -} stream_ctx_t; - -static void opts_parse_short_option( stream_ctx_t* ctx ); -static void opts_parse_long_option( stream_ctx_t* ctx ); -static char* opts_parse_optarg(stream_ctx_t* ctx, char* opt_name); -static void opts_parse_argument( stream_ctx_t* ctx ); -static void opts_parse_error(const char* msg, char* opt_name); -static opts_cfg_t* opts_get_option_config( opts_cfg_t* opts, opt_type_t typ, char* name ); -static char* opts_next_token( stream_ctx_t* ctx ); -static void opts_consume_ws( stream_ctx_t* ctx ); -static char opts_next_char( stream_ctx_t* ctx ); -static char* opts_append_char( char* str, char ch ); -static char* strclone(const char* p_old); -static void opts_add_option(char* name, char* tag, char* arg); -static void opts_add_argument(char* arg); - -/* Global State - *****************************************************************************/ -static const char* Program_Name = NULL; -static entry_t* Options = NULL; -static entry_t* Arguments = NULL; -static opts_err_cbfn_t Error_Callback = &opts_parse_error; - -/* The Options Parser - *****************************************************************************/ -void opts_parse(opts_cfg_t* opts, opts_err_cbfn_t err_cb, int argc, char** argv) { - /* Setup the stream */ - stream_ctx_t ctx; - ctx.line_idx = 0; - ctx.col_idx = -1; - ctx.arg_count = argc-1; - ctx.arg_vect = &argv[1]; - ctx.options = opts; - (void)opts_next_char( &ctx ); /* Loads up the first char */ - - /* Record the error handler if one was provided */ - if (NULL != err_cb) - Error_Callback = err_cb; - - /* Record the program name */ - Program_Name = argv[0]; - - /* Until we run out of characters */ - while (ctx.current != EOF) { - opts_consume_ws( &ctx ); - /* If we have an option */ - if ('-' == ctx.current) { - /* And it's a long one */ - if ('-' == opts_next_char( &ctx )) { - /* Consume the second '-' */ - opts_next_char( &ctx ); - /* Parse the option */ - opts_parse_long_option( &ctx ); - } else { - /* Parse the option */ - opts_parse_short_option( &ctx ); - } - } else { - /* It's not an option so add it to the "extra" bucket */ - opts_parse_argument( &ctx ); - } - } -} - -static void opts_parse_short_option( stream_ctx_t* ctx ) { - char opt[2] = { ctx->current, '\0' }; - char* opt_name = strclone(opt); - opts_cfg_t* config = opts_get_option_config( ctx->options, SHORT, opt_name ); - if (config != NULL) { - char* opt_arg = NULL; - (void)opts_next_char( ctx ); - /* Check if the flag has an argument */ - if (config->has_arg) - opt_arg = opts_parse_optarg( ctx, opt_name ); - /* If there are more flags in the flag group */ - else if ((' ' != ctx->current) && (EOF != ctx->current)) - opts_parse_short_option( ctx ); - opts_add_option( opt_name, config->tag, opt_arg ); - } else { - Error_Callback("Unknown Option", opt_name); - } -} - -static void opts_parse_long_option( stream_ctx_t* ctx ) { - char* opt_name = opts_next_token( ctx ); - opts_cfg_t* config = opts_get_option_config( ctx->options, LONG, opt_name ); - if (config != NULL) { - char* opt_arg = NULL; - /* Parse the argument if one is expected */ - if (config->has_arg) - opt_arg = opts_parse_optarg( ctx, opt_name ); - /* Store off the option value */ - opts_add_option( opt_name, config->tag, opt_arg ); - } else { - Error_Callback("Unknown Option", opt_name); - } -} - -static char* opts_parse_optarg(stream_ctx_t* ctx, char* opt_name) { - opts_consume_ws( ctx ); - if (('-' == ctx->current) || (EOF == ctx->current)) - Error_Callback("Expected an argument, none received", opt_name); - return opts_next_token( ctx ); -} - -static void opts_parse_error(const char* msg, char* opt_name) { - fprintf(stderr, "Option '%s' : %s\n", opt_name, msg); - free(opt_name); - opts_reset(); - exit(1); -} - -static void opts_parse_argument( stream_ctx_t* ctx ) { - char* arg_val = opts_next_token( ctx ); - if (NULL != arg_val) - opts_add_argument(arg_val); -} - -static opts_cfg_t* opts_get_option_config( opts_cfg_t* opts, opt_type_t type, char* name ) { - opts_cfg_t* cfg = NULL; - int i = 0; - while( opts[i].name != NULL ) { - opt_type_t curr_type = (strlen(opts[i].name) > 1) ? LONG : SHORT; - if ((curr_type == type) && (0 == strcmp(opts[i].name, name))) { - cfg = &(opts[i]); - break; - } - i++; - } - return cfg; -} - -static char* opts_next_token( stream_ctx_t* ctx ) { - char* tok = NULL; - - opts_consume_ws( ctx ); - if (EOF != ctx->current) { - // Setup the string - tok = (char*)malloc(2); - tok[0] = ctx->current; - tok[1] = '\0'; - - (void)opts_next_char( ctx ); - while ((EOF != ctx->current) && (' ' != ctx->current)) { - tok = opts_append_char( tok, ctx->current ); - (void)opts_next_char( ctx ); - } - } - return tok; -} - -static void opts_consume_ws( stream_ctx_t* ctx ) { - while (' ' == ctx->current) - (void)opts_next_char( ctx ); -} - -static char opts_next_char( stream_ctx_t* ctx ) { - char current = EOF; - ctx->current = EOF; - - if (ctx->line_idx < ctx->arg_count) { - ctx->col_idx++; - if (ctx->line_idx < ctx->arg_count) { - char temp = ctx->arg_vect[ ctx->line_idx ][ ctx->col_idx ]; - if (temp == '\0') { - ctx->col_idx = -1; - ctx->line_idx++; - current = ' '; - ctx->current = current; - } else { - temp = (temp == '=') ? ' ' : temp; - current = temp; - ctx->current = current; - } - } - } - - return current; -} - -static char* opts_append_char( char* str, char ch ) { - unsigned int new_size = strlen( str ) + 2; - str = (char*)realloc( str, new_size ); - str[ new_size - 2 ] = ch; - str[ new_size - 1 ] = '\0'; - return str; -} - -static void opts_add_option(char* name, char* tag, char* arg) { - option_t* option = (option_t*)malloc(sizeof(option_t)); - option->name = name; - option->tag = strclone(tag); - option->value = (NULL == arg) ? name : arg; - entry_t* entry = (entry_t*)malloc(sizeof(entry_t)); - entry->value = (void*)option; - entry->next = Options; - Options = entry; -} - -static void opts_add_argument(char* arg_val) { - entry_t* entry = (entry_t*)malloc(sizeof(entry_t)); - entry->value = (void*)arg_val; - entry->next = Arguments; - Arguments = entry; -} - -/* Parser Cleanup - *****************************************************************************/ -void opts_reset(void) { - while (Options != NULL) { - entry_t* entry = Options; - option_t* opt = (option_t*)entry->value; - Options = entry->next; - free(opt->name); - free(opt->tag); - if(opt->name != opt->value) - free(opt->value); - free(opt); - free(entry); - } - - while (Arguments != NULL) { - entry_t* entry = Arguments; - char* arg = (char*)entry->value; - Arguments = entry->next; - free(arg); - free(entry); - } -} - -/* Utility Functions - *****************************************************************************/ -static char* strclone(const char* p_old) { - size_t length = strlen(p_old); - char* p_str = (char*)malloc(length+1); - memcpy(p_str, p_old, length); - p_str[length] = '\0'; - return p_str; -} - -/* Query Functions - *****************************************************************************/ -static option_t* find_option(const char* name, const char* tag) { - option_t* p_opt = NULL; - entry_t* current = Options; - while (current != NULL) { - option_t* curr_opt = (option_t*)current->value; - if (((NULL == name) || (0 == strcmp(name, curr_opt->name))) && - ((NULL == tag) || (0 == strcmp(tag, curr_opt->tag)))) { - p_opt = curr_opt; - break; - } - current = current->next; - } - return p_opt; -} - -bool opts_is_set(const char* name, const char* tag) { - return (NULL != find_option(name,tag)); -} - -const char* opts_get_value(const char* name, const char* tag) { - option_t* p_opt = find_option(name,tag); - return (NULL == p_opt) ? NULL : p_opt->value; -} - -bool opts_equal(const char* name, const char* tag, const char* value) { - return (0 == strcmp(value, opts_get_value(name,tag))); -} - -const char** opts_select(const char* name, const char* tag) { - size_t index = 0; - const char** ret = (const char**)malloc(sizeof(const char*)); - ret[index] = NULL; - - entry_t* current = Options; - while (current != NULL) { - option_t* curr_opt = (option_t*)current->value; - if (((NULL == name) || (0 == strcmp(name, curr_opt->name))) && - ((NULL == tag) || (0 == strcmp(tag, curr_opt->tag)))) { - ret = (const char**)realloc(ret, (index+2)*sizeof(const char*)); - ret[index++] = curr_opt->value; - ret[index] = NULL; - } - current = current->next; - } - - return ret; -} - -const char** opts_arguments(void) { - size_t index = 0; - const char** ret = (const char**)malloc(sizeof(const char*)); - ret[0] = NULL; - entry_t* entry = Arguments; - while (NULL != entry) { - ret = (const char**)realloc(ret, (index+2)*sizeof(const char*)); - ret[index++] = (const char*)entry->value; - ret[index] = NULL; - entry = entry->next; - } - return ret; -} - -const char* opts_prog_name(void) { - return Program_Name; -} - -/* Help Message Printing - *****************************************************************************/ -static int opts_calc_padding(opts_cfg_t* opts) { - bool opts_have_args = false; - size_t sz = 0; - /* Figure out the longest option name */ - while (NULL != opts->name) { - size_t name_sz = strlen(opts->name); - if (name_sz > sz) { - sz = name_sz; - } - if (opts->has_arg) { - opts_have_args = true; - } - opts++; - } - return sz + 4 + ((opts_have_args) ? 4 : 0); -} - -void opts_print_help(FILE* ofile, opts_cfg_t* opts) { - int padding = opts_calc_padding(opts); - char* buffer = (char*)malloc(padding+1); - while (NULL != opts->name) { - if (1 == strlen(opts->name)) - sprintf(buffer, " -%s", opts->name); - else - sprintf(buffer, " --%s", opts->name); - if (opts->has_arg) sprintf(&buffer[strlen(buffer)], "=ARG "); - fprintf(ofile, "%-*s%s\n", padding, buffer, opts->desc); - opts++; - } - free(buffer); -} - diff --git a/source/opts.h b/source/opts.h deleted file mode 100644 index a6c4166..0000000 --- a/source/opts.h +++ /dev/null @@ -1,172 +0,0 @@ -/** - * @file - * @author Mike D. Lowis - * - * This project is an implementation of a very lightweight command-line options - * parser. It is capable of interpreting the Unix/GNU style command line - * argument flags. It is designed to be platform independent and can be used as - * a static library or directly as source. - * - * The library is designed to work like something of a database for your - * command line. At initialization time you feed in the arguments vector (your - * data records) and a list of option definitions (your schema). The library - * then parses the options and stores them internally for querying later. - * Several querying functions are provided that cover the most common use cases - * for options handling. - * - * All of the query functions take an option name and an option tag as - * parameters. These two arguments will be used to search the list of parsed - * options for any that match both parameters. In some cases only one of the - * parameters is needed for a query. To facilitate this, the query functions - * will interpret a NULL pointer to match everything. An example of this would - * be selecting all parsed options with the tag "foo": - * - * const char** foo_lst = opts_select(NULL,"foo"); - * - * In the example above, the NULL would match *all* parsed options and from that - * group only those having the tag "foo" would be returned. Another common - * scenario would be searching by parameter name: - * - * const char** includes = opts_select("I", NULL); - * - * In this scenario all of the options that were parsed having the name 'I' - * would be returned regardless of their tag value. This would equate to all of - * the instances of '-I' that would occur on the command line for an invocation - * of gcc. - * - * With this design you should be able to let the library handle your options - * parsing while you focus on your application logic using appropriate queries - * to change behavior where necessary. - * - */ -#ifndef OPTS_H -#define OPTS_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include - -/** Structure representing an option to be parsed */ -typedef struct { - /** The name of the option as it will appear on the command line. If the - * name is a single character in length the parse will treat it as a short - * option and require a single dash. Otherwise, it is considered a long - * option and will require double dashes */ - char* name; - /** Flag indicating whether the option expects an argument or not */ - bool has_arg; - /** An optional tag which can be used to group related options together - * logically */ - char* tag; - /** A short description of the flag used for displaying help messages */ - char* desc; -} opts_cfg_t; - -typedef void (*opts_err_cbfn_t)(const char* msg, char* opt_name); - -/** - * Parse the command line options using the provided option definition list. - * - * @param opts Pointer to a list of option definitions - * @param argc The number of arguments in the vector - * @param argv The vector of command line arguments - */ -void opts_parse(opts_cfg_t* opts, opts_err_cbfn_t err_cb, int argc, char** argv); - -/** - * Resets the global state back to defaults. This includes freeing any - * allocated memory and clearing any saved pointers to NULL. - */ -void opts_reset(void); - -/** - * Determines if a given option is set. This function searches the list of - * parsed options for an entry with the given name and/or the given tag. A value - * of NULL for either parameter will match everything. - * - * @param name The name of the option to find. - * @param tag The tag of the option to find. - * - * @return true if an entry was found, false otherwise. - */ -bool opts_is_set(const char* name, const char* tag); - -/** - * Searches for the last received option with the given name and/or tag and - * does a string comparison of it's value. The parsed options are stored - * internally in reverse order so the first match equates to the last option - * that the parser saw on the command line. The value returned is the text of - * any argument that was received for the option or the name of the option - * itself if the option does not take an argument. - * - * @param name The name of the option to find. - * @param tag The tag of the option to find. - * @param value The value to compare. - * - * @return true if the value matches exactly, false otherwise. - */ -bool opts_equal(const char* name, const char* tag, const char* value); - -/** - * Search for a parsed option value with the given name and/or tag. If multiple - * matches are found, only the first match is found. The parsed options are - * stored internally in reverse order so the first match equates to the last - * option that the parser saw on the command line. The value returned is the - * text of any argument that was received for the option or the name of the - * option itself if the option does not take an argument. - * - * @param name The name of the option to search for. - * @param tag The tag of the option to search for. - * - * @return The text of the value of the parsed option. - */ -const char* opts_get_value(const char* name, const char* tag); - -/** - * Search for a group of parsed option values with the given name and/or tag. - * The value returned for each matching option is the text of the argument that - * was received for the option. If the option does not expect an argument then - * the value is returned as the name of the option itself. - * - * @param name The name of the options to search for. - * @param tag The tag of the options to search for. - * - * @return Pointer to the array of options. - */ -const char** opts_select(const char* name, const char* tag); - -/** - * Returns a null terminated array of strings representing the arguments of the - * executable. These are the entries provided on the command line that are not - * parsed as options. A common example would be the list of files passed to the - * unix "cat" command. - * - * @return Pointer to the array of arguments. - */ -const char** opts_arguments(void); - -/** - * Returns the program name as received on the command line. - * - * @return String representing the program name. - */ -const char* opts_prog_name(void); - -/** - * Prints out the options and their descriptions in a tabular format to the - * given file handle. - * - * @param ofile The file handle to use for output. - * @param opts The list of option definitions. - */ -void opts_print_help(FILE* ofile, opts_cfg_t* opts); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/source/sclpl.h b/source/sclpl.h index e44782f..296c30c 100644 --- a/source/sclpl.h +++ b/source/sclpl.h @@ -13,7 +13,7 @@ #include #include #include -#include +#include /* Garbage Collection *****************************************************************************/ diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 20f0b84..b931a73 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -9,7 +9,7 @@ def cli(options, input = "") end def lexer(input) - cli(['--tokens'], input).scan(/^\d+:\d+:(T_[A-Z]+(:("[^"]*"|[^\n]+))?)/m).map {|m| m[0] } + cli(['-Atok'], input).scan(/^\d+:\d+:(T_[A-Z]+(:("[^"]*"|[^\n]+))?)/m).map {|m| m[0] } end def re_structure( token_array, offset = 0 ) @@ -30,7 +30,7 @@ def re_structure( token_array, offset = 0 ) end def ast(input) - out = cli(['--ast'], input) + out = cli(['-Aast'], input) # Prep the parens for reading out.gsub!(/([()])|tree/,' \1 ') # Replace string literals so we can tokenize on spaces @@ -53,5 +53,5 @@ def ast(input) end def ccode(input) - cli(['--csource'], input) + cli(['-Asrc'], input) end -- 2.52.0