Beispiel #1
0
/*
 * Define a user named label to have the offset of the next opcode.
 *
 * given:
 *	name		label name
 */
void
definelabel(char *name)
{
	register LABEL *lp;		/* current label */
	long i;				/* current label index */

	i = findstr(&labelnames, name);
	if (i >= 0) {
		lp = &labels[i];
		if (lp->l_offset >= 0) {
			scanerror(T_NULL, "Label \"%s\" is multiply defined",
				name);
			return;
		}
		setlabel(lp);
		return;
	}
	if (labelcount >= MAXLABELS) {
		scanerror(T_NULL, "Too many labels in use");
		return;
	}
	lp = &labels[labelcount++];
	lp->l_chain = -1L;
	lp->l_offset = (long)curfunc->f_opcodecount;
	lp->l_name = addstr(&labelnames, name);
	clearopt();
}
Beispiel #2
0
static Boolean getfds(int fd[2], int c, int default0, int default1) {
	int n;
	fd[0] = default0;
	fd[1] = default1;

	if (c != '[') {
		UNGETC(c);
		return TRUE;
	}
	if ((unsigned int) (n = GETC() - '0') > 9) {
		scanerror("expected digit after '['");
		return FALSE;
	}

	while ((unsigned int) (c = GETC() - '0') <= 9)
		n = n * 10 + c;
	fd[0] = n;

	switch (c += '0') {
	case '=':
		if ((unsigned int) (n = GETC() - '0') > 9) {
			if (n != ']' - '0') {
				scanerror("expected digit or ']' after '='");
				return FALSE;
			}
			fd[1] = CLOSED;
		} else {
			while ((unsigned int) (c = GETC() - '0') <= 9)
				n = n * 10 + c;
			if (c != ']' - '0') {
				scanerror("expected ']' after digit");
				return FALSE;
			}
			fd[1] = n;
		}
		break;
	case ']':
		break;
	default:
		scanerror("expected '=' or ']' after digit");
		return FALSE;
	}
	return TRUE;
}
Beispiel #3
0
/*
 * Check to make sure that all labels are defined.
 */
void
checklabels(void)
{
	register LABEL *lp;		/* label being checked */
	long i;				/* counter */

	for (i = labelcount, lp = labels; --i >= 0; lp++) {
		if (lp->l_offset >= 0)
			continue;
		scanerror(T_NULL, "Label \"%s\" was never defined",
			lp->l_name);
	}
}
Beispiel #4
0
static void getpair(int c) {
	int n;
	fd_left = fd_right = UNSET;
	if (c != '[') {
		ugchar(c);
		return;
	}
	if ((unsigned int) (n = gchar() - '0') > 9) {
		scanerror("expected digit after '['");
		return;
	}
	while ((unsigned int) (c = gchar() - '0') <= 9)
		n = n * 10 + c;
	fd_left = n;
	c += '0';
	switch (c) {
	default:
		scanerror("expected '=' or ']' after digit");
		return;
	case ']':
		return;
	case '=':
		if ((unsigned int) (n = gchar() - '0') > 9) {
			if (n != ']' - '0') {
				scanerror("expected digit or ']' after '='");
				return;
			}
			fd_right = CLOSED;
		} else {
			while ((unsigned int) (c = gchar() - '0') <= 9)
				n = n * 10 + c;
			if (c != ']' - '0') {
				scanerror("expected ']' after digit");
				return;
			}
			fd_right = n;
		}
	}
}
Beispiel #5
0
/*
 * Add the offset corresponding to the specified user label name to the
 * opcode table for a function. If the label is not yet defined, then a
 * chain of undefined offsets is built using the offset value, and it
 * will be fixed up when the label is defined.
 *
 * given:
 *	name		user symbol name
 */
void
addlabel(char *name)
{
	register LABEL *lp;		/* current label */
	long i;				/* counter */

	for (i = labelcount, lp = labels; --i >= 0; lp++) {
		if (strcmp(name, lp->l_name))
			continue;
		uselabel(lp);
		return;
	}
	if (labelcount >= MAXLABELS) {
		scanerror(T_NULL, "Too many labels in use");
		return;
	}
	lp = &labels[labelcount++];
	lp->l_offset = -1L;
	lp->l_chain = -1L;
	lp->l_name = addstr(&labelnames, name);
	uselabel(lp);
}
Beispiel #6
0
int
s_yylex()
{
	register c;
	register char *cp;
	int f;
	char delim;

if (yylineno == 0)
	incrlineno();

while(1) {
	/*
	 * skip white space
	 */
	if (c = lookaheadchar ) {
		lookaheadchar = 0;
		}
	 else
		c = readkey();

	cp = yytext;
	while (c == ' ' || c == '\t' || c == 0 || c == 12 /* FF */) {
		c = readkey();
	}
	yytext[0] = c; yytext[1] = yytext[2] = 0;
	if( isascii(c) && (isalpha( c ) || c == '_') ) {
		do {
			*cp++ = c;
			c = readkey();
		} while (isascii(c) && (isalnum(c) || c == '_'));
		*cp = 0;

		lookaheadchar = c;
		c = look_kw(yytext);
		clearla();
		if (c == 0) {
			yylval.strval = allocstring(yytext);
			return (YID);
			}
		return c;
		}

	else if( isascii(c) && isdigit(c) ) {
		f = 0;
		do {
			*cp++ = c;
			c = readkey();
		} while (isascii(c) && isdigit(c));
		if (c == '.') {
			c = readkey();
			if (c == '.') {
				*cp = 0;
				lookaheadchar = YDOTDOT;
				yylval.strval = allocstring(yytext);
				return (YINT);
			}
infpnumb:
			f++;
			*cp++ = '.';
			if (!isascii(c) || !isdigit(c)) {
				scanerror("syntax error: digits required after decimal point");
				*cp++ = '0';
			} else
				while (isdigit(c)) {
					*cp++ = c;
					c = readkey();
				}
		}
		if (c == 'e' || c == 'E') {
			f++;
			*cp++ = c;
			if ((c = lookaheadchar) == 0)
				c = readkey();
			if (c == '+' || c == '-') {
				*cp++ = c;
				c = readkey();
			}
			if (!isascii(c) || !isdigit(c)) {
				scanerror("syntax error: digits required in exponent");
				*cp++ = '0';
			} else
				while (isascii(c) && isdigit(c)) {
					*cp++ = c;
					c = readkey();
				}
		}
		*cp = 0;
		lookaheadchar = c;
		clearla();
		yylval.strval = allocstring(yytext);
		if (f)
			return (YNUMB);
		return (YINT);
		}
	printt2("Select on char %d - %c\n", c, c );
	switch (c) {
	case EOF:
		return 0;
	case ' ':
	case '\t':
	case 12: /* form feed */
		break;
	case '"':
	case '\'':
		*cp++ = delim = c;
		do {
			do {
				c = readkey();
				if (c == '\n' || c == EOFCHAR) {
					scanerror("syntax error: unmatched quote for string" );
					if (cp == yytext)
						*cp++ = ' ', cp++;
					return YILLCH;
				}
				*cp++ = c;
			} while (c != delim);
			c = readkey();
		} while (c == delim);
		if( c == '^' || c== '#' ) {
			par_error( "Can't imbed ^A or #nnn codes in strings.  Try concatenating strings together\n" );
			}
		*--cp = 0;
#ifndef TURBO
		if (cp == yytext && delim == '\'') {
			scanerror("syntax error: null string not allowed");
			*cp++ = ' ';
			*cp++ = 0;
		}
#endif
		lookaheadchar = c;
		clearla();
		/* len of 2 means 1 char and 1 quote char */
		if (delim == '"' || strlen(yytext) != 2) {
			yylval.strval = allocstring(yytext);
			return (YSTRING);
			}
		else  {
			yylval.intval = yytext[1];
			return (YCHAR);
			}
	case '.':
		c = readkey();
		if (c == '.')
			return (YDOTDOT);
		if (isdigit(c)) {
			scanerror("syntax error: digits required before decimal point");
			*cp++ = '0';
			goto infpnumb;
		}
		lookaheadchar = c;
		clearla();
		return '.';

	case '\n':
		break;
	case '{': /* { ... } comment */
		delim = '{';
comment:
		c = readkey();
#ifdef TURBO
		if (c == '$' && turbo_flag) {
			f = scanturbo();
			if (f >= 0)
				return f;
			}
		else
#endif
		if (c == '+') {
			/* Stubs generated by alist, we know they use {} */
			f = scanstub();
			if (f == YC_BLCOMMENT) {
				/* Kludge - throw away to keep grammar LALR.
				 * Doesn't matter since they will be generated
				 * in all appropriate places anyway.
				 */
				continue;	/* outer while loop */
			}
			if (f >= 0)
				return f;
		}
		else {
			for (;;) {
				if (delim=='{' && c == '}') {
					break;
				}
				if (c == '\n') {
					/* Break into one line pieces */
					*cp++ = 0;
					savecomment(yytext);
					cp = yytext;
					*cp = 0;
				} else {
					*cp++ = c;
					if (c <= 0) {
						/* nonterminated comment */
						/* This "can't happen" */
						fatal("Bug - nonterm comment");
					}
				}
				c = readkey();
				if (delim=='(' && c == ')' && cp[-1] == '*') {
					*--cp = 0;
					break;
				}
			}
			*cp++ = 0;
		}
		/*
		 * Comments generated by the lister for procedure or
		 * function calls (in parens, ending in =) are ignored.
		 */
		if (parendepth <= 0 || cp[-2] != '=')
			savecomment(yytext);
		clearla();
		cp = yytext;
		*cp = 0;
		if (allowcom)
			return 0;
		break;
	case ':':
		if ((c=readkey()) == '=') {
			*++cp = c;
			return YCOLEQUALS;
			}
		lookaheadchar = c;
		clearla();
		return ':';
	case '(':
		if ((c=readkey()) == '*') {
			delim = '(';
			goto comment;
			}
		lookaheadchar = c;
		clearla();
		parendepth++;
		return '(';
	case ')':
		parendepth--;
		return ')';
	case '$':
		while( isxdigit(c = readkey()) )
			*++cp = c;
		*++cp = 0;
		lookaheadchar = c;
		if( strlen(yytext) <= 1 )	
			return YILLCH;
		yylval.strval = allocstring(yytext);
		return YINT;
	case '#':
		c = readkey();
		if( c == '$' ) {
			unsigned hxnum;
			while( isxdigit(c = readkey()) )
				hxnum = (hxnum << 4) + ((c > '9') ? 9 : 0)
					+ (c & 0xf);

			lookaheadchar = c;
			yylval.intval = hxnum;
			return YCHAR;
			}
		else while (isdigit(c)) {
			*++cp = c;
			c = readkey();
			}
		*++cp = 0;
		lookaheadchar = c;
		yylval.intval = atoi(&yytext[1]);
		return YCHAR;
	case '^':
		c = readkey();
		if (strchr("\\_", c)) {		/* others include []@^ */
			yylval.intval = c & 0x1f;
			return YCHAR;
		}
		else {
			lookaheadchar = c;
			yylval.intval = '^';
			return YPTR;
		}
	case '@':
		yylval.intval = '@';
		return YPTR;
	case ';':
	case ',':
	case '=':
	case '*':
	case '+':
	case '/':
	case '-':
	case '[':
	case ']':
	case '<':
	case '>':
	case '_':
	case '\\':
	case '}':	/* for DO..SET */
		return c;
	case YDOTDOT:
		return YDOTDOT;

	default:
		if (c <= 0)
			return (0);
		do
			lookaheadchar = readkey();
		while (lookaheadchar == c);
		clearla();
		printt1("illegal char in scanner %o\n", c);
		return (YILLCH);
	}
  
  } /* big while */
}
Beispiel #7
0
extern int yylex(void) {
	static Boolean dollar = FALSE;
	int c;
	size_t i;			/* The purpose of all these local assignments is to	*/
	const char *meta;		/* allow optimizing compilers like gcc to load these	*/
	char *buf = tokenbuf;		/* values into registers. On a sparc this is a		*/
	YYSTYPE *y = &yylval;		/* win, in code size *and* execution time		*/

	if (goterror) {
		goterror = FALSE;
		return NL;
	}

	/* rc variable-names may contain only alnum, '*' and '_', so use dnw if we are scanning one. */
	meta = (dollar ? dnw : nw);
	dollar = FALSE;
	if (newline) {
		--input->lineno; /* slight space optimization; print_prompt2() always increments lineno */
		print_prompt2();
		newline = FALSE;
	}
top:	while ((c = GETC()) == ' ' || c == '\t')
		w = NW;
	if (c == EOF)
		return ENDFILE;
	if (!meta[(unsigned char) c]) {	/* it's a word or keyword. */
		InsertFreeCaret();
		w = RW;
		i = 0;
		do {
			buf[i++] = c;
			if (i >= bufsize)
				buf = tokenbuf = erealloc(buf, bufsize *= 2);
		} while ((c = GETC()) != EOF && !meta[(unsigned char) c]);
		UNGETC(c);
		buf[i] = '\0';
		w = KW;
		if (buf[1] == '\0') {
			int k = *buf;
			if (k == '@' || k == '~')
				return k;
		} else if (*buf == 'f') {
			if (streq(buf + 1, "n"))	return FN;
			if (streq(buf + 1, "or"))	return FOR;
		} else if (*buf == 'l') {
			if (streq(buf + 1, "ocal"))	return LOCAL;
			if (streq(buf + 1, "et"))	return LET;
		} else if (streq(buf, "~~"))
			return EXTRACT;
		else if (streq(buf, "%closure"))
			return CLOSURE;
		w = RW;
		y->str = gcdup(buf);
		return WORD;
	}
	if (c == '`' || c == '!' || c == '$' || c == '\'') {
		InsertFreeCaret();
		if (c == '!')
			w = KW;
	}
	switch (c) {
	case '!':
		return '!';
	case '`':
		c = GETC();
		if (c == '`')
			return BACKBACK;
		UNGETC(c);
		return '`';
	case '$':
		dollar = TRUE;
		switch (c = GETC()) {
		case '#':	return COUNT;
		case '^':	return FLAT;
		case '&':	return PRIM;
		default:	UNGETC(c); return '$';
		}
	case '\'':
		w = RW;
		i = 0;
		while ((c = GETC()) != '\'' || (c = GETC()) == '\'') {
			buf[i++] = c;
			if (c == '\n')
				print_prompt2();
			if (c == EOF) {
				w = NW;
				scanerror("eof in quoted string");
				return ERROR;
			}
			if (i >= bufsize)
				buf = tokenbuf = erealloc(buf, bufsize *= 2);
		}
		UNGETC(c);
		buf[i] = '\0';
		y->str = gcdup(buf);
		return QWORD;
	case '\\':
		if ((c = GETC()) == '\n') {
			print_prompt2();
			UNGETC(' ');
			goto top; /* Pretend it was just another space. */
		}
		if (c == EOF) {
			UNGETC(EOF);
			goto badescape;
		}
		UNGETC(c);
		c = '\\';
		InsertFreeCaret();
		w = RW;
		c = GETC();
		switch (c) {
		case 'a':	*buf = '\a';	break;
		case 'b':	*buf = '\b';	break;
		case 'e':	*buf = '\033';	break;
		case 'f':	*buf = '\f';	break;
		case 'n':	*buf = '\n';	break;
		case 'r':	*buf = '\r';	break;
		case 't':	*buf = '\t';	break;
		case 'x': case 'X': {
			int n = 0;
			for (;;) {
				c = GETC();
				if (!isxdigit(c))
					break;
				n = (n << 4)
				  | (c - (isdigit(c) ? '0' : ((islower(c) ? 'a' : 'A') - 0xA)));
			}
			if (n == 0)
				goto badescape;
			UNGETC(c);
			*buf = n;
			break;
		}
		case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': {
			int n = 0;
			do {
				n = (n << 3) | (c - '0');
				c = GETC();
			} while (isodigit(c));
			if (n == 0)
				goto badescape;
			UNGETC(c);
			*buf = n;
			break;
		}
		default:
			if (isalnum(c)) {
			badescape:
				scanerror("bad backslash escape");
				return ERROR;
			}
			*buf = c;
			break;
		}
		buf[1] = 0;
		y->str = gcdup(buf);
		return QWORD;
	case '#':
		while ((c = GETC()) != '\n') /* skip comment until newline */
			if (c == EOF)
				return ENDFILE;
		/* FALLTHROUGH */
	case '\n':
		input->lineno++;
		newline = TRUE;
		w = NW;
		return NL;
	case '(':
		if (w == RW)	/* not keywords, so let & friends work */
			c = SUB;
		/* FALLTHROUGH */
	case ';':
	case '^':
	case ')':
	case '=':
	case '{': case '}':
		w = NW;
		return c;
	case '&':
		w = NW;
		c = GETC();
		if (c == '&')
			return ANDAND;
		UNGETC(c);
		return '&';

	case '|': {
		int p[2];
		w = NW;
		c = GETC();
		if (c == '|')
			return OROR;
		if (!getfds(p, c, 1, 0))
			return ERROR;
		if (p[1] == CLOSED) {
			scanerror("expected digit after '='");	/* can't close a pipe */
			return ERROR;
		}
		y->tree = mk(nPipe, p[0], p[1]);
		return PIPE;
	}

	{
		char *cmd;
		int fd[2];
	case '<':
		fd[0] = 0;
		if ((c = GETC()) == '>')
			if ((c = GETC()) == '>') {
				c = GETC();
				cmd = "%open-append";
			} else
				cmd = "%open-write";
		else if (c == '<')
			if ((c = GETC()) == '<') {
				c = GETC();
				cmd = "%here";
			} else
				cmd = "%heredoc";
		else if (c == '=')
			return CALL;
		else
			cmd = "%open";
		goto redirection;
	case '>':
		fd[0] = 1;
		if ((c = GETC()) == '>')
			if ((c = GETC()) == '<') {
				c = GETC();
				cmd = "%open-append";
			} else
				cmd = "%append";
		else if (c == '<') {
			c = GETC();
			cmd = "%open-create";
		} else
			cmd = "%create";
		goto redirection;
	redirection:
		w = NW;
		if (!getfds(fd, c, fd[0], DEFAULT))
			return ERROR;
		if (fd[1] != DEFAULT) {
			y->tree = (fd[1] == CLOSED)
					? mkclose(fd[0])
					: mkdup(fd[0], fd[1]);
			return DUP;
		}
		y->tree = mkredircmd(cmd, fd[0]);
		return REDIR;
	}

	default:
		assert(c != '\0');
		w = NW;
		return c; /* don't know what it is, let yacc barf on it */
	}
}
Beispiel #8
0
extern int yylex() {
	static bool dollar = FALSE;
	bool saw_meta = FALSE;
	int c;
	SIZE_T i;			/* The purpose of all these local assignments is to	*/
	char *meta;		/* allow optimizing compilers like gcc to load these	*/
	char *buf = realbuf;		/* values into registers. On a sparc this is a		*/
	YYSTYPE *y = &yylval;		/* win, in code size *and* execution time		*/
	if (errset) {
		errset = FALSE;
		return '\n';
	}
	/* rc variable-names may contain only alnum, '*' and '_', so use dnw if we are scanning one. */
	meta = (dollar ? dnw : nw);
	dollar = FALSE;
	if (newline) {
		--lineno; /* slight space optimization; print_prompt2() always increments lineno */
		print_prompt2();
		newline = FALSE;
	}
top:	while ((c = gchar()) == ' ' || c == '\t')
		w = NW;
	if (c == EOF)
		return END;
	if (!meta[(unsigned char) c]) {	/* it's a word or keyword. */
		checkfreecaret;
		w = RW;
		i = 0;
	read:	do {
			buf[i++] = c;
			if (c == '?' || c == '[' || c == '*')
				saw_meta = TRUE;
			if (i >= bufsize)
				buf = realbuf = erealloc(buf, bufsize *= 2);
		} while ((c = gchar()) != EOF && !meta[(unsigned char) c]);
		while (c == '\\') {
			if ((c = gchar()) == '\n') {
				print_prompt2();
				c = ' '; /* Pretend a space was read */
				break;
			} else {
	bs:			if (meta != dnw) { /* all words but varnames may have a bslash */
					buf[i++] = '\\';
					if (i >= bufsize)
						buf = realbuf = erealloc(buf, bufsize *= 2);
					if (!meta[(unsigned char) c])
						goto read;
				} else {
					ugchar(c);
					c = '\\';
					break;
				}
			}
		}
		ugchar(c);
		buf[i] = '\0';
		w = KW;
		if (i == 2) {
			if (*buf == 'i' && buf[1] == 'f') return IF;
			if (*buf == 'f' && buf[1] == 'n') return FN;
			if (*buf == 'i' && buf[1] == 'n') return IN;
		}
		if (streq(buf, "for")) return FOR;
		if (streq(buf, "else")) return ELSE;
		if (streq(buf, "switch")) return SWITCH;
		if (streq(buf, "while")) return WHILE;
		if (streq(buf, "case")) return CASE;
		w = RW;
		y->word.w = ncpy(buf);
		if (saw_meta) {
			char *r, *s;

			y->word.m = nalloc(strlen(buf) + 1);
			for (r = buf, s = y->word.m; *r != '\0'; r++, s++)
				*s = (*r == '?' || *r == '[' || *r == '*');
		} else {
			y->word.m = NULL;
		}
		return WORD;
	}
	if (c == '`' || c == '!' || c == '@' || c == '~' || c == '$' || c == '\'') {
		checkfreecaret;
		if (c == '!' || c == '@' || c == '~')
			w = KW;
	}
	switch (c) {
	case '!':
		return BANG;
	case '@':
		return SUBSHELL;
	case '~':
		return TWIDDLE;
	case '`':
		c = gchar();
		if (c == '`')
			return BACKBACK;
		ugchar(c);
		return '`';
	case '$':
		dollar = TRUE;
		c = gchar();
		if (c == '#')
			return COUNT;
		if (c == '^')
			return FLAT;
		ugchar(c);
		return '$';
	case '\'':
		w = RW;
		i = 0;
		do {
			buf[i++] = c;
			if (c == '\n')
				print_prompt2();
			if (c == EOF) {
				w = NW;
				scanerror("eof in quoted string");
				return HUH;
			}
			if (i >= bufsize)
				buf = realbuf = erealloc(buf, bufsize *= 2);
		} while ((c = gchar()) != '\'' || (c = gchar()) == '\''); /* quote "'" thus: 'how''s it going?' */
		ugchar(c);
		buf[i] = '\0';
		y->word.w = ncpy(buf);
		y->word.m = NULL;
		return WORD;
	case '\\':
		if ((c = gchar()) == '\n') {
			print_prompt2();
			goto top; /* Pretend it was just another space. */
		}
		ugchar(c);
		c = '\\';
		checkfreecaret;
		c = gchar();
		i = 0;
		goto bs;
	case '(':
		if (w == RW) /* SUB's happen only after real words, not keyowrds, so if () and while () work */
			c = SUB;
		w = NW;
		return c;
	case '#':
		while ((c = gchar()) != '\n') /* skip comment until newline */
			if (c == EOF)
				return END;
		/* FALLTHROUGH */
	case '\n':
		lineno++;
		newline = TRUE;
		/* FALLTHROUGH */
	case ';':
	case '^':
	case ')':
	case '=':
	case '{': case '}':
		w = NW;
		return c;
	case '&':
		w = NW;
		c = gchar();
		if (c == '&')
			return ANDAND;
		ugchar(c);
		return '&';
	case '|':
		w = NW;
		c = gchar();
		if (c == '|')
			return OROR;
		getpair(c);
		if (errset)
			return HUH;
		if ((y->pipe.left = fd_left) == UNSET)
			y->pipe.left = 1;				/* default to fd 1 */
		if ((y->pipe.right = fd_right) == UNSET)
			y->pipe.right = 0;				/* default to fd 0 */
		if (y->pipe.right == CLOSED) {
			scanerror("expected digit after '='");		/* can't close a pipe */
			return HUH;
		}
		return PIPE;
	case '>':
		c = gchar();
		if (c == '>') {
			c = gchar();
			y->redir.type = rAppend;
		} else
			y->redir.type = rCreate;
		y->redir.fd = 1;
		goto common;
	case '<':
		c = gchar();
		if (c == '<') {
			c = gchar();
			if (c == '<') {
				c = gchar();
				y->redir.type = rHerestring;
			} else {
				y->redir.type = rHeredoc;
			}
		} else
			y->redir.type = rFrom;
		y->redir.fd = 0;
	common:
		w = NW;
		getpair(c);
		if (errset)
			return HUH;
		if (fd_right == UNSET) { /* redirection, not dup */
			if (fd_left != UNSET) {
				y->redir.fd = fd_left;
				return SREDIR;
			}
			return (y->redir.type == rFrom || y->redir.type == rCreate) ? REDIR : SREDIR;
		} else { /* dup; recast yylval */
			y->dup.type = y->redir.type;
			y->dup.left = fd_left;
			y->dup.right = fd_right;
			return DUP;
		}
	default:
		w = NW;
		return c; /* don't know what it is, let yacc barf on it */
	}
}