Parsing optionsΒΆ
This example shows how to parse command-line options with possible arguments, where each individual option may need its own argument format. Our parser handles errors and typos: for known options it reports ill-formed arguments; for unrecognized options it collects them and reports at the end of parsing. Our imaginary options are summarized below:
-v
,--verbose
-l LIMIT
,--limit=LIMIT
, whereLIMIT
is a decimal number followed by one of the suffixesB
,K
,M
orG
-d DATE
,--date=DATE
, whereDATE
has the formDD/MM/YYYY
-p PATH
,--path=PATH
, wherePATH
is a/
-separated file path-f FORMAT
,--format=FORMAT
, whereFORMAT
is a double-quoted format string
// re2c $INPUT -o $OUTPUT -i
#include <assert.h>
#include <stdio.h>
#include <string>
#include <vector>
typedef std::vector<std::pair<std::string, std::string> > unknown_t;
struct options_t {
std::string date;
std::string path;
std::string format;
std::string limit;
bool verbose;
};
static void show(const options_t &o, const unknown_t &u) {
fprintf(stderr, "\noptions:\n");
fprintf(stderr, " date: %s\n", o.date.c_str());
fprintf(stderr, " path: %s\n", o.path.c_str());
fprintf(stderr, " format: %s\n", o.format.c_str());
fprintf(stderr, " limit: %s\n", o.limit.c_str());
fprintf(stderr, " verbose: %s\n", o.verbose ? "yes" : "no");
fprintf(stderr, "\nunknown:\n");
unknown_t::const_iterator i = u.begin(), e = u.end();
for (; i != e; ++i) {
fprintf(stderr, " %s: '%s'\n", i->first.c_str(), i->second.c_str());
}
}
static void bad_arg(const char *k, const char *v, const char *e) {
fprintf(stderr, "bad argument '%.*s' to option %.*s\n",
(int) (e - v), v, (int) (v - k), k);
}
static int lex(const char *s) {
options_t o;
unknown_t u;
const char *m, *k, *v;
/*!stags:re2c format = 'const char *@@;'; */
for (;;) {
/*!re2c
re2c:define:YYCTYPE = char;
re2c:define:YYCURSOR = s;
re2c:define:YYMARKER = m;
re2c:yyfill:enable = 0;
re2c:tags = 1;
end = "\x00";
sp = [ \t\n\r];
eq = "=";
wsp = sp*;
char = [^=] \ end;
ochar = char \ sp;
pchar = ochar \ [/];
str = ["] (char \ ["] | [\]["])* ["];
opt = ochar+;
arg = ochar* | str;
date = [0-9]{2} "/" [0-9]{2} "/" [0-9]{4};
path = pchar* ("/" pchar*)*;
format = str;
limit = [0-9]+ [BKMG]?;
* { fprintf(stderr, "error: %s\n", s); return 1; }
end { show(o, u); return 0; }
wsp { continue; }
"-v" | "--verbose" { o.verbose = true; continue; }
("-l" | "--limit" eq) @v limit { o.limit = std::string(v, s); continue; }
("-f" | "--format" eq) @v str { o.format = std::string(v, s); continue; }
("-d" | "--date" eq) @v date { o.date = std::string(v, s); continue; }
("-p" | "--path" eq) @v path { o.path = std::string(v, s); continue; }
@k ("--" ("limit" | "format" | "date" | "path") | "-" [lfdp]) @v eq? arg {
bad_arg(k, v, s);
continue;
}
[-]{1,2} @k opt @v eq? arg {
u.push_back(std::make_pair(std::string(k, v), std::string(v, s)));
continue;
}
*/
}
}
int main() {
assert(lex("-v --limit=8K -d08/08/1985 -p/usr/src/linux "
"--format=\"%s\" --limit -f=3 --verbos --d\"19th May\"") == 0);
return 0;
}
Compile as re2c -o options.c options.re
.