9216 awk: this statement may fall through
[unleashed.git] / usr / src / cmd / awk_xpg4 / awk3.c
blobca72a82ab03b8b938d2749e1bdfa4611b6f15115
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * awk -- executor
24 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
27 * Copyright 1985, 1994 by Mortice Kern Systems Inc. All rights reserved.
29 * Based on MKS awk(1) ported to be /usr/xpg4/bin/awk with POSIX/XCU4 changes
32 #include "awk.h"
33 #include "y.tab.h"
35 static int dohash(wchar_t *name);
36 static NODE *arithmetic(NODE *np);
37 static NODE *comparison(NODE *np);
38 static int type_of(NODE *np);
39 static NODE *lfield(INT fieldno, NODE *value);
40 static NODE *rfield(INT fieldno);
41 static NODE *userfunc(NODE *np);
42 static wchar_t *lltoa(long long l);
43 static NODE *exprconcat(NODE *np, int len);
44 static int s_if(NODE *np);
45 static int s_while(NODE *np);
46 static int s_for(NODE *np);
47 static int s_forin(NODE *np);
48 static void setrefield(NODE *value);
49 static void freetemps(void);
50 static int action(NODE *np);
51 static wchar_t *makeindex(NODE *np, wchar_t *array, int tag);
52 static int exprtest(NODE *np);
54 #define regmatch(rp, s) REGWEXEC(rp, s, 0, (REGWMATCH_T*)NULL, 0)
57 * This code allows for integers to be stored in longs (type INT) and
58 * only promoted to double precision floating point numbers (type REAL)
59 * when overflow occurs during +, -, or * operations. This is very
60 * non-portable if you desire such a speed optimisation. You may wish
61 * to put something here for your system. This "something" would likely
62 * include either an assembler "jump on overflow" instruction or a
63 * method to get traps on overflows from the hardware.
65 * This portable method works for ones and twos complement integer
66 * representations (which is, realistically) almost all machines.
68 #if __TURBOC__
69 #define addoverflow() asm jo overflow
70 #define suboverflow() asm jo overflow
71 #else
73 * These are portable to two's complement integer machines
75 #define addoverflow() if ((i1^i2) >= 0 && (iresult^i1) < 0) goto overflow
76 #define suboverflow() if ((i1^i2) < 0 && (iresult^i2) >= 0) goto overflow
77 #endif
78 #define muloverflow() if (((short)i1 != i1 || (short)i2 != i2) && \
79 ((i2 != 0 && iresult/i2 != i1) || \
80 (i1 == LONG_MIN && i2 == -1))) goto overflow
82 static char notarray[] = "scalar \"%s\" cannot be used as array";
83 static char badarray[] = "array \"%s\" cannot be used as a scalar";
84 static char varnotfunc[] = "variable \"%s\" cannot be used as a function";
85 static char tmfld[] = "Too many fields (LIMIT: %d)";
86 static char toolong[] = "Record too long (LIMIT: %d bytes)";
87 static char divzero[] = "division (/ or %%) by zero";
88 static char toodeep[] = "too deeply nested for in loop (LIMIT: %d)";
90 static wchar_t numbuf[NUMSIZE]; /* Used to convert INTs to strings */
91 static wchar_t *fields[NFIELD]; /* Cache of pointers into fieldbuf */
92 static wchar_t *fieldbuf; /* '\0' separated copy of linebuf */
93 static NODE nodes[NSNODE]; /* Cache of quick access nodes */
94 static NODE *fnodep = &nodes[0];
95 #define NINDEXBUF 50
96 static wchar_t indexbuf[NINDEXBUF]; /* Used for simple array indices */
97 static int concflag; /* In CONCAT operation (no frees) */
98 static NODE *retval; /* Last return value of a function */
101 * The following stack is used to store the next pointers for all nested
102 * for-in loops. This needs to be global so that delete can check to see
103 * if it is deleting the next node to be used by a loop.
105 #define NFORINLOOP 10
106 static NODE* forindex[NFORINLOOP];
107 static NODE** next_forin = forindex;
110 * Assign a string directly to a NODE without creating an intermediate
111 * NODE. This can handle either FALLOC, FSTATIC, FNOALLOC or FSENSE for
112 * "flags" argument. Also the NODE "np" must be reduced to an lvalue
113 * (PARM nodes are not acceptable).
115 void
116 strassign(NODE *np, STRING string, int flags, size_t length)
118 if (np->n_type == FUNC)
119 awkerr(gettext("attempt to redefine builtin function"));
120 else if (np->n_type == GETLINE || np->n_type == KEYWORD)
121 awkerr(gettext("inadmissible use of reserved keyword"));
122 if (np->n_flags & FSPECIAL) {
123 (void) nassign(np, stringnode(string, flags, length));
124 return;
126 if (isastring(np->n_flags))
127 free((wchar_t *)np->n_string);
128 np->n_strlen = length++;
129 if (flags & FALLOC) {
130 length *= sizeof (wchar_t);
131 np->n_string = (STRING) emalloc(length);
132 (void) memcpy((void *)np->n_string, string, length);
133 } else {
134 np->n_string = string;
135 if (flags & FNOALLOC) {
136 flags &= ~FNOALLOC;
137 flags |= FALLOC;
140 np->n_flags &= FSAVE;
141 if (flags & FSENSE) {
142 flags &= ~FSENSE;
143 flags |= type_of(np);
144 } else
145 flags |= FSTRING;
146 np->n_flags |= flags;
150 * Assign to a variable node.
151 * LHS must be a VAR type and RHS must be reduced by now.
152 * To speed certain operations up, check for
153 * certain things here and do special assignments.
155 NODE *
156 nassign(NODE *np, NODE *value)
158 register wchar_t *cp;
159 register int len;
161 /* short circuit assignment of a node to itself */
162 if (np == value)
163 return (np);
164 if (np->n_flags & FSPECIAL) {
165 if (np == varRS || np == varFS) {
166 if (isastring(np->n_flags))
167 free((void *)np->n_string);
168 len = sizeof (wchar_t) * ((np->n_strlen =
169 wcslen(cp = exprstring(value)))+1);
170 np->n_string = emalloc(len);
171 (void) memcpy((wchar_t *)np->n_string, cp, len);
172 np->n_flags = FALLOC|FSTRING|FSPECIAL;
173 if (np == varRS) {
174 if (np->n_string[0] == '\n')
175 awkrecord = defrecord;
176 else if (np->n_string[0] == '\0')
177 awkrecord = multirecord;
178 else
179 awkrecord = charrecord;
180 } else if (np == varFS) {
181 if (resep != (REGEXP)NULL) {
182 REGWFREE(resep);
183 resep = (REGEXP)NULL;
185 if (wcslen((wchar_t *)np->n_string) > 1)
186 setrefield(np);
187 else if (np->n_string[0] == ' ')
188 awkfield = whitefield;
189 else
190 awkfield = blackfield;
192 return (np);
195 if (isastring(np->n_flags))
196 free((wchar_t *)np->n_string);
197 if (isstring(value->n_flags)) {
198 np->n_strlen = value->n_strlen;
199 if (value->n_flags&FALLOC || value->n_string != _null) {
200 len = (np->n_strlen+1) * sizeof (wchar_t);
201 np->n_string = emalloc(len);
202 (void) memcpy(np->n_string, value->n_string, len);
203 np->n_flags &= FSAVE;
204 np->n_flags |= value->n_flags & ~FSAVE;
205 np->n_flags |= FALLOC;
206 return (np);
207 } else
208 np->n_string = value->n_string;
209 } else if (value->n_flags & FINT)
210 np->n_int = value->n_int;
211 else
212 np->n_real = value->n_real;
213 np->n_flags &= FSAVE;
214 np->n_flags |= value->n_flags & ~FSAVE;
215 return (np);
219 * Set regular expression FS value.
221 static void
222 setrefield(NODE *np)
224 static REGEXP re;
225 int n;
227 if ((n = REGWCOMP(&re, np->n_string)) != REG_OK) {
228 REGWERROR(n, &re, (char *)linebuf, sizeof (linebuf));
229 awkerr(gettext("syntax error \"%s\" in /%s/\n"),
230 (char *)linebuf, np->n_string);
232 resep = re;
233 awkfield = refield;
237 * Assign to an l-value node.
239 NODE *
240 assign(NODE *left, NODE *right)
242 if (isleaf(right->n_flags)) {
243 if (right->n_type == PARM)
244 right = right->n_next;
245 } else
246 right = exprreduce(right);
247 top:
248 switch (left->n_type) {
249 case INDEX:
250 left = exprreduce(left);
251 /* FALLTHROUGH */
252 case VAR:
253 return (nassign(left, right));
255 case PARM:
257 * If it's a parameter then link to the actual value node and
258 * do the checks again.
260 left = left->n_next;
261 goto top;
263 case FIELD:
264 return (lfield(exprint(left->n_left), right));
266 case CALLUFUNC:
267 case UFUNC:
268 awkerr(gettext("cannot assign to function \"%s\""),
269 left->n_name);
271 default:
272 awkerr(gettext("lvalue required in assignment"));
274 /* NOTREACHED */
275 return (0);
279 * Compiled tree non-terminal node.
281 NODE *
282 node(int type, NODE *left, NODE *right)
284 register NODE *np;
286 np = emptynode(type, 0);
287 np->n_left = left;
288 np->n_right = right;
289 np->n_lineno = lineno;
290 return (np);
294 * Create an integer node.
296 NODE *
297 intnode(INT i)
299 register NODE *np;
301 np = emptynode(CONSTANT, 0);
302 np->n_flags = FINT|FVINT;
303 np->n_int = i;
304 return (np);
308 * Create a real number node.
310 NODE *
311 realnode(REAL real)
313 register NODE *np;
315 np = emptynode(CONSTANT, 0);
316 np->n_flags = FREAL|FVREAL;
317 np->n_real = real;
318 return (np);
322 * Make a node for a string.
324 NODE *
325 stringnode(STRING s, int how, size_t length)
327 register NODE *np;
329 np = emptynode(CONSTANT, 0);
330 np->n_strlen = length;
331 if (how & FALLOC) {
332 np->n_string = emalloc(length = (length+1) * sizeof (wchar_t));
333 (void) memcpy(np->n_string, s, length);
334 } else {
335 np->n_string = s;
336 if (how & FNOALLOC) {
337 how &= ~FNOALLOC;
338 how |= FALLOC;
341 if (how & FSENSE) {
342 np->n_flags = type_of(np);
343 how &= ~FSENSE;
344 } else
345 np->n_flags = FSTRING;
346 np->n_flags |= how;
347 return (np);
351 * Save a copy of a string.
353 STRING
354 strsave(wchar_t *old)
356 STRING new;
357 register size_t len;
359 new = (STRING)emalloc(len = (wcslen(old)+1) * sizeof (wchar_t));
360 (void) memcpy(new, old, len);
361 return (new);
365 * Allocate an empty node of given type.
366 * String space for the node is given by `length'.
368 NODE *
369 emptynode(int type, size_t length)
371 register NODE *np;
373 if (length == 0 && running && fnodep < &nodes[NSNODE]) {
374 np = fnodep++;
375 } else {
376 np = (NODE *)emalloc(sizeof (NODE) +
377 (length * sizeof (wchar_t)));
378 if (running && type != VAR && type != ARRAY) {
379 np->n_next = freelist;
380 freelist = np;
383 np->n_flags = FNONTOK;
384 np->n_type = type;
385 np->n_alink = NNULL;
387 return (np);
391 * Free a node.
393 void
394 freenode(NODE *np)
396 if (isastring(np->n_flags))
397 free((wchar_t *)np->n_string);
398 else if (np->n_type == RE) {
399 REGWFREE(np->n_regexp);
401 free((wchar_t *)np);
405 * Install a keyword of given `type'.
407 void
408 kinstall(LOCCHARP name, int type)
410 register NODE *np;
411 register size_t l;
413 l = wcslen(name);
414 np = emptynode(KEYWORD, l);
415 np->n_keywtype = type;
416 (void) memcpy(np->n_name, name, (l+1) * sizeof (wchar_t));
417 addsymtab(np);
421 * Install built-in function.
423 NODE *
424 finstall(LOCCHARP name, FUNCTION func, int type)
426 register NODE *np;
427 register size_t l;
429 l = wcslen(name);
430 np = emptynode(type, l);
431 np->n_function = func;
432 (void) memcpy(np->n_name, name, (l+1) * sizeof (wchar_t));
433 addsymtab(np);
434 return (np);
438 * Lookup an identifier.
439 * nocreate contains the following flag values:
440 * 1 if no creation of a new NODE,
441 * 0 if ok to create new NODE
443 NODE *
444 vlookup(wchar_t *name, int nocreate)
446 register ushort_t hash;
447 register NODE *np;
449 np = symtab[hashbuck(hash = dohash((wchar_t *)name))];
450 while (np != NNULL) {
451 if (np->n_hash == hash && wcscmp(name, np->n_name) == 0)
452 return (np);
453 np = np->n_next;
455 if (nocreate) {
456 np = NNULL;
457 } else {
458 np = emptynode(VAR, hash = wcslen(name));
459 np->n_flags = FSTRING|FVINT;
460 np->n_strlen = 0;
461 np->n_string = _null;
462 (void) memcpy(np->n_name, name,
463 (hash+1) * sizeof (wchar_t));
464 addsymtab(np);
466 return (np);
470 * Add a symbol to the table.
472 void
473 addsymtab(NODE *np)
475 register NODE **spp;
477 np->n_hash = dohash((wchar_t *)np->n_name);
478 spp = &symtab[hashbuck(np->n_hash)];
479 np->n_next = *spp;
480 *spp = np;
484 * Delete the given node from the symbol table.
485 * If fflag is non-zero, also free the node space.
486 * This routine must also check the stack of forin loop pointers. If
487 * we are deleting the next item to be used, then the pointer must be
488 * advanced.
490 void
491 delsymtab(NODE *np, int fflag)
493 register NODE *rnp;
494 register NODE *prevp;
495 register NODE **sptr;
496 register ushort_t h;
502 h = hashbuck(np->n_hash);
503 prevp = NNULL;
504 for (rnp = symtab[h]; rnp != NNULL; rnp = rnp->n_next) {
505 if (rnp == np) {
507 * check all of the for-in loop pointers
508 * to see if any need to be advanced because
509 * this element is being deleted.
511 if (next_forin != forindex) {
512 sptr = next_forin;
513 do {
514 if (*--sptr == rnp) {
515 *sptr = rnp->n_next;
516 break;
518 } while (sptr != forindex);
520 if (prevp == NNULL)
521 symtab[h] = rnp->n_next; else
522 prevp->n_next = rnp->n_next;
523 if (fflag)
524 freenode(rnp);
525 break;
527 prevp = rnp;
532 * Hashing function.
534 static int
535 dohash(wchar_t *name)
537 register int hash = 0;
539 while (*name != '\0')
540 hash += *name++;
541 return (hash);
545 * Top level executor for an awk programme.
546 * This will be passed: pattern, action or a list of these.
547 * The former function to evaluate a pattern has been
548 * subsumed into this function for speed.
549 * Patterns are:
550 * BEGIN,
551 * END,
552 * other expressions (including regular expressions)
554 void
555 execute(NODE *wp)
557 register NODE *np;
558 register int type;
559 register NODE *tnp;
561 curnode = wp;
562 if (phase != 0) {
563 linebuf[0] = '\0';
564 lbuflen = 0;
566 while (wp != NNULL) {
567 if (wp->n_type == COMMA) {
568 np = wp->n_left;
569 wp = wp->n_right;
570 } else {
571 np = wp;
572 wp = NNULL;
574 if (np->n_type != PACT)
575 awkerr(interr, "PACT");
577 * Save the parent node and evaluate the pattern.
578 * If it evaluates to false (0) just continue
579 * to the next pattern/action (PACT) pair.
581 tnp = np;
582 np = np->n_left;
583 if (np == NNULL) {
584 if (phase != 0)
585 continue;
586 } else if (phase != 0) {
587 if (np->n_type != phase)
588 continue;
589 } else if ((type = np->n_type) == BEGIN || type == END) {
590 continue;
591 } else if (type == COMMA) {
593 * The grammar only allows expressions
594 * to be separated by the ',' operator
595 * for range patterns.
597 if (np->n_flags & FMATCH) {
598 if (exprint(np->n_right) != 0)
599 np->n_flags &= ~FMATCH;
600 } else if (exprint(np->n_left) != 0) {
601 if (exprint(np->n_right) == 0)
602 np->n_flags |= FMATCH;
603 } else
604 continue;
605 } else if (exprint(np) == 0)
606 continue;
607 np = tnp;
608 if (action(np->n_right)) {
609 loopexit = 0;
610 break;
613 if (freelist != NNULL)
614 freetemps();
618 * Free all temporary nodes.
620 static void
621 freetemps()
623 register NODE *np, *nnp;
625 if (concflag)
626 return;
627 for (np = &nodes[0]; np < fnodep; np++) {
628 if (isastring(np->n_flags)) {
629 free((wchar_t *)np->n_string);
630 } else if (np->n_type == RE) {
631 REGWFREE(np->n_regexp);
634 fnodep = &nodes[0];
635 for (np = freelist; np != NNULL; np = nnp) {
636 nnp = np->n_next;
637 freenode(np);
639 freelist = NNULL;
643 * Do the given action.
644 * Actions are statements or expressions.
646 static int
647 action(NODE *wp)
649 register NODE *np;
650 register int act = 0;
651 register NODE *l;
653 while (wp != NNULL) {
654 if (wp->n_type == COMMA) {
655 np = wp->n_left;
656 wp = wp->n_right;
657 } else {
658 np = wp;
659 wp = NNULL;
661 if (freelist != NNULL)
662 freetemps();
663 curnode = np;
665 * Don't change order of these cases without
666 * changing order in awk.y declarations.
667 * The order is optimised.
669 switch (np->n_type) {
670 case ASG:
671 (void) assign(np->n_left, np->n_right);
672 continue;
674 case PRINT:
675 s_print(np);
676 continue;
678 case PRINTF:
679 s_prf(np);
680 continue;
682 case EXIT:
683 if (np->n_left != NNULL)
684 act = (int)exprint(np->n_left); else
685 act = 0;
686 doend(act);
687 /* NOTREACHED */
689 case RETURN:
690 if (slevel == 0)
691 awkerr(gettext("return outside of a function"));
692 np = np->n_left != NNULL
693 ? exprreduce(np->n_left)
694 : const0;
695 retval = emptynode(CONSTANT, 0);
696 retval->n_flags = FINT;
697 (void) nassign(retval, np);
698 return (RETURN);
700 case NEXT:
701 loopexit = NEXT;
702 /* FALLTHROUGH */
703 case BREAK:
704 case CONTINUE:
705 return (np->n_type);
707 case DELETE:
708 if ((l = np->n_left)->n_type == PARM) {
709 l = l->n_next;
710 if (!(l->n_flags & FLARRAY))
711 l = l->n_alink;
713 switch (l->n_type) {
714 case ARRAY:
715 delarray(l);
716 break;
718 case INDEX:
719 if ((np = l->n_left)->n_type == PARM) {
720 np = np->n_next;
721 if (!(np->n_flags & FLARRAY))
722 np = np->n_alink;
725 * get pointer to the node for this array
726 * element using the hash key.
728 l = exprreduce(l);
730 * now search linearly from the beginning of
731 * the list to find the element before the
732 * one being deleted. This must be done
733 * because arrays are singley-linked.
735 while (np != NNULL) {
736 if (np->n_alink == l) {
737 np->n_alink = l->n_alink;
738 break;
740 np = np->n_alink;
742 delsymtab(l, 1);
743 break;
745 case VAR:
746 if (isstring(l->n_flags) &&
747 l->n_string == _null)
748 break;
749 /* FALLTHROUGH */
750 default:
751 awkerr(gettext(
752 "may delete only array element or array"));
753 break;
755 continue;
757 case WHILE:
758 case DO:
759 if ((act = s_while(np)) != 0)
760 break;
761 continue;
763 case FOR:
764 if ((act = s_for(np)) != 0)
765 break;
766 continue;
768 case FORIN:
769 if ((act = s_forin(np)) != 0)
770 break;
771 continue;
773 case IF:
774 if ((act = s_if(np)) != 0)
775 break;
776 continue;
778 default:
779 (void) exprreduce(np);
780 if (loopexit != 0) {
781 act = loopexit;
782 break;
784 continue;
786 return (act);
788 return (0);
792 * Delete an entire array
794 void
795 delarray(NODE *np)
797 register NODE *nnp;
799 nnp = np->n_alink;
800 np->n_alink = NNULL;
801 while (nnp != NNULL) {
802 np = nnp->n_alink;
803 delsymtab(nnp, 1);
804 nnp = np;
809 * Return the INT value of an expression.
812 exprint(NODE *np)
814 if (isleaf(np->n_flags)) {
815 if (np->n_type == PARM)
816 np = np->n_next;
817 goto leaf;
819 np = exprreduce(np);
820 switch (np->n_type) {
821 case CONSTANT:
822 case VAR:
823 leaf:
824 if (np->n_flags & FINT)
825 return (np->n_int);
826 if (np->n_flags & FREAL)
827 return ((INT)np->n_real);
828 return ((INT)wcstoll(np->n_string, NULL, 10));
830 default:
831 awkerr(interr, "exprint");
833 /* NOTREACHED */
834 return (0);
838 * Return a real number from an expression tree.
840 REAL
841 exprreal(NODE *np)
843 if (loopexit)
844 return ((REAL)loopexit);
845 if (isleaf(np->n_flags)) {
846 if (np->n_type == PARM)
847 np = np->n_next;
848 goto leaf;
850 np = exprreduce(np);
851 switch (np->n_type) {
852 case CONSTANT:
853 case VAR:
854 leaf:
855 if (np->n_flags & FREAL)
856 return (np->n_real);
857 if (np->n_flags & FINT)
858 return ((REAL)np->n_int);
859 return ((REAL)wcstod((wchar_t *)np->n_string, (wchar_t **)0));
861 default:
862 awkerr(interr, "exprreal");
864 /* NOTREACHED */
865 return ((REAL)0);
869 * Return a string from an expression tree.
871 STRING
872 exprstring(NODE *np)
874 if (isleaf(np->n_flags)) {
875 if (np->n_type == PARM)
876 np = np->n_next;
877 goto leaf;
879 np = exprreduce(np);
880 switch (np->n_type) {
881 case CONSTANT:
882 case VAR:
883 leaf:
884 if (isstring(np->n_flags))
885 return (np->n_string);
886 if (np->n_flags & FINT)
887 return (STRING)lltoa((long long)np->n_int);
889 char *tmp;
890 (void) wsprintf(numbuf,
891 (const char *) (tmp = wcstombsdup(exprstring(varCONVFMT))),
892 (double)np->n_real);
893 if (tmp != NULL)
894 free(tmp);
896 return ((STRING)numbuf);
898 default:
899 awkerr(interr, "exprstring");
901 /* NOTREACHED */
902 return (0);
906 * Convert number to string.
908 static wchar_t *
909 lltoa(long long l)
911 register wchar_t *p = &numbuf[NUMSIZE];
912 register int s;
913 register int neg;
914 static wchar_t zero[] = M_MB_L("0");
916 if (l == 0)
917 return (zero);
918 *--p = '\0';
919 if (l < 0)
920 neg = 1, l = -l; else
921 neg = 0;
922 if ((s = (short)l) == l) {
923 while (s != 0) {
924 *--p = s%10 + '0';
925 s /= 10;
927 } else {
928 while (l != 0) {
929 *--p = l%10 + '0';
930 l /= 10;
933 if (neg)
934 *--p = '-';
935 return (wcscpy(numbuf, p));
939 * Return pointer to node with concatenation of operands of CONCAT node.
940 * In the interest of speed, a left recursive tree of CONCAT nodes
941 * is handled with a single malloc. The accumulated lengths of the
942 * right operands are passed down recursive invocations of this
943 * routine, which allocates a large enough string when the left
944 * operand is not a CONCAT node.
946 static NODE *
947 exprconcat(NODE *np, int len)
949 /* we KNOW (np->n_type==CONCAT) */
950 register NODE *lnp = np->n_left;
951 register NODE *rnp = np->n_right;
952 register STRING rsp;
953 int rlen;
954 size_t llen;
955 wchar_t *cp;
956 wchar_t rnumbuf[NUMSIZE];
958 if (isleaf(rnp->n_flags) && rnp->n_type == PARM)
959 rnp = rnp->n_next;
960 if (isstring(rnp->n_flags)) {
961 rsp = rnp->n_string;
962 rlen = rnp->n_strlen;
963 } else
964 rlen = wcslen((wchar_t *)(rsp = exprstring(rnp)));
965 if (rsp == numbuf) { /* static, so save a copy */
966 (void) memcpy(rnumbuf, (wchar_t *)rsp,
967 (rlen+1) * sizeof (wchar_t));
968 rsp = rnumbuf;
970 len += rlen;
971 if (lnp->n_type == CONCAT) {
972 lnp = exprconcat(lnp, len);
973 cp = lnp->n_string;
974 llen = lnp->n_strlen;
975 } else {
976 register STRING lsp;
978 if (isleaf(lnp->n_flags) && lnp->n_type == PARM)
979 lnp = lnp->n_next;
980 if (isstring(lnp->n_flags)) {
981 lsp = lnp->n_string;
982 llen = lnp->n_strlen;
983 } else
984 llen = wcslen((wchar_t *)(lsp = exprstring(lnp)));
985 cp = emalloc((llen+len+1) * sizeof (wchar_t));
986 (void) memcpy(cp, (wchar_t *)lsp, llen * sizeof (wchar_t));
987 lnp = stringnode(cp, FNOALLOC, llen);
989 (void) memcpy(cp+llen, (wchar_t *)rsp, (rlen+1) * sizeof (wchar_t));
990 lnp->n_strlen += rlen;
991 return (lnp);
995 * Reduce an expression to a terminal node.
997 NODE *
998 exprreduce(NODE *np)
1000 register wchar_t *cp;
1001 NODE *tnp;
1002 register int temp;
1003 register int t;
1004 register int tag;
1005 register wchar_t *fname;
1006 register wchar_t *aname;
1009 * a var or constant is a leaf-node (no further reduction required)
1010 * so return immediately.
1012 if ((t = np->n_type) == VAR || t == CONSTANT)
1013 return (np);
1015 * If it's a parameter then it is probably a leaf node but it
1016 * might be an array so we check.. If it is an array, then signal
1017 * an error as an array by itself cannot be used in this context.
1019 if (t == PARM)
1020 if ((np = np->n_next)->n_type == ARRAY)
1021 awkerr(badarray, np->n_name);
1022 else
1023 return (np);
1025 * All the rest are non-leaf nodes.
1027 curnode = np;
1028 switch (t) {
1029 case CALLUFUNC:
1030 return (userfunc(np));
1032 case FIELD:
1033 return (rfield(exprint(np->n_left)));
1035 case IN:
1036 case INDEX:
1037 tag = 0;
1038 temp = np->n_type;
1039 tnp = np->n_left;
1040 np = np->n_right;
1041 /* initially formal var name and array key name are the same */
1042 fname = aname = tnp->n_name;
1043 if (tnp->n_type == PARM) {
1044 tnp = tnp->n_next;
1045 tag = tnp->n_scope;
1046 if (!(tnp->n_flags & FLARRAY)) {
1047 tnp = tnp->n_alink;
1049 aname = tnp->n_name;
1051 if (tnp->n_type != ARRAY) {
1052 if (!isstring(tnp->n_flags) || tnp->n_string != _null)
1053 awkerr(notarray, fname);
1054 else {
1055 /* promotion to array */
1056 promote(tnp);
1057 if (tnp->n_alink != NNULL) {
1058 tag = tnp->n_scope;
1059 if (!(tnp->n_flags & FLARRAY))
1060 tnp = tnp->n_alink;
1061 aname = tnp->n_name;
1062 } else {
1063 tag = 0;
1064 if (tnp->n_flags & FLARRAY)
1065 tag = tnp->n_scope;
1069 if (tnp == varSYMTAB) {
1070 if (np == NNULL || np->n_type == COMMA)
1071 awkerr(gettext(
1072 "SYMTAB must have exactly one index"));
1073 np = vlook(exprstring(np));
1074 return (np);
1076 cp = makeindex(np, aname, tag);
1077 if (temp == INDEX) {
1078 np = vlook(cp);
1079 if (!(np->n_flags & FINARRAY)) {
1080 np->n_alink = tnp->n_alink;
1081 tnp->n_alink = np;
1082 np->n_flags |= FINARRAY;
1084 } else
1085 np = vlookup(cp, 1) == NNULL ? const0 : const1;
1086 if (cp != indexbuf)
1087 free(cp);
1088 return (np);
1090 case CONCAT:
1091 ++concflag;
1092 np = exprconcat(np, 0);
1093 --concflag;
1094 return (np);
1096 case NOT:
1097 return (intnode(exprtest(np->n_left) == 0 ? (INT)1 : (INT)0));
1099 case AND:
1100 return ((exprtest(np->n_left) != 0 &&
1101 exprtest(np->n_right) != 0) ? const1 : const0);
1103 case OR:
1104 return ((exprtest(np->n_left) != 0 ||
1105 exprtest(np->n_right) != 0) ? const1 : const0);
1107 case EXP:
1109 double f1, f2;
1112 * evaluate expressions in proper order before
1113 * calling pow().
1114 * Can't guarantee that compiler will do this
1115 * correctly for us if we put them inline.
1117 f1 = (double)exprreal(np->n_left);
1118 f2 = (double)exprreal(np->n_right);
1119 return (realnode((REAL)pow(f1, f2)));
1122 case QUEST:
1123 if (np->n_right->n_type != COLON)
1124 awkerr(interr, "?:");
1125 if (exprtest(np->n_left))
1126 np = np->n_right->n_left; else
1127 np = np->n_right->n_right;
1128 return (exprreduce(np));
1130 case EQ:
1131 case NE:
1132 case GE:
1133 case LE:
1134 case GT:
1135 case LT:
1136 return (comparison(np));
1138 case ADD:
1139 case SUB:
1140 case MUL:
1141 case DIV:
1142 case REM:
1143 return (arithmetic(np));
1145 case DEC:
1146 inc_oper->n_type = SUB;
1147 goto do_inc_op;
1148 case INC:
1149 inc_oper->n_type = ADD;
1150 do_inc_op:
1151 if ((np = np->n_left)->n_type == INDEX)
1152 np = exprreduce(np);
1153 if (np->n_flags & FREAL)
1154 tnp = realnode(np->n_real);
1155 else
1156 tnp = intnode(exprint(np));
1157 inc_oper->n_left = np;
1158 (void) assign(np, inc_oper);
1159 return (tnp);
1161 case PRE_DEC:
1162 inc_oper->n_type = SUB;
1163 goto do_pinc_op;
1164 case PRE_INC:
1165 inc_oper->n_type = ADD;
1166 do_pinc_op:
1167 if ((np = np->n_left)->n_type == INDEX)
1168 np = exprreduce(np);
1169 inc_oper->n_left = np;
1170 return (assign(np, inc_oper));
1172 case AADD:
1173 asn_oper->n_type = ADD;
1174 goto do_asn_op;
1175 case ASUB:
1176 asn_oper->n_type = SUB;
1177 goto do_asn_op;
1178 case AMUL:
1179 asn_oper->n_type = MUL;
1180 goto do_asn_op;
1181 case ADIV:
1182 asn_oper->n_type = DIV;
1183 goto do_asn_op;
1184 case AREM:
1185 asn_oper->n_type = REM;
1186 goto do_asn_op;
1187 case AEXP:
1188 asn_oper->n_type = EXP;
1189 do_asn_op:
1190 asn_oper->n_right = np->n_right;
1191 if ((np = np->n_left)->n_type == INDEX)
1192 np = exprreduce(np);
1193 asn_oper->n_left = np;
1194 return (assign(np, asn_oper));
1197 case GETLINE:
1198 return (f_getline(np));
1200 case CALLFUNC:
1201 return ((*np->n_left->n_function)(np->n_right));
1203 case RE:
1204 if (regmatch(np->n_regexp, linebuf) == REG_OK)
1205 return (const1);
1206 return (const0);
1208 case TILDE:
1209 cp = exprstring(np->n_left);
1210 if (regmatch(getregexp(np->n_right), cp) == REG_OK)
1211 return (const1);
1212 return (const0);
1214 case NRE:
1215 cp = exprstring(np->n_left);
1216 if (regmatch(getregexp(np->n_right), cp) != REG_OK)
1217 return (const1);
1218 return (const0);
1220 case ASG:
1221 return (assign(np->n_left, np->n_right));
1223 case ARRAY:
1224 awkerr(badarray, np->n_name);
1226 case UFUNC:
1227 awkerr(varnotfunc, np->n_name);
1229 default:
1230 awkerr(gettext("panic: exprreduce(%d)"), t);
1231 /* NOTREACHED */
1233 return (0);
1237 * Do arithmetic operators.
1239 static NODE *
1240 arithmetic(NODE *np)
1242 register NODE *left, *right;
1243 int type;
1244 register INT i1, i2;
1245 register INT iresult;
1246 register REAL r1, r2;
1248 left = exprreduce(np->n_left);
1249 if (isreal(left->n_flags) ||
1250 (isstring(left->n_flags) && (type_of(left)&FVREAL))) {
1251 type = FREAL;
1252 r1 = exprreal(left);
1253 r2 = exprreal(np->n_right);
1254 } else {
1255 i1 = exprint(left);
1256 right = exprreduce(np->n_right);
1257 if (isreal(right->n_flags) ||
1258 (isstring(right->n_flags) && (type_of(right)&FVREAL))) {
1260 type = FREAL;
1261 r1 = i1;
1262 r2 = exprreal(right);
1263 } else {
1264 type = FINT;
1265 i2 = exprint(right);
1268 reswitch:
1269 switch (np->n_type) {
1270 case ADD:
1271 if (type == FINT) {
1272 iresult = i1 + i2;
1273 addoverflow();
1274 } else
1275 r1 += r2;
1276 break;
1279 * Strategically placed between ADD and SUB
1280 * so "jo" branches will reach on 80*86
1282 overflow:
1283 r1 = i1;
1284 r2 = i2;
1285 type = FREAL;
1286 goto reswitch;
1288 case SUB:
1289 if (type == FINT) {
1290 iresult = i1 - i2;
1291 suboverflow();
1292 } else
1293 r1 -= r2;
1294 break;
1296 case MUL:
1297 if (type == FINT) {
1298 iresult = i1 * i2;
1299 muloverflow();
1300 } else
1301 r1 *= r2;
1302 break;
1304 case DIV:
1305 if (type == FINT) {
1306 r1 = i1;
1307 r2 = i2;
1308 type = FREAL;
1310 if (r2 == 0.0)
1311 awkerr(divzero);
1312 r1 /= r2;
1313 break;
1315 case REM:
1316 if (type == FINT) {
1317 if (i2 == 0)
1318 awkerr(divzero);
1319 iresult = i1 % i2;
1320 } else {
1321 double fmod(double x, double y);
1323 errno = 0;
1324 r1 = fmod(r1, r2);
1325 if (errno == EDOM)
1326 awkerr(divzero);
1328 break;
1330 return (type == FINT ? intnode(iresult) : realnode(r1));
1334 * Do comparison operators.
1336 static NODE *
1337 comparison(NODE *np)
1339 register NODE *left, *right;
1340 register int cmp;
1341 int tl, tr;
1342 register REAL r1, r2;
1343 register INT i1, i2;
1345 left = np->n_left;
1346 if (isleaf(left->n_flags)) {
1347 if (left->n_type == PARM)
1348 left = left->n_next;
1349 } else
1350 left = exprreduce(left);
1351 tl = left->n_flags;
1352 right = np->n_right;
1353 if (isleaf(right->n_flags)) {
1354 if (right->n_type == PARM)
1355 right = right->n_next;
1356 } else {
1357 ++concflag;
1358 right = exprreduce(right);
1359 --concflag;
1361 tr = right->n_flags;
1363 * Posix mandates semantics for the comparison operators that
1364 * are incompatible with traditional AWK behaviour. If the following
1365 * define is true then awk will use the traditional behaviour.
1366 * if it's false, then AWK will use the POSIX-mandated behaviour.
1368 #define TRADITIONAL 0
1369 #if TRADITIONAL
1370 if (!isnumber(tl) || !isnumber(tr)) {
1371 cmp = wcscoll((wchar_t *)exprstring(left),
1372 (wchar_t *)exprstring(right));
1373 } else if (isreal(tl) || isreal(tr)) {
1374 r1 = exprreal(left);
1375 r2 = exprreal(right);
1376 if (r1 < r2)
1377 cmp = -1;
1378 else if (r1 > r2)
1379 cmp = 1;
1380 else
1381 cmp = 0;
1382 } else {
1383 i1 = exprint(left);
1384 i2 = exprint(right);
1385 if (i1 < i2)
1386 cmp = -1;
1387 else if (i1 > i2)
1388 cmp = 1;
1389 else
1390 cmp = 0;
1392 #else
1393 if (!isnumber(tl) && !isnumber(tr)) {
1394 do_strcmp:
1395 cmp = wcscoll((wchar_t *)exprstring(left),
1396 (wchar_t *)exprstring(right));
1397 } else {
1398 if (isstring(tl))
1399 tl = type_of(left);
1400 if (isstring(tr))
1401 tr = type_of(right);
1402 if (!isnumber(tl) || !isnumber(tr))
1403 goto do_strcmp;
1404 if (isreal(tl) || isreal(tr)) {
1405 r1 = exprreal(left);
1406 r2 = exprreal(right);
1407 if (r1 < r2)
1408 cmp = -1;
1409 else if (r1 > r2)
1410 cmp = 1;
1411 else
1412 cmp = 0;
1413 } else {
1414 i1 = exprint(left);
1415 i2 = exprint(right);
1416 if (i1 < i2)
1417 cmp = -1;
1418 else if (i1 > i2)
1419 cmp = 1;
1420 else
1421 cmp = 0;
1424 #endif
1425 switch (np->n_type) {
1426 case EQ:
1427 return (cmp == 0 ? const1 : const0);
1429 case NE:
1430 return (cmp != 0 ? const1 : const0);
1432 case GE:
1433 return (cmp >= 0 ? const1 : const0);
1435 case LE:
1436 return (cmp <= 0 ? const1 : const0);
1438 case GT:
1439 return (cmp > 0 ? const1 : const0);
1441 case LT:
1442 return (cmp < 0 ? const1 : const0);
1444 default:
1445 awkerr(interr, "comparison");
1447 /* NOTREACHED */
1448 return (0);
1452 * Return the type of a constant that is a string.
1453 * The node must be a FSTRING type and the return value
1454 * will possibly have FVINT or FVREAL or'ed in.
1456 static int
1457 type_of(NODE *np)
1459 wchar_t *cp;
1460 int somedigits = 0;
1461 int seene = 0;
1462 int seenradix = 0;
1463 int seensign = 0;
1464 int digitsaftere = 0;
1466 cp = (wchar_t *)np->n_string;
1467 if (*cp == '\0')
1468 return (FSTRING|FVINT);
1469 while (iswspace(*cp))
1470 cp++;
1471 if (*cp == '-' || *cp == '+')
1472 cp++;
1473 while (*cp != '\0') {
1474 switch (*cp) {
1475 case '0':
1476 case '1':
1477 case '2':
1478 case '3':
1479 case '4':
1480 case '5':
1481 case '6':
1482 case '7':
1483 case '8':
1484 case '9':
1485 if (seene)
1486 digitsaftere = 1;
1487 somedigits++;
1488 break;
1490 case 'E':
1491 case 'e':
1492 if (seene || !somedigits)
1493 return (FSTRING);
1494 seene = 1;
1495 break;
1497 case '+':
1498 case '-':
1499 if (seensign || !seene || digitsaftere)
1500 return (FSTRING);
1501 seensign = 1;
1502 break;
1504 default:
1505 if (*cp == radixpoint) {
1506 if (seenradix || seene || (!somedigits &&
1507 !iswdigit(*++cp)))
1508 return (FSTRING);
1509 } else
1510 return (FSTRING);
1511 seenradix = 1;
1513 cp++;
1515 if (somedigits == 0)
1516 return (FSTRING);
1517 if (somedigits >= MAXDIGINT || seenradix || seene) {
1518 if (seensign && !digitsaftere)
1519 return (FSTRING);
1520 else
1521 return (FSTRING|FVREAL);
1522 } else
1523 return (FSTRING|FVINT);
1527 * Return a field rvalue.
1529 static NODE *
1530 rfield(INT fieldno)
1532 register wchar_t *cp;
1534 if (fieldno == 0)
1535 return (stringnode(linebuf, FSTATIC|FSENSE, lbuflen));
1536 if (!splitdone)
1537 fieldsplit();
1538 if (fieldno > nfield || fieldno < 0)
1539 return (stringnode(_null, FSTATIC, 0));
1540 cp = fields[fieldno-1];
1541 return (stringnode(cp, FSTATIC|FSENSE, wcslen(cp)));
1545 * Split linebuf into fields. Done only once
1546 * per input record (maximum).
1548 void
1549 fieldsplit()
1551 register wchar_t *ip, *op;
1552 register int n;
1553 wchar_t *ep;
1555 if (fieldbuf == NULL)
1556 fieldbuf = emalloc(NLINE * sizeof (wchar_t));
1557 fcount = 0;
1558 ep = linebuf;
1559 op = fieldbuf;
1560 while ((ip = (*awkfield)(&ep)) != NULL) {
1561 fields[fcount++] = op;
1562 if (fcount > NFIELD)
1563 awkerr(tmfld, NFIELD);
1564 n = ep-ip;
1565 (void) memcpy(op, ip, n * sizeof (wchar_t));
1566 op += n;
1567 *op++ = '\0';
1569 if (varNF->n_flags & FINT)
1570 varNF->n_int = fcount;
1571 else {
1572 constant->n_int = fcount;
1573 (void) nassign(varNF, constant);
1575 nfield = fcount;
1576 splitdone++;
1580 * Assign to a field as an lvalue.
1581 * Return the unevaluated node as one doesn't always need it
1582 * evaluated in an assignment.
1584 static NODE *
1585 lfield(INT fieldno, NODE *np)
1587 register wchar_t *cp;
1588 register wchar_t *op;
1589 register wchar_t *sep;
1590 register int i;
1591 register wchar_t *newval;
1592 register int seplen;
1593 register int newlen;
1595 newlen = wcslen(newval = (wchar_t *)exprstring(np));
1596 if (fieldno == 0) {
1597 splitdone = 0;
1598 (void) memcpy(linebuf, newval, (newlen+1) * sizeof (wchar_t));
1599 lbuflen = newlen;
1600 fieldsplit();
1601 } else {
1602 seplen = wcslen(sep = (wchar_t *)exprstring(varOFS));
1603 if (!splitdone)
1604 fieldsplit();
1605 if (--fieldno < nfield &&
1606 (newlen <= wcslen(fields[fieldno]))) {
1607 (void) memcpy(fields[fieldno], newval,
1608 (newlen+1) * sizeof (wchar_t));
1609 } else {
1610 register wchar_t *buf;
1612 buf = fieldbuf;
1613 fieldbuf = emalloc(NLINE * sizeof (wchar_t));
1614 if (fieldno >= nfield) {
1615 if (fieldno >= NFIELD)
1616 awkerr(tmfld, NFIELD);
1617 while (nfield < fieldno)
1618 fields[nfield++] = _null;
1619 ++nfield;
1621 fields[fieldno] = newval;
1622 op = fieldbuf;
1623 for (i = 0; i < nfield; i++) {
1624 newlen = wcslen(cp = fields[i])+1;
1625 fields[i] = op;
1626 if (op+newlen >= fieldbuf+NLINE)
1627 awkerr(toolong, NLINE);
1628 (void) memcpy(op, cp,
1629 newlen * sizeof (wchar_t));
1630 op += newlen;
1632 free(buf);
1635 * Reconstruct $0
1637 op = linebuf;
1638 i = 0;
1639 while (i < nfield) {
1640 newlen = wcslen(cp = fields[i++]);
1641 (void) memcpy(op, cp, newlen * sizeof (wchar_t));
1642 op += newlen;
1643 if (i < nfield) {
1644 (void) memcpy(op, sep,
1645 seplen * sizeof (wchar_t));
1646 op += seplen;
1648 if (op >= &linebuf[NLINE])
1649 awkerr(toolong, NLINE);
1651 *op = '\0';
1652 lbuflen = op-linebuf;
1653 if (varNF->n_flags & FINT)
1654 varNF->n_int = nfield;
1655 else {
1656 constant->n_int = nfield;
1657 (void) nassign(varNF, constant);
1660 return (np);
1664 * Do a user function.
1665 * Each formal parameter must:
1666 * have the actual parameter assigned to it (call by value),
1667 * have a pointer to an array put into it (call by reference),
1668 * and be made undefined (extra formal parameters)
1670 static NODE *
1671 userfunc(NODE *np)
1673 register NODE *temp;
1674 NODE *fnp;
1676 if ((fnp = np->n_left) == NNULL)
1677 awkerr(gettext("impossible function call"));
1678 if (fnp->n_type != UFUNC)
1679 awkerr(varnotfunc, fnp->n_name);
1681 #ifndef M_STKCHK
1682 if (slevel >= NRECUR)
1683 awkerr(gettext("function \"%S\" nesting level > %u"),
1684 fnp->n_name, NRECUR);
1685 #else
1686 if (!M_STKCHK)
1687 awkerr(gettext("function \"%s\" nesting level too deep"),
1688 fnp->n_name);
1689 #endif
1691 fnp = fnp->n_ufunc;
1693 register NODE *formal;
1694 register NODE *actual;
1695 NODE *formlist, *actlist, *templist, *temptail;
1697 templist = temptail = NNULL;
1698 actlist = np->n_right;
1699 formlist = fnp->n_left;
1701 * pass through formal list, setting up a list
1702 * (on templist) containing temps for the values
1703 * of the actuals.
1704 * If the actual list runs out before the formal
1705 * list, assign 'constundef' as the value
1707 while ((formal = getlist(&formlist)) != NNULL) {
1708 register NODE *array;
1709 register int t;
1710 register size_t len;
1711 register int scope_tag;
1713 actual = getlist(&actlist);
1714 if (actual == NNULL) {
1715 actual = constundef;
1716 scope_tag = slevel+1;
1717 } else
1718 scope_tag = 0;
1719 array = actual;
1720 switch (actual->n_type) {
1721 case ARRAY:
1722 t = ARRAY;
1723 scope_tag = 0;
1724 break;
1726 case PARM:
1727 array = actual = actual->n_next;
1728 t = actual->n_type;
1729 scope_tag = actual->n_scope;
1730 if (!(actual->n_flags & FLARRAY))
1731 array = actual->n_alink;
1732 break;
1734 default:
1735 t = VAR;
1736 break;
1738 temp = emptynode(t, len = wcslen(formal->n_name));
1739 (void) memcpy(temp->n_name, formal->n_name,
1740 (len+1) * sizeof (wchar_t));
1741 temp->n_flags = FSTRING|FVINT;
1742 temp->n_string = _null;
1743 temp->n_strlen = 0;
1744 if (t == VAR)
1745 (void) assign(temp, actual);
1746 if (t != ARRAY)
1747 temp->n_flags |= FLARRAY;
1748 temp->n_scope = scope_tag;
1750 * link to actual parameter in case of promotion to
1751 * array
1753 if (actual != constundef)
1754 temp->n_alink = actual;
1756 * Build the templist
1758 if (templist != NNULL) {
1759 temptail->n_next = temp;
1760 temptail = temp;
1761 } else
1762 templist = temptail = temp;
1763 temp->n_next = NNULL;
1764 if (actual->n_type == CONSTANT)
1765 temp->n_alink = temp;
1766 else
1767 temp->n_alink = array;
1770 * Bind results of the evaluation of actuals to formals.
1772 formlist = fnp->n_left;
1773 while (templist != NNULL) {
1774 temp = templist;
1775 templist = temp->n_next;
1776 formal = getlist(&formlist);
1777 temp->n_next = formal->n_next;
1778 formal->n_next = temp;
1790 register NODE *savenode = curnode;
1792 ++slevel;
1793 if (action(fnp->n_right) == RETURN)
1794 np = retval; else
1795 np = const0;
1796 curnode = savenode;
1799 register NODE *formal;
1800 NODE *formlist;
1802 formlist = fnp->n_left;
1803 while ((formal = getlist(&formlist)) != NNULL) {
1804 temp = formal->n_next;
1805 formal->n_next = temp->n_next;
1806 /* if node is a local array, free the elements */
1807 if (temp->n_type == ARRAY && (temp->n_scope == slevel))
1808 delarray(temp);
1809 freenode(temp);
1812 --slevel;
1813 return (np);
1817 * Get the regular expression from an expression tree.
1819 REGEXP
1820 getregexp(NODE *np)
1822 if (np->n_type == RE)
1823 return (np->n_regexp);
1824 np = renode((wchar_t *)exprstring(np));
1825 return (np->n_regexp);
1829 * Get the next element from a list.
1831 NODE *
1832 getlist(NODE **npp)
1834 register NODE *np;
1836 if ((np = *npp) == NNULL)
1837 return (np);
1838 if (np->n_type == COMMA) {
1839 *npp = np->n_right;
1840 return (np->n_left);
1841 } else {
1842 *npp = NNULL;
1843 return (np);
1848 * if statement.
1850 static int
1851 s_if(NODE *np)
1853 register NODE *xp;
1854 register int test;
1856 test = exprtest(np->n_left);
1857 xp = np->n_right;
1858 if (xp->n_type != ELSE)
1859 awkerr(interr, "if/else");
1860 if (test)
1861 xp = xp->n_left;
1862 else
1863 xp = xp->n_right;
1864 return (action(xp));
1868 * while and do{}while statements.
1870 static int
1871 s_while(NODE *np)
1873 register int act = 0;
1875 if (np->n_type == DO)
1876 goto dowhile;
1877 for (;;) {
1878 if (exprtest(np->n_left) == 0)
1879 break;
1880 dowhile:
1881 if ((act = action(np->n_right)) != 0) {
1882 switch (act) {
1883 case BREAK:
1884 act = 0;
1885 break;
1887 case CONTINUE:
1888 act = 0;
1889 continue;
1891 break;
1894 return (act);
1898 * for statement.
1900 static int
1901 s_for(NODE *np)
1903 register NODE *testnp, *incnp, *initnp;
1904 register int act = 0;
1905 NODE *listp;
1907 listp = np->n_left;
1908 initnp = getlist(&listp);
1909 testnp = getlist(&listp);
1910 incnp = getlist(&listp);
1911 if (initnp != NNULL)
1912 (void) exprreduce(initnp);
1913 for (;;) {
1914 if (exprtest(testnp) == 0)
1915 break;
1916 if ((act = action(np->n_right)) != 0) {
1917 switch (act) {
1918 case BREAK:
1919 act = 0;
1920 break;
1922 case CONTINUE:
1923 act = 0;
1924 goto clabel;
1926 break;
1928 clabel:
1929 if (incnp != NNULL)
1930 (void) exprreduce(incnp);
1932 return (act);
1936 * for variable in array statement.
1938 static int
1939 s_forin(NODE *np)
1941 register NODE *left;
1942 register int act = 0;
1943 register NODE *var;
1944 register NODE **nnp;
1945 register NODE *statement;
1946 register int issymtab = 0;
1947 wchar_t *index;
1948 register int alen;
1949 int nbuck;
1951 left = np->n_left;
1952 statement = np->n_right;
1953 if (left->n_type != IN)
1954 awkerr(interr, "for (var in array)");
1955 if ((var = left->n_left)->n_type == PARM)
1956 var = var->n_next;
1957 np = left->n_right;
1958 if (np->n_type == PARM) {
1959 np = np->n_next;
1960 if (!(np->n_flags & FLARRAY))
1961 np = np->n_alink;
1963 if (np == varSYMTAB) {
1964 issymtab++;
1965 np = NNULL;
1966 nbuck = 0;
1967 } else {
1969 * At this point if the node is not actually an array
1970 * check to see if it has already been established as
1971 * a scalar. If it is a scalar then flag an error. If
1972 * not then promote the object to an array type.
1974 if (np->n_type != ARRAY) {
1975 if (!isstring(np->n_flags) || np->n_string != _null)
1976 awkerr(notarray, np->n_name);
1977 else {
1978 /* promotion to array */
1979 promote(np);
1980 if (np->n_alink != NNULL)
1981 if (!(np->n_flags & FLARRAY))
1982 np = np->n_alink;
1986 * Set up a pointer to the first node in the array list.
1987 * Save this pointer on the delete stack. This information
1988 * is used by the delete function to advance any pointers
1989 * that might be pointing at a node which has been deleted.
1990 * See the delsymtab() function for more information. Note
1991 * that if the a_link field is nil, then just return 0 since
1992 * this array has no elements yet.
1994 if ((*(nnp = next_forin) = np->n_alink) == 0)
1995 return (0);
1996 if (++next_forin > &forindex[NFORINLOOP])
1997 awkerr(toodeep, NFORINLOOP);
1999 * array elements have names of the form
2000 * <name>]<index> (global arrays)
2001 * or
2002 * <name>[<scope>]<index> (local arrays)
2003 * We need to know the offset of the index portion of the
2004 * name string in order to place it in the index variable so
2005 * we look for the ']'. This is calculated here and then
2006 * used below.
2008 for (alen = 0; (*nnp)->n_name[alen++] != ']'; )
2009 if ((*nnp)->n_name[alen] == '\0')
2010 awkerr(interr, "for: invalid array");
2012 for (;;) {
2013 if (issymtab) {
2014 if ((left = symwalk(&nbuck, &np)) == NNULL)
2015 break;
2016 index = left->n_name;
2017 } else {
2018 if ((np = *nnp) == NNULL)
2019 break;
2020 index = np->n_name+alen;
2021 *nnp = np->n_alink;
2023 strassign(var, index, FSTATIC, wcslen(index));
2024 if ((act = action(statement)) != 0) {
2025 switch (act) {
2026 case BREAK:
2027 act = 0;
2028 break;
2030 case CONTINUE:
2031 act = 0;
2032 continue;
2034 break;
2037 next_forin--;
2038 return (act);
2042 * Walk the symbol table using the same algorithm as arraynode.
2044 NODE *
2045 symwalk(int *buckp, NODE **npp)
2047 register NODE *np;
2049 np = *npp;
2050 for (;;) {
2051 while (np == NNULL) {
2052 if (*buckp >= NBUCKET)
2053 return (*npp = NNULL);
2054 np = symtab[(*buckp)++];
2056 if (np->n_type == VAR &&
2057 (!isstring(np->n_flags) || np->n_string != _null)) {
2058 *npp = np->n_next;
2059 return (np);
2061 np = np->n_next;
2063 /* NOTREACHED */
2067 * Test the result of an expression.
2069 static int
2070 exprtest(NODE *np)
2072 register int t;
2074 if (np == NNULL)
2075 return (1);
2076 if (freelist != NNULL)
2077 freetemps();
2078 np = exprreduce(np);
2079 if (isint(t = np->n_flags)) {
2080 if (isstring(t))
2081 return (exprint(np) != 0);
2082 return (np->n_int != 0);
2084 if (isreal(t)) {
2085 REAL rval;
2087 rval = isstring(t) ? exprreal(np) : np->n_real;
2088 return (rval != 0.0);
2090 return (*(wchar_t *)exprstring(np) != '\0');
2094 * Return malloc'ed space that holds the given name "[" scope "]" index ...
2095 * concatenated string.
2096 * The node (np) is the list of indices and 'array' is the array name.
2098 static wchar_t *
2099 makeindex(NODE *np, wchar_t *array, int tag)
2101 static wchar_t tags[sizeof (int)];
2102 static wchar_t tag_chars[] = M_MB_L("0123456789ABCDEF");
2103 register wchar_t *cp;
2104 register NODE *index;
2105 register uint_t n;
2106 register int len;
2107 register wchar_t *indstr;
2108 register wchar_t *sep;
2109 register int seplen;
2110 register int taglen;
2114 * calculate and create the tag string
2116 for (taglen = 0; tag; tag >>= 4)
2117 tags[taglen++] = tag_chars[tag & 0xf];
2119 * Special (normal) case: only one index.
2121 if (np->n_type != COMMA) {
2122 wchar_t *ocp;
2123 size_t i;
2125 if (isleaf(np->n_flags) && np->n_type == PARM)
2126 np = np->n_next;
2127 if (isstring(np->n_flags)) {
2128 indstr = np->n_string;
2129 len = np->n_strlen;
2130 } else {
2131 indstr = exprstring(np);
2132 len = wcslen(indstr);
2134 i = (n = wcslen(array)) + len + 3 + taglen;
2135 if (i < NINDEXBUF)
2136 ocp = indexbuf;
2137 else
2138 ocp = emalloc(i * sizeof (wchar_t));
2139 (void) memcpy(ocp, array, n * sizeof (wchar_t));
2140 cp = ocp+n;
2141 if (taglen) {
2142 *cp++ = '[';
2143 while (taglen)
2144 *cp++ = tags[--taglen];
2146 *cp++ = ']';
2147 (void) memcpy(cp, indstr, (len+1) * sizeof (wchar_t));
2149 return (ocp);
2151 n = 0;
2152 seplen = wcslen(sep = (wchar_t *)exprstring(varSUBSEP));
2153 while ((index = getlist(&np)) != NNULL) {
2154 indstr = exprstring(index);
2155 len = wcslen(indstr);
2156 if (n == 0) {
2157 cp = emalloc(sizeof (wchar_t) * ((n = wcslen(array)) +
2158 len + 3 + taglen));
2159 (void) memcpy(cp, array, n * sizeof (wchar_t));
2160 if (taglen) {
2161 cp[n++] = '[';
2162 while (taglen)
2163 cp[n++] = tags[--taglen];
2165 cp[n++] = ']';
2166 } else {
2167 cp = erealloc(cp, (n+len+seplen+1) * sizeof (wchar_t));
2168 (void) memcpy(cp+n, sep, seplen * sizeof (wchar_t));
2169 n += seplen;
2171 (void) memcpy(cp+n, indstr, (len+1) * sizeof (wchar_t));
2172 n += len;
2174 return (cp);
2179 * Promote a node to an array. In the simplest case, just set the
2180 * node type field to ARRAY. The more complicated case involves walking
2181 * a list of variables that haven't been determined yet as scalar or array.
2182 * This routine plays with the pointers to avoid recursion.
2184 void
2185 promote(NODE *n)
2187 register NODE *prev = NNULL;
2188 register NODE *next;
2191 * walk down the variable chain, reversing the pointers and
2192 * setting each node to type array.
2194 while ((n->n_flags & FLARRAY) && (n->n_alink != n)) {
2195 n->n_type = ARRAY;
2196 next = n->n_alink;
2197 n->n_alink = prev;
2198 prev = n;
2199 n = next;
2203 * If the final entity on the chain is a local variable, then
2204 * reset it's alink field to NNULL - normally it points back
2205 * to itself - this is used in other parts of the code to
2206 * reduce the number of conditionals when handling locals.
2208 n->n_type = ARRAY;
2209 if (n->n_flags & FLARRAY)
2210 n->n_alink = NNULL;
2213 * Now walk back up the list setting the alink to point to
2214 * the last entry in the chain and clear the 'local array'
2215 * flag.
2217 while (prev != NNULL) {
2218 prev->n_flags &= ~FLARRAY;
2219 next = prev->n_alink;
2220 prev->n_alink = n;
2221 prev = next;