[Commit] nickle ChangeLog, 1.129, 1.130 builtin.5c, 1.9,
1.10 command.5c, 1.20, 1.21 compile.c, 1.163,
1.164 parse-args.5c, 1.2, 1.3
Bart Massey
commit at keithp.com
Mon Aug 1 02:20:32 PDT 2005
Committed by: bart
Update of /local/src/CVS/nickle
In directory home.keithp.com:/tmp/cvs-serv26728
Modified Files:
ChangeLog builtin.5c command.5c compile.c parse-args.5c
Log Message:
2005-07-31 Bart Massey <bart at cs.pdx.edu>
* parse-args.5c:
Big rewrite of parse-args code to work better and be
more usable. Will now accomodate Nickle startup.
* builtin.5c, command.5c:
Changes to use parse-args instead of ad hoc argument parsing
at startup. Changed key conventions: -e now takes a single
argument; -e, -f, and -l can be freely mixed; interactive mode
can now have argv through "--"; others?
* compile.c:
Fixed trivial spelling error.
Index: ChangeLog
===================================================================
RCS file: /local/src/CVS/nickle/ChangeLog,v
retrieving revision 1.129
retrieving revision 1.130
diff -u -d -r1.129 -r1.130
--- ChangeLog 9 Jul 2005 05:46:53 -0000 1.129
+++ ChangeLog 1 Aug 2005 09:20:29 -0000 1.130
@@ -1,3 +1,18 @@
+2005-07-31 Bart Massey <bart at cs.pdx.edu>
+
+ * parse-args.5c:
+ Big rewrite of parse-args code to work better and be
+ more usable. Will now accomodate Nickle startup.
+
+ * builtin.5c, command.5c:
+ Changes to use parse-args instead of ad hoc argument parsing
+ at startup. Changed key conventions: -e now takes a single
+ argument; -e, -f, and -l can be freely mixed; interactive mode
+ can now have argv through "--"; others?
+
+ * compile.c:
+ Fixed trivial spelling error.
+
2005-07-08 Keith Packard <keithp at keithp.com>
* builtin-sockets.c: (do_Socket_connect):
Index: builtin.5c
===================================================================
RCS file: /local/src/CVS/nickle/builtin.5c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- builtin.5c 30 Nov 2004 18:34:41 -0000 1.9
+++ builtin.5c 1 Aug 2005 09:20:29 -0000 1.10
@@ -111,6 +111,7 @@
library "history.5c";
# Now load the extra commands.
+library "parse-args.5c";
library "command.5c";
# Note that some libraries extend namespaces, and
@@ -127,5 +128,5 @@
# parse the command line
extend namespace Command {
- argv = process_args (argv);
+ process_args (&argv);
}
Index: command.5c
===================================================================
RCS file: /local/src/CVS/nickle/command.5c,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -d -r1.20 -r1.21
--- command.5c 8 Jun 2004 09:30:53 -0000 1.20
+++ command.5c 1 Aug 2005 09:20:29 -0000 1.21
@@ -1,4 +1,5 @@
extend namespace Command {
+
/*
* These are used by the parser when building
* programs to run from the top level of the
@@ -226,78 +227,105 @@
new ("char", do_char);
- /*
- * Command line processing
- */
- string[*] process_args(string[*] argv)
+ void process_args(&string[*] argv)
{
- typedef struct {
- bool library;
- string name;
- } lex_arg;
- lex_arg[dim(argv)] files;
- int nfiles = 0;
- bool lex_stdin = true;
- bool done = false;
- int i = 0;
+ bool lex_stdin = true;
+ string script_name = "";
- while (!done && i < dim (argv))
- {
- switch (argv[i]) {
- case "-e":
- /*
- * -e -- remaining arguments are a single expression
- */
- string expr = "";
- while (++i < dim(argv))
- {
- expr += argv[i];
- if (i < dim(argv)-1)
- expr += " ";
- else
- expr += "\n";
- }
- lex_string (expr);
- done = true;
- lex_stdin = false;
- break;
- case "-f":
- /*
- * -f -- lex a file
- */
- i++;
- files[nfiles].library = false;
- files[nfiles].name = argv[i];
- nfiles++;
- i++;
- break;
- case "-l":
- i++;
- files[nfiles].library = true;
- files[nfiles].name = argv[i];
- nfiles++;
- i++;
- break;
- default:
- /*
- * Add the script base directory to the library path
- */
- nickle_path += ":" + String::dirname(argv[0]);
- files[nfiles].library = false;
- files[nfiles].name = argv[i];
- nfiles++;
- done = true;
- lex_stdin = false;
- break;
- }
+ /* XXX Much of this architecture is driven by
+ the fact that the lexer stacks the
+ files to be processed rather than queueing them. */
+
+ typedef union {
+ string library;
+ string sfile;
+ string script;
+ string expr;
+ } lexable;
+
+ lexable[...] lexables = {};
+
+ void process_lexables() {
+ }
+
+ void save_lexable(lexable l) {
+ lexables[dim(lexables)] = l;
+ }
+
+ void save_library(string arg) {
+ save_lexable((lexable.library)arg);
+ }
+
+ void save_script(string arg) {
+ save_lexable((lexable.script)arg);
+ script_name = arg;
+ lex_stdin = false;
+ }
+
+ void save_file(string arg) {
+ save_lexable((lexable.sfile)arg);
+ }
+
+ void save_expr(string arg) {
+ save_lexable((lexable.expr)arg);
+ lex_stdin = false;
+ }
+
+ ParseArgs::argdesc argd = {
+ args = {
+ {var = {arg_lambda = save_library},
+ abbr = 'l',
+ name = "library",
+ expr_name = "lib",
+ desc = "Library to load."},
+ {var = {arg_lambda = save_file},
+ abbr = 'f',
+ name = "file",
+ expr_name = "source",
+ desc = "Source file to load."},
+ {var = {arg_lambda = save_expr},
+ abbr = 'e',
+ name = "expr",
+ expr_name = "expression",
+ desc = "Expression to evaluate."}
+ },
+ posn_args = {
+ {var = {arg_lambda = save_script},
+ name = "script",
+ optional = <>}
+ },
+ unknown = &(int user_argind),
+ prog_name = "nickle"
+ };
+
+ /* actually parse the arguments */
+ ParseArgs::parseargs(&argd, &argv);
+
+ /* Reset argv to hold remaining arguments */
+ if (is_uninit(&user_argind)) {
+ string[0] rest = {};
+ argv = rest;
+ } else {
+ string[dim(argv) - user_argind + 1] rest;
+ rest[0] = script_name;
+ for (int i = 1; i < dim(rest); i++)
+ rest[i] = argv[i + user_argind - 1];
+ argv = rest;
}
+
+ /* Recall the comment above. Since the lexer
+ stacks, we must stack stdin, which is to run last,
+ *before* the other stuff. Bleah. */
if (lex_stdin)
{
- /*
- * Add the current directory to the library path
- */
+ /* Add the current directory to the library path */
nickle_path += ":.";
+
+ /* we want stdin to be processed after all other lexables */
lex_input (stdin, "<stdin>", false, File::isatty (stdin));
+
+ /* if there's a .nicklerc, we apparently want that
+ next-to-last? */
try {
lex_file (Environ::get ("HOME") + "/.nicklerc");
} catch invalid_argument (msg, int i, poly value) {
@@ -309,31 +337,39 @@
}
}
- while (nfiles-- > 0)
- {
- exception load_fail (string msg);
- try {
- if (files[nfiles].library) {
- if (!lex_library (files[nfiles].name))
- raise load_fail ("no such library");
- } else {
- try {
- lex_file (files[nfiles].name);
- } catch File::open_error (string msg,
- File::error_type err,
- string name) {
- raise load_fail (msg);
- }
- }
- } catch load_fail (string msg) {
+ /* now stack the other arguments, in reverse order */
+ for (int i = dim(lexables) - 1; i >=0; --i) {
+ static void load_fail(string name, string msg) {
File::fprintf (stderr, "Cannot load \"%s\": %s\n",
- files[nfiles].name, msg);
+ name, msg);
exit (1);
}
+
+ static void lex_script(string arg) {
+ try {
+ lex_file (arg);
+ } catch File::open_error (string msg,
+ File::error_type err,
+ string name) {
+ load_fail (name, msg);
+ }
+ }
+
+ union switch(lexables[i]) {
+ case library arg:
+ if (!lex_library (arg))
+ load_fail (arg, "cannot load library");
+ break;
+ case script arg:
+ lex_script(arg);
+ break;
+ case sfile arg:
+ lex_script(arg);
+ break;
+ case expr arg:
+ lex_string(arg + "\n");
+ break;
+ }
}
- /*
- * Reset argv to hold remaining arguments
- */
- return (string[dim(argv) - i]) { [j] = argv[i+j] };
}
}
Index: compile.c
===================================================================
RCS file: /local/src/CVS/nickle/compile.c,v
retrieving revision 1.163
retrieving revision 1.164
diff -u -d -r1.163 -r1.164
--- compile.c 9 Jul 2005 05:46:54 -0000 1.163
+++ compile.c 1 Aug 2005 09:20:29 -0000 1.164
@@ -3542,7 +3542,7 @@
CompileIsReachable (obj, obj->used))
{
CompileError (obj, expr,
- "Fall through case with varient value");
+ "Fall-through case with variant value");
}
inst->tagcase.offset = obj->used - case_inst[icase];
inst->tagcase.tag = tag;
Index: parse-args.5c
===================================================================
RCS file: /local/src/CVS/nickle/parse-args.5c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- parse-args.5c 8 Jun 2004 09:30:54 -0000 1.2
+++ parse-args.5c 1 Aug 2005 09:20:30 -0000 1.3
@@ -1,14 +1,13 @@
-import File;
-import String;
-
namespace ParseArgs {
+ import File;
+ import String;
public typedef union {
&bool arg_flag;
&string arg_string;
&int arg_int;
&real arg_real;
- &(string[*]) arg_list;
+ (void(string)) arg_lambda;
} arg_var;
public typedef struct {
@@ -20,13 +19,24 @@
} arg;
public typedef struct {
+ arg_var var;
+ void optional;
+ string name;
+ } posn_arg;
+
+ public typedef struct {
string prog_name;
arg[*] args;
- &(string[*]) rest;
+ posn_arg[*] posn_args;
&int unknown;
} argdesc;
- string arg_string(arg a) {
+ string arg_string(arg a)
+ /*
+ * Given an arg desc, produce
+ * a printable representation
+ */
+ {
string stdarg() {
if (is_uninit(&a.name))
return a.expr_name;
@@ -37,17 +47,12 @@
return s;
}
union switch (a.var) {
- case arg_list:
- return sprintf("%s ...", a.expr_name);
case arg_flag:
return stdarg();
default:
return sprintf("%s <%s>", stdarg(), a.expr_name);
}
- abort("internal error");
- }
-
- void print_options(&(arg[*]) a) {
+ abort("internal error: unknown arg type");
}
public string basename(string path)
@@ -61,13 +66,37 @@
return substr(path, p + 1, length(path) - p - 1);
}
+ /*
+ * the argument description was defective, with
+ * a reason string
+ */
+ public exception bad_argd(string reason);
+
public void parseargs(&argdesc argd, &(string[*]) argv)
/*
* Parse arguments in 'argv' according to 'argd'
*/
{
- argd.prog_name = basename(argv[0]);
+ /*
+ * validate that any argd.posn_args
+ * consists of mandatory followed by optional args
+ */
+ if (!is_uninit(&argd.posn_args))
+ for (int i = 1; i < dim(argd.posn_args); i++)
+ if (!is_uninit(&argd.posn_args[i - 1].optional) &&
+ is_uninit(&argd.posn_args[i].optional))
+ raise bad_argd("fixed after optional posn arg");
+
+ /* argument that is current focus */
+ int argind = 0;
+
+ /* save program basename as needed */
+ if (is_uninit(&argd.prog_name)) {
+ argd.prog_name = basename(argv[0]);
+ argind++;
+ }
+ /* build hashes for flags */
arg[int] arg_abbr_hash = {};
arg[string] arg_name_hash = {};
for (int i = 0; i < dim(argd.args); i++) {
@@ -78,30 +107,46 @@
arg_name_hash[d.name] = d;
}
- void usage() {
- fprintf(stderr, "%s: usage: ", argd.prog_name);
- fprintf(stderr, "%s <options>", argd.prog_name);
+ void usage(file f)
+ /*
+ * Print a description of program usage on f
+ */
+ {
+ fprintf(f, "%s: usage: ", argd.prog_name);
+ fprintf(f, "%s <options>", argd.prog_name);
for (int i = 0; i < dim(argd.args); i++)
if (is_uninit(&argd.args[i].name))
- fprintf(stderr, " %s", arg_string(argd.args[i]));
- fprintf(stderr, "\n");
+ fprintf(f, " %s", arg_string(argd.args[i]));
+ if (!is_uninit(&argd.posn_args)) {
+ for (int i = 0; i < dim(argd.posn_args); i++)
+ if (is_uninit(&argd.posn_args[i].optional))
+ fprintf(f, " %s", argd.posn_args[i].name);
+ else
+ fprintf(f, " [%s]", argd.posn_args[i].name);
+ }
+ if (!is_uninit(&&argd.unknown))
+ fprintf(f, " [--] ...");
+ fprintf(f, "\n");
for (int i = 0; i < dim(argd.args); i++)
if (is_uninit(&argd.args[i].name))
- fprintf(stderr, " %s %s\n",
+ fprintf(f, " %s %s\n",
argd.args[i].expr_name,
argd.args[i].desc);
for (int i = 0; i < dim(argd.args); i++)
if (!is_uninit(&argd.args[i].name))
- fprintf(stderr, " %s %s\n",
+ fprintf(f, " %s %s\n",
arg_string(argd.args[i]),
argd.args[i].desc);
exit(1);
}
- int argi = 1;
-
- void save_value(&arg a, string value) {
- union switch(a.var) {
+ void save_value(&arg_var a, string value)
+ /*
+ * convert and store the value
+ * associated with an argument
+ */
+ {
+ union switch(a) {
case arg_flag var:
var = true;
break;
@@ -109,95 +154,123 @@
var = value;
break;
case arg_int var:
- var = atoi(value);
+ var = string_to_integer(value);
break;
case arg_real var:
- var = atof(value);
+ var = string_to_real(value);
+ break;
+ case arg_lambda var:
+ var(value);
break;
- case arg_list:
- abort("flagged list in argument description");
}
}
- void process_flag(&arg a) {
- if (argi >= dim(argv)) {
+ void process_flag(&arg a)
+ /*
+ * Process a flag that requires an argument
+ */
+ {
+ if (argind >= dim(argv)) {
fprintf(stderr, "%s: missing value for --%s\n",
argd.prog_name, a.name);
- usage();
+ usage(stderr);
}
- save_value(&a, argv[argi]);
- argi++;
+ save_value(&a.var, argv[argind]);
+ argind++;
}
- while(argi < dim(argv)) {
- string a = argv[argi];
- if (a == "" || a == "-" || a == "--") {
- if (is_uninit(&argd.unknown)) {
+ /* handle the help case first */
+ if (argind < dim(argv) &&
+ (argv[argind] == "--help" || argv[argind] == "--usage"))
+ usage(stdout);
+
+ /* now walk the arguments */
+ while(argind < dim(argv)) {
+ string a = argv[argind];
+
+ /* we're done on a "user stop" */
+ if (a == "--") {
+ if (is_uninit(&&argd.unknown)) {
fprintf(stderr,
"%s: don't know what to do with arg \"%s\"\n",
argd.prog_name,
a);
- usage();
+ usage(stderr);
}
- argd.unknown = argi + 1;
- return;
+ break;
}
+
+ /* process abbreviated (old-style) flags (maybe grouped) */
if (a[0] == '-' && a[1] != '-') {
- argi++;
+ argind++;
for (int i = 1; i < length(a); i++) {
if (!hash_test(arg_abbr_hash, a[i])) {
fprintf(stderr, "%s: unknown flag char '-%c'\n",
argd.prog_name,
a[i]);
- usage();
+ usage(stderr);
}
process_flag(&arg_abbr_hash[a[i]]);
}
continue;
}
+
+ /* process a long flag */
if (a[0] == '-' && a[1] == '-') {
string argname = substr(a, 2, length(a) - 2);
if (!hash_test(arg_name_hash, argname)) {
fprintf(stderr, "%s: unknown flag \"--%s\"\n",
argd.prog_name,
argname);
- usage();
+ usage(stderr);
}
- argi++;
+ argind++;
process_flag(&arg_name_hash[argname]);
continue;
}
- break;
+
+ /* maybe something will suck up remaining args */
+ if (!is_uninit(&argd.posn_args) ||
+ !is_uninit(&&argd.unknown))
+ break;
+
+ fprintf(stderr, "%s: extra argument \"%s\"\n",
+ argd.prog_name,
+ argv[argind]);
+ usage(stderr);
}
- for (int i = 0; i < dim(argd.args); i++) {
- if (!is_uninit(&argd.args[i].name))
- continue;
- if (argi >= dim(argv)) {
- fprintf(stderr, "%s: missing required argument %s\n",
- argd.prog_name, argd.args[i].expr_name);
- usage();
- }
- union switch (argd.args[i].var) {
- case arg_list v:
- string[...] rest = {};
- v = rest;
- while(argi < dim(argv)) {
- rest[argi] = argv[argi];
- argi++;
+
+ /* process any positional arguments */
+ if (!is_uninit(&argd.posn_args)) {
+ for (int i = 0; i < dim(argd.posn_args); i++) {
+ if (argind >= dim(argv) ||
+ argv[argind] == "--") {
+ if (!is_uninit(&argd.posn_args[i].optional))
+ break;
+ fprintf(stderr, "%s: missing required argument %s\n",
+ argd.prog_name,
+ argd.args[i].expr_name);
+ usage(stderr);
}
- return;
- case arg_flag:
- abort("fixed flag in argument description");
- default:
- save_value(&argd.args[i], argv[argi]);
- argi++;
+ save_value(&argd.posn_args[i].var, argv[argind]);
+ argind++;
}
}
- if (argi < dim(argv)) {
- fprintf(stderr, "%s: unknown or extra argument \"%s\"\n",
- argv[argi],
- argd.prog_name);
- usage();
+
+ /* process any unknown arguments */
+ if (argind < dim(argv)) {
+ if (argv[argind] == "--")
+ argind++;
+ if (!is_uninit(&&argd.unknown)) {
+ argd.unknown = argind;
+ return;
+ }
+ if (argind < dim(argv)) {
+ fprintf(stderr, "%s: unknown or extra argument \"%s\"\n",
+ argd.prog_name,
+ argv[argind]);
+ usage(stderr);
+ }
}
}
}
More information about the Commit
mailing list