diff --git a/command.cc b/command.cc index 58b4497..e57eea2 100644 --- a/command.cc +++ b/command.cc @@ -2,6 +2,20 @@ #define fatal printf +static inline bool check_num(const char *s) { + if (isdigit(s[0])) + return true; + switch (s[0]) { + case '+': + case '-': + return isdigit(s[1]) || (s[1] == '.' && isdigit(s[2])); + case '.': + return isdigit(s[1]) != 0; + default: + return false; + } +} + CsState cstate; const struct NullValue: TaggedValue { @@ -65,6 +79,62 @@ void CsState::clear_overrides() { clear_override(id); } +Ident *CsState::new_ident(ostd::ConstCharRange name, int flags) { + Ident *id = idents.at(name); + if (!id) { + if (check_num(name.data())) { + debug_code("number %.*s is not a valid identifier name", int(name.size()), name.data()); + return dummy; + } + id = add_ident(ID_ALIAS, name, flags); + } + return id; +} + +Ident *CsState::force_ident(TaggedValue &v) { + switch (v.type) { + case VAL_IDENT: + return v.id; + case VAL_MACRO: + case VAL_CSTR: { + Ident *id = new_ident(v.s, IDF_UNKNOWN); + v.set_ident(id); + return id; + } + case VAL_STR: { + Ident *id = new_ident(v.s, IDF_UNKNOWN); + delete[] v.s; + v.set_ident(id); + return id; + } + } + v.cleanup(); + v.set_ident(dummy); + return dummy; +} + +bool CsState::reset_var(ostd::ConstCharRange name) { + Ident *id = idents.at(name); + if (!id) return false; + if (id->flags & IDF_READONLY) { + debug_code("variable %s is read only", id->name.data()); + return false; + } + clear_override(*id); + return true; +} + +void CsState::touch_var(ostd::ConstCharRange name) { + Ident *id = idents.at(name); + if (id) switch (id->type) { + case ID_VAR: + case ID_FVAR: + case ID_SVAR: + id->changed(*this); + break; + } +} + int _numargs = variable("numargs", MAX_ARGUMENTS, 0, 0, &_numargs, nullptr, 0); void TaggedValue::cleanup() { @@ -252,6 +322,17 @@ void Ident::redo_arg(const IdentStack &st) { clean_code(); } +void Ident::push_alias(IdentStack &stack) { + if (type == ID_ALIAS && index >= MAX_ARGUMENTS) { + push_arg(null_value, stack); + flags &= ~IDF_UNKNOWN; + } +} + +void Ident::pop_alias() { + if (type == ID_ALIAS && index >= MAX_ARGUMENTS) pop_arg(); +} + template static void cs_do_args(CsState &cs, F body) { IdentStack argstack[MAX_ARGUMENTS]; @@ -288,90 +369,12 @@ void init_lib_base(CsState &cs) { executeret(code, *cs.result); id->pop_arg(); }); -} -static inline void pushalias(Ident &id, IdentStack &stack) { - if (id.type == ID_ALIAS && id.index >= MAX_ARGUMENTS) { - id.push_arg(null_value, stack); - id.flags &= ~IDF_UNKNOWN; - } -} + cs.add_command("local", ostd::ConstCharRange(), nullptr, ID_LOCAL); -static inline void popalias(Ident &id) { - if (id.type == ID_ALIAS && id.index >= MAX_ARGUMENTS) id.pop_arg(); -} - -KEYWORD(local, ID_LOCAL); - -static inline bool checknumber(const char *s) { - if (isdigit(s[0])) return true; - else switch (s[0]) { - case '+': - case '-': - return isdigit(s[1]) || (s[1] == '.' && isdigit(s[2])); - case '.': - return isdigit(s[1]) != 0; - default: - return false; - } -} - -Ident *CsState::new_ident(ostd::ConstCharRange name, int flags) { - Ident *id = idents.at(name); - if (!id) { - if (checknumber(name.data())) { - debug_code("number %.*s is not a valid identifier name", int(name.size()), name.data()); - return dummy; - } - id = add_ident(ID_ALIAS, name, flags); - } - return id; -} - -Ident *CsState::force_ident(TaggedValue &v) { - switch (v.type) { - case VAL_IDENT: - return v.id; - case VAL_MACRO: - case VAL_CSTR: { - Ident *id = new_ident(v.s, IDF_UNKNOWN); - v.set_ident(id); - return id; - } - case VAL_STR: { - Ident *id = new_ident(v.s, IDF_UNKNOWN); - delete[] v.s; - v.set_ident(id); - return id; - } - } - v.cleanup(); - v.set_ident(dummy); - return dummy; -} - -bool CsState::reset_var(ostd::ConstCharRange name) { - Ident *id = idents.at(name); - if (!id) return false; - if (id->flags & IDF_READONLY) { - debug_code("variable %s is read only", id->name.data()); - return false; - } - clear_override(*id); - return true; -} - -ICOMMAND(resetvar, "s", (CsState &cs, char *name), cs.result->set_int(cs.reset_var(name));); - -void CsState::touch_var(ostd::ConstCharRange name) { - Ident *id = idents.at(name); - if (id) switch (id->type) { - case ID_VAR: - case ID_FVAR: - case ID_SVAR: - id->changed(*this); - break; - } + cs.add_command("resetvar", "s", [](CsState &cs, char *name) { + cs.result->set_int(cs.reset_var(name)); + }); } static inline void setarg(Ident &id, TaggedValue &v) { @@ -414,7 +417,7 @@ static void setalias(const char *name, TaggedValue &v) { break; } v.cleanup(); - } else if (checknumber(name)) { + } else if (check_num(name)) { cstate.debug_code("cannot alias number %s", name); v.cleanup(); } else { @@ -1673,7 +1676,7 @@ noid: } else { Ident *id = cstate.idents.at(idname); if (!id) { - if (!checknumber(idname.data())) { + if (!check_num(idname.data())) { compilestr(code, idname, true); goto noid; } @@ -2336,9 +2339,9 @@ static const ostd::uint *runcode(const ostd::uint *code, TaggedValue &result) { result.cleanup(); int numlocals = op >> 8, offset = numargs - numlocals; IdentStack locals[MAX_ARGUMENTS]; - for (int i = 0; i < numlocals; ++i) pushalias(*args[offset + i].id, locals[i]); + for (int i = 0; i < numlocals; ++i) args[offset + i].id->push_alias(locals[i]); code = runcode(code, result); - for (int i = offset; i < numargs; i++) popalias(*args[i].id); + for (int i = offset; i < numargs; i++) args[i].id->pop_alias(); goto exit; } @@ -2899,7 +2902,7 @@ litval: Ident *id = cstate.idents.at(idarg.s); if (!id) { noid: - if (checknumber(idarg.s)) goto litval; + if (check_num(idarg.s)) goto litval; cstate.debug_code("unknown command: %s", idarg.s); result.force_null(); FORCERESULT; @@ -2918,9 +2921,9 @@ noid: case ID_LOCAL: { IdentStack locals[MAX_ARGUMENTS]; idarg.cleanup(); - for (ostd::Size j = 0; j < ostd::Size(callargs); ++j) pushalias(*cstate.force_ident(args[offset + j]), locals[j]); + for (ostd::Size j = 0; j < ostd::Size(callargs); ++j) cstate.force_ident(args[offset + j])->push_alias(locals[j]); code = runcode(code, result); - for (ostd::Size j = 0; j < ostd::Size(callargs); ++j) popalias(*args[offset + j].id); + for (ostd::Size j = 0; j < ostd::Size(callargs); ++j) args[offset + j].id->pop_alias(); goto exit; } case ID_VAR: diff --git a/command.hh b/command.hh index 92f60ba..48f236a 100644 --- a/command.hh +++ b/command.hh @@ -282,6 +282,9 @@ struct Ident { void pop_arg(); void undo_arg(IdentStack &st); void redo_arg(const IdentStack &st); + + void push_alias(IdentStack &st); + void pop_alias(); }; struct IdentLink { @@ -581,7 +584,6 @@ static inline void loopiter(Ident *id, IdentStack &stack, const char *s) { loopiter(id, stack, v); } -#define KEYWORD(name, type) static bool __dummy_##type = addcommand(#name, (IdentFunc)nullptr, nullptr, type) #define COMMANDKN(name, type, fun, nargs) static bool __dummy_##fun = addcommand(#name, (IdentFunc)fun, nargs, type) #define COMMANDK(name, type, nargs) COMMANDKN(name, type, name, nargs) #define COMMANDN(name, fun, nargs) COMMANDKN(name, ID_COMMAND, fun, nargs)