xref: /plan9-contrib/sys/src/cmd/rc/lex.c (revision c6df144405f586b73992827d584728dc975dff14)
13e12c5d1SDavid du Colombier #include "rc.h"
23e12c5d1SDavid du Colombier #include "exec.h"
33e12c5d1SDavid du Colombier #include "io.h"
43e12c5d1SDavid du Colombier #include "fns.h"
5*c6df1444SDavid du Colombier 
6*c6df1444SDavid du Colombier Rune getnext(void);
7dc5a79c1SDavid du Colombier 
8dc5a79c1SDavid du Colombier int
wordchr(Rune c)9*c6df1444SDavid du Colombier wordchr(Rune c)		/* is c in the alphabet of words (non-delimiters)? */
103e12c5d1SDavid du Colombier {
11*c6df1444SDavid du Colombier 	return c != EOF &&
12*c6df1444SDavid du Colombier 		(c >= Runeself || strchr("\n \t#;&|^$=`'{}()<>", c) == nil);
133e12c5d1SDavid du Colombier }
14dc5a79c1SDavid du Colombier 
15*c6df1444SDavid du Colombier /*
16*c6df1444SDavid du Colombier  * is c in the alphabet of identifiers?  as in the c compiler, treat
17*c6df1444SDavid du Colombier  * non-ascii as alphabetic.
18*c6df1444SDavid du Colombier  */
19dc5a79c1SDavid du Colombier int
idchr(Rune c)20*c6df1444SDavid du Colombier idchr(Rune c)
213e12c5d1SDavid du Colombier {
223e12c5d1SDavid du Colombier 	/*
233e12c5d1SDavid du Colombier 	 * Formerly:
243e12c5d1SDavid du Colombier 	 * return 'a'<=c && c<='z' || 'A'<=c && c<='Z' || '0'<=c && c<='9'
253e12c5d1SDavid du Colombier 	 *	|| c=='_' || c=='*';
263e12c5d1SDavid du Colombier 	 */
27*c6df1444SDavid du Colombier 	return c != EOF && (c >= Runeself ||
28*c6df1444SDavid du Colombier 		c > ' ' &&
29*c6df1444SDavid du Colombier 		  strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c) == nil);
303e12c5d1SDavid du Colombier }
31*c6df1444SDavid du Colombier 
32*c6df1444SDavid du Colombier Rune future = EOF;
333e12c5d1SDavid du Colombier int doprompt = 1;
34*c6df1444SDavid du Colombier int inquote;		/* are we processing a quoted word ('...')? */
35*c6df1444SDavid du Colombier int incomm;		/* are we ignoring input in a comment (#...\n)? */
363e12c5d1SDavid du Colombier /*
373e12c5d1SDavid du Colombier  * Look ahead in the input stream
383e12c5d1SDavid du Colombier  */
39dc5a79c1SDavid du Colombier 
40*c6df1444SDavid du Colombier Rune
nextc(void)41dc5a79c1SDavid du Colombier nextc(void)
42dc5a79c1SDavid du Colombier {
43dc5a79c1SDavid du Colombier 	if(future==EOF)
44dc5a79c1SDavid du Colombier 		future = getnext();
453e12c5d1SDavid du Colombier 	return future;
463e12c5d1SDavid du Colombier }
473e12c5d1SDavid du Colombier /*
483e12c5d1SDavid du Colombier  * Consume the lookahead character.
493e12c5d1SDavid du Colombier  */
50dc5a79c1SDavid du Colombier 
51*c6df1444SDavid du Colombier Rune
advance(void)52dc5a79c1SDavid du Colombier advance(void)
53dc5a79c1SDavid du Colombier {
54*c6df1444SDavid du Colombier 	Rune c = nextc();
55*c6df1444SDavid du Colombier 
563e12c5d1SDavid du Colombier 	lastc = future;
573e12c5d1SDavid du Colombier 	future = EOF;
583e12c5d1SDavid du Colombier 	return c;
593e12c5d1SDavid du Colombier }
603e12c5d1SDavid du Colombier /*
613e12c5d1SDavid du Colombier  * read a character from the input stream
623e12c5d1SDavid du Colombier  */
63dc5a79c1SDavid du Colombier 
64*c6df1444SDavid du Colombier Rune
getnext(void)65dc5a79c1SDavid du Colombier getnext(void)
66dc5a79c1SDavid du Colombier {
67*c6df1444SDavid du Colombier 	Rune c;
68*c6df1444SDavid du Colombier 	char buf[UTFmax+1];
69*c6df1444SDavid du Colombier 	static Rune peekc = EOF;
70*c6df1444SDavid du Colombier 
713e12c5d1SDavid du Colombier 	if(peekc!=EOF){
723e12c5d1SDavid du Colombier 		c = peekc;
733e12c5d1SDavid du Colombier 		peekc = EOF;
743e12c5d1SDavid du Colombier 		return c;
753e12c5d1SDavid du Colombier 	}
76dc5a79c1SDavid du Colombier 	if(runq->eof)
77dc5a79c1SDavid du Colombier 		return EOF;
78dc5a79c1SDavid du Colombier 	if(doprompt)
79dc5a79c1SDavid du Colombier 		pprompt();
80*c6df1444SDavid du Colombier 	rutf(runq->cmdfd, buf, &c);
813e12c5d1SDavid du Colombier 	if(!inquote && c=='\\'){
82*c6df1444SDavid du Colombier 		rutf(runq->cmdfd, buf, &c);
836852fd5aSDavid du Colombier 		if(c=='\n' && !incomm){		/* don't continue a comment */
843e12c5d1SDavid du Colombier 			doprompt = 1;
853e12c5d1SDavid du Colombier 			c=' ';
863e12c5d1SDavid du Colombier 		}
873e12c5d1SDavid du Colombier 		else{
883e12c5d1SDavid du Colombier 			peekc = c;
893e12c5d1SDavid du Colombier 			c='\\';
903e12c5d1SDavid du Colombier 		}
913e12c5d1SDavid du Colombier 	}
923e12c5d1SDavid du Colombier 	doprompt = doprompt || c=='\n' || c==EOF;
93dc5a79c1SDavid du Colombier 	if(c==EOF)
94dc5a79c1SDavid du Colombier 		runq->eof++;
953e12c5d1SDavid du Colombier 	else if(flag['V'] || ndot>=2 && flag['v']) pchr(err, c);
963e12c5d1SDavid du Colombier 	return c;
973e12c5d1SDavid du Colombier }
98dc5a79c1SDavid du Colombier 
99dc5a79c1SDavid du Colombier void
pprompt(void)100dc5a79c1SDavid du Colombier pprompt(void)
101dc5a79c1SDavid du Colombier {
1023e12c5d1SDavid du Colombier 	var *prompt;
1033e12c5d1SDavid du Colombier 	if(runq->iflag){
1043e12c5d1SDavid du Colombier 		pstr(err, promptstr);
1053e12c5d1SDavid du Colombier 		flush(err);
1063e12c5d1SDavid du Colombier 		prompt = vlook("prompt");
1073e12c5d1SDavid du Colombier 		if(prompt->val && prompt->val->next)
1083e12c5d1SDavid du Colombier 			promptstr = prompt->val->next->word;
1093e12c5d1SDavid du Colombier 		else
1103e12c5d1SDavid du Colombier 			promptstr="\t";
1113e12c5d1SDavid du Colombier 	}
1123e12c5d1SDavid du Colombier 	runq->lineno++;
1133e12c5d1SDavid du Colombier 	doprompt = 0;
1143e12c5d1SDavid du Colombier }
115dc5a79c1SDavid du Colombier 
116dc5a79c1SDavid du Colombier void
skipwhite(void)117dc5a79c1SDavid du Colombier skipwhite(void)
118dc5a79c1SDavid du Colombier {
119*c6df1444SDavid du Colombier 	Rune c;
120*c6df1444SDavid du Colombier 
1213e12c5d1SDavid du Colombier 	for(;;){
1223e12c5d1SDavid du Colombier 		c = nextc();
1236852fd5aSDavid du Colombier 		/* Why did this used to be  if(!inquote && c=='#') ?? */
1246852fd5aSDavid du Colombier 		if(c=='#'){
1256852fd5aSDavid du Colombier 			incomm = 1;
1263e12c5d1SDavid du Colombier 			for(;;){
1273e12c5d1SDavid du Colombier 				c = nextc();
1286852fd5aSDavid du Colombier 				if(c=='\n' || c==EOF) {
1296852fd5aSDavid du Colombier 					incomm = 0;
130dc5a79c1SDavid du Colombier 					break;
1316852fd5aSDavid du Colombier 				}
1323e12c5d1SDavid du Colombier 				advance();
1333e12c5d1SDavid du Colombier 			}
1343e12c5d1SDavid du Colombier 		}
135dc5a79c1SDavid du Colombier 		if(c==' ' || c=='\t')
136dc5a79c1SDavid du Colombier 			advance();
1373e12c5d1SDavid du Colombier 		else return;
1383e12c5d1SDavid du Colombier 	}
1393e12c5d1SDavid du Colombier }
140dc5a79c1SDavid du Colombier 
141dc5a79c1SDavid du Colombier void
skipnl(void)142dc5a79c1SDavid du Colombier skipnl(void)
143dc5a79c1SDavid du Colombier {
144*c6df1444SDavid du Colombier 	Rune c, c0;
145*c6df1444SDavid du Colombier 
146*c6df1444SDavid du Colombier 	for(c0 = nextc(); ; c0 = c){
1473e12c5d1SDavid du Colombier 		skipwhite();
1483e12c5d1SDavid du Colombier 		c = nextc();
149*c6df1444SDavid du Colombier 		if(c != c0)
150*c6df1444SDavid du Colombier 			lastword = 0; /* change of whitespace or c is not ws */
151dc5a79c1SDavid du Colombier 		if(c!='\n')
152dc5a79c1SDavid du Colombier 			return;
153*c6df1444SDavid du Colombier 		lastword = 0;			/* new line; continue */
1543e12c5d1SDavid du Colombier 		advance();
1553e12c5d1SDavid du Colombier 	}
1563e12c5d1SDavid du Colombier }
157dc5a79c1SDavid du Colombier 
158dc5a79c1SDavid du Colombier int
nextis(Rune c)159*c6df1444SDavid du Colombier nextis(Rune c)
160dc5a79c1SDavid du Colombier {
1613e12c5d1SDavid du Colombier 	if(nextc()==c){
1623e12c5d1SDavid du Colombier 		advance();
1633e12c5d1SDavid du Colombier 		return 1;
1643e12c5d1SDavid du Colombier 	}
1653e12c5d1SDavid du Colombier 	return 0;
1663e12c5d1SDavid du Colombier }
167dc5a79c1SDavid du Colombier 
168dc5a79c1SDavid du Colombier char*
addutf(char * p,Rune c)169*c6df1444SDavid du Colombier addutf(char *p, Rune c)
170dc5a79c1SDavid du Colombier {
171dc5a79c1SDavid du Colombier 	if(p==0)
172dc5a79c1SDavid du Colombier 		return 0;
173*c6df1444SDavid du Colombier 	if(p >= &tok[NTOK-1-UTFmax*2]){
1743e12c5d1SDavid du Colombier 		*p = 0;
1753e12c5d1SDavid du Colombier 		yyerror("token buffer too short");
1763e12c5d1SDavid du Colombier 		return 0;
1773e12c5d1SDavid du Colombier 	}
178*c6df1444SDavid du Colombier 	p += runetochar(p, &c);
1793e12c5d1SDavid du Colombier 	return p;
1803e12c5d1SDavid du Colombier }
18182726826SDavid du Colombier 
1823e12c5d1SDavid du Colombier int lastdol;	/* was the last token read '$' or '$#' or '"'? */
1833e12c5d1SDavid du Colombier int lastword;	/* was the last token read a word or compound word terminator? */
184dc5a79c1SDavid du Colombier 
185dc5a79c1SDavid du Colombier int
yylex(void)186dc5a79c1SDavid du Colombier yylex(void)
187dc5a79c1SDavid du Colombier {
188*c6df1444SDavid du Colombier 	Rune c, d = nextc();
189dc5a79c1SDavid du Colombier 	char *w = tok;
190dc5a79c1SDavid du Colombier 	struct tree *t;
191*c6df1444SDavid du Colombier 
1923e12c5d1SDavid du Colombier 	yylval.tree = 0;
1933e12c5d1SDavid du Colombier 	/*
194*c6df1444SDavid du Colombier 	 * Embarrassing sneakiness: if the last token read was a quoted or
195*c6df1444SDavid du Colombier 	 * unquoted WORD then we alter the meaning of what follows.  If the
196*c6df1444SDavid du Colombier 	 * next character is `(', we return SUB (a subscript paren) and
197*c6df1444SDavid du Colombier 	 * consume the `('.  Otherwise, if the next character is the first
198*c6df1444SDavid du Colombier 	 * character of a simple or compound word, we insert a `^' before it.
1993e12c5d1SDavid du Colombier 	 */
2003e12c5d1SDavid du Colombier 	if(lastword){
2013e12c5d1SDavid du Colombier 		lastword = 0;
2023e12c5d1SDavid du Colombier 		if(d=='('){
2033e12c5d1SDavid du Colombier 			advance();
2043e12c5d1SDavid du Colombier 			strcpy(tok, "( [SUB]");
2053e12c5d1SDavid du Colombier 			return SUB;
2063e12c5d1SDavid du Colombier 		}
2073e12c5d1SDavid du Colombier 		if(wordchr(d) || d=='\'' || d=='`' || d=='$' || d=='"'){
2083e12c5d1SDavid du Colombier 			strcpy(tok, "^");
2093e12c5d1SDavid du Colombier 			return '^';
2103e12c5d1SDavid du Colombier 		}
2113e12c5d1SDavid du Colombier 	}
2123e12c5d1SDavid du Colombier 	skipwhite();
2133e12c5d1SDavid du Colombier 	switch(c = advance()){
2143e12c5d1SDavid du Colombier 	case EOF:
2153e12c5d1SDavid du Colombier 		lastdol = 0;
2163e12c5d1SDavid du Colombier 		strcpy(tok, "EOF");
2173e12c5d1SDavid du Colombier 		return EOF;
2183e12c5d1SDavid du Colombier 	case '$':
2193e12c5d1SDavid du Colombier 		lastdol = 1;
2203e12c5d1SDavid du Colombier 		if(nextis('#')){
2213e12c5d1SDavid du Colombier 			strcpy(tok, "$#");
2223e12c5d1SDavid du Colombier 			return COUNT;
2233e12c5d1SDavid du Colombier 		}
2243e12c5d1SDavid du Colombier 		if(nextis('"')){
2253e12c5d1SDavid du Colombier 			strcpy(tok, "$\"");
2263e12c5d1SDavid du Colombier 			return '"';
2273e12c5d1SDavid du Colombier 		}
2283e12c5d1SDavid du Colombier 		strcpy(tok, "$");
2293e12c5d1SDavid du Colombier 		return '$';
2303e12c5d1SDavid du Colombier 	case '&':
2313e12c5d1SDavid du Colombier 		lastdol = 0;
2323e12c5d1SDavid du Colombier 		if(nextis('&')){
2333e12c5d1SDavid du Colombier 			skipnl();
2343e12c5d1SDavid du Colombier 			strcpy(tok, "&&");
2353e12c5d1SDavid du Colombier 			return ANDAND;
2363e12c5d1SDavid du Colombier 		}
2373e12c5d1SDavid du Colombier 		strcpy(tok, "&");
2383e12c5d1SDavid du Colombier 		return '&';
2393e12c5d1SDavid du Colombier 	case '|':
2403e12c5d1SDavid du Colombier 		lastdol = 0;
2413e12c5d1SDavid du Colombier 		if(nextis(c)){
2423e12c5d1SDavid du Colombier 			skipnl();
2433e12c5d1SDavid du Colombier 			strcpy(tok, "||");
2443e12c5d1SDavid du Colombier 			return OROR;
2453e12c5d1SDavid du Colombier 		}
2463e12c5d1SDavid du Colombier 	case '<':
2473e12c5d1SDavid du Colombier 	case '>':
2483e12c5d1SDavid du Colombier 		lastdol = 0;
2493e12c5d1SDavid du Colombier 		/*
2503e12c5d1SDavid du Colombier 		 * funny redirection tokens:
2513e12c5d1SDavid du Colombier 		 *	redir:	arrow | arrow '[' fd ']'
2523e12c5d1SDavid du Colombier 		 *	arrow:	'<' | '<<' | '>' | '>>' | '|'
2533e12c5d1SDavid du Colombier 		 *	fd:	digit | digit '=' | digit '=' digit
2543e12c5d1SDavid du Colombier 		 *	digit:	'0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
2553e12c5d1SDavid du Colombier 		 * some possibilities are nonsensical and get a message.
2563e12c5d1SDavid du Colombier 		 */
2573e12c5d1SDavid du Colombier 		*w++=c;
2583e12c5d1SDavid du Colombier 		t = newtree();
2593e12c5d1SDavid du Colombier 		switch(c){
2603e12c5d1SDavid du Colombier 		case '|':
2613e12c5d1SDavid du Colombier 			t->type = PIPE;
2623e12c5d1SDavid du Colombier 			t->fd0 = 1;
2633e12c5d1SDavid du Colombier 			t->fd1 = 0;
2643e12c5d1SDavid du Colombier 			break;
2653e12c5d1SDavid du Colombier 		case '>':
2663e12c5d1SDavid du Colombier 			t->type = REDIR;
2673e12c5d1SDavid du Colombier 			if(nextis(c)){
2683e12c5d1SDavid du Colombier 				t->rtype = APPEND;
2693e12c5d1SDavid du Colombier 				*w++=c;
2703e12c5d1SDavid du Colombier 			}
2713e12c5d1SDavid du Colombier 			else t->rtype = WRITE;
2723e12c5d1SDavid du Colombier 			t->fd0 = 1;
2733e12c5d1SDavid du Colombier 			break;
2743e12c5d1SDavid du Colombier 		case '<':
2753e12c5d1SDavid du Colombier 			t->type = REDIR;
2763e12c5d1SDavid du Colombier 			if(nextis(c)){
2773e12c5d1SDavid du Colombier 				t->rtype = HERE;
2783e12c5d1SDavid du Colombier 				*w++=c;
279119a69faSDavid du Colombier 			} else if (nextis('>')){
280119a69faSDavid du Colombier 				t->rtype = RDWR;
281119a69faSDavid du Colombier 				*w++=c;
282119a69faSDavid du Colombier 			} else t->rtype = READ;
2833e12c5d1SDavid du Colombier 			t->fd0 = 0;
2843e12c5d1SDavid du Colombier 			break;
2853e12c5d1SDavid du Colombier 		}
2863e12c5d1SDavid du Colombier 		if(nextis('[')){
2873e12c5d1SDavid du Colombier 			*w++='[';
2883e12c5d1SDavid du Colombier 			c = advance();
2893e12c5d1SDavid du Colombier 			*w++=c;
2903e12c5d1SDavid du Colombier 			if(c<'0' || '9'<c){
2913e12c5d1SDavid du Colombier 			RedirErr:
2923e12c5d1SDavid du Colombier 				*w = 0;
2933e12c5d1SDavid du Colombier 				yyerror(t->type==PIPE?"pipe syntax"
2943e12c5d1SDavid du Colombier 						:"redirection syntax");
2953e12c5d1SDavid du Colombier 				return EOF;
2963e12c5d1SDavid du Colombier 			}
2973e12c5d1SDavid du Colombier 			t->fd0 = 0;
2983e12c5d1SDavid du Colombier 			do{
2993e12c5d1SDavid du Colombier 				t->fd0 = t->fd0*10+c-'0';
3003e12c5d1SDavid du Colombier 				*w++=c;
3013e12c5d1SDavid du Colombier 				c = advance();
3023e12c5d1SDavid du Colombier 			}while('0'<=c && c<='9');
3033e12c5d1SDavid du Colombier 			if(c=='='){
3043e12c5d1SDavid du Colombier 				*w++='=';
305dc5a79c1SDavid du Colombier 				if(t->type==REDIR)
306dc5a79c1SDavid du Colombier 					t->type = DUP;
3073e12c5d1SDavid du Colombier 				c = advance();
3083e12c5d1SDavid du Colombier 				if('0'<=c && c<='9'){
3093e12c5d1SDavid du Colombier 					t->rtype = DUPFD;
3103e12c5d1SDavid du Colombier 					t->fd1 = t->fd0;
3113e12c5d1SDavid du Colombier 					t->fd0 = 0;
3123e12c5d1SDavid du Colombier 					do{
3133e12c5d1SDavid du Colombier 						t->fd0 = t->fd0*10+c-'0';
3143e12c5d1SDavid du Colombier 						*w++=c;
3153e12c5d1SDavid du Colombier 						c = advance();
3163e12c5d1SDavid du Colombier 					}while('0'<=c && c<='9');
3173e12c5d1SDavid du Colombier 				}
3183e12c5d1SDavid du Colombier 				else{
319dc5a79c1SDavid du Colombier 					if(t->type==PIPE)
320dc5a79c1SDavid du Colombier 						goto RedirErr;
3213e12c5d1SDavid du Colombier 					t->rtype = CLOSE;
3223e12c5d1SDavid du Colombier 				}
3233e12c5d1SDavid du Colombier 			}
3243e12c5d1SDavid du Colombier 			if(c!=']'
3253e12c5d1SDavid du Colombier 			|| t->type==DUP && (t->rtype==HERE || t->rtype==APPEND))
3263e12c5d1SDavid du Colombier 				goto RedirErr;
3273e12c5d1SDavid du Colombier 			*w++=']';
3283e12c5d1SDavid du Colombier 		}
3293e12c5d1SDavid du Colombier 		*w='\0';
3303e12c5d1SDavid du Colombier 		yylval.tree = t;
331dc5a79c1SDavid du Colombier 		if(t->type==PIPE)
332dc5a79c1SDavid du Colombier 			skipnl();
3333e12c5d1SDavid du Colombier 		return t->type;
3343e12c5d1SDavid du Colombier 	case '\'':
3353e12c5d1SDavid du Colombier 		lastdol = 0;
3363e12c5d1SDavid du Colombier 		lastword = 1;
3373e12c5d1SDavid du Colombier 		inquote = 1;
3383e12c5d1SDavid du Colombier 		for(;;){
3393e12c5d1SDavid du Colombier 			c = advance();
340dc5a79c1SDavid du Colombier 			if(c==EOF)
341dc5a79c1SDavid du Colombier 				break;
3423e12c5d1SDavid du Colombier 			if(c=='\''){
3433e12c5d1SDavid du Colombier 				if(nextc()!='\'')
3443e12c5d1SDavid du Colombier 					break;
3453e12c5d1SDavid du Colombier 				advance();
3463e12c5d1SDavid du Colombier 			}
3473e12c5d1SDavid du Colombier 			w = addutf(w, c);
3483e12c5d1SDavid du Colombier 		}
349dc5a79c1SDavid du Colombier 		if(w!=0)
350dc5a79c1SDavid du Colombier 			*w='\0';
3513e12c5d1SDavid du Colombier 		t = token(tok, WORD);
3523e12c5d1SDavid du Colombier 		t->quoted = 1;
3533e12c5d1SDavid du Colombier 		yylval.tree = t;
354*c6df1444SDavid du Colombier 		inquote = 0;
3553e12c5d1SDavid du Colombier 		return t->type;
3563e12c5d1SDavid du Colombier 	}
3573e12c5d1SDavid du Colombier 	if(!wordchr(c)){
3583e12c5d1SDavid du Colombier 		lastdol = 0;
359*c6df1444SDavid du Colombier 		addutf(tok, c);
3603e12c5d1SDavid du Colombier 		return c;
3613e12c5d1SDavid du Colombier 	}
3623e12c5d1SDavid du Colombier 	for(;;){
3634e3613abSDavid du Colombier 		if(c=='*' || c=='[' || c=='?' || c==GLOB)
364*c6df1444SDavid du Colombier 			w = addutf(w, GLOB);
3653e12c5d1SDavid du Colombier 		w = addutf(w, c);
3663e12c5d1SDavid du Colombier 		c = nextc();
3673e12c5d1SDavid du Colombier 		if(lastdol?!idchr(c):!wordchr(c)) break;
3683e12c5d1SDavid du Colombier 		advance();
3693e12c5d1SDavid du Colombier 	}
3703e12c5d1SDavid du Colombier 	lastword = 1;
3713e12c5d1SDavid du Colombier 	lastdol = 0;
372dc5a79c1SDavid du Colombier 	if(w!=0)
373dc5a79c1SDavid du Colombier 		*w='\0';
3743e12c5d1SDavid du Colombier 	t = klook(tok);
375dc5a79c1SDavid du Colombier 	if(t->type!=WORD)
376dc5a79c1SDavid du Colombier 		lastword = 0;
3773e12c5d1SDavid du Colombier 	t->quoted = 0;
3783e12c5d1SDavid du Colombier 	yylval.tree = t;
3793e12c5d1SDavid du Colombier 	return t->type;
3803e12c5d1SDavid du Colombier }
381