5 static tree* body(int tok, int *ptok);
6 static tree* brace(int tok);
7 static tree* cmd(int tok, int *ptok);
8 static tree* cmd2(int tok, int *ptok);
9 static tree* cmd3(int tok, int *ptok);
10 static tree* cmds(int tok, int *ptok, int nlok);
11 static tree* epilog(int tok, int *ptok);
12 static int iswordtok(int tok);
13 static tree* line(int tok, int *ptok);
14 static tree* paren(int tok);
15 static tree* yyredir(int tok, int *ptok);
16 static tree* yyword(int tok, int *ptok, int eqok);
17 static tree* word1(int tok, int *ptok);
18 static tree* words(int tok, int *ptok);
25 while(tok == ' ' || tok == '\n')
42 yyerror("syntax error");
56 // | line '\n' {return !compile($1);}
58 tok = dropsp(yylex());
63 yyerror("missing newline at end of line");
69 line(int tok, int *ptok)
71 return cmds(tok, ptok, 0);
75 body(int tok, int *ptok)
77 return cmds(tok, ptok, 1);
81 cmds(int tok, int *ptok, int nlok)
86 // | cmdsa line {$$=tree2(';', $1, $2);}
88 // | cmd '&' {$$=tree1('&', $1);}
91 // | cmdsan body {$$=tree2(';', $1, $2);}
107 *last = tree2(';', *last, t2);
108 last = &(*last)->child[1];
111 if(tok != ';' && tok != '&' && (!nlok || tok != '\n'))
124 // brace: '{' body '}' {$$=tree1(BRACE, $2);}
129 t = body(yylex(), &tok);
132 return tree1(BRACE, t);
140 // paren: '(' body ')' {$$=tree1(PCMD, $2);}
145 t = body(yylex(), &tok);
148 return tree1(PCMD, t);
152 epilog(int tok, int *ptok)
157 // | redir epilog {$$=mung2($1, $1->child[0], $2);}
159 if(tok != REDIR && tok != DUP) {
164 r = yyredir(tok, &tok);
165 t = epilog(tok, &tok);
167 return mung2(r, r->child[0], t);
171 yyredir(int tok, int *ptok)
175 // redir: REDIR word {$$=mung1($1, $1->rtype==HERE?heredoc($2):$2);}
183 *ptok = dropsp(yylex());
187 w = yyword(yylex(), &tok, 1);
189 r = mung1(r, r->rtype==HERE?heredoc(w):w);
196 cmd(int tok, int *ptok)
201 // | cmd ANDAND cmd {$$=tree2(ANDAND, $1, $3);}
202 // | cmd OROR cmd {$$=tree2(OROR, $1, $3);}
205 t1 = cmd2(tok, &tok);
206 while(tok == ANDAND || tok == OROR) {
208 t2 = cmd2(dropnl(yylex()), &tok);
209 t1 = tree2(op, t1, t2);
216 cmd2(int tok, int *ptok)
220 // | cmd PIPE cmd {$$=mung2($2, $1, $3);}
221 t1 = cmd3(tok, &tok);
224 t3 = cmd3(dropnl(yylex()), &tok);
225 t1 = mung2(t2, t1, t3);
232 cmd3(int tok, int *ptok)
234 tree *t1, *t2, *t3, *t4;
245 // | IF paren {skipnl();} cmd {$$=mung2($1, $2, $4);}
246 // | IF NOT {skipnl();} cmd {$$=mung1($2, $4);}
248 tok = dropsp(yylex());
251 t2 = cmd(dropnl(yylex()), ptok);
252 return mung1(t1, t2);
255 t3 = cmd(dropnl(yylex()), ptok);
256 return mung2(t1, t2, t3);
259 // | FOR '(' word IN words ')' {skipnl();} cmd
260 // {$$=mung3($1, $3, $5 ? $5 : tree1(PAREN, $5), $8);}
261 // | FOR '(' word ')' {skipnl();} cmd
262 // {$$=mung3($1, $3, (tree *)0, $6);}
264 tok = dropsp(yylex());
267 t2 = yyword(yylex(), &tok, 1);
275 t3 = words(yylex(), &tok);
277 t3 = tree1(PAREN, nil);
282 t4 = cmd(dropnl(yylex()), ptok);
283 return mung3(t1, t2, t3, t4);
286 // | WHILE paren {skipnl();} cmd
287 // {$$=mung2($1, $2, $4);}
290 t3 = cmd(dropnl(yylex()), ptok);
291 return mung2(t1, t2, t3);
294 // | SWITCH word {skipnl();} brace
295 // {$$=tree2(SWITCH, $2, $4);}
296 t1 = yyword(yylex(), &tok, 1);
297 tok = dropnl(tok); // doesn't work in yacc grammar but works here!
299 *ptok = dropsp(yylex());
300 return tree2(SWITCH, t1, t2);
301 // Note: cmd: a && for(x) y && b is a && {for (x) {y && b}}.
302 return cmd(tok, ptok);
305 // | FN words brace {$$=tree2(FN, $2, $3);}
306 // | FN words {$$=tree1(FN, $2);}
307 t1 = words(yylex(), &tok);
310 return tree1(FN, t1);
313 *ptok = dropsp(yylex());
314 return tree2(FN, t1, t2);
317 // | TWIDDLE word words {$$=mung2($1, $2, $3);}
319 t2 = yyword(yylex(), &tok, 1);
320 t3 = words(tok, ptok);
321 return mung2(t1, t2, t3);
325 // | BANG cmd {$$=mung1($1, $2);}
326 // | SUBSHELL cmd {$$=mung1($1, $2);}
327 // Note: cmd2: ! x | y is !{x | y} not {!x} | y.
329 return mung1(t1, cmd2(yylex(), ptok));
333 // | redir cmd %prec BANG {$$=mung2($1, $1->child[0], $2);}
334 // Note: cmd2: {>x echo a | tr a-z A-Z} writes A to x.
335 t1 = yyredir(tok, &tok);
336 t2 = cmd2(tok, ptok);
337 return mung2(t1, t1->child[0], t2);
340 // | brace epilog {$$=epimung($1, $2);}
342 tok = dropsp(yylex());
343 t2 = epilog(tok, ptok);
344 return epimung(t1, t2);
347 if(!iswordtok(tok)) {
353 // | simple {$$=simplemung($1);}
354 // | assign cmd %prec BANG {$$=mung3($1, $1->child[0], $1->child[1], $2);}
355 // assign: first '=' word {$$=tree2('=', $1, $3);}
356 // Note: first is same as word except for disallowing all the leading keywords,
357 // but all those keywords have been picked off in the switch above.
358 // Except NOT, but disallowing that in yacc was likely a mistake anyway:
359 // there's no ambiguity in not=1 or not x y z.
360 t1 = yyword(tok, &tok, 0);
363 // Note: cmd2: {x=1 true | echo $x} echoes 1.
364 t1 = tree2('=', t1, yyword(yylex(), &tok, 1));
365 t2 = cmd2(tok, ptok);
366 return mung3(t1, t1->child[0], t1->child[1], t2);
370 // | simple word {$$=tree2(ARGLIST, $1, $2);}
371 // | simple redir {$$=tree2(ARGLIST, $1, $2);}
373 if(tok == REDIR || tok == DUP) {
374 t1 = tree2(ARGLIST, t1, yyredir(tok, &tok));
375 } else if(iswordtok(tok)) {
376 t1 = tree2(ARGLIST, t1, yyword(tok, &tok, 1));
382 return simplemung(t1);
386 words(int tok, int *ptok)
390 // words: {$$=(tree*)0;}
391 // | words word {$$=tree2(WORDS, $1, $2);}
395 while(iswordtok(tok))
396 t = tree2(WORDS, t, yyword(tok, &tok, 1));
402 yyword(int tok, int *ptok, int eqok)
406 // word: keyword {lastword=1; $1->type=WORD;}
408 // | word '^' word {$$=tree2('^', $1, $3);}
409 // comword: '$' word {$$=tree1('$', $2);}
410 // | '$' word SUB words ')' {$$=tree2(SUB, $2, $4);}
411 // | '"' word {$$=tree1('"', $2);}
412 // | COUNT word {$$=tree1(COUNT, $2);}
414 // | '`' brace {$$=tree1('`', $2);}
415 // | '(' words ')' {$$=tree1(PAREN, $2);}
416 // | REDIR brace {$$=mung1($1, $2); $$->type=PIPEFD;}
417 // keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN
424 // word1: keyword | comword
426 t = word1(tok, &tok);
427 if(tok == '=' && !eqok)
431 // No free carats around parens.
432 if(t->type == PAREN || tok == '(')
434 t = tree2('^', t, word1(tok, &tok));
439 t = tree2('^', t, word1(yylex(), &tok));
450 word1(int tok, int *ptok)
471 // keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN
479 return token("=", WORD);
482 // comword: '$' word1 {$$=tree1('$', $2);}
483 // | '$' word1 SUB words ')' {$$=tree2(SUB, $2, $4);}
484 w = word1(yylex(), &tok);
486 sub = words(yylex(), &tok);
490 return tree2(SUB, w, sub);
493 return tree1('$', w);
496 // | '"' word1 {$$=tree1('"', $2);}
497 return tree1('"', word1(yylex(), ptok));
500 // | COUNT word1 {$$=tree1(COUNT, $2);}
501 return tree1(COUNT, word1(yylex(), ptok));
504 // | '`' brace {$$=tree1('`', $2);}
505 t = tree1('`', brace(yylex()));
510 // | '(' words ')' {$$=tree1(PAREN, $2);}
511 t = tree1(PAREN, words(yylex(), &tok));
518 // | REDIRW brace {$$=mung1($1, $2); $$->type=PIPEFD;}
520 t = mung1(t, brace(yylex()));