ccScript 5.1.0
 All Classes Namespaces Files Functions Variables Typedefs Friends Macros
script.cpp
Go to the documentation of this file.
1 // Copyright (C) 1995-1999 David Sugar, Tycho Softworks.
2 // Copyright (C) 1999-2005 Open Source Telecom Corp.
3 // Copyright (C) 2005-2014 David Sugar, Tycho Softworks.
4 // Copyright (C) 2015 Cherokees of Idaho.
5 //
6 // This file is part of GNU ccScript.
7 //
8 // GNU ccScript is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 3 of the License, or
11 // (at your option) any later version.
12 //
13 // GNU ccScript is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with GNU ccScript. If not, see <http://www.gnu.org/licenses/>.
20 
21 #include <ccscript-config.h>
22 #include <ucommon/ucommon.h>
23 #include <ucommon/export.h>
24 #include <ccscript.h>
25 #include <ctype.h>
26 #include <new>
27 #include <fstream>
28 
29 namespace ucommon {
30 
31 static Script::keyword_t *keywords = NULL;
32 static unsigned long icounter = 0;
33 
34 size_t Script::paging = 0; // default page size used...
35 unsigned Script::sizing = 64; // default symbol size is 64...
36 unsigned Script::indexing = 77; // hash size of symbol index
37 unsigned Script::stacking = 20; // max stack depth 20...
38 unsigned Script::stepping = 7; // automatic stepping...
39 unsigned Script::decimals = 2; // two decimal places...us default
40 
41 static bool ideq(const char *id1, const char *id2)
42 {
43  unsigned count = 0;
44 
45  if(!id1)
46  id1 = "";
47 
48  if(!id2)
49  id2 = "";
50 
51  while(id1[count] && id1[count] != ':') {
52  if(id2[count] != id1[count])
53  return false;
54  ++count;
55  }
56  if(id2[count] && id2[count] != ':')
57  return false;
58 
59  return true;
60 }
61 static bool iskeyword(const char *str)
62 {
63  if(!str || !*str)
64  return false;
65 
66  if(*str == '_')
67  ++str;
68 
69  while(*str) {
70  if(!isalpha(*str) && *str != '.')
71  return false;
72  ++str;
73  }
74  return true;
75 }
76 
77 static bool isend(const char *str)
78 {
79  if(!str || !*str)
80  return true;
81 
82  if(!strncmp("%%", str, 2))
83  return true;
84 
85  if(!strncmp("//", str, 2))
86  return true;
87 
88  return false;
89 }
90 
91 static bool preparse(char **tokens)
92 {
93  if(!tokens || !*tokens)
94  return true;
95 
96  while(*tokens && isspace(**tokens))
97  ++*tokens;
98 
99  char *str = *tokens;
100  if(isend(str)) {
101  *str = 0;
102  return true;
103  }
104 
105  switch(*str) {
106  case '=':
107  if(isspace(str[1]) || (str[1] == '=' && isspace(str[2]))) {
108  --*tokens;
109  **tokens = '?';
110  return true;
111  }
112  return false;
113 #ifdef HAVE_REGEX_H
114  case '~':
115  if(isspace(str[1])) {
116  --*tokens;
117  **tokens = '?';
118  return true;
119  }
120  return false;
121 #endif
122  case '>':
123  if(eq(str, ">>%", 3)) {
124  --*tokens;
125  --str;
126  str[0] = '$';
127  str[3] = ':';
128  return true;
129  }
130  if(isspace(str[1]) || (str[1] == '=' && isspace(str[2]))) {
131  --*tokens;
132  **tokens = '?';
133  return true;
134  }
135  return false;
136  case '$':
137  if(isspace(str[1])) {
138  --*tokens;
139  **tokens = '?';
140  return true;
141  }
142  break;
143  case '?':
144  if(isspace(str[1])) {
145  --*tokens;
146  **tokens = '?';
147  return true;
148  }
149  return false;
150  case '<':
151  if(eq(str, "<<%", 3)) {
152  --*tokens;
153  --str;
154  str[0] = '$';
155  str[3] = ':';
156  return true;
157  }
158  if(isspace(str[1]) || (str[1] == '=' && isspace(str[2])) || (str[1] == '>' && isspace(str[2]))) {
159  --*tokens;
160  **tokens = '?';
161  return true;
162  }
163  return false;
164  case '!':
165  if(str[1] == '=' && isspace(str[2])) {
166  --*tokens;
167  **tokens = '?';
168  return true;
169  }
170  else if(str[1] == '?' && isspace(str[2])) {
171  --*tokens;
172  **tokens = '?';
173  return true;
174  }
175  else if(str[1] == '$' && isspace(str[2])) {
176  --*tokens;
177  **tokens = '?';
178  return true;
179  }
180  else if(str[1] == '~' && isspace(str[2])) {
181  --*tokens;
182  **tokens = '?';
183  return true;
184  }
185  if(isalnum(str[1]))
186  break;
187  return false;
188  case '&':
189  if(str[1] == '&' && isspace(str[2])) {
190  --*tokens;
191  **tokens = '?';
192  return true;
193  }
194  else if(isalnum(str[1])) {
195  *str = '%';
196  break;
197  }
198  return false;
199  case '|':
200  if(str[1] == '|' && isspace(str[2])) {
201  --*tokens;
202  **tokens = '?';
203  return true;
204  }
205  return false;
206  case '/':
207  case '*':
208  if(isspace(str[1]))
209  break;
210  if(str[1] == '=' && isspace(str[2]))
211  break;
212  return false;
213  case ':':
214  if(str[1] == '=' && isspace(str[2]))
215  return true;
216  if(isalnum(str[1]))
217  break;
218  case ',':
219  case '`':
220  case '(':
221  case '[':
222  case ')':
223  case ']':
224  case ';':
225  case '_':
226  return false;
227  case '+':
228  if(eq(str, "++%", 3)) {
229  --*tokens;
230  --str;
231  str[0] = '$';
232  str[3] = ':';
233  return true;
234  }
235  if(isdigit(str[1]) || str[1] == '.') {
236  ++*tokens;
237  return true;
238  }
239  if(isspace(str[1]))
240  break;
241  if(str[1] == '=' && isspace(str[2]))
242  break;
243  return false;
244  case '.':
245  if(isdigit(str[1]))
246  break;
247  return false;
248  case '-':
249  if(eq(str, "--%", 3)) {
250  --*tokens;
251  --str;
252  str[0] = '$';
253  str[3] = ':';
254  return true;
255  }
256  if(isalnum(str[1]) || str[1] == '.')
257  return true;
258  if(isspace(str[1]))
259  break;
260  if(str[1] == '=' && isspace(str[2]))
261  break;
262  return false;
263  case '\'':
264  case '\"':
265  case '{':
266  --str;
267  --*tokens;
268  str[0] = str[1];
269  str[1] = '&';
270  return true;
271  }
272 
273  while(*str && (isalnum(*str) || *str == ':' || *str == '.'))
274  ++str;
275 
276  // we flip xxx=... into =xxx objects...
277 
278  if(*str == '=') {
279  --*tokens;
280  **tokens = '=';
281  *str = ' ';
282  }
283 
284  return true;
285 }
286 
287 Script::error::error(Script *img, unsigned line, const char *msg) :
288 OrderedObject(&img->errlist)
289 {
290  errmsg = img->dup(msg);
291  errline = line;
292  filename = img->filename;
293 }
294 
295 Script::Script() :
297 {
298  instance = icounter++;
299  errors = 0;
300  loop = 0;
301  lines = 0;
302  first = NULL;
303  global = NULL;
304  headers = NULL;
305  scheduler = NULL;
306  stack = (line_t **)alloc(sizeof(line_t *) * Script::stacking);
307  scripts = (LinkedObject **)alloc(sizeof(LinkedObject *) * Script::indexing);
308  memset(scripts, 0, sizeof(LinkedObject **) * Script::indexing);
309 
310  if(instance)
311  shell::log(shell::INFO, "creating image instance %lu\n", instance);
312 }
313 
315 {
316  purge();
317  shared = NULL;
318  if(instance)
319  shell::log(shell::INFO, "releasing image instance %lu\n", instance);
320 }
321 
322 void Script::errlog(unsigned line, const char *fmt, ...)
323 {
324  char text[65];
325  va_list args;
326 
327  va_start(args, fmt);
328  vsnprintf(text, sizeof(text), fmt, args);
329 
330  ++errors;
331  void *mp = alloc(sizeof(Script::error));
332  new(mp) Script::error(this, line, text);
333  va_end(args);
334 }
335 
337 {
338  while(keyword && keyword->name) {
339  keyword->next = keywords;
340  keywords = keyword;
341  ++keyword;
342  }
343 }
344 
346 {
347  keyword_t *keyword = keywords;
348 
349  while(keyword != NULL) {
350  if(eq(cmd, keyword->name))
351  break;
352  keyword = keyword->next;
353  }
354  return keyword;
355 }
356 
357 void Script::init(void)
358 {
359  static keyword_t keywords[] = {
395  {"strict", (method_t)NULL, (check_t)&checks::chkStrict},
396  {"apply", (method_t)NULL, (check_t)&checks::chkApply},
397  {"ignore", (method_t)NULL, (check_t)&checks::chkIgnmask},
402  {NULL}
403  };
404 
405  static bool initial = false;
406 
407  if(!initial) {
408  initial = true;
409  assign(keywords);
410  }
411 }
412 
413 Script::header *Script::find(Script *img, const char *id)
414 {
415  unsigned path = NamedObject::keyindex(id, Script::indexing);
416  linked_pointer<header> hp = img->scripts[path];
417 
418  while(is(hp)) {
419  if(eq(hp->name, id))
420  break;
421 
422  hp.next();
423  }
424  return *hp;
425 }
426 
427 Script *Script::compile(Script *merge, const char *fn, Script *cfg)
428 {
429 // linked_pointer<script::strict> sp;
430 
431  static unsigned serial;
432 
433  char **argv = new char *[256];
434  stringbuf<512> buffer;
435  char localname[128];
436  Script *img;
437  std::ifstream cf(fn);
438  header *scr = NULL;
439  const char *name = "_init_";
440  Script::event *current;
441  Script::event *prior;
442  char *tokens;
443  const char *token = NULL;
444  char *arg;
445  unsigned lnum = 0;
446  line_t *line, *last;
447  bool section = false;
448  unsigned argc;
449  const char *err, *op;
450  char *assigned;
451  unsigned path;
452  bool indented, formed;
453  Script::header *invoke;
454  bool define = false;
455  bool when = false;
456  bool label = false;
457  bool branching;
458  unsigned pos;
459  const char *cp;
460  bool requires = false;
461  char *ep;
462  size_t len;
463 
464  if(!cf.is_open()) {
465  if(merge)
466  return merge;
467  return NULL;
468  }
469 
470  if(merge)
471  img = merge;
472  else
473  img = new Script();
474 
475  img->shared = cfg;
476  img->filename = strrchr(fn, '/');
477  if(!img->filename)
478  img->filename = strrchr(fn, '\\');
479  if(!img->filename)
480  img->filename = strrchr(fn, ':');
481  if(img->filename)
482  ++img->filename;
483  else
484  img->filename = fn;
485 
486  img->filename = img->dup(img->filename);
487  img->serial = ++serial;
488 
489 initial:
490  current = NULL;
491  prior = NULL;
492  last = NULL;
493 
494  if(img->first && eq(name, "_init_")) {
495  scr = img->first;
496  last = scr->first;
497  while(last && last->next)
498  last = last->next;
499  }
500  else {
501  scr = (header *)img->alloc(sizeof(header));
502  scr->name = img->dup(name);
503  scr->file = img->dup(img->filename);
504  scr->events = NULL;
505  scr->first = NULL;
506  scr->resmask = 0;
507  scr->scoped = NULL;
508  scr->methods = NULL;
509  scr->link(NULL);
510 
511  ep = (char *)strrchr(scr->file, '.');
512  if(ep)
513  *ep = 0;
514  }
515 
517  img->loop = 0;
518  char *temp;
519 
520  // we drop additional initializers during append
521  if(!eq(name, "_init_") || !merge) {
522  path = NamedObject::keyindex(name, Script::indexing);
523  scr->enlist(&img->scripts[path]);
524  }
525 
526  if(!img->first)
527  img->first = scr;
528 
529  while(when || label || define || cf.getline(buffer.c_mem(), 512)) {
530  String::fix(buffer);
531  if(define) {
532  indented = true;
533  goto parse;
534  }
535 
536  if(when) {
537  indented = true;
538  when = false;
539  goto parse;
540  }
541 
542  if(label) {
543  label = false;
544  indented = true;
545  token = String::token(NULL, &tokens, " \t", "{}\'\'\"\"");
546  if(!token)
547  continue;
548  goto parse;
549  }
550 
551  img->lines = ++lnum;
552  img->thencheck = false;
553 
554  indented = false;
555  tokens = buffer.c_mem();
556  if(isspace(*tokens)) {
557  while(isspace(*tokens))
558  ++tokens;
559  indented = true;
560  if(!preparse(&tokens)) {
561  img->errlog(lnum, "malformed line");
562  continue;
563  }
564  }
565 
566  buffer.trim(" \t\r\n");
567 
568  // if empty line or comment, continue...
569  if(isend(*buffer))
570  continue;
571 
572  tokens = NULL;
573  token = String::token(buffer.c_mem(), &tokens, " \t", "{}\'\'\"\"");
574 
575  if(eq(token, "endreq") || eq(token, "endrequires")) {
576  if(indented) {
577  img->errlog(lnum, "endreq cannot be indented");
578  continue;
579  }
580  requires = false;
581  continue;
582  }
583  else if(eq(token, "requires")) {
584  if(indented) {
585  img->errlog(lnum, "requires cannot be indented");
586  continue;
587  }
588  requires = true;
589  while(NULL != (token = String::token(NULL, &tokens, " \t", "{}\'\'\"\""))) {
590  bool rev = false;
591  if(*token == '!') {
592  rev = true;
593  ++token;
594  }
595  keyword = find(token);
596  invoke = find(img, token);
597  if(!invoke && is(img->shared))
598  invoke = find(*(img->shared), token);
599  if(!rev && (keyword || invoke)) {
600  requires = false;
601  break;
602  }
603  if(rev && !keyword && !invoke) {
604  requires = false;
605  break;
606  }
607  }
608  continue;
609  }
610 
611  if(requires)
612  continue;
613 
614  if(*token == '^' || *token == '-') {
615  if(scr == img->first) {
616  img->errlog(lnum, "events cannot be in init segment");
617  continue;
618  }
619  current = (event *)img->alloc(sizeof(Script::event));
620  if(!prior)
621  prior = current;
622 
623  last = NULL;
624 
625  if(*token == '^')
626  current->enlist(&scr->events);
627  else
628  current->enlist(&scr->methods);
629  current->name = (char *)img->dup(++token);
630  current->first = NULL;
631  continue;
632  }
633 
634  if(*token == '@') {
635  section = true;
636  name = token;
637  label = true;
638  goto closure;
639  }
640 
641  if(*token == ':') {
642  section = true;
643  snprintf(localname, sizeof(localname), "@%04x%s", serial & 0xffff, token);
644  name = localname;
645  label = true;
646  goto closure;
647  }
648 
649  if(eq(token, "template")) {
650  if(section) {
651  img->errlog(lnum, "templates must be before named sections");
652  continue;
653  }
654  if(indented) {
655  img->errlog(lnum, "templates cannot be indented");
656  continue;
657  }
658  token = String::token(NULL, &tokens, " \t", "{}\'\'\"\"");
659  if(!token)
660  img->errlog(lnum, "template must be named");
661  name = token;
662  goto closure;
663  }
664 
665  if(eq(token, "define")) {
666  if(section) {
667  img->errlog(lnum, "defines must be before named sections");
668  continue;
669  }
670  if(indented) {
671  img->errlog(lnum, "define cannot be indented");
672  continue;
673  }
674  token = String::token(NULL, &tokens, " \t", "{}\'\'\"\"");
675  keyword = find(token);
676  if(keyword) {
677  img->errlog(lnum, "cannot redefine existing command");
678  continue;
679  }
680  define = true;
681  name = token;
682  goto closure;
683  }
684  if(!indented) {
685  img->errlog(lnum, "unindented statement");
686  continue;
687  }
688 
689 parse:
690  assigned = NULL;
691  op = NULL;
692 
693  branching = false;
694 
695  if(eq(token, "goto") || eq(token, "gosub"))
696  branching = true;
697 
698  if(*token == '%') {
699  assigned = img->dup(token);
700  op = String::token(NULL, &tokens, " \t", "{}\'\'\"\"");
701  if(op && (eq(op, ":=") || eq(op, "+=") || eq(op, "-=") || eq(op, "*=") || eq(op, "/=") || eq(op, "%=") || eq(op, "#=")))
702  token = "expr";
703  else if(op && (eq(op, "=") || eq(op, "==") || eq(op, "$="))) {
704  op = NULL;
705  token = "set";
706  }
707  else if(op && (eq(op, ".") || eq(op, ".="))) {
708  op = NULL;
709  token = "add";
710  }
711  else if(op && (eq(op, ",") || eq(op, ",="))) {
712  op = NULL;
713  token = "pack";
714  }
715  else {
716  img->errlog(lnum, "invalid assignment");
717  continue;
718  }
719  }
720  else if(*token == '$') {
721  assigned = img->dup(token);
722  token = "_ref";
723  }
724  invoke = NULL;
725  if(!iskeyword(token)) {
726  img->errlog(lnum, "invalid keyword");
727  continue;
728  }
729 
730  if(define) {
731  define = false;
732  keyword = find("_define");
733  if(!keyword) {
734  img->errlog(lnum, "define unsupported");
735  continue;
736  }
737  }
738  else {
739  keyword = find(token);
740  if(!keyword && NULL != (invoke = find(img, token)))
741  keyword = find("_invoke");
742  if(!keyword && is(img->shared) && NULL != (invoke = find(*(img->shared), token)))
743  keyword = find("_invoke");
744 
745  if(!keyword) {
746  img->errlog(lnum, "unknown keyword \"%s\"", token);
747  continue;
748  }
749  }
750 
751  // protects in backparse
752  token = img->dup(token);
753 
754  line = (line_t *)img->alloc(sizeof(line_t));
755  memset(line, 0, sizeof(line_t));
756  line->next = NULL;
757  line->lnum = lnum;
758  line->mask = 0;
759  if(invoke)
760  line->sub = invoke;
761  else
762  line->cmd = token;
763  line->loop = img->loop;
764  line->method = keyword->method;
765 
766  formed = true;
767  argc = 0;
768  arg = NULL;
769 
770  if(assigned)
771  argv[argc++] = assigned;
772 
773  if(op)
774  argv[argc++] = img->dup(op);
775 
776  while(argc < 249 && formed) {
777  if(!arg) {
778  formed = preparse(&tokens);
779  if(!formed)
780  break;
781  arg = (char *)String::token(NULL, &tokens, " \t", "{}\'\'\"\"");
782  }
783  if(!arg)
784  break;
785 
786  if(eq(token, "if")) {
787  if(eq(arg, "if")) {
788  formed = false;
789  break;
790  }
791  if(eq(arg, "then")) {
792  keyword = find("_ifthen");
793  line->method = keyword->method;
794  token = String::token(NULL, &tokens, " \t", "{}\'\'\"\"");
795  if(!token || !keyword || img->thencheck)
796  formed = false;
797  else
798  img->thencheck = when = true;
799  break;
800  }
801  }
802 
803  // compute script local label or symbol name...
804  if(*arg == ':' && branching) {
805  snprintf(localname, sizeof(localname), "@%04x%s", serial & 0xffff, arg);
806  arg = localname;
807  }
808  else if(*arg == ':' && isalnum(arg[1])) {
809  snprintf(localname, sizeof(localname), "%c_%04x_.%s",
810  '%', serial & 0xffff, ++arg);
811  arg = localname;
812  }
813 
814  ep = strchr(arg, '<');
815  if(*arg == '%' && ep) {
816  len = strlen(arg) + 10;
817  *(ep++) = 0;
818  temp = (char *)img->alloc(len);
819  String::set(temp, len, "$map/");
820  String::add(temp, len, ep);
821  ep = strchr(temp, '>');
822  if(ep)
823  *ep = ':';
824  String::add(temp, len, ++arg);
825  argv[argc++] = temp;
826  arg = NULL;
827  continue;
828  }
829 
830  ep = strchr(arg, '[');
831  if(*arg == '%' && ep) {
832  len = strlen(arg) + 10;
833  *(ep++) = 0;
834  temp = (char *)img->alloc(len);
835  if(atoi(ep))
836  String::set(temp, len, "$offset/");
837  else
838  String::set(temp, len, "$find/");
839  String::add(temp, len, ep);
840  ep = strchr(temp, ']');
841  if(ep)
842  *ep = ':';
843  String::add(temp, len, ++arg);
844  argv[argc++] = temp;
845  arg = NULL;
846  continue;
847  }
848 
849  ep = strchr(arg, '(');
850  if(*arg == '%' && ep) {
851  len = strlen(arg) + 10;
852  *(ep++) = 0;
853  temp = (char *)img->alloc(len);
854  String::set(temp, len, "$index/");
855  String::add(temp, len, ep);
856  ep = strchr(temp, ')');
857  if(ep)
858  *ep = ':';
859  String::add(temp, len, ++arg);
860  argv[argc++] = temp;
861  arg = NULL;
862  continue;
863  }
864 
865  argv[argc++] = img->dup(arg);
866  arg = NULL;
867  }
868 
869  if(!formed) {
870  img->errlog(lnum, "malformed statement or argument");
871  continue;
872  }
873 
874  line->argc = argc;
875  argv[argc++] = NULL;
876  line->argv = (char **)img->alloc(sizeof(char *) * argc);
877  memcpy(line->argv, argv, sizeof(char *) * argc);
878 
879  err = (*(keyword->check))(img, scr, line);
880  if(err) {
881  img->errlog(lnum, "%s", err);
882  continue;
883  }
884 
885  pos = 0;
886  while(img->isStrict() && pos < line->argc) {
887  cp = line->argv[pos++];
888  if(!Script::strict::find(img, scr, cp))
889  img->errlog(lnum, "undefined symbol reference %s\n", cp);
890  }
891 
892  // if compile-time only line, then no runtime method, so we skip...
893 
894  if(line->method == (method_t)NULL)
895  continue;
896 
897  // after error checking...we may add starting line...
898 
899  if(last)
900  last->next = line;
901  else {
902  if(current) {
903  linked_pointer<event> ep = prior;
904  while(is(ep) && *ep != current) {
905  ep->first = line;
906  ep.next();
907  }
908  current->first = line;
909  }
910  else
911  scr->first = line;
912  }
913  last = line;
914  }
915 
916 closure:
917  while(img->loop) {
918  line = img->stack[--img->loop];
919  img->errlog(line->lnum, "%s never completed loop", line->cmd);
920  }
921 
922  keyword = find("_close");
923  if(keyword) {
924  err = (*(keyword->check))(img, scr, scr->first);
925  if(err)
926  img->errlog(lnum, "%s", err);
927  }
928 
929 // sp = scr->scoped;
930 // while(is(sp)) {
931 // sp->put(stdout, scr->name);
932 // sp.next();
933 // }
934 
935  if(!cf.eof())
936  goto initial;
937 
938  delete[] argv;
939 // sp = img->global;
940 // while(is(sp)) {
941 // sp->put(stdout, "*");
942 // sp.next();
943 // }
944 
945  return img;
946 }
947 
948 bool Script::isEvent(header *scr, const char *id)
949 {
950  linked_pointer<event> ep = scr->events;
951 
952  while(is(ep)) {
953  if(eq(ep->name, id))
954  return true;
955  ep.next();
956  }
957  return false;
958 }
959 
960 bool Script::push(line_t *line)
961 {
962  if(loop < stacking) {
963  stack[loop++] = line;
964  return true;
965  }
966  return false;
967 }
968 
970 {
971  if(!loop)
972  return NULL;
973 
974  return stack[--loop]->method;
975 }
976 
978 {
979  if(!loop)
980  return NULL;
981 
982  return stack[loop - 1]->method;
983 }
984 
985 void Script::strict::createVar(Script* image, Script::header *scr, const char *id)
986 {
987  assert(id && *id);
988  assert(scr != NULL);
989  assert(image != NULL);
990 
991  linked_pointer<Script::strict> sp;
992  Script::strict *sym;
993 
994  if(*id == '%' || *id == '=' || *id == '$')
995  ++id;
996 
997  if(!image->global)
998  return;
999 
1000  if(*(scr->name) != '@') {
1001  sp = scr->scoped;
1002  while(is(sp)) {
1003  if(ideq(sp->id, id))
1004  return;
1005  sp.next();
1006  }
1007  sym = (Script::strict *)image->zalloc(sizeof(Script::strict));
1008  sym->enlist(&scr->scoped);
1009  sym->id = id;
1010  return;
1011  }
1012  sp = image->global;
1013  while(is(sp)) {
1014  if(ideq(sp->id, id))
1015  return;
1016  sp.next();
1017  }
1018  sym = (Script::strict *)image->zalloc(sizeof(Script::strict));
1019  sym->enlist(&image->global);
1020  sym->id = id;
1021 }
1022 
1023 void Script::strict::createSym(Script* image, Script::header *scr, const char *id)
1024 {
1025  assert(id && *id);
1026  assert(scr != NULL);
1027  assert(image != NULL);
1028 
1029  linked_pointer<Script::strict> sp;
1030  Script::strict *sym;
1031 
1032  if(*id == '%' || *id == '=' || *id == '$')
1033  ++id;
1034 
1035  if(scr && !image->global)
1036  return;
1037 
1038  if(scr && *(scr->name) != '@') {
1039  sp = scr->scoped;
1040  while(is(sp)) {
1041  if(ideq(sp->id, id))
1042  return;
1043  sp.next();
1044  }
1045  }
1046  sp = image->global;
1047  while(is(sp)) {
1048  if(ideq(sp->id, id))
1049  return;
1050  sp.next();
1051  }
1052  sym = (Script::strict *)image->zalloc(sizeof(Script::strict));
1053  sym->enlist(&image->global);
1054  sym->id = id;
1055 }
1056 
1057 void Script::strict::createAny(Script* image, Script::header *scr, const char *id)
1058 {
1059  assert(id && *id);
1060  assert(scr != NULL);
1061  assert(image != NULL);
1062 
1063  linked_pointer<Script::strict> sp;
1064  Script::strict *sym;
1065 
1066  if(*id == '%' || *id == '=' || *id == '$')
1067  ++id;
1068 
1069  if(scr && !image->global)
1070  return;
1071 
1072  if(scr && *(scr->name) != '@') {
1073  sp = scr->scoped;
1074  while(is(sp)) {
1075  if(ideq(sp->id, id))
1076  return;
1077  sp.next();
1078  }
1079  }
1080  sp = image->global;
1081  while(is(sp)) {
1082  if(ideq(sp->id, id))
1083  return;
1084  sp.next();
1085  }
1086  sym = (Script::strict *)image->zalloc(sizeof(Script::strict));
1087  if(scr && *(scr->name) != '@')
1088  sym->enlist(&scr->scoped);
1089  else
1090  sym->enlist(&image->global);
1091  sym->id = id;
1092 }
1093 
1094 void Script::strict::createGlobal(Script *image, const char *id)
1095 {
1096  assert(id && *id);
1097  assert(image != NULL);
1098 
1099  linked_pointer<Script::strict> sp;
1100  Script::strict *sym;
1101 
1102  if(*id == '%' || *id == '=' || *id == '$')
1103  ++id;
1104 
1105  sp = image->global;
1106  while(is(sp)) {
1107  if(ideq(sp->id, id))
1108  return;
1109  sp.next();
1110  }
1111  sym = (Script::strict *)image->zalloc(sizeof(Script::strict));
1112  sym->enlist(&image->global);
1113  sym->id = id;
1114 }
1115 
1116 bool Script::strict::find(Script* image, Script::header *scr, const char *id)
1117 {
1118  assert(id && *id);
1119  assert(scr != NULL);
1120  assert(image != NULL);
1121 
1122  char buf[64];
1123  const char *cp;
1124  char *ep;
1125  linked_pointer<Script::strict> sp;
1126 
1127  if(!image->global)
1128  return true;
1129 
1130  if(*id != '%' && *id != '$')
1131  return true;
1132 
1133  if(eq(id, "$map/", 5)) {
1134  buf[0] = '%';
1135  String::set(buf + 1, sizeof(buf) - 1, id + 5);
1136  ep = strchr(buf, ':');
1137  if(ep)
1138  *ep = 0;
1139 
1140  if(!find(image, scr, buf))
1141  return false;
1142  }
1143 
1144  if(*id == '$') {
1145  cp = strchr(id, ':');
1146  if(cp)
1147  id = ++cp;
1148  else
1149  ++id;
1150  }
1151  else
1152  ++id;
1153 
1154  if(*(scr->name) != '@') {
1155  sp = scr->scoped;
1156  while(is(sp)) {
1157  if(ideq(sp->id, id))
1158  return true;
1159  sp.next();
1160  }
1161  }
1162 
1163  sp = image->global;
1164  while(is(sp)) {
1165  if(ideq(sp->id, id))
1166  return true;
1167  sp.next();
1168  }
1169  return false;
1170 }
1171 
1172 void Script::strict::put(FILE *fp, const char *header)
1173 {
1174  assert(fp != NULL);
1175  assert(id != NULL);
1176 
1177  const char *pid = id;
1178  if(header) {
1179  fputs(header, fp);
1180  fputc(':', fp);
1181  }
1182  while(*pid && *pid != ':')
1183  fputc(*(pid++), fp);
1184  fputc('\n', fp);
1185 }
1186 
1187 unsigned Script::count(const char *data)
1188 {
1189  unsigned count = 0;
1190  char quote = 0;
1191  unsigned paren = 0;
1192 
1193  if(!data || !*data)
1194  return 0;
1195 
1196  ++count;
1197  while(*data) {
1198  if(*data == ',' && !quote && !paren)
1199  ++count;
1200  else if(*data == quote && !paren)
1201  quote = 0;
1202  else if(*data == '\"' && !paren)
1203  quote = *data;
1204  else if(*data == '(' && !quote)
1205  ++paren;
1206  else if(*data == ')' && !quote)
1207  --paren;
1208  ++data;
1209  }
1210  return count;
1211 }
1212 
1213 void Script::copy(const char *list, char *item, unsigned size)
1214 {
1215  assert(size > 0);
1216  assert(item != NULL);
1217 
1218  bool lead = false;
1219  char quote = 0;
1220  char prev = 0;
1221  unsigned paren = 0;
1222  bool leadparen = false;
1223 
1224  if(!list || !*list || *list == ',') {
1225  *item = 0;
1226  return;
1227  }
1228 
1229  while(isspace(*list))
1230  ++list;
1231 
1232  if(*list == '(') {
1233  leadparen = true;
1234  ++paren;
1235  ++list;
1236  }
1237  else {
1238  if(*list == '\"' || *list == '\'') {
1239  quote = *(list++);
1240  lead = true;
1241  }
1242  }
1243 
1244  while(--size && *list) {
1245  if(paren == 1 && leadparen && *list == ')' && !quote)
1246  break;
1247  if(*list == '(')
1248  ++paren;
1249  else if(*list == ')')
1250  --paren;
1251  if(*list == ',' && !quote && !paren)
1252  break;
1253  if(*list == quote && lead)
1254  break;
1255  if(*list == quote) {
1256  *(item++) = quote;
1257  break;
1258  }
1259  if(!quote && *list == '\"' && prev == '=' && !paren)
1260  quote = *list;
1261  prev = *item;
1262  *(item++) = *(list++);
1263  }
1264  *item = 0;
1265 }
1266 
1267 unsigned Script::offset(const char *list, unsigned index)
1268 {
1269  const char *cp = get(list, index);
1270  return (unsigned)(cp - list);
1271 }
1272 
1273 const char *Script::get(const char *list, unsigned index)
1274 {
1275  char quote = 0;
1276  unsigned paren = 0;
1277 
1278  if(!list || !*list)
1279  return NULL;
1280 
1281  if(!index)
1282  return list;
1283 
1284  while(*list && index) {
1285  if(*list == ',' && !quote && !paren) {
1286  --index;
1287  if(!index)
1288  return ++list;
1289  } else if(*list == quote)
1290  quote = 0;
1291  else if(*list == '(' && !quote)
1292  ++paren;
1293  else if(*list == ')' && !quote)
1294  --paren;
1295  else if(*list == '\"' && !paren)
1296  quote = *list;
1297  ++list;
1298  }
1299  return NULL;
1300 }
1301 
1302 char *Script::get(char *list, unsigned index)
1303 {
1304  char quote = 0;
1305  unsigned paren = 0;
1306 
1307  if(!list || !*list)
1308  return NULL;
1309 
1310  if(!index)
1311  return list;
1312 
1313  while(*list && index) {
1314  if(*list == ',' && !quote && !paren) {
1315  --index;
1316  if(!index)
1317  return ++list;
1318  } else if(*list == quote)
1319  quote = 0;
1320  else if(*list == '(' && !quote)
1321  ++paren;
1322  else if(*list == ')' && !quote)
1323  --paren;
1324  else if(*list == '\"' && !paren)
1325  quote = *list;
1326  ++list;
1327  }
1328  return NULL;
1329 }
1330 
1331 } // namespace ucommon
static void createVar(Script *img, header *scr, const char *id)
Definition: script.cpp:985
static const char * chkDefine(Script *img, header *scr, line_t *line)
Definition: checks.cpp:621
struct ucommon::Script::keyword keyword_t
NAMESPACE_UCOMMON A structure to introduce new core commands to the runtime engine.
static const char * chkConst(Script *img, header *scr, line_t *line)
Definition: checks.cpp:847
unsigned resmask
post-compile processing resource mask
Definition: ccscript.h:162
static const char * chkEndif(Script *img, header *scr, line_t *line)
Definition: checks.cpp:386
static size_t paging
default heap paging
Definition: ccscript.h:451
LinkedObject ** scripts
Definition: ccscript.h:499
void link(header *scr)
Used to set linked list linkage.
Definition: ccscript.h:168
static const char * chkExit(Script *img, header *scr, line_t *line)
Definition: checks.cpp:571
const char *(* check_t)(Script *img, Script::header *scr, Script::line_t *line)
A type for compile-time command verification method invokation.
Definition: ccscript.h:64
LinkedObject * scheduler
scheduler list
Definition: ccscript.h:456
static const char * chkIf(Script *img, header *scr, line_t *line)
Definition: checks.cpp:264
A class to collect compile-time errors.
Definition: ccscript.h:377
static const char * chkLoop(Script *img, header *scr, line_t *line)
Definition: checks.cpp:422
static Script * compile(Script *merge, const char *filename, Script *config=NULL)
Compiled a file into an existing image.
Definition: script.cpp:427
struct line * next
Definition: ccscript.h:50
static unsigned stepping
default stepping increment
Definition: ccscript.h:449
static const char * chkPrevious(Script *img, header *scr, line_t *line)
Definition: checks.cpp:161
static unsigned indexing
default symbol indexing
Definition: ccscript.h:450
static const char * chkClear(Script *img, header *scr, line_t *line)
Definition: checks.cpp:810
line_t * first
first line of section or define
Definition: ccscript.h:159
static const char * chkCase(Script *img, header *scr, line_t *line)
Definition: checks.cpp:453
static bool isEvent(header *scr, const char *id)
Definition: script.cpp:948
static const char * get(const char *list, unsigned offset)
Definition: script.cpp:1273
const char * name
Definition: ccscript.h:134
static void copy(const char *list, char *item, unsigned size)
Definition: script.cpp:1213
const char * name
name of command
Definition: ccscript.h:73
NAMESPACE_UCOMMON A structure to introduce new core commands to the runtime engine.
Definition: ccscript.h:71
static const char * chkForeach(Script *img, header *scr, line_t *line)
Definition: checks.cpp:324
static const char * chkStrict(Script *img, header *scr, line_t *line)
Definition: checks.cpp:205
static const char * chkExpr(Script *img, header *scr, line_t *line)
Definition: checks.cpp:993
static void createGlobal(Script *img, const char *id)
Definition: script.cpp:1094
static const char * chkBreak(Script *img, header *scr, line_t *line)
Definition: checks.cpp:231
unsigned short argc
Definition: ccscript.h:56
static const char * chkVar(Script *img, header *scr, line_t *line)
Definition: checks.cpp:1052
static const char * chkExpand(Script *img, header *scr, line_t *line)
Definition: checks.cpp:289
static const char * chkUntil(Script *img, header *scr, line_t *line)
Definition: checks.cpp:547
Basic compiled statement.
Definition: ccscript.h:49
static const char * chkWhile(Script *ing, header *scr, line_t *line)
Definition: checks.cpp:275
static unsigned stacking
stack frames in script runtime
Definition: ccscript.h:453
bool isStrict(void)
Definition: ccscript.h:514
static unsigned count(const char *list)
Definition: script.cpp:1187
static const char * chkContinue(Script *img, header *scr, line_t *line)
Definition: checks.cpp:180
static const char * chkEndcase(Script *img, header *scr, line_t *line)
Definition: checks.cpp:402
static unsigned offset(const char *list, unsigned index)
Definition: script.cpp:1267
static void createAny(Script *img, header *scr, const char *id)
Definition: script.cpp:1057
static const char * chkWhen(Script *img, header *scr, line_t *line)
Definition: checks.cpp:256
Contains defined variables found by scope when strict is used.
Definition: ccscript.h:86
static void assign(keyword_t *list)
Assign new keywords from extensions and derived service.
Definition: script.cpp:336
static const char * chkNop(Script *img, header *scr, line_t *line)
Definition: checks.cpp:563
static unsigned decimals
default decimal places
Definition: ccscript.h:454
const char * id
Definition: ccscript.h:92
static const char * chkElse(Script *img, header *scr, line_t *line)
Definition: checks.cpp:497
static keyword_t * find(const char *id)
Find a keyword from internal command table.
Definition: script.cpp:345
bool(Script::interp::* method_t)(void)
A type for runtime script method invokation.
Definition: ccscript.h:41
const char * cmd
Definition: ccscript.h:52
struct keyword * next
linked list set by assign()
Definition: ccscript.h:76
static const char * chkRef(Script *img, header *scr, line_t *line)
Definition: checks.cpp:244
header * first
Definition: ccscript.h:498
const char * name
name of script section or define
Definition: ccscript.h:161
method_t pull(void)
Definition: script.cpp:969
struct ucommon::Script::line line_t
Basic compiled statement.
const char * file
filename of script
Definition: ccscript.h:160
static const char * chkGoto(Script *img, header *scr, line_t *line)
Definition: checks.cpp:874
Compiled script container.
Definition: ccscript.h:31
check_t check
compile-time check routine
Definition: ccscript.h:75
static void init(void)
Initialize entire script engine.
Definition: script.cpp:357
static const char * chkElif(Script *img, header *scr, line_t *line)
Definition: checks.cpp:479
method_t method
runtime method or NULL if c-t only
Definition: ccscript.h:74
static const char * chkError(Script *img, header *scr, line_t *line)
Definition: checks.cpp:828
static const char * chkPush(Script *img, header *scr, line_t *line)
Definition: checks.cpp:701
static const char * chkPack(Script *img, header *scr, line_t *line)
Definition: checks.cpp:661
Header describes a script section.
Definition: ccscript.h:150
An event block for a script.
Definition: ccscript.h:127
static const char * chkGosub(Script *img, header *src, line_t *line)
Definition: checks.cpp:893
void put(FILE *fp, const char *header)
Definition: script.cpp:1172
unsigned short loop
Definition: ccscript.h:56
bool scrPrevious(void)
Definition: methods.cpp:35
static unsigned sizing
default symbol size
Definition: ccscript.h:452
static const char * chkInvoke(Script *img, header *scr, line_t *line)
Definition: checks.cpp:582
static const char * chkOtherwise(Script *img, header *scr, line_t *line)
Definition: checks.cpp:522
LinkedObject * methods
named members
Definition: ccscript.h:158
LinkedObject * scoped
scoped symbol defs
Definition: ccscript.h:156
LinkedObject * events
named events
Definition: ccscript.h:157
method_t looping(void)
Definition: script.cpp:977
bool push(line_t *line)
Definition: script.cpp:960
static const char * chkIgnmask(Script *img, header *scr, line_t *line)
Definition: checks.cpp:736
static const char * chkIndex(Script *img, header *scr, line_t *line)
Definition: checks.cpp:958
static bool find(Script *img, header *scr, const char *id)
Definition: script.cpp:1116
static const char * chkSet(Script *img, header *scr, line_t *line)
Definition: checks.cpp:752
static const char * chkApply(Script *img, header *scr, line_t *line)
Definition: checks.cpp:135
static const char * chkDo(Script *img, header *scr, line_t *line)
Definition: checks.cpp:369
static void createSym(Script *img, header *scr, const char *id)
Definition: script.cpp:1023