1 package org.sentrysoftware.jawk.frontend;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 import java.io.IOException;
26 import java.io.LineNumberReader;
27 import java.io.PrintStream;
28 import java.lang.reflect.Field;
29 import java.lang.reflect.Modifier;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35
36 import org.sentrysoftware.jawk.NotImplementedError;
37 import org.sentrysoftware.jawk.backend.AVM;
38 import org.sentrysoftware.jawk.ext.JawkExtension;
39 import org.sentrysoftware.jawk.intermediate.Address;
40 import org.sentrysoftware.jawk.intermediate.AwkTuples;
41 import org.sentrysoftware.jawk.intermediate.HasFunctionAddress;
42 import org.sentrysoftware.jawk.jrt.KeyList;
43 import org.sentrysoftware.jawk.util.AwkLogger;
44 import org.sentrysoftware.jawk.util.ScriptSource;
45 import org.slf4j.Logger;
46
47
48
49
50
51
52
53
54
55 public class AwkParser {
56
57 private static final Logger LOG = AwkLogger.getLogger(AwkParser.class);
58
59
60
61
62
63 private interface Breakable {
64 Address breakAddress();
65 }
66
67
68
69
70
71 private interface Nextable {
72 Address nextAddress();
73 }
74
75
76
77
78
79 private interface Continueable {
80 Address continueAddress();
81 }
82
83
84 private static int s_idx = 257;
85
86
87
88 private static final int _EOF_ = s_idx++;
89 private static final int _NEWLINE_ = s_idx++;
90 private static final int _SEMICOLON_ = s_idx++;
91 private static final int _ID_ = s_idx++;
92 private static final int _FUNC_ID_ = s_idx++;
93 private static final int _INTEGER_ = s_idx++;
94 private static final int _DOUBLE_ = s_idx++;
95 private static final int _STRING_ = s_idx++;
96
97 private static final int _EQUALS_ = s_idx++;
98
99 private static final int _AND_ = s_idx++;
100 private static final int _OR_ = s_idx++;
101
102 private static final int _EQ_ = s_idx++;
103 private static final int _GT_ = s_idx++;
104 private static final int _GE_ = s_idx++;
105 private static final int _LT_ = s_idx++;
106 private static final int _LE_ = s_idx++;
107 private static final int _NE_ = s_idx++;
108 private static final int _NOT_ = s_idx++;
109 private static final int _PIPE_ = s_idx++;
110 private static final int _QUESTION_MARK_ = s_idx++;
111 private static final int _COLON_ = s_idx++;
112 private static final int _APPEND_ = s_idx++;
113
114 private static final int _PLUS_ = s_idx++;
115 private static final int _MINUS_ = s_idx++;
116 private static final int _MULT_ = s_idx++;
117 private static final int _DIVIDE_ = s_idx++;
118 private static final int _MOD_ = s_idx++;
119 private static final int _POW_ = s_idx++;
120 private static final int _COMMA_ = s_idx++;
121 private static final int _MATCHES_ = s_idx++;
122 private static final int _NOT_MATCHES_ = s_idx++;
123 private static final int _DOLLAR_ = s_idx++;
124
125 private static final int _INC_ = s_idx++;
126 private static final int _DEC_ = s_idx++;
127
128 private static final int _PLUS_EQ_ = s_idx++;
129 private static final int _MINUS_EQ_ = s_idx++;
130 private static final int _MULT_EQ_ = s_idx++;
131 private static final int _DIV_EQ_ = s_idx++;
132 private static final int _MOD_EQ_ = s_idx++;
133 private static final int _POW_EQ_ = s_idx++;
134
135 private static final int _OPEN_PAREN_ = s_idx++;
136 private static final int _CLOSE_PAREN_ = s_idx++;
137 private static final int _OPEN_BRACE_ = s_idx++;
138 private static final int _CLOSE_BRACE_ = s_idx++;
139 private static final int _OPEN_BRACKET_ = s_idx++;
140 private static final int _CLOSE_BRACKET_ = s_idx++;
141
142 private static final int _BUILTIN_FUNC_NAME_ = s_idx++;
143
144 private static final int _EXTENSION_ = s_idx++;
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162 private static final Map<String, Integer> KEYWORDS = new HashMap<String, Integer>();
163 static {
164
165 KEYWORDS.put("function", s_idx++);
166 KEYWORDS.put("BEGIN", s_idx++);
167 KEYWORDS.put("END", s_idx++);
168 KEYWORDS.put("in", s_idx++);
169
170
171 KEYWORDS.put("if", s_idx++);
172 KEYWORDS.put("else", s_idx++);
173 KEYWORDS.put("while", s_idx++);
174 KEYWORDS.put("for", s_idx++);
175 KEYWORDS.put("do", s_idx++);
176 KEYWORDS.put("return", s_idx++);
177 KEYWORDS.put("exit", s_idx++);
178 KEYWORDS.put("next", s_idx++);
179 KEYWORDS.put("continue", s_idx++);
180 KEYWORDS.put("delete", s_idx++);
181 KEYWORDS.put("break", s_idx++);
182
183
184 KEYWORDS.put("print", s_idx++);
185 KEYWORDS.put("printf", s_idx++);
186 KEYWORDS.put("getline", s_idx++);
187 }
188
189
190
191
192
193
194 private static int f_idx = 257;
195
196
197
198
199
200
201
202
203
204 private static final Map<String, Integer> BUILTIN_FUNC_NAMES = new HashMap<String, Integer>();
205 static {
206 BUILTIN_FUNC_NAMES.put("atan2", f_idx++);
207 BUILTIN_FUNC_NAMES.put("close", f_idx++);
208 BUILTIN_FUNC_NAMES.put("cos", f_idx++);
209 BUILTIN_FUNC_NAMES.put("exp", f_idx++);
210 BUILTIN_FUNC_NAMES.put("index", f_idx++);
211 BUILTIN_FUNC_NAMES.put("int", f_idx++);
212 BUILTIN_FUNC_NAMES.put("length", f_idx++);
213 BUILTIN_FUNC_NAMES.put("log", f_idx++);
214 BUILTIN_FUNC_NAMES.put("match", f_idx++);
215 BUILTIN_FUNC_NAMES.put("rand", f_idx++);
216 BUILTIN_FUNC_NAMES.put("sin", f_idx++);
217 BUILTIN_FUNC_NAMES.put("split", f_idx++);
218 BUILTIN_FUNC_NAMES.put("sprintf", f_idx++);
219 BUILTIN_FUNC_NAMES.put("sqrt", f_idx++);
220 BUILTIN_FUNC_NAMES.put("srand", f_idx++);
221 BUILTIN_FUNC_NAMES.put("sub", f_idx++);
222 BUILTIN_FUNC_NAMES.put("gsub", f_idx++);
223 BUILTIN_FUNC_NAMES.put("substr", f_idx++);
224 BUILTIN_FUNC_NAMES.put("system", f_idx++);
225 BUILTIN_FUNC_NAMES.put("tolower", f_idx++);
226 BUILTIN_FUNC_NAMES.put("toupper", f_idx++);
227 }
228
229 private static final int sp_idx = 257;
230
231
232
233
234
235
236
237
238
239
240 private static final Map<String, Integer> SPECIAL_VAR_NAMES = new HashMap<String, Integer>();
241 static {
242 SPECIAL_VAR_NAMES.put("NR", sp_idx);
243 SPECIAL_VAR_NAMES.put("FNR", sp_idx);
244 SPECIAL_VAR_NAMES.put("NF", sp_idx);
245 SPECIAL_VAR_NAMES.put("FS", sp_idx);
246 SPECIAL_VAR_NAMES.put("RS", sp_idx);
247 SPECIAL_VAR_NAMES.put("OFS", sp_idx);
248 SPECIAL_VAR_NAMES.put("ORS", sp_idx);
249 SPECIAL_VAR_NAMES.put("RSTART", sp_idx);
250 SPECIAL_VAR_NAMES.put("RLENGTH", sp_idx);
251 SPECIAL_VAR_NAMES.put("FILENAME", sp_idx);
252 SPECIAL_VAR_NAMES.put("SUBSEP", sp_idx);
253 SPECIAL_VAR_NAMES.put("CONVFMT", sp_idx);
254 SPECIAL_VAR_NAMES.put("OFMT", sp_idx);
255 SPECIAL_VAR_NAMES.put("ENVIRON", sp_idx);
256 SPECIAL_VAR_NAMES.put("ARGC", sp_idx);
257 SPECIAL_VAR_NAMES.put("ARGV", sp_idx);
258 }
259
260
261
262
263
264
265 private final AwkSymbolTableImpl symbol_table = new AwkSymbolTableImpl();
266
267 private final boolean additional_functions;
268 private final boolean additional_type_functions;
269 private final Map<String, JawkExtension> extensions;
270
271
272
273
274
275
276
277
278 public AwkParser(boolean additional_functions, boolean additional_type_functions, Map<String, JawkExtension> extensions) {
279 this.additional_functions = additional_functions;
280 this.additional_type_functions = additional_type_functions;
281
282
283
284
285
286 if (additional_functions && (KEYWORDS.get("_sleep") == null)) {
287
288
289 assert KEYWORDS.get("_sleep") == null;
290 assert KEYWORDS.get("_dump") == null;
291 KEYWORDS.put("_sleep", s_idx++);
292 KEYWORDS.put("_dump", s_idx++);
293 BUILTIN_FUNC_NAMES.put("exec", f_idx++);
294 }
295 if (additional_type_functions && (KEYWORDS.get("_INTEGER") == null)) {
296
297
298 assert KEYWORDS.get("_INTEGER") == null;
299 assert KEYWORDS.get("_DOUBLE") == null;
300 assert KEYWORDS.get("_STRING") == null;
301 KEYWORDS.put("_INTEGER", s_idx++);
302 KEYWORDS.put("_DOUBLE", s_idx++);
303 KEYWORDS.put("_STRING", s_idx++);
304 }
305
306
307
308
309
310 this.extensions = extensions;
311 }
312
313 private List<ScriptSource> scriptSources;
314 private int scriptSourcesCurrentIndex;
315 private LineNumberReader reader;
316 private int c;
317 private int token;
318
319 private StringBuffer text = new StringBuffer();
320 private StringBuffer string = new StringBuffer();
321 private StringBuffer regexp = new StringBuffer();
322
323 private void read()
324 throws IOException
325 {
326 text.append((char) c);
327 c = reader.read();
328
329 while (c == '\r') {
330 c = reader.read();
331 }
332 if (c < 0) {
333
334 if ((scriptSourcesCurrentIndex + 1) < scriptSources.size()) {
335 scriptSourcesCurrentIndex++;
336 reader = new LineNumberReader(scriptSources.get(scriptSourcesCurrentIndex).getReader());
337 read();
338 }
339 }
340 }
341
342
343
344
345
346 private void skipWhitespaces() throws IOException {
347 while (c == ' ' || c == '\t' || c == '#' || c == '\n') {
348 if (c == '#') {
349 while (c >= 0 && c != '\n') {
350 read();
351 }
352 }
353 read();
354 }
355 }
356
357
358
359
360
361 private void warn(String message) {
362 LOG.warn(
363 "%s (%s:%d)",
364 message,
365 scriptSources.get(scriptSourcesCurrentIndex).getDescription(),
366 reader.getLineNumber()
367 );
368 }
369
370
371
372
373
374
375
376
377
378 public AwkSyntaxTree parse(List<ScriptSource> scriptSources)
379 throws IOException
380 {
381 if ((scriptSources == null) || scriptSources.isEmpty()) {
382 throw new IOException("No script sources supplied");
383 }
384 this.scriptSources = scriptSources;
385 scriptSourcesCurrentIndex = 0;
386 reader = new LineNumberReader(scriptSources.get(scriptSourcesCurrentIndex).getReader());
387 read();
388 lexer();
389 return SCRIPT();
390 }
391
392
393
394
395
396 public class LexerException extends IOException {
397
398 private static final long serialVersionUID = 1L;
399
400
401
402
403
404
405 LexerException(String msg) {
406 super(msg + " ("
407 + scriptSources.get(scriptSourcesCurrentIndex).getDescription()
408 + ":" + reader.getLineNumber() + ")");
409 }
410 }
411
412
413
414
415
416 private void readString()
417 throws IOException {
418
419 string.setLength(0);
420
421 while (token != _EOF_ && c > 0 && c != '"' && c != '\n') {
422 if (c == '\\') {
423 read();
424 switch (c) {
425 case 'n': string.append('\n'); break;
426 case 't': string.append('\t'); break;
427 case 'r': string.append('\r'); break;
428 case 'a': string.append('\007'); break;
429 case 'b': string.append('\010'); break;
430 case 'f': string.append('\014'); break;
431 case 'v': string.append('\013'); break;
432
433 case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': {
434 int octalChar = c - '0';
435 read();
436 if (c >= '0' && c <= '7') {
437 octalChar = (octalChar << 3) + c - '0';
438 read();
439 if (c >= '0' && c <= '7') {
440 octalChar = (octalChar << 3) + c - '0';
441 read();
442 }
443 }
444 string.append((char)octalChar);
445 continue;
446 }
447
448 case 'x': {
449 int hexChar = 0;
450 read();
451 if (c >= '0' && c <= '9') {
452 hexChar = c - '0';
453 } else if (c >= 'A' && c <= 'F') {
454 hexChar = c - 'A' + 10;
455 } else if (c >= 'a' && c <= 'f') {
456 hexChar = c - 'a' + 10;
457 } else {
458 warn("no hex digits in `\\x' sequence");
459 string.append('x');
460 continue;
461 }
462 read();
463 if (c >= '0' && c <= '9') {
464 hexChar = (hexChar << 4) + c - '0';
465 } else if (c >= 'A' && c <= 'F') {
466 hexChar = (hexChar << 4) + c - 'A' + 10;
467 } else if (c >= 'a' && c <= 'f') {
468 hexChar = (hexChar << 4) + c - 'a' + 10;
469 } else {
470
471 string.append((char)hexChar);
472 continue;
473 }
474 string.append((char)hexChar);
475 break;
476 }
477 default: string.append((char)c); break;
478 }
479 } else {
480 string.append((char) c);
481 }
482 read();
483 }
484 if (token == _EOF_ || c == '\n' || c <= 0) {
485 throw new LexerException("Unterminated string: " + text);
486 }
487 read();
488
489 }
490
491
492
493
494
495 private void readRegexp()
496 throws IOException {
497
498 regexp.setLength(0);
499
500 while (token != _EOF_ && c > 0 && c != '/' && c != '\n') {
501 if (c == '\\') {
502 read();
503 if (c != '/') {
504 regexp.append('\\');
505 }
506 }
507 regexp.append((char) c);
508 read();
509 }
510 if (token == _EOF_ || c == '\n' || c <= 0) {
511 throw new LexerException("Unterminated string: " + text);
512 }
513 read();
514
515 }
516
517 private static String toTokenString(int token) {
518 Class<AwkParser> c = AwkParser.class;
519 Field[] fields = c.getDeclaredFields();
520 try {
521 for (Field field : fields) {
522 if ((field.getModifiers() & Modifier.STATIC) > 0 && field.getType() == Integer.TYPE && field.getInt(null) == token) {
523 return field.getName();
524 }
525 }
526 } catch (IllegalAccessException iac) {
527 LOG.error("Failed to create token string", iac);
528 return "[" + token + ": " + iac + "]";
529 }
530 return "{" + token + "}";
531 }
532
533 private int lexer(int expected_token)
534 throws IOException
535 {
536
537 if (token != expected_token) {
538 throw new ParserException("Expecting " + toTokenString(expected_token) + ". Found: " + toTokenString(token) + " (" + text + ")");
539 }
540 return lexer();
541 }
542
543 private int lexer()
544 throws IOException
545 {
546
547
548 while (c >= 0 && (c == ' ' || c == '\t' || c == '#' || c == '\\')) {
549 if (c == '\\') {
550 read();
551 if (c == '\n') {
552 read();
553 }
554 continue;
555 }
556 if (c == '#') {
557
558 while (c >= 0 && c != '\n') {
559 read();
560 }
561 } else {
562 read();
563 }
564 }
565 text.setLength(0);
566 if (c < 0) {
567 return token = _EOF_;
568 }
569 if (c == ',') {
570 read();
571 skipWhitespaces();
572 return token = _COMMA_;
573 }
574 if (c == '(') {
575 read();
576 return token = _OPEN_PAREN_;
577 }
578 if (c == ')') {
579 read();
580 return token = _CLOSE_PAREN_;
581 }
582 if (c == '{') {
583 read();
584 skipWhitespaces();
585 return token = _OPEN_BRACE_;
586 }
587 if (c == '}') {
588 read();
589 return token = _CLOSE_BRACE_;
590 }
591 if (c == '[') {
592 read();
593 return token = _OPEN_BRACKET_;
594 }
595 if (c == ']') {
596 read();
597 return token = _CLOSE_BRACKET_;
598 }
599 if (c == '$') {
600 read();
601 return token = _DOLLAR_;
602 }
603 if (c == '~') {
604 read();
605 return token = _MATCHES_;
606 }
607 if (c == '?') {
608 read();
609 skipWhitespaces();
610 return token = _QUESTION_MARK_;
611 }
612 if (c == ':') {
613 read();
614 skipWhitespaces();
615 return token = _COLON_;
616 }
617 if (c == '&') {
618 read();
619 if (c == '&') {
620 read();
621 skipWhitespaces();
622 return token = _AND_;
623 }
624 throw new LexerException("use && for logical and");
625 }
626 if (c == '|') {
627 read();
628 if (c == '|') {
629 read();
630 skipWhitespaces();
631 return token = _OR_;
632 }
633 return token = _PIPE_;
634 }
635 if (c == '=') {
636 read();
637 if (c == '=') {
638 read();
639 return token = _EQ_;
640 }
641 return token = _EQUALS_;
642 }
643 if (c == '+') {
644 read();
645 if (c == '=') {
646 read();
647 return token = _PLUS_EQ_;
648 } else if (c == '+') {
649 read();
650 return token = _INC_;
651 }
652 return token = _PLUS_;
653 }
654 if (c == '-') {
655 read();
656 if (c == '=') {
657 read();
658 return token = _MINUS_EQ_;
659 } else if (c == '-') {
660 read();
661 return token = _DEC_;
662 }
663 return token = _MINUS_;
664 }
665 if (c == '*') {
666 read();
667 if (c == '=') {
668 read();
669 return token = _MULT_EQ_;
670 } else if (c == '*') {
671 read();
672 return token = _POW_;
673 }
674 return token = _MULT_;
675 }
676 if (c == '/') {
677 read();
678 if (c == '=') {
679 read();
680 return token = _DIV_EQ_;
681 }
682 return token = _DIVIDE_;
683 }
684 if (c == '%') {
685 read();
686 if (c == '=') {
687 read();
688 return token = _MOD_EQ_;
689 }
690 return token = _MOD_;
691 }
692 if (c == '^') {
693 read();
694 if (c == '=') {
695 read();
696 return token = _POW_EQ_;
697 }
698 return token = _POW_;
699 }
700 if (c == '>') {
701 read();
702 if (c == '=') {
703 read();
704 return token = _GE_;
705 } else if (c == '>') {
706 read();
707 return token = _APPEND_;
708 }
709 return token = _GT_;
710 }
711 if (c == '<') {
712 read();
713 if (c == '=') {
714 read();
715 return token = _LE_;
716 }
717 return token = _LT_;
718 }
719 if (c == '!') {
720 read();
721 if (c == '=') {
722 read();
723 return token = _NE_;
724 } else if (c == '~') {
725 read();
726 return token = _NOT_MATCHES_;
727 }
728 return token = _NOT_;
729 }
730
731 if (c == '.') {
732
733 read();
734 boolean hit = false;
735 while (c > 0 && Character.isDigit(c)) {
736 hit = true;
737 read();
738 }
739 if (!hit) {
740 throw new LexerException("Decimal point encountered with no values on either side.");
741 }
742 return token = _DOUBLE_;
743 }
744
745 if (Character.isDigit(c)) {
746
747 read();
748 while (c > 0) {
749 if (c == '.') {
750
751 read();
752 while (c > 0 && Character.isDigit(c)) {
753 read();
754 }
755 return token = _DOUBLE_;
756 } else if (Character.isDigit(c)) {
757
758 read();
759 } else {
760 break;
761 }
762 }
763
764 return token = _INTEGER_;
765 }
766
767 if (Character.isJavaIdentifierStart(c)) {
768 read();
769 while (Character.isJavaIdentifierPart(c)) {
770 read();
771 }
772
773
774 if (extensions.get(text.toString()) != null) {
775 return token = _EXTENSION_;
776 }
777 Integer kw_token = KEYWORDS.get(text.toString());
778 if (kw_token != null) {
779 return token = kw_token.intValue();
780 }
781 Integer bf_idx = BUILTIN_FUNC_NAMES.get(text.toString());
782 if (bf_idx != null) {
783 return token = _BUILTIN_FUNC_NAME_;
784 }
785 if (c == '(') {
786 return token = _FUNC_ID_;
787 } else {
788 return token = _ID_;
789 }
790 }
791
792 if (c == ';') {
793 read();
794 while (c == ' ' || c == '\t' || c == '\n' || c == '#') {
795 if (c == '\n') {
796 break;
797 }
798 if (c == '#') {
799 while (c >= 0 && c != '\n') {
800 read();
801 }
802 if (c == '\n') {
803 read();
804 }
805 } else {
806 read();
807 }
808 }
809 return token = _SEMICOLON_;
810 }
811
812 if (c == '\n') {
813 read();
814 while (c == ' ' || c == '\t' || c == '#' || c == '\n') {
815 if (c == '#') {
816 while (c >= 0 && c != '\n') {
817 read();
818 }
819 }
820 read();
821 }
822 return token = _NEWLINE_;
823 }
824
825 if (c == '"') {
826
827 read();
828 readString();
829 return token = _STRING_;
830 }
831
832
833
834
835
836
837
838
839
840
841
842
843
844 throw new LexerException("Invalid character (" + c + "): " + ((char) c));
845 }
846
847
848 private void terminator()
849 throws IOException
850 {
851
852 if (!opt_terminator()) {
853 throw new ParserException("Expecting statement terminator. Got " + toTokenString(token) + ": " + text);
854 }
855 }
856
857 private boolean opt_terminator()
858 throws IOException
859 {
860 if (opt_newline()) {
861 return true;
862 } else if (token == _EOF_ || token == _CLOSE_BRACE_) {
863 return true;
864 } else if (token == _SEMICOLON_) {
865 lexer();
866 return true;
867 } else {
868
869 return false;
870 }
871 }
872
873 private boolean opt_newline()
874 throws IOException
875 {
876 if (token == _NEWLINE_) {
877 lexer();
878 return true;
879 } else {
880 return false;
881 }
882 }
883
884
885
886 AST SCRIPT()
887 throws IOException
888 {
889 AST rl;
890 if (token != _EOF_) {
891 rl = RULE_LIST();
892 } else {
893 rl = null;
894 }
895 lexer(_EOF_);
896 return rl;
897 }
898
899
900 AST RULE_LIST()
901 throws IOException
902 {
903 opt_newline();
904 AST rule_or_function = null;
905 if (token == KEYWORDS.get("function")) {
906 rule_or_function = FUNCTION();
907 } else if (token != _EOF_) {
908 rule_or_function = RULE();
909 } else {
910 return null;
911 }
912 opt_terminator();
913 if (rule_or_function == null) {
914 return RULE_LIST();
915 } else {
916 return new RuleList_AST(rule_or_function, RULE_LIST());
917 }
918 }
919
920 AST FUNCTION()
921 throws IOException
922 {
923 expectKeyword("function");
924 String function_name;
925 if (token == _FUNC_ID_ || token == _ID_) {
926 function_name = text.toString();
927 lexer();
928 } else {
929 throw new ParserException("Expecting function name. Got " + toTokenString(token) + ": " + text);
930 }
931 symbol_table.setFunctionName(function_name);
932 lexer(_OPEN_PAREN_);
933 AST formal_param_list;
934 if (token == _CLOSE_PAREN_) {
935 formal_param_list = null;
936 } else {
937 formal_param_list = FORMAL_PARAM_LIST(function_name);
938 }
939 lexer(_CLOSE_PAREN_);
940 opt_newline();
941
942 lexer(_OPEN_BRACE_);
943 AST function_block = STATEMENT_LIST();
944 lexer(_CLOSE_BRACE_);
945 symbol_table.clearFunctionName(function_name);
946 return symbol_table.addFunctionDef(function_name, formal_param_list, function_block);
947 }
948
949 AST FORMAL_PARAM_LIST(String func_name)
950 throws IOException
951 {
952 if (token == _ID_) {
953 String id = text.toString();
954 int offset = symbol_table.addFunctionParameter(func_name, id);
955 lexer();
956 if (token == _COMMA_) {
957 lexer();
958 opt_newline();
959 AST rest = FORMAL_PARAM_LIST(func_name);
960 if (rest == null) {
961 throw new ParserException("Cannot terminate a formal parameter list with a comma.");
962 } else {
963 return new FunctionDefParamList_AST(id, offset, rest);
964 }
965 } else {
966 return new FunctionDefParamList_AST(id, offset, null);
967 }
968 } else {
969 return null;
970 }
971 }
972
973
974 AST RULE()
975 throws IOException
976 {
977 AST opt_expr;
978 AST opt_stmts;
979 if (token == KEYWORDS.get("BEGIN")) {
980 lexer();
981 opt_expr = symbol_table.addBEGIN();
982 } else if (token == KEYWORDS.get("END")) {
983 lexer();
984 opt_expr = symbol_table.addEND();
985 } else if (token != _OPEN_BRACE_ && token != _SEMICOLON_ && token != _NEWLINE_ && token != _EOF_) {
986
987 opt_expr = ASSIGNMENT_EXPRESSION(true, true, false);
988
989 if (token == _COMMA_) {
990 lexer();
991 opt_newline();
992
993 opt_expr = new ConditionPair_AST(opt_expr, ASSIGNMENT_EXPRESSION(true, true, false));
994 }
995 } else {
996 opt_expr = null;
997 }
998 if (token == _OPEN_BRACE_) {
999 lexer();
1000 opt_stmts = STATEMENT_LIST();
1001 lexer(_CLOSE_BRACE_);
1002 } else {
1003 opt_stmts = null;
1004 }
1005 return new Rule_AST(opt_expr, opt_stmts);
1006 }
1007
1008
1009 private AST STATEMENT_LIST()
1010 throws IOException
1011 {
1012
1013 opt_newline();
1014 if (token == _CLOSE_BRACE_ || token == _EOF_) {
1015 return null;
1016 }
1017 AST stmt;
1018 if (token == _OPEN_BRACE_) {
1019 lexer();
1020 stmt = STATEMENT_LIST();
1021 lexer(_CLOSE_BRACE_);
1022 } else {
1023 if (token == _SEMICOLON_) {
1024
1025
1026
1027 lexer();
1028 return STATEMENT_LIST();
1029 } else {
1030 stmt = STATEMENT();
1031 }
1032 }
1033
1034 AST rest = STATEMENT_LIST();
1035 if (rest == null) {
1036 return stmt;
1037 } else if (stmt == null) {
1038 return rest;
1039 } else {
1040 return new STATEMENTLIST_AST(stmt, rest);
1041 }
1042 }
1043
1044
1045 AST EXPRESSION_LIST(boolean not_in_print_root, boolean allow_in_keyword)
1046 throws IOException
1047 {
1048 AST expr = ASSIGNMENT_EXPRESSION(not_in_print_root, allow_in_keyword, false);
1049 if (token == _COMMA_) {
1050 lexer();
1051 opt_newline();
1052 return new FunctionCallParamList_AST(expr, EXPRESSION_LIST(not_in_print_root, allow_in_keyword));
1053 } else {
1054 return new FunctionCallParamList_AST(expr, null);
1055 }
1056 }
1057
1058
1059 AST ASSIGNMENT_EXPRESSION(boolean not_in_print_root, boolean allow_in_keyword, boolean allow_multidim_indices)
1060 throws IOException
1061 {
1062 AST comma_expression = COMMA_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1063 int op = 0;
1064 String txt = null;
1065 AST assignment_expression = null;
1066 if (token == _EQUALS_ || token == _PLUS_EQ_ || token == _MINUS_EQ_ || token == _MULT_EQ_ || token == _DIV_EQ_ || token == _MOD_EQ_ || token == _POW_EQ_) {
1067 op = token;
1068 txt = text.toString();
1069 lexer();
1070 assignment_expression = ASSIGNMENT_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1071 return new AssignmentExpression_AST(comma_expression, op, txt, assignment_expression);
1072 }
1073 return comma_expression;
1074 }
1075
1076
1077
1078
1079 AST COMMA_EXPRESSION(boolean not_in_print_root, boolean allow_in_keyword, boolean allow_multidim_indices)
1080 throws IOException
1081 {
1082 AST concat_expression = TERNARY_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1083 if (allow_multidim_indices && token == _COMMA_) {
1084
1085 lexer();
1086 opt_newline();
1087 AST rest = COMMA_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1088 if (rest instanceof ArrayIndex_AST) {
1089 return new ArrayIndex_AST(concat_expression, rest);
1090 } else {
1091 return new ArrayIndex_AST(concat_expression, new ArrayIndex_AST(rest, null));
1092 }
1093 } else {
1094 return concat_expression;
1095 }
1096 }
1097
1098
1099 AST TERNARY_EXPRESSION(boolean not_in_print_root, boolean allow_in_keyword, boolean allow_multidim_indices)
1100 throws IOException
1101 {
1102 AST le1 = LOGICAL_OR_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1103 if (token == _QUESTION_MARK_) {
1104 lexer();
1105 AST true_block = TERNARY_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1106 lexer(_COLON_);
1107 AST false_block = TERNARY_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1108 return new TernaryExpression_AST(le1, true_block, false_block);
1109 } else {
1110 return le1;
1111 }
1112 }
1113
1114
1115 AST LOGICAL_OR_EXPRESSION(boolean not_in_print_root, boolean allow_in_keyword, boolean allow_multidim_indices)
1116 throws IOException
1117 {
1118 AST le2 = LOGICAL_AND_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1119 int op = 0;
1120 String txt = null;
1121 AST le1 = null;
1122 if (token == _OR_) {
1123 op = token;
1124 txt = text.toString();
1125 lexer();
1126 le1 = LOGICAL_OR_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1127 return new LogicalExpression_AST(le2, op, txt, le1);
1128 }
1129 return le2;
1130 }
1131
1132
1133 AST LOGICAL_AND_EXPRESSION(boolean not_in_print_root, boolean allow_in_keyword, boolean allow_multidim_indices)
1134 throws IOException
1135 {
1136 AST comparison_expression = IN_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1137 int op = 0;
1138 String txt = null;
1139 AST le2 = null;
1140 if (token == _AND_) {
1141 op = token;
1142 txt = text.toString();
1143 lexer();
1144 le2 = LOGICAL_AND_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1145 return new LogicalExpression_AST(comparison_expression, op, txt, le2);
1146 }
1147 return comparison_expression;
1148 }
1149
1150
1151
1152
1153
1154
1155
1156 AST IN_EXPRESSION(boolean not_in_print_root, boolean allow_in_keyword, boolean allow_multidim_indices)
1157 throws IOException
1158 {
1159
1160 AST comparison = MATCHING_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1161 if (allow_in_keyword && token == KEYWORDS.get("in")) {
1162 lexer();
1163 return new InExpression_AST(comparison, IN_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices));
1164 }
1165 return comparison;
1166 }
1167
1168
1169 AST MATCHING_EXPRESSION(boolean not_in_print_root, boolean allow_in_keyword, boolean allow_multidim_indices)
1170 throws IOException
1171 {
1172 AST expression = COMPARISON_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1173 int op = 0;
1174 String txt = null;
1175 AST comparison_expression = null;
1176 if (token == _MATCHES_ || token == _NOT_MATCHES_)
1177 {
1178 op = token;
1179 txt = text.toString();
1180 lexer();
1181 comparison_expression = MATCHING_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1182 return new ComparisonExpression_AST(expression, op, txt, comparison_expression);
1183 }
1184 return expression;
1185 }
1186
1187
1188
1189
1190 AST COMPARISON_EXPRESSION(boolean not_in_print_root, boolean allow_in_keyword, boolean allow_multidim_indices)
1191 throws IOException
1192 {
1193 AST expression = CONCAT_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1194 int op = 0;
1195 String txt = null;
1196 AST comparison_expression = null;
1197
1198 if (token == _EQ_ || token == _GE_ || token == _LT_ || token == _LE_ || token == _NE_
1199 || (token == _GT_ && not_in_print_root))
1200 {
1201 op = token;
1202 txt = text.toString();
1203 lexer();
1204 comparison_expression = COMPARISON_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1205 return new ComparisonExpression_AST(expression, op, txt, comparison_expression);
1206 } else if (not_in_print_root && token == _PIPE_) {
1207 lexer();
1208 return GETLINE_EXPRESSION(expression, not_in_print_root, allow_in_keyword);
1209 }
1210
1211 return expression;
1212 }
1213
1214
1215 AST CONCAT_EXPRESSION(boolean not_in_print_root, boolean allow_in_keyword, boolean allow_multidim_indices)
1216 throws IOException
1217 {
1218 AST te = EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1219 if (token == _INTEGER_ || token == _DOUBLE_ || token == _OPEN_PAREN_ || token == _FUNC_ID_ || token == _INC_ || token == _DEC_ || token == _ID_ || token == _STRING_ || token == _DOLLAR_ || token == _BUILTIN_FUNC_NAME_ || token == _EXTENSION_) {
1220
1221 return new ConcatExpression_AST(te, CONCAT_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices));
1222 } else if (additional_type_functions && (
1223 token == KEYWORDS.get("_INTEGER")
1224 || token == KEYWORDS.get("_DOUBLE")
1225 || token == KEYWORDS.get("_STRING")))
1226 {
1227
1228 return new ConcatExpression_AST(te, CONCAT_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices));
1229 } else {
1230 return te;
1231 }
1232 }
1233
1234
1235 AST EXPRESSION(boolean not_in_print_root, boolean allow_in_keyword, boolean allow_multidim_indices)
1236 throws IOException {
1237 AST term = TERM(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1238 while (token == _PLUS_ || token == _MINUS_) {
1239 int op = token;
1240 String txt = text.toString();
1241 lexer();
1242 AST nextTerm = TERM(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1243
1244
1245 term = new BinaryExpression_AST(term, op, txt, nextTerm);
1246 }
1247 return term;
1248 }
1249
1250
1251 AST TERM(boolean not_in_print_root, boolean allow_in_keyword, boolean allow_multidim_indices)
1252 throws IOException
1253 {
1254 AST unaryFactor = UNARY_FACTOR(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1255 while (token == _MULT_ || token == _DIVIDE_ || token == _MOD_) {
1256 int op = token;
1257 String txt = text.toString();
1258 lexer();
1259 AST nextUnaryFactor = UNARY_FACTOR(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1260
1261
1262 unaryFactor = new BinaryExpression_AST(unaryFactor, op, txt, nextUnaryFactor);
1263 }
1264 return unaryFactor;
1265 }
1266
1267
1268 AST UNARY_FACTOR(boolean not_in_print_root, boolean allow_in_keyword, boolean allow_multidim_indices)
1269 throws IOException
1270 {
1271 if (token == _NOT_) {
1272 lexer();
1273 return new NotExpression_AST(POWER_FACTOR(not_in_print_root, allow_in_keyword, allow_multidim_indices));
1274 } else if (token == _MINUS_) {
1275 lexer();
1276 return new NegativeExpression_AST(POWER_FACTOR(not_in_print_root, allow_in_keyword, allow_multidim_indices));
1277 } else if (token == _PLUS_) {
1278 lexer();
1279 return new UnaryPlusExpression_AST(POWER_FACTOR(not_in_print_root, allow_in_keyword, allow_multidim_indices));
1280 } else {
1281 return POWER_FACTOR(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1282 }
1283 }
1284
1285
1286 AST POWER_FACTOR(boolean not_in_print_root, boolean allow_in_keyword, boolean allow_multidim_indices)
1287 throws IOException
1288 {
1289 AST incdec_ast = FACTOR_FOR_INCDEC(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1290 if (token == _POW_) {
1291 int op = token;
1292 String txt = text.toString();
1293 lexer();
1294 AST term = POWER_FACTOR(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1295
1296 return new BinaryExpression_AST(incdec_ast, op, txt, term);
1297 }
1298 return incdec_ast;
1299 }
1300
1301
1302
1303
1304 private boolean isLvalue(AST ast) {
1305 return (ast instanceof ID_AST)
1306 || (ast instanceof ArrayReference_AST)
1307 || (ast instanceof DollarExpression_AST);
1308 }
1309
1310 AST FACTOR_FOR_INCDEC(boolean not_in_print_root, boolean allow_in_keyword, boolean allow_multidim_indices)
1311 throws IOException
1312 {
1313 boolean pre_inc = false;
1314 boolean pre_dec = false;
1315 boolean post_inc = false;
1316 boolean post_dec = false;
1317 if (token == _INC_) {
1318 pre_inc = true;
1319 lexer();
1320 } else if (token == _DEC_) {
1321 pre_dec = true;
1322 lexer();
1323 }
1324
1325 AST factor_ast = FACTOR(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1326
1327 if ((pre_inc || pre_dec) && !isLvalue(factor_ast)) {
1328 throw new ParserException("Cannot pre inc/dec a non-lvalue");
1329 }
1330
1331
1332
1333
1334 if (isLvalue(factor_ast) && !pre_inc && !pre_dec) {
1335 if (token == _INC_) {
1336 post_inc = true;
1337 lexer();
1338 } else if (token == _DEC_) {
1339 post_dec = true;
1340 lexer();
1341 }
1342 }
1343
1344 if ((pre_inc || pre_dec) && (post_inc || post_dec)) {
1345 throw new ParserException("Cannot do pre inc/dec AND post inc/dec.");
1346 }
1347
1348 if (pre_inc) {
1349 return new PreInc_AST(factor_ast);
1350 } else if (pre_dec) {
1351 return new PreDec_AST(factor_ast);
1352 } else if (post_inc) {
1353 return new PostInc_AST(factor_ast);
1354 } else if (post_dec) {
1355 return new PostDec_AST(factor_ast);
1356 } else {
1357 return factor_ast;
1358 }
1359 }
1360
1361
1362
1363 AST FACTOR(boolean not_in_print_root, boolean allow_in_keyword, boolean allow_multidim_indices)
1364 throws IOException
1365 {
1366 if (token == _OPEN_PAREN_) {
1367 lexer();
1368
1369 AST assignment_expression = ASSIGNMENT_EXPRESSION(true, allow_in_keyword, true);
1370 if (allow_multidim_indices && (assignment_expression instanceof ArrayIndex_AST)) {
1371 throw new ParserException("Cannot nest multi-dimensional array index expressions.");
1372 }
1373 lexer(_CLOSE_PAREN_);
1374 return assignment_expression;
1375 } else if (token == _INTEGER_) {
1376 AST integer = symbol_table.addINTEGER(text.toString());
1377 lexer();
1378 return integer;
1379 } else if (token == _DOUBLE_) {
1380 AST dbl = symbol_table.addDOUBLE(text.toString());
1381 lexer();
1382 return dbl;
1383 } else if (token == _STRING_) {
1384 AST str = symbol_table.addSTRING(string.toString());
1385 lexer();
1386 return str;
1387 } else if (token == KEYWORDS.get("getline")) {
1388 return GETLINE_EXPRESSION(null, not_in_print_root, allow_in_keyword);
1389 } else if (token == _DIVIDE_ || token == _DIV_EQ_) {
1390 readRegexp();
1391 if (token == _DIV_EQ_) {
1392 regexp.insert(0, '=');
1393 }
1394 AST regexp_ast = symbol_table.addREGEXP(regexp.toString());
1395 lexer();
1396 return regexp_ast;
1397 } else if (additional_type_functions && token == KEYWORDS.get("_INTEGER")) {
1398 return INTEGER_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1399 } else if (additional_type_functions && token == KEYWORDS.get("_DOUBLE")) {
1400 return DOUBLE_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1401 } else if (additional_type_functions && token == KEYWORDS.get("_STRING")) {
1402 return STRING_EXPRESSION(not_in_print_root, allow_in_keyword, allow_multidim_indices);
1403 } else {
1404 if (token == _DOLLAR_) {
1405 lexer();
1406 if (token == _INC_ || token == _DEC_) {
1407 return new DollarExpression_AST(FACTOR_FOR_INCDEC(not_in_print_root, allow_in_keyword, allow_multidim_indices));
1408 }
1409 if (token == _NOT_ || token == _MINUS_ || token == _PLUS_) {
1410 return new DollarExpression_AST(UNARY_FACTOR(not_in_print_root, allow_in_keyword, allow_multidim_indices));
1411 }
1412 return new DollarExpression_AST(FACTOR(not_in_print_root, allow_in_keyword, allow_multidim_indices));
1413 }
1414 return SYMBOL(not_in_print_root, allow_in_keyword);
1415 }
1416 }
1417
1418 AST INTEGER_EXPRESSION(boolean not_in_print_root, boolean allow_in_keyword, boolean allow_multidim_indices)
1419 throws IOException
1420 {
1421 boolean parens = (c == '(');
1422 expectKeyword("_INTEGER");
1423 if (token == _SEMICOLON_ || token == _NEWLINE_ || token == _CLOSE_BRACE_) {
1424 throw new ParserException("expression expected");
1425 } else {
1426
1427
1428 if (parens) {
1429 lexer(_OPEN_PAREN_);
1430 }
1431 AST int_expr_ast;
1432 if (token == _CLOSE_PAREN_) {
1433 throw new ParserException("expression expected");
1434 } else {
1435 int_expr_ast = new IntegerExpression_AST(ASSIGNMENT_EXPRESSION(not_in_print_root || parens, allow_in_keyword, allow_multidim_indices));
1436 }
1437 if (parens) {
1438 lexer(_CLOSE_PAREN_);
1439 }
1440 return int_expr_ast;
1441 }
1442 }
1443
1444 AST DOUBLE_EXPRESSION(boolean not_in_print_root, boolean allow_in_keyword, boolean allow_multidim_indices)
1445 throws IOException
1446 {
1447 boolean parens = (c == '(');
1448 expectKeyword("_DOUBLE");
1449 if (token == _SEMICOLON_ || token == _NEWLINE_ || token == _CLOSE_BRACE_) {
1450 throw new ParserException("expression expected");
1451 } else {
1452
1453
1454 if (parens) {
1455 lexer(_OPEN_PAREN_);
1456 }
1457 AST double_expr_ast;
1458 if (token == _CLOSE_PAREN_) {
1459 throw new ParserException("expression expected");
1460 } else {
1461 double_expr_ast = new DoubleExpression_AST(ASSIGNMENT_EXPRESSION(not_in_print_root || parens, allow_in_keyword, allow_multidim_indices));
1462 }
1463 if (parens) {
1464 lexer(_CLOSE_PAREN_);
1465 }
1466 return double_expr_ast;
1467 }
1468 }
1469
1470 AST STRING_EXPRESSION(boolean not_in_print_root, boolean allow_in_keyword, boolean allow_multidim_indices)
1471 throws IOException
1472 {
1473 boolean parens = (c == '(');
1474 expectKeyword("_STRING");
1475 if (token == _SEMICOLON_ || token == _NEWLINE_ || token == _CLOSE_BRACE_) {
1476 throw new ParserException("expression expected");
1477 } else {
1478
1479
1480 if (parens) {
1481 lexer(_OPEN_PAREN_);
1482 }
1483 AST string_expr_ast;
1484 if (token == _CLOSE_PAREN_) {
1485 throw new ParserException("expression expected");
1486 } else {
1487 string_expr_ast = new StringExpression_AST(ASSIGNMENT_EXPRESSION(not_in_print_root || parens, allow_in_keyword, allow_multidim_indices));
1488 }
1489 if (parens) {
1490 lexer(_CLOSE_PAREN_);
1491 }
1492 return string_expr_ast;
1493 }
1494 }
1495
1496
1497 AST SYMBOL(boolean not_in_print_root, boolean allow_in_keyword)
1498 throws IOException
1499 {
1500 if (token != _ID_ && token != _FUNC_ID_ && token != _BUILTIN_FUNC_NAME_ && token != _EXTENSION_) {
1501 throw new ParserException("Expecting an ID. Got " + toTokenString(token) + ": " + text);
1502 }
1503 int id_token = token;
1504 String id = text.toString();
1505 boolean parens = (c == '(');
1506 lexer();
1507
1508 if (id_token == _EXTENSION_) {
1509 String extension_keyword = id;
1510
1511 AST params;
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536 if (parens) {
1537 lexer();
1538 if (token == _CLOSE_PAREN_) {
1539 params = null;
1540 } else {
1541 params = EXPRESSION_LIST(true, allow_in_keyword);
1542 }
1543 lexer(_CLOSE_PAREN_);
1544 } else {
1545
1546
1547
1548
1549
1550
1551
1552 params = null;
1553 }
1554
1555 return new Extension_AST(extension_keyword, params);
1556 } else if (id_token == _FUNC_ID_ || id_token == _BUILTIN_FUNC_NAME_) {
1557 AST params;
1558
1559 if (id.equals("length")) {
1560 if (token == _OPEN_PAREN_) {
1561 lexer();
1562 if (token == _CLOSE_PAREN_) {
1563 params = null;
1564 } else {
1565 params = EXPRESSION_LIST(true, allow_in_keyword);
1566 }
1567 lexer(_CLOSE_PAREN_);
1568 } else {
1569 params = null;
1570 }
1571 } else {
1572 lexer(_OPEN_PAREN_);
1573 if (token == _CLOSE_PAREN_) {
1574 params = null;
1575 } else {
1576 params = EXPRESSION_LIST(true, allow_in_keyword);
1577 }
1578 lexer(_CLOSE_PAREN_);
1579 }
1580 if (id_token == _BUILTIN_FUNC_NAME_) {
1581 return new BuiltinFunctionCall_AST(id, params);
1582 } else {
1583 return symbol_table.addFunctionCall(id, params);
1584 }
1585 }
1586 if (token == _OPEN_BRACKET_) {
1587 lexer();
1588 AST idx_ast = ARRAY_INDEX(true, allow_in_keyword);
1589 lexer(_CLOSE_BRACKET_);
1590 if (token == _OPEN_BRACKET_) {
1591 throw new ParserException("Use [a,b,c,...] instead of [a][b][c]... for multi-dimensional arrays.");
1592 }
1593 return symbol_table.addArrayReference(id, idx_ast);
1594 }
1595 return symbol_table.addID(id);
1596 }
1597
1598
1599 AST ARRAY_INDEX(boolean not_in_print_root, boolean allow_in_keyword)
1600 throws IOException
1601 {
1602 AST expr_ast = ASSIGNMENT_EXPRESSION(not_in_print_root, allow_in_keyword, false);
1603 if (token == _COMMA_) {
1604 opt_newline();
1605 lexer();
1606 return new ArrayIndex_AST(expr_ast, ARRAY_INDEX(not_in_print_root, allow_in_keyword));
1607 } else {
1608 return new ArrayIndex_AST(expr_ast, null);
1609 }
1610 }
1611
1612
1613
1614
1615
1616
1617
1618
1619 AST STATEMENT()
1620 throws IOException
1621 {
1622 if (token == _OPEN_BRACE_) {
1623 lexer();
1624 AST lst = STATEMENT_LIST();
1625 lexer(_CLOSE_BRACE_);
1626 return lst;
1627 }
1628 AST stmt;
1629 if (token == KEYWORDS.get("if")) { stmt = IF_STATEMENT();
1630 } else if (token == KEYWORDS.get("while")) { stmt = WHILE_STATEMENT();
1631 } else if (token == KEYWORDS.get("for")) { stmt = FOR_STATEMENT();
1632 } else {
1633 if (token == KEYWORDS.get("do")) { stmt = DO_STATEMENT();
1634 } else if (token == KEYWORDS.get("return")) { stmt = RETURN_STATEMENT();
1635 } else if (token == KEYWORDS.get("exit")) { stmt = EXIT_STATEMENT();
1636 } else if (token == KEYWORDS.get("delete")) { stmt = DELETE_STATEMENT();
1637 } else if (token == KEYWORDS.get("print")) { stmt = PRINT_STATEMENT();
1638 } else if (token == KEYWORDS.get("printf")) { stmt = PRINTF_STATEMENT();
1639 } else if (token == KEYWORDS.get("next")) { stmt = NEXT_STATEMENT();
1640 } else if (token == KEYWORDS.get("continue")) { stmt = CONTINUE_STATEMENT();
1641 } else if (token == KEYWORDS.get("break")) { stmt = BREAK_STATEMENT();
1642 } else if (additional_functions && token == KEYWORDS.get("_sleep")) { stmt = SLEEP_STATEMENT();
1643 } else if (additional_functions && token == KEYWORDS.get("_dump")) { stmt = DUMP_STATEMENT();
1644 } else { stmt = EXPRESSION_STATEMENT(true, false);
1645 }
1646 terminator();
1647 return stmt;
1648 }
1649
1650
1651 return stmt;
1652 }
1653
1654 AST EXPRESSION_STATEMENT(boolean allow_in_keyword, boolean allow_non_statement_asts)
1655 throws IOException
1656 {
1657
1658
1659
1660
1661 AST expr_ast = ASSIGNMENT_EXPRESSION(true, allow_in_keyword, false);
1662 if (!allow_non_statement_asts && expr_ast instanceof NonStatement_AST) {
1663 throw new ParserException("Not a valid statement.");
1664 }
1665 return new ExpressionStatement_AST(expr_ast);
1666 }
1667
1668 AST IF_STATEMENT()
1669 throws IOException
1670 {
1671 expectKeyword("if");
1672 lexer(_OPEN_PAREN_);
1673 AST expr = ASSIGNMENT_EXPRESSION(true, true, false);
1674 lexer(_CLOSE_PAREN_);
1675
1676
1677
1678
1679
1680
1681 opt_newline();
1682 AST b1;
1683 if (token == _SEMICOLON_) {
1684 lexer();
1685
1686 opt_newline();
1687 b1 = null;
1688 } else {
1689 b1 = BLOCK_OR_STMT();
1690 }
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702 opt_newline();
1703 if (token == KEYWORDS.get("else")) {
1704 lexer();
1705 opt_newline();
1706 AST b2 = BLOCK_OR_STMT();
1707 return new IfStatement_AST(expr, b1, b2);
1708 } else {
1709 AST if_ast = new IfStatement_AST(expr, b1, null);
1710 return if_ast;
1711 }
1712 }
1713
1714 AST BREAK_STATEMENT()
1715 throws IOException
1716 {
1717 expectKeyword("break");
1718 return new BreakStatement_AST();
1719 }
1720
1721 AST BLOCK_OR_STMT()
1722 throws IOException
1723 {
1724
1725 return BLOCK_OR_STMT(false);
1726 }
1727
1728 AST BLOCK_OR_STMT(boolean require_terminator)
1729 throws IOException
1730 {
1731 opt_newline();
1732 AST block;
1733
1734 if (token == _OPEN_BRACE_) {
1735 lexer();
1736 block = STATEMENT_LIST();
1737 lexer(_CLOSE_BRACE_);
1738 return block;
1739 } else if (token == _SEMICOLON_) {
1740 block = null;
1741 } else {
1742 block = STATEMENT();
1743
1744 }
1745 if (require_terminator) {
1746 terminator();
1747 }
1748 return block;
1749 }
1750
1751 AST WHILE_STATEMENT()
1752 throws IOException
1753 {
1754 expectKeyword("while");
1755 lexer(_OPEN_PAREN_);
1756 AST expr = ASSIGNMENT_EXPRESSION(true, true, false);
1757 lexer(_CLOSE_PAREN_);
1758 AST block = BLOCK_OR_STMT();
1759 return new WhileStatement_AST(expr, block);
1760 }
1761
1762 AST FOR_STATEMENT()
1763 throws IOException
1764 {
1765 expectKeyword("for");
1766 AST expr1 = null;
1767 AST expr2 = null;
1768 AST expr3 = null;
1769 lexer(_OPEN_PAREN_);
1770 expr1 = OPT_SIMPLE_STATEMENT(false);
1771
1772
1773 if (token == KEYWORDS.get("in")) {
1774 if (expr1.ast1 == null || expr1.ast2 != null) {
1775 throw new ParserException("Invalid expression prior to 'in' statement. Got : " + expr1);
1776 }
1777 expr1 = expr1.ast1;
1778
1779 if (expr1 == null || !(expr1 instanceof ID_AST)) {
1780 throw new ParserException("Expecting an ID for 'in' statement. Got : " + expr1);
1781 }
1782
1783 lexer();
1784
1785 if (token != _ID_) {
1786 throw new ParserException("Expecting an ARRAY ID for 'in' statement. Got " + toTokenString(token) + ": " + text);
1787 }
1788 String arr_id = text.toString();
1789
1790
1791 AST array_id_ast = symbol_table.addArrayID(arr_id);
1792
1793 lexer();
1794
1795 lexer(_CLOSE_PAREN_);
1796 AST block = BLOCK_OR_STMT();
1797 return new ForInStatement_AST(expr1, array_id_ast, block);
1798 }
1799
1800 if (token == _SEMICOLON_) {
1801 lexer();
1802 } else {
1803 throw new ParserException("Expecting ;. Got " + toTokenString(token) + ": " + text);
1804 }
1805 if (token != _SEMICOLON_) {
1806 expr2 = ASSIGNMENT_EXPRESSION(true, true, false);
1807 }
1808 if (token == _SEMICOLON_) {
1809 lexer();
1810 } else {
1811 throw new ParserException("Expecting ;. Got " + toTokenString(token) + ": " + text);
1812 }
1813 if (token != _CLOSE_PAREN_) {
1814 expr3 = OPT_SIMPLE_STATEMENT(true);
1815 }
1816 lexer(_CLOSE_PAREN_);
1817 AST block = BLOCK_OR_STMT();
1818 return new ForStatement_AST(expr1, expr2, expr3, block);
1819 }
1820
1821 AST OPT_SIMPLE_STATEMENT(boolean allow_in_keyword)
1822 throws IOException
1823 {
1824 if (token == _SEMICOLON_) {
1825 return null;
1826 } else if (token == KEYWORDS.get("delete")) {
1827 return DELETE_STATEMENT();
1828 } else if (token == KEYWORDS.get("print")) {
1829 return PRINT_STATEMENT();
1830 } else if (token == KEYWORDS.get("printf")) {
1831 return PRINTF_STATEMENT();
1832 } else {
1833
1834 return EXPRESSION_STATEMENT(allow_in_keyword, true);
1835 }
1836 }
1837
1838 AST DELETE_STATEMENT()
1839 throws IOException
1840 {
1841 boolean parens = (c == '(');
1842 expectKeyword("delete");
1843 if (parens) {
1844 assert token == _OPEN_PAREN_;
1845 lexer();
1846 }
1847 AST symbol_ast = SYMBOL(true, true);
1848 if (parens) {
1849 lexer(_CLOSE_PAREN_);
1850 }
1851
1852 return new DeleteStatement_AST(symbol_ast);
1853 }
1854
1855 private static final class ParsedPrintStatement {
1856
1857 private AST funcParams;
1858 private int outputToken;
1859 private AST outputExpr;
1860
1861 ParsedPrintStatement(AST funcParams, int outputToken, AST outputExpr) {
1862 this.funcParams = funcParams;
1863 this.outputToken = outputToken;
1864 this.outputExpr = outputExpr;
1865 }
1866
1867 public AST getFuncParams() {
1868 return funcParams;
1869 }
1870
1871 public int getOutputToken() {
1872 return outputToken;
1873 }
1874
1875 public AST getOutputExpr() {
1876 return outputExpr;
1877 }
1878 }
1879
1880 private ParsedPrintStatement parsePrintStatement(boolean parens)
1881 throws IOException
1882 {
1883 AST func_params;
1884 int output_token;
1885 AST output_expr;
1886 if (parens) {
1887 lexer();
1888 if (token == _CLOSE_PAREN_) {
1889 func_params = null;
1890 } else {
1891 func_params = EXPRESSION_LIST(true, true);
1892 }
1893 lexer(_CLOSE_PAREN_);
1894 } else {
1895 if (token == _NEWLINE_ || token == _SEMICOLON_ || token == _CLOSE_BRACE_ || token == _CLOSE_PAREN_
1896 || (token == _GT_ || token == _APPEND_ || token == _PIPE_))
1897 {
1898 func_params = null;
1899 } else {
1900 func_params = EXPRESSION_LIST(false, true);
1901 }
1902 }
1903 if (token == _GT_ || token == _APPEND_ || token == _PIPE_) {
1904 output_token = token;
1905 lexer();
1906 output_expr = ASSIGNMENT_EXPRESSION(true, true, false);
1907 } else {
1908 output_token = -1;
1909 output_expr = null;
1910 }
1911
1912 return new ParsedPrintStatement(func_params, output_token, output_expr);
1913 }
1914
1915 AST PRINT_STATEMENT()
1916 throws IOException
1917 {
1918 boolean parens = (c == '(');
1919 expectKeyword("print");
1920 ParsedPrintStatement parsedPrintStatement = parsePrintStatement(parens);
1921
1922 return new Print_AST(
1923 parsedPrintStatement.getFuncParams(),
1924 parsedPrintStatement.getOutputToken(),
1925 parsedPrintStatement.getOutputExpr());
1926 }
1927
1928 AST PRINTF_STATEMENT()
1929 throws IOException
1930 {
1931 boolean parens = (c == '(');
1932 expectKeyword("printf");
1933 ParsedPrintStatement parsedPrintStatement = parsePrintStatement(parens);
1934
1935 return new Printf_AST(
1936 parsedPrintStatement.getFuncParams(),
1937 parsedPrintStatement.getOutputToken(),
1938 parsedPrintStatement.getOutputExpr());
1939 }
1940
1941 AST GETLINE_EXPRESSION(AST pipe_expr, boolean not_in_print_root, boolean allow_in_keyword)
1942 throws IOException
1943 {
1944 expectKeyword("getline");
1945 AST lvalue = LVALUE(not_in_print_root, allow_in_keyword);
1946 if (token == _LT_) {
1947 lexer();
1948 AST assignment_expr = ASSIGNMENT_EXPRESSION(not_in_print_root, allow_in_keyword, false);
1949 if (pipe_expr != null) {
1950 throw new ParserException("Cannot have both pipe expression and redirect into a getline.");
1951 }
1952 return new Getline_AST(pipe_expr, lvalue, assignment_expr);
1953 } else {
1954 return new Getline_AST(pipe_expr, lvalue, null);
1955 }
1956 }
1957
1958 AST LVALUE(boolean not_in_print_root, boolean allow_in_keyword)
1959 throws IOException
1960 {
1961
1962 if (token == _DOLLAR_) {
1963 return FACTOR(not_in_print_root, allow_in_keyword, false);
1964 }
1965 if (token == _ID_) {
1966 return FACTOR(not_in_print_root, allow_in_keyword, false);
1967 }
1968 return null;
1969 }
1970
1971 AST DO_STATEMENT()
1972 throws IOException
1973 {
1974 expectKeyword("do");
1975 opt_newline();
1976 AST block = BLOCK_OR_STMT();
1977 if (token == _SEMICOLON_) {
1978 lexer();
1979 }
1980 opt_newline();
1981 expectKeyword("while");
1982 lexer(_OPEN_PAREN_);
1983 AST expr = ASSIGNMENT_EXPRESSION(true, true, false);
1984 lexer(_CLOSE_PAREN_);
1985 return new DoStatement_AST(block, expr);
1986 }
1987
1988 AST RETURN_STATEMENT()
1989 throws IOException
1990 {
1991 expectKeyword("return");
1992 if (token == _SEMICOLON_ || token == _NEWLINE_ || token == _CLOSE_BRACE_) {
1993 return new ReturnStatement_AST(null);
1994 } else {
1995 return new ReturnStatement_AST(ASSIGNMENT_EXPRESSION(true, true, false));
1996 }
1997 }
1998
1999 AST EXIT_STATEMENT()
2000 throws IOException
2001 {
2002 expectKeyword("exit");
2003 if (token == _SEMICOLON_ || token == _NEWLINE_ || token == _CLOSE_BRACE_) {
2004 return new ExitStatement_AST(null);
2005 } else {
2006 return new ExitStatement_AST(ASSIGNMENT_EXPRESSION(true, true, false));
2007 }
2008 }
2009
2010 AST SLEEP_STATEMENT()
2011 throws IOException
2012 {
2013 boolean parens = (c == '(');
2014 expectKeyword("_sleep");
2015 if (token == _SEMICOLON_ || token == _NEWLINE_ || token == _CLOSE_BRACE_) {
2016 return new SleepStatement_AST(null);
2017 } else {
2018
2019
2020 if (parens) {
2021 lexer();
2022 }
2023 AST sleep_ast;
2024 if (token == _CLOSE_PAREN_) {
2025 sleep_ast = new SleepStatement_AST(null);
2026 } else {
2027 sleep_ast = new SleepStatement_AST(ASSIGNMENT_EXPRESSION(true, true, false));
2028 }
2029 if (parens) {
2030 lexer(_CLOSE_PAREN_);
2031 }
2032 return sleep_ast;
2033 }
2034 }
2035
2036 AST DUMP_STATEMENT()
2037 throws IOException
2038 {
2039 boolean parens = (c == '(');
2040 expectKeyword("_dump");
2041 if (token == _SEMICOLON_ || token == _NEWLINE_ || token == _CLOSE_BRACE_) {
2042 return new DumpStatement_AST(null);
2043 } else {
2044 if (parens) {
2045 lexer();
2046 }
2047 AST dump_ast;
2048 if (token == _CLOSE_PAREN_) {
2049 dump_ast = new DumpStatement_AST(null);
2050 } else {
2051 dump_ast = new DumpStatement_AST(EXPRESSION_LIST(true, true));
2052 }
2053 if (parens) {
2054 lexer(_CLOSE_PAREN_);
2055 }
2056 return dump_ast;
2057 }
2058 }
2059
2060 AST NEXT_STATEMENT()
2061 throws IOException
2062 {
2063 expectKeyword("next");
2064 return new NextStatement_AST();
2065 }
2066
2067 AST CONTINUE_STATEMENT()
2068 throws IOException
2069 {
2070 expectKeyword("continue");
2071 return new ContinueStatement_AST();
2072 }
2073
2074 private void expectKeyword(String keyword)
2075 throws IOException
2076 {
2077 if (token == KEYWORDS.get(keyword)) {
2078 lexer();
2079 } else {
2080 throw new ParserException("Expecting " + keyword + ". Got " + toTokenString(token) + ": " + text);
2081 }
2082 }
2083
2084
2085
2086
2087 private abstract class AST implements AwkSyntaxTree {
2088
2089 private final String sourceDescription = scriptSources.get(scriptSourcesCurrentIndex).getDescription();
2090 private final int lineNo = reader.getLineNumber() + 1;
2091 protected AST parent;
2092 protected AST ast1, ast2, ast3, ast4;
2093
2094 protected final AST searchFor(Class<?> cls) {
2095 AST ptr = this;
2096 while (ptr != null) {
2097 if (cls.isInstance(ptr)) {
2098 return ptr;
2099 }
2100 ptr = ptr.parent;
2101 }
2102 return null;
2103 }
2104
2105 protected AST() {}
2106
2107 protected AST(AST ast1) {
2108 this.ast1 = ast1;
2109
2110 if (ast1 != null) {
2111 ast1.parent = this;
2112 }
2113 }
2114
2115 protected AST(AST ast1, AST ast2) {
2116 this.ast1 = ast1;
2117 this.ast2 = ast2;
2118
2119 if (ast1 != null) {
2120 ast1.parent = this;
2121 }
2122 if (ast2 != null) {
2123 ast2.parent = this;
2124 }
2125 }
2126
2127 protected AST(AST ast1, AST ast2, AST ast3) {
2128 this.ast1 = ast1;
2129 this.ast2 = ast2;
2130 this.ast3 = ast3;
2131
2132 if (ast1 != null) {
2133 ast1.parent = this;
2134 }
2135 if (ast2 != null) {
2136 ast2.parent = this;
2137 }
2138 if (ast3 != null) {
2139 ast3.parent = this;
2140 }
2141 }
2142
2143 protected AST(AST ast1, AST ast2, AST ast3, AST ast4) {
2144 this.ast1 = ast1;
2145 this.ast2 = ast2;
2146 this.ast3 = ast3;
2147 this.ast4 = ast4;
2148
2149 if (ast1 != null) {
2150 ast1.parent = this;
2151 }
2152 if (ast2 != null) {
2153 ast2.parent = this;
2154 }
2155 if (ast3 != null) {
2156 ast3.parent = this;
2157 }
2158 if (ast4 != null) {
2159 ast4.parent = this;
2160 }
2161 }
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173 @Override
2174 public void dump(PrintStream ps) {
2175 dump(ps, 0);
2176 }
2177
2178 private void dump(PrintStream ps, int lvl) {
2179 StringBuffer spaces = new StringBuffer();
2180 for (int i = 0; i < lvl; i++) {
2181 spaces.append(' ');
2182 }
2183 ps.println(spaces + toString());
2184 if (ast1 != null) {
2185 ast1.dump(ps, lvl + 1);
2186 }
2187 if (ast2 != null) {
2188 ast2.dump(ps, lvl + 1);
2189 }
2190 if (ast3 != null) {
2191 ast3.dump(ps, lvl + 1);
2192 }
2193 if (ast4 != null) {
2194 ast4.dump(ps, lvl + 1);
2195 }
2196 }
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207 @Override
2208 public void semanticAnalysis() {
2209 if (ast1 != null) {
2210 ast1.semanticAnalysis();
2211 }
2212 if (ast2 != null) {
2213 ast2.semanticAnalysis();
2214 }
2215 if (ast3 != null) {
2216 ast3.semanticAnalysis();
2217 }
2218 if (ast4 != null) {
2219 ast4.semanticAnalysis();
2220 }
2221 }
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239 @Override
2240 public abstract int populateTuples(AwkTuples tuples);
2241
2242 protected final void pushSourceLineNumber(AwkTuples tuples) {
2243 tuples.pushSourceLineNumber(lineNo);
2244 }
2245
2246 protected final void popSourceLineNumber(AwkTuples tuples) {
2247 tuples.popSourceLineNumber(lineNo);
2248 }
2249
2250 protected boolean is_begin = isBegin();
2251 private boolean isBegin() {
2252 boolean result = is_begin;
2253 if (!result && ast1 != null) {
2254 result = ast1.isBegin();
2255 }
2256 if (!result && ast2 != null) {
2257 result = ast2.isBegin();
2258 }
2259 if (!result && ast3 != null) {
2260 result = ast3.isBegin();
2261 }
2262 if (!result && ast4 != null) {
2263 result = ast4.isBegin();
2264 }
2265 return result;
2266 }
2267
2268 protected boolean is_end = isEnd();
2269 private boolean isEnd() {
2270 boolean result = is_end;
2271 if (!result && ast1 != null) {
2272 result = ast1.isEnd();
2273 }
2274 if (!result && ast2 != null) {
2275 result = ast2.isEnd();
2276 }
2277 if (!result && ast3 != null) {
2278 result = ast3.isEnd();
2279 }
2280 if (!result && ast4 != null) {
2281 result = ast4.isEnd();
2282 }
2283 return result;
2284 }
2285
2286 protected boolean is_function = isFunction();
2287 private boolean isFunction() {
2288 boolean result = is_function;
2289 if (!result && ast1 != null) {
2290 result = ast1.isFunction();
2291 }
2292 if (!result && ast2 != null) {
2293 result = ast2.isFunction();
2294 }
2295 if (!result && ast3 != null) {
2296 result = ast3.isFunction();
2297 }
2298 if (!result && ast4 != null) {
2299 result = ast4.isFunction();
2300 }
2301 return result;
2302 }
2303
2304 public boolean isArray() {
2305 return false;
2306 }
2307
2308 public boolean isScalar() {
2309 return false;
2310 }
2311
2312
2313
2314
2315
2316 protected class SemanticException extends RuntimeException {
2317
2318 private static final long serialVersionUID = 1L;
2319
2320 SemanticException(String msg) {
2321 super(msg + " (" + sourceDescription + ":" + lineNo + ")");
2322 }
2323 }
2324
2325 protected final void throwSemanticException(String msg) {
2326 throw new SemanticException(msg);
2327 }
2328
2329 @Override
2330 public String toString() {
2331 return getClass().getName().replaceFirst(".*[$.]", "");
2332 }
2333 }
2334
2335 private abstract class ScalarExpression_AST extends AST {
2336
2337 protected ScalarExpression_AST() {
2338 super();
2339 }
2340
2341 protected ScalarExpression_AST(AST a1) {
2342 super(a1);
2343 }
2344
2345 protected ScalarExpression_AST(AST a1, AST a2) {
2346 super(a1, a2);
2347 }
2348
2349 protected ScalarExpression_AST(AST a1, AST a2, AST a3) {
2350 super(a1, a2, a3);
2351 }
2352
2353 @Override
2354 public final boolean isArray() {
2355 return false;
2356 }
2357
2358 @Override
2359 public final boolean isScalar() {
2360 return true;
2361 }
2362 }
2363
2364 private static boolean isRule(AST ast) {
2365 return ast != null && !ast.isBegin() && !ast.isEnd() && !ast.isFunction();
2366 }
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380 @SuppressWarnings("unused")
2381 private static boolean isExtensionConditionRule(AST ast) {
2382 if (!isRule(ast)) {
2383 return false;
2384 }
2385 if (ast.ast1 == null) {
2386 return false;
2387 }
2388
2389 if (!containsASTType(ast.ast1, Extension_AST.class)) {
2390 return false;
2391 }
2392
2393 if (containsASTType(ast.ast1, new Class[] {FunctionCall_AST.class, DollarExpression_AST.class})) {
2394 return false;
2395 }
2396
2397 return true;
2398 }
2399
2400 private static boolean containsASTType(AST ast, Class<?> cls) {
2401 return containsASTType(ast, new Class[] {cls});
2402 }
2403
2404 private static boolean containsASTType(AST ast, Class<?>[] cls_array) {
2405 if (ast == null) {
2406 return false;
2407 }
2408 for (Class<?> cls : cls_array) {
2409 if (cls.isInstance(ast)) {
2410 return true;
2411 }
2412 }
2413 return containsASTType(ast.ast1, cls_array)
2414 || containsASTType(ast.ast2, cls_array)
2415 || containsASTType(ast.ast3, cls_array)
2416 || containsASTType(ast.ast4, cls_array);
2417 }
2418
2419 private Address next_address;
2420
2421 private final class RuleList_AST extends AST {
2422
2423 private RuleList_AST(AST rule, AST rest) {
2424 super(rule, rest);
2425 }
2426
2427 @Override
2428 public int populateTuples(AwkTuples tuples) {
2429 pushSourceLineNumber(tuples);
2430
2431 next_address = tuples.createAddress("next_address");
2432
2433 Address exit_addr = tuples.createAddress("end blocks start address");
2434
2435
2436 Address start_address = tuples.createAddress("start address");
2437
2438 tuples.setExitAddress(exit_addr);
2439
2440 tuples.gotoAddress(start_address);
2441
2442 AST ptr;
2443
2444
2445
2446 ptr = this;
2447 while (ptr != null) {
2448 if (ptr.ast1 != null && ptr.ast1.isFunction()) {
2449 assert ptr.ast1 != null;
2450 int ast1_count = ptr.ast1.populateTuples(tuples);
2451 assert ast1_count == 0;
2452 }
2453
2454 ptr = ptr.ast2;
2455 }
2456
2457
2458
2459 tuples.address(start_address);
2460
2461
2462 ID_AST nr_ast = symbol_table.getID("NR");
2463 ID_AST fnr_ast = symbol_table.getID("FNR");
2464 ID_AST nf_ast = symbol_table.getID("NF");
2465 ID_AST fs_ast = symbol_table.getID("FS");
2466 ID_AST rs_ast = symbol_table.getID("RS");
2467 ID_AST ofs_ast = symbol_table.getID("OFS");
2468 ID_AST ors_ast = symbol_table.getID("ORS");
2469 ID_AST rstart_ast = symbol_table.getID("RSTART");
2470 ID_AST rlength_ast = symbol_table.getID("RLENGTH");
2471 ID_AST filename_ast = symbol_table.getID("FILENAME");
2472 ID_AST subsep_ast = symbol_table.getID("SUBSEP");
2473 ID_AST convfmt_ast = symbol_table.getID("CONVFMT");
2474 ID_AST ofmt_ast = symbol_table.getID("OFMT");
2475 ID_AST environ_ast = symbol_table.getID("ENVIRON");
2476 ID_AST argc_ast = symbol_table.getID("ARGC");
2477 ID_AST argv_ast = symbol_table.getID("ARGV");
2478
2479
2480
2481
2482 tuples.setNumGlobals(symbol_table.numGlobals());
2483
2484 tuples.nfOffset(nf_ast.offset);
2485 tuples.nrOffset(nr_ast.offset);
2486 tuples.fnrOffset(fnr_ast.offset);
2487 tuples.fsOffset(fs_ast.offset);
2488 tuples.rsOffset(rs_ast.offset);
2489 tuples.ofsOffset(ofs_ast.offset);
2490 tuples.orsOffset(ors_ast.offset);
2491 tuples.rstartOffset(rstart_ast.offset);
2492 tuples.rlengthOffset(rlength_ast.offset);
2493 tuples.filenameOffset(filename_ast.offset);
2494 tuples.subsepOffset(subsep_ast.offset);
2495 tuples.convfmtOffset(convfmt_ast.offset);
2496 tuples.ofmtOffset(ofmt_ast.offset);
2497 tuples.environOffset(environ_ast.offset);
2498 tuples.argcOffset(argc_ast.offset);
2499 tuples.argvOffset(argv_ast.offset);
2500
2501
2502 ptr = this;
2503
2504 while (ptr != null) {
2505 if (ptr.ast1 != null && ptr.ast1.isBegin()) {
2506 ptr.ast1.populateTuples(tuples);
2507 }
2508
2509 ptr = ptr.ast2;
2510 }
2511
2512
2513
2514 boolean req_input = false;
2515
2516
2517 ptr = this;
2518 while (!req_input && (ptr != null)) {
2519 if (isRule(ptr.ast1)) {
2520 req_input = true;
2521 }
2522 ptr = ptr.ast2;
2523 }
2524
2525
2526 ptr = this;
2527 while (!req_input && (ptr != null)) {
2528 if (ptr.ast1 != null && ptr.ast1.isEnd()) {
2529 req_input = true;
2530 }
2531 ptr = ptr.ast2;
2532 }
2533
2534 if (req_input) {
2535 Address input_loop_address = null;
2536 Address no_more_input = null;
2537
2538 input_loop_address = tuples.createAddress("input_loop_address");
2539 tuples.address(input_loop_address);
2540
2541 ptr = this;
2542
2543 no_more_input = tuples.createAddress("no_more_input");
2544 tuples.consumeInput(no_more_input);
2545
2546
2547 while (ptr != null) {
2548
2549 if (isRule(ptr.ast1)) {
2550 ptr.ast1.populateTuples(tuples);
2551 }
2552 ptr = ptr.ast2;
2553 }
2554 tuples.address(next_address);
2555
2556 tuples.gotoAddress(input_loop_address);
2557
2558 if (req_input) {
2559 tuples.address(no_more_input);
2560
2561 tuples.nop();
2562 }
2563 }
2564
2565
2566
2567 tuples.address(exit_addr);
2568 tuples.setWithinEndBlocks(true);
2569
2570
2571 ptr = this;
2572 while (ptr != null) {
2573 if (ptr.ast1 != null && ptr.ast1.isEnd()) {
2574 ptr.ast1.populateTuples(tuples);
2575 }
2576 ptr = ptr.ast2;
2577 }
2578
2579
2580
2581 tuples.nop();
2582
2583 popSourceLineNumber(tuples);
2584 return 0;
2585 }
2586 }
2587
2588
2589 private final class Rule_AST extends AST implements Nextable {
2590
2591 private Rule_AST(AST opt_expression, AST opt_rule) {
2592 super(opt_expression, opt_rule);
2593 }
2594
2595 @Override
2596 public int populateTuples(AwkTuples tuples) {
2597 pushSourceLineNumber(tuples);
2598 if (ast1 == null) {
2599
2600 tuples.push(1);
2601 } else {
2602 int result = ast1.populateTuples(tuples);
2603 assert result == 1;
2604 }
2605
2606 Address bypass_rule = tuples.createAddress("bypass_rule");
2607 tuples.ifFalse(bypass_rule);
2608
2609 if (ast2 == null) {
2610 if (ast1 == null || !ast1.isBegin() && !ast1.isEnd()) {
2611
2612 tuples.print(0);
2613 }
2614
2615
2616 } else {
2617
2618 int ast2_count = ast2.populateTuples(tuples);
2619 assert ast2_count == 0;
2620 }
2621 tuples.address(bypass_rule).nop();
2622 popSourceLineNumber(tuples);
2623 return 0;
2624 }
2625
2626 @Override
2627 public Address nextAddress() {
2628 if (!isRule(this)) {
2629 throw new SemanticException("Must call next within an input rule.");
2630 }
2631 if (next_address == null) {
2632 throw new SemanticException("Cannot call next here.");
2633 }
2634 return next_address;
2635 }
2636 }
2637
2638 private final class IfStatement_AST extends AST {
2639
2640 private IfStatement_AST(AST expr, AST b1, AST b2) {
2641 super(expr, b1, b2);
2642 }
2643
2644 @Override
2645 public int populateTuples(AwkTuples tuples) {
2646 pushSourceLineNumber(tuples);
2647 assert ast1 != null;
2648
2649 Address elseblock = tuples.createAddress("elseblock");
2650
2651 int ast1_result = ast1.populateTuples(tuples);
2652 assert ast1_result == 1;
2653 tuples.ifFalse(elseblock);
2654 if (ast2 != null) {
2655 int ast2_result = ast2.populateTuples(tuples);
2656 assert ast2_result == 0;
2657 }
2658 if (ast3 == null) {
2659 tuples.address(elseblock);
2660 } else {
2661 Address end = tuples.createAddress("end");
2662 tuples.gotoAddress(end);
2663 tuples.address(elseblock);
2664 int ast3_result = ast3.populateTuples(tuples);
2665 assert ast3_result == 0;
2666 tuples.address(end);
2667 }
2668 popSourceLineNumber(tuples);
2669 return 0;
2670 }
2671 }
2672
2673 private final class TernaryExpression_AST extends ScalarExpression_AST {
2674
2675 private TernaryExpression_AST(AST a1, AST a2, AST a3) {
2676 super(a1, a2, a3);
2677 }
2678
2679 @Override
2680 public int populateTuples(AwkTuples tuples) {
2681 pushSourceLineNumber(tuples);
2682 assert ast1 != null;
2683 assert ast2 != null;
2684 assert ast3 != null;
2685
2686 Address elseexpr = tuples.createAddress("elseexpr");
2687 Address end_tertiary = tuples.createAddress("end_tertiary");
2688
2689 int ast1_result = ast1.populateTuples(tuples);
2690 assert ast1_result == 1;
2691 tuples.ifFalse(elseexpr);
2692 int ast2_result = ast2.populateTuples(tuples);
2693 assert ast2_result == 1;
2694 tuples.gotoAddress(end_tertiary);
2695
2696 tuples.address(elseexpr);
2697 int ast3_result = ast3.populateTuples(tuples);
2698 assert ast3_result == 1;
2699
2700 tuples.address(end_tertiary);
2701
2702 popSourceLineNumber(tuples);
2703 return 1;
2704 }
2705 }
2706
2707 private final class WhileStatement_AST extends AST implements Breakable, Continueable {
2708
2709 private Address break_address;
2710 private Address continue_address;
2711
2712 private WhileStatement_AST(AST expr, AST block) {
2713 super(expr, block);
2714 }
2715
2716 @Override
2717 public Address breakAddress() {
2718 assert break_address != null;
2719 return break_address;
2720 }
2721
2722 @Override
2723 public Address continueAddress() {
2724 assert continue_address != null;
2725 return continue_address;
2726 }
2727
2728 @Override
2729 public int populateTuples(AwkTuples tuples) {
2730 pushSourceLineNumber(tuples);
2731
2732 break_address = tuples.createAddress("break_address");
2733
2734
2735 Address loop = tuples.createAddress("loop");
2736 tuples.address(loop);
2737
2738
2739 continue_address = loop;
2740
2741
2742 assert (ast1 != null);
2743 int ast1_result = ast1.populateTuples(tuples);
2744 assert ast1_result == 1;
2745 tuples.ifFalse(break_address);
2746
2747 if (ast2 != null) {
2748 int ast2_result = ast2.populateTuples(tuples);
2749 assert ast2_result == 0;
2750 }
2751
2752 tuples.gotoAddress(loop);
2753
2754 tuples.address(break_address);
2755
2756 popSourceLineNumber(tuples);
2757 return 0;
2758 }
2759 }
2760
2761 private final class DoStatement_AST extends AST implements Breakable, Continueable {
2762
2763 private Address break_address;
2764 private Address continue_address;
2765
2766 private DoStatement_AST(AST block, AST expr) {
2767 super(block, expr);
2768 }
2769
2770 @Override
2771 public Address breakAddress() {
2772 assert break_address != null;
2773 return break_address;
2774 }
2775
2776 @Override
2777 public Address continueAddress() {
2778 assert continue_address != null;
2779 return continue_address;
2780 }
2781
2782 @Override
2783 public int populateTuples(AwkTuples tuples) {
2784 pushSourceLineNumber(tuples);
2785
2786 break_address = tuples.createAddress("break_address");
2787 continue_address = tuples.createAddress("continue_address");
2788
2789
2790 Address loop = tuples.createAddress("loop");
2791 tuples.address(loop);
2792
2793 if (ast1 != null) {
2794 int ast1_result = ast1.populateTuples(tuples);
2795 assert ast1_result == 0;
2796 }
2797
2798
2799 tuples.address(continue_address);
2800
2801
2802 assert (ast2 != null);
2803 int ast2_result = ast2.populateTuples(tuples);
2804 assert ast2_result == 1;
2805 tuples.ifTrue(loop);
2806
2807
2808
2809 tuples.address(break_address);
2810
2811 popSourceLineNumber(tuples);
2812 return 0;
2813 }
2814 }
2815
2816 private final class ForStatement_AST extends AST implements Breakable, Continueable {
2817
2818 private Address break_address;
2819 private Address continue_address;
2820
2821 private ForStatement_AST(AST expr1, AST expr2, AST expr3, AST block) {
2822 super(expr1, expr2, expr3, block);
2823 }
2824
2825 @Override
2826 public Address breakAddress() {
2827 assert break_address != null;
2828 return break_address;
2829 }
2830
2831 @Override
2832 public Address continueAddress() {
2833 assert continue_address != null;
2834 return continue_address;
2835 }
2836
2837 @Override
2838 public int populateTuples(AwkTuples tuples) {
2839 pushSourceLineNumber(tuples);
2840
2841 break_address = tuples.createAddress("break_address");
2842 continue_address = tuples.createAddress("continue_address");
2843
2844
2845 if (ast1 != null) {
2846 int ast1_result = ast1.populateTuples(tuples);
2847 for (int i = 0; i < ast1_result; i++) {
2848 tuples.pop();
2849 }
2850 }
2851
2852 Address loop = tuples.createAddress("loop");
2853 tuples.address(loop);
2854
2855 if (ast2 != null) {
2856
2857
2858 int ast2_result = ast2.populateTuples(tuples);
2859 assert ast2_result == 1;
2860 tuples.ifFalse(break_address);
2861 }
2862
2863 if (ast4 != null) {
2864
2865 int ast4_result = ast4.populateTuples(tuples);
2866 assert ast4_result == 0;
2867 }
2868
2869
2870 tuples.address(continue_address);
2871
2872
2873 if (ast3 != null) {
2874 int ast3_result = ast3.populateTuples(tuples);
2875 for (int i = 0; i < ast3_result; i++) {
2876 tuples.pop();
2877 }
2878 }
2879
2880 tuples.gotoAddress(loop);
2881
2882 tuples.address(break_address);
2883
2884 popSourceLineNumber(tuples);
2885 return 0;
2886 }
2887 }
2888
2889 private final class ForInStatement_AST extends AST implements Breakable, Continueable {
2890
2891 private Address break_address;
2892 private Address continue_address;
2893
2894 private ForInStatement_AST(AST key_id_ast, AST array_id_ast, AST block) {
2895 super(key_id_ast, array_id_ast, block);
2896 }
2897
2898 @Override
2899 public Address breakAddress() {
2900 assert break_address != null;
2901 return break_address;
2902 }
2903
2904 @Override
2905 public Address continueAddress() {
2906 assert continue_address != null;
2907 return continue_address;
2908 }
2909
2910 @Override
2911 public int populateTuples(AwkTuples tuples) {
2912 pushSourceLineNumber(tuples);
2913
2914 assert ast2 != null;
2915
2916 ID_AST array_id_ast = (ID_AST) ast2;
2917 if (array_id_ast.isScalar()) {
2918 throw new SemanticException(array_id_ast + " is not an array");
2919 }
2920 array_id_ast.setArray(true);
2921
2922 break_address = tuples.createAddress("break_address");
2923
2924 ast2.populateTuples(tuples);
2925
2926 tuples.keylist();
2927
2928
2929
2930
2931
2932 Address loop = tuples.createAddress("loop");
2933 tuples.address(loop);
2934
2935
2936 continue_address = loop;
2937
2938 assert tuples.checkClass(KeyList.class);
2939
2940
2941 tuples.dup();
2942 tuples.isEmptyList(break_address);
2943
2944 assert tuples.checkClass(KeyList.class);
2945
2946
2947 tuples.dup();
2948 tuples.getFirstAndRemoveFromList();
2949
2950 tuples.assign(((ID_AST) ast1).offset, ((ID_AST) ast1).is_global);
2951 tuples.pop();
2952
2953 if (ast3 != null) {
2954
2955 int ast3_result = ast3.populateTuples(tuples);
2956 assert ast3_result == 0;
2957 }
2958
2959
2960 assert tuples.checkClass(KeyList.class);
2961
2962 tuples.gotoAddress(loop);
2963
2964 tuples.address(break_address);
2965 tuples.pop();
2966
2967 popSourceLineNumber(tuples);
2968 return 0;
2969 }
2970 }
2971
2972 @SuppressWarnings("unused")
2973 private final class EmptyStatement_AST extends AST {
2974
2975 private EmptyStatement_AST() {
2976 super();
2977 }
2978
2979 @Override
2980 public int populateTuples(AwkTuples tuples) {
2981 pushSourceLineNumber(tuples);
2982
2983 popSourceLineNumber(tuples);
2984 return 0;
2985 }
2986 }
2987
2988
2989
2990
2991
2992
2993 private final class ExpressionStatement_AST extends AST {
2994
2995 private ExpressionStatement_AST(AST expr) {
2996 super(expr);
2997 }
2998
2999 @Override
3000 public int populateTuples(AwkTuples tuples) {
3001 pushSourceLineNumber(tuples);
3002 int expr_count = ast1.populateTuples(tuples);
3003 if (expr_count == 0) {
3004 } else if (expr_count == 1) {
3005 tuples.pop();
3006 } else {
3007 assert false : "expr_count = " + expr_count;
3008 }
3009 popSourceLineNumber(tuples);
3010 return 0;
3011 }
3012 }
3013
3014 private final class AssignmentExpression_AST extends ScalarExpression_AST {
3015
3016
3017 private int op;
3018 private String text;
3019
3020 private AssignmentExpression_AST(AST lhs, int op, String text, AST rhs) {
3021 super(lhs, rhs);
3022 this.op = op;
3023 this.text = text;
3024 }
3025
3026 @Override
3027 public String toString() {
3028 return super.toString() + " (" + op + "/" + text + ")";
3029 }
3030
3031 @Override
3032 public int populateTuples(AwkTuples tuples) {
3033 pushSourceLineNumber(tuples);
3034 assert ast2 != null;
3035 int ast2_count = ast2.populateTuples(tuples);
3036 assert ast2_count == 1;
3037
3038 if (ast1 instanceof ID_AST) {
3039 ID_AST id_ast = (ID_AST) ast1;
3040 if (id_ast.isArray()) {
3041 throw new SemanticException("Cannot use " + id_ast + " as a scalar. It is an array.");
3042 }
3043 id_ast.setScalar(true);
3044 if (op == _EQUALS_) {
3045
3046
3047 tuples.assign(id_ast.offset, id_ast.is_global);
3048 } else if (op == _PLUS_EQ_) {
3049 tuples.plusEq(id_ast.offset, id_ast.is_global);
3050 } else if (op == _MINUS_EQ_) {
3051 tuples.minusEq(id_ast.offset, id_ast.is_global);
3052 } else if (op == _MULT_EQ_) {
3053 tuples.multEq(id_ast.offset, id_ast.is_global);
3054 } else if (op == _DIV_EQ_) {
3055 tuples.divEq(id_ast.offset, id_ast.is_global);
3056 } else if (op == _MOD_EQ_) {
3057 tuples.modEq(id_ast.offset, id_ast.is_global);
3058 } else if (op == _POW_EQ_) {
3059 tuples.powEq(id_ast.offset, id_ast.is_global);
3060 } else {
3061 throw new Error("Unhandled op: "+op+" / "+text);
3062 }
3063 if (id_ast.id.equals("RS")) {
3064 tuples.applyRS();
3065 }
3066 } else if (ast1 instanceof ArrayReference_AST) {
3067 ArrayReference_AST arr = (ArrayReference_AST) ast1;
3068
3069 assert arr.ast2 != null;
3070 int arr_ast2_result = arr.ast2.populateTuples(tuples);
3071 assert arr_ast2_result == 1;
3072
3073 ID_AST id_ast = (ID_AST) arr.ast1;
3074 if (id_ast.isScalar()) {
3075 throw new SemanticException("Cannot use " + id_ast + " as an array. It is a scalar.");
3076 }
3077 id_ast.setArray(true);
3078 if (op == _EQUALS_) {
3079 tuples.assignArray(id_ast.offset, id_ast.is_global);
3080 } else if (op == _PLUS_EQ_) {
3081 tuples.plusEqArray(id_ast.offset, id_ast.is_global);
3082 } else if (op == _MINUS_EQ_) {
3083 tuples.minusEqArray(id_ast.offset, id_ast.is_global);
3084 } else if (op == _MULT_EQ_) {
3085 tuples.multEqArray(id_ast.offset, id_ast.is_global);
3086 } else if (op == _DIV_EQ_) {
3087 tuples.divEqArray(id_ast.offset, id_ast.is_global);
3088 } else if (op == _MOD_EQ_) {
3089 tuples.modEqArray(id_ast.offset, id_ast.is_global);
3090 } else if (op == _POW_EQ_) {
3091 tuples.powEqArray(id_ast.offset, id_ast.is_global);
3092 } else {
3093 throw new NotImplementedError("Unhandled op: "+op+" / "+text+" for arrays.");
3094 }
3095 } else if (ast1 instanceof DollarExpression_AST) {
3096 DollarExpression_AST dollar_expr = (DollarExpression_AST) ast1;
3097 assert dollar_expr.ast1 != null;
3098 int ast1_result = dollar_expr.ast1.populateTuples(tuples);
3099 assert ast1_result == 1;
3100
3101
3102 if (op == _EQUALS_) {
3103 tuples.assignAsInputField();
3104 } else if (op == _PLUS_EQ_) {
3105 tuples.plusEqInputField();
3106 } else if (op == _MINUS_EQ_) {
3107 tuples.minusEqInputField();
3108 } else if (op == _MULT_EQ_) {
3109 tuples.multEqInputField();
3110 } else if (op == _DIV_EQ_) {
3111 tuples.divEqInputField();
3112 } else if (op == _MOD_EQ_) {
3113 tuples.modEqInputField();
3114 } else if (op == _POW_EQ_) {
3115 tuples.powEqInputField();
3116 } else {
3117 throw new NotImplementedError("Unhandled op: "+op+" / "+text+" for dollar expressions.");
3118 }
3119 } else {
3120 throw new SemanticException("Cannot perform an assignment on: "+ast1);
3121 }
3122 popSourceLineNumber(tuples);
3123 return 1;
3124 }
3125 }
3126
3127 private final class InExpression_AST extends ScalarExpression_AST {
3128
3129 private InExpression_AST(AST arg, AST arr) {
3130 super(arg, arr);
3131 }
3132
3133 @Override
3134 public int populateTuples(AwkTuples tuples) {
3135 pushSourceLineNumber(tuples);
3136 assert ast1 != null;
3137 assert ast2 != null;
3138 if (!(ast2 instanceof ID_AST)) {
3139 throw new SemanticException("Expecting an array for rhs of IN. Got an expression.");
3140 }
3141 ID_AST arr_ast = (ID_AST) ast2;
3142 if (arr_ast.isScalar()) {
3143 throw new SemanticException("Expecting an array for rhs of IN. Got a scalar.");
3144 }
3145 arr_ast.setArray(true);
3146
3147 int ast1_result = ast1.populateTuples(tuples);
3148 assert ast1_result == 1;
3149
3150 int ast2_result = arr_ast.populateTuples(tuples);
3151 assert ast2_result == 1;
3152
3153 tuples.isIn();
3154
3155 popSourceLineNumber(tuples);
3156 return 1;
3157 }
3158 }
3159
3160 private final class ComparisonExpression_AST extends ScalarExpression_AST {
3161
3162
3163
3164
3165 private int op;
3166 private String text;
3167
3168 private ComparisonExpression_AST(AST lhs, int op, String text, AST rhs) {
3169 super(lhs, rhs);
3170 this.op = op;
3171 this.text = text;
3172 }
3173
3174 @Override
3175 public String toString() {
3176 return super.toString() + " (" + op + "/" + text + ")";
3177 }
3178
3179 @Override
3180 public int populateTuples(AwkTuples tuples) {
3181 pushSourceLineNumber(tuples);
3182 assert ast1 != null;
3183 assert ast2 != null;
3184
3185 int ast1_result = ast1.populateTuples(tuples);
3186 assert ast1_result == 1;
3187
3188 int ast2_result = ast2.populateTuples(tuples);
3189 assert ast2_result == 1;
3190
3191
3192
3193 if (op == _EQ_) {
3194 tuples.cmpEq();
3195 } else if (op == _NE_) {
3196 tuples.cmpEq();
3197 tuples.not();
3198 } else if (op == _LT_) {
3199 tuples.cmpLt();
3200 } else if (op == _GT_) {
3201 tuples.cmpGt();
3202 } else if (op == _LE_) {
3203 tuples.cmpGt();
3204 tuples.not();
3205 } else if (op == _GE_) {
3206 tuples.cmpLt();
3207 tuples.not();
3208 } else if (op == _MATCHES_) {
3209 tuples.matches();
3210 } else if (op == _NOT_MATCHES_) {
3211 tuples.matches();
3212 tuples.not();
3213 } else {
3214 throw new Error("Unhandled op: "+op+" / "+text);
3215 }
3216
3217 popSourceLineNumber(tuples);
3218 return 1;
3219 }
3220 }
3221
3222 private final class LogicalExpression_AST extends ScalarExpression_AST {
3223
3224
3225
3226
3227 private int op;
3228 private String text;
3229
3230 private LogicalExpression_AST(AST lhs, int op, String text, AST rhs) {
3231 super(lhs, rhs);
3232 this.op = op;
3233 this.text = text;
3234 }
3235
3236 @Override
3237 public String toString() {
3238 return super.toString() + " (" + op + "/" + text + ")";
3239 }
3240
3241 @Override
3242 public int populateTuples(AwkTuples tuples) {
3243 pushSourceLineNumber(tuples);
3244
3245 Address end = tuples.createAddress("end");
3246 int ast1_result = ast1.populateTuples(tuples);
3247 assert ast1_result == 1;
3248 tuples.dup();
3249 if (op == _OR_) {
3250
3251 tuples.ifTrue(end);
3252 } else if (op == _AND_) {
3253 tuples.ifFalse(end);
3254 } else {
3255 assert false : "Invalid op: " + op + " / " + text;
3256 }
3257 tuples.pop();
3258 int ast2_result = ast2.populateTuples(tuples);
3259 assert ast2_result == 1;
3260
3261 tuples.address(end);
3262
3263
3264 tuples.toNumber();
3265 popSourceLineNumber(tuples);
3266 return 1;
3267 }
3268 }
3269
3270 private final class BinaryExpression_AST extends ScalarExpression_AST {
3271
3272
3273
3274
3275 private int op;
3276 private String text;
3277
3278 private BinaryExpression_AST(AST lhs, int op, String text, AST rhs) {
3279 super(lhs, rhs);
3280 this.op = op;
3281 this.text = text;
3282 }
3283
3284 @Override
3285 public String toString() {
3286 return super.toString() + " (" + op + "/" + text + ")";
3287 }
3288
3289 @Override
3290 public int populateTuples(AwkTuples tuples) {
3291 pushSourceLineNumber(tuples);
3292 int ast1_result = ast1.populateTuples(tuples);
3293 assert ast1_result == 1;
3294 int ast2_result = ast2.populateTuples(tuples);
3295 assert ast2_result == 1;
3296 if (op == _PLUS_) {
3297 tuples.add();
3298 } else if (op == _MINUS_) {
3299 tuples.subtract();
3300 } else if (op == _MULT_) {
3301 tuples.multiply();
3302 } else if (op == _DIVIDE_) {
3303 tuples.divide();
3304 } else if (op == _MOD_) {
3305 tuples.mod();
3306 } else if (op == _POW_) {
3307 tuples.pow();
3308 } else {
3309 throw new Error("Unhandled op: " + op + " / " + this);
3310 }
3311 popSourceLineNumber(tuples);
3312 return 1;
3313 }
3314 }
3315
3316 private final class ConcatExpression_AST extends ScalarExpression_AST {
3317
3318 private ConcatExpression_AST(AST lhs, AST rhs) {
3319 super(lhs, rhs);
3320 }
3321
3322 @Override
3323 public int populateTuples(AwkTuples tuples) {
3324 pushSourceLineNumber(tuples);
3325 assert ast1 != null;
3326 int lhs_count = ast1.populateTuples(tuples);
3327 assert lhs_count == 1;
3328 assert ast2 != null;
3329 int rhs_count = ast2.populateTuples(tuples);
3330 assert rhs_count == 1;
3331 tuples.concat();
3332 popSourceLineNumber(tuples);
3333 return 1;
3334 }
3335 }
3336
3337 private final class NegativeExpression_AST extends ScalarExpression_AST {
3338
3339 private NegativeExpression_AST(AST expr) {
3340 super(expr);
3341 }
3342
3343 @Override
3344 public int populateTuples(AwkTuples tuples) {
3345 pushSourceLineNumber(tuples);
3346 assert ast1 != null;
3347 int ast1_result = ast1.populateTuples(tuples);
3348 assert ast1_result == 1;
3349 tuples.negate();
3350 popSourceLineNumber(tuples);
3351 return 1;
3352 }
3353 }
3354
3355 private final class UnaryPlusExpression_AST extends ScalarExpression_AST {
3356
3357 private UnaryPlusExpression_AST(AST expr) {
3358 super(expr);
3359 }
3360
3361 @Override
3362 public int populateTuples(AwkTuples tuples) {
3363 pushSourceLineNumber(tuples);
3364 assert ast1 != null;
3365 int ast1_result = ast1.populateTuples(tuples);
3366 assert ast1_result == 1;
3367 tuples.unaryPlus();
3368 popSourceLineNumber(tuples);
3369 return 1;
3370 }
3371 }
3372
3373 private final class NotExpression_AST extends ScalarExpression_AST {
3374
3375 private NotExpression_AST(AST expr) {
3376 super(expr);
3377 }
3378
3379 @Override
3380 public int populateTuples(AwkTuples tuples) {
3381 pushSourceLineNumber(tuples);
3382 assert ast1 != null;
3383 int ast1_result = ast1.populateTuples(tuples);
3384 assert ast1_result == 1;
3385 tuples.not();
3386 popSourceLineNumber(tuples);
3387 return 1;
3388 }
3389 }
3390
3391 private final class DollarExpression_AST extends ScalarExpression_AST {
3392
3393 private DollarExpression_AST(AST expr) {
3394 super(expr);
3395 }
3396
3397 @Override
3398 public int populateTuples(AwkTuples tuples) {
3399 pushSourceLineNumber(tuples);
3400 assert ast1 != null;
3401 int ast1_result = ast1.populateTuples(tuples);
3402 assert ast1_result == 1;
3403 tuples.getInputField();
3404 popSourceLineNumber(tuples);
3405 return 1;
3406 }
3407 }
3408
3409 private final class ArrayIndex_AST extends ScalarExpression_AST {
3410
3411 private ArrayIndex_AST(AST expr_ast, AST next) {
3412 super(expr_ast, next);
3413 }
3414
3415 @Override
3416 public int populateTuples(AwkTuples tuples) {
3417 pushSourceLineNumber(tuples);
3418 AST ptr = this;
3419 int cnt = 0;
3420 while (ptr != null) {
3421 assert ptr.ast1 != null;
3422 int ptr_ast1_result = ptr.ast1.populateTuples(tuples);
3423 assert ptr_ast1_result == 1;
3424 ++cnt;
3425 ptr = ptr.ast2;
3426 }
3427 assert cnt >= 1;
3428 if (cnt > 1) {
3429 tuples.applySubsep(cnt);
3430 }
3431 popSourceLineNumber(tuples);
3432 return 1;
3433 }
3434 }
3435
3436
3437
3438 private final class STATEMENTLIST_AST extends AST {
3439
3440 private STATEMENTLIST_AST(AST statement_ast, AST rest) {
3441 super(statement_ast, rest);
3442 }
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455 @Override
3456 public int populateTuples(AwkTuples tuples) {
3457 pushSourceLineNumber(tuples);
3458
3459 assert ast1 != null;
3460 int ast1_count = ast1.populateTuples(tuples);
3461 assert ast1_count == 0;
3462 if (ast2 != null) {
3463 int ast2_count = ast2.populateTuples(tuples);
3464 assert ast2_count == 0;
3465 }
3466 popSourceLineNumber(tuples);
3467 return 0;
3468 }
3469
3470 @Override
3471 public String toString() {
3472 return super.toString() + " <" + ast1 + ">";
3473 }
3474 }
3475
3476 private interface Returnable {
3477
3478 Address returnAddress();
3479 }
3480
3481
3482 private final class FunctionDef_AST extends AST implements Returnable {
3483
3484 private String id;
3485 private Address function_address;
3486 private Address return_address;
3487
3488
3489 @Override
3490 public Address returnAddress() {
3491 assert return_address != null;
3492 return return_address;
3493 }
3494
3495 private FunctionDef_AST(String id, AST params, AST func_body) {
3496 super(params, func_body);
3497 this.id = id;
3498 is_function = true;
3499 }
3500
3501 public Address getAddress() {
3502 assert function_address != null;
3503 return function_address;
3504 }
3505
3506 @Override
3507 public int populateTuples(AwkTuples tuples) {
3508 pushSourceLineNumber(tuples);
3509
3510 function_address = tuples.createAddress("function: " + id);
3511 return_address = tuples.createAddress("return_address for " + id);
3512
3513
3514
3515
3516 tuples.function(id, paramCount());
3517
3518
3519
3520
3521
3522
3523 tuples.address(function_address);
3524
3525
3526
3527
3528
3529 if (ast2 != null) {
3530 int ast2_result = ast2.populateTuples(tuples);
3531 assert ast2_result == 0 || ast2_result == 1;
3532 }
3533
3534 tuples.address(return_address);
3535
3536 tuples.returnFromFunction();
3537
3538
3539
3540 popSourceLineNumber(tuples);
3541 return 0;
3542 }
3543
3544 int paramCount() {
3545 AST ptr = ast1;
3546 int count = 0;
3547 while (ptr != null) {
3548 ++count;
3549 ptr = ptr.ast1;
3550 }
3551 return count;
3552 }
3553
3554 void checkActualToFormalParameters(AST actual_param_list) {
3555 AST a_ptr = actual_param_list;
3556 FunctionDefParamList_AST f_ptr = (FunctionDefParamList_AST) ast1;
3557 while (a_ptr != null) {
3558
3559 AST aparam = a_ptr.ast1;
3560
3561 AST fparam = symbol_table.getFunctionParameterIDAST(id, f_ptr.id);
3562
3563
3564 if (aparam.isArray() && fparam.isScalar()) {
3565 aparam.throwSemanticException(id + ": Actual parameter (" + aparam + ") is an array, but formal parameter is used like a scalar.");
3566 }
3567 if (aparam.isScalar() && fparam.isArray()) {
3568 aparam.throwSemanticException(id + ": Actual parameter (" + aparam + ") is a scalar, but formal parameter is used like an array.");
3569 }
3570
3571
3572 if (aparam instanceof ID_AST) {
3573 ID_AST aparam_id_ast = (ID_AST) aparam;
3574 if (fparam.isScalar()) {
3575 aparam_id_ast.setScalar(true);
3576 }
3577 if (fparam.isArray()) {
3578 aparam_id_ast.setArray(true);
3579 }
3580 }
3581
3582 a_ptr = a_ptr.ast2;
3583 f_ptr = (FunctionDefParamList_AST) f_ptr.ast1;
3584 }
3585 }
3586 }
3587
3588 private final class FunctionCall_AST extends ScalarExpression_AST {
3589
3590 private FunctionProxy function_proxy;
3591
3592 private FunctionCall_AST(FunctionProxy function_proxy, AST params) {
3593 super(params);
3594 this.function_proxy = function_proxy;
3595 }
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620 @Override
3621 public void semanticAnalysis()
3622 throws SemanticException
3623 {
3624 if (!function_proxy.isDefined()) {
3625 throw new SemanticException("function " + function_proxy + " not defined");
3626 }
3627 int actual_param_count;
3628 if (ast1 == null) {
3629 actual_param_count = 0;
3630 } else {
3631 actual_param_count = actualParamCount();
3632 }
3633 int formal_param_count = function_proxy.getFunctionParamCount();
3634 if (formal_param_count < actual_param_count) {
3635 throw new SemanticException("the " + function_proxy.getFunctionName() + " function"
3636 + " only accepts at most " + formal_param_count + " parameter(s), not " + actual_param_count);
3637 }
3638 if (ast1 != null) {
3639 function_proxy.checkActualToFormalParameters(ast1);
3640 }
3641 }
3642
3643 @Override
3644 public int populateTuples(AwkTuples tuples) {
3645 pushSourceLineNumber(tuples);
3646 if (!function_proxy.isDefined()) {
3647 throw new SemanticException("function " + function_proxy + " not defined");
3648 }
3649 tuples.scriptThis();
3650 int actual_param_count;
3651 if (ast1 == null) {
3652 actual_param_count = 0;
3653 } else {
3654 actual_param_count = ast1.populateTuples(tuples);
3655 }
3656 int formal_param_count = function_proxy.getFunctionParamCount();
3657 if (formal_param_count < actual_param_count) {
3658 throw new SemanticException("the " + function_proxy.getFunctionName() + " function"
3659 + " only accepts at most " + formal_param_count + " parameter(s), not " + actual_param_count);
3660 }
3661
3662 function_proxy.checkActualToFormalParameters(ast1);
3663 tuples.callFunction(function_proxy, function_proxy.getFunctionName(), formal_param_count, actual_param_count);
3664 popSourceLineNumber(tuples);
3665 return 1;
3666 }
3667
3668 private int actualParamCount() {
3669 int cnt = 0;
3670 AST ptr = ast1;
3671 while (ptr != null) {
3672 assert ptr.ast1 != null;
3673 ++cnt;
3674 ptr = ptr.ast2;
3675 }
3676 return cnt;
3677 }
3678 }
3679
3680 private final class BuiltinFunctionCall_AST extends ScalarExpression_AST {
3681
3682 private String id;
3683 private int f_idx;
3684
3685 private BuiltinFunctionCall_AST(String id, AST params) {
3686 super(params);
3687 this.id = id;
3688 assert BUILTIN_FUNC_NAMES.get(id) != null;
3689 this.f_idx = BUILTIN_FUNC_NAMES.get(id);
3690 }
3691
3692 @Override
3693 public int populateTuples(AwkTuples tuples) {
3694 pushSourceLineNumber(tuples);
3695 if (f_idx == BUILTIN_FUNC_NAMES.get("sprintf")) {
3696 if (ast1 == null) {
3697 throw new SemanticException("sprintf requires at least 1 argument");
3698 }
3699 int ast1_result = ast1.populateTuples(tuples);
3700 if (ast1_result == 0) {
3701 throw new SemanticException("sprintf requires at minimum 1 argument");
3702 }
3703 tuples.sprintf(ast1_result);
3704 popSourceLineNumber(tuples);
3705 return 1;
3706 } else if (f_idx == BUILTIN_FUNC_NAMES.get("close")) {
3707 if (ast1 == null) {
3708 throw new SemanticException("close requires 1 argument");
3709 }
3710 int ast1_result = ast1.populateTuples(tuples);
3711 if (ast1_result != 1) {
3712 throw new SemanticException("close requires only 1 argument");
3713 }
3714 tuples.close();
3715 popSourceLineNumber(tuples);
3716 return 1;
3717 } else if (f_idx == BUILTIN_FUNC_NAMES.get("length")) {
3718 if (ast1 == null) {
3719 tuples.length(0);
3720 } else {
3721 int ast1_result = ast1.populateTuples(tuples);
3722 if (ast1_result != 1) {
3723 throw new SemanticException("length requires at least one argument");
3724 }
3725 tuples.length(1);
3726 }
3727 popSourceLineNumber(tuples);
3728 return 1;
3729 } else if (f_idx == BUILTIN_FUNC_NAMES.get("srand")) {
3730 if (ast1 == null) {
3731 tuples.srand(0);
3732 } else {
3733 int ast1_result = ast1.populateTuples(tuples);
3734 if (ast1_result != 1) {
3735 throw new SemanticException("srand takes either 0 or one argument, not " + ast1_result);
3736 }
3737 tuples.srand(1);
3738 }
3739 popSourceLineNumber(tuples);
3740 return 1;
3741 } else if (f_idx == BUILTIN_FUNC_NAMES.get("rand")) {
3742 if (ast1 != null) {
3743 throw new SemanticException("rand does not take arguments");
3744 }
3745 tuples.rand();
3746 popSourceLineNumber(tuples);
3747 return 1;
3748 } else if (f_idx == BUILTIN_FUNC_NAMES.get("sqrt")) {
3749 int ast1_result = ast1.populateTuples(tuples);
3750 if (ast1_result != 1) {
3751 throw new SemanticException("sqrt requires only 1 argument");
3752 }
3753 tuples.sqrt();
3754 popSourceLineNumber(tuples);
3755 return 1;
3756 } else if (f_idx == BUILTIN_FUNC_NAMES.get("int")) {
3757 int ast1_result = ast1.populateTuples(tuples);
3758 if (ast1_result != 1) {
3759 throw new SemanticException("int requires only 1 argument");
3760 }
3761 tuples.intFunc();
3762 popSourceLineNumber(tuples);
3763 return 1;
3764 } else if (f_idx == BUILTIN_FUNC_NAMES.get("log")) {
3765 int ast1_result = ast1.populateTuples(tuples);
3766 if (ast1_result != 1) {
3767 throw new SemanticException("int requires only 1 argument");
3768 }
3769 tuples.log();
3770 popSourceLineNumber(tuples);
3771 return 1;
3772 } else if (f_idx == BUILTIN_FUNC_NAMES.get("exp")) {
3773 int ast1_result = ast1.populateTuples(tuples);
3774 if (ast1_result != 1) {
3775 throw new SemanticException("exp requires only 1 argument");
3776 }
3777 tuples.exp();
3778 popSourceLineNumber(tuples);
3779 return 1;
3780 } else if (f_idx == BUILTIN_FUNC_NAMES.get("sin")) {
3781 int ast1_result = ast1.populateTuples(tuples);
3782 if (ast1_result != 1) {
3783 throw new SemanticException("sin requires only 1 argument");
3784 }
3785 tuples.sin();
3786 popSourceLineNumber(tuples);
3787 return 1;
3788 } else if (f_idx == BUILTIN_FUNC_NAMES.get("cos")) {
3789 int ast1_result = ast1.populateTuples(tuples);
3790 if (ast1_result != 1) {
3791 throw new SemanticException("cos requires only 1 argument");
3792 }
3793 tuples.cos();
3794 popSourceLineNumber(tuples);
3795 return 1;
3796 } else if (f_idx == BUILTIN_FUNC_NAMES.get("atan2")) {
3797 int ast1_result = ast1.populateTuples(tuples);
3798 if (ast1_result != 2) {
3799 throw new SemanticException("atan2 requires 2 arguments");
3800 }
3801 tuples.atan2();
3802 popSourceLineNumber(tuples);
3803 return 1;
3804 } else if (f_idx == BUILTIN_FUNC_NAMES.get("match")) {
3805 int ast1_result = ast1.populateTuples(tuples);
3806 if (ast1_result != 2) {
3807 throw new SemanticException("match requires 2 arguments");
3808 }
3809 tuples.match();
3810 popSourceLineNumber(tuples);
3811 return 1;
3812 } else if (f_idx == BUILTIN_FUNC_NAMES.get("index")) {
3813 int ast1_result = ast1.populateTuples(tuples);
3814 if (ast1_result != 2) {
3815 throw new SemanticException("index requires 2 arguments");
3816 }
3817 tuples.index();
3818 popSourceLineNumber(tuples);
3819 return 1;
3820 } else if (f_idx == BUILTIN_FUNC_NAMES.get("sub") || f_idx == BUILTIN_FUNC_NAMES.get("gsub")) {
3821 if (ast1 == null || ast1.ast2 == null || ast1.ast2.ast1 == null) {
3822 throw new SemanticException("sub needs at least 2 arguments");
3823 }
3824 boolean is_gsub = f_idx == BUILTIN_FUNC_NAMES.get("gsub");
3825
3826 int numargs = ast1.populateTuples(tuples);
3827
3828
3829
3830 if (numargs == 2) {
3831 tuples.subForDollar0(is_gsub);
3832 } else if (numargs == 3) {
3833 AST ptr = ast1.ast2.ast2.ast1;
3834 if (ptr instanceof ID_AST) {
3835 ID_AST id_ast = (ID_AST) ptr;
3836 if (id_ast.isArray()) {
3837 throw new SemanticException("sub cannot accept an unindexed array as its 3rd argument");
3838 }
3839 id_ast.setScalar(true);
3840 tuples.subForVariable(id_ast.offset, id_ast.is_global, is_gsub);
3841 } else if (ptr instanceof ArrayReference_AST) {
3842 ArrayReference_AST arr_ast = (ArrayReference_AST) ptr;
3843
3844 int ast2_result = arr_ast.ast2.populateTuples(tuples);
3845 assert ast2_result == 1;
3846 ID_AST id_ast = (ID_AST) arr_ast.ast1;
3847 if (id_ast.isScalar()) {
3848 throw new SemanticException("Cannot use " + id_ast + " as an array.");
3849 }
3850 tuples.subForArrayReference(id_ast.offset, id_ast.is_global, is_gsub);
3851 } else if (ptr instanceof DollarExpression_AST) {
3852
3853 DollarExpression_AST dollar_expr = (DollarExpression_AST) ptr;
3854 assert dollar_expr.ast1 != null;
3855 int ast1_result = dollar_expr.ast1.populateTuples(tuples);
3856 assert ast1_result == 1;
3857 tuples.subForDollarReference(is_gsub);
3858 } else {
3859 throw new SemanticException("sub's 3rd argument must be either an id, an array reference, or an input field reference");
3860 }
3861 }
3862 popSourceLineNumber(tuples);
3863 return 1;
3864 } else if (f_idx == BUILTIN_FUNC_NAMES.get("split")) {
3865
3866
3867
3868
3869
3870 if (ast1 == null || ast1.ast2 == null || ast1.ast2.ast1 == null) {
3871 throw new SemanticException("split needs at least 2 arguments");
3872 }
3873 AST ptr = ast1.ast2.ast1;
3874 if (!(ptr instanceof ID_AST)) {
3875 throw new SemanticException("split needs an array name as its 2nd argument");
3876 }
3877 ID_AST arr_ast = (ID_AST) ptr;
3878 if (arr_ast.isScalar()) {
3879 throw new SemanticException("split's 2nd arg cannot be a scalar");
3880 }
3881 arr_ast.setArray(true);
3882
3883 int ast1_result = ast1.populateTuples(tuples);
3884 if (ast1_result != 2 && ast1_result != 3) {
3885 throw new SemanticException("split requires 2 or 3 arguments, not " + ast1_result);
3886 }
3887 tuples.split(ast1_result);
3888 popSourceLineNumber(tuples);
3889 return 1;
3890 } else if (f_idx == BUILTIN_FUNC_NAMES.get("substr")) {
3891 if (ast1 == null) {
3892 throw new SemanticException("substr requires at least 2 arguments");
3893 }
3894 int ast1_result = ast1.populateTuples(tuples);
3895 if (ast1_result != 2 && ast1_result != 3) {
3896 throw new SemanticException("substr requires 2 or 3 arguments, not " + ast1_result);
3897 }
3898 tuples.substr(ast1_result);
3899 popSourceLineNumber(tuples);
3900 return 1;
3901 } else if (f_idx == BUILTIN_FUNC_NAMES.get("tolower")) {
3902 if (ast1 == null) {
3903 throw new SemanticException("tolower requires 1 argument");
3904 }
3905 int ast1_result = ast1.populateTuples(tuples);
3906 if (ast1_result != 1) {
3907 throw new SemanticException("tolower requires only 1 argument");
3908 }
3909 tuples.tolower();
3910 popSourceLineNumber(tuples);
3911 return 1;
3912 } else if (f_idx == BUILTIN_FUNC_NAMES.get("toupper")) {
3913 if (ast1 == null) {
3914 throw new SemanticException("toupper requires 1 argument");
3915 }
3916 int ast1_result = ast1.populateTuples(tuples);
3917 if (ast1_result != 1) {
3918 throw new SemanticException("toupper requires only 1 argument");
3919 }
3920 tuples.toupper();
3921 popSourceLineNumber(tuples);
3922 return 1;
3923 } else if (f_idx == BUILTIN_FUNC_NAMES.get("system")) {
3924 if (ast1 == null) {
3925 throw new SemanticException("system requires 1 argument");
3926 }
3927 int ast1_result = ast1.populateTuples(tuples);
3928 if (ast1_result != 1) {
3929 throw new SemanticException("system requires only 1 argument");
3930 }
3931 tuples.system();
3932 popSourceLineNumber(tuples);
3933 return 1;
3934 } else if (f_idx == BUILTIN_FUNC_NAMES.get("exec")) {
3935 if (ast1 == null) {
3936 throw new SemanticException("exec requires 1 argument");
3937 }
3938 int ast1_result = ast1.populateTuples(tuples);
3939 if (ast1_result != 1) {
3940 throw new SemanticException("exec requires only 1 argument");
3941 }
3942 tuples.exec();
3943 popSourceLineNumber(tuples);
3944 return 1;
3945 } else {
3946 throw new NotImplementedError("builtin: " + id);
3947 }
3948 }
3949 }
3950
3951 private final class FunctionCallParamList_AST extends AST {
3952
3953 private FunctionCallParamList_AST(AST expr, AST rest) {
3954 super(expr, rest);
3955 }
3956
3957 @Override
3958 public int populateTuples(AwkTuples tuples) {
3959 pushSourceLineNumber(tuples);
3960 assert ast1 != null;
3961 int retval;
3962 if (ast2 == null) {
3963 retval = ast1.populateTuples(tuples);
3964 } else {
3965 retval = ast1.populateTuples(tuples) + ast2.populateTuples(tuples);
3966 }
3967 popSourceLineNumber(tuples);
3968 return retval;
3969 }
3970 }
3971
3972 private final class FunctionDefParamList_AST extends AST {
3973
3974 private String id;
3975 private FunctionDefParamList_AST(String id, int offset, AST rest) {
3976 super(rest);
3977 this.id = id;
3978 }
3979
3980 public final int populateTuples(AwkTuples tuples) {
3981 throw new Error("Cannot 'execute' function definition parameter list (formal parameters) in this manner.");
3982 }
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992 @Override
3993 public void semanticAnalysis()
3994 throws SemanticException
3995 {
3996
3997
3998
3999
4000
4001
4002 FunctionDefParamList_AST ptr = this;
4003 while (ptr != null) {
4004 if (SPECIAL_VAR_NAMES.get(ptr.id) != null) {
4005 throw new SemanticException("Special variable " + ptr.id + " cannot be used as a formal parameter");
4006 }
4007 ptr = (FunctionDefParamList_AST) ptr.ast1;
4008 }
4009 }
4010 }
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022 private interface NonStatement_AST {}
4023
4024 private final class ID_AST extends AST implements NonStatement_AST {
4025
4026 private String id;
4027 private int offset = AVM.NULL_OFFSET;
4028 private boolean is_global;
4029
4030 private ID_AST(String id, boolean is_global) {
4031 this.id = id;
4032 this.is_global = is_global;
4033 }
4034 private boolean is_array = false;
4035 private boolean is_scalar = false;
4036 @Override
4037 public String toString() {
4038 return super.toString() + " (" + id + ")";
4039 }
4040
4041 @Override
4042 public int populateTuples(AwkTuples tuples) {
4043 pushSourceLineNumber(tuples);
4044 assert offset != AVM.NULL_OFFSET : "offset = " + offset + " for " + this;
4045 tuples.dereference(offset, isArray(), is_global);
4046 popSourceLineNumber(tuples);
4047 return 1;
4048 }
4049
4050 @Override
4051 public final boolean isArray() {
4052 return is_array;
4053 }
4054
4055 @Override
4056 public final boolean isScalar() {
4057 return is_scalar;
4058 }
4059
4060 private void setArray(boolean b) {
4061 is_array = b;
4062 }
4063
4064 private void setScalar(boolean b) {
4065 is_scalar = b;
4066 }
4067 }
4068
4069 private final class ArrayReference_AST extends ScalarExpression_AST {
4070
4071 private ArrayReference_AST(AST id_ast, AST idx_ast) {
4072 super(id_ast, idx_ast);
4073 }
4074
4075 @Override
4076 public String toString() {
4077 return super.toString() + " (" + ast1 + " [...])";
4078 }
4079
4080 @Override
4081 public int populateTuples(AwkTuples tuples) {
4082 pushSourceLineNumber(tuples);
4083 assert ast1 != null;
4084 assert ast2 != null;
4085
4086 int ast1_result = ast1.populateTuples(tuples);
4087 assert ast1_result == 1;
4088
4089 int ast2_result = ast2.populateTuples(tuples);
4090 assert ast2_result == 1;
4091 tuples.dereferenceArray();
4092 popSourceLineNumber(tuples);
4093 return 1;
4094 }
4095 }
4096
4097 private final class Integer_AST extends ScalarExpression_AST implements NonStatement_AST {
4098
4099 private Long I;
4100
4101 private Integer_AST(Long I) {
4102 this.I = I;
4103 }
4104
4105 @Override
4106 public String toString() {
4107 return super.toString() + " (" + I + ")";
4108 }
4109
4110 @Override
4111 public int populateTuples(AwkTuples tuples) {
4112 pushSourceLineNumber(tuples);
4113 tuples.push(I);
4114 popSourceLineNumber(tuples);
4115 return 1;
4116 }
4117 }
4118
4119
4120
4121
4122
4123 private final class Double_AST extends ScalarExpression_AST implements NonStatement_AST {
4124
4125 private Object D;
4126
4127 private Double_AST(Double D) {
4128 double d = D.doubleValue();
4129 if (d == (int) d) {
4130 this.D = (int) d;
4131 } else {
4132 this.D = d;
4133 }
4134 }
4135
4136 @Override
4137 public String toString() {
4138 return super.toString() + " (" + D + ")";
4139 }
4140
4141 @Override
4142 public int populateTuples(AwkTuples tuples) {
4143 pushSourceLineNumber(tuples);
4144 tuples.push(D);
4145 popSourceLineNumber(tuples);
4146 return 1;
4147 }
4148 }
4149
4150
4151
4152
4153
4154 private final class String_AST extends ScalarExpression_AST implements NonStatement_AST {
4155
4156 private String S;
4157
4158 private String_AST(String str) {
4159 assert str != null;
4160 this.S = str;
4161 }
4162
4163 @Override
4164 public String toString() {
4165 return super.toString() + " (" + S + ")";
4166 }
4167
4168 @Override
4169 public int populateTuples(AwkTuples tuples) {
4170 pushSourceLineNumber(tuples);
4171 tuples.push(S);
4172 popSourceLineNumber(tuples);
4173 return 1;
4174 }
4175 }
4176
4177 private final class Regexp_AST extends ScalarExpression_AST {
4178
4179 private String regexp_str;
4180
4181 private Regexp_AST(String regexp_str) {
4182 assert regexp_str != null;
4183 this.regexp_str = regexp_str;
4184 }
4185
4186 @Override
4187 public String toString() {
4188 return super.toString() + " (" + regexp_str + ")";
4189 }
4190
4191 @Override
4192 public int populateTuples(AwkTuples tuples) {
4193 pushSourceLineNumber(tuples);
4194 tuples.regexp(regexp_str);
4195 popSourceLineNumber(tuples);
4196 return 1;
4197 }
4198 }
4199
4200 private final class ConditionPair_AST extends ScalarExpression_AST {
4201
4202 private ConditionPair_AST(AST boolean_ast_1, AST boolean_ast_2) {
4203 super(boolean_ast_1, boolean_ast_2);
4204 }
4205
4206 @Override
4207 public int populateTuples(AwkTuples tuples) {
4208 pushSourceLineNumber(tuples);
4209 assert ast1 != null;
4210 int ast1_result = ast1.populateTuples(tuples);
4211 assert ast1_result == 1;
4212 assert ast2 != null;
4213 int ast2_result = ast2.populateTuples(tuples);
4214 assert ast2_result == 1;
4215 tuples.conditionPair();
4216 popSourceLineNumber(tuples);
4217 return 1;
4218 }
4219 }
4220
4221 private final class IntegerExpression_AST extends ScalarExpression_AST {
4222
4223 private IntegerExpression_AST(AST expr) {
4224 super(expr);
4225 }
4226
4227 @Override
4228 public int populateTuples(AwkTuples tuples) {
4229 pushSourceLineNumber(tuples);
4230 int ast1_result = ast1.populateTuples(tuples);
4231 assert ast1_result == 1;
4232 tuples.castInt();
4233 popSourceLineNumber(tuples);
4234 return 1;
4235 }
4236 }
4237
4238 private final class DoubleExpression_AST extends ScalarExpression_AST {
4239
4240 private DoubleExpression_AST(AST expr) {
4241 super(expr);
4242 }
4243
4244 @Override
4245 public int populateTuples(AwkTuples tuples) {
4246 pushSourceLineNumber(tuples);
4247 int ast1_result = ast1.populateTuples(tuples);
4248 assert ast1_result == 1;
4249 tuples.castDouble();
4250 popSourceLineNumber(tuples);
4251 return 1;
4252 }
4253 }
4254
4255 private final class StringExpression_AST extends ScalarExpression_AST {
4256
4257 private StringExpression_AST(AST expr) {
4258 super(expr);
4259 }
4260
4261 @Override
4262 public int populateTuples(AwkTuples tuples) {
4263 pushSourceLineNumber(tuples);
4264 int ast1_result = ast1.populateTuples(tuples);
4265 assert ast1_result == 1;
4266 tuples.castString();
4267 popSourceLineNumber(tuples);
4268 return 1;
4269 }
4270 }
4271
4272 private final class Begin_AST extends AST {
4273
4274 private Begin_AST() {
4275 super();
4276 is_begin = true;
4277 }
4278
4279 @Override
4280 public int populateTuples(AwkTuples tuples) {
4281 pushSourceLineNumber(tuples);
4282 tuples.push(1);
4283 popSourceLineNumber(tuples);
4284 return 1;
4285 }
4286 }
4287
4288 private final class End_AST extends AST {
4289
4290 private End_AST() {
4291 super();
4292 is_end = true;
4293 }
4294
4295 @Override
4296 public int populateTuples(AwkTuples tuples) {
4297 pushSourceLineNumber(tuples);
4298 tuples.push(1);
4299 popSourceLineNumber(tuples);
4300 return 1;
4301 }
4302 }
4303
4304 private final class PreInc_AST extends ScalarExpression_AST {
4305
4306 private PreInc_AST(AST symbol_ast) {
4307 super(symbol_ast);
4308 }
4309
4310 @Override
4311 public int populateTuples(AwkTuples tuples) {
4312 pushSourceLineNumber(tuples);
4313 assert ast1 != null;
4314 if (ast1 instanceof ID_AST) {
4315 ID_AST id_ast = (ID_AST) ast1;
4316 tuples.inc(id_ast.offset, id_ast.is_global);
4317 } else if (ast1 instanceof ArrayReference_AST) {
4318 ArrayReference_AST arr_ast = (ArrayReference_AST) ast1;
4319 ID_AST id_ast = (ID_AST) arr_ast.ast1;
4320 assert id_ast != null;
4321 assert arr_ast.ast2 != null;
4322 int arr_ast2_result = arr_ast.ast2.populateTuples(tuples);
4323 assert arr_ast2_result == 1;
4324 tuples.incArrayRef(id_ast.offset, id_ast.is_global);
4325 } else if (ast1 instanceof DollarExpression_AST) {
4326 DollarExpression_AST dollar_expr = (DollarExpression_AST) ast1;
4327 assert dollar_expr.ast1 != null;
4328 int ast1_result = dollar_expr.ast1.populateTuples(tuples);
4329 assert ast1_result == 1;
4330
4331
4332 tuples.dup();
4333
4334
4335 tuples.incDollarRef();
4336
4337
4338
4339 tuples.getInputField();
4340 popSourceLineNumber(tuples);
4341 return 1;
4342 } else {
4343 throw new NotImplementedError("unhandled preinc for " + ast1);
4344 }
4345
4346
4347 int ast1_result = ast1.populateTuples(tuples);
4348 assert ast1_result == 1;
4349 popSourceLineNumber(tuples);
4350 return 1;
4351 }
4352 }
4353
4354 private final class PreDec_AST extends ScalarExpression_AST {
4355
4356 private PreDec_AST(AST symbol_ast) {
4357 super(symbol_ast);
4358 }
4359
4360 @Override
4361 public int populateTuples(AwkTuples tuples) {
4362 pushSourceLineNumber(tuples);
4363 assert ast1 != null;
4364 if (ast1 instanceof ID_AST) {
4365 ID_AST id_ast = (ID_AST) ast1;
4366 tuples.dec(id_ast.offset, id_ast.is_global);
4367 } else if (ast1 instanceof ArrayReference_AST) {
4368 ArrayReference_AST arr_ast = (ArrayReference_AST) ast1;
4369 ID_AST id_ast = (ID_AST) arr_ast.ast1;
4370 assert id_ast != null;
4371 assert arr_ast.ast2 != null;
4372 int arr_ast2_result = arr_ast.ast2.populateTuples(tuples);
4373 assert arr_ast2_result == 1;
4374 tuples.decArrayRef(id_ast.offset, id_ast.is_global);
4375 } else if (ast1 instanceof DollarExpression_AST) {
4376 DollarExpression_AST dollar_expr = (DollarExpression_AST) ast1;
4377 assert dollar_expr.ast1 != null;
4378 int ast1_result = dollar_expr.ast1.populateTuples(tuples);
4379 assert ast1_result == 1;
4380
4381
4382 tuples.dup();
4383
4384
4385 tuples.decDollarRef();
4386
4387
4388
4389 tuples.getInputField();
4390 popSourceLineNumber(tuples);
4391 return 1;
4392 } else {
4393 throw new NotImplementedError("unhandled predec for " + ast1);
4394 }
4395 int ast1_result = ast1.populateTuples(tuples);
4396 assert ast1_result == 1;
4397 popSourceLineNumber(tuples);
4398 return 1;
4399 }
4400 }
4401
4402 private final class PostInc_AST extends ScalarExpression_AST {
4403
4404 private PostInc_AST(AST symbol_ast) {
4405 super(symbol_ast);
4406 }
4407
4408 @Override
4409 public int populateTuples(AwkTuples tuples) {
4410 pushSourceLineNumber(tuples);
4411 assert ast1 != null;
4412 int ast1_result = ast1.populateTuples(tuples);
4413 assert ast1_result == 1;
4414 if (ast1 instanceof ID_AST) {
4415 ID_AST id_ast = (ID_AST) ast1;
4416 tuples.postInc(id_ast.offset, id_ast.is_global);
4417 } else if (ast1 instanceof ArrayReference_AST) {
4418 ArrayReference_AST arr_ast = (ArrayReference_AST) ast1;
4419 ID_AST id_ast = (ID_AST) arr_ast.ast1;
4420 assert id_ast != null;
4421 assert arr_ast.ast2 != null;
4422 int arr_ast2_result = arr_ast.ast2.populateTuples(tuples);
4423 assert arr_ast2_result == 1;
4424 tuples.incArrayRef(id_ast.offset, id_ast.is_global);
4425 } else if (ast1 instanceof DollarExpression_AST) {
4426 DollarExpression_AST dollar_expr = (DollarExpression_AST) ast1;
4427 assert dollar_expr.ast1 != null;
4428 int dollarast_ast1_result = dollar_expr.ast1.populateTuples(tuples);
4429 assert dollarast_ast1_result == 1;
4430 tuples.incDollarRef();
4431 } else {
4432 throw new NotImplementedError("unhandled postinc for " + ast1);
4433 }
4434 popSourceLineNumber(tuples);
4435 return 1;
4436 }
4437 }
4438
4439 private final class PostDec_AST extends ScalarExpression_AST {
4440
4441 private PostDec_AST(AST symbol_ast) {
4442 super(symbol_ast);
4443 }
4444
4445 @Override
4446 public int populateTuples(AwkTuples tuples) {
4447 pushSourceLineNumber(tuples);
4448 assert ast1 != null;
4449 int ast1_result = ast1.populateTuples(tuples);
4450 assert ast1_result == 1;
4451 if (ast1 instanceof ID_AST) {
4452 ID_AST id_ast = (ID_AST) ast1;
4453 tuples.postDec(id_ast.offset, id_ast.is_global);
4454 } else if (ast1 instanceof ArrayReference_AST) {
4455 ArrayReference_AST arr_ast = (ArrayReference_AST) ast1;
4456 ID_AST id_ast = (ID_AST) arr_ast.ast1;
4457 assert id_ast != null;
4458 assert arr_ast.ast2 != null;
4459 int arr_ast2_result = arr_ast.ast2.populateTuples(tuples);
4460 assert arr_ast2_result == 1;
4461 tuples.decArrayRef(id_ast.offset, id_ast.is_global);
4462 } else if (ast1 instanceof DollarExpression_AST) {
4463 DollarExpression_AST dollar_expr = (DollarExpression_AST) ast1;
4464 assert dollar_expr.ast1 != null;
4465 int dollarast_ast1_result = dollar_expr.ast1.populateTuples(tuples);
4466 assert dollarast_ast1_result == 1;
4467 tuples.decDollarRef();
4468 } else {
4469 throw new NotImplementedError("unhandled postinc for " + ast1);
4470 }
4471 popSourceLineNumber(tuples);
4472 return 1;
4473 }
4474 }
4475
4476 private final class Print_AST extends ScalarExpression_AST {
4477
4478 private int output_token;
4479
4480 private Print_AST(AST expr_list, int output_token, AST output_expr) {
4481 super(expr_list, output_expr);
4482 this.output_token = output_token;
4483 }
4484
4485 @Override
4486 public int populateTuples(AwkTuples tuples) {
4487 pushSourceLineNumber(tuples);
4488
4489 int param_count;
4490 if (ast1 == null) {
4491 param_count = 0;
4492 } else {
4493 param_count = ast1.populateTuples(tuples);
4494 assert param_count >= 0;
4495 if (param_count == 0) {
4496 throw new SemanticException("Cannot print the result. The expression doesn't return anything.");
4497 }
4498 }
4499
4500 if (ast2 != null) {
4501 int ast2_result = ast2.populateTuples(tuples);
4502 assert ast2_result == 1;
4503 }
4504
4505 if (output_token == _GT_) {
4506 tuples.printToFile(param_count, false);
4507 } else if (output_token == _APPEND_) {
4508 tuples.printToFile(param_count, true);
4509 } else if (output_token == _PIPE_) {
4510 tuples.printToPipe(param_count);
4511 } else {
4512 tuples.print(param_count);
4513 }
4514
4515 popSourceLineNumber(tuples);
4516 return 0;
4517 }
4518 }
4519
4520
4521 private final class Extension_AST extends AST {
4522
4523 private String extension_keyword;
4524
4525 private Extension_AST(String extension_keyword, AST param_ast) {
4526 super(param_ast);
4527 this.extension_keyword = extension_keyword;
4528 }
4529
4530 @Override
4531 public int populateTuples(AwkTuples tuples) {
4532 pushSourceLineNumber(tuples);
4533 int param_count;
4534 if (ast1 == null) {
4535 param_count = 0;
4536 } else {
4537
4538 JawkExtension extension = extensions.get(extension_keyword);
4539 int arg_count = countParams((FunctionCallParamList_AST) ast1);
4540
4541 int[] req_array_idxs = extension.getAssocArrayParameterPositions(extension_keyword, arg_count);
4542 assert req_array_idxs != null;
4543
4544 for (int idx : req_array_idxs) {
4545 AST param_ast = getParamAst((FunctionCallParamList_AST) ast1, idx);
4546 assert ast1 instanceof FunctionCallParamList_AST;
4547
4548 if (param_ast.ast1 instanceof ID_AST) {
4549
4550
4551 ID_AST id_ast = (ID_AST) param_ast.ast1;
4552 if (id_ast.isScalar()) {
4553 throw new SemanticException("Extension '" + extension_keyword + "' requires parameter position " + idx + " be an associative array, not a scalar.");
4554 }
4555 id_ast.setArray(true);
4556 }
4557 }
4558
4559 param_count = ast1.populateTuples(tuples);
4560 assert param_count >= 0;
4561 }
4562
4563
4564
4565
4566 boolean is_initial;
4567 if (parent instanceof FunctionCallParamList_AST) {
4568 AST ptr = parent;
4569 while (ptr instanceof FunctionCallParamList_AST) {
4570 ptr = ptr.parent;
4571 }
4572 is_initial = !(ptr instanceof Extension_AST);
4573 } else {
4574 is_initial = true;
4575 }
4576 tuples.extension(extension_keyword, param_count, is_initial);
4577 popSourceLineNumber(tuples);
4578
4579 return 1;
4580 }
4581
4582 private AST getParamAst(FunctionCallParamList_AST p_ast, int pos) {
4583 for (int i = 0; i < pos; ++i) {
4584 p_ast = (FunctionCallParamList_AST) p_ast.ast2;
4585 if (p_ast == null) {
4586 throw new SemanticException("More arguments required for assoc array parameter position specification.");
4587 }
4588 }
4589 return p_ast;
4590 }
4591
4592 private int countParams(FunctionCallParamList_AST p_ast) {
4593 int cnt = 0;
4594 while (p_ast != null) {
4595 p_ast = (FunctionCallParamList_AST) p_ast.ast2;
4596 ++cnt;
4597 }
4598 return cnt;
4599 }
4600
4601 @Override
4602 public String toString() {
4603 return super.toString() + " (" + extension_keyword + ")";
4604 }
4605 }
4606
4607 private final class Printf_AST extends ScalarExpression_AST {
4608
4609 private int output_token;
4610
4611 private Printf_AST(AST expr_list, int output_token, AST output_expr) {
4612 super(expr_list, output_expr);
4613 this.output_token = output_token;
4614 }
4615
4616 @Override
4617 public int populateTuples(AwkTuples tuples) {
4618 pushSourceLineNumber(tuples);
4619
4620 int param_count;
4621 if (ast1 == null) {
4622 param_count = 0;
4623 } else {
4624 param_count = ast1.populateTuples(tuples);
4625 assert param_count >= 0;
4626 if (param_count == 0) {
4627 throw new SemanticException("Cannot printf the result. The expression doesn't return anything.");
4628 }
4629 }
4630
4631 if (ast2 != null) {
4632 int ast2_result = ast2.populateTuples(tuples);
4633 assert ast2_result == 1;
4634 }
4635
4636 if (output_token == _GT_) {
4637 tuples.printfToFile(param_count, false);
4638 } else if (output_token == _APPEND_) {
4639 tuples.printfToFile(param_count, true);
4640 } else if (output_token == _PIPE_) {
4641 tuples.printfToPipe(param_count);
4642 } else {
4643 tuples.printf(param_count);
4644 }
4645
4646 popSourceLineNumber(tuples);
4647 return 0;
4648 }
4649 }
4650
4651 private final class Getline_AST extends ScalarExpression_AST {
4652
4653 private Getline_AST(AST pipe_expr, AST lvalue_ast, AST in_redirect) {
4654 super(pipe_expr, lvalue_ast, in_redirect);
4655 }
4656
4657 @Override
4658 public int populateTuples(AwkTuples tuples) {
4659 pushSourceLineNumber(tuples);
4660 if (ast1 != null) {
4661 int ast1_result = ast1.populateTuples(tuples);
4662 assert ast1_result == 1;
4663
4664 tuples.useAsCommandInput();
4665 } else if (ast3 != null) {
4666
4667 int ast3_result = ast3.populateTuples(tuples);
4668 assert ast3_result == 1;
4669
4670 tuples.useAsFileInput();
4671 } else {
4672 tuples.getlineInput();
4673 }
4674
4675
4676
4677 if (ast2 == null) {
4678 tuples.assignAsInput();
4679
4680
4681 } else if (ast2 instanceof ID_AST) {
4682 ID_AST id_ast = (ID_AST) ast2;
4683 tuples.assign(id_ast.offset, id_ast.is_global);
4684 if (id_ast.id.equals("RS")) {
4685 tuples.applyRS();
4686 }
4687 } else if (ast2 instanceof ArrayReference_AST) {
4688 ArrayReference_AST arr = (ArrayReference_AST) ast2;
4689
4690 assert arr.ast2 != null;
4691 int arr_ast2_result = arr.ast2.populateTuples(tuples);
4692 assert arr_ast2_result == 1;
4693
4694 ID_AST id_ast = (ID_AST) arr.ast1;
4695 tuples.assignArray(id_ast.offset, id_ast.is_global);
4696 } else if (ast2 instanceof DollarExpression_AST) {
4697 DollarExpression_AST dollar_expr = (DollarExpression_AST) ast2;
4698 if (dollar_expr.ast2 != null) {
4699 int ast2_result = dollar_expr.ast2.populateTuples(tuples);
4700 assert ast2_result == 1;
4701 }
4702
4703 tuples.assignAsInputField();
4704 } else {
4705 throw new SemanticException("Cannot getline into a " + ast2);
4706 }
4707
4708 tuples.pop();
4709
4710 popSourceLineNumber(tuples);
4711 return 1;
4712 }
4713 }
4714
4715 private final class ReturnStatement_AST extends AST {
4716
4717 private ReturnStatement_AST(AST expr) {
4718 super(expr);
4719 }
4720
4721 @Override
4722 public int populateTuples(AwkTuples tuples) {
4723 pushSourceLineNumber(tuples);
4724 Returnable returnable = (Returnable) searchFor(Returnable.class);
4725 if (returnable == null) {
4726 throw new SemanticException("Cannot use return here.");
4727 }
4728 if (ast1 != null) {
4729 int ast1_result = ast1.populateTuples(tuples);
4730 assert ast1_result == 1;
4731 tuples.setReturnResult();
4732 }
4733 tuples.gotoAddress(returnable.returnAddress());
4734 popSourceLineNumber(tuples);
4735 return 0;
4736 }
4737 }
4738
4739 private final class ExitStatement_AST extends AST {
4740
4741 private ExitStatement_AST(AST expr) {
4742 super(expr);
4743 }
4744
4745 @Override
4746 public int populateTuples(AwkTuples tuples) {
4747 pushSourceLineNumber(tuples);
4748 if (ast1 != null) {
4749 int ast1_result = ast1.populateTuples(tuples);
4750 assert ast1_result == 1;
4751 tuples.exitWithCode();
4752 } else {
4753 tuples.exitWithoutCode();
4754 }
4755 popSourceLineNumber(tuples);
4756 return 0;
4757 }
4758 }
4759
4760 private final class DeleteStatement_AST extends AST {
4761
4762 private DeleteStatement_AST(AST symbol_ast) {
4763 super(symbol_ast);
4764 }
4765
4766 @Override
4767 public int populateTuples(AwkTuples tuples) {
4768 pushSourceLineNumber(tuples);
4769 assert ast1 != null;
4770
4771 if (ast1 instanceof ArrayReference_AST) {
4772 assert ast1.ast1 != null;
4773 assert ast1.ast2 != null;
4774 ID_AST id_ast = (ID_AST) ast1.ast1;
4775 if (id_ast.isScalar()) {
4776 throw new SemanticException("delete: Cannot use a scalar as an array.");
4777 }
4778 id_ast.setArray(true);
4779 int idx_result = ast1.ast2.populateTuples(tuples);
4780 assert idx_result == 1;
4781
4782 tuples.deleteArrayElement(id_ast.offset, id_ast.is_global);
4783 } else if (ast1 instanceof ID_AST) {
4784 ID_AST id_ast = (ID_AST) ast1;
4785 if (id_ast.isScalar()) {
4786 throw new SemanticException("delete: Cannot delete a scalar.");
4787 }
4788 id_ast.setArray(true);
4789 tuples.deleteArray(id_ast.offset, id_ast.is_global);
4790 } else {
4791 throw new Error("Should never reach here : delete for " + ast1);
4792 }
4793
4794 popSourceLineNumber(tuples);
4795 return 0;
4796 }
4797 }
4798
4799 private class BreakStatement_AST extends AST {
4800
4801 @Override
4802 public int populateTuples(AwkTuples tuples) {
4803 pushSourceLineNumber(tuples);
4804 Breakable breakable = (Breakable) searchFor(Breakable.class);
4805 if (breakable == null) {
4806 throw new SemanticException("cannot break; not within a loop");
4807 }
4808 assert breakable != null;
4809 tuples.gotoAddress(breakable.breakAddress());
4810 popSourceLineNumber(tuples);
4811 return 0;
4812 }
4813 }
4814
4815 private final class SleepStatement_AST extends AST {
4816
4817 private SleepStatement_AST(AST expr) {
4818 super(expr);
4819 }
4820
4821 @Override
4822 public int populateTuples(AwkTuples tuples) {
4823 pushSourceLineNumber(tuples);
4824 if (ast1 == null) {
4825 tuples.sleep(0);
4826 } else {
4827 int ast1_result = ast1.populateTuples(tuples);
4828 assert ast1_result == 1;
4829 tuples.sleep(ast1_result);
4830 }
4831 popSourceLineNumber(tuples);
4832 return 0;
4833 }
4834 }
4835
4836 private final class DumpStatement_AST extends AST {
4837
4838 private DumpStatement_AST(AST expr) {
4839 super(expr);
4840 }
4841
4842 @Override
4843 public int populateTuples(AwkTuples tuples) {
4844 pushSourceLineNumber(tuples);
4845 if (ast1 == null) {
4846 tuples.dump(0);
4847 } else {
4848 assert ast1 instanceof FunctionCallParamList_AST;
4849 AST ptr = ast1;
4850 while (ptr != null) {
4851 if (!(ptr.ast1 instanceof ID_AST)) {
4852 throw new SemanticException("ID required for argument(s) to _dump");
4853 }
4854 ID_AST id_ast = (ID_AST) ptr.ast1;
4855 if (id_ast.isScalar()) {
4856 throw new SemanticException("_dump: Cannot use a scalar as an argument.");
4857 }
4858 id_ast.setArray(true);
4859 ptr = ptr.ast2;
4860 }
4861 int ast1_result = ast1.populateTuples(tuples);
4862 tuples.dump(ast1_result);
4863 }
4864 popSourceLineNumber(tuples);
4865 return 0;
4866 }
4867 }
4868
4869 private class NextStatement_AST extends AST {
4870
4871 @Override
4872 public int populateTuples(AwkTuples tuples) {
4873 pushSourceLineNumber(tuples);
4874 Nextable nextable = (Nextable) searchFor(Nextable.class);
4875 if (nextable == null) {
4876 throw new SemanticException("cannot next; not within any input rules");
4877 }
4878 assert nextable != null;
4879 tuples.gotoAddress(nextable.nextAddress());
4880 popSourceLineNumber(tuples);
4881 return 0;
4882 }
4883 }
4884
4885 private final class ContinueStatement_AST extends AST {
4886
4887 private ContinueStatement_AST() {
4888 super();
4889 }
4890
4891 @Override
4892 public int populateTuples(AwkTuples tuples) {
4893 pushSourceLineNumber(tuples);
4894 Continueable continueable = (Continueable) searchFor(Continueable.class);
4895 if (continueable == null) {
4896 throw new SemanticException("cannot issue a continue; not within any loops");
4897 }
4898 assert continueable != null;
4899 tuples.gotoAddress(continueable.continueAddress());
4900 popSourceLineNumber(tuples);
4901 return 0;
4902 }
4903 }
4904
4905
4906
4907 private final class FunctionProxy implements HasFunctionAddress {
4908
4909 private FunctionDef_AST function_def_ast;
4910 private String id;
4911
4912 private FunctionProxy(String id) {
4913 this.id = id;
4914 }
4915
4916 private void setFunctionDefinition(FunctionDef_AST function_def) {
4917 if (function_def_ast != null) {
4918 throw new ParserException("function " + function_def + " already defined");
4919 } else {
4920 function_def_ast = function_def;
4921 }
4922 }
4923
4924 private boolean isDefined() {
4925 return function_def_ast != null;
4926 }
4927
4928 @Override
4929 public Address getFunctionAddress() {
4930 return function_def_ast.getAddress();
4931 }
4932
4933 private String getFunctionName() {
4934 return id;
4935 }
4936
4937 private int getFunctionParamCount() {
4938 return function_def_ast.paramCount();
4939 }
4940
4941 @Override
4942 public String toString() {
4943 return super.toString() + " (" + id + ")";
4944 }
4945
4946 private void checkActualToFormalParameters(AST actual_params) {
4947 function_def_ast.checkActualToFormalParameters(actual_params);
4948 }
4949 }
4950
4951
4952
4953
4954
4955
4956
4957
4958
4959
4960
4961 public void populateGlobalVariableNameToOffsetMappings(AwkTuples tuples) {
4962 for (String varname : symbol_table.global_ids.keySet()) {
4963 ID_AST id_ast = symbol_table.global_ids.get(varname);
4964
4965
4966
4967 tuples.addGlobalVariableNameToOffsetMapping(varname, id_ast.offset, id_ast.is_array);
4968 }
4969 tuples.setFunctionNameSet(symbol_table.function_proxies.keySet());
4970 }
4971
4972 private class AwkSymbolTableImpl {
4973
4974 int numGlobals() {
4975 return global_ids.size();
4976 }
4977
4978
4979 private Begin_AST begin_ast = null;
4980 private End_AST end_ast = null;
4981
4982
4983 private Map<String, FunctionProxy> function_proxies = new HashMap<String, FunctionProxy>();
4984
4985
4986 private Map<String, ID_AST> global_ids = new HashMap<String, ID_AST>();
4987 private Map<String, Map<String, ID_AST>> local_ids = new HashMap<String, Map<String, ID_AST>>();
4988 private Map<String, Set<String>> function_parameters = new HashMap<String, Set<String>>();
4989 private Set<String> ids = new HashSet<String>();
4990
4991
4992 private String func_name = null;
4993
4994
4995 void setFunctionName(String func_name) {
4996 assert this.func_name == null;
4997 this.func_name = func_name;
4998 }
4999
5000 void clearFunctionName(String func_name) {
5001 assert this.func_name != null && this.func_name.length() > 0;
5002 assert this.func_name.equals(func_name);
5003 this.func_name = null;
5004 }
5005
5006 AST addBEGIN() {
5007 if (begin_ast == null) {
5008 begin_ast = new Begin_AST();
5009 }
5010 return begin_ast;
5011 }
5012
5013 AST addEND() {
5014 if (end_ast == null) {
5015 end_ast = new End_AST();
5016 }
5017 return end_ast;
5018 }
5019
5020 private ID_AST getID(String id) {
5021 if (function_proxies.get(id) != null) {
5022 throw new ParserException("cannot use " + id + " as a variable; it is a function");
5023 }
5024
5025
5026 ids.add(id);
5027
5028 Map<String, ID_AST> map;
5029 if (func_name == null) {
5030 map = global_ids;
5031 } else {
5032 Set<String> set = function_parameters.get(func_name);
5033
5034
5035
5036 if (set != null && set.contains(id)) {
5037 map = local_ids.get(func_name);
5038 if (map == null) {
5039 local_ids.put(func_name, map = new HashMap<String, ID_AST>());
5040 }
5041 } else {
5042 map = global_ids;
5043 }
5044 }
5045 assert map != null;
5046 ID_AST id_ast = map.get(id);
5047 if (id_ast == null) {
5048 id_ast = new ID_AST(id, map == global_ids);
5049 id_ast.offset = map.size();
5050 assert id_ast.offset != AVM.NULL_OFFSET;
5051 map.put(id, id_ast);
5052 }
5053 return id_ast;
5054 }
5055
5056 AST addID(String id)
5057 throws ParserException
5058 {
5059 ID_AST ret_val = getID(id);
5060
5061
5062
5063
5064
5065
5066
5067 return ret_val;
5068 }
5069
5070 int addFunctionParameter(String func_name, String id) {
5071 Set<String> set = function_parameters.get(func_name);
5072 if (set == null) {
5073 function_parameters.put(func_name, set = new HashSet<String>());
5074 }
5075 if (set.contains(id)) {
5076 throw new ParserException("multiply defined parameter " + id + " in function " + func_name);
5077 }
5078 int retval = set.size();
5079 set.add(id);
5080
5081 Map<String, ID_AST> map = local_ids.get(func_name);
5082 if (map == null) {
5083 local_ids.put(func_name, map = new HashMap<String, ID_AST>());
5084 }
5085 assert map != null;
5086 ID_AST id_ast = map.get(id);
5087 if (id_ast == null) {
5088 id_ast = new ID_AST(id, map == global_ids);
5089 id_ast.offset = map.size();
5090 assert id_ast.offset != AVM.NULL_OFFSET;
5091 map.put(id, id_ast);
5092 }
5093
5094 return retval;
5095 }
5096
5097 ID_AST getFunctionParameterIDAST(String func_name, String f_id_string) {
5098 return local_ids.get(func_name).get(f_id_string);
5099 }
5100
5101 AST addArrayID(String id)
5102 throws ParserException
5103 {
5104 ID_AST ret_val = getID(id);
5105 if (ret_val.isScalar()) {
5106 throw new ParserException("Cannot use " + ret_val + " as an array.");
5107 }
5108 ret_val.setArray(true);
5109 return ret_val;
5110 }
5111
5112 AST addFunctionDef(String func_name, AST param_list, AST block) {
5113 if (ids.contains(func_name)) {
5114 throw new ParserException("cannot use " + func_name + " as a function; it is a variable");
5115 }
5116 FunctionProxy function_proxy = function_proxies.get(func_name);
5117 if (function_proxy == null) {
5118 function_proxies.put(func_name, function_proxy = new FunctionProxy(func_name));
5119 }
5120 FunctionDef_AST function_def = new FunctionDef_AST(func_name, param_list, block);
5121 function_proxy.setFunctionDefinition(function_def);
5122 return function_def;
5123 }
5124
5125 AST addFunctionCall(String id, AST param_list) {
5126 FunctionProxy function_proxy = function_proxies.get(id);
5127 if (function_proxy == null) {
5128 function_proxies.put(id, function_proxy = new FunctionProxy(id));
5129 }
5130 return new FunctionCall_AST(function_proxy, param_list);
5131 }
5132
5133 AST addArrayReference(String id, AST idx_ast)
5134 throws ParserException
5135 {
5136 return new ArrayReference_AST(addArrayID(id), idx_ast);
5137 }
5138
5139
5140
5141 AST addINTEGER(String integer) {
5142 return new Integer_AST(Long.parseLong(integer));
5143 }
5144
5145 AST addDOUBLE(String dbl) {
5146 return new Double_AST(Double.valueOf(dbl));
5147 }
5148
5149 AST addSTRING(String str) {
5150 return new String_AST(str);
5151 }
5152
5153 AST addREGEXP(String regexp) {
5154 return new Regexp_AST(regexp);
5155 }
5156 }
5157
5158 public class ParserException extends RuntimeException {
5159
5160 private static final long serialVersionUID = 1L;
5161
5162 ParserException(String msg) {
5163 super(msg + " ("
5164 + scriptSources.get(scriptSourcesCurrentIndex).getDescription()
5165 + ":" + reader.getLineNumber() + ")");
5166 }
5167 }
5168 }