libcubescript/src/cs_gen.cc

1441 lines
50 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
}
2021-03-18 23:53:16 +01:00
cs_string cs_gen_state::get_str_dup() {
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>();
2021-03-18 23:53:16 +01:00
util::unescape_string(app, 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) {
2021-03-18 20:55:14 +01:00
if (type >= CS_VAL_ANY) {
return (type == CS_VAL_STRING) ? CS_RET_STRING : def;
2016-08-17 02:25:12 +02:00
}
2021-03-18 20:55:14 +01:00
return type << CS_CODE_RET;
}
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,
2021-03-18 20:55:14 +01:00
int rettype = CS_RET_NULL, 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) {
2021-03-18 20:55:14 +01:00
case CS_VAL_ANY:
2016-08-17 02:25:12 +02:00
if (!word.empty()) {
gen_str(word);
} else {
gen_null();
}
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_STRING:
gen_str(word);
2016-08-17 02:25:12 +02:00
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_FLOAT:
2016-08-17 02:25:12 +02:00
gen_float(word);
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_INT:
2016-08-17 02:25:12 +02:00
gen_int(word);
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_COND:
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;
2021-03-18 20:55:14 +01:00
case CS_VAL_CODE:
2016-09-22 01:44:35 +02:00
compileblock(*this, word, line);
2016-08-17 02:25:12 +02:00
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_IDENT:
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) {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_EMPTY);
}
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();
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_BLOCK);
gs.code.push_back(CS_CODE_OFFSET | ((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;
2021-03-18 20:55:14 +01:00
compilestatements(gs, CS_VAL_ANY, 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) {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_EXIT | 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);
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_EMPTY | rettype);
}
2017-01-28 23:04:10 +01:00
return std::make_pair(p, retline);
}
static inline void compileunescapestr(cs_gen_state &gs) {
2016-09-20 22:24:56 +02:00
auto str = gs.get_str();
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_VAL | CS_RET_STRING);
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 '[':
2021-03-18 20:55:14 +01:00
if (!compilearg(gs, CS_VAL_STRING, prevargs)) {
2016-08-17 02:25:12 +02:00
goto invalid;
}
break;
case '$':
2021-03-18 20:55:14 +01:00
compilelookup(gs, CS_VAL_STRING, 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()) {
2021-03-18 20:55:14 +01:00
case cs_ident_type::IVAR:
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2021-03-18 20:55:14 +01:00
CS_CODE_IVAR | cs_ret_code(ltype, CS_RET_INT) |
2016-08-18 03:53:51 +02:00
(id->get_index() << 8)
2016-08-17 02:25:12 +02:00
);
switch (ltype) {
2021-03-18 20:55:14 +01:00
case CS_VAL_POP:
2017-01-25 01:18:29 +01:00
gs.code.pop_back();
2016-08-17 02:25:12 +02:00
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_CODE:
gs.code.push_back(CS_CODE_COMPILE);
2016-08-17 02:25:12 +02:00
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_IDENT:
gs.code.push_back(CS_CODE_IDENT_U);
2016-08-17 02:25:12 +02:00
break;
}
return;
2021-03-18 20:55:14 +01:00
case cs_ident_type::FVAR:
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2021-03-18 20:55:14 +01:00
CS_CODE_FVAR | cs_ret_code(ltype, CS_RET_FLOAT) |
2016-08-18 03:53:51 +02:00
(id->get_index() << 8)
2016-08-17 02:25:12 +02:00
);
switch (ltype) {
2021-03-18 20:55:14 +01:00
case CS_VAL_POP:
2017-01-25 01:18:29 +01:00
gs.code.pop_back();
2016-08-17 02:25:12 +02:00
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_CODE:
gs.code.push_back(CS_CODE_COMPILE);
2016-08-17 02:25:12 +02:00
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_IDENT:
gs.code.push_back(CS_CODE_IDENT_U);
2016-08-17 02:25:12 +02:00
break;
}
return;
2021-03-18 20:55:14 +01:00
case cs_ident_type::SVAR:
2016-08-17 02:25:12 +02:00
switch (ltype) {
2021-03-18 20:55:14 +01:00
case CS_VAL_POP:
2016-08-17 02:25:12 +02:00
return;
default:
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2021-03-18 20:55:14 +01:00
CS_CODE_SVAR | cs_ret_code(ltype, CS_RET_STRING) |
2016-08-18 03:53:51 +02:00
(id->get_index() << 8)
2016-08-17 02:25:12 +02:00
);
break;
}
goto done;
2021-03-18 20:55:14 +01:00
case cs_ident_type::ALIAS:
2016-08-17 02:25:12 +02:00
switch (ltype) {
2021-03-18 20:55:14 +01:00
case CS_VAL_POP:
2016-08-17 02:25:12 +02:00
return;
2021-03-18 20:55:14 +01:00
case CS_VAL_COND:
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-08-18 03:53:51 +02:00
(id->get_index() < MaxArguments
2021-03-18 20:55:14 +01:00
? CS_CODE_LOOKUP_MARG
: CS_CODE_LOOKUP_M
2016-08-18 03:53:51 +02:00
) | (id->get_index() << 8)
2016-08-17 02:25:12 +02:00
);
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_CODE:
case CS_VAL_IDENT:
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2016-08-18 03:53:51 +02:00
(id->get_index() < MaxArguments
2021-03-18 20:55:14 +01:00
? CS_CODE_LOOKUP_MARG
: CS_CODE_LOOKUP_M
) | CS_RET_STRING | (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
2021-03-18 20:55:14 +01:00
? CS_CODE_LOOKUP_ARG
: CS_CODE_LOOKUP
) | cs_ret_code(ltype, CS_RET_STRING) |
2016-08-18 03:53:51 +02:00
(id->get_index() << 8)
2016-08-17 02:25:12 +02:00
);
break;
}
goto done;
2021-03-18 20:55:14 +01:00
case cs_ident_type::COMMAND: {
int comtype = CS_CODE_COM, numargs = 0;
2016-08-17 02:25:12 +02:00
if (prevargs >= MaxResults) {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_ENTER);
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':
gs.gen_str(ostd::string_range());
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':
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_DUP | CS_RET_FLOAT);
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':
2021-03-18 20:55:14 +01:00
comtype = CS_CODE_COM_C;
2016-08-17 02:25:12 +02:00
goto compilecomv;
case 'V':
2021-03-18 20:55:14 +01:00
comtype = CS_CODE_COM_V;
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
2021-03-18 20:55:14 +01:00
? CS_CODE_EXIT
: CS_CODE_RESULT_ARG
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
2021-03-18 20:55:14 +01:00
? CS_CODE_EXIT
: CS_CODE_RESULT_ARG
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;
}
}
gs.gen_str(lookup);
2016-08-17 02:25:12 +02:00
break;
}
}
switch (ltype) {
2021-03-18 20:55:14 +01:00
case CS_VAL_COND:
gs.code.push_back(CS_CODE_LOOKUP_MU);
2016-08-17 02:25:12 +02:00
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_CODE:
case CS_VAL_IDENT:
gs.code.push_back(CS_CODE_LOOKUP_MU | CS_RET_STRING);
2016-08-17 02:25:12 +02:00
break;
default:
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_LOOKUP_U | cs_ret_code(ltype));
2016-08-17 02:25:12 +02:00
break;
}
done:
switch (ltype) {
2021-03-18 20:55:14 +01:00
case CS_VAL_POP:
gs.code.push_back(CS_CODE_POP);
2016-08-17 02:25:12 +02:00
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_CODE:
gs.code.push_back(CS_CODE_COMPILE);
2016-08-17 02:25:12 +02:00
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_COND:
gs.code.push_back(CS_CODE_COND);
2016-08-17 02:25:12 +02:00
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_IDENT:
gs.code.push_back(CS_CODE_IDENT_U);
2016-08-17 02:25:12 +02:00
break;
}
return;
invalid:
switch (ltype) {
2021-03-18 20:55:14 +01:00
case CS_VAL_POP:
2016-08-17 02:25:12 +02:00
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_NULL:
case CS_VAL_ANY:
case CS_VAL_WORD:
case CS_VAL_COND:
2016-08-17 02:25:12 +02:00
gs.gen_null();
break;
default:
gs.gen_value(ltype);
break;
}
}
static bool compileblockstr(cs_gen_state &gs, ostd::string_range str) {
int startc = gs.code.size();
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_VAL | CS_RET_STRING);
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 '(':
2021-03-18 20:55:14 +01:00
if (!compilearg(gs, CS_VAL_ANY, prevargs)) {
2016-08-17 02:25:12 +02:00
return false;
}
2016-08-17 02:25:12 +02:00
break;
case '[':
2021-03-18 20:55:14 +01:00
if (!compilearg(gs, CS_VAL_STRING, prevargs)) {
2016-08-17 02:25:12 +02:00
return false;
}
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_LOOKUP_MU);
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()) {
2021-03-18 20:55:14 +01:00
case cs_ident_type::IVAR:
gs.code.push_back(CS_CODE_IVAR | (id->get_index() << 8));
2016-08-17 02:25:12 +02:00
goto done;
2021-03-18 20:55:14 +01:00
case cs_ident_type::FVAR:
gs.code.push_back(CS_CODE_FVAR | (id->get_index() << 8));
2016-08-17 02:25:12 +02:00
goto done;
2021-03-18 20:55:14 +01:00
case cs_ident_type::SVAR:
gs.code.push_back(CS_CODE_SVAR | (id->get_index() << 8));
2016-08-17 02:25:12 +02:00
goto done;
2021-03-18 20:55:14 +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
2021-03-18 20:55:14 +01:00
? CS_CODE_LOOKUP_MARG
: CS_CODE_LOOKUP_M
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
}
}
gs.gen_str(lookup);
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_LOOKUP_MU);
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) {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_ENTER);
2016-08-17 02:25:12 +02:00
}
if (concs + 2 > MaxArguments) {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_CONC_W | CS_RET_STRING | (concs << 8));
2016-08-17 02:25:12 +02:00
concs = 1;
}
if (compileblockstr(gs, ostd::string_range(start, esc))) {
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) {
2021-03-18 20:55:14 +01:00
case CS_VAL_POP:
2016-08-17 02:25:12 +02:00
return;
2021-03-18 20:55:14 +01:00
case CS_VAL_CODE:
case CS_VAL_COND: {
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()
2021-03-18 20:55:14 +01:00
), curline, CS_RET_NULL, ']');
2016-09-22 01:44:35 +02:00
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
}
2021-03-18 20:55:14 +01:00
case CS_VAL_IDENT:
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
}
compileblockstr(gs, ostd::string_range(start, gs.source.data() - 1));
2016-08-17 02:25:12 +02:00
if (concs > 1) {
concs++;
}
}
if (concs) {
if (prevargs >= MaxResults) {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_CONC_M | cs_ret_code(wordtype) | (concs << 8));
gs.code.push_back(CS_CODE_EXIT | cs_ret_code(wordtype));
2016-08-17 02:25:12 +02:00
} else {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_CONC_W | cs_ret_code(wordtype) | (concs << 8));
}
}
2016-08-17 02:25:12 +02:00
switch (wordtype) {
2021-03-18 20:55:14 +01:00
case CS_VAL_POP:
2016-09-22 01:07:43 +02:00
if (concs || gs.source.data() - 1 > start) {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_POP);
2016-08-17 02:25:12 +02:00
}
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_COND:
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 {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_COND);
2016-08-17 02:25:12 +02:00
}
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_CODE:
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 {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_COMPILE);
2016-08-17 02:25:12 +02:00
}
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_IDENT:
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 {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_IDENT_U);
2016-08-17 02:25:12 +02:00
}
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_STRING:
case CS_VAL_NULL:
case CS_VAL_ANY:
case CS_VAL_WORD:
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 {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_FORCE | (wordtype << CS_CODE_RET));
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) {
2021-03-18 20:55:14 +01:00
case CS_VAL_POP:
2016-09-20 22:24:56 +02:00
gs.get_str();
2016-08-17 02:25:12 +02:00
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_COND: {
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;
}
2021-03-18 20:55:14 +01:00
case CS_VAL_CODE: {
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;
}
2021-03-18 20:55:14 +01:00
case CS_VAL_WORD:
2016-09-20 22:11:40 +02:00
if (word) {
*word = gs.get_str_dup();
}
2016-08-17 02:25:12 +02:00
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_ANY:
case CS_VAL_STRING:
2016-08-17 02:25:12 +02:00
compileunescapestr(gs);
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) {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_ENTER);
compilestatements(gs, CS_VAL_ANY, ')');
gs.code.push_back(CS_CODE_EXIT | 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();
2021-03-18 20:55:14 +01:00
compilestatements(gs, CS_VAL_ANY, ')', prevargs);
2016-08-17 02:25:12 +02:00
if (gs.code.size() > start) {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_RESULT_ARG | cs_ret_code(wordtype));
2016-08-17 02:25:12 +02:00
} else {
gs.gen_value(wordtype);
return true;
}
}
switch (wordtype) {
2021-03-18 20:55:14 +01:00
case CS_VAL_POP:
gs.code.push_back(CS_CODE_POP);
2016-08-17 02:25:12 +02:00
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_COND:
gs.code.push_back(CS_CODE_COND);
2016-08-17 02:25:12 +02:00
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_CODE:
gs.code.push_back(CS_CODE_COMPILE);
2016-08-17 02:25:12 +02:00
break;
2021-03-18 20:55:14 +01:00
case CS_VAL_IDENT:
gs.code.push_back(CS_CODE_IDENT_U);
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) {
2021-03-18 20:55:14 +01:00
case CS_VAL_POP: {
2016-09-20 22:24:56 +02:00
return !gs.get_word().empty();
2016-08-17 02:25:12 +02:00
}
2021-03-18 20:55:14 +01:00
case CS_VAL_COND: {
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;
}
2021-03-18 20:55:14 +01:00
case CS_VAL_CODE: {
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;
}
2021-03-18 20:55:14 +01:00
case CS_VAL_WORD: {
2016-09-20 22:11:40 +02:00
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
) {
2021-03-18 20:55:14 +01:00
int comtype = CS_CODE_COM, numargs = 0, fakeargs = 0;
2016-09-17 22:32:32 +02:00
bool rep = false;
auto fmt = id->get_args();
for (; !fmt.empty(); ++fmt) {
switch (*fmt) {
case 's': /* string */
2016-09-17 22:32:32 +02:00
if (more) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_STRING, prevargs + numargs);
2016-09-17 22:32:32 +02:00
}
if (!more) {
if (rep) {
break;
}
gs.gen_str(ostd::string_range());
2016-09-17 22:32:32 +02:00
fakeargs++;
} else if (fmt.size() == 1) {
int numconc = 1;
while ((numargs + numconc) < MaxArguments) {
more = compilearg(
2021-03-18 20:55:14 +01:00
gs, CS_VAL_STRING, prevargs + numargs + numconc
2016-09-17 22:32:32 +02:00
);
if (!more) {
break;
}
numconc++;
}
if (numconc > 1) {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_CONC | CS_RET_STRING | (numconc << 8));
2016-09-17 22:32:32 +02:00
}
}
numargs++;
break;
case 'i': /* integer */
2016-09-17 22:32:32 +02:00
if (more) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_INT, prevargs + numargs);
2016-09-17 22:32:32 +02:00
}
if (!more) {
if (rep) {
break;
}
gs.gen_int();
fakeargs++;
}
numargs++;
break;
case 'b': /* integer, INT_MIN default */
2016-09-17 22:32:32 +02:00
if (more) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_INT, prevargs + numargs);
2016-09-17 22:32:32 +02:00
}
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': /* float */
2016-09-17 22:32:32 +02:00
if (more) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_FLOAT, prevargs + numargs);
2016-09-17 22:32:32 +02:00
}
if (!more) {
if (rep) {
break;
}
gs.gen_float();
fakeargs++;
}
numargs++;
break;
case 'F': /* float, prev-argument default */
2016-09-17 22:32:32 +02:00
if (more) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_FLOAT, prevargs + numargs);
2016-09-17 22:32:32 +02:00
}
if (!more) {
if (rep) {
break;
}
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_DUP | CS_RET_FLOAT);
2016-09-17 22:32:32 +02:00
fakeargs++;
}
numargs++;
break;
case 't': /* any arg */
2016-09-17 22:32:32 +02:00
if (more) {
more = compilearg(
2021-03-18 20:55:14 +01:00
gs, CS_VAL_ANY,
2016-09-17 22:32:32 +02:00
prevargs + numargs
);
}
if (!more) {
if (rep) {
break;
}
gs.gen_null();
fakeargs++;
}
numargs++;
break;
case 'E': /* condition */
2016-09-17 22:32:32 +02:00
if (more) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_COND, prevargs + numargs);
2016-09-17 22:32:32 +02:00
}
if (!more) {
if (rep) {
break;
}
gs.gen_null();
fakeargs++;
}
numargs++;
break;
case 'e': /* code */
2016-09-17 22:32:32 +02:00
if (more) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_CODE, prevargs + numargs);
2016-09-17 22:32:32 +02:00
}
if (!more) {
if (rep) {
break;
}
compileblock(gs);
fakeargs++;
}
numargs++;
break;
case 'r': /* ident */
2016-09-17 22:32:32 +02:00
if (more) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_IDENT, prevargs + numargs);
2016-09-17 22:32:32 +02:00
}
if (!more) {
if (rep) {
break;
}
gs.gen_ident();
fakeargs++;
}
numargs++;
break;
case '$': /* self */
2016-09-17 22:32:32 +02:00
gs.gen_ident(id);
numargs++;
break;
case 'N': /* number of arguments */
2016-09-17 22:32:32 +02:00
gs.gen_int(numargs - fakeargs);
numargs++;
break;
case 'C': /* concatenated string */
2021-03-18 20:55:14 +01:00
comtype = CS_CODE_COM_C;
2016-09-17 22:32:32 +02:00
if (more) {
while (numargs < MaxArguments) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_ANY, prevargs + numargs);
2016-09-17 22:32:32 +02:00
if (!more) {
break;
}
numargs++;
}
}
goto compilecomv;
case 'V': /* varargs */
2021-03-18 20:55:14 +01:00
comtype = CS_CODE_COM_V;
2016-09-17 22:32:32 +02:00
if (more) {
while (numargs < MaxArguments) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_ANY, prevargs + numargs);
2016-09-17 22:32:32 +02:00
if (!more) {
break;
}
numargs++;
}
}
goto compilecomv;
case '1': /* vararg repetition */
2016-09-17 22:32:32 +02:00
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) {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_POP);
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) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_ANY, prevargs + numargs);
2016-09-17 22:32:32 +02:00
if (!more) {
break;
}
++numargs;
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2021-03-18 20:55:14 +01:00
(id->get_index() < MaxArguments ? CS_CODE_CALL_ARG : CS_CODE_CALL)
2016-09-17 22:32:32 +02:00
| (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) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_IDENT, prevargs + numargs);
2016-09-17 22:32:32 +02:00
if (!more) {
break;
}
numargs++;
}
}
if (more) {
2021-03-18 20:55:14 +01:00
while ((more = compilearg(gs, CS_VAL_POP)));
2016-09-17 22:32:32 +02:00
}
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_LOCAL | (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) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_CODE, prevargs);
2016-09-17 22:32:32 +02:00
}
2021-03-18 20:55:14 +01:00
gs.code.push_back((more ? opcode : CS_CODE_NULL) | 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) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_ANY, prevargs);
2016-09-17 22:32:32 +02:00
}
if (!more) {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_NULL | cs_ret_code(rettype));
2016-09-17 22:32:32 +02:00
} else {
int start1 = gs.code.size();
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_CODE, prevargs + 1);
2016-09-17 22:32:32 +02:00
if (!more) {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_POP);
gs.code.push_back(CS_CODE_NULL | cs_ret_code(rettype));
2016-09-17 22:32:32 +02:00
} else {
int start2 = gs.code.size();
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_CODE, prevargs + 2);
2017-01-25 02:10:17 +01:00
uint32_t inst1 = gs.code[start1];
2021-03-18 20:55:14 +01:00
uint32_t op1 = inst1 & ~CS_CODE_RET_MASK;
2017-01-25 02:10:17 +01:00
uint32_t len1 = start2 - (start1 + 1);
2016-09-17 22:32:32 +02:00
if (!more) {
2021-03-18 20:55:14 +01:00
if (op1 == (CS_CODE_BLOCK | (len1 << 8))) {
gs.code[start1] = (len1 << 8) | CS_CODE_JUMP_B | CS_CODE_FLAG_FALSE;
gs.code[start1 + 1] = CS_CODE_ENTER_RESULT;
2016-09-17 22:32:32 +02:00
gs.code[start1 + len1] = (
2021-03-18 20:55:14 +01:00
gs.code[start1 + len1] & ~CS_CODE_RET_MASK
2016-09-17 22:32:32 +02:00
) | cs_ret_code(rettype);
return;
}
compileblock(gs);
} else {
2017-01-25 02:10:17 +01:00
uint32_t inst2 = gs.code[start2];
2021-03-18 20:55:14 +01:00
uint32_t op2 = inst2 & ~CS_CODE_RET_MASK;
2017-01-25 02:10:17 +01:00
uint32_t len2 = gs.code.size() - (start2 + 1);
2021-03-18 20:55:14 +01:00
if (op2 == (CS_CODE_BLOCK | (len2 << 8))) {
if (op1 == (CS_CODE_BLOCK | (len1 << 8))) {
2016-09-17 22:32:32 +02:00
gs.code[start1] = ((start2 - start1) << 8)
2021-03-18 20:55:14 +01:00
| CS_CODE_JUMP_B | CS_CODE_FLAG_FALSE;
gs.code[start1 + 1] = CS_CODE_ENTER_RESULT;
2016-09-17 22:32:32 +02:00
gs.code[start1 + len1] = (
2021-03-18 20:55:14 +01:00
gs.code[start1 + len1] & ~CS_CODE_RET_MASK
2016-09-17 22:32:32 +02:00
) | cs_ret_code(rettype);
2021-03-18 20:55:14 +01:00
gs.code[start2] = (len2 << 8) | CS_CODE_JUMP;
gs.code[start2 + 1] = CS_CODE_ENTER_RESULT;
2016-09-17 22:32:32 +02:00
gs.code[start2 + len2] = (
2021-03-18 20:55:14 +01:00
gs.code[start2 + len2] & ~CS_CODE_RET_MASK
2016-09-17 22:32:32 +02:00
) | cs_ret_code(rettype);
return;
2021-03-18 20:55:14 +01:00
} else if (op1 == (CS_CODE_EMPTY | (len1 << 8))) {
gs.code[start1] = CS_CODE_NULL | (inst2 & CS_CODE_RET_MASK);
gs.code[start2] = (len2 << 8) | CS_CODE_JUMP_B | CS_CODE_FLAG_TRUE;
gs.code[start2 + 1] = CS_CODE_ENTER_RESULT;
2016-09-17 22:32:32 +02:00
gs.code[start2 + len2] = (
2021-03-18 20:55:14 +01:00
gs.code[start2 + len2] & ~CS_CODE_RET_MASK
2016-09-17 22:32:32 +02:00
) | cs_ret_code(rettype);
return;
}
}
}
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_COM | 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) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_COND, prevargs);
2016-09-17 22:32:32 +02:00
}
if (!more) {
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2021-03-18 20:55:14 +01:00
((id->get_type_raw() == CsIdAnd) ? CS_CODE_TRUE : CS_CODE_FALSE)
2016-09-17 22:32:32 +02:00
| cs_ret_code(rettype)
);
} else {
numargs++;
int start = gs.code.size(), end = start;
while (numargs < MaxArguments) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_COND, prevargs + numargs);
2016-09-17 22:32:32 +02:00
if (!more) {
break;
}
numargs++;
2021-03-18 20:55:14 +01:00
if ((gs.code[end] & ~CS_CODE_RET_MASK) != (
CS_CODE_BLOCK | (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) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_COND, prevargs + numargs);
2016-09-17 22:32:32 +02:00
if (!more) {
break;
}
numargs++;
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2021-03-18 20:55:14 +01:00
CS_CODE_COM_V | cs_ret_code(rettype) |
2016-09-17 22:32:32 +02:00
(numargs << 8) | (id->get_index() << 13)
);
} else {
2017-01-25 02:10:17 +01:00
uint32_t op = (id->get_type_raw() == CsIdAnd)
2021-03-18 20:55:14 +01:00
? (CS_CODE_JUMP_RESULT | CS_CODE_FLAG_FALSE)
: (CS_CODE_JUMP_RESULT | CS_CODE_FLAG_TRUE);
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;
2021-03-18 20:55:14 +01:00
gs.code[start + 1] = CS_CODE_ENTER;
2016-09-17 22:32:32 +02:00
gs.code[start + len] = (
2021-03-18 20:55:14 +01:00
gs.code[start + len] & ~CS_CODE_RET_MASK
2016-09-17 22:32:32 +02:00
) | 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;
2021-03-18 20:55:14 +01:00
bool more = compilearg(gs, CS_VAL_WORD, 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()) {
2021-03-18 20:55:14 +01:00
case cs_ident_type::ALIAS:
more = compilearg(gs, CS_VAL_ANY, 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
2021-03-18 20:55:14 +01:00
? CS_CODE_ALIAS_ARG
: CS_CODE_ALIAS
2016-08-18 03:53:51 +02:00
) | (id->get_index() << 8)
2016-08-17 02:25:12 +02:00
);
goto endstatement;
2021-03-18 20:55:14 +01:00
case cs_ident_type::IVAR:
more = compilearg(gs, CS_VAL_INT, 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(
2021-03-18 20:55:14 +01:00
CS_CODE_IVAR1 | (id->get_index() << 8)
2016-08-18 03:53:51 +02:00
);
2016-08-17 02:25:12 +02:00
goto endstatement;
2021-03-18 20:55:14 +01:00
case cs_ident_type::FVAR:
more = compilearg(gs, CS_VAL_FLOAT, 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(
2021-03-18 20:55:14 +01:00
CS_CODE_FVAR1 | (id->get_index() << 8)
2016-08-18 03:53:51 +02:00
);
2016-08-17 02:25:12 +02:00
goto endstatement;
2021-03-18 20:55:14 +01:00
case cs_ident_type::SVAR:
more = compilearg(gs, CS_VAL_STRING, 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(
2021-03-18 20:55:14 +01:00
CS_CODE_SVAR1 | (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
}
}
gs.gen_str(idname);
2016-08-17 02:25:12 +02:00
}
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_ANY);
2016-08-17 02:25:12 +02:00
if (!more) {
gs.gen_str();
}
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_ALIAS_U);
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) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_ANY, prevargs + numargs);
2016-08-17 02:25:12 +02:00
if (!more) {
break;
}
++numargs;
}
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_CALL_U | (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);
goto noid;
}
switch (rettype) {
2021-03-18 20:55:14 +01:00
case CS_VAL_ANY: {
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()) {
gs.gen_str(idname);
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;
}
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_RESULT);
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:
2021-03-18 20:55:14 +01:00
compile_do(gs, more, prevargs, rettype, CS_CODE_DO);
2016-08-17 02:25:12 +02:00
break;
2016-09-07 20:20:36 +02:00
case CsIdDoArgs:
2021-03-18 20:55:14 +01:00
compile_do(gs, more, prevargs, rettype, CS_CODE_DO_ARGS);
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:
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_BREAK | CS_CODE_FLAG_FALSE);
2016-09-15 02:12:22 +02:00
break;
case CsIdContinue:
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_BREAK | CS_CODE_FLAG_TRUE);
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) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_ANY, prevargs);
2016-08-17 02:25:12 +02:00
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2021-03-18 20:55:14 +01:00
(more ? CS_CODE_RESULT : CS_CODE_NULL) |
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) {
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_ANY, prevargs);
}
2017-01-25 01:18:29 +01:00
gs.code.push_back(
2021-03-18 20:55:14 +01:00
(more ? CS_CODE_NOT : CS_CODE_TRUE) | 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:
2021-03-18 20:55:14 +01:00
if (!(more = compilearg(gs, CS_VAL_INT, prevargs))) {
gs.code.push_back(CS_CODE_PRINT | (id->get_index() << 8));
2017-02-13 18:10:40 +01:00
} else if (!(id->get_flags() & CS_IDF_HEX) || !(
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_INT, prevargs + 1)
2016-08-17 02:25:12 +02:00
)) {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_IVAR1 | (id->get_index() << 8));
2016-08-17 02:25:12 +02:00
} else if (!(
2021-03-18 20:55:14 +01:00
more = compilearg(gs, CS_VAL_INT, prevargs + 2)
2016-08-17 02:25:12 +02:00
)) {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_IVAR2 | (id->get_index() << 8));
2016-08-17 02:25:12 +02:00
} else {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_IVAR3 | (id->get_index() << 8));
2016-08-17 02:25:12 +02:00
}
break;
2016-09-07 20:20:36 +02:00
case CsIdFvar:
2021-03-18 20:55:14 +01:00
if (!(more = compilearg(gs, CS_VAL_FLOAT, prevargs))) {
gs.code.push_back(CS_CODE_PRINT | (id->get_index() << 8));
2016-08-17 02:25:12 +02:00
} else {
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_FVAR1 | (id->get_index() << 8));
2016-08-17 02:25:12 +02:00
}
break;
2016-09-07 20:20:36 +02:00
case CsIdSvar:
2021-03-18 20:55:14 +01:00
if (!(more = compilearg(gs, CS_VAL_STRING, prevargs))) {
gs.code.push_back(CS_CODE_PRINT | (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(
2021-03-18 20:55:14 +01:00
gs, CS_VAL_ANY, 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(
2021-03-18 20:55:14 +01:00
CS_CODE_CONC | CS_RET_STRING | (numargs << 8)
2016-09-07 20:20:36 +02:00
);
2016-08-17 02:25:12 +02:00
}
2021-03-18 20:55:14 +01:00
gs.code.push_back(CS_CODE_SVAR1 | (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) {
2021-03-18 20:55:14 +01:00
while (compilearg(gs, CS_VAL_POP));
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;
2021-03-18 20:55:14 +01:00
code.push_back(CS_CODE_START);
compilestatements(*this, CS_VAL_ANY);
code.push_back(CS_CODE_EXIT | ((ret_type < CS_VAL_ANY) ? (ret_type << CS_CODE_RET) : 0));
}
} /* namespace cscript */