21 #include <ccscript-config.h>
22 #include <ucommon/ucommon.h>
23 #include <ucommon/export.h>
31 #define NUM_FORMAT "%ld"
47 unsigned tempcount =
sizeof(temps) /
sizeof(
char *);
59 while(pos < tempcount)
72 fprintf(stderr,
"*** %s(%d): %s\n", image->filename, stack[frame].line->
lnum, msg);
76 String::set(errmsg, 65, msg);
78 if(!eq(stack[frame].scr->name,
"_init_")) {
79 if(scriptEvent(
"error"))
89 unsigned tempcount =
sizeof(temps) /
sizeof(
char *);
91 char *ptr = temps[tempindex++];
92 if(tempindex >= tempcount)
105 static char null[1] = {0};
107 size_t dcount = 0, pos;
120 if(eq(
id,
"len:", 4))
122 else if(eq(
id,
"key:", 4)) {
124 ep = strchr(tp,
'=');
128 String::set(tp, 2,
"-");
130 else if(eq(
id,
"tail:", 5)) {
137 else if(eq(
id,
"head:", 5)) {
145 else if(eq(
id,
"pull:", 5) || eq(
id,
"<<:", 3)) {
150 memcpy(sym->
data, sym->
data + dcount, strlen(sym->
data + dcount) + 1);
155 else if(eq(
id,
"pop:", 4) || eq(
id,
">>:", 3)) {
161 sym->
data[--dcount] = 0;
169 else if(eq(
id,
"val:", 4) && (*cp ==
'\'' || *cp ==
'\"' || *cp ==
'(')) {
172 ep = strrchr(tp,
')');
174 ep = strchr(tp, *cp);
178 else if(eq(
id,
"val:", 4) && strchr(sym->
data,
'=')) {
179 cp = strchr(sym->
data,
'=') + 1;
180 if(*cp ==
'\"' || *cp ==
'\'') {
182 ep = strchr(tp, *cp);
188 ep = strchr(tp,
',');
193 else if(eq(
id,
"unquote:", 8) && sym->
size) {
199 ep = strrchr(cp,
')');
203 else if(*cp ==
'\"' || *cp ==
'\'') {
204 ep = strchr(cp + 1, *cp);
209 String::set(sym->
data, sym->
size + 1, cp);
212 else if(eq(
id,
"upper:", 6) && sym->
size) {
213 String::upper(sym->
data);
216 else if(eq(
id,
"lower:", 6) && sym->
size) {
217 String::lower(sym->
data);
220 else if((eq(
id,
"inc:", 4) || eq(
id,
"++:", 3)) && sym->
size) {
225 else if(eq(
id,
"count:", 6))
227 else if(eq(
id,
"index/", 6)) {
234 if(pos < strlen(sym->
data))
235 cp = sym->
data + pos;
240 else if(eq(
id,
"offset/", 7)) {
251 else if((eq(
id,
"dec:", 4) || eq(
id,
"--:", 3)) && sym->
size) {
256 else if(eq(
id,
"size:", 5))
258 else if(eq(
id,
"val:", 4) || eq(
id,
"int:", 4)) {
262 else if(eq(
id,
"num:", 4)) {
268 cp = strchr(sym->
data,
'.');
274 if(*cp && isdigit(*cp))
281 else if(eq(
id,
"map/", 4)) {
283 String::set(idbuf,
sizeof(idbuf),
id + 4);
284 ep = strchr(idbuf,
':');
288 if(!index || !index->
data[0])
290 pos = atoi(sym->
data);
293 snprintf(idbuf,
sizeof(idbuf),
",%s", sym->
data);
297 else if(eq(
id,
"find/", 5)) {
302 while(dcount < 30 && *
id && *
id !=
':')
303 idbuf[dcount++] = *(
id++);
304 idbuf[dcount++] =
'=';
309 if(!strncmp(cp, idbuf + 1, len - 1))
310 cp = sym->
data + len - 1;
311 else if(NULL != (cp = strstr(sym->
data, idbuf)))
320 else if(*cp ==
'(') {
327 if(*cp ==
'(' && paren)
329 if(*cp ==
')' && paren) {
333 if(*cp ==
'=' && quote ==
',' && cp[1] ==
'\"') {
334 tp[dcount++] = *(cp++);
338 tp[dcount++] = *(cp++);
342 else if(eq(
id,
"bool:", 5)) {
343 if(atoi(sym->
data) > 0 || tolower(sym->
data[0]) ==
't' || tolower(sym->
data[0] ==
'y'))
363 id = strchr(cp,
':');
369 return getFormat(sym, ++cp, tp);
382 if(cp[1] && cp[1] !=
'=')
394 while(index < line->argc) {
395 cp = line->
argv[index++];
398 return getContent(line->
argv[index]);
409 unsigned pos = frame;
411 method = stack[--pos].line->
method;
413 char *temp = getTemp();
426 return stack[frame - 1].line->
method;
433 while(stack[frame].index < line->argc) {
434 cp = line->
argv[stack[frame].index++];
437 ++stack[frame].index;
450 while(stack[frame].index < line->argc) {
451 cp = line->
argv[stack[frame].index++];
454 ++stack[frame].index;
457 return getContent(cp);
466 linked_pointer<Script::symbol> sp;
469 if(*
id ==
'=' || *
id ==
'%')
479 if(eq(sp->name,
id) && sp->scope == stack[frame].scope)
487 var->
scope = stack[frame].scope;
489 var->
data = dup(value);
490 var->enlist(&syms[path]);
497 linked_pointer<Script::symbol> sp;
502 if(*
id ==
'=' || *
id ==
'%')
508 if(strchr(
id,
':')) {
509 char *temp = getTemp();
512 cp = strchr(temp,
':');
527 if(eq(sp->name,
id) && sp->scope == NULL)
529 if(eq(sp->name,
id) && sp->scope == stack[frame].scope)
544 var->
data = (
char *)alloc(size + 1);
545 var->enlist(&syms[path]);
556 if(eq(type_id,
"int"))
559 if(eq(type_id,
"num"))
562 if(eq(type_id,
"bool"))
573 if(eq(type_id,
"int") || eq(type_id,
"num"))
576 if(eq(type_id,
"bool"))
591 while(index < line->argc) {
592 cp = line->
argv[index++];
595 cp = line->
argv[index++];
598 snprintf(pbuf,
sizeof(pbuf),
"%d", ++param);
601 if(eq(cp,
"required") || eq(cp,
"optional"))
602 setRef(scope,
id, const_cast<char *>(
""), 0);
603 else if(*cp ==
'%') {
606 setRef(scope,
id, sym->
data, sym->
size);
610 setRef(scope,
id, const_cast<char *>(
""), 0);
615 setRef(scope,
id, const_cast<char *>(cp), 0);
623 linked_pointer<Script::symbol> sp;
626 if(*
id ==
'=' || *
id ==
'%')
636 if(eq(sp->name,
id) && sp->scope == scope) {
649 var->enlist(&syms[path]);
659 linked_pointer<Script::symbol> sp;
664 if(*
id ==
'=' || *
id ==
'%')
670 if(strchr(
id,
':')) {
671 char *temp = getTemp();
674 cp = strchr(temp,
':');
678 size = getTypesize(cp);
680 value = getTypeinit(cp);
693 if(eq(sp->name,
id) && sp->scope == stack[frame].scope) {
705 var->
scope = stack[frame].scope;
707 var->
data = (
char *)alloc(size + 1);
708 var->enlist(&syms[path]);
718 String::set(var->
data, var->
size + 1, value);
727 linked_pointer<Script::symbol> sp = syms[path];
731 if(eq(sp->name,
id)) {
732 if(sp->scope == NULL)
734 else if(sp->scope == stack[frame].scope)
753 return stack[stack[frame].base].scr->file;
758 linked_pointer<Script::event> ep = scr->
events;
761 if(eq(ep->name,
"init")) {
763 stack[frame].event = *ep;
764 stack[frame].line = ep->first;
779 if(entry && *entry ==
'@')
788 setStack(img->
first);
790 while(frame && stack[frame].
line)
791 (this->*(stack[frame].line->
method))();
793 if(is(img->shared)) {
795 setStack(img->shared->first);
796 while(frame && stack[frame].line)
797 (this->*(stack[frame].line->
method))();
810 stack[frame].line = stack[frame].line->
next;
815 linked_pointer<Script::event> mp = stack[frame].scr->methods;
818 if(eq_case(mp->name, name))
827 assert(name != NULL);
829 linked_pointer<Script::event> ep;
831 const char *group = NULL;
832 unsigned stackp = frame;
845 while(ignore && pos < ignore->argc) {
848 if(group && eq_case(group, ignore->
argv[pos]))
852 if(eq_case(name, ignore->
argv[pos++]))
857 ep = stack[stackp].scr->events;
861 if(eq_case(ep->name, name))
864 if(group && eq_case(ep->name, group))
875 if(stack[stackp].
event == *ep)
881 setStack(stack[frame].scr, *ep);
886 if(eq_case(name,
"timeout"))
889 while(stackp > stack[stackp].base && stack[stackp].
line->
loop)
892 if(stackp && stackp >= stack[stackp].base)
901 stack[frame].scr = scr;
902 stack[frame].event = ev;
903 stack[frame].index = 0;
904 stack[frame].resmask = scr->
resmask;
905 stack[frame].ignore = NULL;
908 stack[frame].line = ev->
first;
910 stack[frame].line = scr->
first;
915 while(frame && stack[frame - 1].base == stack[frame].base)
921 while(frame && stack[frame - 1].scr == stack[frame].scr)
929 stack[frame - 1].line = stack[frame].line;
930 stack[frame - 1].index = 0;
937 if(!stack || !stack[frame].scr || (frame == 0 && !stack[frame].
line))
940 if(stack[frame].line)
941 return stack[frame].line->
mask | stack[frame].resmask;
943 return stack[frame].resmask;
960 if(!scriptEvent(
"stack")) {
962 stack[frame].line = NULL;
967 stack[frame + 1] = stack[frame];
977 if(!scr || !scr->
first || stack[stack[frame].base].scr == scr)
980 frame = stack[frame].base;
990 if(scriptEvent(
"exit"))
996 if(!ex || stack[frame].scr == ex)
1009 while(line && rtn && scount--) {
1010 rtn = (this->*(line->
method))();
1011 line = stack[frame].line;
1017 while(stack[frame].line == NULL && frame)
1020 if(!stack[frame].line && !tryexit())
1028 unsigned points = 0;
1031 if(eq(test,
"defined")) {
1046 if(eq(test,
"const")) {
1062 if(eq(test,
"modify")) {
1079 if(eq(test,
"empty")) {
1085 if(eq(test,
"integer")) {
1100 if(eq(test,
"digits")) {
1112 if(eq(test,
"number")) {
1144 while(index < line->argc) {
1145 rtn = getExpression(index);
1146 cp = line->
argv[index];
1147 if((*cp ==
'-' || *cp ==
'!') && isalpha(cp[1]))
1152 if(index >= line->
argc)
1155 cp = line->
argv[index++];
1157 if(eq(cp,
"?&&") || eq(cp,
"and")) {
1163 if(eq(cp,
"?||") || eq(cp,
"or")) {
1174 bool Script::interp::getExpression(
unsigned index)
1177 const char *v1 =
"", *v2 =
"", *op;
1178 const char *d1, *d2;
1180 char dec1[9], dec2[9];
1182 unsigned pos = 0, pcount;
1190 if(index < line->argc) {
1191 v1 = line->
argv[index++];
1192 if((*v1 ==
'-' || *v1 ==
'!') && isalpha(v1[1])) {
1193 if(index < line->argc)
1194 v2 = line->
argv[index++];
1198 return getCondition(++v1, v2);
1200 return !getCondition(++v1, v2);
1202 v1 = getContent(v1);
1207 if(index <= line->argc) {
1208 op = line->
argv[index++];
1217 if(index <= line->argc)
1218 v2 = getContent(line->
argv[index++]);
1220 d1 = strchr(v1,
'.');
1221 d2 = strchr(v2,
'.');
1226 snprintf(dec1,
sizeof(dec1),
NUM_FORMAT, (
long)dv);
1230 snprintf(dec2,
sizeof(dec2),
NUM_FORMAT, (
long)dv);
1233 unsigned c1 = strlen(dec1);
1234 unsigned c2 = strlen(dec2);
1241 dec1[8] = dec2[8] = 0;
1243 return ((atol(v1) == atol(v2)) && !strcmp(dec1, dec2));
1246 return ((atol(v1) != atol(v2)) || strcmp(dec1, dec2));
1249 return (*v1 && *v2);
1252 return (*v1 || *v2);
1255 if(strcmp(v1, v2) > 0)
1261 if(strcmp(v1, v2) < 0)
1267 if(strcmp(v1, v2) >= 0)
1273 if(strcmp(v1, v2) <= 0)
1278 if(eq(op,
"==") || eq(op,
"eq"))
1281 if(eq(op,
"!=") || eq(op,
"ne"))
1291 return (atol(v1) < atol(v2) || (atol(v1) == atol(v2) && dv1 < dv2));
1301 return (atoi(v1) < atoi(v2) || (atol(v1) == atol(v2) && dv1 <= dv2));
1311 return (atol(v1) > atol(v2) || (atol(v1) == atol(v2) && dv1 > dv2));
1321 return (atol(v1) > atol(v2) || (atol(v1) == atol(v2) && dv1 >= dv2));
1324 if(eq(op,
"?") || eq(op,
"in")) {
1330 while(pos < pcount) {
1332 if(op && eq(v1, op, len) && (op[len] ==
',' || op[len] == 0 || op[len] ==
'='))
1338 if(eq(op,
"!?") || eq(op,
"notin")) {
1344 while(pos < pcount) {
1346 if(op && eq(v1, op, len) && (op[len] ==
',' || op[len] == 0 || op[len] ==
'='))
1352 if(eq(op,
"!$") || eq(op,
"isnot"))
1353 return !eq_case(v2, v1);
1355 if(eq(op,
"$") || eq(op,
"is"))
1356 return eq_case(v2, v1);
1359 if(eq(op,
"~") || eq(op,
"!~")) {
1361 regex_t *regex =
new regex_t;
1362 memset(regex, 0,
sizeof(regex_t));
1364 if(regcomp(regex, v2, REG_ICASE|REG_NOSUB|REG_NEWLINE)) {
1370 if(regexec(regex, v1, 0, NULL, 0))
method_t getLooping(void)
const char * getIndex(void)
symbol * createSymbol(const char *id)
bool step(void)
Step through an instance of the interpreter.
virtual const char * getTypeinit(const char *type_id)
static unsigned stepping
default stepping increment
static unsigned indexing
default symbol indexing
virtual const char * getFormat(symbol *sym, const char *id, char *temp)
static const char * get(const char *list, unsigned offset)
static void copy(const char *list, char *item, unsigned size)
void setStack(header *scr, event *ev=NULL)
char * data
content of symbol
bool error(const char *text)
Invoke runtime interpreter error handling.
bool setConst(const char *id, const char *value)
bool scriptEvent(const char *name)
Try to branch to a named event handler.
event * scriptMethod(const char *name)
Search for an event object in the method table.
const char * name
name of symbol
const char * getContent(void)
Basic compiled statement.
static unsigned stacking
stack frames in script runtime
Contains instance of a runtime symbol.
virtual bool getCondition(const char *test, const char *value)
static unsigned count(const char *list)
static unsigned offset(const char *list, unsigned index)
symbol * getVar(const char *id, const char *value=NULL)
header * scope
scope of symbol definition
static unsigned decimals
default decimal places
static keyword_t * find(const char *id)
Find a keyword from internal command table.
bool(Script::interp::* method_t)(void)
A type for runtime script method invokation.
void initialize(void)
Used to initialize and purge the interpreter between runs.
Compiled script container.
unsigned getResource(void)
Get current dsp resource mask.
virtual unsigned getTypesize(const char *type_id)
void startScript(header *scr)
void detach(void)
Cleanup after interpreter run.
int main(int argc, char **argv)
An event block for a script.
void getParams(header *scope, line_t *line)
bool trylabel(const char *id)
unsigned size
size of data buffer or 0 if const
Runtime stack for each interpreter instance.
static unsigned sizing
default symbol size
const char * getValue(void)
bool attach(Script *image, const char *entry=NULL)
Attach a compiled image to the interpreter and start.
const char * getKeyword(const char *id)
void setRef(header *scope, const char *id, char *data, unsigned size)
const char * getFilename(void)
Get effective filename of base.
symbol * find(const char *id)
bool isConditional(unsigned index)