blob: 64b28672dcff2c355a6588d254e7b4000a10a0ff [file] [log] [blame]
Thorsten Glaserba2627c2010-08-24 18:21:37 +02001/* $OpenBSD: syn.c,v 1.28 2008/07/23 16:34:38 jaredy Exp $ */
2
3/*-
4 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009
5 * Thorsten Glaser <tg@mirbsd.org>
6 *
7 * Provided that these terms and disclaimer and all copyright notices
8 * are retained or reproduced in an accompanying document, permission
9 * is granted to deal in this work without restriction, including un-
10 * limited rights to use, publicly perform, distribute, sell, modify,
11 * merge, give away, or sublicence.
12 *
13 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
14 * the utmost extent permitted by applicable law, neither express nor
15 * implied; without malicious intent or gross negligence. In no event
16 * may a licensor, author or contributor be held liable for indirect,
17 * direct, other damage, loss, or other issues arising in any way out
18 * of dealing in the work, even if advised of the possibility of such
19 * damage or existence of a defect, except proven that it results out
20 * of said person's immediate fault when using the work as intended.
21 */
22
23#include "sh.h"
24
25__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.49 2010/07/17 22:09:39 tg Exp $");
26
27struct nesting_state {
28 int start_token; /* token than began nesting (eg, FOR) */
29 int start_line; /* line nesting began on */
30};
31
32static void yyparse(void);
33static struct op *pipeline(int);
34static struct op *andor(void);
35static struct op *c_list(int);
36static struct ioword *synio(int);
37static struct op *nested(int, int, int);
38static struct op *get_command(int);
39static struct op *dogroup(void);
40static struct op *thenpart(void);
41static struct op *elsepart(void);
42static struct op *caselist(void);
43static struct op *casepart(int);
44static struct op *function_body(char *, bool);
45static char **wordlist(void);
46static struct op *block(int, struct op *, struct op *, char **);
47static struct op *newtp(int);
48static void syntaxerr(const char *) MKSH_A_NORETURN;
49static void nesting_push(struct nesting_state *, int);
50static void nesting_pop(struct nesting_state *);
51static int assign_command(char *);
52static int inalias(struct source *);
53static Test_op dbtestp_isa(Test_env *, Test_meta);
54static const char *dbtestp_getopnd(Test_env *, Test_op, bool);
55static int dbtestp_eval(Test_env *, Test_op, const char *,
56 const char *, bool);
57static void dbtestp_error(Test_env *, int, const char *) MKSH_A_NORETURN;
58
59static struct op *outtree; /* yyparse output */
60static struct nesting_state nesting; /* \n changed to ; */
61
62static int reject; /* token(cf) gets symbol again */
63static int symbol; /* yylex value */
64
65#define REJECT (reject = 1)
66#define ACCEPT (reject = 0)
67#define token(cf) ((reject) ? (ACCEPT, symbol) : (symbol = yylex(cf)))
68#define tpeek(cf) ((reject) ? (symbol) : (REJECT, symbol = yylex(cf)))
69#define musthave(c,cf) do { if (token(cf) != (c)) syntaxerr(NULL); } while (0)
70
71static void
72yyparse(void)
73{
74 int c;
75
76 ACCEPT;
77
78 outtree = c_list(source->type == SSTRING);
79 c = tpeek(0);
80 if (c == 0 && !outtree)
81 outtree = newtp(TEOF);
82 else if (c != '\n' && c != 0)
83 syntaxerr(NULL);
84}
85
86static struct op *
87pipeline(int cf)
88{
89 struct op *t, *p, *tl = NULL;
90
91 t = get_command(cf);
92 if (t != NULL) {
93 while (token(0) == '|') {
94 if ((p = get_command(CONTIN)) == NULL)
95 syntaxerr(NULL);
96 if (tl == NULL)
97 t = tl = block(TPIPE, t, p, NOWORDS);
98 else
99 tl = tl->right = block(TPIPE, tl->right, p, NOWORDS);
100 }
101 REJECT;
102 }
103 return (t);
104}
105
106static struct op *
107andor(void)
108{
109 struct op *t, *p;
110 int c;
111
112 t = pipeline(0);
113 if (t != NULL) {
114 while ((c = token(0)) == LOGAND || c == LOGOR) {
115 if ((p = pipeline(CONTIN)) == NULL)
116 syntaxerr(NULL);
117 t = block(c == LOGAND? TAND: TOR, t, p, NOWORDS);
118 }
119 REJECT;
120 }
121 return (t);
122}
123
124static struct op *
125c_list(int multi)
126{
127 struct op *t = NULL, *p, *tl = NULL;
128 int c, have_sep;
129
130 while (1) {
131 p = andor();
132 /* Token has always been read/rejected at this point, so
133 * we don't worry about what flags to pass token()
134 */
135 c = token(0);
136 have_sep = 1;
137 if (c == '\n' && (multi || inalias(source))) {
138 if (!p) /* ignore blank lines */
139 continue;
140 } else if (!p)
141 break;
142 else if (c == '&' || c == COPROC)
143 p = block(c == '&' ? TASYNC : TCOPROC,
144 p, NOBLOCK, NOWORDS);
145 else if (c != ';')
146 have_sep = 0;
147 if (!t)
148 t = p;
149 else if (!tl)
150 t = tl = block(TLIST, t, p, NOWORDS);
151 else
152 tl = tl->right = block(TLIST, tl->right, p, NOWORDS);
153 if (!have_sep)
154 break;
155 }
156 REJECT;
157 return (t);
158}
159
160static struct ioword *
161synio(int cf)
162{
163 struct ioword *iop;
164 static struct ioword *nextiop = NULL;
165 bool ishere;
166
167 if (nextiop != NULL) {
168 iop = nextiop;
169 nextiop = NULL;
170 return (iop);
171 }
172
173 if (tpeek(cf) != REDIR)
174 return (NULL);
175 ACCEPT;
176 iop = yylval.iop;
177 ishere = (iop->flag&IOTYPE) == IOHERE;
178 musthave(LWORD, ishere ? HEREDELIM : 0);
179 if (ishere) {
180 iop->delim = yylval.cp;
181 if (*ident != 0) /* unquoted */
182 iop->flag |= IOEVAL;
183 if (herep > &heres[HERES - 1])
184 yyerror("too many <<s\n");
185 *herep++ = iop;
186 } else
187 iop->name = yylval.cp;
188
189 if (iop->flag & IOBASH) {
190 char *cp;
191
192 nextiop = alloc(sizeof(*iop), ATEMP);
193 nextiop->name = cp = alloc(5, ATEMP);
194
195 if (iop->unit > 9) {
196 *cp++ = CHAR;
197 *cp++ = '0' + (iop->unit / 10);
198 }
199 *cp++ = CHAR;
200 *cp++ = '0' + (iop->unit % 10);
201 *cp = EOS;
202
203 iop->flag &= ~IOBASH;
204 nextiop->unit = 2;
205 nextiop->flag = IODUP;
206 nextiop->delim = NULL;
207 nextiop->heredoc = NULL;
208 }
209 return (iop);
210}
211
212static struct op *
213nested(int type, int smark, int emark)
214{
215 struct op *t;
216 struct nesting_state old_nesting;
217
218 nesting_push(&old_nesting, smark);
219 t = c_list(true);
220 musthave(emark, KEYWORD|ALIAS);
221 nesting_pop(&old_nesting);
222 return (block(type, t, NOBLOCK, NOWORDS));
223}
224
225static struct op *
226get_command(int cf)
227{
228 struct op *t;
229 int c, iopn = 0, syniocf;
230 struct ioword *iop, **iops;
231 XPtrV args, vars;
232 struct nesting_state old_nesting;
233
234 iops = alloc((NUFILE + 1) * sizeof(struct ioword *), ATEMP);
235 XPinit(args, 16);
236 XPinit(vars, 16);
237
238 syniocf = KEYWORD|ALIAS;
239 switch (c = token(cf|KEYWORD|ALIAS|VARASN)) {
240 default:
241 REJECT;
242 afree(iops, ATEMP);
243 XPfree(args);
244 XPfree(vars);
245 return (NULL); /* empty line */
246
247 case LWORD:
248 case REDIR:
249 REJECT;
250 syniocf &= ~(KEYWORD|ALIAS);
251 t = newtp(TCOM);
252 t->lineno = source->line;
253 while (1) {
254 cf = (t->u.evalflags ? ARRAYVAR : 0) |
255 (XPsize(args) == 0 ? ALIAS|VARASN : CMDWORD);
256 switch (tpeek(cf)) {
257 case REDIR:
258 while ((iop = synio(cf)) != NULL) {
259 if (iopn >= NUFILE)
260 yyerror("too many redirections\n");
261 iops[iopn++] = iop;
262 }
263 break;
264
265 case LWORD:
266 ACCEPT;
267 /* the iopn == 0 and XPsize(vars) == 0 are
268 * dubious but AT&T ksh acts this way
269 */
270 if (iopn == 0 && XPsize(vars) == 0 &&
271 XPsize(args) == 0 &&
272 assign_command(ident))
273 t->u.evalflags = DOVACHECK;
274 if ((XPsize(args) == 0 || Flag(FKEYWORD)) &&
275 is_wdvarassign(yylval.cp))
276 XPput(vars, yylval.cp);
277 else
278 XPput(args, yylval.cp);
279 break;
280
281 case '(':
282 /* Check for "> foo (echo hi)" which AT&T ksh
283 * allows (not POSIX, but not disallowed)
284 */
285 afree(t, ATEMP);
286 if (XPsize(args) == 0 && XPsize(vars) == 0) {
287 ACCEPT;
288 goto Subshell;
289 }
290#ifndef MKSH_SMALL
291 if ((XPsize(args) == 0 || Flag(FKEYWORD)) &&
292 XPsize(vars) == 1 && is_wdvarassign(yylval.cp))
293 goto is_wdarrassign;
294#endif
295 /* Must be a function */
296 if (iopn != 0 || XPsize(args) != 1 ||
297 XPsize(vars) != 0)
298 syntaxerr(NULL);
299 ACCEPT;
300 /*(*/
301 musthave(')', 0);
302 t = function_body(XPptrv(args)[0], false);
303 goto Leave;
304#ifndef MKSH_SMALL
305 is_wdarrassign:
306 {
307 static const char set_cmd0[] = {
308 CHAR, 'e', CHAR, 'v',
309 CHAR, 'a', CHAR, 'l', EOS
310 };
311 static const char set_cmd1[] = {
312 CHAR, 's', CHAR, 'e',
313 CHAR, 't', CHAR, ' ',
314 CHAR, '-', CHAR, 'A', EOS
315 };
316 static const char set_cmd2[] = {
317 CHAR, '-', CHAR, '-', EOS
318 };
319 char *tcp;
320 XPfree(vars);
321 XPinit(vars, 16);
322 /*
323 * we know (or rather hope) that yylval.cp
324 * contains a string "varname="
325 */
326 tcp = wdcopy(yylval.cp, ATEMP);
327 tcp[wdscan(tcp, EOS) - tcp - 3] = EOS;
328 /* now make an array assignment command */
329 t = newtp(TCOM);
330 t->lineno = source->line;
331 ACCEPT;
332 XPput(args, wdcopy(set_cmd0, ATEMP));
333 XPput(args, wdcopy(set_cmd1, ATEMP));
334 XPput(args, tcp);
335 XPput(args, wdcopy(set_cmd2, ATEMP));
336 musthave(LWORD,LETARRAY);
337 XPput(args, yylval.cp);
338 break;
339 }
340#endif
341
342 default:
343 goto Leave;
344 }
345 }
346 Leave:
347 break;
348
349 case '(':
350 Subshell:
351 t = nested(TPAREN, '(', ')');
352 break;
353
354 case '{': /*}*/
355 t = nested(TBRACE, '{', '}');
356 break;
357
358 case MDPAREN: {
359 int lno;
360 static const char let_cmd[] = {
361 CHAR, 'l', CHAR, 'e',
362 CHAR, 't', EOS
363 };
364
365 /* Leave KEYWORD in syniocf (allow if (( 1 )) then ...) */
366 lno = source->line;
367 ACCEPT;
368 switch (token(LETEXPR)) {
369 case LWORD:
370 break;
371 case '(': /* ) */
372 goto Subshell;
373 default:
374 syntaxerr(NULL);
375 }
376 t = newtp(TCOM);
377 t->lineno = lno;
378 XPput(args, wdcopy(let_cmd, ATEMP));
379 XPput(args, yylval.cp);
380 break;
381 }
382
383 case DBRACKET: /* [[ .. ]] */
384 /* Leave KEYWORD in syniocf (allow if [[ -n 1 ]] then ...) */
385 t = newtp(TDBRACKET);
386 ACCEPT;
387 {
388 Test_env te;
389
390 te.flags = TEF_DBRACKET;
391 te.pos.av = &args;
392 te.isa = dbtestp_isa;
393 te.getopnd = dbtestp_getopnd;
394 te.eval = dbtestp_eval;
395 te.error = dbtestp_error;
396
397 test_parse(&te);
398 }
399 break;
400
401 case FOR:
402 case SELECT:
403 t = newtp((c == FOR) ? TFOR : TSELECT);
404 musthave(LWORD, ARRAYVAR);
405 if (!is_wdvarname(yylval.cp, true))
406 yyerror("%s: bad identifier\n",
407 c == FOR ? "for" : "select");
408 strdupx(t->str, ident, ATEMP);
409 nesting_push(&old_nesting, c);
410 t->vars = wordlist();
411 t->left = dogroup();
412 nesting_pop(&old_nesting);
413 break;
414
415 case WHILE:
416 case UNTIL:
417 nesting_push(&old_nesting, c);
418 t = newtp((c == WHILE) ? TWHILE : TUNTIL);
419 t->left = c_list(true);
420 t->right = dogroup();
421 nesting_pop(&old_nesting);
422 break;
423
424 case CASE:
425 t = newtp(TCASE);
426 musthave(LWORD, 0);
427 t->str = yylval.cp;
428 nesting_push(&old_nesting, c);
429 t->left = caselist();
430 nesting_pop(&old_nesting);
431 break;
432
433 case IF:
434 nesting_push(&old_nesting, c);
435 t = newtp(TIF);
436 t->left = c_list(true);
437 t->right = thenpart();
438 musthave(FI, KEYWORD|ALIAS);
439 nesting_pop(&old_nesting);
440 break;
441
442 case BANG:
443 syniocf &= ~(KEYWORD|ALIAS);
444 t = pipeline(0);
445 if (t == NULL)
446 syntaxerr(NULL);
447 t = block(TBANG, NOBLOCK, t, NOWORDS);
448 break;
449
450 case TIME:
451 syniocf &= ~(KEYWORD|ALIAS);
452 t = pipeline(0);
453 if (t) {
454 t->str = alloc(2, ATEMP);
455 t->str[0] = '\0'; /* TF_* flags */
456 t->str[1] = '\0';
457 }
458 t = block(TTIME, t, NOBLOCK, NOWORDS);
459 break;
460
461 case FUNCTION:
462 musthave(LWORD, 0);
463 t = function_body(yylval.cp, true);
464 break;
465 }
466
467 while ((iop = synio(syniocf)) != NULL) {
468 if (iopn >= NUFILE)
469 yyerror("too many redirections\n");
470 iops[iopn++] = iop;
471 }
472
473 if (iopn == 0) {
474 afree(iops, ATEMP);
475 t->ioact = NULL;
476 } else {
477 iops[iopn++] = NULL;
478 iops = aresize(iops, iopn * sizeof(struct ioword *), ATEMP);
479 t->ioact = iops;
480 }
481
482 if (t->type == TCOM || t->type == TDBRACKET) {
483 XPput(args, NULL);
484 t->args = (const char **)XPclose(args);
485 XPput(vars, NULL);
486 t->vars = (char **) XPclose(vars);
487 } else {
488 XPfree(args);
489 XPfree(vars);
490 }
491
492 return (t);
493}
494
495static struct op *
496dogroup(void)
497{
498 int c;
499 struct op *list;
500
501 c = token(CONTIN|KEYWORD|ALIAS);
502 /* A {...} can be used instead of do...done for for/select loops
503 * but not for while/until loops - we don't need to check if it
504 * is a while loop because it would have been parsed as part of
505 * the conditional command list...
506 */
507 if (c == DO)
508 c = DONE;
509 else if (c == '{')
510 c = '}';
511 else
512 syntaxerr(NULL);
513 list = c_list(true);
514 musthave(c, KEYWORD|ALIAS);
515 return (list);
516}
517
518static struct op *
519thenpart(void)
520{
521 struct op *t;
522
523 musthave(THEN, KEYWORD|ALIAS);
524 t = newtp(0);
525 t->left = c_list(true);
526 if (t->left == NULL)
527 syntaxerr(NULL);
528 t->right = elsepart();
529 return (t);
530}
531
532static struct op *
533elsepart(void)
534{
535 struct op *t;
536
537 switch (token(KEYWORD|ALIAS|VARASN)) {
538 case ELSE:
539 if ((t = c_list(true)) == NULL)
540 syntaxerr(NULL);
541 return (t);
542
543 case ELIF:
544 t = newtp(TELIF);
545 t->left = c_list(true);
546 t->right = thenpart();
547 return (t);
548
549 default:
550 REJECT;
551 }
552 return (NULL);
553}
554
555static struct op *
556caselist(void)
557{
558 struct op *t, *tl;
559 int c;
560
561 c = token(CONTIN|KEYWORD|ALIAS);
562 /* A {...} can be used instead of in...esac for case statements */
563 if (c == IN)
564 c = ESAC;
565 else if (c == '{')
566 c = '}';
567 else
568 syntaxerr(NULL);
569 t = tl = NULL;
570 while ((tpeek(CONTIN|KEYWORD|ESACONLY)) != c) { /* no ALIAS here */
571 struct op *tc = casepart(c);
572 if (tl == NULL)
573 t = tl = tc, tl->right = NULL;
574 else
575 tl->right = tc, tl = tc;
576 }
577 musthave(c, KEYWORD|ALIAS);
578 return (t);
579}
580
581static struct op *
582casepart(int endtok)
583{
584 struct op *t;
585 XPtrV ptns;
586
587 XPinit(ptns, 16);
588 t = newtp(TPAT);
589 /* no ALIAS here */
590 if (token(CONTIN | KEYWORD) != '(')
591 REJECT;
592 do {
593 musthave(LWORD, 0);
594 XPput(ptns, yylval.cp);
595 } while (token(0) == '|');
596 REJECT;
597 XPput(ptns, NULL);
598 t->vars = (char **) XPclose(ptns);
599 musthave(')', 0);
600
601 t->left = c_list(true);
602 /* Note: POSIX requires the ;; */
603 if ((tpeek(CONTIN|KEYWORD|ALIAS)) != endtok)
604 musthave(BREAK, CONTIN|KEYWORD|ALIAS);
605 return (t);
606}
607
608static struct op *
609function_body(char *name,
610 bool ksh_func) /* function foo { ... } vs foo() { .. } */
611{
612 char *sname, *p;
613 struct op *t;
614 bool old_func_parse;
615
616 sname = wdstrip(name, false, false);
617 /* Check for valid characters in name. POSIX and AT&T ksh93 say only
618 * allow [a-zA-Z_0-9] but this allows more as old pdkshs have
619 * allowed more (the following were never allowed:
620 * NUL TAB NL SP " $ & ' ( ) ; < = > \ ` |
621 * C_QUOTE covers all but adds # * ? [ ]
622 */
623 for (p = sname; *p; p++)
624 if (ctype(*p, C_QUOTE))
625 yyerror("%s: invalid function name\n", sname);
626
627 /* Note that POSIX allows only compound statements after foo(), sh and
628 * AT&T ksh allow any command, go with the later since it shouldn't
629 * break anything. However, for function foo, AT&T ksh only accepts
630 * an open-brace.
631 */
632 if (ksh_func) {
633 if (tpeek(CONTIN|KEYWORD|ALIAS) == '(' /* ) */) {
634 struct tbl *tp;
635
636 /* function foo () { */
637 ACCEPT;
638 musthave(')', 0);
639 /* degrade to POSIX function */
640 ksh_func = false;
641 if ((tp = ktsearch(&aliases, sname, hash(sname))))
642 ktdelete(tp);
643 }
644 musthave('{', CONTIN|KEYWORD|ALIAS); /* } */
645 REJECT;
646 }
647
648 t = newtp(TFUNCT);
649 t->str = sname;
650 t->u.ksh_func = ksh_func;
651 t->lineno = source->line;
652
653 old_func_parse = e->flags & EF_FUNC_PARSE;
654 e->flags |= EF_FUNC_PARSE;
655 if ((t->left = get_command(CONTIN)) == NULL) {
656 char *tv;
657 /*
658 * Probably something like foo() followed by eof or ;.
659 * This is accepted by sh and ksh88.
660 * To make "typeset -f foo" work reliably (so its output can
661 * be used as input), we pretend there is a colon here.
662 */
663 t->left = newtp(TCOM);
664 t->left->args = alloc(2 * sizeof(char *), ATEMP);
665 t->left->args[0] = tv = alloc(3, ATEMP);
666 tv[0] = CHAR;
667 tv[1] = ':';
668 tv[2] = EOS;
669 t->left->args[1] = NULL;
670 t->left->vars = alloc(sizeof(char *), ATEMP);
671 t->left->vars[0] = NULL;
672 t->left->lineno = 1;
673 }
674 if (!old_func_parse)
675 e->flags &= ~EF_FUNC_PARSE;
676
677 return (t);
678}
679
680static char **
681wordlist(void)
682{
683 int c;
684 XPtrV args;
685
686 XPinit(args, 16);
687 /* POSIX does not do alias expansion here... */
688 if ((c = token(CONTIN|KEYWORD|ALIAS)) != IN) {
689 if (c != ';') /* non-POSIX, but AT&T ksh accepts a ; here */
690 REJECT;
691 return (NULL);
692 }
693 while ((c = token(0)) == LWORD)
694 XPput(args, yylval.cp);
695 if (c != '\n' && c != ';')
696 syntaxerr(NULL);
697 if (XPsize(args) == 0) {
698 XPfree(args);
699 return (NULL);
700 } else {
701 XPput(args, NULL);
702 return ((char **)XPclose(args));
703 }
704}
705
706/*
707 * supporting functions
708 */
709
710static struct op *
711block(int type, struct op *t1, struct op *t2, char **wp)
712{
713 struct op *t;
714
715 t = newtp(type);
716 t->left = t1;
717 t->right = t2;
718 t->vars = wp;
719 return (t);
720}
721
722const struct tokeninfo {
723 const char *name;
724 short val;
725 short reserved;
726} tokentab[] = {
727 /* Reserved words */
728 { "if", IF, true },
729 { "then", THEN, true },
730 { "else", ELSE, true },
731 { "elif", ELIF, true },
732 { "fi", FI, true },
733 { "case", CASE, true },
734 { "esac", ESAC, true },
735 { "for", FOR, true },
736 { "select", SELECT, true },
737 { "while", WHILE, true },
738 { "until", UNTIL, true },
739 { "do", DO, true },
740 { "done", DONE, true },
741 { "in", IN, true },
742 { "function", FUNCTION, true },
743 { "time", TIME, true },
744 { "{", '{', true },
745 { "}", '}', true },
746 { "!", BANG, true },
747 { "[[", DBRACKET, true },
748 /* Lexical tokens (0[EOF], LWORD and REDIR handled specially) */
749 { "&&", LOGAND, false },
750 { "||", LOGOR, false },
751 { ";;", BREAK, false },
752 { "((", MDPAREN, false },
753 { "|&", COPROC, false },
754 /* and some special cases... */
755 { "newline", '\n', false },
756 { NULL, 0, false }
757};
758
759void
760initkeywords(void)
761{
762 struct tokeninfo const *tt;
763 struct tbl *p;
764
765 ktinit(&keywords, APERM,
766 /* must be 80% of 2^n (currently 20 keywords) */ 32);
767 for (tt = tokentab; tt->name; tt++) {
768 if (tt->reserved) {
769 p = ktenter(&keywords, tt->name, hash(tt->name));
770 p->flag |= DEFINED|ISSET;
771 p->type = CKEYWD;
772 p->val.i = tt->val;
773 }
774 }
775}
776
777static void
778syntaxerr(const char *what)
779{
780 char redir[6]; /* 2<<- is the longest redirection, I think */
781 const char *s;
782 struct tokeninfo const *tt;
783 int c;
784
785 if (!what)
786 what = "unexpected";
787 REJECT;
788 c = token(0);
789 Again:
790 switch (c) {
791 case 0:
792 if (nesting.start_token) {
793 c = nesting.start_token;
794 source->errline = nesting.start_line;
795 what = "unmatched";
796 goto Again;
797 }
798 /* don't quote the EOF */
799 yyerror("%s: unexpected EOF\n", T_synerr);
800 /* NOTREACHED */
801
802 case LWORD:
803 s = snptreef(NULL, 32, "%S", yylval.cp);
804 break;
805
806 case REDIR:
807 s = snptreef(redir, sizeof(redir), "%R", yylval.iop);
808 break;
809
810 default:
811 for (tt = tokentab; tt->name; tt++)
812 if (tt->val == c)
813 break;
814 if (tt->name)
815 s = tt->name;
816 else {
817 if (c > 0 && c < 256) {
818 redir[0] = c;
819 redir[1] = '\0';
820 } else
821 shf_snprintf(redir, sizeof(redir),
822 "?%d", c);
823 s = redir;
824 }
825 }
826 yyerror("%s: '%s' %s\n", T_synerr, s, what);
827}
828
829static void
830nesting_push(struct nesting_state *save, int tok)
831{
832 *save = nesting;
833 nesting.start_token = tok;
834 nesting.start_line = source->line;
835}
836
837static void
838nesting_pop(struct nesting_state *saved)
839{
840 nesting = *saved;
841}
842
843static struct op *
844newtp(int type)
845{
846 struct op *t;
847
848 t = alloc(sizeof(struct op), ATEMP);
849 t->type = type;
850 t->u.evalflags = 0;
851 t->args = NULL;
852 t->vars = NULL;
853 t->ioact = NULL;
854 t->left = t->right = NULL;
855 t->str = NULL;
856 return (t);
857}
858
859struct op *
860compile(Source *s)
861{
862 nesting.start_token = 0;
863 nesting.start_line = 0;
864 herep = heres;
865 source = s;
866 yyparse();
867 return (outtree);
868}
869
870/* This kludge exists to take care of sh/AT&T ksh oddity in which
871 * the arguments of alias/export/readonly/typeset have no field
872 * splitting, file globbing, or (normal) tilde expansion done.
873 * AT&T ksh seems to do something similar to this since
874 * $ touch a=a; typeset a=[ab]; echo "$a"
875 * a=[ab]
876 * $ x=typeset; $x a=[ab]; echo "$a"
877 * a=a
878 * $
879 */
880static int
881assign_command(char *s)
882{
883 if (!*s)
884 return (0);
885 return ((strcmp(s, "alias") == 0) ||
886 (strcmp(s, "export") == 0) ||
887 (strcmp(s, "readonly") == 0) ||
888 (strcmp(s, T_typeset) == 0));
889}
890
891/* Check if we are in the middle of reading an alias */
892static int
893inalias(struct source *s)
894{
895 for (; s && s->type == SALIAS; s = s->next)
896 if (!(s->flags & SF_ALIASEND))
897 return (1);
898 return (0);
899}
900
901
902/* Order important - indexed by Test_meta values
903 * Note that ||, &&, ( and ) can't appear in as unquoted strings
904 * in normal shell input, so these can be interpreted unambiguously
905 * in the evaluation pass.
906 */
907static const char dbtest_or[] = { CHAR, '|', CHAR, '|', EOS };
908static const char dbtest_and[] = { CHAR, '&', CHAR, '&', EOS };
909static const char dbtest_not[] = { CHAR, '!', EOS };
910static const char dbtest_oparen[] = { CHAR, '(', EOS };
911static const char dbtest_cparen[] = { CHAR, ')', EOS };
912const char *const dbtest_tokens[] = {
913 dbtest_or, dbtest_and, dbtest_not,
914 dbtest_oparen, dbtest_cparen
915};
916const char db_close[] = { CHAR, ']', CHAR, ']', EOS };
917const char db_lthan[] = { CHAR, '<', EOS };
918const char db_gthan[] = { CHAR, '>', EOS };
919
920/*
921 * Test if the current token is a whatever. Accepts the current token if
922 * it is. Returns 0 if it is not, non-zero if it is (in the case of
923 * TM_UNOP and TM_BINOP, the returned value is a Test_op).
924 */
925static Test_op
926dbtestp_isa(Test_env *te, Test_meta meta)
927{
928 int c = tpeek(ARRAYVAR | (meta == TM_BINOP ? 0 : CONTIN));
929 int uqword;
930 char *save = NULL;
931 Test_op ret = TO_NONOP;
932
933 /* unquoted word? */
934 uqword = c == LWORD && *ident;
935
936 if (meta == TM_OR)
937 ret = c == LOGOR ? TO_NONNULL : TO_NONOP;
938 else if (meta == TM_AND)
939 ret = c == LOGAND ? TO_NONNULL : TO_NONOP;
940 else if (meta == TM_NOT)
941 ret = (uqword && !strcmp(yylval.cp,
942 dbtest_tokens[(int)TM_NOT])) ? TO_NONNULL : TO_NONOP;
943 else if (meta == TM_OPAREN)
944 ret = c == '(' /*)*/ ? TO_NONNULL : TO_NONOP;
945 else if (meta == TM_CPAREN)
946 ret = c == /*(*/ ')' ? TO_NONNULL : TO_NONOP;
947 else if (meta == TM_UNOP || meta == TM_BINOP) {
948 if (meta == TM_BINOP && c == REDIR &&
949 (yylval.iop->flag == IOREAD || yylval.iop->flag == IOWRITE)) {
950 ret = TO_NONNULL;
951 save = wdcopy(yylval.iop->flag == IOREAD ?
952 db_lthan : db_gthan, ATEMP);
953 } else if (uqword && (ret = test_isop(meta, ident)))
954 save = yylval.cp;
955 } else /* meta == TM_END */
956 ret = (uqword && !strcmp(yylval.cp,
957 db_close)) ? TO_NONNULL : TO_NONOP;
958 if (ret != TO_NONOP) {
959 ACCEPT;
960 if (meta < NELEM(dbtest_tokens))
961 save = wdcopy(dbtest_tokens[(int)meta], ATEMP);
962 if (save)
963 XPput(*te->pos.av, save);
964 }
965 return (ret);
966}
967
968static const char *
969dbtestp_getopnd(Test_env *te, Test_op op MKSH_A_UNUSED,
970 bool do_eval MKSH_A_UNUSED)
971{
972 int c = tpeek(ARRAYVAR);
973
974 if (c != LWORD)
975 return (NULL);
976
977 ACCEPT;
978 XPput(*te->pos.av, yylval.cp);
979
980 return (null);
981}
982
983static int
984dbtestp_eval(Test_env *te MKSH_A_UNUSED, Test_op op MKSH_A_UNUSED,
985 const char *opnd1 MKSH_A_UNUSED, const char *opnd2 MKSH_A_UNUSED,
986 bool do_eval MKSH_A_UNUSED)
987{
988 return (1);
989}
990
991static void
992dbtestp_error(Test_env *te, int offset, const char *msg)
993{
994 te->flags |= TEF_ERROR;
995
996 if (offset < 0) {
997 REJECT;
998 /* Kludgy to say the least... */
999 symbol = LWORD;
1000 yylval.cp = *(XPptrv(*te->pos.av) + XPsize(*te->pos.av) +
1001 offset);
1002 }
1003 syntaxerr(msg);
1004}