X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=parse.cc;h=48a32c717c0318a806ce6edfb5eb077a0a4dc06d;hb=bd1389b30f2a5addf0570c5f3358567df8134fc6;hp=c0b8a3542439f475f8de92941a3d061cd682a68f;hpb=4f08fc1b75c10b9149e60833fb4deb17f414e0df;p=paperjam.git diff --git a/parse.cc b/parse.cc index c0b8a35..48a32c7 100644 --- a/parse.cc +++ b/parse.cc @@ -1,3 +1,9 @@ +/* + * PaperJam -- Command parser + * + * (c) 2018 Martin Mares + */ + #include #include #include @@ -30,7 +36,7 @@ static string token; static double token_num; static void NONRET parse_error(const char *msg, ...); -static void parse_commands(list *cmds); +static void parse_commands(list &cmds); static void parse_error(const char *msg, ...) { @@ -71,7 +77,8 @@ static token_type get_next_token() { while (*in_pos >= 'A' && *in_pos <= 'Z' || *in_pos >= 'a' && *in_pos <= 'z' || - *in_pos >= '0' && *in_pos <= '9') + *in_pos >= '0' && *in_pos <= '9' || + *in_pos == '_') token += *in_pos++; return TOK_IDENT; } @@ -154,22 +161,31 @@ static bool token_is_int() /*** Argument types ***/ +class arg_int : public arg_val { + int val; +public: + arg_int(int x) { val = x; } + bool given() { return true; } + int as_int(int def UNUSED) { return val; } + string dump() { return " " + to_string(val); } +}; + class arg_double : public arg_val { double val; public: - bool given() { return true; } - explicit operator double () { return val; } arg_double(double x) { val = x; } - string dump() { return to_string(val); } + bool given() { return true; } + double as_double(double def UNUSED) { return val; } + string dump() { return " " + to_string(val); } }; class arg_string : public arg_val { string val; public: - bool given() { return true; } - explicit operator string () { return val; } arg_string(string x) { val = x; } - string dump() { return '"' + val + '"'; } + bool given() { return true; } + const string as_string(string def UNUSED) { return val; } + string dump() { return " \"" + val + '"'; } }; static arg_val null_arg; @@ -222,23 +238,15 @@ static void parse_pipeline(cmd *c) pipeline_branch *pb = new pipeline_branch; pp->branches.push_back(pb); + token_type t; for (;;) { - token_type t = next_token(); - if (t == TOK_CLOSE_BRACE || t == TOK_END) - parse_error("Premature end of pipeline"); - if (t == TOK_COLON) + t = next_token(); + if (t == TOK_END) + parse_error("Missing close brace"); + if (t == TOK_CLOSE_BRACE || t == TOK_COLON || t == TOK_COMMA) break; - if (pb->selectors.size()) - { - if (t != TOK_COMMA) - parse_error("Invalid pipeline selector"); - t = next_token(); - if (t == TOK_CLOSE_BRACE || t == TOK_END) - parse_error("Premature end of pipeline"); - } - pipeline_selector ps; if (t != TOK_NUMBER) parse_error("Pipeline selectors must start with a number"); @@ -261,7 +269,10 @@ static void parse_pipeline(cmd *c) pb->selectors.push_back(ps); } - parse_commands(&pb->commands); + if (t == TOK_COLON) + parse_commands(pb->commands); + else + return_token(); } c->pipe = pp; @@ -290,7 +301,10 @@ static void parse_args(cmd *c) for (;;) { t = next_token(); + if (t == TOK_CLOSE_PAREN) + break; uint argi = 0; + bool has_value = false; if (t == TOK_IDENT) { while (adefs[argi].name && token != adefs[argi].name) @@ -300,8 +314,10 @@ static void parse_args(cmd *c) if (c->args.at(argi)->given()) parse_error("Parameter %s given multiple times", token.c_str()); t = next_token(); - if (t != TOK_EQUAL) - parse_error("Parameter name must be followed by '='"); + if (t == TOK_EQUAL) + has_value = true; + else + return_token(); saw_named = true; } else if (saw_named) @@ -314,29 +330,53 @@ static void parse_args(cmd *c) if (next_pos >= num_args) parse_error("Too many positional arguments for command %s", cdef->name); argi = next_pos++; + has_value = true; } const arg_def *adef = &adefs[argi]; + uint type = adef->type & AT_TYPE_MASK; arg_val *val = NULL; - switch (adef->type & AT_TYPE_MASK) - { - case AT_STRING: - t = next_token(); - if (t != TOK_STRING) - parse_error("Parameter %s must be a string", adef->name); - val = new arg_string(token); - break; - case AT_DOUBLE: - t = next_token(); - if (t != TOK_NUMBER) - parse_error("Parameter %s must be a number", adef->name); - val = new arg_double(token_num); - break; - case AT_DIMEN: - val = new arg_double(parse_dimen(adef)); - break; - default: - abort(); + if (has_value) + { + switch (type) + { + case AT_STRING: + t = next_token(); + if (t != TOK_STRING) + parse_error("Parameter %s must be a string", adef->name); + val = new arg_string(token); + break; + case AT_INT: + t = next_token(); + if (t != TOK_NUMBER || !token_is_int()) + parse_error("Parameter %s must be an integer", adef->name); + val = new arg_int((int) token_num); + break; + case AT_DOUBLE: + t = next_token(); + if (t != TOK_NUMBER) + parse_error("Parameter %s must be a number", adef->name); + val = new arg_double(token_num); + break; + case AT_DIMEN: + val = new arg_double(parse_dimen(adef)); + break; + case AT_SWITCH: + t = next_token(); + if (t != TOK_NUMBER || !token_is_int() || ((int) token_num != 0 && (int) token_num != 1)) + parse_error("Parameter %s must be a switch", adef->name); + val = new arg_int((int) token_num); + break; + default: + abort(); + } + } + else + { + if (type == AT_SWITCH) + val = new arg_int(1); + else + parse_error("Parameter %s must have a value", adef->name); } c->args.at(argi) = val; @@ -377,9 +417,9 @@ static void debug_cmd(cmd *c, uint indent=0) } } -static void debug_cmds(list *cmds) +static void debug_cmds(list &cmds) { - for (auto c: *cmds) + for (auto c: cmds) debug_cmd(c); } @@ -409,7 +449,7 @@ static cmd *parse_cmd() return c; } -static void parse_commands(list *cmds) +static void parse_commands(list &cmds) { for (;;) { @@ -421,24 +461,24 @@ static void parse_commands(list *cmds) } cmd *c = parse_cmd(); - cmds->push_back(c); + cmds.push_back(c); } } -static void instantiate(list *cmds) +static void instantiate(list &cmds) { - for (auto c: *cmds) + for (auto c: cmds) { c->exec = c->def->constructor(c); if (c->pipe) { for (auto pb: c->pipe->branches) - instantiate(&pb->commands); + instantiate(pb->commands); } } } -void parse(const char *in, list *cmds) +void parse(const char *in, list &cmds) { in_pos = in; parse_commands(cmds); @@ -448,3 +488,29 @@ void parse(const char *in, list *cmds) debug_cmds(cmds); instantiate(cmds); } + +void parser_help() +{ + for (int i=0; cmd_table[i].name; i++) + { + const cmd_def *def = &cmd_table[i]; + printf("%s\n", def->name); + + const arg_def *arg = def->arg_defs; + static const char * const type_names[] = { + "string", "int", "double", "dimen", "switch" + }; + while (arg->name) + { + printf("\t%s (%s)%s%s\n", + arg->name, + type_names[arg->type & AT_TYPE_MASK], + (arg->type & AT_MANDATORY) ? " [mandatory]" : "", + (arg->type & AT_POSITIONAL) ? " [positional]" : ""); + arg++; + } + + if (def->has_pipeline) + printf("\t{ pipeline }\n"); + } +}