21 #include <ucommon/ucommon.h>
22 #include <ucommon/export.h>
27 using namespace UCOMMON_NAMESPACE;
29 static Script::keyword_t *keywords = NULL;
31 size_t Script::paging = 0;
32 unsigned Script::sizing = 64;
33 unsigned Script::indexing = 77;
34 unsigned Script::stacking = 20;
35 unsigned Script::stepping = 7;
36 unsigned Script::decimals = 2;
38 static bool ideq(
const char *id1,
const char *id2)
48 while(id1[count] && id1[count] !=
':') {
49 if(id2[count] != id1[count])
53 if(id2[count] && id2[count] !=
':')
58 static bool iskeyword(
const char *str)
67 if(!isalpha(*str) && *str !=
'.')
74 static bool isend(
const char *str)
79 if(!strncmp(
"%%", str, 2))
82 if(!strncmp(
"//", str, 2))
88 static bool preparse(
char **tokens)
90 if(!tokens || !*tokens)
93 while(*tokens && isspace(**tokens))
104 if(isspace(str[1]) || (str[1] ==
'=' && isspace(str[2]))) {
112 if(isspace(str[1])) {
120 if(eq(str,
">>%", 3)) {
127 if(isspace(str[1]) || (str[1] ==
'=' && isspace(str[2]))) {
134 if(isspace(str[1])) {
141 if(isspace(str[1])) {
148 if(eq(str,
"<<%", 3)) {
155 if(isspace(str[1]) || (str[1] ==
'=' && isspace(str[2])) || (str[1] ==
'>' && isspace(str[2]))) {
162 if(str[1] ==
'=' && isspace(str[2])) {
167 else if(str[1] ==
'?' && isspace(str[2])) {
172 else if(str[1] ==
'$' && isspace(str[2])) {
177 else if(str[1] ==
'~' && isspace(str[2])) {
186 if(str[1] ==
'&' && isspace(str[2])) {
191 else if(isalnum(str[1])) {
197 if(str[1] ==
'|' && isspace(str[2])) {
207 if(str[1] ==
'=' && isspace(str[2]))
211 if(str[1] ==
'=' && isspace(str[2]))
223 if(eq(str,
"++%", 3)) {
230 if(isdigit(str[1]) || str[1] ==
'.') {
236 if(str[1] ==
'=' && isspace(str[2]))
244 if(eq(str,
"--%", 3)) {
251 if(isalnum(str[1]) || str[1] ==
'.')
255 if(str[1] ==
'=' && isspace(str[2]))
268 while(*str && (isalnum(*str) || *str ==
':' || *str ==
'.'))
282 Script::error::error(Script *img,
unsigned line,
const char *msg) :
283 OrderedObject(&img->errlist)
285 errmsg = img->dup(msg);
290 CountedObject(), memalloc()
299 scripts = (LinkedObject **)alloc(
sizeof(LinkedObject **) * Script::indexing);
300 memset(scripts, 0,
sizeof(LinkedObject **) * Script::indexing);
310 void Script::errlog(
unsigned line,
const char *fmt, ...)
316 vsnprintf(text,
sizeof(text), fmt, args);
319 caddr_t mp = (caddr_t)alloc(
sizeof(Script::error));
320 new(mp) Script::error(
this, line, text);
324 void Script::assign(Script::keyword_t *keyword)
326 while(keyword && keyword->name) {
327 keyword->next = keywords;
333 Script::keyword_t *Script::find(
const char *cmd)
335 keyword_t *keyword = keywords;
337 while(keyword != NULL) {
338 if(eq(cmd, keyword->name))
340 keyword = keyword->next;
345 void Script::init(
void)
347 static keyword_t keywords[] = {
348 {
"pause", (method_t)&methods::scrPause, (check_t)&checks::chkNop},
349 {
"nop", (method_t)&methods::scrNop, (check_t)&checks::chkNop},
350 {
"exit", (method_t)&methods::scrExit, (check_t)&checks::chkExit},
351 {
"return", (method_t)&methods::scrReturn, (check_t)&checks::chkExit},
352 {
"restart", (method_t)&methods::scrRestart, (check_t)&checks::chkExit},
353 {
"goto", (method_t)&methods::scrGoto, (check_t)&checks::chkGoto},
354 {
"gosub", (method_t)&methods::scrGosub, (check_t)&checks::chkGosub},
355 {
"var", (method_t)&methods::scrVar, (check_t)&checks::chkVar},
356 {
"const", (method_t)&methods::scrConst, (check_t)&checks::chkConst},
357 {
"error", (method_t)&methods::scrError, (check_t)&checks::chkError},
358 {
"clear", (method_t)&methods::scrClear, (check_t)&checks::chkClear},
359 {
"push", (method_t)&methods::scrPush, (check_t)&checks::chkPush},
360 {
"set", (method_t)&methods::scrSet, (check_t)&checks::chkSet},
361 {
"add", (method_t)&methods::scrAdd, (check_t)&checks::chkSet},
362 {
"pack", (method_t)&methods::scrPack, (check_t)&checks::chkPack},
363 {
"expand", (method_t)&methods::scrExpand, (check_t)&checks::chkExpand},
364 {
"do", (method_t)&methods::scrDo, (check_t)&checks::chkDo},
365 {
"until", (method_t)&methods::scrUntil, (check_t)&checks::chkUntil},
366 {
"break", (method_t)&methods::scrBreak, (check_t)&checks::chkBreak},
367 {
"continue", (method_t)&methods::scrContinue, (check_t)&checks::chkContinue},
368 {
"previous", (method_t)&methods::scrPrevious, (check_t)&checks::chkPrevious},
369 {
"repeat", (method_t)&methods::scrRepeat, (check_t)&checks::chkPrevious},
370 {
"index", (method_t)&methods::scrIndex, (check_t)&checks::chkIndex},
371 {
"loop", (method_t)&methods::scrLoop, (check_t)&checks::chkLoop},
372 {
"while", (method_t)&methods::scrWhile, (check_t)&checks::chkWhile},
373 {
"for", (method_t)&methods::scrForeach, (check_t)&checks::chkForeach},
374 {
"foreach", (method_t)&methods::scrForeach, (check_t)&checks::chkForeach},
375 {
"case", (method_t)&methods::scrCase, (check_t)&checks::chkCase},
376 {
"otherwise", (method_t)&methods::scrOtherwise, (check_t)&checks::chkOtherwise},
377 {
"endcase", (method_t)&methods::scrEndcase, (check_t)&checks::chkEndcase},
378 {
"if", (method_t)&methods::scrIf, (check_t)&checks::chkIf},
379 {
"elif", (method_t)&methods::scrElif, (check_t)&checks::chkElif},
380 {
"else", (method_t)&methods::scrElse, (check_t)&checks::chkElse},
381 {
"endif", (method_t)&methods::scrEndif, (check_t)&checks::chkEndif},
382 {
"expr", (method_t)&methods::scrExpr, (check_t)&checks::chkExpr},
383 {
"strict", (method_t)NULL, (check_t)&checks::chkStrict},
384 {
"apply", (method_t)NULL, (check_t)&checks::chkApply},
385 {
"_ifthen", (method_t)&methods::scrWhen, (check_t)&checks::chkWhen},
386 {
"_define", (method_t)&methods::scrDefine, (check_t)&checks::chkDefine},
387 {
"_invoke", (method_t)&methods::scrInvoke, (check_t)&checks::chkInvoke},
388 {
"_ref", (method_t)&methods::scrRef, (check_t)&checks::chkRef},
392 static bool initial =
false;
400 Script::header *Script::find(Script *img,
const char *
id)
402 unsigned path = NamedObject::keyindex(
id, Script::indexing);
403 linked_pointer<header> hp = img->scripts[path];
414 Script *Script::merge(
const char *fn, Script *root)
416 Script *img = compile(fn, root);
420 return merge(img, root);
423 Script *Script::merge(Script *img, Script *root)
425 assert(img != NULL && root != NULL);
427 for(
unsigned index = 0; index < Script::indexing; ++index) {
428 header *prior = NULL;
429 linked_pointer<header> hp = img->scripts[index];
435 prior->link(static_cast<header *>(root->scripts[index]));
437 img->scripts[index] = root->scripts[index];
443 Script *Script::compile(
const char *fn, Script *cfg)
445 return Script::append(NULL, fn, cfg);
448 Script *Script::append(Script *merge,
const char *fn, Script *cfg)
452 char **argv =
new char *[256];
453 stringbuf<512> buffer;
455 charfile cf(fn,
"r");
457 const char *name =
"_init_";
458 Script::event *current;
459 Script::event *prior;
461 const char *token = NULL;
465 bool section =
false;
467 const char *err, *op;
470 bool indented, formed;
471 Script::header *invoke;
477 bool requires =
false;
493 img->stack =
new line_t*[Script::stacking];
496 img->filename = strrchr(fn,
'/');
498 img->filename = strrchr(fn,
'\\');
500 img->filename = strrchr(fn,
':');
511 scr = (header *)img->alloc(
sizeof(header));
512 memset(scr, 0,
sizeof(header));
513 scr->name = img->dup(name);
523 if(!eq(name,
"_init_") || !merge) {
524 path = NamedObject::keyindex(name, Script::indexing);
525 scr->enlist(&img->scripts[path]);
531 while(when || label || define || cf.readline(buffer)) {
546 token = String::token(NULL, &tokens,
" \t",
"{}\'\'\"\"");
553 img->thencheck =
false;
556 tokens = buffer.c_mem();
557 if(isspace(*tokens)) {
558 while(isspace(*tokens))
561 if(!preparse(&tokens)) {
562 img->errlog(lnum,
"malformed line");
567 String::trim(buffer,
" \t\r\n");
574 token = String::token(buffer.c_mem(), &tokens,
" \t",
"{}\'\'\"\"");
576 if(eq(token,
"endreq") || eq(token,
"endrequires")) {
578 img->errlog(lnum,
"endreq cannot be indented");
584 else if(eq(token,
"requires")) {
586 img->errlog(lnum,
"requires cannot be indented");
590 while(NULL != (token = String::token(NULL, &tokens,
" \t",
"{}\'\'\"\""))) {
596 keyword = find(token);
597 invoke = find(img, token);
598 if(!invoke && is(img->shared))
599 invoke = find(*(img->shared), token);
600 if(!rev && (keyword || invoke)) {
604 if(rev && !keyword && !invoke) {
615 if(*token ==
'^' || *token ==
'-') {
616 current = (
event *)img->alloc(
sizeof(Script::event));
621 memset(current, 0,
sizeof(event));
623 current->enlist(&scr->events);
625 current->enlist(&scr->methods);
626 current->name = (
char *)img->dup(++token);
627 current->first = NULL;
638 if(eq(token,
"template")) {
640 img->errlog(lnum,
"templates must be before named sections");
644 img->errlog(lnum,
"templates cannot be indented");
647 token = String::token(NULL, &tokens,
" \t",
"{}\'\'\"\"");
649 img->errlog(lnum,
"template must be named");
654 if(eq(token,
"define")) {
656 img->errlog(lnum,
"defines must be before named sections");
660 img->errlog(lnum,
"define cannot be indented");
663 token = String::token(NULL, &tokens,
" \t",
"{}\'\'\"\"");
664 keyword = find(token);
666 img->errlog(lnum,
"cannot redefine existing command");
674 img->errlog(lnum,
"unindented statement");
682 assigned = img->dup(token);
683 op = String::token(NULL, &tokens,
" \t",
"{}\'\'\"\"");
684 if(op && (eq(op,
":=") || eq(op,
"+=") || eq(op,
"-=") || eq(op,
"*=") || eq(op,
"/=") || eq(op,
"%=") || eq(op,
"#=")))
686 else if(op && (eq(op,
"=") || eq(op,
"==") || eq(op,
"$="))) {
690 else if(op && (eq(op,
".") || eq(op,
".="))) {
694 else if(op && (eq(op,
",") || eq(op,
",="))) {
699 img->errlog(lnum,
"invalid assignment");
703 else if(*token ==
'$') {
704 assigned = img->dup(token);
708 if(!iskeyword(token)) {
709 img->errlog(lnum,
"invalid keyword");
715 keyword = find(
"_define");
717 img->errlog(lnum,
"define unsupported");
722 keyword = find(token);
723 if(!keyword && NULL != (invoke = find(img, token)))
724 keyword = find(
"_invoke");
725 if(!keyword && is(img->shared) && NULL != (invoke = find(*(img->shared), token)))
726 keyword = find(
"_invoke");
729 img->errlog(lnum,
"unknown keyword \"%s\"", token);
735 token = img->dup(token);
737 line = (line_t *)img->alloc(
sizeof(line_t));
738 memset(line, 0,
sizeof(line_t));
746 line->loop = img->loop;
747 line->method = keyword->method;
754 argv[argc++] = assigned;
757 argv[argc++] = img->dup(op);
759 while(argc < 249 && formed) {
761 formed = preparse(&tokens);
764 arg = (
char *)String::token(NULL, &tokens,
" \t",
"{}\'\'\"\"");
769 if(eq(token,
"if")) {
774 if(eq(arg,
"then")) {
775 keyword = find(
"_ifthen");
776 line->method = keyword->method;
777 token = String::token(NULL, &tokens,
" \t",
"{}\'\'\"\"");
778 if(!token || !keyword || img->thencheck)
781 img->thencheck = when =
true;
786 ep = strchr(arg,
'<');
787 if(*arg ==
'%' && ep) {
788 len = strlen(arg) + 10;
790 temp = (
char *)img->alloc(len);
791 String::set(temp, len,
"$map/");
792 String::add(temp, len, ep);
793 ep = strchr(temp,
'>');
796 String::add(temp, len, ++arg);
802 ep = strchr(arg,
'[');
803 if(*arg ==
'%' && ep) {
804 len = strlen(arg) + 10;
806 temp = (
char *)img->alloc(len);
808 String::set(temp, len,
"$offset/");
810 String::set(temp, len,
"$find/");
811 String::add(temp, len, ep);
812 ep = strchr(temp,
']');
815 String::add(temp, len, ++arg);
821 ep = strchr(arg,
'(');
822 if(*arg ==
'%' && ep) {
823 len = strlen(arg) + 10;
825 temp = (
char *)img->alloc(len);
826 String::set(temp, len,
"$index/");
827 String::add(temp, len, ep);
828 ep = strchr(temp,
')');
831 String::add(temp, len, ++arg);
837 argv[argc++] = img->dup(arg);
842 img->errlog(lnum,
"malformed statement or argument");
848 line->argv = (
char **)img->alloc(
sizeof(
char *) * argc);
849 memcpy(line->argv, argv,
sizeof(
char *) * argc);
851 err = (*(keyword->check))(img, scr, line);
853 img->errlog(lnum,
"%s", err);
858 while(img->isStrict() && pos < line->argc) {
859 cp = line->argv[pos++];
860 if(!Script::strict::find(img, scr, cp))
861 img->errlog(lnum,
"undefined symbol reference %s\n", cp);
866 if(line->method == (method_t)NULL)
875 linked_pointer<event> ep = prior;
876 while(is(ep) && *ep != current) {
880 current->first = line;
890 line = img->stack[--img->loop];
891 img->errlog(line->lnum,
"%s never completed loop", line->cmd);
894 keyword = find(
"_close");
896 err = (*(keyword->check))(img, scr, scr->first);
898 img->errlog(lnum,
"%s", err);
922 bool Script::isEvent(header *scr,
const char *
id)
924 linked_pointer<event> ep = scr->events;
934 bool Script::push(line_t *line)
936 if(loop < stacking) {
937 stack[loop++] = line;
943 Script::method_t Script::pull(
void)
948 return stack[--loop]->method;
951 Script::method_t Script::looping(
void)
956 return stack[loop - 1]->method;
959 void Script::strict::createVar(Script* image, Script::header *scr,
const char *
id)
963 assert(image != NULL);
965 linked_pointer<Script::strict> sp;
968 if(*
id ==
'%' || *
id ==
'=' || *
id ==
'$')
974 if(*(scr->name) !=
'@') {
981 sym = (Script::strict *)image->zalloc(
sizeof(Script::strict));
982 sym->enlist(&scr->scoped);
992 sym = (Script::strict *)image->zalloc(
sizeof(Script::strict));
993 sym->enlist(&image->global);
997 void Script::strict::createSym(Script* image, Script::header *scr,
const char *
id)
1000 assert(scr != NULL);
1001 assert(image != NULL);
1003 linked_pointer<Script::strict> sp;
1004 Script::strict *sym;
1006 if(*
id ==
'%' || *
id ==
'=' || *
id ==
'$')
1009 if(scr && !image->global)
1012 if(*(scr->name) !=
'@') {
1015 if(ideq(sp->id,
id))
1022 if(ideq(sp->id,
id))
1026 sym = (Script::strict *)image->zalloc(
sizeof(Script::strict));
1027 sym->enlist(&image->global);
1031 void Script::strict::createAny(Script* image, Script::header *scr,
const char *
id)
1034 assert(scr != NULL);
1035 assert(image != NULL);
1037 linked_pointer<Script::strict> sp;
1038 Script::strict *sym;
1040 if(*
id ==
'%' || *
id ==
'=' || *
id ==
'$')
1043 if(scr && !image->global)
1046 if(*(scr->name) !=
'@') {
1049 if(ideq(sp->id,
id))
1056 if(ideq(sp->id,
id))
1060 sym = (Script::strict *)image->zalloc(
sizeof(Script::strict));
1061 if(*(scr->name) !=
'@')
1062 sym->enlist(&scr->scoped);
1064 sym->enlist(&image->global);
1068 void Script::strict::createGlobal(Script *image,
const char *
id)
1071 assert(image != NULL);
1073 linked_pointer<Script::strict> sp;
1074 Script::strict *sym;
1076 if(*
id ==
'%' || *
id ==
'=' || *
id ==
'$')
1081 if(ideq(sp->id,
id))
1085 sym = (Script::strict *)image->zalloc(
sizeof(Script::strict));
1086 sym->enlist(&image->global);
1090 bool Script::strict::find(Script* image, Script::header *scr,
const char *
id)
1093 assert(scr != NULL);
1094 assert(image != NULL);
1099 linked_pointer<Script::strict> sp;
1104 if(*
id !=
'%' && *
id !=
'$')
1107 if(eq(
id,
"$map/", 5)) {
1109 String::set(buf + 1,
sizeof(buf) - 1,
id + 5);
1110 ep = strchr(buf,
':');
1114 if(!find(image, scr, buf))
1119 cp = strchr(
id,
':');
1128 if(*(scr->name) !=
'@') {
1131 if(ideq(sp->id,
id))
1139 if(ideq(sp->id,
id))
1146 void Script::strict::put(FILE *fp,
const char *header)
1151 const char *pid = id;
1156 while(*pid && *pid !=
':')
1157 fputc(*(pid++), fp);
1161 unsigned Script::count(
const char *data)
1172 if(*data ==
',' && !quote && !paren)
1174 else if(*data == quote && !paren)
1176 else if(*data ==
'\"' && !paren)
1178 else if(*data ==
'(' && !quote)
1180 else if(*data ==
')' && !quote)
1187 void Script::copy(
const char *list,
char *item,
unsigned size)
1190 assert(item != NULL);
1196 bool leadparen =
false;
1198 if(!list || !*list || *list ==
',') {
1203 while(isspace(*list))
1212 if(*list ==
'\"' || *list ==
'\'') {
1218 while(--size && *list) {
1219 if(paren == 1 && leadparen && *list ==
')' && !quote)
1223 else if(*list ==
')')
1225 if(*list ==
',' && !quote && !paren)
1227 if(*list == quote && lead)
1229 if(*list == quote) {
1233 if(!quote && *list ==
'\"' && prev ==
'=' && !paren)
1236 *(item++) = *(list++);
1241 unsigned Script::offset(
const char *list,
unsigned index)
1243 const char *cp =
get(list, index);
1247 const char *Script::get(
const char *list,
unsigned index)
1258 while(*list && index) {
1259 if(*list ==
',' && !quote && !paren) {
1263 }
else if(*list == quote)
1265 else if(*list ==
'(' && !quote)
1267 else if(*list ==
')' && !quote)
1269 else if(*list ==
'\"' && !paren)
1276 char *Script::get(
char *list,
unsigned index)
1287 while(*list && index) {
1288 if(*list ==
',' && !quote && !paren) {
1292 }
else if(*list == quote)
1294 else if(*list ==
'(' && !quote)
1296 else if(*list ==
')' && !quote)
1298 else if(*list ==
'\"' && !paren)
#define BAYONNE_NAMESPACE
GNU Bayonne library namespace.