rewrite compilearg

master
Daniel Kolesa 2021-04-10 05:53:17 +02:00
parent e5cf9452f2
commit a6426c60ee
2 changed files with 109 additions and 110 deletions

View File

@ -396,10 +396,6 @@ std::string_view parser_state::get_word() {
return std::string_view{beg, std::size_t(source - beg)}; return std::string_view{beg, std::size_t(source - beg)};
} }
static bool compilearg(
parser_state &gs, int wordtype, charbuf *word = nullptr
);
/* lookups that are invalid but not causing an error */ /* lookups that are invalid but not causing an error */
static void lookup_invalid(gen_state &gs, int ltype) { static void lookup_invalid(gen_state &gs, int ltype) {
switch (ltype) { switch (ltype) {
@ -443,7 +439,7 @@ void parser_state::parse_lookup(int ltype) {
/* $(...), $[...] */ /* $(...), $[...] */
case '(': case '(':
case '[': case '[':
if (!compilearg(*this, VAL_STRING)) { if (!parse_arg(VAL_STRING)) {
lookup_invalid(gs, ltype); lookup_invalid(gs, ltype);
return; return;
} }
@ -602,10 +598,10 @@ bool parser_state::parse_subblock() {
switch (current()) { switch (current()) {
/* @(...) */ /* @(...) */
case '(': case '(':
return compilearg(*this, VAL_ANY); return parse_arg(VAL_ANY);
/* @[...]; like a variable lookup */ /* @[...]; like a variable lookup */
case '[': case '[':
if (!compilearg(*this, VAL_STRING)) { if (!parse_arg(VAL_STRING)) {
return false; return false;
} }
gs.gen_lookup_ident(); gs.gen_lookup_ident();
@ -807,125 +803,127 @@ done:
} }
} }
static bool compilearg( /* parses a single argument passed to anything
parser_state &gs, int wordtype, charbuf *word * this also includes left and right sides in assignments
) { * returns if we parsed something
gs.skip_comments(); */
switch (gs.current()) { bool parser_state::parse_arg(int ltype, charbuf *word) {
/* not a part of the grammar */
skip_comments();
/* guess what our argument is */
switch (current()) {
/* a plain string literal: "..." */
case '\"': case '\"':
switch (wordtype) { switch (ltype) {
case VAL_POP: case VAL_POP:
gs.get_str(); get_str();
break; break;
case VAL_COND: { case VAL_COND: {
size_t line = gs.current_line; auto line = current_line;
auto s = gs.get_str_dup(); auto s = get_str_dup();
if (!s.empty()) { if (!s.empty()) {
s.push_back('\0'); s.push_back('\0');
gs.gs.gen_block(s.str_term(), line); gs.gen_block(s.str_term(), line);
} else { } else {
gs.gs.gen_val_null(); gs.gen_val_null();
} }
break; break;
} }
case VAL_CODE: { case VAL_CODE: {
auto s = gs.get_str_dup(); auto line = current_line;
auto s = get_str_dup();
s.push_back('\0'); s.push_back('\0');
gs.gs.gen_block(s.str_term(), gs.current_line); gs.gen_block(s.str_term(), line);
break; break;
} }
case VAL_WORD: /* used to begin a statement */
if (word) { case VAL_WORD: {
*word = gs.get_str_dup(); *word = get_str_dup();
}
break; break;
}
case VAL_ANY: case VAL_ANY:
case VAL_STRING: case VAL_STRING:
gs.gs.gen_val_string_unescape(gs.get_str()); gs.gen_val_string_unescape(get_str());
break; break;
default: { default: {
int line = int(gs.current_line); auto line = current_line;
auto s = gs.get_str_dup(); auto s = get_str_dup();
s.push_back('\0'); s.push_back('\0');
gs.gs.gen_val(wordtype, s.str_term(), line); gs.gen_val(ltype, s.str_term(), line);
break; break;
} }
} }
return true; return true;
/* a lookup: $foo */
case '$': case '$':
gs.parse_lookup(wordtype); parse_lookup(ltype);
return true; return true;
/* an expression: (...) */
case '(': { case '(': {
gs.next_char(); next_char();
auto start = gs.gs.count(); auto start = gs.count();
gs.parse_block(VAL_ANY, ')'); parse_block(VAL_ANY, ')');
if (gs.gs.count() > start) { if (gs.count() > start) {
gs.gs.gen_push_result(wordtype); /* non-empty */
gs.gen_push_result(ltype);
} else { } else {
gs.gs.gen_val(wordtype); gs.gen_val(ltype);
return true; return true;
} }
switch (wordtype) { switch (ltype) {
case VAL_POP: case VAL_POP:
gs.gs.gen_pop(); gs.gen_pop();
break; break;
case VAL_COND: case VAL_COND:
gs.gs.gen_compile(true);
break;
case VAL_CODE: case VAL_CODE:
gs.gs.gen_compile(); gs.gen_compile(ltype == VAL_COND);
break; break;
case VAL_IDENT: case VAL_IDENT:
gs.gs.gen_ident_lookup(); gs.gen_ident_lookup();
break; break;
} }
return true; return true;
} }
/* a block: [...] */
case '[': case '[':
gs.next_char(); next_char();
gs.parse_blockarg(wordtype); parse_blockarg(ltype);
return true; return true;
/* something else, presumably a word */
default: default:
switch (wordtype) { break;
case VAL_POP: { }
return !gs.get_word().empty(); switch (ltype) {
} case VAL_POP:
case VAL_COND: { return !get_word().empty();
size_t line = gs.current_line; case VAL_COND:
auto s = gs.get_word(); case VAL_CODE: {
if (s.empty()) { auto line = current_line;
return false; auto s = get_word();
} if (s.empty()) {
gs.gs.gen_block(s, line); return false;
return true;
}
case VAL_CODE: {
size_t line = gs.current_line;
auto s = gs.get_word();
if (s.empty()) {
return false;
}
gs.gs.gen_block(s, line);
return true;
}
case VAL_WORD: {
auto w = gs.get_word();
if (word) {
word->clear();
word->append(w);
}
return !w.empty();
}
default: {
int line = int(gs.current_line);
auto s = gs.get_word();
if (s.empty()) {
return false;
}
gs.gs.gen_val(wordtype, s, line);
return true;
}
} }
gs.gen_block(s, line);
return true;
}
case VAL_WORD: {
auto s = get_word();
if (s.empty()) {
return false;
}
word->clear();
word->append(s);
return true;
}
default: {
auto line = current_line;
auto s = get_word();
if (s.empty()) {
return false;
}
gs.gen_val(ltype, s, line);
return true;
}
} }
} }
@ -940,7 +938,7 @@ static void compile_cmd(
switch (*it) { switch (*it) {
case 's': /* string */ case 's': /* string */
if (more && (!limit || (numcargs < limit))) { if (more && (!limit || (numcargs < limit))) {
more = compilearg(gs, VAL_STRING); more = gs.parse_arg(VAL_STRING);
} }
if (!more || (limit && (numcargs >= limit))) { if (!more || (limit && (numcargs >= limit))) {
if (rep) { if (rep) {
@ -951,7 +949,7 @@ static void compile_cmd(
} else if ((it + 1) == fmt.end()) { } else if ((it + 1) == fmt.end()) {
int numconc = 1; int numconc = 1;
for (;;) { for (;;) {
more = compilearg(gs, VAL_STRING); more = gs.parse_arg(VAL_STRING);
if (!more) { if (!more) {
break; break;
} }
@ -966,7 +964,7 @@ static void compile_cmd(
break; break;
case 'i': /* integer */ case 'i': /* integer */
if (more && (!limit || (numcargs < limit))) { if (more && (!limit || (numcargs < limit))) {
more = compilearg(gs, VAL_INT); more = gs.parse_arg(VAL_INT);
} }
if (!more || (limit && (numcargs >= limit))) { if (!more || (limit && (numcargs >= limit))) {
if (rep) { if (rep) {
@ -980,7 +978,7 @@ static void compile_cmd(
break; break;
case 'b': /* integer, INT_MIN default */ case 'b': /* integer, INT_MIN default */
if (more && (!limit || (numcargs < limit))) { if (more && (!limit || (numcargs < limit))) {
more = compilearg(gs, VAL_INT); more = gs.parse_arg(VAL_INT);
} }
if (!more || (limit && (numcargs >= limit))) { if (!more || (limit && (numcargs >= limit))) {
if (rep) { if (rep) {
@ -994,7 +992,7 @@ static void compile_cmd(
break; break;
case 'f': /* float */ case 'f': /* float */
if (more && (!limit || (numcargs < limit))) { if (more && (!limit || (numcargs < limit))) {
more = compilearg(gs, VAL_FLOAT); more = gs.parse_arg(VAL_FLOAT);
} }
if (!more || (limit && (numcargs >= limit))) { if (!more || (limit && (numcargs >= limit))) {
if (rep) { if (rep) {
@ -1008,7 +1006,7 @@ static void compile_cmd(
break; break;
case 'F': /* float, prev-argument default */ case 'F': /* float, prev-argument default */
if (more && (!limit || (numcargs < limit))) { if (more && (!limit || (numcargs < limit))) {
more = compilearg(gs, VAL_FLOAT); more = gs.parse_arg(VAL_FLOAT);
} }
if (!more || (limit && (numcargs >= limit))) { if (!more || (limit && (numcargs >= limit))) {
if (rep) { if (rep) {
@ -1022,7 +1020,7 @@ static void compile_cmd(
break; break;
case 't': /* any arg */ case 't': /* any arg */
if (more && (!limit || (numcargs < limit))) { if (more && (!limit || (numcargs < limit))) {
more = compilearg(gs, VAL_ANY); more = gs.parse_arg(VAL_ANY);
} }
if (!more || (limit && (numcargs >= limit))) { if (!more || (limit && (numcargs >= limit))) {
if (rep) { if (rep) {
@ -1036,7 +1034,7 @@ static void compile_cmd(
break; break;
case 'E': /* condition */ case 'E': /* condition */
if (more && (!limit || (numcargs < limit))) { if (more && (!limit || (numcargs < limit))) {
more = compilearg(gs, VAL_COND); more = gs.parse_arg(VAL_COND);
} }
if (!more || (limit && (numcargs >= limit))) { if (!more || (limit && (numcargs >= limit))) {
if (rep) { if (rep) {
@ -1050,7 +1048,7 @@ static void compile_cmd(
break; break;
case 'e': /* code */ case 'e': /* code */
if (more && (!limit || (numcargs < limit))) { if (more && (!limit || (numcargs < limit))) {
more = compilearg(gs, VAL_CODE); more = gs.parse_arg(VAL_CODE);
} }
if (!more || (limit && (numcargs >= limit))) { if (!more || (limit && (numcargs >= limit))) {
if (rep) { if (rep) {
@ -1064,7 +1062,7 @@ static void compile_cmd(
break; break;
case 'r': /* ident */ case 'r': /* ident */
if (more && (!limit || (numcargs < limit))) { if (more && (!limit || (numcargs < limit))) {
more = compilearg(gs, VAL_IDENT); more = gs.parse_arg(VAL_IDENT);
} }
if (!more || (limit && (numcargs >= limit))) { if (!more || (limit && (numcargs >= limit))) {
if (rep) { if (rep) {
@ -1088,7 +1086,7 @@ static void compile_cmd(
comtype = BC_INST_COM_C; comtype = BC_INST_COM_C;
if (more && (!limit || (numcargs < limit))) { if (more && (!limit || (numcargs < limit))) {
for (;;) { for (;;) {
more = compilearg(gs, VAL_ANY); more = gs.parse_arg(VAL_ANY);
if (!more || (limit && (numcargs >= limit))) { if (!more || (limit && (numcargs >= limit))) {
break; break;
} }
@ -1101,7 +1099,7 @@ static void compile_cmd(
comtype = BC_INST_COM_V; comtype = BC_INST_COM_V;
if (more && (!limit || (numcargs < limit))) { if (more && (!limit || (numcargs < limit))) {
for(;;) { for(;;) {
more = compilearg(gs, VAL_ANY); more = gs.parse_arg(VAL_ANY);
if (!more || (limit && (numcargs >= limit))) { if (!more || (limit && (numcargs >= limit))) {
break; break;
} }
@ -1128,7 +1126,7 @@ static void compile_cmd(
static void compile_alias(parser_state &gs, alias *id, bool &more) { static void compile_alias(parser_state &gs, alias *id, bool &more) {
std::uint32_t numargs = 0; std::uint32_t numargs = 0;
for (;;) { for (;;) {
more = compilearg(gs, VAL_ANY); more = gs.parse_arg(VAL_ANY);
if (!more) { if (!more) {
break; break;
} }
@ -1141,7 +1139,7 @@ static void compile_local(parser_state &gs, bool &more) {
std::uint32_t numargs = 0; std::uint32_t numargs = 0;
if (more) { if (more) {
for (;;) { for (;;) {
more = compilearg(gs, VAL_IDENT); more = gs.parse_arg(VAL_IDENT);
if (!more) { if (!more) {
break; break;
} }
@ -1155,7 +1153,7 @@ static void compile_do(
parser_state &gs, bool args, int rettype, bool &more parser_state &gs, bool args, int rettype, bool &more
) { ) {
if (more) { if (more) {
more = compilearg(gs, VAL_CODE); more = gs.parse_arg(VAL_CODE);
} }
if (!more) { if (!more) {
gs.gs.gen_result_null(rettype); gs.gs.gen_result_null(rettype);
@ -1169,7 +1167,7 @@ static void compile_if(
) { ) {
if (more) { if (more) {
/* condition */ /* condition */
more = compilearg(gs, VAL_ANY); more = gs.parse_arg(VAL_ANY);
} }
if (!more) { if (!more) {
/* no condition: expr is nothing */ /* no condition: expr is nothing */
@ -1177,7 +1175,7 @@ static void compile_if(
} else { } else {
auto tpos = gs.gs.count(); auto tpos = gs.gs.count();
/* true block */ /* true block */
more = compilearg(gs, VAL_CODE); more = gs.parse_arg(VAL_CODE);
if (!more) { if (!more) {
/* we only had condition: expr is nothing */ /* we only had condition: expr is nothing */
gs.gs.gen_pop(); gs.gs.gen_pop();
@ -1185,7 +1183,7 @@ static void compile_if(
} else { } else {
auto fpos = gs.gs.count(); auto fpos = gs.gs.count();
/* false block */ /* false block */
more = compilearg(gs, VAL_CODE); more = gs.parse_arg(VAL_CODE);
if (!gs.gs.gen_if(tpos, more ? fpos : 0)) { if (!gs.gs.gen_if(tpos, more ? fpos : 0)) {
/* can't fully compile: use a call */ /* can't fully compile: use a call */
gs.gs.gen_command_call(*id, BC_INST_COM, rettype); gs.gs.gen_command_call(*id, BC_INST_COM, rettype);
@ -1200,7 +1198,7 @@ static void compile_and_or(
std::uint32_t numargs = 0; std::uint32_t numargs = 0;
if (more) { if (more) {
/* first */ /* first */
more = compilearg(gs, VAL_COND); more = gs.parse_arg(VAL_COND);
} }
if (!more) { if (!more) {
/* no first: generate true or false */ /* no first: generate true or false */
@ -1214,7 +1212,7 @@ static void compile_and_or(
std::size_t start = gs.gs.count(), end = start; std::size_t start = gs.gs.count(), end = start;
for (;;) { for (;;) {
/* keep going as long as we only get blocks */ /* keep going as long as we only get blocks */
more = compilearg(gs, VAL_COND); more = gs.parse_arg(VAL_COND);
if (!more) { if (!more) {
break; break;
} }
@ -1228,7 +1226,7 @@ static void compile_and_or(
/* last parsed thing was not a block, fall back to call */ /* last parsed thing was not a block, fall back to call */
for (;;) { for (;;) {
/* but first, parse out the remainder of values */ /* but first, parse out the remainder of values */
more = compilearg(gs, VAL_COND); more = gs.parse_arg(VAL_COND);
if (!more) { if (!more) {
break; break;
} }
@ -1248,7 +1246,7 @@ void parser_state::parse_block(int rettype, int brak) {
skip_comments(); skip_comments();
idname.clear(); idname.clear();
size_t curline = current_line; size_t curline = current_line;
bool more = compilearg(*this, VAL_WORD, &idname); bool more = parse_arg(VAL_WORD, &idname);
if (!more) { if (!more) {
goto endstatement; goto endstatement;
} }
@ -1274,7 +1272,7 @@ void parser_state::parse_block(int rettype, int brak) {
); );
switch (id.get_type()) { switch (id.get_type()) {
case ident_type::ALIAS: case ident_type::ALIAS:
more = compilearg(*this, VAL_ANY); more = parse_arg(VAL_ANY);
if (!more) { if (!more) {
gs.gen_val_string(); gs.gen_val_string();
} }
@ -1309,7 +1307,7 @@ void parser_state::parse_block(int rettype, int brak) {
} }
gs.gen_val_string(idname.str_term()); gs.gen_val_string(idname.str_term());
} }
more = compilearg(*this, VAL_ANY); more = parse_arg(VAL_ANY);
if (!more) { if (!more) {
gs.gen_val_string(); gs.gen_val_string();
} }
@ -1321,7 +1319,7 @@ void parser_state::parse_block(int rettype, int brak) {
noid: noid:
std::uint32_t numargs = 0; std::uint32_t numargs = 0;
for (;;) { for (;;) {
more = compilearg(*this, VAL_ANY); more = parse_arg(VAL_ANY);
if (!more) { if (!more) {
break; break;
} }
@ -1385,7 +1383,7 @@ noid:
break; break;
case ID_RESULT: case ID_RESULT:
if (more) { if (more) {
more = compilearg(*this, VAL_ANY); more = parse_arg(VAL_ANY);
} }
if (!more) { if (!more) {
gs.gen_result_null(rettype); gs.gen_result_null(rettype);
@ -1395,7 +1393,7 @@ noid:
break; break;
case ID_NOT: case ID_NOT:
if (more) { if (more) {
more = compilearg(*this, VAL_ANY); more = parse_arg(VAL_ANY);
} }
if (!more) { if (!more) {
gs.gen_result_true(rettype); gs.gen_result_true(rettype);
@ -1436,7 +1434,7 @@ noid:
} }
endstatement: endstatement:
if (more) { if (more) {
while (compilearg(*this, VAL_POP)); while (parse_arg(VAL_POP));
} }
switch (skip_until(")];/\n")) { switch (skip_until(")];/\n")) {
case '\0': case '\0':

View File

@ -71,6 +71,7 @@ struct parser_state {
void parse_lookup(int ltype); void parse_lookup(int ltype);
bool parse_subblock(); bool parse_subblock();
void parse_blockarg(int ltype); void parse_blockarg(int ltype);
bool parse_arg(int ltype, charbuf *word = nullptr);
}; };
} /* namespace cubescript */ } /* namespace cubescript */