From 5849faf3cf733083b43d33937514cc3c2ba14125 Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Sun, 30 Dec 2007 04:11:33 +0000 Subject: [PATCH] cubescript backports git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@1528 e016b1c5-ed68-44aa-a2f7-31cac88cffde --- source/src/command.cpp | 239 ++++++++++++++++++++++++++++++----------- source/src/command.h | 30 ++++-- source/src/menus.cpp | 33 +++--- source/src/protos.h | 8 +- 4 files changed, 227 insertions(+), 83 deletions(-) diff --git a/source/src/command.cpp b/source/src/command.cpp index 2711645e..b2981052 100644 --- a/source/src/command.cpp +++ b/source/src/command.cpp @@ -12,6 +12,67 @@ hashtable *idents = NULL; // contains ALL vars/comma bool persistidents = true; +void clearstack(ident &id) +{ + identstack *stack = id.stack; + while(stack) + { + delete[] stack->action; + identstack *tmp = stack; + stack = stack->next; + delete tmp; + } + id.stack = NULL; +} + +void pushident(ident &id, char *val) +{ + if(id.type != ID_ALIAS) return; + identstack *stack = new identstack; + stack->action = id.executing==id.action ? newstring(id.action) : id.action; + stack->context = id.context; + stack->next = id.stack; + id.stack = stack; + id.action = val; + id.context = execcontext; +} + +void popident(ident &id) +{ + if(id.type != ID_ALIAS || !id.stack) return; + if(id.action != id.executing) delete[] id.action; + identstack *stack = id.stack; + id.action = stack->action; + id.stack = stack->next; + id.context = stack->context; + delete stack; +} + +void pusha(const char *name, char *action) +{ + ident *id = idents->access(name); + if(!id) + { + ident init(ID_ALIAS, newstring(name), newstring(""), persistidents, IEXC_CORE); + id = idents->access(init.name, &init); + } + pushident(*id, action); +} + +void push(const char *name, const char *action) +{ + pusha(name, newstring(action)); +} + +void pop(const char *name) +{ + ident *id = idents->access(name); + if(id) popident(*id); +} + +COMMAND(push, ARG_2STR); +COMMAND(pop, ARG_1STR); + void alias(const char *name, const char *action) { ident *b = idents->access(name); @@ -87,15 +148,24 @@ char *parseexp(const char *&p, int right) // parse any nested set of else if(!c) { p--; conoutf("missing \"%c\"", right); return NULL; } } char *s = newstring(word, p-word-1); - if(left=='(') - { - string t; - itoa(t, execute(s)); // evaluate () exps directly, and substitute result - s = exchangestr(s, t); - } + if(left=='(') s = exchangestr(s, executeret(s)); // evaluate () exps directly, and substitute result return s; } +char *lookup(char *n) // find value of ident referenced with $ in exp +{ + ident *id = idents->access(n+1); + if(id) switch(id->type) + { + case ID_VAR: { string t; itoa(t, *id->storage.i); return exchangestr(n, t); } + case ID_FVAR: { s_sprintfd(t)("%f", *id->storage.f); return exchangestr(n, t); } + case ID_SVAR: return exchangestr(n, *id->storage.s); + case ID_ALIAS: return exchangestr(n, id->action); + } + conoutf("unknown alias lookup: %s", n+1); + return n; +} + char *parseword(const char *&p) // parse single argument, including expressions { p += strspn(p, " \t\r"); @@ -114,28 +184,44 @@ char *parseword(const char *&p) // parse single argument, const char *word = p; p += strcspn(p, "; \t\r\n\0"); if(p-word==0) return NULL; - return newstring(word, p-word); + char *s = newstring(word, p-word); + if(*s=='$') return lookup(s); + return s; } -char *lookup(char *n) // find value of ident referenced with $ in exp +char *conc(char **w, int n, bool space) { - ident *id = idents->access(n+1); - if(id) switch(id->type) + int len = space ? max(n-1, 0) : 0; + loopj(n) len += (int)strlen(w[j]); + char *r = newstring("", len); + loopi(n) { - case ID_VAR: { string t; itoa(t, *id->storage.i); return exchangestr(n, t); } - case ID_FVAR: { s_sprintfd(t)("%f", *id->storage.f); return exchangestr(n, t); } - case ID_SVAR: return exchangestr(n, *id->storage.s); - case ID_ALIAS: return exchangestr(n, id->action); + strcat(r, w[i]); // make string-list out of all arguments + if(i==n-1) break; + if(space) strcat(r, " "); } - conoutf("unknown alias lookup: %s", n+1); - return n; + return r; } -int execute(const char *p) // all evaluation happens here, recursively +VARN(numargs, _numargs, 0, 0, 25); + +char *commandret = NULL; + +void intret(int v) +{ + string t; + itoa(t, v); + commandret = newstring(t); +} + +void result(const char *s) { commandret = newstring(s); } + +char *executeret(const char *p) // all evaluation happens here, recursively { const int MAXWORDS = 25; // limit, remove char *w[MAXWORDS]; - int val = 0; + char *retval = NULL; + #define setretval(v) { char *rv = v; if(rv) retval = rv; commandret = NULL; } for(bool cont = true; cont;) // for each ; seperated statement { int numargs = MAXWORDS; @@ -144,9 +230,8 @@ int execute(const char *p) // all evaluation happens w[i] = (char *)""; if(i>numargs) continue; char *s = parseword(p); // parse and evaluate exps - if(!s) { numargs = i; s = (char *)""; } - if(*s=='$') s = lookup(s); // substitute variables - w[i] = s; + if(s) w[i] = s; + else numargs = i; } p += strcspn(p, ";\n\0"); @@ -154,12 +239,14 @@ int execute(const char *p) // all evaluation happens char *c = w[0]; if(*c=='/') c++; // strip irc-style command prefix if(!*c) continue; // empty statement - + + DELETEA(retval); + ident *id = idents->access(c); if(!id) { - val = ATOI(c); - if(!val && *c!='0') conoutf("unknown command: %s", c); + if(!isdigit(*c)) conoutf("unknown command: %s", c); + setretval(newstring(c)); } else { @@ -188,26 +275,20 @@ int execute(const char *p) // all evaluation happens case ARG_7STR: ((void (__cdecl *)(char *, char *, char*, char*, char*, char*, char*))id->fun)(w[1], w[2], w[3], w[4], w[5], w[6], w[7]); break; case ARG_8STR: ((void (__cdecl *)(char *, char *, char*, char*, char*, char*, char*, char*))id->fun)(w[1], w[2], w[3], w[4], w[5], w[6], w[7], w[8]); break; case ARG_DOWN: ((void (__cdecl *)(bool))id->fun)(addreleaseaction(id->name)!=NULL); break; - case ARG_1EXP: val = ((int (__cdecl *)(int))id->fun)(execute(w[1])); break; - case ARG_2EXP: val = ((int (__cdecl *)(int, int))id->fun)(execute(w[1]), execute(w[2])); break; - case ARG_1EST: val = ((int (__cdecl *)(char *))id->fun)(w[1]); break; - case ARG_2EST: val = ((int (__cdecl *)(char *, char *))id->fun)(w[1], w[2]); break; + case ARG_1EXP: intret(((int (__cdecl *)(int))id->fun)(execute(w[1]))); break; + case ARG_2EXP: intret(((int (__cdecl *)(int, int))id->fun)(execute(w[1]), execute(w[2]))); break; + case ARG_1EST: intret(((int (__cdecl *)(char *))id->fun)(w[1])); break; + case ARG_2EST: intret(((int (__cdecl *)(char *, char *))id->fun)(w[1], w[2])); break; case ARG_VARI: + case ARG_VARIW: { - int len = max(numargs-2, 0); - for(int i = 1; inarg==ARG_VARI); ((void (__cdecl *)(char *))id->fun)(r); delete[] r; break; } } + setretval(commandret); break; case ID_VAR: // game defined variables @@ -245,22 +326,43 @@ int execute(const char *p) // all evaluation happens break; case ID_ALIAS: // alias, also used as functions and (global) variables + static vector argids; for(int i = 1; i argids.length()) + { + s_sprintfd(argname)("arg%d", i); + ident *id = idents->access(argname); + if(!id) + { + ident init(ID_ALIAS, newstring(argname), newstring(""), persistidents, IEXC_CORE); + id = idents->access(init.name, &init); + } + argids.add(id); + } + pushident(*argids[i-1], w[i]); // set any arguments as (global) arg values so functions can access them } + _numargs = numargs-1; char *wasexecuting = id->executing; id->executing = id->action; - val = execute(id->action); + setretval(executeret(id->action)); if(id->executing!=id->action && id->executing!=wasexecuting) delete[] id->executing; id->executing = wasexecuting; - break; + for(int i = 1; i &elems) { - for(char *a = s, *b = s; (*a = *b); b++) if(*a!=' ') a++; - concat(s); + whitespaceskip; + while(*s) + { + const char *elem = s; + elementskip; + elems.add(*elem=='"' ? newstring(elem+1, s-elem-(s[-1]=='"' ? 2 : 1)) : newstring(elem, s-elem)); + whitespaceskip; + } } -int listlen(char *a) +char *indexlist(const char *s, int pos) +{ + whitespaceskip; + loopi(pos) elementskip, whitespaceskip; + const char *e = s; + elementskip; + if(*e=='"') + { + e++; + if(s[-1]=='"') --s; + } + return newstring(e, s-e); +} + +void listlen(char *s) { - if(!*a) return 0; int n = 0; - while(*a) if(*a++==' ') n++; - return n+1; + whitespaceskip; + for(; *s; n++) elementskip, whitespaceskip; + intret(n); } void at(char *s, char *pos) { - int n = atoi(pos); - loopi(n) - { - s += strcspn(s, " \0"); - s += strspn(s, " "); - } - s[strcspn(s, " \0")] = 0; - concat(s); + commandret = indexlist(s, ATOI(pos)); } COMMANDN(loop, loopa, ARG_2STR); @@ -350,7 +469,7 @@ COMMANDN(while, whilea, ARG_2STR); COMMANDN(if, ifthen, ARG_3STR); COMMAND(exec, ARG_1STR); COMMAND(concat, ARG_VARI); -COMMAND(concatword, ARG_VARI); +COMMAND(concatword, ARG_VARIW); COMMAND(at, ARG_2STR); COMMAND(listlen, ARG_1EST); diff --git a/source/src/command.h b/source/src/command.h index f0330726..b5b83127 100644 --- a/source/src/command.h +++ b/source/src/command.h @@ -1,5 +1,12 @@ enum { ID_VAR, ID_FVAR, ID_SVAR, ID_COMMAND, ID_ALIAS }; +struct identstack +{ + char *action; + int context; + identstack *next; +}; + struct ident { int type; // one of ID_* above @@ -9,9 +16,13 @@ struct ident { int *i; // ID_VAR float *f; // ID_FVAR - char **s; // ID_SVAR; + char **s; // ID_SVAR; } storage; - void (*fun)(); // ID_VAR, ID_COMMAND + union + { + void (*fun)(); // ID_VAR, ID_COMMAND + identstack *stack; // ID_ALIAS + }; int narg; // ID_VAR, ID_COMMAND char *action, *executing; // ID_ALIAS bool persist; @@ -22,31 +33,31 @@ struct ident // ID_VAR ident(int type, const char *name, int min, int max, int *i, void (*fun)(), bool persist, int context) : type(type), name(name), min(min), max(max), fun(fun), - narg(0), action(0), executing(0), persist(persist), context(context) + narg(0), action(NULL), executing(NULL), persist(persist), context(context) { storage.i = i; } // ID_FVAR ident(int type, const char *name, float *f, void (*fun)(), bool persist, int context) : type(type), name(name), min(0), max(0), fun(fun), - narg(0), action(0), executing(0), persist(persist), context(context) + narg(0), action(NULL), executing(NULL), persist(persist), context(context) { storage.f = f; } // ID_SVAR ident(int type, const char *name, char **s, void (*fun)(), bool persist, int context) : type(type), name(name), min(0), max(0), fun(fun), - narg(0), action(0), executing(0), persist(persist), context(context) + narg(0), action(NULL), executing(NULL), persist(persist), context(context) { storage.s = s; } // ID_ALIAS ident(int type, const char *name, char *action, bool persist, int context) - : type(type), name(name), min(0), max(0), fun(0), - narg(0), action(action), executing(0), persist(persist), context(context) + : type(type), name(name), min(0), max(0), stack(0), + narg(0), action(action), executing(NULL), persist(persist), context(context) { storage.i = NULL; } // ID_COMMAND ident(int type, const char *name, void (*fun)(), int narg, int context) : type(type), name(name), min(0), max(0), fun(fun), - narg(narg), action(0), executing(0), persist(false), context(context) + narg(narg), action(NULL), executing(NULL), persist(false), context(context) { storage.i = NULL; } }; @@ -58,7 +69,7 @@ enum // function signatures for script functions, see command.cpp ARG_DOWN, ARG_1EXP, ARG_2EXP, ARG_1EST, ARG_2EST, - ARG_VARI + ARG_VARI, ARG_VARIW }; enum { IEXC_CORE = 0, IEXC_FOREIGN, IEXC_NUM }; // script execution context @@ -69,6 +80,7 @@ enum { IEXC_CORE = 0, IEXC_FOREIGN, IEXC_NUM }; // script execution context #define VARP(name, min, cur, max) int name = variable(#name, min, cur, max, &name, NULL, true) #define VAR(name, min, cur, max) int name = variable(#name, min, cur, max, &name, NULL, false) +#define VARN(name, global, min, cur, max) int global = variable(#name, min, cur, max, &global, NULL, false) #define VARF(name, min, cur, max, body) void var_##name(); int name = variable(#name, min, cur, max, &name, var_##name, false); void var_##name() { body; } #define VARFP(name, min, cur, max, body) void var_##name(); int name = variable(#name, min, cur, max, &name, var_##name, true); void var_##name() { body; } diff --git a/source/src/menus.cpp b/source/src/menus.cpp index c9cf753a..a2912565 100644 --- a/source/src/menus.cpp +++ b/source/src/menus.cpp @@ -137,8 +137,9 @@ struct mitemtext : mitem { menustack.add(curmenu); menuset(NULL); - alias("arg1", text); + push("arg1", text); execute(action); + pop("arg1"); } } }; @@ -178,9 +179,11 @@ struct mitemtextinput : mitemtext if(!strlen(input.buf)) setdefaultvalue(); if(action) { - alias("arg1", on ? "1" : "0"); - alias("arg2", input.buf); + push("arg1", on ? "1" : "0"); + push("arg2", input.buf); execute(action); + pop("arg2"); + pop("arg1"); } } @@ -226,10 +229,13 @@ struct mitemslider : mitem { if(action) { - alias("arg1", on ? "1" : "0"); - alias("arg2", "0"); + push("arg1", on ? "1" : "0"); + push("arg2", "0"); setvaluealias(); execute(action); + pop("arg3"); + pop("arg2"); + pop("arg1"); } } @@ -248,11 +254,9 @@ struct mitemslider : mitem string v; if(display) // extract display name from list { - string disp, val; - s_strcpy(disp, display); - itoa(val, cval); - at(disp, val); // pass to script 'at' cmd - s_strcpy(v, getalias("s")); // grab result + char *val = indexlist(display, cval); + s_strcpy(v, val); + delete[] val; } else itoa(v, value); int vw = text_width(v); @@ -284,10 +288,13 @@ struct mitemslider : mitem { value += right ? step : -step; value = min(max_, max(min_, value)); - alias("arg1", "-1"); - alias("arg2", right ? "1" : "-1"); + push("arg1", "-1"); + push("arg2", right ? "1" : "-1"); setvaluealias(); execute(action); + pop("arg3"); + pop("arg2"); + pop("arg1"); } } @@ -295,7 +302,7 @@ struct mitemslider : mitem { string v; itoa(v, value); - alias("arg3", v); + push("arg3", v); } }; diff --git a/source/src/protos.h b/source/src/protos.h index 08014bac..6a6c5361 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -27,16 +27,22 @@ extern int getvar(const char *name); extern bool identexists(const char *name); extern bool addcommand(const char *name, void (*fun)(), int narg); extern int execute(const char *p); +extern char *executeret(const char *p); +extern void intret(int v); +extern void result(const char *s); extern void exec(const char *cfgfile); extern bool execfile(const char *cfgfile); extern void resetcomplete(); extern void complete(char *s); +extern void push(const char *name, const char *action); +extern void pop(const char *name); extern void alias(const char *name, const char *action); extern const char *getalias(const char *name); extern void writecfg(); extern void identnames(vector &names, bool builtinonly); extern void changescriptcontext(int newcontext); -extern void at(char *s, char *pos); +extern void explodelist(const char *s, vector &elems); +extern char *indexlist(const char *s, int pos); extern char *parseword(const char *&p); // console