source/grammar.c \
source/lexer.c \
source/parser.c \
- source/opts.c \
source/pprint.c \
source/gc.c \
source/vec.c \
#include <sclpl.h>
+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<type> 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);
}
return 0;
}
-static int exec_repl(void) {
- return 0;
-}
-
static int emit_object(void) {
return 0;
}
return 0;
}
-static int emit_sharedlib(void) {
- return 0;
-}
-
static int emit_program(void) {
return 0;
}
*/
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;
}
--- /dev/null
+/* 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
+++ /dev/null
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#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);
-}
-
+++ /dev/null
-/**
- * @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 <stdbool.h>
-#include <stddef.h>
-#include <stdio.h>
-
-/** 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
#include <errno.h>
#include <assert.h>
#include <setjmp.h>
-#include <opts.h>
+#include <opt.h>
/* Garbage Collection
*****************************************************************************/
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 )
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
end
def ccode(input)
- cli(['--csource'], input)
+ cli(['-Asrc'], input)
end