1 package org.sentrysoftware.jawk.backend;
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.FileOutputStream;
26 import java.io.IOException;
27 import java.io.PrintStream;
28 import java.io.StringReader;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Collections;
32 import java.util.Enumeration;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Locale;
36 import java.util.Map;
37 import java.util.Random;
38 import java.util.Set;
39 import java.util.StringTokenizer;
40 import java.util.regex.Matcher;
41 import java.util.regex.Pattern;
42
43 import org.sentrysoftware.jawk.ExitException;
44 import org.sentrysoftware.jawk.ext.JawkExtension;
45 import org.sentrysoftware.jawk.frontend.AwkSyntaxTree;
46 import org.sentrysoftware.jawk.intermediate.Address;
47 import org.sentrysoftware.jawk.intermediate.AwkTuples;
48 import org.sentrysoftware.jawk.intermediate.Position;
49 import org.sentrysoftware.jawk.intermediate.PositionForInterpretation;
50 import org.sentrysoftware.jawk.intermediate.UninitializedObject;
51 import org.sentrysoftware.jawk.jrt.AssocArray;
52 import org.sentrysoftware.jawk.jrt.AwkRuntimeException;
53 import org.sentrysoftware.jawk.jrt.BlockManager;
54 import org.sentrysoftware.jawk.jrt.BlockObject;
55 import org.sentrysoftware.jawk.jrt.CharacterTokenizer;
56 import org.sentrysoftware.jawk.jrt.JRT;
57 import org.sentrysoftware.jawk.jrt.KeyList;
58 import org.sentrysoftware.jawk.jrt.KeyListImpl;
59 import org.sentrysoftware.jawk.jrt.ConditionPair;
60 import org.sentrysoftware.jawk.jrt.RegexTokenizer;
61 import org.sentrysoftware.jawk.jrt.SingleCharacterTokenizer;
62 import org.sentrysoftware.jawk.jrt.VariableManager;
63 import org.sentrysoftware.jawk.util.ArrayStackImpl;
64 import org.sentrysoftware.jawk.util.AwkLogger;
65 import org.sentrysoftware.jawk.util.AwkSettings;
66 import org.sentrysoftware.jawk.util.LinkedListStackImpl;
67 import org.sentrysoftware.jawk.util.MyStack;
68 import org.sentrysoftware.jawk.util.ScriptSource;
69 import org.sentrysoftware.printf4j.Printf4J;
70 import org.slf4j.Logger;
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101 public class AVM implements AwkInterpreter, VariableManager {
102
103 private static final Logger LOG = AwkLogger.getLogger(AVM.class);
104 private static final boolean IS_WINDOWS = (System.getProperty("os.name").indexOf("Windows") >= 0);
105
106 private RuntimeStack runtime_stack = new RuntimeStack();
107
108
109
110
111
112 private MyStack<Object> operand_stack = new ArrayStackImpl<Object>();
113 private java.util.List<String> arguments;
114 private boolean sorted_array_keys;
115 private Map<String, Object> initial_variables;
116 private String initial_fs_value;
117 private boolean trap_illegal_format_exceptions;
118 private JRT jrt;
119 final private Locale locale;
120 private Map<String, JawkExtension> extensions;
121
122
123
124
125 private Object pop() { return operand_stack.pop(); }
126 private void push(Object o) { operand_stack.push(o); }
127
128 private final AwkSettings settings;
129
130
131
132
133
134
135
136 public AVM() {
137 settings = null;
138 arguments = new ArrayList<String>();
139 sorted_array_keys = false;
140 initial_variables = new HashMap<String, Object>();
141 initial_fs_value = null;
142 trap_illegal_format_exceptions = false;
143 jrt = new JRT(this);
144 locale = Locale.getDefault();
145 this.extensions = Collections.emptyMap();
146 }
147
148
149
150
151
152
153
154
155
156 public AVM(final AwkSettings parameters, final Map<String, JawkExtension> extensions) {
157 if (parameters == null) {
158 throw new IllegalArgumentException("AwkSettings can not be null");
159 }
160 this.settings = parameters;
161 locale = settings.getLocale();
162 arguments = parameters.getNameValueOrFileNames();
163 sorted_array_keys = parameters.isUseSortedArrayKeys();
164 initial_variables = parameters.getVariables();
165 initial_fs_value = parameters.getFieldSeparator();
166 trap_illegal_format_exceptions = parameters.isCatchIllegalFormatExceptions();
167 jrt = new JRT(this);
168 this.extensions = extensions;
169 for (JawkExtension ext : extensions.values()) {
170 ext.init(this, jrt, settings);
171 }
172 }
173
174 private long nf_offset = NULL_OFFSET;
175 private long nr_offset = NULL_OFFSET;
176 private long fnr_offset = NULL_OFFSET;
177 private long fs_offset = NULL_OFFSET;
178 private long rs_offset = NULL_OFFSET;
179 private long ofs_offset = NULL_OFFSET;
180 private long ors_offset = NULL_OFFSET;
181 private long rstart_offset = NULL_OFFSET;
182 private long rlength_offset = NULL_OFFSET;
183 private long filename_offset = NULL_OFFSET;
184 private long subsep_offset = NULL_OFFSET;
185 private long convfmt_offset = NULL_OFFSET;
186 private long ofmt_offset = NULL_OFFSET;
187 private long environ_offset = NULL_OFFSET;
188 private long argc_offset = NULL_OFFSET;
189 private long argv_offset = NULL_OFFSET;
190
191 private static final Integer ZERO = Integer.valueOf(0);
192 private static final Integer ONE = Integer.valueOf(1);
193
194 private Random random_number_generator;
195 private int oldseed;
196
197 private Address exit_address = null;
198
199
200
201
202
203 private boolean within_end_blocks = false;
204
205
206
207
208 private int exit_code = 0;
209
210
211
212
213 private boolean throw_exit_exception = false;
214
215
216
217
218
219
220 private Map<String, Integer> global_variable_offsets;
221
222
223
224
225 private Map<String, Boolean> global_variable_arrays;
226 private Set<String> function_names;
227
228 private static int parseIntField(Object obj, PositionForInterpretation position) {
229
230 int fieldVal;
231
232 if (obj instanceof Number) {
233 fieldVal = ((Number) obj).intValue();
234 } else {
235 try {
236 fieldVal = (int) Double.parseDouble(obj.toString());
237 } catch (NumberFormatException nfe) {
238 throw new AwkRuntimeException(position.lineNumber(), "Field $(" + obj.toString() + ") is incorrect.");
239 }
240 }
241
242 return fieldVal;
243 }
244
245 private void setNumOnJRT(int fieldNum, double num) {
246
247 String numString;
248 if (num == (long) num) {
249 numString = Long.toString((long) num);
250 } else {
251 numString = Double.toString(num);
252 }
253
254
255 if (fieldNum == 0) {
256 jrt.setInputLine(numString.toString());
257 jrt.jrtParseFields();
258 } else {
259 jrt.jrtSetInputField(numString, fieldNum);
260 }
261 }
262
263 private String execSubOrGSub(PositionForInterpretation position, int gsubArgPos) {
264
265 String newString;
266
267
268
269
270
271 boolean is_gsub = position.boolArg(gsubArgPos);
272 String convfmt = getCONVFMT().toString();
273 String orig = JRT.toAwkString(pop(), convfmt, locale);
274 String repl = JRT.toAwkString(pop(), convfmt, locale);
275 String ere = JRT.toAwkString(pop(), convfmt, locale);
276 if (is_gsub) {
277 newString = replaceAll(orig, ere, repl);
278 } else {
279 newString = replaceFirst(orig, ere, repl);
280 }
281
282 return newString;
283 }
284
285
286
287
288
289
290
291
292 @Override
293 public void interpret(AwkTuples tuples)
294 throws ExitException, IOException
295 {
296 Map<String, Pattern> regexps = new HashMap<String, Pattern>();
297 Map<Integer, ConditionPair> condition_pairs = new HashMap<Integer, ConditionPair>();
298
299 global_variable_offsets = tuples.getGlobalVariableOffsetMap();
300 global_variable_arrays = tuples.getGlobalVariableAarrayMap();
301 function_names = tuples.getFunctionNameSet();
302
303 PositionForInterpretation position = (PositionForInterpretation) tuples.top();
304
305 try {
306 while (!position.isEOF()) {
307
308 int opcode = position.opcode();
309
310 switch (opcode) {
311 case AwkTuples._PRINT_: {
312
313
314
315
316 long num_args = position.intArg(0);
317 printTo(settings.getOutputStream(), num_args);
318 position.next();
319 break;
320 }
321 case AwkTuples._PRINT_TO_FILE_: {
322
323
324
325
326
327
328 long num_args = position.intArg(0);
329 boolean append = position.boolArg(1);
330 String key = JRT.toAwkString(pop(), getCONVFMT().toString(), locale);
331 PrintStream ps = jrt.getOutputFiles().get(key);
332 if (ps == null) {
333 try {
334 jrt.getOutputFiles().put(key, ps = new PrintStream(new FileOutputStream(key, append), true));
335 } catch (IOException ioe) {
336 throw new AwkRuntimeException(position.lineNumber(), "Cannot open " + key + " for writing: " + ioe);
337 }
338 }
339 printTo(ps, num_args);
340 position.next();
341 break;
342 }
343 case AwkTuples._PRINT_TO_PIPE_: {
344
345
346
347
348
349 long num_args = position.intArg(0);
350 String cmd = JRT.toAwkString(pop(), getCONVFMT().toString(), locale);
351 PrintStream ps = jrt.jrtSpawnForOutput(cmd);
352 printTo(ps, num_args);
353 position.next();
354 break;
355 }
356 case AwkTuples._PRINTF_: {
357
358
359
360
361 long num_args = position.intArg(0);
362 printfTo(settings.getOutputStream(), num_args);
363 position.next();
364 break;
365 }
366 case AwkTuples._PRINTF_TO_FILE_: {
367
368
369
370
371
372
373 long num_args = position.intArg(0);
374 boolean append = position.boolArg(1);
375 String key = JRT.toAwkString(pop(), getCONVFMT().toString(), locale);
376 PrintStream ps = jrt.getOutputFiles().get(key);
377 if (ps == null) {
378 try {
379 jrt.getOutputFiles().put(key, ps = new PrintStream(new FileOutputStream(key, append), true));
380 } catch (IOException ioe) {
381 throw new AwkRuntimeException(position.lineNumber(), "Cannot open " + key + " for writing: " + ioe);
382 }
383 }
384 printfTo(ps, num_args);
385 position.next();
386 break;
387 }
388 case AwkTuples._PRINTF_TO_PIPE_: {
389
390
391
392
393
394 long num_args = position.intArg(0);
395 String cmd = JRT.toAwkString(pop(), getCONVFMT().toString(), locale);
396 PrintStream ps = jrt.jrtSpawnForOutput(cmd);
397 printfTo(ps, num_args);
398 position.next();
399 break;
400 }
401 case AwkTuples._SPRINTF_: {
402
403
404
405
406 long num_args = position.intArg(0);
407 push(sprintfFunction(num_args));
408 position.next();
409 break;
410 }
411 case AwkTuples._LENGTH_: {
412
413
414
415
416
417
418 long num = position.intArg(0);
419 if (num == 0) {
420
421 push(jrt.jrtGetInputField(0).toString().length());
422 } else {
423 push(pop().toString().length());
424 }
425 position.next();
426 break;
427 }
428 case AwkTuples._PUSH_: {
429
430 push(position.arg(0));
431 position.next();
432 break;
433 }
434 case AwkTuples._POP_: {
435
436 pop();
437 position.next();
438 break;
439 }
440 case AwkTuples._IFFALSE_: {
441
442
443
444
445
446
447 boolean jump = !jrt.toBoolean(pop());
448 if (jump) {
449 position.jump(position.addressArg());
450 } else {
451 position.next();
452 }
453 break;
454 }
455 case AwkTuples._TO_NUMBER_: {
456
457
458
459
460
461 boolean val = jrt.toBoolean(pop());
462 push(val ? ONE : ZERO);
463 position.next();
464 break;
465 }
466 case AwkTuples._IFTRUE_: {
467
468
469
470
471
472
473 boolean jump = jrt.toBoolean(pop());
474 if (jump) {
475 position.jump(position.addressArg());
476 } else {
477 position.next();
478 }
479 break;
480 }
481 case AwkTuples._NOT_: {
482
483
484
485
486
487 Object o = pop();
488 boolean result;
489 if (o instanceof Integer) {
490 result = ((Integer)o).intValue() != 0;
491 } else if (o instanceof Long) {
492 result = ((Long)o).longValue() != 0;
493 } else if (o instanceof Double) {
494 result = ((Double)o).doubleValue() != 0;
495 } else if (o instanceof String) {
496 result = (o.toString().length() > 0);
497 } else if (o instanceof UninitializedObject) {
498 result = false;
499 } else {
500 throw new Error("Unknown operand_stack type: "+o.getClass()+" for value "+o);
501 }
502 if (result) {
503 push(0);
504 } else {
505 push(1);
506 }
507 position.next();
508 break;
509 }
510 case AwkTuples._NEGATE_: {
511
512
513 double d = JRT.toDouble(pop());
514 if (d == (long) d) {
515 push((long) -d);
516 } else {
517 push(-d);
518 }
519 position.next();
520 break;
521 }
522 case AwkTuples._UNARY_PLUS_: {
523
524 double d = JRT.toDouble(pop());
525 if (d == (long) d) {
526 push((long)d);
527 } else {
528 push(d);
529 }
530 position.next();
531 break;
532 }
533 case AwkTuples._GOTO_: {
534
535
536 position.jump(position.addressArg());
537 break;
538 }
539 case AwkTuples._NOP_: {
540
541 position.next();
542 break;
543 }
544 case AwkTuples._CONCAT_: {
545
546
547 String convfmt = getCONVFMT().toString();
548 String s2 = JRT.toAwkString(pop(), convfmt, locale);
549 String s1 = JRT.toAwkString(pop(), convfmt, locale);
550 String result_string = s1 + s2;
551 push(result_string);
552 position.next();
553 break;
554 }
555 case AwkTuples._ASSIGN_: {
556
557
558
559 Object value = pop();
560 boolean is_global = position.boolArg(1);
561 assign(position.intArg(0), value, is_global, position);
562 position.next();
563 break;
564 }
565 case AwkTuples._ASSIGN_ARRAY_: {
566
567
568
569
570 Object arr_idx = pop();
571 Object rhs = pop();
572 if (rhs == null) {
573 rhs = BLANK;
574 }
575 long offset = position.intArg(0);
576 boolean is_global = position.boolArg(1);
577 assignArray(offset, arr_idx, rhs, is_global);
578 position.next();
579 break;
580 }
581 case AwkTuples._PLUS_EQ_ARRAY_:
582 case AwkTuples._MINUS_EQ_ARRAY_:
583 case AwkTuples._MULT_EQ_ARRAY_:
584 case AwkTuples._DIV_EQ_ARRAY_:
585 case AwkTuples._MOD_EQ_ARRAY_:
586 case AwkTuples._POW_EQ_ARRAY_: {
587
588
589
590
591 Object arr_idx = pop();
592 Object rhs = pop();
593 if (rhs == null) {
594 rhs = BLANK;
595 }
596 long offset = position.intArg(0);
597 boolean is_global = position.boolArg(1);
598
599 double val = JRT.toDouble(rhs);
600
601
602
603
604 Object o1 = runtime_stack.getVariable(offset, is_global);
605 if (o1 == null || o1 instanceof UninitializedObject) {
606 runtime_stack.setVariable(offset, o1 = new AssocArray(sorted_array_keys), is_global);
607 } else {
608 assert o1 instanceof AssocArray;
609 }
610
611 AssocArray array = (AssocArray) o1;
612 Object o = array.get(arr_idx);
613 assert o != null;
614 double orig_val = JRT.toDouble(o);
615
616 double new_val;
617
618 switch (opcode) {
619 case AwkTuples._PLUS_EQ_ARRAY_:
620 new_val = orig_val + val;
621 break;
622 case AwkTuples._MINUS_EQ_ARRAY_:
623 new_val = orig_val - val;
624 break;
625 case AwkTuples._MULT_EQ_ARRAY_:
626 new_val = orig_val * val;
627 break;
628 case AwkTuples._DIV_EQ_ARRAY_:
629 new_val = orig_val / val;
630 break;
631 case AwkTuples._MOD_EQ_ARRAY_:
632 new_val = orig_val % val;
633 break;
634 case AwkTuples._POW_EQ_ARRAY_:
635 new_val = Math.pow(orig_val, val);
636 break;
637 default:
638 throw new Error("Invalid op code here: " + opcode);
639 }
640
641 if (new_val == (long) new_val) {
642 assignArray(offset, arr_idx, (long) new_val, is_global);
643 } else {
644 assignArray(offset, arr_idx, new_val, is_global);
645 }
646 position.next();
647 break;
648 }
649 case AwkTuples._ASSIGN_AS_INPUT_: {
650
651 jrt.setInputLine(pop().toString());
652 jrt.jrtParseFields();
653 push(jrt.getInputLine());
654 position.next();
655 break;
656 }
657 case AwkTuples._ASSIGN_AS_INPUT_FIELD_: {
658
659
660 Object field_num_obj = pop();
661 int field_num;
662 if (field_num_obj instanceof Number) {
663 field_num = ((Number) field_num_obj).intValue();
664 } else {
665 try {
666 field_num = Integer.parseInt(field_num_obj.toString());
667 } catch (NumberFormatException nfe) {
668 field_num = 0;
669 }
670 }
671 String value = pop().toString();
672 push(value);
673 if (field_num == 0) {
674 jrt.setInputLine(value);
675 jrt.jrtParseFields();
676 } else {
677 jrt.jrtSetInputField(value, field_num);
678 }
679 position.next();
680 break;
681 }
682 case AwkTuples._PLUS_EQ_:
683 case AwkTuples._MINUS_EQ_:
684 case AwkTuples._MULT_EQ_:
685 case AwkTuples._DIV_EQ_:
686 case AwkTuples._MOD_EQ_:
687 case AwkTuples._POW_EQ_: {
688
689
690
691 boolean is_global = position.boolArg(1);
692 Object o1 = runtime_stack.getVariable(position.intArg(0), is_global);
693 if (o1 == null) {
694 o1 = BLANK;
695 }
696 Object o2 = pop();
697 double d1 = JRT.toDouble(o1);
698 double d2 = JRT.toDouble(o2);
699 double ans;
700 switch (opcode) {
701 case AwkTuples._PLUS_EQ_:
702 ans = d1 + d2;
703 break;
704 case AwkTuples._MINUS_EQ_:
705 ans = d1 - d2;
706 break;
707 case AwkTuples._MULT_EQ_:
708 ans = d1 * d2;
709 break;
710 case AwkTuples._DIV_EQ_:
711 ans = d1 / d2;
712 break;
713 case AwkTuples._MOD_EQ_:
714 ans = d1 % d2;
715 break;
716 case AwkTuples._POW_EQ_:
717 ans = Math.pow(d1, d2);
718 break;
719 default:
720 throw new Error("Invalid opcode here: " + opcode);
721 }
722 if (ans == (long) ans) {
723 push((long) ans);
724 runtime_stack.setVariable(position.intArg(0), (int) ans, is_global);
725 } else {
726 push(ans);
727 runtime_stack.setVariable(position.intArg(0), ans, is_global);
728 }
729 position.next();
730 break;
731 }
732 case AwkTuples._PLUS_EQ_INPUT_FIELD_:
733 case AwkTuples._MINUS_EQ_INPUT_FIELD_:
734 case AwkTuples._MULT_EQ_INPUT_FIELD_:
735 case AwkTuples._DIV_EQ_INPUT_FIELD_:
736 case AwkTuples._MOD_EQ_INPUT_FIELD_:
737 case AwkTuples._POW_EQ_INPUT_FIELD_: {
738
739
740
741
742 int fieldnum = parseIntField(pop(), position);
743 double incval = JRT.toDouble(pop());
744
745
746 Object num_obj = jrt.jrtGetInputField(fieldnum);
747 double num;
748 switch (opcode) {
749 case AwkTuples._PLUS_EQ_INPUT_FIELD_:
750 num = JRT.toDouble(num_obj) + incval;
751 break;
752 case AwkTuples._MINUS_EQ_INPUT_FIELD_:
753 num = JRT.toDouble(num_obj) - incval;
754 break;
755 case AwkTuples._MULT_EQ_INPUT_FIELD_:
756 num = JRT.toDouble(num_obj) * incval;
757 break;
758 case AwkTuples._DIV_EQ_INPUT_FIELD_:
759 num = JRT.toDouble(num_obj) / incval;
760 break;
761 case AwkTuples._MOD_EQ_INPUT_FIELD_:
762 num = JRT.toDouble(num_obj) % incval;
763 break;
764 case AwkTuples._POW_EQ_INPUT_FIELD_:
765 num = Math.pow(JRT.toDouble(num_obj), incval);
766 break;
767 default:
768 throw new Error("Invalid opcode here: " + opcode);
769 }
770 setNumOnJRT(fieldnum, num);
771
772
773 push(num);
774 position.next();
775
776 break;
777 }
778 case AwkTuples._INC_: {
779
780
781 inc(position.intArg(0), position.boolArg(1));
782 position.next();
783 break;
784 }
785 case AwkTuples._DEC_: {
786
787
788 dec(position.intArg(0), position.boolArg(1));
789 position.next();
790 break;
791 }
792 case AwkTuples._POSTINC_: {
793
794
795 pop();
796 push(inc(position.intArg(0), position.boolArg(1)));
797 position.next();
798 break;
799 }
800 case AwkTuples._POSTDEC_: {
801
802
803 pop();
804 push(dec(position.intArg(0), position.boolArg(1)));
805 position.next();
806 break;
807 }
808 case AwkTuples._INC_ARRAY_REF_: {
809
810
811
812 boolean is_global = position.boolArg(1);
813 Object o1 = runtime_stack.getVariable(position.intArg(0), is_global);
814 if (o1 == null || o1 instanceof UninitializedObject) {
815 runtime_stack.setVariable(position.intArg(0), o1 = new AssocArray(sorted_array_keys), is_global);
816 }
817 AssocArray aa = (AssocArray) o1;
818 Object key = pop();
819 Object o = aa.get(key);
820 assert o != null;
821 double ans = JRT.toDouble(o) + 1;
822 if (ans == (long) ans) {
823 aa.put(key, (long) ans);
824 } else {
825 aa.put(key, ans);
826 }
827 position.next();
828 break;
829 }
830 case AwkTuples._DEC_ARRAY_REF_: {
831
832
833
834 boolean is_global = position.boolArg(1);
835 Object o1 = runtime_stack.getVariable(position.intArg(0), is_global);
836 if (o1 == null || o1 instanceof UninitializedObject) {
837 runtime_stack.setVariable(position.intArg(0), o1 = new AssocArray(sorted_array_keys), is_global);
838 }
839 AssocArray aa = (AssocArray) o1;
840 Object key = pop();
841 Object o = aa.get(key);
842 assert o != null;
843 double ans = JRT.toDouble(o) - 1;
844 if (ans == (long) ans) {
845 aa.put(key, (long) ans);
846 } else {
847 aa.put(key, ans);
848 }
849 position.next();
850 break;
851 }
852 case AwkTuples._INC_DOLLAR_REF_: {
853
854
855 int fieldnum = parseIntField(pop(), position);
856
857
858 Object num_obj = jrt.jrtGetInputField(fieldnum);
859 double num = JRT.toDouble(num_obj) + 1;
860 setNumOnJRT(fieldnum, num);
861
862 position.next();
863 break;
864 }
865 case AwkTuples._DEC_DOLLAR_REF_: {
866
867
868 int fieldnum = parseIntField(pop(), position);
869
870
871 Object num_obj = jrt.jrtGetInputField(fieldnum);
872 double num = JRT.toDouble(num_obj) - 1;
873 setNumOnJRT(fieldnum, num);
874
875 position.next();
876 break;
877 }
878 case AwkTuples._DEREFERENCE_: {
879
880
881 boolean is_global = position.boolArg(2);
882 Object o = runtime_stack.getVariable(position.intArg(0), is_global);
883 if (o == null) {
884 if (position.boolArg(1)) {
885
886 push(runtime_stack.setVariable(position.intArg(0), new AssocArray(sorted_array_keys), is_global));
887 } else {
888 push(runtime_stack.setVariable(position.intArg(0), BLANK, is_global));
889 }
890 } else {
891 push(o);
892 }
893 position.next();
894 break;
895 }
896 case AwkTuples._DEREF_ARRAY_: {
897
898
899 Object idx = pop();
900 Object array = pop();
901 if (!(array instanceof AssocArray)) {
902 throw new AwkRuntimeException("Attempting to index a non-associative-array.");
903 }
904 Object o = ((AssocArray) array).get(idx);
905 assert o != null;
906 push(o);
907 position.next();
908 break;
909 }
910 case AwkTuples._SRAND_: {
911
912
913 long numargs = position.intArg(0);
914 int seed;
915 if (numargs == 0) {
916
917 seed = JRT.timeSeed();
918 } else {
919 Object o = pop();
920 if (o instanceof Double) {
921 seed = ((Double) o).intValue();
922 } else if (o instanceof Long) {
923 seed = ((Long) o).intValue();
924 } else if (o instanceof Integer) {
925 seed = ((Integer) o).intValue();
926 } else {
927 try {
928 seed = Integer.parseInt(o.toString());
929 } catch (NumberFormatException nfe) {
930 seed = 0;
931 }
932 }
933 }
934 random_number_generator = new Random(seed);
935 push(oldseed);
936 oldseed = seed;
937 position.next();
938 break;
939 }
940 case AwkTuples._RAND_: {
941 if (random_number_generator == null) {
942 int seed = JRT.timeSeed();
943 random_number_generator = new Random(seed);
944 oldseed = seed;
945 }
946 push(random_number_generator.nextDouble());
947 position.next();
948 break;
949 }
950 case AwkTuples._INTFUNC_:
951 case AwkTuples._CAST_INT_: {
952
953 push((long) JRT.toDouble(pop()));
954 position.next();
955 break;
956 }
957 case AwkTuples._SQRT_: {
958
959 push(Math.sqrt(JRT.toDouble(pop())));
960 position.next();
961 break;
962 }
963 case AwkTuples._LOG_: {
964
965 push(Math.log(JRT.toDouble(pop())));
966 position.next();
967 break;
968 }
969 case AwkTuples._EXP_: {
970
971 push(Math.exp(JRT.toDouble(pop())));
972 position.next();
973 break;
974 }
975 case AwkTuples._SIN_: {
976
977 push(Math.sin(JRT.toDouble(pop())));
978 position.next();
979 break;
980 }
981 case AwkTuples._COS_: {
982
983 push(Math.cos(JRT.toDouble(pop())));
984 position.next();
985 break;
986 }
987 case AwkTuples._ATAN2_: {
988
989
990 double d2 = JRT.toDouble(pop());
991 double d1 = JRT.toDouble(pop());
992 push(Math.atan2(d1, d2));
993 position.next();
994 break;
995 }
996 case AwkTuples._MATCH_: {
997
998
999 String convfmt = getCONVFMT().toString();
1000 String ere = JRT.toAwkString(pop(), convfmt, locale);
1001 String s = JRT.toAwkString(pop(), convfmt, locale);
1002
1003
1004 int flags = 0;
1005
1006 if (global_variable_offsets.containsKey("IGNORECASE")) {
1007 Integer offset_obj = global_variable_offsets.get("IGNORECASE");
1008 Object ignorecase = runtime_stack.getVariable(offset_obj, true);
1009
1010 if (JRT.toDouble(ignorecase) != 0) {
1011 flags |= Pattern.CASE_INSENSITIVE;
1012 }
1013 }
1014
1015 Pattern pattern = Pattern.compile(ere, flags);
1016 Matcher matcher = pattern.matcher(s);
1017 boolean result = matcher.find();
1018 if (result) {
1019 assign(rstart_offset, matcher.start() + 1, true, position);
1020 assign(rlength_offset, matcher.end() - matcher.start(), true, position);
1021 pop();
1022
1023 } else {
1024 assign(rstart_offset, ZERO, true, position);
1025 assign(rlength_offset, -1, true, position);
1026 pop();
1027
1028 }
1029 position.next();
1030 break;
1031 }
1032 case AwkTuples._INDEX_: {
1033
1034
1035 String convfmt = getCONVFMT().toString();
1036 String s2 = JRT.toAwkString(pop(), convfmt, locale);
1037 String s1 = JRT.toAwkString(pop(), convfmt, locale);
1038 push(s1.indexOf(s2) + 1);
1039 position.next();
1040 break;
1041 }
1042 case AwkTuples._SUB_FOR_DOLLAR_0_: {
1043
1044
1045
1046 boolean is_gsub = position.boolArg(0);
1047 String convfmt = getCONVFMT().toString();
1048 String repl = JRT.toAwkString(pop(), convfmt, locale);
1049 String ere = JRT.toAwkString(pop(), convfmt, locale);
1050 String orig = JRT.toAwkString(jrt.jrtGetInputField(0), convfmt, locale);
1051 String newstring;
1052 if (is_gsub) {
1053 newstring = replaceAll(orig, ere, repl);
1054 } else {
1055 newstring = replaceFirst(orig, ere, repl);
1056 }
1057
1058 jrt.setInputLine(newstring);
1059 jrt.jrtParseFields();
1060 position.next();
1061 break;
1062 }
1063 case AwkTuples._SUB_FOR_DOLLAR_REFERENCE_: {
1064
1065
1066
1067
1068
1069 boolean is_gsub = position.boolArg(0);
1070 String convfmt = getCONVFMT().toString();
1071 int fieldNum = (int) JRT.toDouble(pop());
1072 String orig = JRT.toAwkString(pop(), convfmt, locale);
1073 String repl = JRT.toAwkString(pop(), convfmt, locale);
1074 String ere = JRT.toAwkString(pop(), convfmt, locale);
1075 String newstring;
1076 if (is_gsub) {
1077 newstring = replaceAll(orig, ere, repl);
1078 } else {
1079 newstring = replaceFirst(orig, ere, repl);
1080 }
1081
1082 if (fieldNum == 0) {
1083 jrt.setInputLine(newstring);
1084 jrt.jrtParseFields();
1085 } else {
1086 jrt.jrtSetInputField(newstring, fieldNum);
1087 }
1088 position.next();
1089 break;
1090 }
1091 case AwkTuples._SUB_FOR_VARIABLE_: {
1092
1093
1094
1095
1096
1097
1098 long offset = position.intArg(0);
1099 boolean is_global = position.boolArg(1);
1100 String newString = execSubOrGSub(position, 2);
1101
1102 assign(offset, newString, is_global, position);
1103 pop();
1104 position.next();
1105 break;
1106 }
1107 case AwkTuples._SUB_FOR_ARRAY_REFERENCE_: {
1108
1109
1110
1111
1112
1113
1114
1115
1116 long offset = position.intArg(0);
1117 boolean is_global = position.boolArg(1);
1118 Object arr_idx = pop();
1119 String newString = execSubOrGSub(position, 2);
1120
1121 assignArray(offset, arr_idx, newString, is_global);
1122 pop();
1123 position.next();
1124 break;
1125 }
1126 case AwkTuples._SPLIT_: {
1127
1128
1129
1130
1131 String convfmt = getCONVFMT().toString();
1132 long numargs = position.intArg(0);
1133 String fs_string;
1134 if (numargs == 2) {
1135 fs_string = JRT.toAwkString(getFS(), convfmt, locale);
1136 } else if (numargs == 3) {
1137 fs_string = JRT.toAwkString(pop(), convfmt, locale);
1138 } else {
1139 throw new Error("Invalid # of args. split() requires 2 or 3. Got: " + numargs);
1140 }
1141 Object o = pop();
1142 if (!(o instanceof AssocArray)) {
1143 throw new AwkRuntimeException(position.lineNumber(), o + " is not an array.");
1144 }
1145 String s = JRT.toAwkString(pop(), convfmt, locale);
1146 Enumeration<Object> tokenizer;
1147 if (fs_string.equals(" ")) {
1148 tokenizer = new StringTokenizer(s);
1149 } else if (fs_string.length() == 1) {
1150 tokenizer = new SingleCharacterTokenizer(s, fs_string.charAt(0));
1151 } else if (fs_string.isEmpty()) {
1152 tokenizer = new CharacterTokenizer(s);
1153 } else {
1154 tokenizer = new RegexTokenizer(s, fs_string);
1155 }
1156
1157 AssocArray assoc_array = (AssocArray) o;
1158 assoc_array.clear();
1159 int cnt = 0;
1160 while (tokenizer.hasMoreElements()) {
1161 assoc_array.put(++cnt, tokenizer.nextElement());
1162 }
1163 push(cnt);
1164 position.next();
1165 break;
1166 }
1167 case AwkTuples._SUBSTR_: {
1168
1169
1170
1171
1172 long numargs = position.intArg(0);
1173 int startPos, length;
1174 String s;
1175 if (numargs == 3)
1176 {
1177 length = (int) JRT.toLong(pop());
1178 startPos = (int) JRT.toDouble(pop());
1179 s = JRT.toAwkString(pop(), getCONVFMT().toString(), locale);
1180 } else if (numargs == 2) {
1181 startPos = (int) JRT.toDouble(pop());
1182 s = JRT.toAwkString(pop(), getCONVFMT().toString(), locale);
1183 length = s.length() - startPos + 1;
1184 } else {
1185 throw new Error("numargs for _SUBSTR_ must be 2 or 3. It is " + numargs);
1186 }
1187 if (startPos <= 0) {
1188 startPos = 1;
1189 }
1190 if (length <= 0 || startPos > s.length()) {
1191 push(BLANK);
1192 } else {
1193 if (startPos + length > s.length()) {
1194 push(s.substring(startPos - 1));
1195 } else {
1196 push(s.substring(startPos - 1, startPos + length - 1));
1197 }
1198 }
1199 position.next();
1200 break;
1201 }
1202 case AwkTuples._TOLOWER_: {
1203
1204 push(JRT.toAwkString(pop(), getCONVFMT().toString(), locale).toLowerCase());
1205 position.next();
1206 break;
1207 }
1208 case AwkTuples._TOUPPER_: {
1209
1210 push(JRT.toAwkString(pop(), getCONVFMT().toString(), locale).toUpperCase());
1211 position.next();
1212 break;
1213 }
1214 case AwkTuples._SYSTEM_: {
1215
1216 String s = JRT.toAwkString(pop(), getCONVFMT().toString(), locale);
1217 push(JRT.jrtSystem(s));
1218 position.next();
1219 break;
1220 }
1221 case AwkTuples._SWAP_: {
1222
1223
1224 swapOnStack();
1225 position.next();
1226 break;
1227 }
1228 case AwkTuples._CMP_EQ_: {
1229
1230
1231 Object o2 = pop();
1232 Object o1 = pop();
1233 push(JRT.compare2(o1, o2, 0) ? ONE : ZERO);
1234 position.next();
1235 break;
1236 }
1237 case AwkTuples._CMP_LT_: {
1238
1239
1240 Object o2 = pop();
1241 Object o1 = pop();
1242 push(JRT.compare2(o1, o2, -1) ? ONE : ZERO);
1243 position.next();
1244 break;
1245 }
1246 case AwkTuples._CMP_GT_: {
1247
1248
1249 Object o2 = pop();
1250 Object o1 = pop();
1251 push(JRT.compare2(o1, o2, 1) ? ONE : ZERO);
1252 position.next();
1253 break;
1254 }
1255 case AwkTuples._MATCHES_: {
1256
1257
1258 Object o2 = pop();
1259 Object o1 = pop();
1260
1261 String s = o1.toString();
1262
1263 if (o2 instanceof Pattern) {
1264 Pattern p = (Pattern) o2;
1265 Matcher m = p.matcher(s);
1266
1267
1268 boolean result = m.find();
1269 push(result ? 1 : 0);
1270 } else {
1271 String r = JRT.toAwkString(o2, getCONVFMT().toString(), locale);
1272 boolean result = Pattern.compile(r).matcher(s).find();
1273 push(result ? 1 : 0);
1274 }
1275 position.next();
1276 break;
1277 }
1278 case AwkTuples._SLEEP_: {
1279
1280
1281
1282
1283
1284
1285 long seconds;
1286 long numargs = position.intArg(0);
1287 if (numargs == 0) {
1288 seconds = 1;
1289 } else {
1290 seconds = (long) JRT.toDouble(pop());
1291 }
1292 try {
1293 Thread.sleep(seconds * 1000);
1294 } catch (InterruptedException ie) {
1295 throw new AwkRuntimeException(position.lineNumber(), "Caught exception while waiting for process exit: " + ie);
1296 }
1297 position.next();
1298 break;
1299 }
1300 case AwkTuples._DUMP_: {
1301
1302
1303
1304
1305
1306
1307 long numargs = position.intArg(0);
1308 AssocArray[] aa_array;
1309 if (numargs == 0) {
1310 aa_array = null;
1311 } else {
1312 aa_array = new AssocArray[(int) numargs];
1313 for (int i = 0; i < numargs; ++i) {
1314 aa_array[i] = (AssocArray) pop();
1315 }
1316 }
1317 avmDump(aa_array);
1318 position.next();
1319 break;
1320 }
1321 case AwkTuples._ADD_: {
1322
1323
1324 Object o2 = pop();
1325 Object o1 = pop();
1326 double d1 = JRT.toDouble(o1);
1327 double d2 = JRT.toDouble(o2);
1328 double ans = d1 + d2;
1329 if (ans == (long) ans) {
1330 push((long) ans);
1331 } else {
1332 push(ans);
1333 }
1334 position.next();
1335 break;
1336 }
1337 case AwkTuples._SUBTRACT_: {
1338
1339
1340 Object o2 = pop();
1341 Object o1 = pop();
1342 double d1 = JRT.toDouble(o1);
1343 double d2 = JRT.toDouble(o2);
1344 double ans = d1 - d2;
1345 if (ans == (long) ans) {
1346 push((long) ans);
1347 } else {
1348 push(ans);
1349 }
1350 position.next();
1351 break;
1352 }
1353 case AwkTuples._MULTIPLY_: {
1354
1355
1356 Object o2 = pop();
1357 Object o1 = pop();
1358 double d1 = JRT.toDouble(o1);
1359 double d2 = JRT.toDouble(o2);
1360 double ans = d1 * d2;
1361 if (ans == (long) ans) {
1362 push((long) ans);
1363 } else {
1364 push(ans);
1365 }
1366 position.next();
1367 break;
1368 }
1369 case AwkTuples._DIVIDE_: {
1370
1371
1372 Object o2 = pop();
1373 Object o1 = pop();
1374 double d1 = JRT.toDouble(o1);
1375 double d2 = JRT.toDouble(o2);
1376 double ans = d1 / d2;
1377 if (ans == (long) ans) {
1378 push((long) ans);
1379 } else {
1380 push(ans);
1381 }
1382 position.next();
1383 break;
1384 }
1385 case AwkTuples._MOD_: {
1386
1387
1388 Object o2 = pop();
1389 Object o1 = pop();
1390 double d1 = JRT.toDouble(o1);
1391 double d2 = JRT.toDouble(o2);
1392 double ans = d1 % d2;
1393 if (ans == (long) ans) {
1394 push((long) ans);
1395 } else {
1396 push(ans);
1397 }
1398 position.next();
1399 break;
1400 }
1401 case AwkTuples._POW_: {
1402
1403
1404 Object o2 = pop();
1405 Object o1 = pop();
1406 double d1 = JRT.toDouble(o1);
1407 double d2 = JRT.toDouble(o2);
1408 double ans = Math.pow(d1, d2);
1409 if (ans == (long) ans) {
1410 push((long) ans);
1411 } else {
1412 push(ans);
1413 }
1414 position.next();
1415 break;
1416 }
1417 case AwkTuples._DUP_: {
1418
1419 Object o = pop();
1420 push(o);
1421 push(o);
1422 position.next();
1423 break;
1424 }
1425 case AwkTuples._KEYLIST_: {
1426
1427 Object o = pop();
1428 assert o != null;
1429 if (!(o instanceof AssocArray)) {
1430 throw new AwkRuntimeException(position.lineNumber(), "Cannot get a keylist (via 'in') of a non associative array. arg = " + o.getClass() + ", " + o);
1431 }
1432 AssocArray aa = (AssocArray) o;
1433 push(new KeyListImpl(aa.keySet()));
1434 position.next();
1435 break;
1436 }
1437 case AwkTuples._IS_EMPTY_KEYLIST_: {
1438
1439
1440 Object o = pop();
1441 if (o == null || !(o instanceof KeyList)) {
1442 throw new AwkRuntimeException(position.lineNumber(), "Cannot get a keylist (via 'in') of a non associative array. arg = " + o.getClass() + ", " + o);
1443 }
1444 KeyList keylist = (KeyList) o;
1445 if (keylist.size() == 0) {
1446 position.jump(position.addressArg());
1447 } else {
1448 position.next();
1449 }
1450 break;
1451 }
1452 case AwkTuples._GET_FIRST_AND_REMOVE_FROM_KEYLIST_: {
1453
1454 Object o = pop();
1455 if (o == null || !(o instanceof KeyList)) {
1456 throw new AwkRuntimeException(position.lineNumber(), "Cannot get a keylist (via 'in') of a non associative array. arg = " + o.getClass() + ", " + o);
1457 }
1458
1459 KeyList keylist = (KeyList) o;
1460 assert keylist.size() > 0;
1461 push(keylist.getFirstAndRemove());
1462 position.next();
1463 break;
1464 }
1465 case AwkTuples._CHECK_CLASS_: {
1466
1467
1468 Object o = pop();
1469 if (!(position.classArg().isInstance(o))) {
1470 throw new AwkRuntimeException(position.lineNumber(), "Verification failed. Top-of-stack = " + o.getClass() + " isn't an instance of " + position.classArg());
1471 }
1472 push(o);
1473 position.next();
1474 break;
1475 }
1476 case AwkTuples._CONSUME_INPUT_: {
1477
1478
1479
1480 if (avmConsumeInput(false)) {
1481 position.next();
1482 } else {
1483 position.jump(position.addressArg());
1484 }
1485 break;
1486 }
1487 case AwkTuples._GETLINE_INPUT_: {
1488 avmConsumeInputForGetline();
1489 position.next();
1490 break;
1491 }
1492 case AwkTuples._USE_AS_FILE_INPUT_: {
1493
1494 String s = JRT.toAwkString(pop(), getCONVFMT().toString(), locale);
1495 avmConsumeFileInputForGetline(s);
1496 position.next();
1497 break;
1498 }
1499 case AwkTuples._USE_AS_COMMAND_INPUT_: {
1500
1501 String s = JRT.toAwkString(pop(), getCONVFMT().toString(), locale);
1502 avmConsumeCommandInputForGetline(s);
1503 position.next();
1504 break;
1505 }
1506 case AwkTuples._NF_OFFSET_: {
1507
1508 nf_offset = position.intArg(0);
1509 assert nf_offset != NULL_OFFSET;
1510 assign(nf_offset, 0, true, position);
1511 pop();
1512 position.next();
1513 break;
1514 }
1515 case AwkTuples._NR_OFFSET_: {
1516
1517 nr_offset = position.intArg(0);
1518 assert nr_offset != NULL_OFFSET;
1519 assign(nr_offset, 0, true, position);
1520 pop();
1521 position.next();
1522 break;
1523 }
1524 case AwkTuples._FNR_OFFSET_: {
1525
1526 fnr_offset = position.intArg(0);
1527 assert fnr_offset != NULL_OFFSET;
1528 assign(fnr_offset, 0, true, position);
1529 pop();
1530 position.next();
1531 break;
1532 }
1533 case AwkTuples._FS_OFFSET_: {
1534
1535 fs_offset = position.intArg(0);
1536 assert fs_offset != NULL_OFFSET;
1537 if (initial_fs_value == null) {
1538 assign(fs_offset, " ", true, position);
1539 } else {
1540 assign(fs_offset, initial_fs_value, true, position);
1541 }
1542 pop();
1543 position.next();
1544 break;
1545 }
1546 case AwkTuples._RS_OFFSET_: {
1547
1548 rs_offset = position.intArg(0);
1549 assert rs_offset != NULL_OFFSET;
1550 assign(rs_offset, settings.getDefaultRS(), true, position);
1551 pop();
1552 position.next();
1553 break;
1554 }
1555 case AwkTuples._OFS_OFFSET_: {
1556
1557 ofs_offset = position.intArg(0);
1558 assert ofs_offset != NULL_OFFSET;
1559 assign(ofs_offset, " ", true, position);
1560 pop();
1561 position.next();
1562 break;
1563 }
1564 case AwkTuples._ORS_OFFSET_: {
1565
1566 ors_offset = position.intArg(0);
1567 assert ors_offset != NULL_OFFSET;
1568 assign(ors_offset, settings.getDefaultORS(), true, position);
1569 pop();
1570 position.next();
1571 break;
1572 }
1573 case AwkTuples._RSTART_OFFSET_: {
1574
1575 rstart_offset = position.intArg(0);
1576 assert rstart_offset != NULL_OFFSET;
1577 assign(rstart_offset, "", true, position);
1578 pop();
1579 position.next();
1580 break;
1581 }
1582 case AwkTuples._RLENGTH_OFFSET_: {
1583
1584 rlength_offset = position.intArg(0);
1585 assert rlength_offset != NULL_OFFSET;
1586 assign(rlength_offset, "", true, position);
1587 pop();
1588 position.next();
1589 break;
1590 }
1591 case AwkTuples._FILENAME_OFFSET_: {
1592
1593 filename_offset = position.intArg(0);
1594 assert filename_offset != NULL_OFFSET;
1595 assign(filename_offset, "", true, position);
1596 pop();
1597 position.next();
1598 break;
1599 }
1600 case AwkTuples._SUBSEP_OFFSET_: {
1601
1602 subsep_offset = position.intArg(0);
1603 assert subsep_offset != NULL_OFFSET;
1604 assign(subsep_offset, new String(new byte[] {28}), true, position);
1605 pop();
1606 position.next();
1607 break;
1608 }
1609 case AwkTuples._CONVFMT_OFFSET_: {
1610
1611 convfmt_offset = position.intArg(0);
1612 assert convfmt_offset != NULL_OFFSET;
1613 assign(convfmt_offset, "%.6g", true, position);
1614 pop();
1615 position.next();
1616 break;
1617 }
1618 case AwkTuples._OFMT_OFFSET_: {
1619
1620 ofmt_offset = position.intArg(0);
1621 assert ofmt_offset != NULL_OFFSET;
1622 assign(ofmt_offset, "%.6g", true, position);
1623 pop();
1624 position.next();
1625 break;
1626 }
1627 case AwkTuples._ENVIRON_OFFSET_: {
1628
1629
1630 environ_offset = position.intArg(0);
1631 assert environ_offset != NULL_OFFSET;
1632
1633 Map<String, String> env = System.getenv();
1634 for (Map.Entry<String, String> var : env.entrySet()) {
1635 assignArray(environ_offset, var.getKey(), var.getValue(), true);
1636 pop();
1637 }
1638 position.next();
1639 break;
1640 }
1641 case AwkTuples._ARGC_OFFSET_: {
1642
1643 argc_offset = position.intArg(0);
1644 assert argc_offset != NULL_OFFSET;
1645
1646
1647 assign(argc_offset, arguments.size() + 1, true, position);
1648 pop();
1649 position.next();
1650 break;
1651 }
1652 case AwkTuples._ARGV_OFFSET_: {
1653
1654 argv_offset = position.intArg(0);
1655 assert argv_offset != NULL_OFFSET;
1656
1657 int argc = (int) JRT.toDouble(runtime_stack.getVariable(argc_offset, true));
1658 assignArray(argv_offset, 0, "java Awk", true);
1659 pop();
1660 for (int i = 1; i < argc; i++) {
1661
1662 assignArray(argv_offset, i, arguments.get(i - 1), true);
1663 pop();
1664 }
1665 position.next();
1666 break;
1667 }
1668 case AwkTuples._GET_INPUT_FIELD_: {
1669
1670 int fieldnum = parseIntField(pop(), position);
1671 push(jrt.jrtGetInputField(fieldnum));
1672 position.next();
1673 break;
1674 }
1675 case AwkTuples._APPLY_RS_: {
1676 assert rs_offset != NULL_OFFSET;
1677 Object rs_obj = runtime_stack.getVariable(rs_offset, true);
1678 if (jrt.getPartitioningReader() != null) {
1679 jrt.getPartitioningReader().setRecordSeparator(rs_obj.toString());
1680 }
1681 position.next();
1682 break;
1683 }
1684 case AwkTuples._CALL_FUNCTION_: {
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694 Address func_addr = position.addressArg();
1695
1696 long num_formal_params = position.intArg(2);
1697 long num_actual_params = position.intArg(3);
1698 assert num_formal_params >= num_actual_params;
1699 runtime_stack.pushFrame(num_formal_params, position.current());
1700
1701 for (long i = num_actual_params - 1 ; i >= 0 ; i--) {
1702 runtime_stack.setVariable(i, pop(), false);
1703 }
1704 position.jump(func_addr);
1705
1706 break;
1707 }
1708 case AwkTuples._FUNCTION_: {
1709
1710
1711
1712
1713 position.next();
1714 break;
1715 }
1716 case AwkTuples._SET_RETURN_RESULT_: {
1717
1718 runtime_stack.setReturnValue(pop());
1719 position.next();
1720 break;
1721 }
1722 case AwkTuples._RETURN_FROM_FUNCTION_: {
1723 position.jump(runtime_stack.popFrame());
1724 push(runtime_stack.getReturnValue());
1725 position.next();
1726 break;
1727 }
1728 case AwkTuples._SET_NUM_GLOBALS_: {
1729
1730 assert position.intArg(0) == global_variable_offsets.size();
1731 runtime_stack.setNumGlobals(position.intArg(0));
1732
1733
1734
1735
1736
1737 for (String key : initial_variables.keySet()) {
1738 if (function_names.contains(key)) {
1739 throw new IllegalArgumentException("Cannot assign a scalar to a function name (" + key + ").");
1740 }
1741 Integer offset_obj = global_variable_offsets.get(key);
1742 Boolean array_obj = global_variable_arrays.get(key);
1743 if (offset_obj != null) {
1744 assert array_obj != null;
1745 if (array_obj.booleanValue()) {
1746 throw new IllegalArgumentException("Cannot assign a scalar to a non-scalar variable (" + key + ").");
1747 } else {
1748 Object obj = initial_variables.get(key);
1749 runtime_stack.setFilelistVariable(offset_obj.intValue(), obj);
1750 }
1751 }
1752 }
1753
1754 position.next();
1755 break;
1756 }
1757 case AwkTuples._CLOSE_: {
1758
1759 String s = JRT.toAwkString(pop(), getCONVFMT().toString(), locale);
1760 push(jrt.jrtClose(s));
1761 position.next();
1762 break;
1763 }
1764 case AwkTuples._APPLY_SUBSEP_: {
1765
1766
1767
1768
1769 long count = position.intArg(0);
1770 assert count >= 1;
1771
1772 String convfmt = getCONVFMT().toString();
1773 if (count == 1) {
1774
1775 } else {
1776 StringBuilder sb = new StringBuilder();
1777 sb.append(JRT.toAwkString(pop(), convfmt, locale));
1778 String subsep = JRT.toAwkString(runtime_stack.getVariable(subsep_offset, true), convfmt, locale);
1779 for (int i = 1; i < count; i++) {
1780 sb.insert(0, subsep);
1781 sb.insert(0, JRT.toAwkString(pop(), convfmt, locale));
1782 }
1783 push(sb.toString());
1784 }
1785 position.next();
1786 break;
1787 }
1788 case AwkTuples._DELETE_ARRAY_ELEMENT_: {
1789
1790
1791
1792 long offset = position.intArg(0);
1793 boolean is_global = position.boolArg(1);
1794 AssocArray aa = (AssocArray) runtime_stack.getVariable(offset, is_global);
1795 Object key = pop();
1796 if (aa != null) {
1797 aa.remove(key);
1798 }
1799 position.next();
1800 break;
1801 }
1802 case AwkTuples._DELETE_ARRAY_: {
1803
1804
1805
1806 long offset = position.intArg(0);
1807 boolean is_global = position.boolArg(1);
1808 runtime_stack.removeVariable(offset, is_global);
1809 position.next();
1810 break;
1811 }
1812 case AwkTuples._SET_EXIT_ADDRESS_: {
1813
1814 exit_address = position.addressArg();
1815 position.next();
1816 break;
1817 }
1818 case AwkTuples._SET_WITHIN_END_BLOCKS_: {
1819
1820 within_end_blocks = position.boolArg(0);
1821 position.next();
1822 break;
1823 }
1824 case AwkTuples._EXIT_WITHOUT_CODE_:
1825 case AwkTuples._EXIT_WITH_CODE_: {
1826 if (opcode == AwkTuples._EXIT_WITH_CODE_) {
1827
1828 exit_code = (int) JRT.toDouble(pop());
1829 }
1830 throw_exit_exception = true;
1831
1832
1833 if (!within_end_blocks) {
1834
1835 runtime_stack.popAllFrames();
1836
1837 operand_stack.clear();
1838 position.jump(exit_address);
1839 } else {
1840
1841 jrt.jrtCloseAll();
1842
1843 operand_stack.clear();
1844 throw new ExitException(exit_code, "The AWK script requested an exit");
1845
1846 }
1847 break;
1848 }
1849 case AwkTuples._REGEXP_: {
1850
1851 String key = JRT.toAwkString(position.arg(0), getCONVFMT().toString(), locale);
1852 Pattern pattern = regexps.get(key);
1853 if (pattern == null) {
1854 regexps.put(key, pattern = Pattern.compile(key));
1855 }
1856 push(pattern);
1857 position.next();
1858 break;
1859 }
1860 case AwkTuples._CONDITION_PAIR_: {
1861
1862
1863 ConditionPair cp = condition_pairs.get(position.current());
1864 if (cp == null) {
1865 cp = new ConditionPair();
1866 condition_pairs.put(position.current(), cp);
1867 }
1868 boolean end = jrt.toBoolean(pop());
1869 boolean start = jrt.toBoolean(pop());
1870 push(cp.update(start, end) ? ONE : ZERO);
1871 position.next();
1872 break;
1873 }
1874 case AwkTuples._IS_IN_: {
1875
1876
1877 Object arr = pop();
1878 Object arg = pop();
1879 AssocArray aa = (AssocArray) arr;
1880 boolean result = aa.isIn(arg);
1881 push(result ? ONE : ZERO);
1882 position.next();
1883 break;
1884 }
1885 case AwkTuples._CAST_DOUBLE_: {
1886 push(JRT.toDouble(pop()));
1887 position.next();
1888 break;
1889 }
1890 case AwkTuples._CAST_STRING_: {
1891 push(pop().toString());
1892 position.next();
1893 break;
1894 }
1895 case AwkTuples._THIS_: {
1896
1897
1898
1899
1900 position.next();
1901 break;
1902 }
1903 case AwkTuples._EXEC_: {
1904
1905
1906
1907
1908 String awk_code = JRT.toAwkString(pop(), getCONVFMT().toString(), locale);
1909 List<ScriptSource> scriptSources = new ArrayList<ScriptSource>(1);
1910 scriptSources.add(new ScriptSource(ScriptSource.DESCRIPTION_COMMAND_LINE_SCRIPT, new StringReader(awk_code), false));
1911
1912 org.sentrysoftware.jawk.frontend.AwkParser ap = new org.sentrysoftware.jawk.frontend.AwkParser(
1913
1914 settings.isAdditionalFunctions(),
1915 settings.isAdditionalTypeFunctions(),
1916 extensions);
1917 try {
1918 AwkSyntaxTree ast = ap.parse(scriptSources);
1919 if (ast != null) {
1920 ast.semanticAnalysis();
1921 ast.semanticAnalysis();
1922 AwkTuples new_tuples = new AwkTuples();
1923 int result = ast.populateTuples(new_tuples);
1924 assert result == 0;
1925 new_tuples.postProcess();
1926 ap.populateGlobalVariableNameToOffsetMappings(new_tuples);
1927 AVM new_avm = new AVM(settings, extensions);
1928 int subScriptExitCode = 0;
1929 try {
1930 new_avm.interpret(new_tuples);
1931 } catch (ExitException ex) {
1932 subScriptExitCode = ex.getCode();
1933 }
1934 push(subScriptExitCode);
1935 } else {
1936 push(-1);
1937 }
1938 } catch (IOException ioe) {
1939 throw new AwkRuntimeException(position.lineNumber(), "IO Exception caught : " + ioe);
1940 }
1941
1942 position.next();
1943 break;
1944 }
1945 case AwkTuples._EXTENSION_: {
1946
1947
1948
1949
1950
1951
1952
1953 String extension_keyword = position.arg(0).toString();
1954 long num_args = position.intArg(1);
1955 boolean is_initial = position.boolArg(2);
1956
1957 JawkExtension extension = extensions.get(extension_keyword);
1958 if (extension == null) {
1959 throw new AwkRuntimeException("Extension for '" + extension_keyword + "' not found.");
1960 }
1961
1962 Object[] args = new Object[(int) num_args];
1963 for (int i = (int)num_args - 1 ; i >=0 ; i--) {
1964 args[i] = pop();
1965 }
1966
1967 Object retval = extension.invoke(extension_keyword, args);
1968
1969
1970
1971
1972 if (is_initial && retval != null && retval instanceof BlockObject) {
1973 retval = new BlockManager().block((BlockObject) retval);
1974 }
1975
1976
1977 if (retval == null) {
1978 retval = "";
1979 } else if (retval instanceof Integer) {
1980 } else if (retval instanceof Long) {
1981 } else if (retval instanceof Double) {
1982 } else if (retval instanceof String) {
1983 } else if (retval instanceof AssocArray) {
1984 } else if (retval instanceof BlockObject) {
1985
1986 } else {
1987
1988
1989 retval = retval.toString();
1990 }
1991 push(retval);
1992
1993 position.next();
1994 break;
1995 }
1996 default:
1997 throw new Error("invalid opcode: " + AwkTuples.toOpcodeString(position.opcode()));
1998 }
1999 }
2000
2001
2002 jrt.jrtCloseAll();
2003
2004 } catch (RuntimeException re) {
2005 LOG.error("", re);
2006 LOG.error("operand_stack = {}", operand_stack);
2007 LOG.error("position = {}", position);
2008 LOG.error("line number = {}", position.lineNumber());
2009
2010
2011 runtime_stack.popAllFrames();
2012
2013 operand_stack.clear();
2014
2015 throw re;
2016 } catch (AssertionError ae) {
2017 LOG.error("", ae);
2018 LOG.error("operand_stack = {}", operand_stack);
2019 try {
2020 LOG.error("position = {}", position);
2021 } catch (Throwable t) {
2022 LOG.error("{ could not report on position", t);
2023 }
2024 try {
2025 LOG.error("line number = {}", position.lineNumber());
2026 } catch (Throwable t) {
2027 LOG.error("{ could not report on line number", t);
2028 }
2029 throw ae;
2030 }
2031
2032
2033 if (throw_exit_exception) {
2034 throw new ExitException(exit_code, "The AWK script requested an exit");
2035 }
2036
2037 }
2038
2039
2040
2041
2042 public void waitForIO() {
2043 jrt.jrtCloseAll();
2044 }
2045
2046 private void avmDump(AssocArray[] aa_array) {
2047 if (aa_array == null) {
2048
2049 Object[] globals = runtime_stack.getNumGlobals();
2050 for (String name : global_variable_offsets.keySet()) {
2051 int idx = global_variable_offsets.get(name);
2052 Object value = globals[idx];
2053 if (value instanceof AssocArray) {
2054 AssocArray aa = (AssocArray) value;
2055 value = aa.mapString();
2056 }
2057 LOG.info("{} = {}", name, value);
2058 }
2059 } else {
2060
2061 for (AssocArray aa : aa_array) {
2062 LOG.info(aa.mapString());
2063 }
2064 }
2065 }
2066
2067 private void printTo(PrintStream ps, long num_args) {
2068
2069
2070 if (num_args == 0) {
2071
2072 ps.print(jrt.jrtGetInputField(0));
2073 ps.print(getORS().toString());
2074 } else {
2075
2076
2077 String ofs_string = getOFS().toString();
2078
2079
2080 Object[] args = new Object[(int)num_args];
2081 for (int i = (int)num_args - 1 ; i >=0 ; i--) {
2082 args[i] = pop();
2083 }
2084
2085
2086 for (int i = 0 ; i < num_args ; i++) {
2087 ps.print(JRT.toAwkStringForOutput(args[i], getOFMT().toString(), locale));
2088
2089 if (i < num_args - 1) {
2090
2091 ps.print(ofs_string);
2092 }
2093 }
2094 ps.print(getORS().toString());
2095 }
2096
2097 if (IS_WINDOWS) {
2098 ps.flush();
2099 }
2100 }
2101
2102 private void printfTo(PrintStream ps, long num_args) {
2103
2104 ps.print(sprintfFunction(num_args));
2105
2106 if (IS_WINDOWS) {
2107 ps.flush();
2108 }
2109 }
2110
2111
2112
2113
2114 private String sprintfFunction(long num_args) {
2115
2116
2117 if (num_args == 0) return "";
2118
2119
2120 Object[] arg_array = new Object[(int) (num_args - 1)];
2121
2122
2123
2124
2125 for (int i = (int)num_args - 2 ; i >= 0 ; i--) {
2126 arg_array[i] = pop();
2127 }
2128
2129
2130 String fmt = JRT.toAwkString(pop(), getCONVFMT().toString(), locale);
2131
2132 if (trap_illegal_format_exceptions) {
2133 return Printf4J.sprintf(locale, fmt, arg_array);
2134 } else {
2135 return JRT.sprintfNoCatch(locale, fmt, arg_array);
2136 }
2137 }
2138
2139 private StringBuffer replace_first_sb = new StringBuffer();
2140
2141
2142
2143
2144 private String replaceFirst(String orig, String ere, String repl) {
2145 push(JRT.replaceFirst(orig, repl, ere, replace_first_sb));
2146 return replace_first_sb.toString();
2147 }
2148
2149 private StringBuffer replace_all_sb = new StringBuffer();
2150
2151
2152
2153
2154 private String replaceAll(String orig, String ere, String repl) {
2155 push(JRT.replaceAll(orig, repl, ere, replace_all_sb));
2156 return replace_all_sb.toString();
2157 }
2158
2159
2160
2161
2162 private void assign(long l, Object value, boolean is_global, Position position) {
2163
2164 if (runtime_stack.getVariable(l, is_global) instanceof AssocArray) {
2165 throw new AwkRuntimeException(position.lineNumber(), "cannot assign anything to an unindexed associative array");
2166 }
2167 push(value);
2168 runtime_stack.setVariable(l, value, is_global);
2169 }
2170
2171
2172
2173
2174 private void assignArray(long offset, Object arr_idx, Object rhs, boolean is_global) {
2175 Object o1 = runtime_stack.getVariable(offset, is_global);
2176 if (o1 == null || o1.equals(BLANK)) {
2177 runtime_stack.setVariable(offset, o1 = new AssocArray(sorted_array_keys), is_global);
2178 }
2179 assert o1 != null;
2180
2181
2182
2183
2184
2185
2186
2187
2188 assert o1 instanceof AssocArray;
2189 AssocArray array = (AssocArray) o1;
2190
2191
2192
2193 array.put(arr_idx, rhs);
2194 push(rhs);
2195 }
2196
2197
2198
2199
2200
2201 private Object inc(long l, boolean is_global) {
2202 Object o = runtime_stack.getVariable(l, is_global);
2203 if (o == null || o instanceof UninitializedObject) {
2204 runtime_stack.setVariable(l, o = ZERO, is_global);
2205 }
2206 runtime_stack.setVariable(l, JRT.inc(o), is_global);
2207 return o;
2208 }
2209
2210
2211
2212
2213
2214 private Object dec(long l, boolean is_global) {
2215 Object o = runtime_stack.getVariable(l, is_global);
2216 if (o == null) {
2217 runtime_stack.setVariable(l, o = ZERO, is_global);
2218 }
2219 runtime_stack.setVariable(l, JRT.dec(o), is_global);
2220 return o;
2221 }
2222
2223
2224 @Override
2225 public final Object getRS() {
2226 assert rs_offset != NULL_OFFSET;
2227 Object rs_obj = runtime_stack.getVariable(rs_offset, true);
2228 return rs_obj;
2229 }
2230
2231
2232 @Override
2233 public final Object getOFS() {
2234 assert ofs_offset != NULL_OFFSET;
2235 Object ofs_obj = runtime_stack.getVariable(ofs_offset, true);
2236 return ofs_obj;
2237 }
2238
2239 public final Object getORS() {
2240 return runtime_stack.getVariable(ors_offset, true);
2241 }
2242
2243
2244 @Override
2245 public final Object getSUBSEP() {
2246 assert subsep_offset != NULL_OFFSET;
2247 Object subsep_obj = runtime_stack.getVariable(subsep_offset, true);
2248 return subsep_obj;
2249 }
2250
2251
2252
2253
2254
2255
2256
2257
2258 @SuppressWarnings("unused")
2259 private void setFilelistVariable(String name_value) {
2260 int eq_idx = name_value.indexOf('=');
2261
2262 assert eq_idx >= 0;
2263 if (eq_idx == 0) {
2264 throw new IllegalArgumentException("Must have a non-blank variable name in a name=value variable assignment argument.");
2265 }
2266 String name = name_value.substring(0, eq_idx);
2267 String value = name_value.substring(eq_idx + 1);
2268 Object obj;
2269 try {
2270 obj = Integer.parseInt(value);
2271 } catch (NumberFormatException nfe) {
2272 try {
2273 obj = Double.parseDouble(value);
2274 } catch (NumberFormatException nfe2) {
2275 obj = value;
2276 }
2277 }
2278
2279
2280 if (function_names.contains(name)) {
2281 throw new IllegalArgumentException("Cannot assign a scalar to a function name (" + name + ").");
2282 }
2283
2284 Integer offset_obj = global_variable_offsets.get(name);
2285 Boolean array_obj = global_variable_arrays.get(name);
2286
2287 if (offset_obj != null) {
2288 assert array_obj != null;
2289 if (array_obj.booleanValue()) {
2290 throw new IllegalArgumentException("Cannot assign a scalar to a non-scalar variable (" + name + ").");
2291 } else {
2292 runtime_stack.setFilelistVariable(offset_obj.intValue(), obj);
2293 }
2294 }
2295
2296 }
2297
2298
2299 @Override
2300 public final void assignVariable(String name, Object obj) {
2301
2302 if (function_names.contains(name)) {
2303 throw new IllegalArgumentException("Cannot assign a scalar to a function name (" + name + ").");
2304 }
2305
2306 Integer offset_obj = global_variable_offsets.get(name);
2307 Boolean array_obj = global_variable_arrays.get(name);
2308
2309 if (offset_obj != null) {
2310 assert array_obj != null;
2311 if (array_obj.booleanValue()) {
2312 throw new IllegalArgumentException("Cannot assign a scalar to a non-scalar variable (" + name + ").");
2313 } else {
2314 runtime_stack.setFilelistVariable(offset_obj.intValue(), obj);
2315 }
2316 }
2317
2318 }
2319
2320 private void swapOnStack() {
2321 Object o1 = pop();
2322 Object o2 = pop();
2323 push(o1);
2324 push(o2);
2325 }
2326
2327 private void avmConsumeInputForGetline() throws IOException {
2328 if (avmConsumeInput(true)) {
2329 push(1);
2330 } else {
2331 push("");
2332 push(0);
2333 }
2334 swapOnStack();
2335 }
2336
2337 private void avmConsumeFileInputForGetline(String filename) throws IOException {
2338 if (avmConsumeFileInput(filename)) {
2339 push(1);
2340 } else {
2341 push(0);
2342 }
2343 swapOnStack();
2344 }
2345
2346 private void avmConsumeCommandInputForGetline(String cmd) throws IOException {
2347 if (avmConsumeCommandInput(cmd)) {
2348 push(1);
2349 } else {
2350 push(0);
2351 }
2352 swapOnStack();
2353 }
2354
2355 private boolean avmConsumeFileInput(String filename)
2356 throws IOException
2357 {
2358 boolean retval = jrt.jrtConsumeFileInput(filename);
2359 if (retval) {
2360 push(jrt.getInputLine());
2361 } else {
2362 push("");
2363 }
2364 return retval;
2365 }
2366
2367 private boolean avmConsumeCommandInput(String cmd)
2368 throws IOException
2369 {
2370 boolean retval = jrt.jrtConsumeCommandInput(cmd);
2371 if (retval) {
2372 push(jrt.getInputLine());
2373 } else {
2374 push("");
2375 }
2376 return retval;
2377 }
2378
2379 private boolean avmConsumeInput(boolean for_getline)
2380 throws IOException
2381 {
2382 boolean retval = jrt.jrtConsumeInput(settings.getInput(), for_getline, locale);
2383 if (retval && for_getline) {
2384 push(jrt.getInputLine());
2385 }
2386 return retval;
2387 }
2388
2389
2390 @Override
2391 public Object getFS() {
2392 assert fs_offset != NULL_OFFSET;
2393 Object fs_string = runtime_stack.getVariable(fs_offset, true);
2394 return fs_string;
2395 }
2396
2397
2398 @Override
2399 public Object getCONVFMT() {
2400 assert convfmt_offset != NULL_OFFSET : "convfmt_offset not defined";
2401 Object convfmt_string = runtime_stack.getVariable(convfmt_offset, true);
2402 return convfmt_string;
2403 }
2404
2405
2406 @Override
2407 public void resetFNR() {
2408 runtime_stack.setVariable(fnr_offset, ZERO, true);
2409 }
2410
2411
2412 @Override
2413 public void incFNR() {
2414 inc(fnr_offset, true);
2415 }
2416
2417
2418 @Override
2419 public void incNR() {
2420 inc(nr_offset, true);
2421 }
2422
2423
2424 @Override
2425 public void setNF(Integer I) {
2426 runtime_stack.setVariable(nf_offset, I, true);
2427 }
2428
2429
2430 @Override
2431 public void setFILENAME(String filename) {
2432 runtime_stack.setVariable(filename_offset, filename, true);
2433 }
2434
2435
2436 @Override
2437 public Object getARGV() {
2438 return runtime_stack.getVariable(argv_offset, true);
2439 }
2440
2441
2442 @Override
2443 public Object getARGC() {
2444 return runtime_stack.getVariable(argc_offset, true);
2445 }
2446
2447 private String getOFMT() {
2448 assert ofmt_offset != NULL_OFFSET;
2449 String ofmt_string = runtime_stack.getVariable(ofmt_offset, true).toString();
2450 return ofmt_string;
2451 }
2452
2453 private static final UninitializedObject BLANK = new UninitializedObject();
2454
2455
2456
2457
2458 public static final int NULL_OFFSET = -1;
2459
2460 private static class RuntimeStack {
2461
2462 private Object[] globals = null;
2463 private Object[] locals = null;
2464 private MyStack<Object[]> locals_stack = new ArrayStackImpl<Object[]>();
2465 private MyStack<Integer> return_indexes = new LinkedListStackImpl<Integer>();
2466
2467 @SuppressWarnings("unused")
2468 public void dump() {
2469 LOG.info("globals = " + Arrays.toString(globals));
2470 LOG.info("locals = " + Arrays.toString(locals));
2471 LOG.info("locals_stack = " + locals_stack);
2472 LOG.info("return_indexes = " + return_indexes);
2473 }
2474
2475 Object[] getNumGlobals() {
2476 return globals;
2477 }
2478
2479
2480
2481
2482 void setNumGlobals(long l) {
2483 assert l >= 0;
2484 assert globals == null;
2485 globals = new Object[(int) l];
2486 for (int i = 0 ; i < l ; i++) {
2487 globals[i] = null;
2488 }
2489
2490
2491 }
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507 Object getVariable(long offset, boolean is_global) {
2508 assert globals != null;
2509 assert offset != NULL_OFFSET;
2510 if (is_global) {
2511 return globals[(int) offset];
2512 } else {
2513 return locals[(int) offset];
2514 }
2515 }
2516
2517 Object setVariable(long offset, Object val, boolean is_global) {
2518 assert globals != null;
2519 assert offset != NULL_OFFSET;
2520 if (is_global) {
2521 return globals[(int) offset] = val;
2522 } else {
2523 return locals[(int) offset] = val;
2524 }
2525 }
2526
2527
2528 void removeVariable(long offset, boolean is_global) {
2529 assert globals != null;
2530 assert offset != NULL_OFFSET;
2531 if (is_global) {
2532 assert globals[(int) offset] == null || globals[(int) offset] instanceof AssocArray;
2533 globals[(int) offset] = null;
2534 } else {
2535 assert locals[(int) offset] == null || locals[(int) offset] instanceof AssocArray;
2536 locals[(int) offset] = null;
2537 }
2538 }
2539
2540 void setFilelistVariable(int offset, Object value) {
2541 assert globals != null;
2542 assert offset != NULL_OFFSET;
2543 globals[offset] = value;
2544 }
2545
2546 void pushFrame(long num_formal_params, int position_idx) {
2547 locals_stack.push(locals);
2548 locals = new Object[(int) num_formal_params];
2549 return_indexes.push(position_idx);
2550 }
2551
2552
2553 int popFrame() {
2554 locals = locals_stack.pop();
2555 return return_indexes.pop();
2556 }
2557
2558 void popAllFrames() {
2559 int sz = locals_stack.size();
2560 while (--sz >= 0) {
2561 locals = locals_stack.pop();
2562 return_indexes.pop();
2563 }
2564 }
2565 private Object return_value;
2566
2567 void setReturnValue(Object obj) {
2568 assert return_value == null;
2569 return_value = obj;
2570 }
2571
2572 Object getReturnValue() {
2573 Object retval;
2574 if (return_value == null) {
2575 retval = BLANK;
2576 } else {
2577 retval = return_value;
2578 }
2579 return_value = null;
2580 return retval;
2581 }
2582 }
2583 }