Bayonne 3 - API
 All Classes Namespaces Files Functions Variables Typedefs Macros
checks.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-2011 David Sugar, Tycho Softworks.
4 //
5 // This file is part of GNU Bayonne.
6 //
7 // GNU Bayonne is free software; you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation; either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // GNU Bayonne is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with GNU Bayonne. If not, see <http://www.gnu.org/licenses/>.
19 
20 #include <config.h>
21 #include <ucommon/ucommon.h>
22 #include <ucommon/export.h>
23 #include <bayonne.h>
24 #include <ctype.h>
25 
26 using namespace BAYONNE_NAMESPACE;
27 using namespace UCOMMON_NAMESPACE;
28 
29 static const char *getArgument(Script::line_t *line, unsigned *index)
30 {
31  const char *cp;
32 
33  for(;;) {
34  if(*index >= line->argc)
35  return NULL;
36  cp = line->argv[*index];
37  ++*index;
38  if(*cp == '=') {
39  ++*index;
40  continue;
41  }
42  return cp;
43  }
44 }
45 
46 static const char *getKeyword(const char *kw, Script::line_t *line)
47 {
48  unsigned index = 0;
49  const char *cp;
50 
51  while(index < line->argc) {
52  cp = line->argv[index++];
53  if(*cp == '=' && eq(kw, ++cp))
54  return line->argv[index];
55  }
56  return NULL;
57 }
58 
59 static unsigned getArguments(Script::line_t *line)
60 {
61  unsigned count = 0;
62  unsigned index = 0;
63  const char *cp;
64 
65  while(index < line->argc) {
66  cp = line->argv[index++];
67  if(*cp == '=') {
68  ++index;
69  continue;
70  }
71  ++count;
72  }
73  return count;
74 }
75 
76 static unsigned getRequired(Script::line_t *line)
77 {
78  unsigned count = 0;
79  unsigned index = 0;
80  const char *cp;
81 
82  while(index < line->argc) {
83  cp = line->argv[index++];
84  if(*cp == '=') {
85  ++index;
86  continue;
87  }
88  if(eq(cp, "required"))
89  ++count;
90  }
91  return count;
92 }
93 
94 bool Script::checks::isText(const char *text)
95 {
96  while(*text) {
97  if(!isalnum(*text))
98  return false;
99  ++text;
100  }
101  return true;
102 }
103 
104 bool Script::checks::isValue(const char *text)
105 {
106  switch(*text)
107  {
108  case '-':
109  case '+':
110  if(text[1] == '.')
111  return true;
112  case '.':
113  if(isdigit(text[1]))
114  return true;
115  return false;
116  case '0':
117  case '1':
118  case '2':
119  case '3':
120  case '4':
121  case '5':
122  case '6':
123  case '7':
124  case '8':
125  case '9':
126  case '&':
127  case '%':
128  case '$':
129  return true;
130  default:
131  return false;
132  }
133 }
134 
135 const char *Script::checks::chkApply(Script *img, Script::header *scr, Script::line_t *line)
136 {
137  if(line->argc < 1)
138  return "template define script required";
139 
140  if(line->argc > 1)
141  return "only one template define can be applied";
142 
143  if(scr->first)
144  return "apply must be first statement of a new script";
145 
146  if(scr->events)
147  return "only one apply statement can be used";
148 
149  if(!isalnum(line->argv[0][0]))
150  return "must apply using valid name of a defined script";
151 
152  Script::header *tmp = Script::find(img, line->argv[0]);
153  if(!tmp)
154  return "invalid or unknown script applied";
155 
156  scr->methods = tmp->methods;
157  scr->events = tmp->events;
158  return NULL;
159 }
160 
161 const char *Script::checks::chkPrevious(Script *img, Script::header *scr, Script::line_t *line)
162 {
163  method_t method = img->looping();
164 
165  if(method == (method_t)NULL)
166  return "cannot be called outside loop";
167 
168  if(method == (method_t)&Script::methods::scrForeach)
169  goto valid;
170 
171  return "cannot be called outside for or foreach block";
172 
173 valid:
174  if(line->argc)
175  return "command has no arguments";
176 
177  return NULL;
178 }
179 
180 const char *Script::checks::chkContinue(Script *img, Script::header *scr, Script::line_t *line)
181 {
182  method_t method = img->looping();
183 
184  if(method == (method_t)NULL)
185  return "cannot be called outside loop";
186 
187  if(method == (method_t)&Script::methods::scrDo)
188  goto valid;
189 
190  if(method == (method_t)&Script::methods::scrWhile)
191  goto valid;
192 
193  if(method == (method_t)&Script::methods::scrForeach)
194  goto valid;
195 
196  return "cannot be called from conditional block";
197 
198 valid:
199  if(line->argc)
200  return "command has no arguments";
201 
202  return NULL;
203 }
204 
205 const char *Script::checks::chkStrict(Script *img, Script::header *scr, Script::line_t *line)
206 {
207  unsigned index = 0;
208  const char *cp;
209 
210  if(!eq(scr->name, "_init_"))
211  return "strict can only be used in initialization section";
212 
213  if(scr->first)
214  return "strict must be defined at start of initialization section";
215 
216  if(!line->argc) {
217  Script::strict::createGlobal(img, "error");
218  Script::strict::createGlobal(img, "index");
219  return NULL;
220  }
221 
222  while(index < line->argc) {
223  cp = line->argv[index++];
224  if(!isalpha(*cp))
225  return "strict must only declare names of defined internal global vars";
226  Script::strict::createGlobal(img, cp);
227  }
228  return NULL;
229 }
230 
231 const char *Script::checks::chkBreak(Script *img, Script::header *scr, Script::line_t *line)
232 {
233  method_t method = img->looping();
234 
235  if(method == (method_t)NULL)
236  return "cannot be called outside loop";
237 
238  if(line->argc)
239  return "command has no arguments";
240 
241  return NULL;
242 }
243 
244 const char *Script::checks::chkRef(Script *img, Script::header *scr, Script::line_t *line)
245 {
246  if(line->argc != 1)
247  return "one symbol argument for referencing";
248 
249  const char *cp = line->argv[0];
250  if(*cp != '$')
251  return "only field operations can be referenced alone";
252 
253  return NULL;
254 }
255 
256 const char *Script::checks::chkWhen(Script *img, Script::header *scr, Script::line_t *line)
257 {
258  if(!line->argc)
259  return "missing conditional expression";
260 
261  return chkConditional(img, scr, line);
262 }
263 
264 const char *Script::checks::chkIf(Script *img, Script::header *scr, Script::line_t *line)
265 {
266  if(!img->push(line))
267  return "analysis overflow for if command";
268 
269  if(img->thencheck)
270  return "cannot nest if in if-then clause";
271 
272  return chkConditional(img, scr, line);
273 }
274 
275 const char *Script::checks::chkWhile(Script *img, Script::header *scr, Script::line_t *line)
276 {
277  if(eq(scr->name, "_init_"))
278  return "this command cannot be used to initialize";
279 
280  if(img->thencheck)
281  return "cannot use while in if-then clause";
282 
283  if(!img->push(line))
284  return "stack overflow for while command";
285 
286  return chkConditional(img, scr, line);
287 }
288 
289 const char *Script::checks::chkExpand(Script *img, Script::header *scr, Script::line_t *line)
290 {
291  unsigned index = 1;
292  const char *cp;
293 
294  if(line->argc < 1)
295  return "no value to expand";
296 
297  if(line->argc < 2)
298  return "no symbols to assign";
299 
300  if(!isValue(line->argv[0]))
301  return "cannot expand non-value";
302 
303  while(line->argv[index]) {
304  cp = line->argv[0];
305  switch(*cp) {
306  case '&':
307  return "cannot assign literal";
308  case '=':
309  return "no keywords are used in this command";
310  case '$':
311  return "cannot assign to format";
312  case '@':
313  return "cannot assign to label";
314  case '^':
315  return "cannot assign to event";
316  case '?':
317  return "cannot assign to expression";
318  }
319  strict::createAny(img, scr, line->argv[index++]);
320  }
321  return NULL;
322 }
323 
324 const char *Script::checks::chkForeach(Script *img, Script::header *scr, Script::line_t *line)
325 {
326  const char *cp;
327 
328  if(eq(scr->name, "_init_"))
329  return "this command cannot be used to initialize";
330 
331  if(img->thencheck)
332  return "cannot use for in if-then clause";
333 
334  if(!img->push(line))
335  return "stack overflow for do command";
336 
337  if(!line->argc)
338  return "no symbols to assign";
339 
340  if(line->argc < 2 || line->argc > 3)
341  return "assign from only one source";
342 
343  cp = line->argv[0];
344  switch(*cp) {
345  case '&':
346  return "cannot assign literal";
347  case '=':
348  return "no keywords are used in this command";
349  case '$':
350  return "cannot assign to format";
351  case '@':
352  return "cannot assign to label";
353  case '^':
354  return "cannot assign to event";
355  case '?':
356  return "cannot assign to expression";
357  }
358  strict::createAny(img, scr, line->argv[0]);
359 
360  if(!isValue(line->argv[1]))
361  return "cannot assign from label or expression";
362 
363  if(line->argc == 3 && !isValue(line->argv[2]))
364  return "skip must be a value or symbol";
365 
366  return NULL;
367 }
368 
369 const char *Script::checks::chkDo(Script *img, Script::header *scr, Script::line_t *line)
370 {
371  if(eq(scr->name, "_init_"))
372  return "this command cannot be used to initialize";
373 
374  if(img->thencheck)
375  return "cannot use do in if-then clause";
376 
377  if(line->argc)
378  return "no arguments for do command";
379 
380  if(!img->push(line))
381  return "stack overflow for do command";
382 
383  return NULL;
384 }
385 
386 const char *Script::checks::chkEndif(Script *img, Script::header *scr, Script::line_t *line)
387 {
388  Script::method_t method = img->pull();
389 
390  if(img->thencheck)
391  return "cannot endif in if-then clause";
392 
393  if(method != (method_t)&Script::methods::scrIf && method != (method_t)&Script::methods::scrElse)
394  return "endif not within an if block";
395 
396  if(line->argc)
397  return "endif has no arguments";
398 
399  return NULL;
400 }
401 
402 const char *Script::checks::chkEndcase(Script *img, Script::header *scr, Script::line_t *line)
403 {
404  Script::method_t method = img->pull();
405 
406  if(img->thencheck)
407  return "cannot endcase in if-then clause";
408 
409  if(eq(scr->name, "_init_"))
410  return "this command cannot be used to initialize";
411 
412  if(method != (method_t)&Script::methods::scrCase && method != (method_t)&Script::methods::scrOtherwise)
413  return "endcase not within a case block";
414 
415  if(line->argc)
416  return "endcase has no arguments";
417 
418  --line->loop;
419  return NULL;
420 }
421 
422 const char *Script::checks::chkLoop(Script *img, Script::header *scr, Script::line_t *line)
423 {
424  Script::method_t method = img->pull();
425 
426  if(img->thencheck)
427  return "can not end loop in if-then clause";
428 
429  if(eq(scr->name, "_init_"))
430  return "this command cannot be used to initialize";
431 
432  if(method == (method_t)&Script::methods::scrWhile)
433  goto valid;
434 
435  if(method == (method_t)&Script::methods::scrDo)
436  goto valid;
437 
438  if(method == (method_t)&Script::methods::scrForeach)
439  goto valid;
440 
441  if(method == (method_t)NULL)
442  return "not called from within loop";
443 
444  return "not called from valid loop";
445 
446 valid:
447  if(line->argc)
448  return "loop has no arguments";
449 
450  return NULL;
451 }
452 
453 const char *Script::checks::chkCase(Script *img, Script::header *scr, Script::line_t *line)
454 {
455  Script::method_t method = img->looping();
456 
457  if(img->thencheck)
458  return "cannot create case in if-then clause";
459 
460  if(eq(scr->name, "_init_"))
461  return "this command cannot be used to initialize";
462 
463  if(method == (method_t)&Script::methods::scrOtherwise)
464  return "cannot have case after otherwise";
465 
466  if(method != (method_t)&Script::methods::scrCase) {
467  if(!img->push(line))
468  return "stack overflow for do command";
469  }
470  else {
471  img->pull();
472  img->push(line);
473  --line->loop;
474  }
475 
476  return chkConditional(img, scr, line);
477 }
478 
479 const char *Script::checks::chkElif(Script *img, Script::header *scr, Script::line_t *line)
480 {
481  Script::method_t method = img->looping();
482 
483  if(img->thencheck)
484  return "cannot have elif in if-then clause";
485 
486  if(method == (method_t)&Script::methods::scrElse) {
487  return "cannot have more if conditions after else";
488  }
489 
490  if(method != (method_t)&Script::methods::scrIf) {
491  return "cannot have elif outside of if block";
492  }
493 
494  return chkConditional(img, scr, line);
495 }
496 
497 const char *Script::checks::chkElse(Script *img, Script::header *scr, Script::line_t *line)
498 {
499  Script::method_t method = img->looping();
500 
501  if(img->thencheck)
502  return "cannot have else in if-then clause";
503 
504  if(method == (method_t)&Script::methods::scrElse) {
505  return "cannot have multiple else statements";
506  }
507 
508  if(method != (method_t)&Script::methods::scrIf) {
509  return "cannot have else outside of if block";
510  }
511 
512  // replace loop with else member to prevent duplication...
513  img->pull();
514  img->push(line);
515 
516  if(line->argc)
517  return "otherwise has no arguments";
518 
519  return NULL;
520 }
521 
522 const char *Script::checks::chkOtherwise(Script *img, Script::header *scr, Script::line_t *line)
523 {
524  Script::method_t method = img->looping();
525 
526  if(img->thencheck)
527  return "cannot have otherwise if-then clause";
528 
529  if(eq(scr->name, "_init_"))
530  return "this command cannot be used to initialize";
531 
532  if(method != (method_t)&Script::methods::scrCase) {
533  return "cannot have otherwise outside of case block";
534  }
535 
536  // replace loop with otherwise member to prevent duplication...
537  img->pull();
538  img->push(line);
539  --line->loop;
540 
541  if(line->argc)
542  return "otherwise has no arguments";
543 
544  return NULL;
545 }
546 
547 const char *Script::checks::chkUntil(Script *img, Script::header *scr, Script::line_t *line)
548 {
549  Script::method_t method = img->pull();
550 
551  if(img->thencheck)
552  return "cannot have until in if-then clause";
553 
554  if(eq(scr->name, "_init_"))
555  return "this command cannot be used to initialize";
556 
557  if(method == (method_t)NULL || method != (method_t)&Script::methods::scrDo)
558  return "not called from within do loop";
559 
560  return chkConditional(img, scr, line);
561 }
562 
563 const char *Script::checks::chkNop(Script *img, Script::header *scr, Script::line_t *line)
564 {
565  if(line->argc)
566  return "arguments are not used for this command";
567 
568  return NULL;
569 }
570 
571 const char *Script::checks::chkExit(Script *img, Script::header *scr, Script::line_t *line)
572 {
573  if(line->argc)
574  return "arguments are not used for this command";
575 
576  if(eq(scr->name, "_init_"))
577  return "this command cannot be used to initialize";
578 
579  return NULL;
580 }
581 
582 const char *Script::checks::chkInvoke(Script *img, Script::header *scr, Script::line_t *line)
583 {
584  Script::line_t *sub = line->sub->first;
585  unsigned required = getRequired(sub);
586  unsigned limit = getArguments(sub);
587  unsigned count = getArguments(line);
588  unsigned index = 0;
589  const char *cp, *kw;
590 
591  if(eq(scr->name, "_init_"))
592  return "this command cannot be used to initialize";
593 
594  if(count < required)
595  return "too few arguments for invoked command";
596 
597  if(count > limit)
598  return "too many arguments for invoked command";
599 
600  index = 0;
601  while(index < sub->argc) {
602  kw = sub->argv[index++];
603  if(*kw == '=') {
604  cp = sub->argv[index++];
605  if(eq(cp, "required") && !getKeyword(++kw, line))
606  return "required keyword missing";
607  }
608  }
609  index = 0;
610  while(index < line->argc) {
611  kw = line->argv[index++];
612  if(*kw == '=') {
613  if(!getKeyword(++kw, sub))
614  return "unknown or invalid keyword used";
615  ++index;
616  }
617  }
618  return NULL;
619 }
620 
621 const char *Script::checks::chkDefine(Script *img, Script::header *scr, Script::line_t *line)
622 {
623  unsigned count = 0;
624  unsigned index = 0;
625  const char *cp;
626  char idbuf[8];
627 
628  if(img->thencheck)
629  return "cannot define in if-then clause";
630 
631  if(!line->argc)
632  return NULL;
633 
634  while(index < line->argc) {
635  cp = line->argv[index++];
636  if(*cp == '=') {
637  if(strchr(cp, ':'))
638  return "no size or type set for referencing";
639  strict::createVar(img, scr, cp);
640  continue;
641  }
642 
643  if(isalpha(*cp)) {
644  if(eq(cp, "optional"))
645  line->argv[index - 1] = (char *)"&"; // rewrite to null
646  else if(!eq(cp, "required"))
647  return "invalid keyword used in prototype";
648  }
649  else if(!isValue(cp))
650  return "cannot assign from label or expression";
651 
652  if(img->isStrict()) {
653  snprintf(idbuf, sizeof(idbuf), "%d", ++count);
654  strict::createVar(img, scr, img->dup(idbuf));
655  }
656  }
657 
658  return NULL;
659 }
660 
661 const char *Script::checks::chkPack(Script *img, Script::header *scr, Script::line_t *line)
662 {
663  unsigned index = 1;
664  const char *cp;
665 
666  if(!line->argc)
667  return "no symbols to assign";
668 
669  if(line->argc < 2)
670  return "no values to assign";
671 
672  cp = line->argv[0];
673  switch(*cp) {
674  case '&':
675  return "cannot assign literal";
676  case '=':
677  return "cannot assign members before symbol name";
678  case '$':
679  return "cannot assign to format";
680  case '@':
681  return "cannot assign to label";
682  case '^':
683  return "cannot assign to event";
684  case '?':
685  return "cannot assign to expression";
686  }
687 
688  Script::strict::createAny(img, scr, cp);
689 
690  while(index < line->argc) {
691  cp = line->argv[index++];
692  if(*cp == '=')
693  continue;
694  if(!isValue(cp))
695  return "cannot assign from label or expression";
696  }
697 
698  return NULL;
699 }
700 
701 const char *Script::checks::chkPush(Script *img, Script::header *scr, Script::line_t *line)
702 {
703  const char *cp;
704 
705  if(line->argc < 1)
706  return "no symbol to push";
707 
708  if(line->argc > 3)
709  return "only use value or key and value";
710 
711  cp = line->argv[0];
712  switch(*cp) {
713  case '&':
714  return "cannot assign literal";
715  case '=':
716  return "no keywords are used in this command";
717  case '$':
718  return "cannot assign to format";
719  case '@':
720  return "cannot assign to label";
721  case '^':
722  return "cannot assign to event";
723  case '?':
724  return "cannot assign to expression";
725  }
726  Script::strict::createSym(img, scr, cp);
727  if(!isValue(line->argv[1]) && !isText(line->argv[1]))
728  return "cannot push from label or expression";
729 
730  if(line->argv[2] && !isValue(line->argv[2]) && !isText(line->argv[1]))
731  return "cannot push value from label or expression";
732 
733  return NULL;
734 }
735 
736 const char *Script::checks::chkSet(Script *img, Script::header *scr, Script::line_t *line)
737 {
738  unsigned drop = 0;
739  unsigned index = 1;
740  const char *cp;
741 
742  if(!line->argc)
743  return "no symbols to assign";
744 
745  if(line->argc > 2) {
746  if(eq(line->argv[1], ":="))
747  drop = 1;
748  else if(eq(line->argv[1], "+=")) {
749  drop = 1;
750  line->method = (method_t)&methods::scrAdd;
751  }
752  }
753 
754  if(drop) {
755  --line->argc;
756  while(drop && drop < line->argc) {
757  line->argv[drop] = line->argv[drop + 1];
758  ++drop;
759  }
760  line->argv[drop] = NULL;
761  }
762 
763  if(line->argc < 2)
764  return "no values to assign";
765 
766  cp = line->argv[0];
767  switch(*cp) {
768  case '&':
769  return "cannot assign literal";
770  case '=':
771  return "no keywords are used in this command";
772  case '$':
773  return "cannot assign to format";
774  case '@':
775  return "cannot assign to label";
776  case '^':
777  return "cannot assign to event";
778  case '?':
779  return "cannot assign to expression";
780  }
781 
782  Script::strict::createSym(img, scr, cp);
783 
784  while(index < line->argc) {
785  cp = line->argv[index++];
786  if(*cp == '=')
787  return "no keywords are used in this command";
788  if(!isValue(cp))
789  return "cannot assign to format";
790  }
791  return NULL;
792 }
793 
794 const char *Script::checks::chkClear(Script *img, Script::header *scr, Script::line_t *line)
795 {
796  unsigned index = 0;
797  const char *cp;
798 
799  if(!line->argc)
800  return "no symbols to clear";
801 
802  while(index < line->argc) {
803  cp = line->argv[index++];
804  if(*cp != '%')
805  return "invalid symbol reference or syntax";
806  if(strchr(cp, ':'))
807  return "invalid size usage for symbol";
808  }
809  return NULL;
810 }
811 
812 const char *Script::checks::chkError(Script *img, Script::header *scr, Script::line_t *line)
813 {
814  unsigned index = 0;
815  const char *cp;
816 
817  if(!line->argc)
818  return "no error message";
819 
820  while(index < line->argc) {
821  cp = line->argv[index++];
822  if(*cp == '=')
823  return "no keywords used in error";
824 
825  if(*cp == '^' || *cp == '@')
826  return "cannot use label for error";
827  }
828  return NULL;
829 }
830 
831 const char *Script::checks::chkConst(Script *img, Script::header *scr, Script::line_t *line)
832 {
833  unsigned index = 0;
834  const char *cp;
835 
836  if(!line->argc)
837  return "no constants to assign";
838 
839  while(index < line->argc) {
840  cp = line->argv[index++];
841  if(*cp != '=')
842  return "cannot assign data or use uninitialized symbol as const";
843 
844  if(strchr(cp, ':'))
845  return "cannot alter size of const symbol";
846 
847  Script::strict::createVar(img, scr, cp);
848 
849  cp = line->argv[index++];
850  if(*cp == '=')
851  return "invalid assignment of const";
852  if(!isValue(cp))
853  return "cannot use label or expression for const";
854  }
855  return NULL;
856 }
857 
858 const char *Script::checks::chkGoto(Script *img, Script::header *scr, Script::line_t *line)
859 {
860  unsigned index = 0;
861  const char *cp;
862 
863  if(eq(scr->name, "_init_"))
864  return "this command cannot be used to initialize";
865 
866  if(line->argc < 1)
867  return "goto requires at least one label or event handler";
868 
869  while(index < line->argc) {
870  cp = line->argv[index++];
871  if(*cp != '@' && *cp != '^')
872  return "goto only allows scripts and handlers";
873  }
874  return NULL;
875 }
876 
877 const char *Script::checks::chkGosub(Script *img, Script::header *scr, Script::line_t *line)
878 {
879  unsigned index = 0;
880  const char *cp;
881 
882  if(eq(scr->name, "_init_"))
883  return "this command cannot be used to initialize";
884 
885  if(line->argc < 1)
886  return "gosub requires at least one label";
887 
888  while(index < line->argc) {
889  cp = line->argv[index++];
890  if(*cp != '@' && !isalnum(*cp))
891  return "gosub only allows script sections and named methods";
892  }
893 
894  return NULL;
895 }
896 
897 const char *Script::checks::chkConditional(Script *img, Script::header *scr, Script::line_t *line)
898 {
899  unsigned index = 0;
900  const char *cp;
901 
902  while(index < line->argc) {
903  cp = line->argv[index++];
904  if((*cp == '-' || *cp == '!') && isalpha(cp[1])) {
905  if(index >= line->argc)
906  return "missing test value";
907  cp = line->argv[index++];
908  if(*cp == '?')
909  return "cannot test operator";
910  }
911  else {
912  if(*cp == '?')
913  return "cannot use operator as element of expression";
914 
915  if(index >= line->argc)
916  return "missing operator in expression";
917 
918  cp = line->argv[index++];
919 
920  if(*cp != '?' && !eq(cp, "eq") && !eq(cp, "ne") && !eq(cp, "lt") && !eq(cp, "gt") && !eq(cp, "le") && !eq(cp, "ge") && !eq(cp, "is") && !eq(cp, "isnot") && !eq(cp, "in") && !eq(cp, "notin"))
921  return "invalid operator in expression";
922 
923  if(index >= line->argc)
924  return "missing value from expression";
925 
926  cp = line->argv[index++];
927  if(*cp == '?')
928  return "cannot use operator as element of expression";
929  }
930  if(index == line->argc)
931  return NULL;
932 
933  cp = line->argv[index++];
934  if(eq("?&&", cp) || eq("?||", cp) || eq("and", cp) || eq("or", cp))
935  continue;
936 
937  return "invalid expression joiner statement";
938  }
939  return "conditional expression missing";
940 }
941 
942 const char *Script::checks::chkIndex(Script *img, Script::header *scr, Script::line_t *line)
943 {
944  unsigned index = 0;
945  const char *cp;
946  method_t method = img->looping();
947 
948  if(method == (method_t)NULL)
949  return "cannot be called outside loop";
950 
951  if(method == (method_t)&Script::methods::scrForeach)
952  goto valid;
953 
954  return "cannot be called outside for or foreach block";
955 
956 valid:
957  if(!line->argc)
958  return "requires at least position";
959 
960  while(index < line->argc) {
961  cp = getArgument(line, &index);
962  if(!isValue(cp))
963  return "malformed expression";
964 
965  cp = getArgument(line, &index);
966  if(!cp)
967  break;
968  if(!eq(cp, "*") && !eq(cp, "/") && !eq(cp, "+") && !eq(cp, "-") && !eq(cp, "#"))
969  return "invalid expression used";
970  if(index == line->argc)
971  return "incomplete expression";
972  }
973 
974  return NULL;
975 }
976 
977 const char *Script::checks::chkExpr(Script *img, Script::header *scr, Script::line_t *line)
978 {
979  unsigned index = 0;
980  const char *cp;
981 
982  if(line->argc < 3)
983  return "no variable to assign";
984 
985  while(index < line->argc) {
986  cp = line->argv[index++];
987  if(*cp == '=') {
988  if(!eq(cp, "=decimals"))
989  return "invalid keyword for expression";
990  ++index;
991  }
992  }
993 
994  index = 0;
995  cp = getArgument(line, &index);
996  if(!cp)
997  return "no assignment";
998 
999  if(*cp == '&')
1000  return "cannot assign literal as symbol";
1001 
1002  if(*cp == '$')
1003  return "cannot assign format as symbol";
1004 
1005  if(*cp == '@' || *cp == '^')
1006  return "cannot assign label as symbol";
1007 
1008  if(*cp == '?')
1009  return "cannot assign expression as symbol";
1010 
1011  Script::strict::createVar(img, scr, cp);
1012 
1013  cp = getArgument(line, &index);
1014  if(!cp)
1015  return "expression incomplete";
1016 
1017  if(!eq(cp, ":=") && !eq(cp, "?=") && !eq(cp, "+=") && !eq(cp, "-=") && !eq(cp, "*=") && !eq(cp, "/="))
1018  return "expression must start with assignment expression";
1019 
1020  while(index < line->argc) {
1021  cp = getArgument(line, &index);
1022  if(!isValue(cp))
1023  return "malformed expression";
1024 
1025  cp = getArgument(line, &index);
1026  if(!cp)
1027  break;
1028  if(!eq(cp, "*") && !eq(cp, "/") && !eq(cp, "+") && !eq(cp, "-") && !eq(cp, "#"))
1029  return "invalid expression used";
1030  if(index == line->argc)
1031  return "incomplete expression";
1032  }
1033  return NULL;
1034 }
1035 
1036 const char *Script::checks::chkVar(Script *img, Script::header *scr, Script::line_t *line)
1037 {
1038  unsigned index = 0;
1039  const char *cp;
1040 
1041  if(!line->argc)
1042  return "no variables to assign";
1043 
1044  while(index < line->argc) {
1045  cp = line->argv[index++];
1046  if(*cp == '&')
1047  return "cannot assign literal as symbol";
1048 
1049  if(*cp == '$')
1050  return "cannot assign format as symbol";
1051 
1052  if(*cp == '@' || *cp == '^')
1053  return "cannot assign label as symbol";
1054 
1055  if(*cp == '?')
1056  return "cannot assign expression as symbol";
1057 
1058  if(*cp != '=')
1059  continue;
1060 
1061  Script::strict::createVar(img, scr, cp);
1062  cp = line->argv[index++];
1063  if(*cp == '=')
1064  return "invalid assignment of variables";
1065  if(!isValue(cp))
1066  return "cannot assign from label or expression";
1067  }
1068  return NULL;
1069 }
1070 
1071 const char *Script::checks::chkIgnore(Script *img, Script::header *scr, Script::line_t *line)
1072 {
1073  return NULL;
1074 }
#define BAYONNE_NAMESPACE
Definition: bayonne.h:25
GNU Bayonne library namespace.