* This file is part of zsh, the Z shell.
* This software is Copyright 1992 by Paul Falstad
* Permission is hereby granted to copy, reproduce, redistribute or otherwise
* use this software as long as: there is no monetary profit gained
* specifically from the use or reproduction of this software, it is not
* sold, rented, traded or otherwise marketed, and this copyright notice is
* included prominently in any copy made.
* The author make no claims as to the fitness or correctness of this software
* for any use whatsoever, and it is provided as is. Any use of this software
* is at the user's own risk.
#define YYERROR { tok = LEXERR; return NULL; }
#define YYERRORV { tok = LEXERR; return; }
#define make_list() allocnode(N_LIST)
#define make_sublist() allocnode(N_SUBLIST)
#define make_pline() allocnode(N_PLINE)
#define make_cmd() allocnode(N_CMD)
#define make_forcmd() allocnode(N_FOR)
#define make_casecmd() allocnode(N_CASE)
#define make_ifcmd() allocnode(N_IF)
#define make_whilecmd() allocnode(N_WHILE)
#define make_varnode() allocnode(N_VARASG)
#define make_cond() allocnode(N_COND)
* | sublist [ SEPER | AMPER ]
if (isnewlin
> 0) return NULL
;
if (tok
== ENDINPUT
) return NULL
;
l
->type
= SYNC
; l
->left
= sl
;
} else if (tok
== SEPER
) {
l
->type
= SYNC
; l
->left
= sl
;
if (isnewlin
<= 0) yylex();
} else if (tok
== AMPER
) {
l
->type
= ASYNC
; l
->left
= sl
;
if (errflag
) { yyerror(); return NULL
; }
while ((c
= hgetc()) != '\n' && !lexstop
);
if (c
== '\n') hungetc('\n');
* list : { SEPER } [ sublist [ { SEPER | AMPER } list ] ]
while (tok
== SEPER
) yylex();
if (tok
== SEPER
|| tok
== AMPER
) {
l
->type
= (tok
== SEPER
) ? SYNC
: ASYNC
;
while (tok
== SEPER
|| tok
== AMPER
) yylex();
if (sl
= par_sublist()) {
* sublist : sublist2 [ ( DBAR | DAMPER ) { SEPER } sublist ]
Sublist
par_sublist() /**/
if (tok
== DBAR
|| tok
== DAMPER
) {
while (tok
== SEPER
) yylex();
sl
->right
= par_sublist();
sl
->type
= (qtok
== DBAR
) ? ORNEXT
: ANDNEXT
;
* sublist2 : [ COPROC | BANG ] pline
Sublist
par_sublist2() /**/
if (tok
== COPROC
) { sl
->flags
|= PFLAG_COPROC
; yylex(); }
else if (tok
== BANG
) { sl
->flags
|= PFLAG_NOT
; yylex(); }
if (!(p
= par_pline()) && !sl
->flags
)
* pline : cmd [ ( BAR | BARAMP ) { SEPER } pline ]
while (tok
== SEPER
) yylex();
p
->left
= c
; p
->right
= p2
; p
->type
= PIPE
;
} else if (tok
== BARAMP
) {
struct redir
*rdr
= alloc(sizeof *rdr
);
rdr
->type
= MERGE
; rdr
->fd1
= 2; rdr
->fd2
= 1;
p
->left
= c
; p
->right
= p2
; p
->type
= PIPE
;
p
->left
= c
; p
->type
= END
;
* cmd : { redir } ( for | case | if | while | repeat |
* subsh | funcdef | time | dinbrack | simple ) { redir }
case FOR
: case FOREACH
: case SELECT
: par_for(c
); break;
case CASE
: par_case(c
); break;
case IF
: par_if(c
); break;
case WHILE
: case UNTIL
: par_while(c
); break;
case REPEAT
: par_repeat(c
); break;
case INPAR
: case INBRACE
: par_subsh(c
); break;
case FUNC
: par_funcdef(c
); break;
case TIME
: par_time(c
); break;
case DINBRACK
: par_dinbrack(c
); break;
default: if (!par_simple(c
)) return NULL
; break;
* for : ( FOR[EACH] | SELECT ) name ( "in" wordlist | INPAR wordlist OUTPAR )
{ SEPER } ( DO list DONE | INBRACE list OUTBRACE |
int csh
= (tok
== FOREACH
|| isset(CSHJUNKIELOOPS
));
c
->type
= (tok
== SELECT
) ? CSELECT
: CFOR
;
if (tok
!= STRING
) YYERRORV
;
if (tok
== STRING
&& !strcmp(tokstr
,"in")) {
c
->args
= par_wordlist();
if (tok
!= SEPER
) YYERRORV
;
} else if (tok
== INPAR
) {
c
->args
= par_nl_wordlist();
if (tok
!= OUTPAR
) YYERRORV
;
while (tok
== SEPER
) yylex();
if (tok
!= DONE
) YYERRORV
;
} else if (tok
== INBRACE
) {
if (tok
!= OUTBRACE
) YYERRORV
;
if (tok
!= ZEND
) YYERRORV
;
} else if (isset(NOSHORTLOOPS
)) {
* case : CASE STRING { SEPER } ( "in" | INBRACE )
{ { SEPER } STRING { BAR STRING } OUTPAR list [ DSEMI ] }
{ SEPER } ( "esac" | OUTBRACE )
if (tok
!= STRING
) YYERRORV
;
while (tok
== SEPER
) yylex();
if (!(tok
== STRING
&& !strcmp(tokstr
,"in")) && tok
!= INBRACE
) YYERRORV
;
brflag
= (tok
== INBRACE
);
*ccp
= cc
= make_casecmd();
while (tok
== SEPER
) yylex();
if (tok
!= STRING
) YYERRORV
;
if (!strcmp(tokstr
,"esac")) {
if (tok
!= STRING
) YYERRORV
;
str2
= alloc(sl
+strlen(tokstr
)+1);
strcpy(str2
+sl
+1,tokstr
);
if (tok
!= OUTPAR
) YYERRORV
;
if ((tok
== ESAC
&& !brflag
) || (tok
== OUTBRACE
&& brflag
)) {
if (tok
!= DSEMI
) YYERRORV
;
* if : { ( IF | ELIF ) { SEPER } ( INPAR list OUTPAR | list )
{ SEPER } ( THEN list | INBRACE list OUTBRACE | list1 ) }
[ FI | ELSE list FI | ELSE { SEPER } INBRACE list OUTBRACE ]
while (tok
== SEPER
) yylex();
if (!(xtok
== IF
|| xtok
== ELIF
)) YYERRORV
;
if (tok
!= OUTPAR
) YYERRORV
;
while (tok
== SEPER
) yylex();
} else if (tok
== INBRACE
) {
if (tok
!= OUTBRACE
) YYERRORV
;
} else if (isset(NOSHORTLOOPS
)) {
if (tok
!= OUTBRACE
) YYERRORV
;
* while : ( WHILE | UNTIL ) ( INPAR list OUTPAR | list ) { SEPER }
( DO list DONE | INBRACE list OUTBRACE | list ZEND )
w
= c
->u
.whilecmd
= make_whilecmd();
w
->cond
= (tok
== UNTIL
);
if (tok
!= OUTPAR
) YYERRORV
;
while (tok
== SEPER
) yylex();
if (tok
!= DONE
) YYERRORV
;
} else if (tok
== INBRACE
) {
if (tok
!= OUTBRACE
) YYERRORV
;
} else if (isset(CSHJUNKIELOOPS
)) {
if (tok
!= ZEND
) YYERRORV
;
* repeat : REPEAT STRING { SEPER } ( DO list DONE | list1 )
if (tok
!= STRING
) YYERRORV
;
while (tok
== SEPER
) yylex();
if (tok
!= DONE
) YYERRORV
;
* subsh : ( INPAR | INBRACE ) list ( OUTPAR | OUTBRACE )
c
->type
= (tok
== INPAR
) ? SUBSH
: CURSH
;
if (tok
!= ((c
->type
== SUBSH
) ? OUTPAR
: OUTBRACE
)) YYERRORV
;
* funcdef : FUNCTION wordlist [ INOUTPAR ] { SEPER }
* ( list1 | INBRACE list OUTBRACE )
if (*tokstr
== Inbrace
&& !tokstr
[1]) { tok
= INBRACE
; break; }
if (tok
== INOUTPAR
) yylex();
while (tok
== SEPER
) yylex();
if (tok
!= OUTBRACE
) YYERRORV
;
} else if (isset(NOSHORTLOOPS
)) {
c
->u
.pline
= par_sublist2();
* dinbrack : DINBRACK cond DOUTBRACK
void par_dinbrack(c
) /**/
if (tok
!= DOUTBRACK
) YYERRORV
;
* simple : { COMMAND | EXEC | NOGLOB | NOCORRECT | DASH }
{ STRING | ENVSTRING | ENVARRAY wordlist OUTPAR | redir }
[ INOUTPAR { SEPER } ( list1 | INBRACE list OUTBRACE ) ]
if (tok
== COMMAND
) c
->flags
|= CFLAG_COMMAND
;
else if (tok
== EXEC
) c
->flags
|= CFLAG_EXEC
;
else if (tok
== NOGLOB
) c
->flags
|= CFLAG_NOGLOB
;
else if (tok
== NOCORRECT
) nocorrect
= 1;
else if (tok
== DASH
) c
->flags
= CFLAG_DASH
;
if (tok
== AMPER
) YYERROR
;
} else if (tok
== ENVSTRING
) {
struct varasg
*v
= make_varnode();
equalsplit(v
->name
= tokstr
,&v
->str
);
} else if (tok
== ENVARRAY
) {
struct varasg
*v
= make_varnode();
int oldcmdpos
= incmdpos
;
v
->arr
= par_nl_wordlist();
if (tok
!= OUTPAR
) YYERROR
;
} else if (IS_REDIROP(tok
)) {
} else if (tok
== INOUTPAR
) {
while (tok
== SEPER
) yylex();
if (tok
!= OUTBRACE
) YYERROR
;
} else if (isset(NOSHORTLOOPS
)) {
if (isnull
&& !full(c
->redir
)) return NULL
;
underscore
= ztrdup(getdata(lastnode(c
->args
)));
* cond : cond_1 { SEPER } [ DBAR { SEPER } cond ]
while (tok
== SEPER
) yylex();
while (tok
== SEPER
) yylex();
* cond_1 : cond_2 { SEPER } [ DAMPER { SEPER } cond_1 ]
while (tok
== SEPER
) yylex();
while (tok
== SEPER
) yylex();
c2
->right
= par_cond_1();
| INPAR { SEPER } cond_2 { SEPER } OUTPAR
| STRING ( INANG | OUTANG ) STRING
while (tok
== SEPER
) yylex();
while (tok
== SEPER
) yylex();
if (tok
!= OUTPAR
) YYERROR
;
if (tok
!= STRING
) YYERROR
;
if (tok
== INANG
|| tok
== OUTANG
) {
if (tok
!= STRING
) YYERROR
;
c
->type
= (xtok
== INANG
) ? COND_STRLT
: COND_STRGTR
;
c
->types
[0] = c
->types
[1] = NT_STR
;
if (tok
!= STRING
) YYERROR
;
return par_cond_triple(s1
,s2
,s3
);
return par_cond_double(s1
,s2
);
* redir : ( OUTANG | ... | TRINANG ) STRING
struct redir
*fn
= allocnode(N_REDIR
);
if (tok
!= INANG
) nocorrect
= 1;
fn
->type
= redirtab
[tok
-OUTANG
];
if (tok
!= STRING
&& tok
!= ENVSTRING
) YYERRORV
;
fn
->fd1
= IS_READFD(fn
->type
) ? 0 : 1;
/* > >(...) or < <(...) */
if ((*toks
== Inang
|| *toks
== Outang
) && toks
[1] == Inpar
) {
if ((fn
->type
& ~1) == WRITE
) fn
->type
= OUTPIPE
;
else if (fn
->type
== READ
) fn
->type
= INPIPE
;
} else if (fn
->type
== HEREDOC
|| fn
->type
== HEREDOCDASH
) {
/* Save the rest of the current line for later tokenization */
while (hgets(tbuf
, 256) != NULL
) {
tlin
= ztrdup(tbuf
); /* Test for failure? */
tlin
= realloc(tlin
,tsiz
+l
+1); /* Test for failure? */
strcpy(&tlin
[tsiz
], tbuf
);
if (tbuf
[l
-1] == '\n') break;
/* Now grab the document */
fn
->name
= gethere(toks
,fn
->type
);
/* Put back the saved line to resume tokenizing */
/* >& name or >>& name */
} else if (IS_ERROR_REDIR(fn
->type
) && getfdstr(toks
) == FD_WORD
) {
fn
->type
= UN_ERROR_REDIR(fn
->type
);
/* >>& and >>&! are only valid with a name after them */
} else if (fn
->type
== ERRAPP
|| fn
->type
== ERRAPPNOW
) {
} else if (fn
->type
== MERGE
|| fn
->type
== MERGEOUT
) {
fn
->fd2
= getfdstr(toks
);
if (fn
->fd2
== FD_CLOSE
) fn
->type
= CLOSE
;
else if (fn
->fd2
== FD_WORD
) fn
->fd2
= (fn
->type
==MERGEOUT
) ? 1 : 0;
struct redir
*fe
= allocnode(N_REDIR
);
Lklist
par_wordlist() /**/
* nl_wordlist : { STRING | SEPER }
Lklist
par_nl_wordlist() /**/
while (tok
== STRING
|| tok
== SEPER
) {
/* get fd associated with str */
if (s
[1]) return FD_WORD
;
if (idigit(*s
)) return *s
-'0';
if (*s
== 'p') return FD_COPROC
;
if (*s
== '-') return FD_CLOSE
;
Cond
par_cond_double(a
,b
) /**/
if (a
[0] != '-' || !a
[1] || a
[2])
zerr("parse error: condition expected: %s",a
,0);
n
->types
[0] = n
->types
[1] = NT_STR
;
Cond
par_cond_triple(a
,b
,c
) /**/
static char *condstrs
[] = {
"nt","ot","ef","eq","ne","lt","gt","le","ge",NULL
if ((b
[0] == Equals
|| b
[0] == '=') && !b
[1])
else if (b
[0] == '!' && b
[1] == '=' && !b
[2])
for (t0
= 0; condstrs
[t0
]; t0
++)
if (!strcmp(condstrs
[t0
],b
+1))
zerr("unrecognized condition: %s",b
,0);
zerr("condition expected: %s",b
,0);
n
->types
[0] = n
->types
[1] = NT_STR
;
for (t0
= 0; t0
!= 20; t0
++)
if (!yytext
[t0
] || yytext
[t0
] == '\n' || yytext
[t0
] == HISTSPACE
)
zerr("parse error near `%l...'",yytext
,20);
zerr("parse error near `%l'",yytext
,t0
);
zerr("parse error",NULL
,0);