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>
24 #include <ctype.h>
25
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
GNU Bayonne library namespace.