From 7229672f56f7ebd78144f2e7030bac5566a6a8f3 Mon Sep 17 00:00:00 2001 From: Daniel Kolesa Date: Sun, 11 Apr 2021 00:13:10 +0200 Subject: [PATCH] clean up command call parsing --- src/cs_parser.cc | 327 ++++++++++++++++++++++++----------------------- src/cs_parser.hh | 4 +- 2 files changed, 168 insertions(+), 163 deletions(-) diff --git a/src/cs_parser.cc b/src/cs_parser.cc index c4efe2d..f278325 100644 --- a/src/cs_parser.cc +++ b/src/cs_parser.cc @@ -943,26 +943,96 @@ bool parser_state::parse_arg(int ltype, charbuf *word) { } } +static bool parse_cmd_arg(parser_state &ps, char s, bool more, bool rep) { + switch (s) { + case 's': /* string */ + if (more) { + more = ps.parse_arg(VAL_STRING); + } + if (!more && !rep) { + ps.gs.gen_val_string(); + } + return more; + case 'i': /* integer */ + if (more) { + more = ps.parse_arg(VAL_INT); + } + if (!more && !rep) { + ps.gs.gen_val_integer(); + } + return more; + case 'b': /* integer, INT_MIN default */ + if (more) { + more = ps.parse_arg(VAL_INT); + } + if (!more && !rep) { + ps.gs.gen_val_integer(std::numeric_limits::min()); + } + return more; + case 'f': /* float */ + if (more) { + more = ps.parse_arg(VAL_FLOAT); + } + if (!more && !rep) { + ps.gs.gen_val_float(); + } + return more; + case 'F': /* float, prev-argument default */ + if (more) { + more = ps.parse_arg(VAL_FLOAT); + } + if (!more && !rep) { + ps.gs.gen_dup(VAL_FLOAT); + } + return more; + case 't': /* any arg */ + if (more) { + more = ps.parse_arg(VAL_ANY); + } + if (!more && !rep) { + ps.gs.gen_val_null(); + } + return more; + case 'E': /* condition */ + if (more) { + more = ps.parse_arg(VAL_COND); + } + if (!more && !rep) { + ps.gs.gen_val_null(); + } + return more; + case 'e': /* code */ + if (more) { + more = ps.parse_arg(VAL_CODE); + } + if (!more && !rep) { + ps.gs.gen_block(); + } + return more; + case 'r': /* ident */ + if (more) { + more = ps.parse_arg(VAL_IDENT); + } + if (!more && !rep) { + ps.gs.gen_val_ident(); + } + return more; + default: + return more; + } +} + bool parser_state::parse_call_command( - command_impl *id, ident &self, int rettype, std::uint32_t limit + command_impl *id, ident &self, int rettype ) { - std::uint32_t comtype = BC_INST_COM, numargs = 0, numcargs = 0, fakeargs = 0; - bool rep = false; + std::uint32_t comtype = BC_INST_COM, numargs = 0, fakeargs = 0; auto fmt = id->get_args(); - bool more = true; + bool more = true, rep = false; for (auto it = fmt.begin(); it != fmt.end(); ++it) { switch (*it) { case 's': /* string */ - if (more && (!limit || (numcargs < limit))) { - more = parse_arg(VAL_STRING); - } - if (!more || (limit && (numcargs >= limit))) { - if (rep) { - break; - } - gs.gen_val_string(); - fakeargs++; - } else if ((it + 1) == fmt.end()) { + more = parse_cmd_arg(*this, 's', more, rep); + if (more && ((it + 1) == fmt.end())) { int numconc = 1; for (;;) { more = parse_arg(VAL_STRING); @@ -974,166 +1044,54 @@ bool parser_state::parse_call_command( if (numconc > 1) { gs.gen_concat(numconc, true, VAL_STRING); } - } - numargs++; - numcargs++; - break; - case 'i': /* integer */ - if (more && (!limit || (numcargs < limit))) { - more = parse_arg(VAL_INT); - } - if (!more || (limit && (numcargs >= limit))) { - if (rep) { + } else if (!more) { + if (!rep) { + ++fakeargs; + } else { break; } - gs.gen_val_integer(); - fakeargs++; } - numargs++; - numcargs++; - break; - case 'b': /* integer, INT_MIN default */ - if (more && (!limit || (numcargs < limit))) { - more = parse_arg(VAL_INT); - } - if (!more || (limit && (numcargs >= limit))) { - if (rep) { - break; - } - gs.gen_val_integer(std::numeric_limits::min()); - fakeargs++; - } - numargs++; - numcargs++; - break; - case 'f': /* float */ - if (more && (!limit || (numcargs < limit))) { - more = parse_arg(VAL_FLOAT); - } - if (!more || (limit && (numcargs >= limit))) { - if (rep) { - break; - } - gs.gen_val_float(); - fakeargs++; - } - numargs++; - numcargs++; - break; - case 'F': /* float, prev-argument default */ - if (more && (!limit || (numcargs < limit))) { - more = parse_arg(VAL_FLOAT); - } - if (!more || (limit && (numcargs >= limit))) { - if (rep) { - break; - } - gs.gen_dup(VAL_FLOAT); - fakeargs++; - } - numargs++; - numcargs++; - break; - case 't': /* any arg */ - if (more && (!limit || (numcargs < limit))) { - more = parse_arg(VAL_ANY); - } - if (!more || (limit && (numcargs >= limit))) { - if (rep) { - break; - } - gs.gen_val_null(); - fakeargs++; - } - numargs++; - numcargs++; - break; - case 'E': /* condition */ - if (more && (!limit || (numcargs < limit))) { - more = parse_arg(VAL_COND); - } - if (!more || (limit && (numcargs >= limit))) { - if (rep) { - break; - } - gs.gen_val_null(); - fakeargs++; - } - numargs++; - numcargs++; - break; - case 'e': /* code */ - if (more && (!limit || (numcargs < limit))) { - more = parse_arg(VAL_CODE); - } - if (!more || (limit && (numcargs >= limit))) { - if (rep) { - break; - } - gs.gen_block(); - fakeargs++; - } - numargs++; - numcargs++; - break; - case 'r': /* ident */ - if (more && (!limit || (numcargs < limit))) { - more = parse_arg(VAL_IDENT); - } - if (!more || (limit && (numcargs >= limit))) { - if (rep) { - break; - } - gs.gen_val_ident(); - fakeargs++; - } - numargs++; - numcargs++; + ++numargs; break; case '$': /* self */ gs.gen_val_ident(self); - numargs++; + ++numargs; break; case 'N': /* number of arguments */ gs.gen_val_integer(numargs - fakeargs); - numargs++; + ++numargs; break; case 'C': /* concatenated string */ - comtype = BC_INST_COM_C; - if (more && (!limit || (numcargs < limit))) { + case 'V': /* varargs */ + comtype = (*it == 'C') ? BC_INST_COM_C : BC_INST_COM_V; + if (more) { for (;;) { more = parse_arg(VAL_ANY); - if (!more || (limit && (numcargs >= limit))) { + if (!more) { break; } - numargs++; - numcargs++; + ++numargs; } } break; - case 'V': /* varargs */ - comtype = BC_INST_COM_V; - if (more && (!limit || (numcargs < limit))) { - for(;;) { - more = parse_arg(VAL_ANY); - if (!more || (limit && (numcargs >= limit))) { - break; - } - numargs++; - numcargs++; - } - } - break; - case '1': /* vararg repetition */ - case '2': - case '3': - case '4': - if (more && (!limit || (numcargs < limit))) { + case '1': case '2': case '3': case '4': /* vararg repetition */ + if (more) { int numrep = *it - '0' + 1; it -= numrep; rep = true; } break; + default: + more = parse_cmd_arg(*this, *it, more, rep); + if (!more) { + if (!rep) { + ++fakeargs; + } else { + break; + } + } + ++numargs; + break; } } gs.gen_command_call(*id, comtype, rettype, numargs); @@ -1367,6 +1325,58 @@ static bool parse_no_id(parser_state &ps, int term) { return finish_statement(ps, false, term); } +static bool parse_assign_var( + parser_state &ps, command_impl *id, ident &var, int ltype +) { + auto fmt = id->get_args(); + std::uint32_t comtype = BC_INST_COM; + std::uint32_t nargs = 0; + bool more = true, got = false, rep = false; + for (auto it = fmt.begin(); it != fmt.end(); ++it) { + switch (*it) { + case '$': + ps.gs.gen_val_ident(var); + ++nargs; + break; + case 'N': + ps.gs.gen_val_integer(nargs); + ++nargs; + break; + case 'C': + case 'V': + comtype = (*it == 'C') ? BC_INST_COM_C : BC_INST_COM_V; + if (more && !got) { + more = ps.parse_arg(VAL_ANY); + if (more) { + got = true; + ++nargs; + } + } + break; + case '1': case '2': case '3': case '4': + if (more && !got) { + int numrep = *it - '0' + 1; + it -= numrep; + rep = true; + } + break; + default: { + auto gotarg = parse_cmd_arg(ps, *it, got ? false : more, rep); + if (!got) { + more = gotarg; + } + if (gotarg) { + ++nargs; + got = true; + } + break; + } + } + } + ps.gs.gen_command_call(*id, comtype, ltype, nargs); + return more; +} + bool parser_state::parse_assign( charbuf &idname, int ltype, int term, bool &noass ) { @@ -1409,25 +1419,22 @@ bool parser_state::parse_assign( } case ident_type::IVAR: { auto *hid = ts.istate->cmd_ivar; - bool more = parse_call_command( - static_cast(hid), - id, ltype, 1 + bool more = parse_assign_var( + *this, static_cast(hid), id, ltype ); return finish_statement(*this, more, term); } case ident_type::FVAR: { auto *hid = ts.istate->cmd_fvar; - bool more = parse_call_command( - static_cast(hid), - id, ltype, 1 + bool more = parse_assign_var( + *this, static_cast(hid), id, ltype ); return finish_statement(*this, more, term); } case ident_type::SVAR: { auto *hid = ts.istate->cmd_svar; - bool more = parse_call_command( - static_cast(hid), - id, ltype, 1 + bool more = parse_assign_var( + *this, static_cast(hid), id, ltype ); return finish_statement(*this, more, term); } diff --git a/src/cs_parser.hh b/src/cs_parser.hh index 8e7b10c..e11afa4 100644 --- a/src/cs_parser.hh +++ b/src/cs_parser.hh @@ -73,9 +73,7 @@ struct parser_state { void parse_blockarg(int ltype); bool parse_arg(int ltype, charbuf *word = nullptr); - bool parse_call_command( - command_impl *id, ident &self, int rettype, std::uint32_t limit = 0 - ); + bool parse_call_command(command_impl *id, ident &self, int rettype); bool parse_call_alias(alias &id); bool parse_call_id(ident &id, int ltype);