home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume20 / rc / part03 / parse.y < prev    next >
Encoding:
Text File  |  1991-05-22  |  5.1 KB  |  160 lines

  1. /* parse.y */
  2.  
  3. /*
  4.  * Adapted from rc grammar, v10 manuals, volume 2.
  5.  */
  6.  
  7. %{
  8. #include "stddef.h"
  9. #include "node.h"
  10. #include "lex.h"
  11. #include "tree.h"
  12. #include "heredoc.h"
  13. #include "parse.h"
  14. #include "utils.h"
  15. #undef NULL
  16. #define NULL 0
  17. #undef lint
  18. #define lint        /* hush up gcc -Wall, leave out the dumb sccsid's. */
  19. static Node *star, *nolist;
  20. Node *parsetree;    /* not using yylval because bison declares it as an auto */
  21. %}
  22.  
  23. %term BANG DUP ELSE END FN FOR HUH IF IN LBRACK PIPE RBRACK
  24. %term REDIR STAR SUB SUBSHELL SWITCH TWIDDLE WHILE WORD
  25.  
  26. %left IF WHILE FOR SWITCH ')' ELSE
  27. %left ANDAND OROR
  28. %left BANG SUBSHELL
  29. %left PIPE
  30. %left '^'
  31. %right '$' COUNT FLAT
  32. %left SUB
  33. %left '`' BACKBACK
  34.  
  35. %union {
  36.     struct Node *node;
  37.     struct Redir redir;
  38.     struct Pipe pipe;
  39.     struct Dup dup;
  40.     struct Word word;
  41.     char *keyword;
  42. }
  43.  
  44. %type <redir> REDIR
  45. %type <pipe> PIPE
  46. %type <dup> DUP
  47. %type <word> WORD
  48. %type <keyword> keyword
  49. %type <node> assign body brace cmd cmdsa cmdsan comword epilog
  50.          first line paren redir simple iftail word words
  51.  
  52. %start rc
  53.  
  54. %%
  55.  
  56. rc    : line end        { parsetree = $1; return 1; }
  57.     | error end        { yyerrok; parsetree = NULL; return -1; }
  58.  
  59. /* an rc line may end in end-of-file as well as newline, e.g., rc -c 'ls' */
  60. end    : END    /* EOF */    { heredoc(1); } /* flag error if there is a heredoc in the queue */
  61.     | '\n'            { heredoc(0); } /* get heredoc on \n */
  62.  
  63. /* a cmdsa is a command followed by ampersand or newline (used in "line" and "body") */
  64. cmdsa    : cmd ';'
  65.     | cmd '&'        { $$ = ($1 != NULL ? newnode(NOWAIT,$1) : $1); }
  66.  
  67. /* a line is a single command, or a command terminated by ; or & followed by a line (recursive) */
  68. line    : cmd
  69.     | cmdsa line        { $$ = ($1 != NULL ? newnode(BODY,$1,$2) : $2); }
  70.  
  71. /* a body is like a line, only commands may also be terminated by newline */
  72. body    : cmd
  73.     | cmdsan body        { $$ = ($1 != NULL ? newnode(BODY,$1,$2) : $2); }
  74.  
  75. cmdsan    : cmdsa
  76.     | cmd '\n'        { $$ = $1; heredoc(0); } /* get h.d. on \n */
  77.  
  78. brace    : '{' body '}'        { $$ = $2; }
  79.  
  80. paren    : '(' body ')'        { $$ = $2; }
  81.  
  82. assign    : first '=' word    { $$ = newnode(ASSIGN,$1,$3); }
  83.  
  84. epilog    :            { $$ = NULL; }
  85.     | redir epilog        { $$ = newnode(EPILOG,$1,$2); }
  86.  
  87. /* a redirection is a dup (e.g., >[1=2]) or a file redirection. (e.g., > /dev/null) */
  88. redir    : DUP            { $$ = newnode(rDUP,$1.type,$1.left,$1.right); }
  89.     | REDIR word        { $$ = newnode(rREDIR,$1.type,$1.fd,$2);
  90.                   if ($1.type == HEREDOC) qdoc($2, $$); /* queue heredocs up */
  91.                 }
  92.  
  93. /* the tail of an if statement can be a command, or a braced command followed by else on the same line */
  94. iftail    : cmd %prec IF
  95.     | brace ELSE cmd    { $$ = newnode(rELSE,$1,$3); }
  96.  
  97. /* skipnl() skips newlines and comments between an operator and its operand */
  98. cmd    :                        { $$ = NULL; }
  99.     | simple
  100.     | brace epilog                    { $$ = ($2 == NULL ? $1 : newnode(BRACE,$1,$2)); }
  101.     | IF paren { skipnl(); } iftail            { $$ = newnode(rIF,$2,$4); }
  102.     | FOR '(' word IN words ')' { skipnl(); } cmd    { $$ = newnode(FORIN,$3,$5,$8); }
  103.     | FOR '(' word ')' { skipnl(); } cmd        { $$ = newnode(FORIN,$3,star,$6); }
  104.     | WHILE paren { skipnl(); } cmd            { $$ = newnode(rWHILE,$2,$4); }
  105.     | SWITCH '(' word ')' { skipnl(); } brace    { $$ = newnode(rSWITCH,$3,$6); }
  106.     | TWIDDLE word words                { $$ = newnode(MATCH,$2,$3); }
  107.     | cmd ANDAND { skipnl(); } cmd            { $$ = ($1 != NULL ? newnode(rANDAND,$1,$4) : $4); }
  108.     | cmd OROR { skipnl(); } cmd            { $$ = ($1 != NULL ? newnode(rOROR,$1,$4) : $4); }
  109.      | cmd PIPE { skipnl(); } cmd            { $$ = newnode(rPIPE,$2.left,$2.right,$1,$4); }
  110.     | redir cmd %prec BANG                { $$ = ($2 != NULL ? newnode(PRE,$1,$2) : $1); }
  111.     | assign cmd %prec BANG                { $$ = ($2 != NULL ? newnode(PRE,$1,$2) : $1); }
  112.     | BANG cmd                    { $$ = newnode(rBANG,$2); }
  113.     | SUBSHELL cmd                    { $$ = newnode(rSUBSHELL,$2); }
  114.     | FN words brace                { $$ = newnode(NEWFN,$2,$3); }
  115.     | FN words                    { $$ = newnode(RMFN,$2); }
  116.  
  117. simple    : first
  118.     | simple word            { $$ = ($2 != NULL ? newnode(ARGS,$1,$2) : $1); }
  119.     | simple redir            { $$ = newnode(ARGS,$1,$2); }
  120.  
  121. first    : comword
  122.     | first '^' word        { $$ = newnode(CONCAT,$1,$3); }
  123.  
  124. word    : comword
  125.     | keyword            { $$ = newnode(rWORD,$1, NULL); }
  126.     | word '^' word            { $$ = newnode(CONCAT,$1,$3); }
  127.  
  128. comword    : '$' word            { $$ = newnode(VAR,$2); }
  129.     | '$' word SUB words ')'    { $$ = newnode(VARSUB,$2,$4); }
  130.     | COUNT word            { $$ = newnode(rCOUNT,$2); }
  131.     | FLAT word            { $$ = newnode(rFLAT, $2); }
  132.     | WORD                { $$ = newnode(rWORD,$1.w, $1.m); }
  133.     | '`' word            { $$ = newnode(BACKQ,nolist,$2); }
  134.     | '`' brace            { $$ = newnode(BACKQ,nolist,$2); }
  135.     | BACKBACK word    brace        { $$ = newnode(BACKQ,$2,$3); }
  136.     | BACKBACK word    word        { $$ = newnode(BACKQ,$2,$3); }
  137.     | '(' words ')'            { $$ = $2; }
  138.     | REDIR brace            { $$ = newnode(NMPIPE,$1.type,$1.fd,$2); }
  139.  
  140. keyword    : FOR        { $$ = "for"; }
  141.     | IN        { $$ = "in"; }
  142.     | WHILE        { $$ = "while"; }
  143.     | IF        { $$ = "if"; }
  144.     | SWITCH    { $$ = "switch"; }
  145.     | FN        { $$ = "fn"; }
  146.     | ELSE        { $$ = "else"; }
  147.     | TWIDDLE    { $$ = "~"; }
  148.     | BANG        { $$ = "!"; }
  149.     | SUBSHELL    { $$ = "@"; }
  150.  
  151. words    :        { $$ = NULL; }
  152.     | words word    { $$ = ($1 != NULL ? ($2 != NULL ? newnode(LAPPEND,$1,$2) : $1) : $2); }
  153.  
  154. %%
  155.  
  156. void initparse() {
  157.     star = treecpy(newnode(VAR,newnode(rWORD,"*",NULL)), ealloc);
  158.     nolist = treecpy(newnode(VAR,newnode(rWORD,"ifs",NULL)), ealloc);
  159. }
  160.