more cleanup and deglobalization

master
Daniel Kolesa 2015-08-06 21:43:36 +01:00
parent f83560cad1
commit f28fab7a97
2 changed files with 126 additions and 110 deletions

View File

@ -4,10 +4,6 @@
CsState cstate; CsState cstate;
static constexpr int MAX_ARGUMENTS = 25;
static constexpr int MAX_RESULTS = 7;
static constexpr int MAX_COMARGS = 12;
const struct NullValue: TaggedValue { const struct NullValue: TaggedValue {
NullValue() { set_null(); } NullValue() { set_null(); }
} null_value; } null_value;
@ -174,78 +170,48 @@ void Ident::clean_code() {
} }
} }
static const char *sourcefile = nullptr, *sourcestr = nullptr; ostd::ConstCharRange debugline(CsState &cs, ostd::ConstCharRange p,
ostd::ConstCharRange fmt,
static const char *debugline(const char *p, const char *fmt) { ostd::CharRange buf) {
if (!sourcestr) return fmt; if (cs.src_str.empty()) return fmt;
int num = 1; ostd::Size num = 1;
const char *line = sourcestr; ostd::ConstCharRange line(cs.src_str);
for (;;) { for (;;) {
const char *end = strchr(line, '\n'); ostd::ConstCharRange end = ostd::find(line, '\n');
if (!end) end = line + strlen(line); if (!end.empty())
if (p >= line && p <= end) { line = line.slice(0, line.distance_front(end));
static char buf[256]; if (&p[0] >= &line[0] && &p[0] <= &line[line.size()]) {
auto r = ostd::iter(buf); ostd::CharRange r(buf);
if (sourcefile) ostd::format(r, "%s:%d: %s", sourcefile, num, fmt); if (!cs.src_file.empty())
else ostd::format(r, "%d: %s", num, fmt); ostd::format(r, "%s:%d: %s", cs.src_file, num, fmt);
else
ostd::format(r, "%d: %s", num, fmt);
r.put('\0'); r.put('\0');
return buf; return buf;
} }
if (!*end) break; if (end.empty()) break;
line = end + 1; line = end;
num++; line.pop_front();
++num;
} }
return fmt; return fmt;
} }
static struct IdentLink {
Ident *id;
IdentLink *next;
int usedargs;
IdentStack *argstack;
} noalias = { nullptr, nullptr, (1 << MAX_ARGUMENTS) - 1, nullptr }, *aliasstack = &noalias;
int dbgalias = variable("dbgalias", 0, 4, 1000, &dbgalias, nullptr, 0); int dbgalias = variable("dbgalias", 0, 4, 1000, &dbgalias, nullptr, 0);
static void debugalias() { void debugalias(CsState &cs) {
if (!dbgalias) return; if (!dbgalias) return;
int total = 0, depth = 0; int total = 0, depth = 0;
for (IdentLink *l = aliasstack; l != &noalias; l = l->next) total++; for (IdentLink *l = cs.stack; l != &cs.noalias; l = l->next) total++;
for (IdentLink *l = aliasstack; l != &noalias; l = l->next) { for (IdentLink *l = cs.stack; l != &cs.noalias; l = l->next) {
Ident *id = l->id; Ident *id = l->id;
++depth; ++depth;
if (depth < dbgalias) fprintf(stderr, " %d) %s\n", total - depth + 1, id->name.data()); if (depth < dbgalias) fprintf(stderr, " %d) %s\n", total - depth + 1, id->name.data());
else if (l->next == &noalias) fprintf(stderr, depth == dbgalias ? " %d) %s\n" : " ..%d) %s\n", total - depth + 1, id->name.data()); else if (l->next == &cs.noalias) fprintf(stderr, depth == dbgalias ? " %d) %s\n" : " ..%d) %s\n", total - depth + 1, id->name.data());
} }
} }
static int nodebug = 0; ICOMMAND(nodebug, "e", (CsState &cs, ostd::uint *body), { cs.nodebug++; executeret(body, *cs.result); cs.nodebug--; });
static void debugcode(const char *fmt, ...) {
if (nodebug) return;
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
fputc('\n', stderr);
va_end(args);
debugalias();
}
static void debugcodeline(const char *p, const char *fmt, ...) {
if (nodebug) return;
va_list args;
va_start(args, fmt);
vfprintf(stderr, debugline(p, fmt), args);
fputc('\n', stderr);
va_end(args);
debugalias();
}
ICOMMAND(nodebug, "e", (CsState &cs, ostd::uint *body), { nodebug++; executeret(body, *cs.result); nodebug--; });
void pusharg(Ident &id, const TaggedValue &v, IdentStack &stack) { void pusharg(Ident &id, const TaggedValue &v, IdentStack &stack) {
stack.val = id.val; stack.val = id.val;
@ -277,11 +243,11 @@ static inline void undoarg(Ident &id, IdentStack &stack) {
#define UNDOARGS \ #define UNDOARGS \
IdentStack argstack[MAX_ARGUMENTS]; \ IdentStack argstack[MAX_ARGUMENTS]; \
for(int argmask = aliasstack->usedargs, i = 0; argmask; argmask >>= 1, i++) if(argmask&1) \ for(int argmask = cstate.stack->usedargs, i = 0; argmask; argmask >>= 1, i++) if(argmask&1) \
undoarg(*cstate.identmap[i], argstack[i]); \ undoarg(*cstate.identmap[i], argstack[i]); \
IdentLink *prevstack = aliasstack->next; \ IdentLink *prevstack = cstate.stack->next; \
IdentLink aliaslink = { aliasstack->id, aliasstack, prevstack->usedargs, prevstack->argstack }; \ IdentLink aliaslink = { cstate.stack->id, cstate.stack, prevstack->usedargs, prevstack->argstack }; \
aliasstack = &aliaslink; cstate.stack = &aliaslink;
static inline void redoarg(Ident &id, const IdentStack &stack) { static inline void redoarg(Ident &id, const IdentStack &stack) {
IdentStack *prev = stack.next; IdentStack *prev = stack.next;
@ -294,8 +260,8 @@ static inline void redoarg(Ident &id, const IdentStack &stack) {
#define REDOARGS \ #define REDOARGS \
prevstack->usedargs = aliaslink.usedargs; \ prevstack->usedargs = aliaslink.usedargs; \
aliasstack = aliaslink.next; \ cstate.stack = aliaslink.next; \
for(int argmask = aliasstack->usedargs, i = 0; argmask; argmask >>= 1, i++) if(argmask&1) \ for(int argmask = cstate.stack->usedargs, i = 0; argmask; argmask >>= 1, i++) if(argmask&1) \
redoarg(*cstate.identmap[i], argstack[i]); redoarg(*cstate.identmap[i], argstack[i]);
ICOMMAND(push, "rTe", (CsState &cs, Ident *id, TaggedValue *v, ostd::uint *code), { ICOMMAND(push, "rTe", (CsState &cs, Ident *id, TaggedValue *v, ostd::uint *code), {
@ -338,7 +304,7 @@ Ident *CsState::new_ident(ostd::ConstCharRange name, int flags) {
Ident *id = idents.at(name); Ident *id = idents.at(name);
if (!id) { if (!id) {
if (checknumber(name.data())) { if (checknumber(name.data())) {
debugcode("number %.*s is not a valid identifier name", int(name.size()), name.data()); debug_code("number %.*s is not a valid identifier name", int(name.size()), name.data());
return dummy; return dummy;
} }
id = add_ident(ID_ALIAS, name, flags); id = add_ident(ID_ALIAS, name, flags);
@ -372,7 +338,7 @@ bool CsState::reset_var(ostd::ConstCharRange name) {
Ident *id = idents.at(name); Ident *id = idents.at(name);
if (!id) return false; if (!id) return false;
if (id->flags & IDF_READONLY) { if (id->flags & IDF_READONLY) {
debugcode("variable %s is read only", id->name.data()); debug_code("variable %s is read only", id->name.data());
return false; return false;
} }
clear_override(*id); clear_override(*id);
@ -393,13 +359,13 @@ void CsState::touch_var(ostd::ConstCharRange name) {
} }
static inline void setarg(Ident &id, TaggedValue &v) { static inline void setarg(Ident &id, TaggedValue &v) {
if (aliasstack->usedargs & (1 << id.index)) { if (cstate.stack->usedargs & (1 << id.index)) {
if (id.valtype == VAL_STR) delete[] id.val.s; if (id.valtype == VAL_STR) delete[] id.val.s;
id.setval(v); id.setval(v);
id.clean_code(); id.clean_code();
} else { } else {
pusharg(id, v, aliasstack->argstack[id.index]); pusharg(id, v, cstate.stack->argstack[id.index]);
aliasstack->usedargs |= 1 << id.index; cstate.stack->usedargs |= 1 << id.index;
} }
} }
@ -428,12 +394,12 @@ static void setalias(const char *name, TaggedValue &v) {
setsvarchecked(id, v.get_str()); setsvarchecked(id, v.get_str());
break; break;
default: default:
debugcode("cannot redefine builtin %s with an alias", id->name.data()); cstate.debug_code("cannot redefine builtin %s with an alias", id->name.data());
break; break;
} }
v.cleanup(); v.cleanup();
} else if (checknumber(name)) { } else if (checknumber(name)) {
debugcode("cannot alias number %s", name); cstate.debug_code("cannot alias number %s", name);
v.cleanup(); v.cleanup();
} else { } else {
cstate.add_ident(ID_ALIAS, name, v, cstate.identflags); cstate.add_ident(ID_ALIAS, name, v, cstate.identflags);
@ -479,7 +445,7 @@ char *svariable(const char *name, const char *cur, char **storage, IdentFunc fun
{ \ { \
if(id->flags&IDF_PERSIST) \ if(id->flags&IDF_PERSIST) \
{ \ { \
debugcode("cannot override persistent variable %s", id->name.data()); \ cstate.debug_code("cannot override persistent variable %s", id->name.data()); \
errorval; \ errorval; \
} \ } \
if(!(id->flags&IDF_OVERRIDDEN)) { saveval; id->flags |= IDF_OVERRIDDEN; } \ if(!(id->flags&IDF_OVERRIDDEN)) { saveval; id->flags |= IDF_OVERRIDDEN; } \
@ -541,7 +507,7 @@ ICOMMAND(identexists, "s", (CsState &cs, char *s), cs.result->set_int(cstate.hav
const char *getalias(const char *name) { const char *getalias(const char *name) {
Ident *i = cstate.idents.at(name); Ident *i = cstate.idents.at(name);
return i && i->type == ID_ALIAS && (i->index >= MAX_ARGUMENTS || aliasstack->usedargs & (1 << i->index)) ? i->get_str() : ""; return i && i->type == ID_ALIAS && (i->index >= MAX_ARGUMENTS || cstate.stack->usedargs & (1 << i->index)) ? i->get_str() : "";
} }
ICOMMAND(getalias, "s", (CsState &, char *s), result(getalias(s))); ICOMMAND(getalias, "s", (CsState &, char *s), result(getalias(s)));
@ -550,7 +516,7 @@ int clampvar(Ident *id, int val, int minval, int maxval) {
if (val < minval) val = minval; if (val < minval) val = minval;
else if (val > maxval) val = maxval; else if (val > maxval) val = maxval;
else return val; else return val;
debugcode(id->flags & IDF_HEX ? cstate.debug_code(id->flags & IDF_HEX ?
(minval <= 255 ? "valid range for %s is %d..0x%X" : "valid range for %s is 0x%X..0x%X") : (minval <= 255 ? "valid range for %s is %d..0x%X" : "valid range for %s is 0x%X..0x%X") :
"valid range for %s is %d..%d", "valid range for %s is %d..%d",
id->name.data(), minval, maxval); id->name.data(), minval, maxval);
@ -558,7 +524,7 @@ int clampvar(Ident *id, int val, int minval, int maxval) {
} }
void setvarchecked(Ident *id, int val) { void setvarchecked(Ident *id, int val) {
if (id->flags & IDF_READONLY) debugcode("variable %s is read-only", id->name.data()); if (id->flags & IDF_READONLY) cstate.debug_code("variable %s is read-only", id->name.data());
else { else {
OVERRIDEVAR(return, id->overrideval.i = *id->storage.i, , ) OVERRIDEVAR(return, id->overrideval.i = *id->storage.i, , )
if (val < id->minval || val > id->maxval) val = clampvar(id, val, id->minval, id->maxval); if (val < id->minval || val > id->maxval) val = clampvar(id, val, id->minval, id->maxval);
@ -580,12 +546,12 @@ float clampfvar(Ident *id, float val, float minval, float maxval) {
if (val < minval) val = minval; if (val < minval) val = minval;
else if (val > maxval) val = maxval; else if (val > maxval) val = maxval;
else return val; else return val;
debugcode("valid range for %s is %s..%s", id->name.data(), floatstr(minval), floatstr(maxval)); cstate.debug_code("valid range for %s is %s..%s", id->name.data(), floatstr(minval), floatstr(maxval));
return val; return val;
} }
void setfvarchecked(Ident *id, float val) { void setfvarchecked(Ident *id, float val) {
if (id->flags & IDF_READONLY) debugcode("variable %s is read-only", id->name.data()); if (id->flags & IDF_READONLY) cstate.debug_code("variable %s is read-only", id->name.data());
else { else {
OVERRIDEVAR(return, id->overrideval.f = *id->storage.f, , ); OVERRIDEVAR(return, id->overrideval.f = *id->storage.f, , );
if (val < id->minvalf || val > id->maxvalf) val = clampfvar(id, val, id->minvalf, id->maxvalf); if (val < id->minvalf || val > id->maxvalf) val = clampfvar(id, val, id->minvalf, id->maxvalf);
@ -595,7 +561,7 @@ void setfvarchecked(Ident *id, float val) {
} }
void setsvarchecked(Ident *id, const char *val) { void setsvarchecked(Ident *id, const char *val) {
if (id->flags & IDF_READONLY) debugcode("variable %s is read-only", id->name.data()); if (id->flags & IDF_READONLY) cstate.debug_code("variable %s is read-only", id->name.data());
else { else {
OVERRIDEVAR(return, id->overrideval.s = *id->storage.s, delete[] id->overrideval.s, delete[] * id->storage.s); OVERRIDEVAR(return, id->overrideval.s = *id->storage.s, delete[] id->overrideval.s, delete[] * id->storage.s);
*id->storage.s = dup_ostr(val); *id->storage.s = dup_ostr(val);
@ -1421,7 +1387,7 @@ static void compileblockmain(ostd::Vector<ostd::uint> &code, const char *&p, int
int c = *p++; int c = *p++;
switch (c) { switch (c) {
case '\0': case '\0':
debugcodeline(line, "missing \"]\""); cstate.debug_code_line(line, "missing \"]\"");
p--; p--;
goto done; goto done;
case '\"': case '\"':
@ -1442,7 +1408,7 @@ static void compileblockmain(ostd::Vector<ostd::uint> &code, const char *&p, int
while (*p == '@') p++; while (*p == '@') p++;
int level = p - (esc - 1); int level = p - (esc - 1);
if (brak > level) continue; if (brak > level) continue;
else if (brak < level) debugcodeline(line, "too many @s"); else if (brak < level) cstate.debug_code_line(line, "too many @s");
if (!concs && prevargs >= MAX_RESULTS) code.push(CODE_ENTER); if (!concs && prevargs >= MAX_RESULTS) code.push(CODE_ENTER);
if (concs + 2 > MAX_ARGUMENTS) { if (concs + 2 > MAX_ARGUMENTS) {
code.push(CODE_CONCW | RET_STR | (concs << 8)); code.push(CODE_CONCW | RET_STR | (concs << 8));
@ -1963,14 +1929,14 @@ endstatement:
int c = *p++; int c = *p++;
switch (c) { switch (c) {
case '\0': case '\0':
if (c != brak) debugcodeline(line, "missing \"%c\"", brak); if (c != brak) cstate.debug_code_line(line, "missing \"%c\"", brak);
p--; p--;
return; return;
case ')': case ')':
case ']': case ']':
if (c == brak) return; if (c == brak) return;
debugcodeline(line, "unexpected \"%c\"", c); cstate.debug_code_line(line, "unexpected \"%c\"", c);
break; break;
case '/': case '/':
@ -2277,7 +2243,7 @@ static int rundepth = 0;
static const ostd::uint *runcode(const ostd::uint *code, TaggedValue &result) { static const ostd::uint *runcode(const ostd::uint *code, TaggedValue &result) {
result.set_null(); result.set_null();
if (rundepth >= MAXRUNDEPTH) { if (rundepth >= MAXRUNDEPTH) {
debugcode("exceeded recursion limit"); cstate.debug_code("exceeded recursion limit");
return skipcode(code, result); return skipcode(code, result);
} }
++rundepth; ++rundepth;
@ -2364,7 +2330,7 @@ static const ostd::uint *runcode(const ostd::uint *code, TaggedValue &result) {
case CODE_DOARGS|RET_STR: case CODE_DOARGS|RET_STR:
case CODE_DOARGS|RET_INT: case CODE_DOARGS|RET_INT:
case CODE_DOARGS|RET_FLOAT: case CODE_DOARGS|RET_FLOAT:
if (aliasstack != &noalias) { if (cstate.stack != &cstate.noalias) {
UNDOARGS UNDOARGS
result.cleanup(); result.cleanup();
runcode(args[--numargs].code, result); runcode(args[--numargs].code, result);
@ -2575,9 +2541,9 @@ static const ostd::uint *runcode(const ostd::uint *code, TaggedValue &result) {
continue; continue;
case CODE_IDENTARG: { case CODE_IDENTARG: {
Ident *id = cstate.identmap[op >> 8]; Ident *id = cstate.identmap[op >> 8];
if (!(aliasstack->usedargs & (1 << id->index))) { if (!(cstate.stack->usedargs & (1 << id->index))) {
pusharg(*id, null_value, aliasstack->argstack[id->index]); pusharg(*id, null_value, cstate.stack->argstack[id->index]);
aliasstack->usedargs |= 1 << id->index; cstate.stack->usedargs |= 1 << id->index;
} }
args[numargs++].set_ident(id); args[numargs++].set_ident(id);
continue; continue;
@ -2585,9 +2551,9 @@ static const ostd::uint *runcode(const ostd::uint *code, TaggedValue &result) {
case CODE_IDENTU: { case CODE_IDENTU: {
TaggedValue &arg = args[numargs - 1]; TaggedValue &arg = args[numargs - 1];
Ident *id = arg.type == VAL_STR || arg.type == VAL_MACRO || arg.type == VAL_CSTR ? cstate.new_ident(arg.cstr, IDF_UNKNOWN) : cstate.dummy; Ident *id = arg.type == VAL_STR || arg.type == VAL_MACRO || arg.type == VAL_CSTR ? cstate.new_ident(arg.cstr, IDF_UNKNOWN) : cstate.dummy;
if (id->index < MAX_ARGUMENTS && !(aliasstack->usedargs & (1 << id->index))) { if (id->index < MAX_ARGUMENTS && !(cstate.stack->usedargs & (1 << id->index))) {
pusharg(*id, null_value, aliasstack->argstack[id->index]); pusharg(*id, null_value, cstate.stack->argstack[id->index]);
aliasstack->usedargs |= 1 << id->index; cstate.stack->usedargs |= 1 << id->index;
} }
arg.cleanup(); arg.cleanup();
arg.set_ident(id); arg.set_ident(id);
@ -2604,7 +2570,7 @@ static const ostd::uint *runcode(const ostd::uint *code, TaggedValue &result) {
case ID_ALIAS: \ case ID_ALIAS: \
if(id->flags&IDF_UNKNOWN) break; \ if(id->flags&IDF_UNKNOWN) break; \
arg.cleanup(); \ arg.cleanup(); \
if(id->index < MAX_ARGUMENTS && !(aliasstack->usedargs&(1<<id->index))) { nval; continue; } \ if(id->index < MAX_ARGUMENTS && !(cstate.stack->usedargs&(1<<id->index))) { nval; continue; } \
aval; \ aval; \
continue; \ continue; \
case ID_SVAR: arg.cleanup(); sval; continue; \ case ID_SVAR: arg.cleanup(); sval; continue; \
@ -2623,7 +2589,7 @@ static const ostd::uint *runcode(const ostd::uint *code, TaggedValue &result) {
} \ } \
default: arg.cleanup(); nval; continue; \ default: arg.cleanup(); nval; continue; \
} \ } \
debugcode("unknown alias lookup: %s", arg.s); \ cstate.debug_code("unknown alias lookup: %s", arg.s); \
arg.cleanup(); \ arg.cleanup(); \
nval; \ nval; \
continue; \ continue; \
@ -2636,7 +2602,7 @@ static const ostd::uint *runcode(const ostd::uint *code, TaggedValue &result) {
case CODE_LOOKUP|RET_STR: case CODE_LOOKUP|RET_STR:
#define LOOKUP(aval) { \ #define LOOKUP(aval) { \
Ident *id = cstate.identmap[op>>8]; \ Ident *id = cstate.identmap[op>>8]; \
if(id->flags&IDF_UNKNOWN) debugcode("unknown alias lookup: %s", id->name.data()); \ if(id->flags&IDF_UNKNOWN) cstate.debug_code("unknown alias lookup: %s", id->name.data()); \
aval; \ aval; \
continue; \ continue; \
} }
@ -2644,7 +2610,7 @@ static const ostd::uint *runcode(const ostd::uint *code, TaggedValue &result) {
case CODE_LOOKUPARG|RET_STR: case CODE_LOOKUPARG|RET_STR:
#define LOOKUPARG(aval, nval) { \ #define LOOKUPARG(aval, nval) { \
Ident *id = cstate.identmap[op>>8]; \ Ident *id = cstate.identmap[op>>8]; \
if(!(aliasstack->usedargs&(1<<id->index))) { nval; continue; } \ if(!(cstate.stack->usedargs&(1<<id->index))) { nval; continue; } \
aval; \ aval; \
continue; \ continue; \
} }
@ -2858,15 +2824,15 @@ static const ostd::uint *runcode(const ostd::uint *code, TaggedValue &result) {
_numargs = callargs; \ _numargs = callargs; \
int oldflags = cstate.identflags; \ int oldflags = cstate.identflags; \
cstate.identflags |= id->flags&IDF_OVERRIDDEN; \ cstate.identflags |= id->flags&IDF_OVERRIDDEN; \
IdentLink aliaslink = { id, aliasstack, (1<<callargs)-1, argstack }; \ IdentLink aliaslink = { id, cstate.stack, (1<<callargs)-1, argstack }; \
aliasstack = &aliaslink; \ cstate.stack = &aliaslink; \
if(!id->code) id->code = compilecode(id->get_str()); \ if(!id->code) id->code = compilecode(id->get_str()); \
ostd::uint *code = id->code; \ ostd::uint *code = id->code; \
code[0] += 0x100; \ code[0] += 0x100; \
runcode(code+1, result); \ runcode(code+1, result); \
code[0] -= 0x100; \ code[0] -= 0x100; \
if(int(code[0]) < 0x100) delete[] code; \ if(int(code[0]) < 0x100) delete[] code; \
aliasstack = aliaslink.next; \ cstate.stack = aliaslink.next; \
cstate.identflags = oldflags; \ cstate.identflags = oldflags; \
for(int i = 0; i < callargs; i++) \ for(int i = 0; i < callargs; i++) \
poparg(*cstate.identmap[i]); \ poparg(*cstate.identmap[i]); \
@ -2880,7 +2846,7 @@ static const ostd::uint *runcode(const ostd::uint *code, TaggedValue &result) {
Ident *id = cstate.identmap[op >> 13]; Ident *id = cstate.identmap[op >> 13];
int callargs = (op >> 8) & 0x1F, offset = numargs - callargs; int callargs = (op >> 8) & 0x1F, offset = numargs - callargs;
if (id->flags & IDF_UNKNOWN) { if (id->flags & IDF_UNKNOWN) {
debugcode("unknown command: %s", id->name.data()); cstate.debug_code("unknown command: %s", id->name.data());
FORCERESULT; FORCERESULT;
} }
CALLALIAS; CALLALIAS;
@ -2893,7 +2859,7 @@ static const ostd::uint *runcode(const ostd::uint *code, TaggedValue &result) {
result.force_null(); result.force_null();
Ident *id = cstate.identmap[op >> 13]; Ident *id = cstate.identmap[op >> 13];
int callargs = (op >> 8) & 0x1F, offset = numargs - callargs; int callargs = (op >> 8) & 0x1F, offset = numargs - callargs;
if (!(aliasstack->usedargs & (1 << id->index))) FORCERESULT; if (!(cstate.stack->usedargs & (1 << id->index))) FORCERESULT;
CALLALIAS; CALLALIAS;
continue; continue;
} }
@ -2918,7 +2884,7 @@ litval:
if (!id) { if (!id) {
noid: noid:
if (checknumber(idarg.s)) goto litval; if (checknumber(idarg.s)) goto litval;
debugcode("unknown command: %s", idarg.s); cstate.debug_code("unknown command: %s", idarg.s);
result.force_null(); result.force_null();
FORCERESULT; FORCERESULT;
} }
@ -2954,7 +2920,7 @@ noid:
else setsvarchecked(id, args[offset].force_str()); else setsvarchecked(id, args[offset].force_str());
FORCERESULT; FORCERESULT;
case ID_ALIAS: case ID_ALIAS:
if (id->index < MAX_ARGUMENTS && !(aliasstack->usedargs & (1 << id->index))) FORCERESULT; if (id->index < MAX_ARGUMENTS && !(cstate.stack->usedargs & (1 << id->index))) FORCERESULT;
if (id->valtype == VAL_NULL) goto noid; if (id->valtype == VAL_NULL) goto noid;
idarg.cleanup(); idarg.cleanup();
CALLALIAS; CALLALIAS;
@ -2987,7 +2953,7 @@ void executeret(Ident *id, TaggedValue *args, int numargs, TaggedValue &result)
++rundepth; ++rundepth;
TaggedValue *prevret = cstate.result; TaggedValue *prevret = cstate.result;
cstate.result = &result; cstate.result = &result;
if (rundepth > MAXRUNDEPTH) debugcode("exceeded recursion limit"); if (rundepth > MAXRUNDEPTH) cstate.debug_code("exceeded recursion limit");
else if (id) switch (id->type) { else if (id) switch (id->type) {
default: default:
if (!id->fun) break; if (!id->fun) break;
@ -3013,7 +2979,7 @@ void executeret(Ident *id, TaggedValue *args, int numargs, TaggedValue &result)
else setsvarchecked(id, args[0].force_str()); else setsvarchecked(id, args[0].force_str());
break; break;
case ID_ALIAS: case ID_ALIAS:
if (id->index < MAX_ARGUMENTS && !(aliasstack->usedargs & (1 << id->index))) break; if (id->index < MAX_ARGUMENTS && !(cstate.stack->usedargs & (1 << id->index))) break;
if (id->valtype == VAL_NULL) break; if (id->valtype == VAL_NULL) break;
#define callargs numargs #define callargs numargs
#define offset 0 #define offset 0
@ -3139,7 +3105,7 @@ bool CsState::run_bool(Ident *id, ostd::PointerRange<TaggedValue> args) {
} }
bool CsState::run_file(ostd::ConstCharRange fname, bool msg) { bool CsState::run_file(ostd::ConstCharRange fname, bool msg) {
const char *oldsourcefile = sourcefile, *oldsourcestr = sourcestr; ostd::ConstCharRange oldsrcfile = cstate.src_file, oldsrcstr = cstate.src_str;
char *buf = nullptr; char *buf = nullptr;
ostd::Size len; ostd::Size len;
@ -3154,11 +3120,11 @@ bool CsState::run_file(ostd::ConstCharRange fname, bool msg) {
} }
buf[len] = '\0'; buf[len] = '\0';
sourcefile = fname.data(); cstate.src_file = fname;
sourcestr = buf; cstate.src_str = ostd::ConstCharRange(buf, len);
cstate.run_int(buf); cstate.run_int(buf);
sourcefile = oldsourcefile; cstate.src_file = oldsrcfile;
sourcestr = oldsourcestr; cstate.src_str = oldsrcstr;
delete[] buf; delete[] buf;
return true; return true;
@ -3167,7 +3133,11 @@ error:
return false; return false;
} }
ICOMMAND(exec, "sb", (CsState &cs, char *file, int *msg), cs.result->set_int(cs.run_file(file, *msg != 0) ? 1 : 0)); void init_lib_io(CsState &cs) {
cs.add_command("exec", "sb", [](CsState &cs, char *file, int *msg) {
cs.result->set_int(cs.run_file(file, *msg != 0) ? 1 : 0);
});
}
const char *escapestring(const char *s) { const char *escapestring(const char *s) {
stridx = (stridx + 1) % 4; stridx = (stridx + 1) % 4;
@ -3272,7 +3242,7 @@ const char *floatstr(float v) {
ICOMMANDK(do, ID_DO, "e", (CsState &cs, ostd::uint *body), executeret(body, *cs.result)); ICOMMANDK(do, ID_DO, "e", (CsState &cs, ostd::uint *body), executeret(body, *cs.result));
static void doargs(CsState &cs, ostd::uint *body) { static void doargs(CsState &cs, ostd::uint *body) {
if (aliasstack != &noalias) { if (cstate.stack != &cstate.noalias) {
UNDOARGS UNDOARGS
executeret(body, *cs.result); executeret(body, *cs.result);
REDOARGS REDOARGS

View File

@ -8,6 +8,7 @@
#include <math.h> #include <math.h>
#include <ostd/algorithm.hh> #include <ostd/algorithm.hh>
#include <ostd/array.hh>
#include <ostd/vector.hh> #include <ostd/vector.hh>
#include <ostd/string.hh> #include <ostd/string.hh>
#include <ostd/keyset.hh> #include <ostd/keyset.hh>
@ -23,6 +24,10 @@ inline char *dup_ostr(ostd::ConstCharRange s) {
return r; return r;
} }
static constexpr int MAX_ARGUMENTS = 25;
static constexpr int MAX_RESULTS = 7;
static constexpr int MAX_COMARGS = 12;
enum { enum {
VAL_NULL = 0, VAL_INT, VAL_FLOAT, VAL_STR, VAL_NULL = 0, VAL_INT, VAL_FLOAT, VAL_STR,
VAL_ANY, VAL_CODE, VAL_MACRO, VAL_IDENT, VAL_CSTR, VAL_ANY, VAL_CODE, VAL_MACRO, VAL_IDENT, VAL_CSTR,
@ -274,6 +279,18 @@ struct Ident {
void clean_code(); void clean_code();
}; };
struct IdentLink {
Ident *id;
IdentLink *next;
int usedargs;
IdentStack *argstack;
};
void debugalias(CsState &cs);
ostd::ConstCharRange debugline(CsState &cs, ostd::ConstCharRange p,
ostd::ConstCharRange fmt,
ostd::CharRange buf);
struct CsState { struct CsState {
ostd::Keyset<Ident> idents; ostd::Keyset<Ident> idents;
ostd::Vector<Ident *> identmap; ostd::Vector<Ident *> identmap;
@ -281,7 +298,16 @@ struct CsState {
Ident *dummy = nullptr; Ident *dummy = nullptr;
TaggedValue *result = nullptr; TaggedValue *result = nullptr;
IdentLink noalias = {
nullptr, nullptr, (1 << MAX_ARGUMENTS) - 1, nullptr
};
IdentLink *stack = &noalias;
ostd::ConstCharRange src_file;
ostd::ConstCharRange src_str;
int identflags = 0; int identflags = 0;
int nodebug = 0;
CsState(); CsState();
~CsState(); ~CsState();
@ -337,6 +363,25 @@ struct CsState {
bool run_bool(Ident *id, ostd::PointerRange<TaggedValue> args); bool run_bool(Ident *id, ostd::PointerRange<TaggedValue> args);
bool run_file(ostd::ConstCharRange fname, bool msg = true); bool run_file(ostd::ConstCharRange fname, bool msg = true);
template<typename ...A>
void debug_code(ostd::ConstCharRange fmt, A &&...args) {
if (nodebug) return;
ostd::err.writefln(fmt, ostd::forward<A>(args)...);
debugalias(*this);
}
template<typename ...A>
void debug_code_line(ostd::ConstCharRange p,
ostd::ConstCharRange fmt, A &&...args) {
if (nodebug) return;
ostd::Array<char, 256> buf;
ostd::err.writefln(debugline(*this, p, fmt,
ostd::CharRange(buf.data(),
buf.size())),
ostd::forward<A>(args)...);
debugalias(*this);
}
}; };
extern CsState cstate; extern CsState cstate;
@ -552,5 +597,6 @@ void poparg(Ident &id);
#define ICOMMAND(name, nargs, proto, b) ICOMMANDN(name, ICOMMANDNAME(name), nargs, proto, b) #define ICOMMAND(name, nargs, proto, b) ICOMMANDN(name, ICOMMANDNAME(name), nargs, proto, b)
#define ICOMMANDS(name, nargs, proto, b) ICOMMANDNS(name, ICOMMANDSNAME, nargs, proto, b) #define ICOMMANDS(name, nargs, proto, b) ICOMMANDNS(name, ICOMMANDSNAME, nargs, proto, b)
void init_lib_io(CsState &cs);
void init_lib_math(CsState &cs); void init_lib_math(CsState &cs);
void init_lib_shell(CsState &cs); void init_lib_shell(CsState &cs);