libcubescript/src/cs_gen.cc

1506 lines
52 KiB
C++
Raw Normal View History

2017-06-20 21:21:39 +02:00
#include <cubescript/cubescript.hh>
#include "cs_vm.hh"
#include "cs_util.hh"
#include <ctype.h>
2017-02-09 20:59:14 +01:00
#include <limits>
namespace cscript {
2017-02-16 19:07:22 +01:00
ostd::string_range cs_gen_state::get_str() {
2017-01-25 02:09:50 +01:00
size_t nl;
2017-02-16 19:07:22 +01:00
ostd::string_range beg = source;
2016-10-11 21:23:04 +02:00
source = util::parse_string(cs, source, nl);
2016-10-15 21:15:19 +02:00
current_line += nl - 1;
2017-06-15 20:44:09 +02:00
ostd::string_range ret = beg.slice(0, &source[0] - &beg[0]);
2016-10-11 21:23:04 +02:00
return ret.slice(1, ret.size() - 1);
2016-09-20 22:11:40 +02:00
}
2017-02-13 18:10:40 +01:00
cs_string cs_gen_state::get_str_dup(bool unescape) {
2016-09-20 22:11:40 +02:00
auto str = get_str();
2017-04-17 17:13:14 +02:00
auto app = ostd::appender<cs_string>();
2016-09-20 22:11:40 +02:00
if (unescape) {
util::unescape_string(app, str);
} else {
app.get() = str;
}
2017-01-25 01:57:33 +01:00
return std::move(app.get());
2016-09-20 22:11:40 +02:00
}
2017-02-16 19:07:22 +01:00
ostd::string_range cs_gen_state::read_macro_name() {
2016-09-22 01:07:43 +02:00
auto op = source;
2016-09-22 00:20:23 +02:00
char c = current();
if (!isalpha(c) && (c != '_')) {
return nullptr;
}
for (; isalnum(c) || (c == '_'); c = current()) {
next_char();
}
2017-06-15 20:44:09 +02:00
return op.slice(0, &source[0] - &op[0]);
2016-09-22 00:20:23 +02:00
}
2017-02-16 19:07:22 +01:00
char cs_gen_state::skip_until(ostd::string_range chars) {
2016-09-22 00:20:23 +02:00
char c = current();
while (c && ostd::find(chars, c).empty()) {
next_char();
c = current();
}
return c;
}
2017-02-13 18:10:40 +01:00
char cs_gen_state::skip_until(char cf) {
2016-09-22 00:20:23 +02:00
char c = current();
while (c && (c != cf)) {
next_char();
c = current();
}
return c;
}
static bool cs_is_hspace(char c) {
return (c == ' ') || (c == '\t') || (c == '\r');
}
2017-02-13 18:10:40 +01:00
void cs_gen_state::skip_comments() {
for (;;) {
2016-09-22 00:20:23 +02:00
for (char c = current(); cs_is_hspace(c); c = current()) {
next_char();
}
if (current() == '\\') {
char c = current(1);
if ((c != '\r') && (c != '\n')) {
2017-02-13 18:10:40 +01:00
throw cs_error(cs, "invalid line break");
}
/* skip backslash */
next_char();
/* skip CR or LF */
next_char();
/* when CR, try also skipping LF; covers \r, \n, \r\n */
if ((c == '\r') && (current(1) == '\n')) {
next_char();
}
/* skip whitespace on new line */
continue;
}
2016-09-22 00:20:23 +02:00
if ((current() != '/') || (current(1) != '/')) {
return;
}
while (current() != '\n') {
next_char();
2016-08-17 02:25:12 +02:00
}
}
}
2017-02-16 19:07:22 +01:00
ostd::string_range cs_gen_state::get_word() {
2016-09-22 01:07:43 +02:00
auto beg = source;
source = util::parse_word(cs, source);
2017-06-15 20:44:09 +02:00
return beg.slice(0, &source[0] - &beg[0]);
}
static inline int cs_ret_code(int type, int def = 0) {
2016-09-07 20:20:36 +02:00
if (type >= CsValAny) {
return (type == CsValCstring) ? CsRetString : def;
2016-08-17 02:25:12 +02:00
}
2016-09-07 20:20:36 +02:00
return type << CsCodeRet;
}
2016-08-17 02:25:12 +02:00
static void compilestatements(
2017-02-13 18:10:40 +01:00
cs_gen_state &gs, int rettype, int brak = '\0', int prevargs = 0
2016-08-17 02:25:12 +02:00
);
2017-02-16 19:07:22 +01:00
static inline std::pair<ostd::string_range, size_t> compileblock(
cs_gen_state &gs, ostd::string_range p, size_t line,
2016-09-22 01:44:35 +02:00
int rettype = CsRetNull, int brak = '\0'
2016-08-17 02:25:12 +02:00
);
2017-02-16 19:07:22 +01:00
void cs_gen_state::gen_int(ostd::string_range word) {
2016-08-15 19:55:22 +02:00
gen_int(cs_parse_int(word));
}
2017-02-16 19:07:22 +01:00
void cs_gen_state::gen_float(ostd::string_range word) {
2016-08-15 19:55:22 +02:00
gen_float(cs_parse_float(word));
}
2017-02-16 19:07:22 +01:00
void cs_gen_state::gen_value(int wordtype, ostd::string_range word, int line) {
switch (wordtype) {
2016-09-07 20:20:36 +02:00
case CsValCany:
2016-08-17 02:25:12 +02:00
if (!word.empty()) {
gen_str(word, true);
} else {
gen_null();
}
break;
2016-09-07 20:20:36 +02:00
case CsValCstring:
gen_str(word, true);
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsValAny:
2016-08-17 02:25:12 +02:00
if (!word.empty()) {
gen_str(word);
} else {
gen_null();
}
break;
2016-09-07 20:20:36 +02:00
case CsValString:
gen_str(word);
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsValFloat:
2016-08-17 02:25:12 +02:00
gen_float(word);
break;
2016-09-07 20:20:36 +02:00
case CsValInt:
2016-08-17 02:25:12 +02:00
gen_int(word);
break;
2016-09-07 20:20:36 +02:00
case CsValCond:
2016-08-17 02:25:12 +02:00
if (!word.empty()) {
2016-09-22 01:44:35 +02:00
compileblock(*this, word, line);
2016-08-17 02:25:12 +02:00
} else {
gen_null();
}
break;
2016-09-07 20:20:36 +02:00
case CsValCode:
2016-09-22 01:44:35 +02:00
compileblock(*this, word, line);
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsValIdent:
2016-08-17 02:25:12 +02:00
gen_ident(word);
break;
default:
break;
}
}
2017-02-13 18:10:40 +01:00
static inline void compileblock(cs_gen_state &gs) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeEmpty);
}
2017-02-16 19:07:22 +01:00
static inline std::pair<ostd::string_range, size_t> compileblock(
cs_gen_state &gs, ostd::string_range p, size_t line, int rettype, int brak
2016-08-17 02:25:12 +02:00
) {
2017-01-25 02:09:50 +01:00
size_t start = gs.code.size();
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeBlock);
gs.code.push_back(CsCodeOffset | ((start + 2) << 8));
2017-01-25 02:09:50 +01:00
size_t retline = line;
if (p) {
2017-02-16 19:07:22 +01:00
ostd::string_range op = gs.source;
2017-01-25 02:09:50 +01:00
size_t oldline = gs.current_line;
gs.source = p;
2016-09-22 01:44:35 +02:00
gs.current_line = line;
2016-09-07 20:20:36 +02:00
compilestatements(gs, CsValAny, brak);
p = gs.source;
2016-09-22 01:44:35 +02:00
retline = gs.current_line;
gs.source = op;
2016-09-22 01:44:35 +02:00
gs.current_line = oldline;
}
if (gs.code.size() > start + 2) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeExit | rettype);
2017-01-25 02:10:17 +01:00
gs.code[start] |= uint32_t(gs.code.size() - (start + 1)) << 8;
} else {
gs.code.resize(start);
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeEmpty | rettype);
}
2017-01-28 23:04:10 +01:00
return std::make_pair(p, retline);
}
2017-02-13 18:10:40 +01:00
static inline void compileunescapestr(cs_gen_state &gs, bool macro = false) {
2016-09-20 22:24:56 +02:00
auto str = gs.get_str();
2017-01-25 01:18:29 +01:00
gs.code.push_back(macro ? CsCodeMacro : (CsCodeVal | CsRetString));
2016-08-17 02:25:12 +02:00
gs.code.reserve(
2017-01-25 02:10:17 +01:00
gs.code.size() + str.size() / sizeof(uint32_t) + 1
2016-08-17 02:25:12 +02:00
);
2017-01-25 02:10:17 +01:00
size_t bufs = (gs.code.capacity() - gs.code.size()) * sizeof(uint32_t);
2017-01-25 01:18:29 +01:00
char *buf = new char[bufs + 1];
2017-02-16 19:07:22 +01:00
auto writer = ostd::char_range(buf, buf + bufs);
2017-04-17 17:13:14 +02:00
size_t len = util::unescape_string(ostd::counting_sink(writer), str).get_written();
2017-01-25 02:10:17 +01:00
memset(&buf[len], 0, sizeof(uint32_t) - len % sizeof(uint32_t));
gs.code.back() |= len << 8;
2017-01-25 01:18:29 +01:00
uint32_t *ubuf = reinterpret_cast<uint32_t *>(buf);
2017-01-25 02:10:17 +01:00
gs.code.insert(gs.code.end(), ubuf, ubuf + (len / sizeof(uint32_t) + 1));
2017-01-25 01:18:29 +01:00
delete[] buf;
}
2016-08-17 02:25:12 +02:00
static bool compilearg(
2017-02-13 18:10:40 +01:00
cs_gen_state &gs, int wordtype, int prevargs = MaxResults,
cs_string *word = nullptr
2016-08-17 02:25:12 +02:00
);
2017-02-13 18:10:40 +01:00
static void compilelookup(cs_gen_state &gs, int ltype, int prevargs = MaxResults) {
cs_string lookup;
gs.next_char();
switch (gs.current()) {
2016-08-17 02:25:12 +02:00
case '(':
case '[':
2016-09-07 20:20:36 +02:00
if (!compilearg(gs, CsValCstring, prevargs)) {
2016-08-17 02:25:12 +02:00
goto invalid;
}
break;
case '$':
2016-09-07 20:20:36 +02:00
compilelookup(gs, CsValCstring, prevargs);
2016-08-17 02:25:12 +02:00
break;
case '\"':
2016-09-20 22:11:40 +02:00
lookup = gs.get_str_dup();
2016-08-17 02:25:12 +02:00
goto lookupid;
default: {
2016-09-20 22:11:40 +02:00
lookup = gs.get_word();
if (lookup.empty()) goto invalid;
lookupid:
2017-02-13 18:10:40 +01:00
cs_ident *id = gs.cs.new_ident(lookup);
2016-08-17 02:25:12 +02:00
if (id) {
2016-08-18 03:53:51 +02:00
switch (id->get_type()) {
2017-02-13 18:10:40 +01:00
case cs_ident_type::Ivar:
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-09-07 20:20:36 +02:00
CsCodeIvar | cs_ret_code(ltype, CsRetInt) |
2016-08-18 03:53:51 +02:00
(id->get_index() << 8)
2016-08-17 02:25:12 +02:00
);
switch (ltype) {
2016-09-07 20:20:36 +02:00
case CsValPop:
2017-01-25 01:18:29 +01:00
gs.code.pop_back();
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsValCode:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeCompile);
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsValIdent:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeIdentU);
2016-08-17 02:25:12 +02:00
break;
}
return;
2017-02-13 18:10:40 +01:00
case cs_ident_type::Fvar:
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-09-07 20:20:36 +02:00
CsCodeFvar | cs_ret_code(ltype, CsRetFloat) |
2016-08-18 03:53:51 +02:00
(id->get_index() << 8)
2016-08-17 02:25:12 +02:00
);
switch (ltype) {
2016-09-07 20:20:36 +02:00
case CsValPop:
2017-01-25 01:18:29 +01:00
gs.code.pop_back();
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsValCode:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeCompile);
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsValIdent:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeIdentU);
2016-08-17 02:25:12 +02:00
break;
}
return;
2017-02-13 18:10:40 +01:00
case cs_ident_type::Svar:
2016-08-17 02:25:12 +02:00
switch (ltype) {
2016-09-07 20:20:36 +02:00
case CsValPop:
2016-08-17 02:25:12 +02:00
return;
2016-09-07 20:20:36 +02:00
case CsValCany:
case CsValCstring:
case CsValCode:
case CsValIdent:
case CsValCond:
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-09-07 20:20:36 +02:00
CsCodeSvarM | (id->get_index() << 8)
2016-08-18 03:53:51 +02:00
);
2016-08-17 02:25:12 +02:00
break;
default:
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-09-07 20:20:36 +02:00
CsCodeSvar | cs_ret_code(ltype, CsRetString) |
2016-08-18 03:53:51 +02:00
(id->get_index() << 8)
2016-08-17 02:25:12 +02:00
);
break;
}
goto done;
2017-02-13 18:10:40 +01:00
case cs_ident_type::Alias:
2016-08-17 02:25:12 +02:00
switch (ltype) {
2016-09-07 20:20:36 +02:00
case CsValPop:
2016-08-17 02:25:12 +02:00
return;
2016-09-07 20:20:36 +02:00
case CsValCany:
case CsValCond:
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-08-18 03:53:51 +02:00
(id->get_index() < MaxArguments
2016-09-07 20:20:36 +02:00
? CsCodeLookupMarg
: CsCodeLookupM
2016-08-18 03:53:51 +02:00
) | (id->get_index() << 8)
2016-08-17 02:25:12 +02:00
);
break;
2016-09-07 20:20:36 +02:00
case CsValCstring:
case CsValCode:
case CsValIdent:
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-08-18 03:53:51 +02:00
(id->get_index() < MaxArguments
2016-09-07 20:20:36 +02:00
? CsCodeLookupMarg
: CsCodeLookupM
) | CsRetString | (id->get_index() << 8)
2016-08-17 02:25:12 +02:00
);
break;
default:
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-08-18 03:53:51 +02:00
(id->get_index() < MaxArguments
2016-09-07 20:20:36 +02:00
? CsCodeLookupArg
: CsCodeLookup
) | cs_ret_code(ltype, CsRetString) |
2016-08-18 03:53:51 +02:00
(id->get_index() << 8)
2016-08-17 02:25:12 +02:00
);
break;
}
goto done;
2017-02-13 18:10:40 +01:00
case cs_ident_type::Command: {
2016-09-07 20:20:36 +02:00
int comtype = CsCodeCom, numargs = 0;
2016-08-17 02:25:12 +02:00
if (prevargs >= MaxResults) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeEnter);
2016-08-17 02:25:12 +02:00
}
2017-02-13 18:10:40 +01:00
auto fmt = static_cast<cs_command *>(id)->get_args();
for (char c: fmt) {
switch (c) {
2016-08-17 02:25:12 +02:00
case 'S':
gs.gen_str();
numargs++;
break;
case 's':
2017-02-16 19:07:22 +01:00
gs.gen_str(ostd::string_range(), true);
2016-08-17 02:25:12 +02:00
numargs++;
break;
case 'i':
gs.gen_int();
numargs++;
break;
case 'b':
2017-02-13 18:10:40 +01:00
gs.gen_int(std::numeric_limits<cs_int>::min());
2016-08-17 02:25:12 +02:00
numargs++;
break;
case 'f':
gs.gen_float();
numargs++;
break;
case 'F':
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeDup | CsRetFloat);
2016-08-17 02:25:12 +02:00
numargs++;
break;
case 'E':
case 'T':
case 't':
gs.gen_null();
numargs++;
break;
case 'e':
compileblock(gs);
numargs++;
break;
case 'r':
gs.gen_ident();
numargs++;
break;
case '$':
gs.gen_ident(id);
numargs++;
break;
case 'N':
gs.gen_int(-1);
numargs++;
break;
case 'C':
2016-09-07 20:20:36 +02:00
comtype = CsCodeComC;
2016-08-17 02:25:12 +02:00
goto compilecomv;
case 'V':
2016-09-07 20:20:36 +02:00
comtype = CsCodeComV;
2016-08-17 02:25:12 +02:00
goto compilecomv;
case '1':
case '2':
case '3':
case '4':
break;
}
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-08-18 03:53:51 +02:00
comtype | cs_ret_code(ltype) | (id->get_index() << 8)
2016-08-17 02:25:12 +02:00
);
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-08-17 02:25:12 +02:00
(prevargs >= MaxResults
2016-09-07 20:20:36 +02:00
? CsCodeExit
: CsCodeResultArg
2016-08-17 02:25:12 +02:00
) | cs_ret_code(ltype)
);
goto done;
compilecomv:
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-08-17 02:25:12 +02:00
comtype | cs_ret_code(ltype) | (numargs << 8) |
2016-08-18 03:53:51 +02:00
(id->get_index() << 13)
2016-08-17 02:25:12 +02:00
);
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-08-17 02:25:12 +02:00
(prevargs >= MaxResults
2016-09-07 20:20:36 +02:00
? CsCodeExit
: CsCodeResultArg
2016-08-17 02:25:12 +02:00
) | cs_ret_code(ltype)
);
goto done;
}
2016-08-17 02:25:12 +02:00
default:
goto invalid;
}
}
2016-09-20 22:11:40 +02:00
gs.gen_str(lookup, true);
2016-08-17 02:25:12 +02:00
break;
}
}
switch (ltype) {
2016-09-07 20:20:36 +02:00
case CsValCany:
case CsValCond:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeLookupMu);
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsValCstring:
case CsValCode:
case CsValIdent:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeLookupMu | CsRetString);
2016-08-17 02:25:12 +02:00
break;
default:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeLookupU | cs_ret_code(ltype));
2016-08-17 02:25:12 +02:00
break;
}
done:
switch (ltype) {
2016-09-07 20:20:36 +02:00
case CsValPop:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodePop);
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsValCode:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeCompile);
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsValCond:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeCond);
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsValIdent:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeIdentU);
2016-08-17 02:25:12 +02:00
break;
}
return;
invalid:
switch (ltype) {
2016-09-07 20:20:36 +02:00
case CsValPop:
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsValNull:
case CsValAny:
case CsValCany:
case CsValWord:
case CsValCond:
2016-08-17 02:25:12 +02:00
gs.gen_null();
break;
default:
gs.gen_value(ltype);
break;
}
}
2017-02-16 19:07:22 +01:00
static bool compileblockstr(cs_gen_state &gs, ostd::string_range str, bool macro) {
int startc = gs.code.size();
2017-01-25 01:18:29 +01:00
gs.code.push_back(macro ? CsCodeMacro : CsCodeVal | CsRetString);
2017-01-25 02:10:17 +01:00
gs.code.reserve(gs.code.size() + str.size() / sizeof(uint32_t) + 1);
2017-01-25 01:57:33 +01:00
char *buf = new char[(str.size() / sizeof(uint32_t) + 1) * sizeof(uint32_t)];
int len = 0;
while (!str.empty()) {
char const *p = str.data();
2017-02-16 19:07:22 +01:00
str = ostd::find_one_of(str, ostd::string_range("\r/\"@]"));
memcpy(&buf[len], p, str.data() - p);
len += str.data() - p;
2016-08-17 02:25:12 +02:00
if (str.empty()) {
goto done;
}
2016-08-17 02:25:12 +02:00
switch (str.front()) {
case '\r':
str.pop_front();
2016-08-17 02:25:12 +02:00
break;
case '\"': {
2017-06-15 20:44:09 +02:00
auto start = str;
2016-10-12 02:05:55 +02:00
str = util::parse_string(gs.cs, str);
2017-06-15 20:44:09 +02:00
auto strr = start.slice(0, &str[0] - &start[0]);
2016-10-12 02:05:55 +02:00
memcpy(&buf[len], strr.data(), strr.size());
len += strr.size();
2016-08-17 02:25:12 +02:00
break;
}
2016-08-17 02:25:12 +02:00
case '/':
if (str[1] == '/') {
str = ostd::find(str, '\n');
} else {
buf[len++] = str.front();
str.pop_front();
}
break;
case '@':
case ']':
buf[len++] = str.front();
str.pop_front();
break;
}
}
done:
2017-01-25 02:10:17 +01:00
memset(&buf[len], '\0', sizeof(uint32_t) - len % sizeof(uint32_t));
2017-01-25 01:18:29 +01:00
uint32_t *ubuf = reinterpret_cast<uint32_t *>(buf);
2017-01-25 02:10:17 +01:00
gs.code.insert(gs.code.end(), ubuf, ubuf + (len / sizeof(uint32_t) + 1));
gs.code[startc] |= len << 8;
2017-01-25 01:18:29 +01:00
delete[] buf;
return true;
}
2017-02-13 18:10:40 +01:00
static bool compileblocksub(cs_gen_state &gs, int prevargs) {
cs_string lookup;
switch (gs.current()) {
2016-08-17 02:25:12 +02:00
case '(':
2016-09-07 20:20:36 +02:00
if (!compilearg(gs, CsValCany, prevargs)) {
2016-08-17 02:25:12 +02:00
return false;
}
2016-08-17 02:25:12 +02:00
break;
case '[':
2016-09-07 20:20:36 +02:00
if (!compilearg(gs, CsValCstring, prevargs)) {
2016-08-17 02:25:12 +02:00
return false;
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeLookupMu);
2016-08-17 02:25:12 +02:00
break;
case '\"':
2016-09-20 22:11:40 +02:00
lookup = gs.get_str_dup();
2016-08-17 02:25:12 +02:00
goto lookupid;
default: {
2016-09-22 00:20:23 +02:00
lookup = gs.read_macro_name();
2016-09-20 22:11:40 +02:00
if (lookup.empty()) {
2016-08-17 02:25:12 +02:00
return false;
}
lookupid:
2017-02-13 18:10:40 +01:00
cs_ident *id = gs.cs.new_ident(lookup);
2016-08-17 02:25:12 +02:00
if (id) {
2016-08-18 03:53:51 +02:00
switch (id->get_type()) {
2017-02-13 18:10:40 +01:00
case cs_ident_type::Ivar:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeIvar | (id->get_index() << 8));
2016-08-17 02:25:12 +02:00
goto done;
2017-02-13 18:10:40 +01:00
case cs_ident_type::Fvar:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeFvar | (id->get_index() << 8));
2016-08-17 02:25:12 +02:00
goto done;
2017-02-13 18:10:40 +01:00
case cs_ident_type::Svar:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeSvarM | (id->get_index() << 8));
2016-08-17 02:25:12 +02:00
goto done;
2017-02-13 18:10:40 +01:00
case cs_ident_type::Alias:
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-08-18 03:53:51 +02:00
(id->get_index() < MaxArguments
2016-09-07 20:20:36 +02:00
? CsCodeLookupMarg
: CsCodeLookupM
2016-08-18 03:53:51 +02:00
) | (id->get_index() << 8)
2016-08-17 02:25:12 +02:00
);
goto done;
2016-08-18 03:53:51 +02:00
default:
break;
2016-08-17 02:25:12 +02:00
}
}
2016-09-20 22:11:40 +02:00
gs.gen_str(lookup, true);
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeLookupMu);
done:
2016-08-17 02:25:12 +02:00
break;
}
}
return true;
}
2017-02-13 18:10:40 +01:00
static void compileblockmain(cs_gen_state &gs, int wordtype, int prevargs) {
2016-09-22 01:07:43 +02:00
char const *start = gs.source.data();
2017-01-25 02:09:50 +01:00
size_t curline = gs.current_line;
int concs = 0;
for (int brak = 1; brak;) {
2016-09-22 00:20:23 +02:00
switch (gs.skip_until("@\"/[]")) {
2016-08-17 02:25:12 +02:00
case '\0':
2017-02-13 18:10:40 +01:00
throw cs_error(gs.cs, "missing \"]\"");
2016-09-10 15:01:49 +02:00
return;
2016-08-17 02:25:12 +02:00
case '\"':
2016-09-20 22:24:56 +02:00
gs.get_str();
2016-08-17 02:25:12 +02:00
break;
case '/':
2016-09-20 22:24:56 +02:00
gs.next_char();
2016-08-17 02:25:12 +02:00
if (gs.current() == '/') {
2016-09-22 00:20:23 +02:00
gs.skip_until('\n');
2016-08-17 02:25:12 +02:00
}
break;
case '[':
2016-09-20 22:24:56 +02:00
gs.next_char();
2016-08-17 02:25:12 +02:00
brak++;
break;
case ']':
2016-09-20 22:24:56 +02:00
gs.next_char();
2016-08-17 02:25:12 +02:00
brak--;
break;
case '@': {
2016-09-22 01:07:43 +02:00
char const *esc = gs.source.data();
2016-09-22 00:40:33 +02:00
int level = 0;
2016-08-17 02:25:12 +02:00
while (gs.current() == '@') {
2016-09-22 00:40:33 +02:00
++level;
2016-08-17 02:25:12 +02:00
gs.next_char();
}
if (brak > level) {
continue;
} else if (brak < level) {
2017-02-13 18:10:40 +01:00
throw cs_error(gs.cs, "too many @s");
2016-09-10 15:01:49 +02:00
return;
2016-08-17 02:25:12 +02:00
}
if (!concs && prevargs >= MaxResults) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeEnter);
2016-08-17 02:25:12 +02:00
}
if (concs + 2 > MaxArguments) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeConcW | CsRetString | (concs << 8));
2016-08-17 02:25:12 +02:00
concs = 1;
}
if (compileblockstr(
2017-02-16 19:07:22 +01:00
gs, ostd::string_range(start, esc), true
2016-08-17 02:25:12 +02:00
)) {
concs++;
}
if (compileblocksub(gs, prevargs + concs)) {
concs++;
}
if (concs) {
2016-09-22 01:07:43 +02:00
start = gs.source.data();
2016-09-22 01:44:35 +02:00
curline = gs.current_line;
2016-08-17 02:25:12 +02:00
} else if (prevargs >= MaxResults) {
2017-01-25 01:18:29 +01:00
gs.code.pop_back();
2016-08-17 02:25:12 +02:00
}
break;
2016-09-22 01:07:43 +02:00
}
2016-09-22 00:40:33 +02:00
default:
gs.next_char();
break;
}
}
2016-09-22 01:07:43 +02:00
if (gs.source.data() - 1 > start) {
2016-08-17 02:25:12 +02:00
if (!concs) {
switch (wordtype) {
2016-09-07 20:20:36 +02:00
case CsValPop:
2016-08-17 02:25:12 +02:00
return;
2016-09-07 20:20:36 +02:00
case CsValCode:
2016-09-22 01:44:35 +02:00
case CsValCond: {
2017-02-16 19:07:22 +01:00
auto ret = compileblock(gs, ostd::string_range(
2016-09-22 01:07:43 +02:00
start, gs.source.data() + gs.source.size()
2016-09-22 01:44:35 +02:00
), curline, CsRetNull, ']');
gs.source = ret.first;
gs.current_line = ret.second;
2016-08-17 02:25:12 +02:00
return;
2016-09-22 01:44:35 +02:00
}
2016-09-07 20:20:36 +02:00
case CsValIdent:
2017-02-16 19:07:22 +01:00
gs.gen_ident(ostd::string_range(start, gs.source.data() - 1));
2016-08-17 02:25:12 +02:00
return;
}
2016-08-17 02:25:12 +02:00
}
switch (wordtype) {
2016-09-07 20:20:36 +02:00
case CsValCstring:
case CsValCode:
case CsValIdent:
case CsValCany:
case CsValCond:
2016-08-17 02:25:12 +02:00
compileblockstr(
2017-02-16 19:07:22 +01:00
gs, ostd::string_range(start, gs.source.data() - 1), true
2016-08-17 02:25:12 +02:00
);
break;
default:
compileblockstr(
2017-02-16 19:07:22 +01:00
gs, ostd::string_range(start, gs.source.data() - 1), concs > 0
2016-08-17 02:25:12 +02:00
);
break;
}
if (concs > 1) {
concs++;
}
}
if (concs) {
if (prevargs >= MaxResults) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeConcM | cs_ret_code(wordtype) | (concs << 8));
gs.code.push_back(CsCodeExit | cs_ret_code(wordtype));
2016-08-17 02:25:12 +02:00
} else {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeConcW | cs_ret_code(wordtype) | (concs << 8));
}
}
2016-08-17 02:25:12 +02:00
switch (wordtype) {
2016-09-07 20:20:36 +02:00
case CsValPop:
2016-09-22 01:07:43 +02:00
if (concs || gs.source.data() - 1 > start) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodePop);
2016-08-17 02:25:12 +02:00
}
break;
2016-09-07 20:20:36 +02:00
case CsValCond:
2016-09-22 01:07:43 +02:00
if (!concs && gs.source.data() - 1 <= start) {
2016-08-17 02:25:12 +02:00
gs.gen_null();
} else {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeCond);
2016-08-17 02:25:12 +02:00
}
break;
2016-09-07 20:20:36 +02:00
case CsValCode:
2016-09-22 01:07:43 +02:00
if (!concs && gs.source.data() - 1 <= start) {
2016-08-17 02:25:12 +02:00
compileblock(gs);
} else {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeCompile);
2016-08-17 02:25:12 +02:00
}
break;
2016-09-07 20:20:36 +02:00
case CsValIdent:
2016-09-22 01:07:43 +02:00
if (!concs && gs.source.data() - 1 <= start) {
2016-08-17 02:25:12 +02:00
gs.gen_ident();
} else {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeIdentU);
2016-08-17 02:25:12 +02:00
}
break;
2016-09-07 20:20:36 +02:00
case CsValCstring:
case CsValCany:
2016-09-22 01:07:43 +02:00
if (!concs && gs.source.data() - 1 <= start) {
2017-02-16 19:07:22 +01:00
gs.gen_str(ostd::string_range(), true);
}
break;
2016-09-07 20:20:36 +02:00
case CsValString:
case CsValNull:
case CsValAny:
case CsValWord:
2016-09-22 01:07:43 +02:00
if (!concs && gs.source.data() - 1 <= start) {
2016-08-17 02:25:12 +02:00
gs.gen_str();
}
break;
2016-08-17 02:25:12 +02:00
default:
if (!concs) {
2016-09-22 01:07:43 +02:00
if (gs.source.data() - 1 <= start) {
2016-08-17 02:25:12 +02:00
gs.gen_value(wordtype);
} else {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeForce | (wordtype << CsCodeRet));
2016-08-17 02:25:12 +02:00
}
}
break;
2016-08-17 02:25:12 +02:00
}
}
static bool compilearg(
2017-02-13 18:10:40 +01:00
cs_gen_state &gs, int wordtype, int prevargs, cs_string *word
2016-08-17 02:25:12 +02:00
) {
2016-09-22 00:20:23 +02:00
gs.skip_comments();
2016-08-17 02:25:12 +02:00
switch (gs.current()) {
case '\"':
switch (wordtype) {
2016-09-07 20:20:36 +02:00
case CsValPop:
2016-09-20 22:24:56 +02:00
gs.get_str();
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsValCond: {
2017-01-25 02:09:50 +01:00
size_t line = gs.current_line;
2016-09-20 22:11:40 +02:00
auto s = gs.get_str_dup();
if (!s.empty()) {
2016-09-22 01:44:35 +02:00
compileblock(gs, s, line);
2016-08-17 02:25:12 +02:00
} else {
gs.gen_null();
}
break;
}
2016-09-07 20:20:36 +02:00
case CsValCode: {
2016-09-20 22:11:40 +02:00
auto s = gs.get_str_dup();
2016-09-22 01:07:43 +02:00
compileblock(gs);
2016-08-17 02:25:12 +02:00
break;
}
2016-09-07 20:20:36 +02:00
case CsValWord:
2016-09-20 22:11:40 +02:00
if (word) {
*word = gs.get_str_dup();
}
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsValAny:
case CsValString:
2016-08-17 02:25:12 +02:00
compileunescapestr(gs);
break;
2016-09-07 20:20:36 +02:00
case CsValCany:
case CsValCstring:
2016-08-17 02:25:12 +02:00
compileunescapestr(gs, true);
break;
default: {
2017-01-25 02:09:50 +01:00
size_t line = gs.current_line;
2016-09-20 22:11:40 +02:00
auto s = gs.get_str_dup();
2016-09-22 01:44:35 +02:00
gs.gen_value(wordtype, s, line);
2016-08-17 02:25:12 +02:00
break;
}
}
return true;
2016-08-17 02:25:12 +02:00
case '$':
compilelookup(gs, wordtype, prevargs);
return true;
2016-08-17 02:25:12 +02:00
case '(':
gs.next_char();
if (prevargs >= MaxResults) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeEnter);
2016-08-17 02:25:12 +02:00
compilestatements(
2016-09-07 20:20:36 +02:00
gs, wordtype > CsValAny ? CsValCany : CsValAny, ')'
2016-08-17 02:25:12 +02:00
);
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeExit | cs_ret_code(wordtype));
2016-08-17 02:25:12 +02:00
} else {
2017-01-25 02:09:50 +01:00
size_t start = gs.code.size();
2016-08-17 02:25:12 +02:00
compilestatements(
2016-09-07 20:20:36 +02:00
gs, wordtype > CsValAny ? CsValCany : CsValAny, ')', prevargs
2016-08-17 02:25:12 +02:00
);
if (gs.code.size() > start) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeResultArg | cs_ret_code(wordtype));
2016-08-17 02:25:12 +02:00
} else {
gs.gen_value(wordtype);
return true;
}
}
switch (wordtype) {
2016-09-07 20:20:36 +02:00
case CsValPop:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodePop);
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsValCond:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeCond);
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsValCode:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeCompile);
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsValIdent:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeIdentU);
2016-08-17 02:25:12 +02:00
break;
}
return true;
2016-08-17 02:25:12 +02:00
case '[':
gs.next_char();
compileblockmain(gs, wordtype, prevargs);
return true;
default:
switch (wordtype) {
2016-09-07 20:20:36 +02:00
case CsValPop: {
2016-09-20 22:24:56 +02:00
return !gs.get_word().empty();
2016-08-17 02:25:12 +02:00
}
2016-09-07 20:20:36 +02:00
case CsValCond: {
2017-01-25 02:09:50 +01:00
size_t line = gs.current_line;
2016-09-20 22:11:40 +02:00
auto s = gs.get_word();
if (s.empty()) {
2016-08-17 02:25:12 +02:00
return false;
}
2016-09-22 01:44:35 +02:00
compileblock(gs, s, line);
2016-08-17 02:25:12 +02:00
return true;
}
2016-09-07 20:20:36 +02:00
case CsValCode: {
2017-01-25 02:09:50 +01:00
size_t line = gs.current_line;
2016-09-20 22:11:40 +02:00
auto s = gs.get_word();
if (s.empty()) {
2016-08-17 02:25:12 +02:00
return false;
}
2016-09-22 01:44:35 +02:00
compileblock(gs, s, line);
2016-08-17 02:25:12 +02:00
return true;
}
2016-09-20 22:11:40 +02:00
case CsValWord: {
auto w = gs.get_word();
if (word) {
*word = w;
}
return !w.empty();
}
2016-08-17 02:25:12 +02:00
default: {
2017-01-25 02:09:50 +01:00
size_t line = gs.current_line;
2016-09-20 22:11:40 +02:00
auto s = gs.get_word();
if (s.empty()) {
2016-08-17 02:25:12 +02:00
return false;
}
2016-09-22 01:44:35 +02:00
gs.gen_value(wordtype, s, line);
2016-08-17 02:25:12 +02:00
return true;
}
}
}
}
2016-09-17 22:32:32 +02:00
static void compile_cmd(
2017-02-13 18:10:40 +01:00
cs_gen_state &gs, cs_command *id, bool &more, int rettype, int prevargs
2016-09-17 22:32:32 +02:00
) {
int comtype = CsCodeCom, numargs = 0, fakeargs = 0;
bool rep = false;
auto fmt = id->get_args();
for (; !fmt.empty(); ++fmt) {
switch (*fmt) {
case 'S':
case 's':
if (more) {
more = compilearg(
gs, *fmt == 's' ? CsValCstring : CsValString,
prevargs + numargs
);
}
if (!more) {
if (rep) {
break;
}
2017-02-16 19:07:22 +01:00
gs.gen_str(ostd::string_range(), *fmt == 's');
2016-09-17 22:32:32 +02:00
fakeargs++;
} else if (fmt.size() == 1) {
int numconc = 1;
while ((numargs + numconc) < MaxArguments) {
more = compilearg(
gs, CsValCstring, prevargs + numargs + numconc
);
if (!more) {
break;
}
numconc++;
}
if (numconc > 1) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeConc | CsRetString | (numconc << 8));
2016-09-17 22:32:32 +02:00
}
}
numargs++;
break;
case 'i':
if (more) {
more = compilearg(gs, CsValInt, prevargs + numargs);
}
if (!more) {
if (rep) {
break;
}
gs.gen_int();
fakeargs++;
}
numargs++;
break;
case 'b':
if (more) {
more = compilearg(gs, CsValInt, prevargs + numargs);
}
if (!more) {
if (rep) {
break;
}
2017-02-13 18:10:40 +01:00
gs.gen_int(std::numeric_limits<cs_int>::min());
2016-09-17 22:32:32 +02:00
fakeargs++;
}
numargs++;
break;
case 'f':
if (more) {
more = compilearg(gs, CsValFloat, prevargs + numargs);
}
if (!more) {
if (rep) {
break;
}
gs.gen_float();
fakeargs++;
}
numargs++;
break;
case 'F':
if (more) {
more = compilearg(gs, CsValFloat, prevargs + numargs);
}
if (!more) {
if (rep) {
break;
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeDup | CsRetFloat);
2016-09-17 22:32:32 +02:00
fakeargs++;
}
numargs++;
break;
case 'T':
case 't':
if (more) {
more = compilearg(
gs, *fmt == 't' ? CsValCany : CsValAny,
prevargs + numargs
);
}
if (!more) {
if (rep) {
break;
}
gs.gen_null();
fakeargs++;
}
numargs++;
break;
case 'E':
if (more) {
more = compilearg(gs, CsValCond, prevargs + numargs);
}
if (!more) {
if (rep) {
break;
}
gs.gen_null();
fakeargs++;
}
numargs++;
break;
case 'e':
if (more) {
more = compilearg(gs, CsValCode, prevargs + numargs);
}
if (!more) {
if (rep) {
break;
}
compileblock(gs);
fakeargs++;
}
numargs++;
break;
case 'r':
if (more) {
more = compilearg(gs, CsValIdent, prevargs + numargs);
}
if (!more) {
if (rep) {
break;
}
gs.gen_ident();
fakeargs++;
}
numargs++;
break;
case '$':
gs.gen_ident(id);
numargs++;
break;
case 'N':
gs.gen_int(numargs - fakeargs);
numargs++;
break;
case 'C':
comtype = CsCodeComC;
if (more) {
while (numargs < MaxArguments) {
more = compilearg(gs, CsValCany, prevargs + numargs);
if (!more) {
break;
}
numargs++;
}
}
goto compilecomv;
case 'V':
comtype = CsCodeComV;
if (more) {
while (numargs < MaxArguments) {
more = compilearg(gs, CsValCany, prevargs + numargs);
if (!more) {
break;
}
numargs++;
}
}
goto compilecomv;
case '1':
case '2':
case '3':
case '4':
if (more && (numargs < MaxArguments)) {
2017-03-31 03:34:09 +02:00
int numrep = -int(*fmt) + '0' - 1;
fmt = ostd::string_range{&fmt[numrep], &fmt[fmt.size()]};
2016-09-17 22:32:32 +02:00
rep = true;
} else {
while (numargs > MaxArguments) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodePop);
2016-09-17 22:32:32 +02:00
--numargs;
}
}
break;
}
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(comtype | cs_ret_code(rettype) | (id->get_index() << 8));
2016-09-17 22:32:32 +02:00
return;
compilecomv:
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-09-17 22:32:32 +02:00
comtype | cs_ret_code(rettype) | (numargs << 8) | (id->get_index() << 13)
);
}
2017-02-13 18:10:40 +01:00
static void compile_alias(cs_gen_state &gs, cs_alias *id, bool &more, int prevargs) {
2016-09-17 22:32:32 +02:00
int numargs = 0;
while (numargs < MaxArguments) {
more = compilearg(gs, CsValAny, prevargs + numargs);
if (!more) {
break;
}
++numargs;
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-09-17 22:32:32 +02:00
(id->get_index() < MaxArguments ? CsCodeCallArg : CsCodeCall)
| (numargs << 8) | (id->get_index() << 13)
);
}
2017-02-13 18:10:40 +01:00
static void compile_local(cs_gen_state &gs, bool &more, int prevargs) {
2016-09-17 22:32:32 +02:00
int numargs = 0;
if (more) {
while (numargs < MaxArguments) {
more = compilearg(gs, CsValIdent, prevargs + numargs);
if (!more) {
break;
}
numargs++;
}
}
if (more) {
while ((more = compilearg(gs, CsValPop)));
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeLocal | (numargs << 8));
2016-09-17 22:32:32 +02:00
}
static void compile_do(
2017-02-13 18:10:40 +01:00
cs_gen_state &gs, bool &more, int prevargs, int rettype, int opcode
2016-09-17 22:32:32 +02:00
) {
if (more) {
more = compilearg(gs, CsValCode, prevargs);
}
2017-01-25 01:18:29 +01:00
gs.code.push_back((more ? opcode : CsCodeNull) | cs_ret_code(rettype));
2016-09-17 22:32:32 +02:00
}
static void compile_if(
2017-02-13 18:10:40 +01:00
cs_gen_state &gs, cs_ident *id, bool &more, int prevargs, int rettype
2016-09-17 22:32:32 +02:00
) {
if (more) {
more = compilearg(gs, CsValCany, prevargs);
}
if (!more) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeNull | cs_ret_code(rettype));
2016-09-17 22:32:32 +02:00
} else {
int start1 = gs.code.size();
more = compilearg(gs, CsValCode, prevargs + 1);
if (!more) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodePop);
gs.code.push_back(CsCodeNull | cs_ret_code(rettype));
2016-09-17 22:32:32 +02:00
} else {
int start2 = gs.code.size();
more = compilearg(gs, CsValCode, prevargs + 2);
2017-01-25 02:10:17 +01:00
uint32_t inst1 = gs.code[start1];
uint32_t op1 = inst1 & ~CsCodeRetMask;
uint32_t len1 = start2 - (start1 + 1);
2016-09-17 22:32:32 +02:00
if (!more) {
if (op1 == (CsCodeBlock | (len1 << 8))) {
gs.code[start1] = (len1 << 8) | CsCodeJumpB | CsCodeFlagFalse;
gs.code[start1 + 1] = CsCodeEnterResult;
gs.code[start1 + len1] = (
gs.code[start1 + len1] & ~CsCodeRetMask
) | cs_ret_code(rettype);
return;
}
compileblock(gs);
} else {
2017-01-25 02:10:17 +01:00
uint32_t inst2 = gs.code[start2];
uint32_t op2 = inst2 & ~CsCodeRetMask;
uint32_t len2 = gs.code.size() - (start2 + 1);
2016-09-17 22:32:32 +02:00
if (op2 == (CsCodeBlock | (len2 << 8))) {
if (op1 == (CsCodeBlock | (len1 << 8))) {
gs.code[start1] = ((start2 - start1) << 8)
| CsCodeJumpB | CsCodeFlagFalse;
gs.code[start1 + 1] = CsCodeEnterResult;
gs.code[start1 + len1] = (
gs.code[start1 + len1] & ~CsCodeRetMask
) | cs_ret_code(rettype);
gs.code[start2] = (len2 << 8) | CsCodeJump;
gs.code[start2 + 1] = CsCodeEnterResult;
gs.code[start2 + len2] = (
gs.code[start2 + len2] & ~CsCodeRetMask
) | cs_ret_code(rettype);
return;
} else if (op1 == (CsCodeEmpty | (len1 << 8))) {
gs.code[start1] = CsCodeNull | (inst2 & CsCodeRetMask);
gs.code[start2] = (len2 << 8) | CsCodeJumpB | CsCodeFlagTrue;
gs.code[start2 + 1] = CsCodeEnterResult;
gs.code[start2 + len2] = (
gs.code[start2 + len2] & ~CsCodeRetMask
) | cs_ret_code(rettype);
return;
}
}
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeCom | cs_ret_code(rettype) | (id->get_index() << 8));
2016-09-17 22:32:32 +02:00
}
}
}
static void compile_and_or(
2017-02-13 18:10:40 +01:00
cs_gen_state &gs, cs_ident *id, bool &more, int prevargs, int rettype
2016-09-17 22:32:32 +02:00
) {
int numargs = 0;
if (more) {
more = compilearg(gs, CsValCond, prevargs);
}
if (!more) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-09-17 22:32:32 +02:00
((id->get_type_raw() == CsIdAnd) ? CsCodeTrue : CsCodeFalse)
| cs_ret_code(rettype)
);
} else {
numargs++;
int start = gs.code.size(), end = start;
while (numargs < MaxArguments) {
more = compilearg(gs, CsValCond, prevargs + numargs);
if (!more) {
break;
}
numargs++;
if ((gs.code[end] & ~CsCodeRetMask) != (
2017-01-25 02:10:17 +01:00
CsCodeBlock | (uint32_t(gs.code.size() - (end + 1)) << 8)
2016-09-17 22:32:32 +02:00
)) {
break;
}
end = gs.code.size();
}
if (more) {
while (numargs < MaxArguments) {
more = compilearg(gs, CsValCond, prevargs + numargs);
if (!more) {
break;
}
numargs++;
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-09-17 22:32:32 +02:00
CsCodeComV | cs_ret_code(rettype) |
(numargs << 8) | (id->get_index() << 13)
);
} else {
2017-01-25 02:10:17 +01:00
uint32_t op = (id->get_type_raw() == CsIdAnd)
2016-09-17 22:32:32 +02:00
? (CsCodeJumpResult | CsCodeFlagFalse)
: (CsCodeJumpResult | CsCodeFlagTrue);
2017-01-25 01:18:29 +01:00
gs.code.push_back(op);
2016-09-17 22:32:32 +02:00
end = gs.code.size();
while ((start + 1) < end) {
2017-01-25 02:10:17 +01:00
uint32_t len = gs.code[start] >> 8;
2016-09-17 22:32:32 +02:00
gs.code[start] = ((end - (start + 1)) << 8) | op;
gs.code[start + 1] = CsCodeEnter;
gs.code[start + len] = (
gs.code[start + len] & ~CsCodeRetMask
) | cs_ret_code(rettype);
start += len + 1;
}
}
}
}
2017-02-13 18:10:40 +01:00
static void compilestatements(cs_gen_state &gs, int rettype, int brak, int prevargs) {
cs_string idname;
for (;;) {
2016-09-22 00:20:23 +02:00
gs.skip_comments();
2016-09-20 22:11:40 +02:00
idname.clear();
2017-01-25 02:09:50 +01:00
size_t curline = gs.current_line;
2016-09-07 20:20:36 +02:00
bool more = compilearg(gs, CsValWord, prevargs, &idname);
2016-08-17 02:25:12 +02:00
if (!more) {
goto endstatement;
}
2016-09-22 00:20:23 +02:00
gs.skip_comments();
2016-08-17 02:25:12 +02:00
if (gs.current() == '=') {
2016-09-22 00:42:34 +02:00
switch (gs.current(1)) {
2016-08-17 02:25:12 +02:00
case '/':
2016-09-22 00:42:34 +02:00
if (gs.current(2) != '/') {
2016-08-17 02:25:12 +02:00
break;
}
2017-11-06 01:07:53 +01:00
[[fallthrough]];
2016-08-17 02:25:12 +02:00
case ';':
case ' ':
case '\t':
case '\r':
case '\n':
case '\0':
gs.next_char();
2016-09-20 22:11:40 +02:00
if (!idname.empty()) {
2017-02-13 18:10:40 +01:00
cs_ident *id = gs.cs.new_ident(idname);
2016-08-17 02:25:12 +02:00
if (id) {
2016-08-18 03:53:51 +02:00
switch (id->get_type()) {
2017-02-13 18:10:40 +01:00
case cs_ident_type::Alias:
2016-09-07 20:20:36 +02:00
more = compilearg(gs, CsValAny, prevargs);
2016-08-17 02:25:12 +02:00
if (!more) {
gs.gen_str();
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-08-18 03:53:51 +02:00
(id->get_index() < MaxArguments
2016-09-07 20:20:36 +02:00
? CsCodeAliasArg
: CsCodeAlias
2016-08-18 03:53:51 +02:00
) | (id->get_index() << 8)
2016-08-17 02:25:12 +02:00
);
goto endstatement;
2017-02-13 18:10:40 +01:00
case cs_ident_type::Ivar:
2016-09-07 20:20:36 +02:00
more = compilearg(gs, CsValInt, prevargs);
2016-08-17 02:25:12 +02:00
if (!more) {
gs.gen_int();
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-09-07 20:20:36 +02:00
CsCodeIvar1 | (id->get_index() << 8)
2016-08-18 03:53:51 +02:00
);
2016-08-17 02:25:12 +02:00
goto endstatement;
2017-02-13 18:10:40 +01:00
case cs_ident_type::Fvar:
2016-09-07 20:20:36 +02:00
more = compilearg(gs, CsValFloat, prevargs);
2016-08-17 02:25:12 +02:00
if (!more) {
gs.gen_float();
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-09-07 20:20:36 +02:00
CsCodeFvar1 | (id->get_index() << 8)
2016-08-18 03:53:51 +02:00
);
2016-08-17 02:25:12 +02:00
goto endstatement;
2017-02-13 18:10:40 +01:00
case cs_ident_type::Svar:
2016-09-07 20:20:36 +02:00
more = compilearg(gs, CsValCstring, prevargs);
2016-08-17 02:25:12 +02:00
if (!more) {
gs.gen_str();
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-09-07 20:20:36 +02:00
CsCodeSvar1 | (id->get_index() << 8)
2016-08-18 03:53:51 +02:00
);
2016-08-17 02:25:12 +02:00
goto endstatement;
2016-08-18 03:53:51 +02:00
default:
break;
2016-08-17 02:25:12 +02:00
}
}
2016-09-20 22:11:40 +02:00
gs.gen_str(idname, true);
2016-08-17 02:25:12 +02:00
}
2016-09-07 20:20:36 +02:00
more = compilearg(gs, CsValAny);
2016-08-17 02:25:12 +02:00
if (!more) {
gs.gen_str();
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeAliasU);
2016-08-17 02:25:12 +02:00
goto endstatement;
}
2016-08-17 02:25:12 +02:00
}
2016-09-20 22:11:40 +02:00
if (idname.empty()) {
noid:
2016-09-17 22:32:32 +02:00
int numargs = 0;
2016-08-17 02:25:12 +02:00
while (numargs < MaxArguments) {
2016-09-07 20:20:36 +02:00
more = compilearg(gs, CsValCany, prevargs + numargs);
2016-08-17 02:25:12 +02:00
if (!more) {
break;
}
++numargs;
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeCallU | (numargs << 8));
} else {
2017-02-13 18:10:40 +01:00
cs_ident *id = gs.cs.get_ident(idname);
if (!id) {
2016-09-20 22:11:40 +02:00
if (!cs_check_num(idname)) {
gs.gen_str(idname, true);
goto noid;
}
switch (rettype) {
2016-09-07 20:20:36 +02:00
case CsValAny:
case CsValCany: {
2017-02-16 19:07:22 +01:00
ostd::string_range end = idname;
2017-02-13 18:10:40 +01:00
cs_int val = cs_parse_int(end, &end);
2016-08-17 02:25:12 +02:00
if (!end.empty()) {
2016-09-20 22:11:40 +02:00
gs.gen_str(idname, rettype == CsValCany);
2016-08-17 02:25:12 +02:00
} else {
gs.gen_int(val);
}
break;
}
default:
2016-09-22 01:44:35 +02:00
gs.gen_value(rettype, idname, curline);
2016-08-17 02:25:12 +02:00
break;
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeResult);
2016-08-17 02:25:12 +02:00
} else {
2016-08-18 03:53:51 +02:00
switch (id->get_type_raw()) {
2016-09-07 20:20:36 +02:00
case CsIdAlias:
2016-09-17 22:32:32 +02:00
compile_alias(
2017-02-13 18:10:40 +01:00
gs, static_cast<cs_alias *>(id), more, prevargs
2016-08-17 02:25:12 +02:00
);
break;
2016-09-17 22:32:32 +02:00
case CsIdCommand:
compile_cmd(
2017-02-13 18:10:40 +01:00
gs, static_cast<cs_command *>(id), more,
2016-09-17 22:32:32 +02:00
rettype, prevargs
2016-08-17 02:25:12 +02:00
);
break;
2016-09-07 20:20:36 +02:00
case CsIdLocal:
2016-09-17 22:32:32 +02:00
compile_local(gs, more, prevargs);
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsIdDo:
2016-09-17 22:32:32 +02:00
compile_do(gs, more, prevargs, rettype, CsCodeDo);
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsIdDoArgs:
2016-09-17 22:32:32 +02:00
compile_do(gs, more, prevargs, rettype, CsCodeDoArgs);
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsIdIf:
2016-09-17 22:32:32 +02:00
compile_if(gs, id, more, prevargs, rettype);
2016-08-17 02:25:12 +02:00
break;
2016-09-15 02:12:22 +02:00
case CsIdBreak:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeBreak | CsCodeFlagFalse);
2016-09-15 02:12:22 +02:00
break;
case CsIdContinue:
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeBreak | CsCodeFlagTrue);
2016-09-15 02:12:22 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsIdResult:
2016-08-17 02:25:12 +02:00
if (more) {
2016-09-07 20:20:36 +02:00
more = compilearg(gs, CsValAny, prevargs);
2016-08-17 02:25:12 +02:00
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-09-07 20:20:36 +02:00
(more ? CsCodeResult : CsCodeNull) |
2016-08-17 02:25:12 +02:00
cs_ret_code(rettype)
);
break;
2016-09-07 20:20:36 +02:00
case CsIdNot:
2016-08-17 02:25:12 +02:00
if (more) {
2016-09-07 20:20:36 +02:00
more = compilearg(gs, CsValCany, prevargs);
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-09-07 20:20:36 +02:00
(more ? CsCodeNot : CsCodeTrue) | cs_ret_code(rettype)
2016-08-17 02:25:12 +02:00
);
break;
2016-09-07 20:20:36 +02:00
case CsIdAnd:
case CsIdOr:
2016-09-17 22:32:32 +02:00
compile_and_or(gs, id, more, prevargs, rettype);
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsIdIvar:
if (!(more = compilearg(gs, CsValInt, prevargs))) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodePrint | (id->get_index() << 8));
2017-02-13 18:10:40 +01:00
} else if (!(id->get_flags() & CS_IDF_HEX) || !(
2016-09-07 20:20:36 +02:00
more = compilearg(gs, CsValInt, prevargs + 1)
2016-08-17 02:25:12 +02:00
)) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeIvar1 | (id->get_index() << 8));
2016-08-17 02:25:12 +02:00
} else if (!(
2016-09-07 20:20:36 +02:00
more = compilearg(gs, CsValInt, prevargs + 2)
2016-08-17 02:25:12 +02:00
)) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeIvar2 | (id->get_index() << 8));
2016-08-17 02:25:12 +02:00
} else {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeIvar3 | (id->get_index() << 8));
2016-08-17 02:25:12 +02:00
}
break;
2016-09-07 20:20:36 +02:00
case CsIdFvar:
if (!(more = compilearg(gs, CsValFloat, prevargs))) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodePrint | (id->get_index() << 8));
2016-08-17 02:25:12 +02:00
} else {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeFvar1 | (id->get_index() << 8));
2016-08-17 02:25:12 +02:00
}
break;
2016-09-07 20:20:36 +02:00
case CsIdSvar:
if (!(more = compilearg(gs, CsValCstring, prevargs))) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodePrint | (id->get_index() << 8));
2016-08-17 02:25:12 +02:00
} else {
2016-09-17 22:32:32 +02:00
int numargs = 0;
2016-08-17 02:25:12 +02:00
do {
++numargs;
} while (numargs < MaxArguments && (
more = compilearg(
2016-09-07 20:20:36 +02:00
gs, CsValCany, prevargs + numargs
2016-08-17 02:25:12 +02:00
)
));
if (numargs > 1) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-09-07 20:20:36 +02:00
CsCodeConc | CsRetString | (numargs << 8)
);
2016-08-17 02:25:12 +02:00
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(CsCodeSvar1 | (id->get_index() << 8));
2016-08-17 02:25:12 +02:00
}
break;
}
2016-08-17 02:25:12 +02:00
}
}
endstatement:
2016-08-17 02:25:12 +02:00
if (more) {
2016-09-07 20:20:36 +02:00
while (compilearg(gs, CsValPop));
2016-08-17 02:25:12 +02:00
}
2016-09-22 00:20:23 +02:00
switch (gs.skip_until(")];/\n")) {
2016-08-17 02:25:12 +02:00
case '\0':
2016-09-22 00:20:23 +02:00
if (gs.current() != brak) {
2017-02-13 18:10:40 +01:00
throw cs_error(gs.cs, "missing \"%c\"", char(brak));
2016-09-10 15:01:49 +02:00
return;
2016-08-17 02:25:12 +02:00
}
return;
case ')':
case ']':
2016-09-22 00:20:23 +02:00
if (gs.current() == brak) {
gs.next_char();
2016-08-17 02:25:12 +02:00
return;
}
2017-02-13 18:10:40 +01:00
throw cs_error(gs.cs, "unexpected \"%c\"", gs.current());
2016-09-10 15:01:49 +02:00
return;
2016-08-17 02:25:12 +02:00
case '/':
2016-09-22 00:20:23 +02:00
gs.next_char();
2016-08-17 02:25:12 +02:00
if (gs.current() == '/') {
2016-09-22 00:20:23 +02:00
gs.skip_until('\n');
2016-08-17 02:25:12 +02:00
}
goto endstatement;
2016-09-22 00:20:23 +02:00
default:
gs.next_char();
break;
}
}
}
2017-02-16 19:07:22 +01:00
void cs_gen_state::gen_main(ostd::string_range s, int ret_type) {
2016-09-22 01:07:43 +02:00
source = s;
2017-01-25 01:18:29 +01:00
code.push_back(CsCodeStart);
2016-09-07 20:20:36 +02:00
compilestatements(*this, CsValAny);
2017-01-25 01:18:29 +01:00
code.push_back(CsCodeExit | ((ret_type < CsValAny) ? (ret_type << CsCodeRet) : 0));
}
} /* namespace cscript */