ARB
aisc_commands.c
Go to the documentation of this file.
1 // ================================================================
2 /* */
3 // File : aisc_commands.c
4 // Purpose :
5 /* */
6 // Institute of Microbiology (Technical University Munich)
7 // http://www.arb-home.de/
8 /* */
9 // ================================================================
10 
11 #include "aisc_interpreter.h"
12 #include "aisc_eval.h"
13 
14 Location Location::exit_pc;
15 int Location::global_error_count = 0;
16 
18  if (exit_pc.valid()) return exit_pc;
19 
21  const Code *pc = Interpreter::instance->at();
22  if (pc) return pc->source;
23  }
24 
25  static Location dummy(0, "no_idea_where");
26  return dummy;
27 }
28 
29 void Location::print_internal(const char *msg, const char *msg_type, const char *launcher_file, int launcher_line) const {
30 #if defined(MASK_ERRORS)
31  fputs("(disabled) ", stderr);
32 #endif
33  fputs("./", stderr);
34  fprint_location(stderr);
35 
36  if (msg_type) {
37  fputs(msg_type, stderr);
38  fputs(": ", stderr);
39  }
40 
41  if (msg) {
42  fputs(msg, stderr);
44  const Data& data = Interpreter::instance->get_data();
45  if (data.get_cursor()) {
46  fputs(" (cursor ", stderr);
47  data.dump_cursor_pos(stderr);
48  fputs(")", stderr);
49  }
50  }
51  fputc('\n', stderr);
52  }
53 
54  if (launcher_file) {
55 #if defined(MASK_ERRORS)
56  fputs("(disabled) ", stderr);
57 #endif
58  fputs("../AISC/", stderr);
59  fprint_location(launcher_file, launcher_line, stderr);
60  fprintf(stderr, "%s was launched from here\n", msg_type);
61  }
62 }
63 
64 #define ERRBUFSIZE 500
65 const char *formatted(const char *format, ...) {
66  // goes to header: __ATTR__FORMAT(1)
67 
68  static char *errbuf = NULp;
69  if (!errbuf) { errbuf = (char*)malloc(ERRBUFSIZE+1); }
70 
71  va_list argPtr;
72  va_start(argPtr, format);
73  int chars = vsprintf(errbuf, format, argPtr);
74  if (chars>ERRBUFSIZE) {
75  fprintf(stderr, "%s:%i: Error: Buffer overflow!\n", __FILE__, __LINE__);
76  vfprintf(stderr, format, argPtr);
77  fputc('\n', stderr);
78 
79  va_end(argPtr);
80  exit(EXIT_FAILURE);
81  }
82  va_end(argPtr);
83 
84  return errbuf;
85 }
86 #undef ERRBUFSIZE
87 
88 inline void print_tabs(int count, FILE *out) {
89  while (count--) fputc('\t', out);
90 }
91 
92 static void write_aisc(const TokenListBlock *block, FILE *out, int indentation) {
93  for (const TokenList *list = block->first_list(); list; list = list->next_list()) {
94  print_tabs(indentation, out);
95 
96  const Token *first = list->first_token();
97  for (const Token *tok = first; tok; tok = tok->next_token()) {
98  if (tok != first) fputc(',', out);
99 
100  if (tok->is_block()) {
101  fprintf(out, "'%s'={\n", tok->get_key());
102  const TokenListBlock *content = tok->get_content();
103  if (content) write_aisc(content, out, indentation + 1);
104  print_tabs(indentation+1, out);
105  fputc('}', out);
106  }
107  else {
108  fprintf(out, "\t'%s'=(~%s~)",
109  tok->get_key(),
110  tok->has_value() ? tok->get_value() : "");
111  }
112  }
113  fprintf(out, ";\n");
114  }
115 }
116 
117 // --------------------
118 // Interpreter
119 
121 
122 void Interpreter::define_fun(const char *name, const Code *co) {
123  const Code *exists = find_fun(name);
124  if (exists) {
125  printf_error(co, "Attempt to redefine '%s'", name);
126  print_error(exists, "first definition was here");
127  }
128  else {
129  char buffer[100];
130  sprintf(buffer, "%li", (long)co);
131  functions->write(name, buffer);
132  }
133 }
134 
135 const Code *Interpreter::find_fun(const char *name) {
136  const char *fn = functions->read(name);
137  return fn ? (Code*)atol(fn) : NULp;
138 }
139 
140 
141 int Interpreter::do_dumpdata(const char *filename) {
142  if (!data.get_tokens()) {
143  print_error(at(), "DUMPDATA can only be used after DATA");
144  return 1;
145  }
146  FILE *out = stdout;
147  if (filename[0]) {
148  printf("Dumping data to '%s'\n", filename);
149  out = fopen(filename, "wt");
150  if (!out) {
151  printf_error(at(), "cant write to file '%s' (DUMPDATA)", filename);
152  return 1;
153  }
154  }
155  else {
156  puts("DUMPDATA:");
157  }
158  write_aisc(data.get_tokens(), out, 0);
159  if (filename[0]) fclose(out);
160  return 0;
161 }
162 
163 int Interpreter::do_data(const char *str) {
164  if (strlen(str) < 2) {
165  printf_error(at(), "no parameter '%s'", at()->str);
166  return 1;
167  }
168 
169  if (!set_data(str, 4)) { // hack to correct column reported on errors
170  printf_error(at(), "occurred in following script-part: '%s'", at()->str);
171  return 1;
172  }
173  return 0;
174 }
175 
176 int Interpreter::do_indent(const char *str) {
177  int diff = atoi(str);
178  int indent = current_formatter().get_indent();
179  int new_indent = indent+diff;
180 
181  if (new_indent<0) {
182  printf_error(at(), "invalid resulting indentation %i", new_indent);
183  return 1;
184  }
185 
186  current_formatter().set_indent(new_indent);
187  return 0;
188 }
189 
190 int Interpreter::do_tabstop(const char *str) {
191  int ts = atoi(str);
192  if ((ts < 1) || (ts > 1024)) {
193  printf_error(at(), "illegal TABSTOP %i (legal: [1..1024])", ts);
194  return 1;
195  }
196 
197  current_formatter().set_tabstop(ts);
198  return 0;
199 }
200 
201 class ArgParser : virtual Noncopyable {
202  char *args;
203  char *strtok_arg;
204  const Location& loc;
205 
206  void init(const char *a) { strtok_arg = args = strdup(a); }
207 public:
208  ArgParser(const char *arguments, const Location& loc_) : loc(loc_) { init(arguments); }
209  ArgParser(const char *arguments, const Code *co) : loc(co->source) { init(arguments); }
210  ~ArgParser() { free(args); }
211 
212  const char *get(const char *paramDescription) {
213  const char *res = strtok(strtok_arg, " \t,;\n");
214  strtok_arg = NULp;
215  if (!res) printf_error(&loc, "Missing argument '%s'", paramDescription);
216  return res;
217  }
218 };
219 
220 int Interpreter::do_tab(const char *str) {
221  ArgParser args(str, at());
222 
223  const char *s1 = args.get("TABCOUNT");
224  if (s1) {
225  const char *s2 = args.get("TABVALUE");
226  if (s2) {
227  int ts = atoi(s1);
228  if ((ts < 0) || (ts > 9)) print_error(at(), "wrong TABCOUNT");
229  else {
230  int val = atoi(s2);
231  if ((val < 0) || (val > 1000)) print_error(at(), "wrong TABVALUE");
232  else {
233  current_formatter().set_tab(ts, val);
234  return 0;
235  }
236  }
237  }
238  }
239  return 1;
240 }
241 
242 int Interpreter::do_open(const char *str) {
243  ArgParser args(str, at());
244 
245  const char *fileID = args.get("fileID");
246  if (fileID) {
247  const char *fn = args.get("filename");
248  if (strlen(fn) < 3) printf_error(at(), "Filename '%s' too short (<3)", fn);
249  else {
250  Output *alreadyOpen = find_output_for_ID(fileID);
251  if (alreadyOpen) printf_error(at(), "File '%s' already opened", fileID);
252  else {
253  int i;
254  for (i = 0; i < OPENFILES; i++) {
255  if (!output[i].inUse()) break;
256  }
257  if (i == OPENFILES) print_error(at(), "Too many open files");
258  else {
259  FILE *file = fopen(fn, "wt");
260  if (file) {
261  output[i].assign(file, fileID, fn, at());
262  return 0;
263  }
264  printf_error(at(), "Cannot write to file '%s' (OPEN)", fn);
265  }
266  }
267  }
268  }
269  return 1;
270 }
271 
272 int Interpreter::do_close(const char *str) {
273  ArgParser args(str, at());
274  const char *fileID = args.get("fileID");
275 
276  if (fileID) {
277  Output *known = find_output_for_ID(fileID);
278  if (known) {
279  known->close();
280  return 0;
281  }
282  printf_error(at(), "File '%s' not open or already closed", str);
283  }
284  return 1;
285 }
286 
287 int Interpreter::do_out(const char *str) {
288  ArgParser args(str, at());
289  const char *fileID = args.get("fileID");
290 
291  if (fileID) {
292  Output *known = find_output_for_ID(fileID);
293  if (known) {
294  current_output = known;
295  return 0;
296  }
297  printf_error(at(), "File '%s' not open or already closed", str);
298  }
299  return 1;
300 }
301 
302 inline char *get_ident(const char*& code, const Code *at) {
303  const char *start = strstr(code, "$(");
304  if (!start) {
305  print_error(at, "expected to see '$(' while parsing for ident/selector");
306  return NULp;
307  }
308  const char *end = strchr(start+2, ')');
309  if (!end) {
310  print_error(at, "missing closing ')' after ident/selector");
311  return NULp;
312  }
313 
314  code = end+1;
315 
316  char *ident = copy_string_part(start+2, end-1);
317  if (!ident[0]) {
318  print_error(at, "Empty ident/selector");
319  freenull(ident);
320  }
321  return ident;
322 }
323 
324 int Interpreter::do_moveto(const char *str) {
325  int err = 1;
326  char *selector = get_ident(str, at());
327  if (selector) {
328  LookupScope scope = strrchr(selector, '/') ? LOOKUP_LIST : LOOKUP_BLOCK;
329  const Token *fo = data.find_qualified_token(selector, scope);
330  if (!fo) {
331  printf_error(at(), "Could not find data '%s'", selector);
332  }
333  else {
334  data.set_cursor(fo);
335  err = 0;
336  }
337  free(selector);
338  }
339  return err;
340 }
341 
342 void var_ref::const_violation() {
343  printf_error(Interpreter::instance->at(),
344  "Attempt to modify write-protected variable '%s'", e->key);
345 }
346 
347 int Interpreter::do_makeconst(const char *str) {
348  int err = 1;
349  char *ident = get_ident(str, at());
350 
351  if (ident) {
352  var_ref var = get_local(ident);
353  if (!var) {
354  printf_error(at(), "undefined Ident '%s' in CONST (use CREATE first)", ident);
355  }
356  else {
357  var.write_protect();
358  }
359  free(ident);
360  }
361 
362  return err;
363 }
364 
365 int Interpreter::do_set(const char *str) {
366  int err = 1;
367  char *ident = get_ident(str, at());
368  if (ident) {
369  var_ref var = get_local(ident);
370  if (!var) {
371  printf_error(at(), "undefined Ident '%s' in SET (use CREATE first)", ident);
372  }
373  else {
374  SKIP_SPACE_LF(str);
375  if (str[0] == '=') {
376  ++str;
377  SKIP_SPACE_LF(str);
378  }
379  err = var.write(str);
380  }
381  free(ident);
382  }
383  return err;
384 }
385 
386 int Interpreter::do_create(const char *str) {
387  char *var = get_ident(str, at());
388  const char *def = read_var(var);
389 
390  int result = 1;
391  if (def) printf_error(at(), "Ident '%s' in CREATE already defined", var);
392  else {
393  SKIP_SPACE_LF(str);
394  if (*str == '=') {
395  str++;
396  SKIP_SPACE_LF(str);
397  }
398  write_var(var, str);
399  result = 0;
400  }
401  free(var);
402  return result;
403 }
404 
405 int Interpreter::do_if(const char *str) {
406  int err = 0;
407  bool condition = false;
408 
409  if (str) { // expression is not undefined
410  const char *cursor = strpbrk(str, "=~<");
411  if (!cursor) condition = true; // if no operator found -> assume condition true (even if empty)
412  else {
413  char op = *cursor;
414  aisc_assert(cursor>str);
415  bool negate = cursor[-1] == '!';
416 
417  const char *la = cursor - negate;
418  if (la>str) {
419  --la;
420  SKIP_SPACE_LF_BACKWARD(la, str);
421  }
422 
423  char *left = copy_string_part(str, la);
424  cursor++;
425 
426  char right_buffer[strlen(cursor)+1];
427  const char *right = right_buffer;
428 
429  while (cursor && !condition) {
430  SKIP_SPACE_LF(cursor);
431  const char *kom = strchr(cursor, ',');
432  const char *next = kom;
433 
434  if (kom) {
435  next++;
436  --kom;
437  aisc_assert(kom>=str);
438  SKIP_SPACE_LF_BACKWARD(kom, str);
439 
440  int len = kom-cursor+1;
441  memcpy(right_buffer, cursor, len);
442  right_buffer[len] = 0;
443  }
444  else {
445  right = cursor;
446  }
447 
448  switch (op) {
449  case '=': condition = strcmp(left, right) == 0; break;
450  case '~': condition = strstr(left, right) != NULp; break;
451  case '<': condition = atoi(left) < atoi(right); break;
452  default:
453  print_error(at(), formatted("Unhandled operator (op='%c') applied to '%s'", op, str));
454  err = 1;
455  break;
456  }
457 
458  if (err) break;
459  if (negate) condition = !condition;
460  cursor = next;
461  }
462 
463  free(left);
464  }
465  }
466 
467  if (!err && !condition) jump(at()->ELSE->next);
468  return err;
469 }
470 
471 struct for_data {
472  char *forstr;
473  const Token *forcursor;
474  long forval;
475  long forend;
477 };
478 
479 inline for_data& add_for_data_to(const Code *co) {
480  for_data *fd = (for_data *)calloc(sizeof(for_data), 1);
481 
482  fd->next = co->fd;
483  co->fd = fd;
484 
485  return *fd;
486 }
487 
488 inline void remove_for_data_from(const Code *co) {
489  for_data *fd = co->fd;
490  free(fd->forstr);
491  co->fd = fd->next;
492  free(fd);
493 }
494 
495 int Interpreter::do_push() {
496  if (stack_size++ >= STACKSIZE) {
497  print_error(at(), "Stack size exceeded");
498  return 1;
499  }
500 
501  Stack *st = (Stack *)calloc(sizeof(Stack), 1);
502 
503  st->cursor = data.get_cursor();
504  st->pc = at();
505  st->hs = new hash(HASHSIZE);
506  st->next = stack;
507 
508  stack = st;
509 
510  return 0;
511 }
512 
513 void Interpreter::pop() {
514  aisc_assert(stack_size>0);
515 
516  Stack *st = stack;
517  if (st) {
518  delete st->hs;
519  data.set_cursor(st->cursor);
520  stack = st->next;
521  free(st);
522  stack_size--;
523  }
524 }
525 
526 int Interpreter::do_pop() {
527  if (stack_size<2) {
528  print_error(at(), "Nothing to Pop");
529  return 1;
530  }
531  pop();
532  return 0;
533 }
534 
535 int Interpreter::do_gosub(const char *str) {
536  int result = 1;
537  if (do_push() == 0) {
538  char *params;
539  char *fun_name;
540 
541  {
542  const char *s;
543  for (s = str; !is_SPACE_SEP_LF_EOS(*s); s++) ;
544 
545  fun_name = copy_string_part(str, s-1);
546 
547  if (*s) {
548  s++;
549  SKIP_SPACE_LF(s);
550  params = strdup(s);
551  }
552  else {
553  params = NULp;
554  }
555  }
556 
557  const Code *fun = find_fun(fun_name);
558  if (!fun) {
559  printf_error(at(), "Function '%s' not found", fun_name);
560  }
561  else {
562  bool eval_failed;
563  char *fpara_eval = Expression(data, fun->source, fun->str, false).evaluate(eval_failed);
564 
565  const char *fpara = fpara_eval;
566  SKIP_SPACE_LF(fpara);
567  if (!*fpara) fpara = NULp;
568 
569  char *npara = NULp;
570  const char *nfpara = NULp;
571 
572  int err = eval_failed;
573  for (char *para = params; !err && para; para=npara, fpara=nfpara) {
574  if (!fpara) {
575  printf_error(at(), "Too many Parameters '%s'", para);
576  printf_error(fun, "in call to '%s'", fun_name);
577 
578  err = -1;
579  }
580  else {
581  {
582  char *s;
583  for (s = para; !is_SEP_LF_EOS(*s); s++) ;
584  if (*s) {
585  *s = 0;
586  npara = s+1;
587  SKIP_SPACE_LF(npara);
588  }
589  else npara = NULp;
590  }
591 
592  char *fpara_name;
593  {
594  const char *s;
595  for (s = fpara; !is_SEP_LF_EOS(*s); s++) ;
596  fpara_name = copy_string_part(fpara, s-1);
597  if (*s) {
598  nfpara = s+1;
599  SKIP_SPACE_LF(nfpara);
600  }
601  else nfpara = NULp;
602  }
603 
604  char *para_eval = Expression(data, at()->source, para, false).evaluate(eval_failed);
605 
606  if (eval_failed) {
607  print_error(at(), formatted("Could not evaluate expression '%s' for parameter '%s'", para, fpara_name));
608  }
609  else {
610  const char *s = read_var(fpara_name);
611  if (s) {
612  print_error(fun, formatted("duplicated formal parameter '%s' in definition of function '%s'", fpara_name, fun_name));
613  err = -1;
614  }
615  else {
616  write_var(fpara_name, para_eval);
617  }
618  }
619  free(para_eval);
620  free(fpara_name);
621  }
622  }
623 
624  if (!err && fpara) {
625  printf_error(at(), "Missing parameter '%s'", fpara);
626  printf_error(fun, "in call to '%s'", fun_name);
627  err = -1;
628  }
629 
630  if (!err) jump(fun->next);
631  result = err;
632  free(fpara_eval);
633  }
634  free(fun_name);
635  free(params);
636  }
637  return result;
638 }
639 
640 int Interpreter::do_goto(const char *str) {
641  const Code *func = find_fun(str);
642  if (!func) {
643  printf_error(at(), "Function '%s' not found", str);
644  return 1;
645  }
646  jump(func->next);
647  return 0;
648 }
649 
650 int Interpreter::do_return() {
651  jump(stack->pc->next);
652  return do_pop();
653 }
654 
655 int Interpreter::do_for(const char *str) {
656  int err = 1;
657  char *ident = get_ident(str, at());
658  if (ident) {
659  const char *eq = strchr(str, '=');
660  if (eq) {
661  ++eq;
662  SKIP_SPACE_LF(eq);
663 
664  const char *to = strstr(eq, "TO");
665  if (!to) print_error(at(), "TO not found in FOR - expecting e.g. 'FOR $(i) = a TO b'");
666  else {
667  to += 2;
668  SKIP_SPACE_LF(to);
669 
670  for_data& fd = add_for_data_to(pc);
671  fd.forval = atol(eq);
672  fd.forend = atol(to);
673 
674  if (fd.forval > fd.forend) {
675  nextpc = pc->NEXT->next;
677  err = 0;
678  }
679  else {
680  var_ref var = get_local(ident);
681  if (!var) {
682  printf_error(at(), "Undefined Ident '%s' in FOR (use CREATE first)", ident);
683  }
684  else {
685  err = var.write(formatted("%li", fd.forval));
686  fd.forstr = strdup(ident);
687  }
688  }
689  // cppcheck-suppress memleak (fd.forstr is released from Interpreter::do_next)
690  }
691  }
692  else {
693  const char *p = strrchr(ident, '/');
694  const Token *fo = data.find_qualified_token(ident, p ? LOOKUP_LIST : LOOKUP_BLOCK);
695  if (!fo) {
696  nextpc = pc->NEXT->next;
697  }
698  else {
699  for_data& fd = add_for_data_to(pc);
700  fd.forstr = strdup(p ? p+1 : ident);
701  fd.forcursor = data.get_cursor();
702  data.set_cursor(fo);
703  // cppcheck-suppress memleak (fd.forstr is released from Interpreter::do_next)
704  }
705  err = 0;
706  }
707 
708  free(ident);
709  }
710  return err;
711 }
712 
713 int Interpreter::do_next() {
714  // handles NEXT (end of for-loop) and CONTINUE (loop from inside)
715 
716  for_data& fd = *pc->FOR->fd;
717  if (fd.forcursor) {
718  const Token *fo = data.find_token(data.get_cursor(), fd.forstr, LOOKUP_BLOCK_REST);
719  if (fo) {
720  nextpc = pc->FOR->next;
721  data.set_cursor(fo);
722  return 0;
723  }
724  data.set_cursor(fd.forcursor);
725  }
726  else {
727  if (fd.forval < fd.forend) {
728  fd.forval++;
729  nextpc = pc->FOR->next;
730  return get_local(fd.forstr).write(formatted("%li", fd.forval));
731  }
732 
733  }
734  nextpc = pc->FOR->ENDFOR->next;
736  return 0;
737 }
738 
739 // -------------------
740 // Dispatcher
741 
742 typedef int (Interpreter::*NoArgFun)();
743 typedef int (Interpreter::*ArgFun)(const char *);
744 
745 enum CallMode {
747 
748  // bit values:
753 };
754 
755 const int DISPATCH_LIMIT = 5000000; // abort after 5mio dispatches to one command-type (DEBUG only)
756 
757 struct Command {
758  virtual ~Command() {}
759  virtual bool matches(const char *code) const = 0;
760  virtual int call(Interpreter& interpret) const = 0;
761 
762  const Location& pc() const {
763  return Interpreter::instance->at()->source;
764  }
765 };
766 struct NoSuchCommand : public Command {
767  bool matches(const char *) const OVERRIDE { return true; } // catch all
769  printf_error(interpret.at(), "Unknown command '%s'", interpret.at()->str);
770  return -1; // bail out
771  }
772 };
773 class NamedCommand : public Command, virtual Noncopyable {
774  const char *name;
775  int len;
776  mutable int dispatched;
777 protected:
778  virtual int check_result(int res, char *evaluated_args) const {
779  dispatched++;
780  if (dispatched>DISPATCH_LIMIT) {
781  print_error(&pc(), "possible deadlock detected");
782  res = -1;
783  }
784 #if defined(TRACE)
785  pc().start_message("TRACE");
786  if (res) fprintf(stderr, "[result=%i]", res);
787  fputs(name, stderr);
788  if (evaluated_args) {
789  fputc(' ', stderr);
790  fputs(evaluated_args, stderr);
791  }
792  fputc('\n', stderr);
793 
794 #endif
795  free(evaluated_args);
796  return res;
797  }
798 public:
799  NamedCommand(const char *cmd) : name(cmd), len(strlen(name)), dispatched(0) {}
800  bool matches(const char *code) const OVERRIDE { return strncmp(code, name, len) == 0; }
801  int length() const { return len; }
802 };
803 
804 class SimpleCmmd FINAL_TYPE : public NamedCommand {
805  NoArgFun fun;
806 public:
807  SimpleCmmd(const char *cmd, NoArgFun fun_) : NamedCommand(cmd), fun(fun_) {}
809  return check_result((interpret.*fun)(), NULp);
810  }
811 };
812 
813 class ArgCommand FINAL_TYPE : public NamedCommand {
814  ArgFun fun;
815  CallMode emode;
816 
817  char *eval(Interpreter& interpret, bool& failed) const {
818  int offset = length();
819  if (!(emode&EVAL_PLAIN)) offset++;
820 
821  if (emode & DONT_EVAL) {
822  failed = false;
823  return strdup(interpret.at()->str+offset);
824  }
825 
826  Expression expr(interpret.get_data(), interpret.at()->source, interpret.at()->str+offset, false);
827  return (emode&EVAL_VAR_DECL)
828  ? expr.evalVarDecl(failed)
829  : expr.evaluate(failed);
830  }
831  int check_result(int res, char *evaluated_args) const OVERRIDE {
832  return NamedCommand::check_result(res && (emode&TERMINATED_ON_ERROR) ? -1 : res, evaluated_args);
833  }
834 
835 public:
836  ArgCommand(const char *cmd, ArgFun fun_, CallMode emode_ = STANDARD_CALL)
837  : NamedCommand(cmd), fun(fun_), emode(emode_) {}
838  int call(Interpreter& interpret) const OVERRIDE {
839  int res = 1;
840  bool eval_failed;
841  char *args = eval(interpret, eval_failed);
842  if (args && !eval_failed) {
843  char *trimmed = args;
844  if (!(emode&EVAL_PLAIN)) SKIP_SPACE_LF(trimmed);
845 
846  res = (interpret.*fun)(trimmed);
847  }
848  else {
849  print_error(interpret.at(), "Failed to evaluate arguments");
850  res = -1;
851  }
852  return check_result(res, args);
853  }
854 };
855 
856 
857 void Interpreter::command_table_setup(bool setup) {
858  if (setup) {
859  command_table = new Command*[MAX_COMMANDS+1];
860 
861  int i = 0;
862 
863  command_table[i++] = new ArgCommand("MOVETO", &Interpreter::do_moveto, EVAL_VAR_DECL);
864  command_table[i++] = new ArgCommand("SET", &Interpreter::do_set, EVAL_VAR_DECL);
865  command_table[i++] = new ArgCommand("CONST", &Interpreter::do_makeconst, EVAL_VAR_DECL);
866  command_table[i++] = new ArgCommand("CREATE", &Interpreter::do_create, EVAL_VAR_DECL);
867 
868  command_table[i++] = new ArgCommand("PRINT", &Interpreter::do_write_current, EVAL_PLAIN);
869  command_table[i++] = new ArgCommand("P ", &Interpreter::do_write_current, EVAL_PLAIN);
870  command_table[i++] = new ArgCommand("PP", &Interpreter::do_write_stdout);
871  command_table[i++] = new SimpleCmmd("--", &Interpreter::do_newline);
872  command_table[i++] = new SimpleCmmd("PMSTART", &Interpreter::do_write_maybe_start);
873  command_table[i++] = new SimpleCmmd("PMEND", &Interpreter::do_write_maybe_end);
874  command_table[i++] = new ArgCommand("PM", &Interpreter::do_write_maybe);
875 
876  command_table[i++] = new ArgCommand("GOSUB", &Interpreter::do_gosub, DONT_EVAL);
877  command_table[i++] = new ArgCommand("CALL", &Interpreter::do_gosub, DONT_EVAL);
878  command_table[i++] = new ArgCommand("GOTO", &Interpreter::do_goto);
879  command_table[i++] = new SimpleCmmd("RETURN", &Interpreter::do_return);
880  command_table[i++] = new SimpleCmmd("PUSH", &Interpreter::do_push);
881  command_table[i++] = new SimpleCmmd("POP", &Interpreter::do_pop);
882  command_table[i++] = new SimpleCmmd("CONTINUE", &Interpreter::do_next);
883 
884  command_table[i++] = new ArgCommand("OPEN", &Interpreter::do_open, TERMINATED_ON_ERROR);
885  command_table[i++] = new ArgCommand("CLOSE", &Interpreter::do_close);
886  command_table[i++] = new ArgCommand("OUT", &Interpreter::do_out, TERMINATED_ON_ERROR);
887 
888  command_table[i++] = new ArgCommand("INDENT", &Interpreter::do_indent);
889  command_table[i++] = new ArgCommand("TABSTOP", &Interpreter::do_tabstop);
890  command_table[i++] = new ArgCommand("TAB", &Interpreter::do_tab);
891  command_table[i++] = new SimpleCmmd("EXIT", &Interpreter::do_exit);
892 
893  command_table[i++] = new ArgCommand("DATA", &Interpreter::do_data, TERMINATED_ON_ERROR);
894  command_table[i++] = new ArgCommand("DUMPDATA", &Interpreter::do_dumpdata, TERMINATED_ON_ERROR);
895  command_table[i++] = new ArgCommand("ERROR", &Interpreter::do_error, TERMINATED_ON_ERROR);
896  command_table[i++] = new ArgCommand("WARNING", &Interpreter::do_warning);
897 
898  command_table[i++] = new NoSuchCommand; // should be last!
899  command_table[i++] = NULp;
900 
901  aisc_assert(i<MAX_COMMANDS);
902  }
903  else { // cleanup
904  for (int i = 0; command_table[i]; ++i) delete command_table[i];
905  delete [] command_table;
906  }
907 }
908 
909 const Command *Interpreter::find_command(const Code *co) {
910  for (int c = 0; command_table[c]; ++c) {
911  const Command& cmd = *command_table[c];
912  if (cmd.matches(co->str)) {
913  return &cmd;
914  }
915  }
916  aisc_assert(0); // NoSuchCommand missing ?
917  return NULp;
918 }
919 
920 int Interpreter::run_program() {
921  parser.set_source(prg->source.get_path(), 1);
922 
923  for (pc = prg; pc; pc = nextpc) {
924  nextpc = pc->next;
925 
926  switch (pc->command) {
927  case CT_IF: {
928  Expression expr(data, pc->source, pc->str, true);
929  bool eval_failed;
930  char *val = expr.evaluate(eval_failed);
931  int err = eval_failed;
932  if (!err) err = do_if(val); // execute even if 'val' is NULp!
933  free(val);
934  if (err) return err;
935  break;
936  }
937 
938  case CT_ELSE:
939  nextpc = pc->IF->ENDIF->next;
940  case CT_ENDIF:
941  break;
942 
943  case CT_FOR: {
944  Expression expr(data, pc->source, pc->str, false);
945  bool eval_failed;
946  char *val = expr.evalVarDecl(eval_failed);
947  bool abort = !val || eval_failed || do_for(val);
948  free(val);
949  if (abort) return 1;
950  break;
951  }
952 
953  case CT_NEXT:
954  if (do_next()) return 1;
955  case CT_ENDFOR:
956  break;
957 
958  case CT_FUNCTION:
959  print_error(at(), "fatal: ran into FUNCTION (missing EXIT?)");
960  break;
961 
962  break;
963 
964  case CT_OTHER_CMD: {
965  int res = pc->cmd->call(*this);
966  if (res == -1) return 1;
967  break;
968  }
969 
970  case CT_LABEL:
971  case CT_ELSEIF:
972  case NO_COMMAND:
973  printf_error(at(), "internal error: Expected not to reach command type=%i", pc->command);
974  return 1;
975  }
976 
977  if (!nextpc) { // end of execution ?
979  }
980  }
981  return Location::get_error_count();
982 }
983 
void set_cursor(const Token *newCursor)
Location source
Definition: aisc_parser.h:39
#define STACKSIZE
Definition: aisc_def.h:21
int(Interpreter::* NoArgFun)()
char * copy_string_part(const char *first, const char *last)
Definition: aisc_inline.h:49
virtual int check_result(int res, char *evaluated_args) const
string result
const Token * cursor
const char * get_path() const
Definition: aisc_location.h:44
AliDataPtr format(AliDataPtr data, const size_t wanted_len, GB_ERROR &error)
Definition: insdel.cxx:615
const Code * at() const
LookupScope
Definition: aisc_def.h:23
ArgParser(const char *arguments, const Code *co)
for_data & add_for_data_to(const Code *co)
void set_indent(int indent_)
bool matches(const char *) const
CONSTEXPR_INLINE bool is_SEP_LF_EOS(char c)
Definition: aisc_inline.h:30
void set_tab(int idx, int pos)
bool valid() const
Definition: aisc_location.h:42
static char errbuf[ERRBUF_SIZE]
Definition: client.c:48
static int interpret
Definition: arb_a2ps.c:266
static const Interpreter * instance
const char * formatted(const char *format,...)
Definition: aisc_commands.c:65
void write(const char *key, const char *val)
Definition: aisc_mix.c:242
int get_indent() const
Code * IF
Definition: aisc_parser.h:46
int write(const char *val) __ATTR__USERESULT
const Token * get_cursor() const
bool matches(const char *code) const OVERRIDE
char * str
Definition: aisc_parser.h:37
char buffer[MESSAGE_BUFFERSIZE]
Definition: seq_search.cxx:34
ArgCommand(const char *cmd, ArgFun fun_, CallMode emode_=STANDARD_CALL)
void close()
static HelixNrInfo * start
NamedCommand(const char *cmd)
void remove_for_data_from(const Code *co)
void write_protect()
static int diff(int v1, int v2, int v3, int v4, int st, int en)
Definition: ClustalV.cxx:534
static int get_error_count()
Definition: aisc_location.h:61
const Token * find_token(const Token *curs, const char *str, LookupScope scope) const
Definition: aisc_var_ref.c:81
#define ERRBUFSIZE
Definition: aisc_commands.c:64
const Token * forcursor
const int DISPATCH_LIMIT
var_ref get_local(const char *key)
Definition: aisc_mix.c:258
int chars
Definition: seq_search.cxx:38
#define print_error(code_or_loc, err)
Definition: aisc_def.h:47
Code * FOR
Definition: aisc_parser.h:49
const TokenList * next_list() const
Definition: aisc_token.h:110
const TokenList * first_list() const
Definition: aisc_token.h:140
int call(Interpreter &interpret) const OVERRIDE
char * forstr
static void announce_exit_pc(const Location &exitingHere)
Definition: aisc_location.h:59
fputc('\n', stderr)
char * str
Definition: defines.h:20
ArgParser(const char *arguments, const Location &loc_)
char * key
const Command * cmd
Definition: aisc_parser.h:42
Stack * next
CallMode
Code * ENDFOR
Definition: aisc_parser.h:51
Code * next
Definition: aisc_parser.h:36
SimpleCmmd(const char *cmd, NoArgFun fun_)
char * evalVarDecl(bool &failed)
Definition: aisc_eval.h:80
vfprintf(stderr, format, parg)
for_data * next
CONSTEXPR_INLINE bool is_SPACE_SEP_LF_EOS(char c)
Definition: aisc_inline.h:28
static const Location & guess_pc()
Definition: aisc_commands.c:17
#define OPENFILES
Definition: aisc_def.h:19
char * get_ident(const char *&code, const Code *at)
int call(Interpreter &interpret) const OVERRIDE
virtual bool matches(const char *code) const =0
va_end(argPtr)
#define EXIT_FAILURE
Definition: arb_a2ps.c:157
const Token * next_token() const
Definition: aisc_token.h:72
const char * read(const char *key) const
struct for_data * fd
Definition: aisc_parser.h:44
void SKIP_SPACE_LF_BACKWARD(const char *&var, const char *strStart)
Definition: aisc_inline.h:35
virtual ~Command()
fputs(TRACE_PREFIX, stderr)
hash * hs
xml element
const Code * pc
Definition: output.h:122
#define OVERRIDE
Definition: cxxforward.h:93
char * evaluate(bool &failed)
Definition: aisc_eval.h:76
Code * NEXT
Definition: aisc_parser.h:50
#define HASHSIZE
Definition: aisc_def.h:20
void set_source(const Location &other)
Definition: aisc_parser.h:200
va_start(argPtr, format)
const Data & get_data() const
#define printf_error(code_or_loc, format, arg)
Definition: aisc_def.h:50
#define NULp
Definition: cxxforward.h:97
virtual int call(Interpreter &interpret) const =0
#define offset(field)
Definition: GLwDrawA.c:73
int length() const
static ED4_block block
Definition: ED4_block.cxx:73
void set_tabstop(int ts)
int(Interpreter::* ArgFun)(const char *)
void start_message(const char *prefix) const
Definition: aisc_location.h:54
CommandType command
Definition: aisc_parser.h:41
const TokenListBlock * get_tokens() const
void dump_cursor_pos(FILE *out) const
Definition: aisc_var_ref.c:281
#define aisc_assert(cond)
Definition: aisc_def.h:11
static void write_aisc(const TokenListBlock *block, FILE *out, int indentation)
Definition: aisc_commands.c:92
Code * ENDIF
Definition: aisc_parser.h:48
void print_tabs(int count, FILE *out)
Definition: aisc_commands.c:88
void SKIP_SPACE_LF(const char *&var)
Definition: aisc_inline.h:32
const Token * find_qualified_token(const char *str, LookupScope scope) const
Definition: aisc_var_ref.c:121
Definition: output.h:28
const Location & pc() const
GB_write_int const char s
Definition: AW_awar.cxx:156