Home | History | Annotate | Line # | Download | only in ksh
lex.c revision 1.7
      1  1.7   hubertf /*	$NetBSD: lex.c,v 1.7 1999/10/20 15:49:15 hubertf Exp $	*/
      2  1.2       tls 
      3  1.1       jtc /*
      4  1.1       jtc  * lexical analysis and source input
      5  1.1       jtc  */
      6  1.1       jtc 
      7  1.1       jtc #include "sh.h"
      8  1.1       jtc #include <ctype.h>
      9  1.1       jtc 
     10  1.6   hubertf 
     11  1.6   hubertf /* Structure to keep track of the lexing state and the various pieces of info
     12  1.6   hubertf  * needed for each particular state.
     13  1.6   hubertf  */
     14  1.6   hubertf typedef struct lex_state Lex_state;
     15  1.6   hubertf struct lex_state {
     16  1.6   hubertf 	int ls_state;
     17  1.6   hubertf 	union {
     18  1.6   hubertf 	    /* $(...) */
     19  1.6   hubertf 	    struct scsparen_info {
     20  1.6   hubertf 		    int nparen;		/* count open parenthesis */
     21  1.6   hubertf 		    int csstate; /* XXX remove */
     22  1.6   hubertf #define ls_scsparen ls_info.u_scsparen
     23  1.6   hubertf 	    } u_scsparen;
     24  1.6   hubertf 
     25  1.6   hubertf 	    /* $((...)) */
     26  1.6   hubertf 	    struct sasparen_info {
     27  1.6   hubertf 		    int nparen;		/* count open parenthesis */
     28  1.6   hubertf 		    int start;		/* marks start of $(( in output str */
     29  1.6   hubertf #define ls_sasparen ls_info.u_sasparen
     30  1.6   hubertf 	    } u_sasparen;
     31  1.6   hubertf 
     32  1.6   hubertf 	    /* ((...)) */
     33  1.6   hubertf 	    struct sletparen_info {
     34  1.6   hubertf 		    int nparen;		/* count open parenthesis */
     35  1.6   hubertf #define ls_sletparen ls_info.u_sletparen
     36  1.6   hubertf 	    } u_sletparen;
     37  1.6   hubertf 
     38  1.6   hubertf 	    /* `...` */
     39  1.6   hubertf 	    struct sbquote_info {
     40  1.6   hubertf 		    int indquotes;	/* true if in double quotes: "`...`" */
     41  1.6   hubertf #define ls_sbquote ls_info.u_sbquote
     42  1.6   hubertf 	    } u_sbquote;
     43  1.6   hubertf 
     44  1.6   hubertf 	    Lex_state *base;		/* used to point to next state block */
     45  1.6   hubertf 	} ls_info;
     46  1.6   hubertf };
     47  1.6   hubertf 
     48  1.6   hubertf typedef struct State_info State_info;
     49  1.6   hubertf struct State_info {
     50  1.6   hubertf 	Lex_state	*base;
     51  1.6   hubertf 	Lex_state	*end;
     52  1.6   hubertf };
     53  1.6   hubertf 
     54  1.6   hubertf 
     55  1.1       jtc static void	readhere ARGS((struct ioword *iop));
     56  1.2       tls static int	getsc__ ARGS((void));
     57  1.1       jtc static void	getsc_line ARGS((Source *s));
     58  1.6   hubertf static int	getsc_bn ARGS((void));
     59  1.1       jtc static char	*get_brace_var ARGS((XString *wsp, char *wp));
     60  1.1       jtc static int	arraysub ARGS((char **strp));
     61  1.2       tls static const char *ungetsc ARGS((int c));
     62  1.2       tls static void	gethere ARGS((void));
     63  1.6   hubertf static Lex_state *push_state_ ARGS((State_info *si, Lex_state *old_end));
     64  1.6   hubertf static Lex_state *pop_state_ ARGS((State_info *si, Lex_state *old_end));
     65  1.2       tls 
     66  1.2       tls static int backslash_skip;
     67  1.2       tls static int ignore_backslash_newline;
     68  1.2       tls 
     69  1.2       tls /* optimized getsc_bn() */
     70  1.2       tls #define getsc()		(*source->str != '\0' && *source->str != '\\' \
     71  1.2       tls 			 && !backslash_skip ? *source->str++ : getsc_bn())
     72  1.2       tls /* optimized getsc__() */
     73  1.2       tls #define	getsc_()	((*source->str != '\0') ? *source->str++ : getsc__())
     74  1.1       jtc 
     75  1.6   hubertf #define STATE_BSIZE	32
     76  1.6   hubertf 
     77  1.6   hubertf #define PUSH_STATE(s)	do { \
     78  1.6   hubertf 			    if (++statep == state_info.end) \
     79  1.6   hubertf 				statep = push_state_(&state_info, statep); \
     80  1.6   hubertf 			    state = statep->ls_state = (s); \
     81  1.6   hubertf 			} while (0)
     82  1.6   hubertf 
     83  1.6   hubertf #define POP_STATE()	do { \
     84  1.6   hubertf 			    if (--statep == state_info.base) \
     85  1.6   hubertf 				statep = pop_state_(&state_info, statep); \
     86  1.6   hubertf 			    state = statep->ls_state; \
     87  1.6   hubertf 			} while (0)
     88  1.6   hubertf 
     89  1.6   hubertf 
     90  1.1       jtc 
     91  1.1       jtc /*
     92  1.1       jtc  * Lexical analyzer
     93  1.1       jtc  *
     94  1.1       jtc  * tokens are not regular expressions, they are LL(1).
     95  1.1       jtc  * for example, "${var:-${PWD}}", and "$(size $(whence ksh))".
     96  1.1       jtc  * hence the state stack.
     97  1.1       jtc  */
     98  1.1       jtc 
     99  1.1       jtc int
    100  1.1       jtc yylex(cf)
    101  1.1       jtc 	int cf;
    102  1.1       jtc {
    103  1.6   hubertf 	Lex_state states[STATE_BSIZE], *statep;
    104  1.6   hubertf 	State_info state_info;
    105  1.1       jtc 	register int c, state;
    106  1.1       jtc 	XString ws;		/* expandable output word */
    107  1.1       jtc 	register char *wp;	/* output word pointer */
    108  1.6   hubertf 	char *sp, *dp;
    109  1.6   hubertf 	int c2;
    110  1.1       jtc 
    111  1.1       jtc 
    112  1.1       jtc   Again:
    113  1.6   hubertf 	states[0].ls_state = -1;
    114  1.6   hubertf 	states[0].ls_info.base = (Lex_state *) 0;
    115  1.6   hubertf 	statep = &states[1];
    116  1.6   hubertf 	state_info.base = states;
    117  1.6   hubertf 	state_info.end = &states[STATE_BSIZE];
    118  1.6   hubertf 
    119  1.1       jtc 	Xinit(ws, wp, 64, ATEMP);
    120  1.1       jtc 
    121  1.2       tls 	backslash_skip = 0;
    122  1.2       tls 	ignore_backslash_newline = 0;
    123  1.2       tls 
    124  1.1       jtc 	if (cf&ONEWORD)
    125  1.6   hubertf 		state = SWORD;
    126  1.2       tls #ifdef KSH
    127  1.1       jtc 	else if (cf&LETEXPR) {
    128  1.1       jtc 		*wp++ = OQUOTE;	 /* enclose arguments in (double) quotes */
    129  1.6   hubertf 		state = SLETPAREN;
    130  1.6   hubertf 		statep->ls_sletparen.nparen = 0;
    131  1.2       tls 	}
    132  1.2       tls #endif /* KSH */
    133  1.2       tls 	else {		/* normal lexing */
    134  1.6   hubertf 		state = (cf & HEREDELIM) ? SHEREDELIM : SBASE;
    135  1.1       jtc 		while ((c = getsc()) == ' ' || c == '\t')
    136  1.1       jtc 			;
    137  1.2       tls 		if (c == '#') {
    138  1.2       tls 			ignore_backslash_newline++;
    139  1.1       jtc 			while ((c = getsc()) != '\0' && c != '\n')
    140  1.1       jtc 				;
    141  1.2       tls 			ignore_backslash_newline--;
    142  1.2       tls 		}
    143  1.1       jtc 		ungetsc(c);
    144  1.1       jtc 	}
    145  1.1       jtc 	if (source->flags & SF_ALIAS) {	/* trailing ' ' in alias definition */
    146  1.1       jtc 		source->flags &= ~SF_ALIAS;
    147  1.1       jtc 		/* In POSIX mode, a trailing space only counts if we are
    148  1.1       jtc 		 * parsing a simple command
    149  1.1       jtc 		 */
    150  1.1       jtc 		if (!Flag(FPOSIX) || (cf & CMDWORD))
    151  1.1       jtc 			cf |= ALIAS;
    152  1.1       jtc 	}
    153  1.1       jtc 
    154  1.6   hubertf 	/* Initial state: one of SBASE SHEREDELIM SWORD SASPAREN */
    155  1.6   hubertf 	statep->ls_state = state;
    156  1.6   hubertf 
    157  1.1       jtc 	/* collect non-special or quoted characters to form word */
    158  1.6   hubertf 	while (!((c = getsc()) == 0
    159  1.6   hubertf 		 || ((state == SBASE || state == SHEREDELIM)
    160  1.6   hubertf 		     && ctype(c, C_LEX1))))
    161  1.1       jtc 	{
    162  1.1       jtc 		Xcheck(ws, wp);
    163  1.1       jtc 		switch (state) {
    164  1.1       jtc 		  case SBASE:
    165  1.1       jtc 			if (c == '[' && (cf & (VARASN|ARRAYVAR))) {
    166  1.1       jtc 				*wp = EOS; /* temporary */
    167  1.1       jtc 				if (is_wdvarname(Xstring(ws, wp), FALSE))
    168  1.1       jtc 				{
    169  1.1       jtc 					char *p, *tmp;
    170  1.1       jtc 
    171  1.1       jtc 					if (arraysub(&tmp)) {
    172  1.1       jtc 						*wp++ = CHAR;
    173  1.1       jtc 						*wp++ = c;
    174  1.1       jtc 						for (p = tmp; *p; ) {
    175  1.1       jtc 							Xcheck(ws, wp);
    176  1.1       jtc 							*wp++ = CHAR;
    177  1.1       jtc 							*wp++ = *p++;
    178  1.1       jtc 						}
    179  1.1       jtc 						afree(tmp, ATEMP);
    180  1.1       jtc 						break;
    181  1.1       jtc 					} else {
    182  1.1       jtc 						Source *s;
    183  1.1       jtc 
    184  1.1       jtc 						s = pushs(SREREAD,
    185  1.1       jtc 							  source->areap);
    186  1.1       jtc 						s->start = s->str
    187  1.1       jtc 							= s->u.freeme = tmp;
    188  1.1       jtc 						s->next = source;
    189  1.1       jtc 						source = s;
    190  1.1       jtc 					}
    191  1.1       jtc 				}
    192  1.1       jtc 				*wp++ = CHAR;
    193  1.1       jtc 				*wp++ = c;
    194  1.1       jtc 				break;
    195  1.1       jtc 			}
    196  1.1       jtc 			/* fall through.. */
    197  1.1       jtc 		  Sbase1:	/* includes *(...|...) pattern (*+?@!) */
    198  1.1       jtc #ifdef KSH
    199  1.1       jtc 			if (c == '*' || c == '@' || c == '+' || c == '?'
    200  1.1       jtc 			    || c == '!')
    201  1.1       jtc 			{
    202  1.1       jtc 				c2 = getsc();
    203  1.1       jtc 				if (c2 == '(' /*)*/ ) {
    204  1.1       jtc 					*wp++ = OPAT;
    205  1.1       jtc 					*wp++ = c;
    206  1.6   hubertf 					PUSH_STATE(SPATTERN);
    207  1.1       jtc 					break;
    208  1.1       jtc 				}
    209  1.1       jtc 				ungetsc(c2);
    210  1.1       jtc 			}
    211  1.1       jtc #endif /* KSH */
    212  1.1       jtc 			/* fall through.. */
    213  1.1       jtc 		  Sbase2:	/* doesn't include *(...|...) pattern (*+?@!) */
    214  1.1       jtc 			switch (c) {
    215  1.1       jtc 			  case '\\':
    216  1.1       jtc 				c = getsc();
    217  1.1       jtc #ifdef OS2
    218  1.2       tls 				if (isalnum(c)) {
    219  1.2       tls 					*wp++ = CHAR, *wp++ = '\\';
    220  1.2       tls 					*wp++ = CHAR, *wp++ = c;
    221  1.2       tls 				} else
    222  1.1       jtc #endif
    223  1.2       tls 				if (c) /* trailing \ is lost */
    224  1.2       tls 					*wp++ = QCHAR, *wp++ = c;
    225  1.1       jtc 				break;
    226  1.1       jtc 			  case '\'':
    227  1.1       jtc 				*wp++ = OQUOTE;
    228  1.2       tls 				ignore_backslash_newline++;
    229  1.6   hubertf 				PUSH_STATE(SSQUOTE);
    230  1.1       jtc 				break;
    231  1.1       jtc 			  case '"':
    232  1.1       jtc 				*wp++ = OQUOTE;
    233  1.6   hubertf 				PUSH_STATE(SDQUOTE);
    234  1.1       jtc 				break;
    235  1.1       jtc 			  default:
    236  1.1       jtc 				goto Subst;
    237  1.1       jtc 			}
    238  1.1       jtc 			break;
    239  1.1       jtc 
    240  1.1       jtc 		  Subst:
    241  1.1       jtc 			switch (c) {
    242  1.1       jtc 			  case '\\':
    243  1.1       jtc 				c = getsc();
    244  1.1       jtc 				switch (c) {
    245  1.1       jtc 				  case '"': case '\\':
    246  1.1       jtc 				  case '$': case '`':
    247  1.1       jtc 					*wp++ = QCHAR, *wp++ = c;
    248  1.1       jtc 					break;
    249  1.1       jtc 				  default:
    250  1.1       jtc 					Xcheck(ws, wp);
    251  1.2       tls 					if (c) { /* trailing \ is lost */
    252  1.2       tls 						*wp++ = CHAR, *wp++ = '\\';
    253  1.2       tls 						*wp++ = CHAR, *wp++ = c;
    254  1.2       tls 					}
    255  1.1       jtc 					break;
    256  1.1       jtc 				}
    257  1.1       jtc 				break;
    258  1.1       jtc 			  case '$':
    259  1.1       jtc 				c = getsc();
    260  1.1       jtc 				if (c == '(') /*)*/ {
    261  1.1       jtc 					c = getsc();
    262  1.1       jtc 					if (c == '(') /*)*/ {
    263  1.6   hubertf 						PUSH_STATE(SASPAREN);
    264  1.6   hubertf 						statep->ls_sasparen.nparen = 2;
    265  1.6   hubertf 						statep->ls_sasparen.start =
    266  1.6   hubertf 							Xsavepos(ws, wp);
    267  1.1       jtc 						*wp++ = EXPRSUB;
    268  1.1       jtc 					} else {
    269  1.1       jtc 						ungetsc(c);
    270  1.6   hubertf 						PUSH_STATE(SCSPAREN);
    271  1.6   hubertf 						statep->ls_scsparen.nparen = 1;
    272  1.6   hubertf 						statep->ls_scsparen.csstate = 0;
    273  1.1       jtc 						*wp++ = COMSUB;
    274  1.1       jtc 					}
    275  1.1       jtc 				} else if (c == '{') /*}*/ {
    276  1.1       jtc 					*wp++ = OSUBST;
    277  1.6   hubertf 					*wp++ = '{'; /*}*/
    278  1.1       jtc 					wp = get_brace_var(&ws, wp);
    279  1.6   hubertf 					c = getsc();
    280  1.6   hubertf 					/* allow :# and :% (ksh88 compat) */
    281  1.6   hubertf 					if (c == ':') {
    282  1.6   hubertf 						*wp++ = CHAR, *wp++ = c;
    283  1.6   hubertf 						c = getsc();
    284  1.6   hubertf 					}
    285  1.1       jtc 					/* If this is a trim operation,
    286  1.6   hubertf 					 * treat (,|,) specially in STBRACE.
    287  1.1       jtc 					 */
    288  1.1       jtc 					if (c == '#' || c == '%') {
    289  1.6   hubertf 						ungetsc(c);
    290  1.6   hubertf 						PUSH_STATE(STBRACE);
    291  1.1       jtc 					} else {
    292  1.1       jtc 						ungetsc(c);
    293  1.6   hubertf 						PUSH_STATE(SBRACE);
    294  1.1       jtc 					}
    295  1.1       jtc 				} else if (ctype(c, C_ALPHA)) {
    296  1.1       jtc 					*wp++ = OSUBST;
    297  1.6   hubertf 					*wp++ = 'X';
    298  1.1       jtc 					do {
    299  1.1       jtc 						Xcheck(ws, wp);
    300  1.1       jtc 						*wp++ = c;
    301  1.1       jtc 						c = getsc();
    302  1.1       jtc 					} while (ctype(c, C_ALPHA|C_DIGIT));
    303  1.1       jtc 					*wp++ = '\0';
    304  1.1       jtc 					*wp++ = CSUBST;
    305  1.6   hubertf 					*wp++ = 'X';
    306  1.1       jtc 					ungetsc(c);
    307  1.1       jtc 				} else if (ctype(c, C_DIGIT|C_VAR1)) {
    308  1.1       jtc 					Xcheck(ws, wp);
    309  1.1       jtc 					*wp++ = OSUBST;
    310  1.6   hubertf 					*wp++ = 'X';
    311  1.1       jtc 					*wp++ = c;
    312  1.1       jtc 					*wp++ = '\0';
    313  1.1       jtc 					*wp++ = CSUBST;
    314  1.6   hubertf 					*wp++ = 'X';
    315  1.1       jtc 				} else {
    316  1.1       jtc 					*wp++ = CHAR, *wp++ = '$';
    317  1.1       jtc 					ungetsc(c);
    318  1.1       jtc 				}
    319  1.1       jtc 				break;
    320  1.1       jtc 			  case '`':
    321  1.6   hubertf 				PUSH_STATE(SBQUOTE);
    322  1.1       jtc 				*wp++ = COMSUB;
    323  1.1       jtc 				/* Need to know if we are inside double quotes
    324  1.1       jtc 				 * since sh/at&t-ksh translate the \" to " in
    325  1.1       jtc 				 * "`..\"..`".
    326  1.6   hubertf 				 * This is not done in posix mode (section
    327  1.6   hubertf 				 * 3.2.3, Double Quotes: "The backquote shall
    328  1.6   hubertf 				 * retain its special meaning introducing the
    329  1.6   hubertf 				 * other form of command substitution (see
    330  1.6   hubertf 				 * 3.6.3). The portion of the quoted string
    331  1.6   hubertf 				 * from the initial backquote and the
    332  1.6   hubertf 				 * characters up to the next backquote that
    333  1.6   hubertf 				 * is not preceded by a backslash (having
    334  1.6   hubertf 				 * escape characters removed) defines that
    335  1.6   hubertf 				 * command whose output replaces `...` when
    336  1.6   hubertf 				 * the word is expanded."
    337  1.6   hubertf 				 * Section 3.6.3, Command Substitution:
    338  1.6   hubertf 				 * "Within the backquoted style of command
    339  1.6   hubertf 				 * substitution, backslash shall retain its
    340  1.6   hubertf 				 * literal meaning, except when followed by
    341  1.6   hubertf 				 * $ ` \.").
    342  1.1       jtc 				 */
    343  1.6   hubertf 				statep->ls_sbquote.indquotes = 0;
    344  1.6   hubertf 				if (!Flag(FPOSIX)) {
    345  1.6   hubertf 					Lex_state *s = statep;
    346  1.6   hubertf 					Lex_state *base = state_info.base;
    347  1.6   hubertf 					while (1) {
    348  1.6   hubertf 						for (; s != base; s--) {
    349  1.6   hubertf 							if (s->ls_state == SDQUOTE) {
    350  1.6   hubertf 								statep->ls_sbquote.indquotes = 1;
    351  1.6   hubertf 								break;
    352  1.6   hubertf 							}
    353  1.6   hubertf 						}
    354  1.6   hubertf 						if (s != base)
    355  1.6   hubertf 							break;
    356  1.6   hubertf 						if (!(s = s->ls_info.base))
    357  1.6   hubertf 							break;
    358  1.6   hubertf 						base = s-- - STATE_BSIZE;
    359  1.6   hubertf 					}
    360  1.6   hubertf 				}
    361  1.1       jtc 				break;
    362  1.1       jtc 			  default:
    363  1.1       jtc 				*wp++ = CHAR, *wp++ = c;
    364  1.1       jtc 			}
    365  1.1       jtc 			break;
    366  1.1       jtc 
    367  1.1       jtc 		  case SSQUOTE:
    368  1.1       jtc 			if (c == '\'') {
    369  1.6   hubertf 				POP_STATE();
    370  1.1       jtc 				*wp++ = CQUOTE;
    371  1.2       tls 				ignore_backslash_newline--;
    372  1.1       jtc 			} else
    373  1.1       jtc 				*wp++ = QCHAR, *wp++ = c;
    374  1.1       jtc 			break;
    375  1.1       jtc 
    376  1.1       jtc 		  case SDQUOTE:
    377  1.1       jtc 			if (c == '"') {
    378  1.6   hubertf 				POP_STATE();
    379  1.1       jtc 				*wp++ = CQUOTE;
    380  1.1       jtc 			} else
    381  1.1       jtc 				goto Subst;
    382  1.1       jtc 			break;
    383  1.1       jtc 
    384  1.6   hubertf 		  case SCSPAREN: /* $( .. ) */
    385  1.1       jtc 			/* todo: deal with $(...) quoting properly
    386  1.1       jtc 			 * kludge to partly fake quoting inside $(..): doesn't
    387  1.1       jtc 			 * really work because nested $(..) or ${..} inside
    388  1.1       jtc 			 * double quotes aren't dealt with.
    389  1.1       jtc 			 */
    390  1.6   hubertf 			switch (statep->ls_scsparen.csstate) {
    391  1.1       jtc 			  case 0: /* normal */
    392  1.1       jtc 				switch (c) {
    393  1.1       jtc 				  case '(':
    394  1.6   hubertf 					statep->ls_scsparen.nparen++;
    395  1.1       jtc 					break;
    396  1.1       jtc 				  case ')':
    397  1.6   hubertf 					statep->ls_scsparen.nparen--;
    398  1.1       jtc 					break;
    399  1.1       jtc 				  case '\\':
    400  1.6   hubertf 					statep->ls_scsparen.csstate = 1;
    401  1.1       jtc 					break;
    402  1.1       jtc 				  case '"':
    403  1.6   hubertf 					statep->ls_scsparen.csstate = 2;
    404  1.1       jtc 					break;
    405  1.1       jtc 				  case '\'':
    406  1.6   hubertf 					statep->ls_scsparen.csstate = 4;
    407  1.2       tls 					ignore_backslash_newline++;
    408  1.1       jtc 					break;
    409  1.1       jtc 				}
    410  1.1       jtc 				break;
    411  1.1       jtc 
    412  1.1       jtc 			  case 1: /* backslash in normal mode */
    413  1.1       jtc 			  case 3: /* backslash in double quotes */
    414  1.6   hubertf 				--statep->ls_scsparen.csstate;
    415  1.1       jtc 				break;
    416  1.1       jtc 
    417  1.1       jtc 			  case 2: /* double quotes */
    418  1.1       jtc 				if (c == '"')
    419  1.6   hubertf 					statep->ls_scsparen.csstate = 0;
    420  1.1       jtc 				else if (c == '\\')
    421  1.6   hubertf 					statep->ls_scsparen.csstate = 3;
    422  1.1       jtc 				break;
    423  1.1       jtc 
    424  1.1       jtc 			  case 4: /* single quotes */
    425  1.2       tls 				if (c == '\'') {
    426  1.6   hubertf 					statep->ls_scsparen.csstate = 0;
    427  1.2       tls 					ignore_backslash_newline--;
    428  1.2       tls 				}
    429  1.1       jtc 				break;
    430  1.1       jtc 			}
    431  1.6   hubertf 			if (statep->ls_scsparen.nparen == 0) {
    432  1.6   hubertf 				POP_STATE();
    433  1.1       jtc 				*wp++ = 0; /* end of COMSUB */
    434  1.1       jtc 			} else
    435  1.1       jtc 				*wp++ = c;
    436  1.1       jtc 			break;
    437  1.1       jtc 
    438  1.6   hubertf 		  case SASPAREN: /* $(( .. )) */
    439  1.1       jtc 			/* todo: deal with $((...); (...)) properly */
    440  1.1       jtc 			/* XXX should nest using existing state machine
    441  1.1       jtc 			 *     (embed "..", $(...), etc.) */
    442  1.1       jtc 			if (c == '(')
    443  1.6   hubertf 				statep->ls_sasparen.nparen++;
    444  1.1       jtc 			else if (c == ')') {
    445  1.6   hubertf 				statep->ls_sasparen.nparen--;
    446  1.6   hubertf 				if (statep->ls_sasparen.nparen == 1) {
    447  1.1       jtc 					/*(*/
    448  1.1       jtc 					if ((c2 = getsc()) == ')') {
    449  1.6   hubertf 						POP_STATE();
    450  1.1       jtc 						*wp++ = 0; /* end of EXPRSUB */
    451  1.1       jtc 						break;
    452  1.1       jtc 					} else {
    453  1.6   hubertf 						char *s;
    454  1.6   hubertf 
    455  1.1       jtc 						ungetsc(c2);
    456  1.1       jtc 						/* mismatched parenthesis -
    457  1.1       jtc 						 * assume we were really
    458  1.1       jtc 						 * parsing a $(..) expression
    459  1.1       jtc 						 */
    460  1.6   hubertf 						s = Xrestpos(ws, wp,
    461  1.6   hubertf 						     statep->ls_sasparen.start);
    462  1.6   hubertf 						memmove(s + 1, s, wp - s);
    463  1.6   hubertf 						*s++ = COMSUB;
    464  1.6   hubertf 						*s = '('; /*)*/
    465  1.1       jtc 						wp++;
    466  1.6   hubertf 						statep->ls_scsparen.nparen = 1;
    467  1.6   hubertf 						statep->ls_scsparen.csstate = 0;
    468  1.6   hubertf 						state = statep->ls_state
    469  1.6   hubertf 							= SCSPAREN;
    470  1.6   hubertf 
    471  1.1       jtc 					}
    472  1.1       jtc 				}
    473  1.1       jtc 			}
    474  1.1       jtc 			*wp++ = c;
    475  1.1       jtc 			break;
    476  1.1       jtc 
    477  1.1       jtc 		  case SBRACE:
    478  1.1       jtc 			/*{*/
    479  1.1       jtc 			if (c == '}') {
    480  1.6   hubertf 				POP_STATE();
    481  1.1       jtc 				*wp++ = CSUBST;
    482  1.6   hubertf 				*wp++ = /*{*/ '}';
    483  1.1       jtc 			} else
    484  1.1       jtc 				goto Sbase1;
    485  1.1       jtc 			break;
    486  1.1       jtc 
    487  1.1       jtc 		  case STBRACE:
    488  1.6   hubertf 			/* Same as SBRACE, except (,|,) treated specially */
    489  1.1       jtc 			/*{*/
    490  1.1       jtc 			if (c == '}') {
    491  1.6   hubertf 				POP_STATE();
    492  1.1       jtc 				*wp++ = CSUBST;
    493  1.6   hubertf 				*wp++ = /*{*/ '}';
    494  1.1       jtc 			} else if (c == '|') {
    495  1.1       jtc 				*wp++ = SPAT;
    496  1.6   hubertf 			} else if (c == '(') {
    497  1.6   hubertf 				*wp++ = OPAT;
    498  1.6   hubertf 				*wp++ = ' ';	/* simile for @ */
    499  1.6   hubertf 				PUSH_STATE(SPATTERN);
    500  1.1       jtc 			} else
    501  1.1       jtc 				goto Sbase1;
    502  1.1       jtc 			break;
    503  1.1       jtc 
    504  1.1       jtc 		  case SBQUOTE:
    505  1.1       jtc 			if (c == '`') {
    506  1.1       jtc 				*wp++ = 0;
    507  1.6   hubertf 				POP_STATE();
    508  1.1       jtc 			} else if (c == '\\') {
    509  1.1       jtc 				switch (c = getsc()) {
    510  1.1       jtc 				  case '\\':
    511  1.1       jtc 				  case '$': case '`':
    512  1.1       jtc 					*wp++ = c;
    513  1.1       jtc 					break;
    514  1.1       jtc 				  case '"':
    515  1.6   hubertf 					if (statep->ls_sbquote.indquotes) {
    516  1.1       jtc 						*wp++ = c;
    517  1.1       jtc 						break;
    518  1.1       jtc 					}
    519  1.1       jtc 					/* fall through.. */
    520  1.1       jtc 				  default:
    521  1.2       tls 					if (c) { /* trailing \ is lost */
    522  1.2       tls 						*wp++ = '\\';
    523  1.2       tls 						*wp++ = c;
    524  1.2       tls 					}
    525  1.1       jtc 					break;
    526  1.1       jtc 				}
    527  1.1       jtc 			} else
    528  1.1       jtc 				*wp++ = c;
    529  1.1       jtc 			break;
    530  1.1       jtc 
    531  1.1       jtc 		  case SWORD:	/* ONEWORD */
    532  1.1       jtc 			goto Subst;
    533  1.1       jtc 
    534  1.2       tls #ifdef KSH
    535  1.6   hubertf 		  case SLETPAREN:	/* LETEXPR: (( ... )) */
    536  1.1       jtc 			/*(*/
    537  1.1       jtc 			if (c == ')') {
    538  1.6   hubertf 				if (statep->ls_sletparen.nparen > 0)
    539  1.6   hubertf 				    --statep->ls_sletparen.nparen;
    540  1.1       jtc 				/*(*/
    541  1.1       jtc 				else if ((c2 = getsc()) == ')') {
    542  1.1       jtc 					c = 0;
    543  1.1       jtc 					*wp++ = CQUOTE;
    544  1.1       jtc 					goto Done;
    545  1.1       jtc 				} else
    546  1.1       jtc 					ungetsc(c2);
    547  1.1       jtc 			} else if (c == '(')
    548  1.1       jtc 				/* parenthesis inside quotes and backslashes
    549  1.1       jtc 				 * are lost, but at&t ksh doesn't count them
    550  1.1       jtc 				 * either
    551  1.1       jtc 				 */
    552  1.6   hubertf 				++statep->ls_sletparen.nparen;
    553  1.1       jtc 			goto Sbase2;
    554  1.2       tls #endif /* KSH */
    555  1.1       jtc 
    556  1.1       jtc 		  case SHEREDELIM:	/* <<,<<- delimiter */
    557  1.1       jtc 			/* XXX chuck this state (and the next) - use
    558  1.1       jtc 			 * the existing states ($ and \`..` should be
    559  1.1       jtc 			 * stripped of their specialness after the
    560  1.1       jtc 			 * fact).
    561  1.1       jtc 			 */
    562  1.1       jtc 			/* here delimiters need a special case since
    563  1.1       jtc 			 * $ and `..` are not to be treated specially
    564  1.1       jtc 			 */
    565  1.1       jtc 			if (c == '\\') {
    566  1.1       jtc 				c = getsc();
    567  1.2       tls 				if (c) { /* trailing \ is lost */
    568  1.1       jtc 					*wp++ = QCHAR;
    569  1.1       jtc 					*wp++ = c;
    570  1.1       jtc 				}
    571  1.1       jtc 			} else if (c == '\'') {
    572  1.6   hubertf 				PUSH_STATE(SSQUOTE);
    573  1.1       jtc 				*wp++ = OQUOTE;
    574  1.2       tls 				ignore_backslash_newline++;
    575  1.1       jtc 			} else if (c == '"') {
    576  1.6   hubertf 				state = statep->ls_state = SHEREDQUOTE;
    577  1.1       jtc 				*wp++ = OQUOTE;
    578  1.1       jtc 			} else {
    579  1.1       jtc 				*wp++ = CHAR;
    580  1.1       jtc 				*wp++ = c;
    581  1.1       jtc 			}
    582  1.1       jtc 			break;
    583  1.1       jtc 
    584  1.1       jtc 		  case SHEREDQUOTE:	/* " in <<,<<- delimiter */
    585  1.1       jtc 			if (c == '"') {
    586  1.1       jtc 				*wp++ = CQUOTE;
    587  1.6   hubertf 				state = statep->ls_state = SHEREDELIM;
    588  1.1       jtc 			} else {
    589  1.2       tls 				if (c == '\\') {
    590  1.2       tls 					switch (c = getsc()) {
    591  1.2       tls 					  case '\\': case '"':
    592  1.2       tls 					  case '$': case '`':
    593  1.2       tls 						break;
    594  1.2       tls 					  default:
    595  1.2       tls 						if (c) { /* trailing \ lost */
    596  1.2       tls 							*wp++ = CHAR;
    597  1.2       tls 							*wp++ = '\\';
    598  1.2       tls 						}
    599  1.2       tls 						break;
    600  1.2       tls 					}
    601  1.2       tls 				}
    602  1.1       jtc 				*wp++ = CHAR;
    603  1.1       jtc 				*wp++ = c;
    604  1.1       jtc 			}
    605  1.1       jtc 			break;
    606  1.1       jtc 
    607  1.1       jtc 		  case SPATTERN:	/* in *(...|...) pattern (*+?@!) */
    608  1.1       jtc 			if ( /*(*/ c == ')') {
    609  1.1       jtc 				*wp++ = CPAT;
    610  1.6   hubertf 				POP_STATE();
    611  1.6   hubertf 			} else if (c == '|') {
    612  1.1       jtc 				*wp++ = SPAT;
    613  1.6   hubertf 			} else if (c == '(') {
    614  1.6   hubertf 				*wp++ = OPAT;
    615  1.6   hubertf 				*wp++ = ' ';	/* simile for @ */
    616  1.6   hubertf 				PUSH_STATE(SPATTERN);
    617  1.6   hubertf 			} else
    618  1.1       jtc 				goto Sbase1;
    619  1.1       jtc 			break;
    620  1.1       jtc 		}
    621  1.1       jtc 	}
    622  1.1       jtc Done:
    623  1.1       jtc 	Xcheck(ws, wp);
    624  1.6   hubertf 	if (statep != &states[1])
    625  1.6   hubertf 		/* XXX figure out what is missing */
    626  1.1       jtc 		yyerror("no closing quote\n");
    627  1.1       jtc 
    628  1.1       jtc 	/* This done to avoid tests for SHEREDELIM wherever SBASE tested */
    629  1.1       jtc 	if (state == SHEREDELIM)
    630  1.1       jtc 		state = SBASE;
    631  1.1       jtc 
    632  1.6   hubertf 	dp = Xstring(ws, wp);
    633  1.6   hubertf 	if ((c == '<' || c == '>') && state == SBASE
    634  1.6   hubertf 	    && ((c2 = Xlength(ws, wp)) == 0
    635  1.6   hubertf 	        || (c2 == 2 && dp[0] == CHAR && digit(dp[1]))))
    636  1.6   hubertf 	{
    637  1.6   hubertf 		struct ioword *iop =
    638  1.6   hubertf 				(struct ioword *) alloc(sizeof(*iop), ATEMP);
    639  1.6   hubertf 
    640  1.6   hubertf 		if (c2 == 2)
    641  1.6   hubertf 			iop->unit = dp[1] - '0';
    642  1.6   hubertf 		else
    643  1.6   hubertf 			iop->unit = c == '>'; /* 0 for <, 1 for > */
    644  1.6   hubertf 
    645  1.6   hubertf 		c2 = getsc();
    646  1.6   hubertf 		/* <<, >>, <> are ok, >< is not */
    647  1.6   hubertf 		if (c == c2 || (c == '<' && c2 == '>')) {
    648  1.6   hubertf 			iop->flag = c == c2 ?
    649  1.6   hubertf 				  (c == '>' ? IOCAT : IOHERE) : IORDWR;
    650  1.7   hubertf 			if (iop->flag == IOHERE) {
    651  1.7   hubertf 				if ((c2 = getsc()) == '-') {
    652  1.6   hubertf 					iop->flag |= IOSKIP;
    653  1.7   hubertf 				} else {
    654  1.6   hubertf 					ungetsc(c2);
    655  1.7   hubertf 				}
    656  1.7   hubertf 			}
    657  1.6   hubertf 		} else if (c2 == '&')
    658  1.6   hubertf 			iop->flag = IODUP | (c == '<' ? IORDUP : 0);
    659  1.6   hubertf 		else {
    660  1.6   hubertf 			iop->flag = c == '>' ? IOWRITE : IOREAD;
    661  1.6   hubertf 			if (c == '>' && c2 == '|')
    662  1.6   hubertf 				iop->flag |= IOCLOB;
    663  1.6   hubertf 			else
    664  1.6   hubertf 				ungetsc(c2);
    665  1.6   hubertf 		}
    666  1.6   hubertf 
    667  1.6   hubertf 		iop->name = (char *) 0;
    668  1.6   hubertf 		iop->delim = (char *) 0;
    669  1.6   hubertf 		iop->heredoc = (char *) 0;
    670  1.6   hubertf 		Xfree(ws, wp);	/* free word */
    671  1.6   hubertf 		yylval.iop = iop;
    672  1.6   hubertf 		return REDIR;
    673  1.1       jtc 	}
    674  1.1       jtc 
    675  1.6   hubertf 	if (wp == dp && state == SBASE) {
    676  1.1       jtc 		Xfree(ws, wp);	/* free word */
    677  1.1       jtc 		/* no word, process LEX1 character */
    678  1.1       jtc 		switch (c) {
    679  1.1       jtc 		  default:
    680  1.1       jtc 			return c;
    681  1.1       jtc 
    682  1.1       jtc 		  case '|':
    683  1.1       jtc 		  case '&':
    684  1.1       jtc 		  case ';':
    685  1.1       jtc 			if ((c2 = getsc()) == c)
    686  1.1       jtc 				c = (c == ';') ? BREAK :
    687  1.1       jtc 				    (c == '|') ? LOGOR :
    688  1.1       jtc 				    (c == '&') ? LOGAND :
    689  1.1       jtc 				    YYERRCODE;
    690  1.1       jtc #ifdef KSH
    691  1.1       jtc 			else if (c == '|' && c2 == '&')
    692  1.1       jtc 				c = COPROC;
    693  1.1       jtc #endif /* KSH */
    694  1.1       jtc 			else
    695  1.1       jtc 				ungetsc(c2);
    696  1.1       jtc 			return c;
    697  1.1       jtc 
    698  1.1       jtc 		  case '\n':
    699  1.1       jtc 			gethere();
    700  1.1       jtc 			if (cf & CONTIN)
    701  1.1       jtc 				goto Again;
    702  1.1       jtc 			return c;
    703  1.1       jtc 
    704  1.1       jtc 		  case '(':  /*)*/
    705  1.2       tls #ifdef KSH
    706  1.1       jtc 			if ((c2 = getsc()) == '(') /*)*/
    707  1.6   hubertf 				/* XXX need to handle ((...); (...)) */
    708  1.1       jtc 				c = MDPAREN;
    709  1.1       jtc 			else
    710  1.1       jtc 				ungetsc(c2);
    711  1.2       tls #endif /* KSH */
    712  1.1       jtc 			return c;
    713  1.1       jtc 		  /*(*/
    714  1.1       jtc 		  case ')':
    715  1.1       jtc 			return c;
    716  1.1       jtc 		}
    717  1.1       jtc 	}
    718  1.1       jtc 
    719  1.1       jtc 	*wp++ = EOS;		/* terminate word */
    720  1.1       jtc 	yylval.cp = Xclose(ws, wp);
    721  1.2       tls 	if (state == SWORD
    722  1.2       tls #ifdef KSH
    723  1.6   hubertf 		|| state == SLETPAREN
    724  1.2       tls #endif /* KSH */
    725  1.2       tls 		)	/* ONEWORD? */
    726  1.1       jtc 		return LWORD;
    727  1.1       jtc 	ungetsc(c);		/* unget terminator */
    728  1.1       jtc 
    729  1.1       jtc 	/* copy word to unprefixed string ident */
    730  1.1       jtc 	for (sp = yylval.cp, dp = ident; dp < ident+IDENT && (c = *sp++) == CHAR; )
    731  1.1       jtc 		*dp++ = *sp++;
    732  1.1       jtc 	/* Make sure the ident array stays '\0' paded */
    733  1.1       jtc 	memset(dp, 0, (ident+IDENT) - dp + 1);
    734  1.1       jtc 	if (c != EOS)
    735  1.1       jtc 		*ident = '\0';	/* word is not unquoted */
    736  1.1       jtc 
    737  1.1       jtc 	if (*ident != '\0' && (cf&(KEYWORD|ALIAS))) {
    738  1.1       jtc 		struct tbl *p;
    739  1.1       jtc 		int h = hash(ident);
    740  1.1       jtc 
    741  1.1       jtc 		/* { */
    742  1.1       jtc 		if ((cf & KEYWORD) && (p = tsearch(&keywords, ident, h))
    743  1.1       jtc 		    && (!(cf & ESACONLY) || p->val.i == ESAC || p->val.i == '}'))
    744  1.1       jtc 		{
    745  1.1       jtc 			afree(yylval.cp, ATEMP);
    746  1.1       jtc 			return p->val.i;
    747  1.1       jtc 		}
    748  1.1       jtc 		if ((cf & ALIAS) && (p = tsearch(&aliases, ident, h))
    749  1.1       jtc 		    && (p->flag & ISSET))
    750  1.1       jtc 		{
    751  1.1       jtc 			register Source *s;
    752  1.1       jtc 
    753  1.1       jtc 			for (s = source; s->type == SALIAS; s = s->next)
    754  1.1       jtc 				if (s->u.tblp == p)
    755  1.1       jtc 					return LWORD;
    756  1.1       jtc 			/* push alias expansion */
    757  1.1       jtc 			s = pushs(SALIAS, source->areap);
    758  1.1       jtc 			s->start = s->str = p->val.s;
    759  1.1       jtc 			s->u.tblp = p;
    760  1.1       jtc 			s->next = source;
    761  1.1       jtc 			source = s;
    762  1.1       jtc 			afree(yylval.cp, ATEMP);
    763  1.1       jtc 			goto Again;
    764  1.1       jtc 		}
    765  1.1       jtc 	}
    766  1.1       jtc 
    767  1.1       jtc 	return LWORD;
    768  1.1       jtc }
    769  1.1       jtc 
    770  1.1       jtc static void
    771  1.1       jtc gethere()
    772  1.1       jtc {
    773  1.1       jtc 	register struct ioword **p;
    774  1.1       jtc 
    775  1.1       jtc 	for (p = heres; p < herep; p++)
    776  1.1       jtc 		readhere(*p);
    777  1.1       jtc 	herep = heres;
    778  1.1       jtc }
    779  1.1       jtc 
    780  1.1       jtc /*
    781  1.1       jtc  * read "<<word" text into temp file
    782  1.1       jtc  */
    783  1.1       jtc 
    784  1.1       jtc static void
    785  1.1       jtc readhere(iop)
    786  1.6   hubertf 	struct ioword *iop;
    787  1.1       jtc {
    788  1.1       jtc 	register int c;
    789  1.1       jtc 	char *volatile eof;
    790  1.1       jtc 	char *eofp;
    791  1.2       tls 	int skiptabs;
    792  1.6   hubertf 	XString xs;
    793  1.6   hubertf 	char *xp;
    794  1.6   hubertf 	int xpos;
    795  1.1       jtc 
    796  1.1       jtc 	eof = evalstr(iop->delim, 0);
    797  1.1       jtc 
    798  1.2       tls 	if (!(iop->flag & IOEVAL))
    799  1.2       tls 		ignore_backslash_newline++;
    800  1.2       tls 
    801  1.6   hubertf 	Xinit(xs, xp, 256, ATEMP);
    802  1.6   hubertf 
    803  1.1       jtc 	for (;;) {
    804  1.1       jtc 		eofp = eof;
    805  1.1       jtc 		skiptabs = iop->flag & IOSKIP;
    806  1.6   hubertf 		xpos = Xsavepos(xs, xp);
    807  1.2       tls 		while ((c = getsc()) != 0) {
    808  1.1       jtc 			if (skiptabs) {
    809  1.1       jtc 				if (c == '\t')
    810  1.1       jtc 					continue;
    811  1.1       jtc 				skiptabs = 0;
    812  1.1       jtc 			}
    813  1.1       jtc 			if (c != *eofp)
    814  1.1       jtc 				break;
    815  1.6   hubertf 			Xcheck(xs, xp);
    816  1.6   hubertf 			Xput(xs, xp, c);
    817  1.1       jtc 			eofp++;
    818  1.1       jtc 		}
    819  1.1       jtc 		/* Allow EOF here so commands with out trailing newlines
    820  1.1       jtc 		 * will work (eg, ksh -c '...', $(...), etc).
    821  1.1       jtc 		 */
    822  1.6   hubertf 		if (*eofp == '\0' && (c == 0 || c == '\n')) {
    823  1.6   hubertf 			xp = Xrestpos(xs, xp, xpos);
    824  1.1       jtc 			break;
    825  1.6   hubertf 		}
    826  1.1       jtc 		ungetsc(c);
    827  1.2       tls 		while ((c = getsc()) != '\n') {
    828  1.1       jtc 			if (c == 0)
    829  1.1       jtc 				yyerror("here document `%s' unclosed\n", eof);
    830  1.6   hubertf 			Xcheck(xs, xp);
    831  1.6   hubertf 			Xput(xs, xp, c);
    832  1.1       jtc 		}
    833  1.6   hubertf 		Xcheck(xs, xp);
    834  1.6   hubertf 		Xput(xs, xp, c);
    835  1.1       jtc 	}
    836  1.6   hubertf 	Xput(xs, xp, '\0');
    837  1.6   hubertf 	iop->heredoc = Xclose(xs, xp);
    838  1.6   hubertf 
    839  1.2       tls 	if (!(iop->flag & IOEVAL))
    840  1.2       tls 		ignore_backslash_newline--;
    841  1.1       jtc }
    842  1.1       jtc 
    843  1.1       jtc void
    844  1.1       jtc #ifdef HAVE_PROTOTYPES
    845  1.1       jtc yyerror(const char *fmt, ...)
    846  1.1       jtc #else
    847  1.1       jtc yyerror(fmt, va_alist)
    848  1.1       jtc 	const char *fmt;
    849  1.1       jtc 	va_dcl
    850  1.1       jtc #endif
    851  1.1       jtc {
    852  1.1       jtc 	va_list va;
    853  1.1       jtc 
    854  1.1       jtc 	/* pop aliases and re-reads */
    855  1.1       jtc 	while (source->type == SALIAS || source->type == SREREAD)
    856  1.1       jtc 		source = source->next;
    857  1.1       jtc 	source->str = null;	/* zap pending input */
    858  1.1       jtc 
    859  1.1       jtc 	error_prefix(TRUE);
    860  1.1       jtc 	SH_VA_START(va, fmt);
    861  1.1       jtc 	shf_vfprintf(shl_out, fmt, va);
    862  1.1       jtc 	va_end(va);
    863  1.1       jtc 	errorf(null);
    864  1.1       jtc }
    865  1.1       jtc 
    866  1.1       jtc /*
    867  1.1       jtc  * input for yylex with alias expansion
    868  1.1       jtc  */
    869  1.1       jtc 
    870  1.1       jtc Source *
    871  1.1       jtc pushs(type, areap)
    872  1.1       jtc 	int type;
    873  1.1       jtc 	Area *areap;
    874  1.1       jtc {
    875  1.1       jtc 	register Source *s;
    876  1.1       jtc 
    877  1.1       jtc 	s = (Source *) alloc(sizeof(Source), areap);
    878  1.1       jtc 	s->type = type;
    879  1.1       jtc 	s->str = null;
    880  1.1       jtc 	s->start = NULL;
    881  1.1       jtc 	s->line = 0;
    882  1.1       jtc 	s->errline = 0;
    883  1.1       jtc 	s->file = NULL;
    884  1.1       jtc 	s->flags = 0;
    885  1.1       jtc 	s->next = NULL;
    886  1.1       jtc 	s->areap = areap;
    887  1.1       jtc 	if (type == SFILE || type == SSTDIN) {
    888  1.1       jtc 		char *dummy;
    889  1.1       jtc 		Xinit(s->xs, dummy, 256, s->areap);
    890  1.1       jtc 	} else
    891  1.1       jtc 		memset(&s->xs, 0, sizeof(s->xs));
    892  1.1       jtc 	return s;
    893  1.1       jtc }
    894  1.1       jtc 
    895  1.1       jtc static int
    896  1.2       tls getsc__()
    897  1.1       jtc {
    898  1.1       jtc 	register Source *s = source;
    899  1.1       jtc 	register int c;
    900  1.1       jtc 
    901  1.1       jtc 	while ((c = *s->str++) == 0) {
    902  1.1       jtc 		s->str = NULL;		/* return 0 for EOF by default */
    903  1.1       jtc 		switch (s->type) {
    904  1.1       jtc 		  case SEOF:
    905  1.1       jtc 			s->str = null;
    906  1.1       jtc 			return 0;
    907  1.1       jtc 
    908  1.1       jtc 		  case SSTDIN:
    909  1.1       jtc 		  case SFILE:
    910  1.1       jtc 			getsc_line(s);
    911  1.1       jtc 			break;
    912  1.1       jtc 
    913  1.1       jtc 		  case SWSTR:
    914  1.1       jtc 			break;
    915  1.1       jtc 
    916  1.1       jtc 		  case SSTRING:
    917  1.1       jtc 			break;
    918  1.1       jtc 
    919  1.1       jtc 		  case SWORDS:
    920  1.1       jtc 			s->start = s->str = *s->u.strv++;
    921  1.1       jtc 			s->type = SWORDSEP;
    922  1.1       jtc 			break;
    923  1.1       jtc 
    924  1.1       jtc 		  case SWORDSEP:
    925  1.1       jtc 			if (*s->u.strv == NULL) {
    926  1.1       jtc 				s->start = s->str = newline;
    927  1.1       jtc 				s->type = SEOF;
    928  1.1       jtc 			} else {
    929  1.1       jtc 				s->start = s->str = space;
    930  1.1       jtc 				s->type = SWORDS;
    931  1.1       jtc 			}
    932  1.1       jtc 			break;
    933  1.1       jtc 
    934  1.1       jtc 		  case SALIAS:
    935  1.1       jtc 			if (s->flags & SF_ALIASEND) {
    936  1.1       jtc 				/* pass on an unused SF_ALIAS flag */
    937  1.1       jtc 				source = s->next;
    938  1.1       jtc 				source->flags |= s->flags & SF_ALIAS;
    939  1.1       jtc 				s = source;
    940  1.1       jtc 			} else if (*s->u.tblp->val.s
    941  1.5  christos 				 && isspace((unsigned char)strchr(s->u.tblp->val.s, 0)[-1]))
    942  1.1       jtc 			{
    943  1.1       jtc 				source = s = s->next;	/* pop source stack */
    944  1.2       tls 				/* Note that this alias ended with a space,
    945  1.2       tls 				 * enabling alias expansion on the following
    946  1.2       tls 				 * word.
    947  1.2       tls 				 */
    948  1.1       jtc 				s->flags |= SF_ALIAS;
    949  1.1       jtc 			} else {
    950  1.2       tls 				/* At this point, we need to keep the current
    951  1.2       tls 				 * alias in the source list so recursive
    952  1.2       tls 				 * aliases can be detected and we also need
    953  1.2       tls 				 * to return the next character.  Do this
    954  1.2       tls 				 * by temporarily popping the alias to get
    955  1.2       tls 				 * the next character and then put it back
    956  1.2       tls 				 * in the source list with the SF_ALIASEND
    957  1.2       tls 				 * flag set.
    958  1.1       jtc 				 */
    959  1.2       tls 				source = s->next;	/* pop source stack */
    960  1.2       tls 				source->flags |= s->flags & SF_ALIAS;
    961  1.2       tls 				c = getsc__();
    962  1.2       tls 				if (c) {
    963  1.2       tls 					s->flags |= SF_ALIASEND;
    964  1.2       tls 					s->ugbuf[0] = c; s->ugbuf[1] = '\0';
    965  1.2       tls 					s->start = s->str = s->ugbuf;
    966  1.2       tls 					s->next = source;
    967  1.2       tls 					source = s;
    968  1.2       tls 				} else {
    969  1.2       tls 					s = source;
    970  1.2       tls 					/* avoid reading eof twice */
    971  1.2       tls 					s->str = NULL;
    972  1.2       tls 					break;
    973  1.2       tls 				}
    974  1.1       jtc 			}
    975  1.1       jtc 			continue;
    976  1.1       jtc 
    977  1.1       jtc 		  case SREREAD:
    978  1.2       tls 			if (s->start != s->ugbuf) /* yuck */
    979  1.1       jtc 				afree(s->u.freeme, ATEMP);
    980  1.1       jtc 			source = s = s->next;
    981  1.1       jtc 			continue;
    982  1.1       jtc 		}
    983  1.1       jtc 		if (s->str == NULL) {
    984  1.1       jtc 			s->type = SEOF;
    985  1.1       jtc 			s->start = s->str = null;
    986  1.1       jtc 			return '\0';
    987  1.1       jtc 		}
    988  1.1       jtc 		if (s->flags & SF_ECHO) {
    989  1.1       jtc 			shf_puts(s->str, shl_out);
    990  1.1       jtc 			shf_flush(shl_out);
    991  1.1       jtc 		}
    992  1.1       jtc 	}
    993  1.1       jtc 	return c;
    994  1.1       jtc }
    995  1.1       jtc 
    996  1.1       jtc static void
    997  1.1       jtc getsc_line(s)
    998  1.1       jtc 	Source *s;
    999  1.1       jtc {
   1000  1.1       jtc 	char *xp = Xstring(s->xs, xp);
   1001  1.1       jtc 	int interactive = Flag(FTALKING) && s->type == SSTDIN;
   1002  1.1       jtc 	int have_tty = interactive && (s->flags & SF_TTY);
   1003  1.1       jtc 
   1004  1.1       jtc 	/* Done here to ensure nothing odd happens when a timeout occurs */
   1005  1.1       jtc 	XcheckN(s->xs, xp, LINE);
   1006  1.1       jtc 	*xp = '\0';
   1007  1.1       jtc 	s->start = s->str = xp;
   1008  1.1       jtc 
   1009  1.1       jtc #ifdef KSH
   1010  1.1       jtc 	if (have_tty && ksh_tmout) {
   1011  1.1       jtc 		ksh_tmout_state = TMOUT_READING;
   1012  1.1       jtc 		alarm(ksh_tmout);
   1013  1.1       jtc 	}
   1014  1.1       jtc #endif /* KSH */
   1015  1.1       jtc #ifdef EDIT
   1016  1.1       jtc 	if (have_tty && (0
   1017  1.1       jtc # ifdef VI
   1018  1.1       jtc 			 || Flag(FVI)
   1019  1.1       jtc # endif /* VI */
   1020  1.1       jtc # ifdef EMACS
   1021  1.1       jtc 			 || Flag(FEMACS) || Flag(FGMACS)
   1022  1.1       jtc # endif /* EMACS */
   1023  1.1       jtc 		))
   1024  1.1       jtc 	{
   1025  1.1       jtc 		int nread;
   1026  1.1       jtc 
   1027  1.1       jtc 		nread = x_read(xp, LINE);
   1028  1.1       jtc 		if (nread < 0)	/* read error */
   1029  1.1       jtc 			nread = 0;
   1030  1.1       jtc 		xp[nread] = '\0';
   1031  1.1       jtc 		xp += nread;
   1032  1.1       jtc 	}
   1033  1.1       jtc 	else
   1034  1.1       jtc #endif /* EDIT */
   1035  1.1       jtc 	{
   1036  1.1       jtc 		if (interactive) {
   1037  1.1       jtc 			pprompt(prompt, 0);
   1038  1.1       jtc 		} else
   1039  1.1       jtc 			s->line++;
   1040  1.1       jtc 
   1041  1.1       jtc 		while (1) {
   1042  1.1       jtc 			char *p = shf_getse(xp, Xnleft(s->xs, xp), s->u.shf);
   1043  1.1       jtc 
   1044  1.1       jtc 			if (!p && shf_error(s->u.shf)
   1045  1.1       jtc 			    && shf_errno(s->u.shf) == EINTR)
   1046  1.1       jtc 			{
   1047  1.1       jtc 				shf_clearerr(s->u.shf);
   1048  1.1       jtc 				if (trap)
   1049  1.1       jtc 					runtraps(0);
   1050  1.1       jtc 				continue;
   1051  1.1       jtc 			}
   1052  1.1       jtc 			if (!p || (xp = p, xp[-1] == '\n'))
   1053  1.1       jtc 				break;
   1054  1.1       jtc 			/* double buffer size */
   1055  1.1       jtc 			xp++; /* move past null so doubling works... */
   1056  1.1       jtc 			XcheckN(s->xs, xp, Xlength(s->xs, xp));
   1057  1.1       jtc 			xp--; /* ...and move back again */
   1058  1.1       jtc 		}
   1059  1.1       jtc 		/* flush any unwanted input so other programs/builtins
   1060  1.1       jtc 		 * can read it.  Not very optimal, but less error prone
   1061  1.1       jtc 		 * than flushing else where, dealing with redirections,
   1062  1.1       jtc 		 * etc..
   1063  1.1       jtc 		 * todo: reduce size of shf buffer (~128?) if SSTDIN
   1064  1.1       jtc 		 */
   1065  1.1       jtc 		if (s->type == SSTDIN)
   1066  1.1       jtc 			shf_flush(s->u.shf);
   1067  1.1       jtc 	}
   1068  1.1       jtc 	/* XXX: temporary kludge to restore source after a
   1069  1.1       jtc 	 * trap may have been executed.
   1070  1.1       jtc 	 */
   1071  1.1       jtc 	source = s;
   1072  1.1       jtc #ifdef KSH
   1073  1.1       jtc 	if (have_tty && ksh_tmout)
   1074  1.1       jtc 	{
   1075  1.1       jtc 		ksh_tmout_state = TMOUT_EXECUTING;
   1076  1.1       jtc 		alarm(0);
   1077  1.1       jtc 	}
   1078  1.1       jtc #endif /* KSH */
   1079  1.1       jtc 	s->start = s->str = Xstring(s->xs, xp);
   1080  1.1       jtc 	strip_nuls(Xstring(s->xs, xp), Xlength(s->xs, xp));
   1081  1.1       jtc 	/* Note: if input is all nulls, this is not eof */
   1082  1.1       jtc 	if (Xlength(s->xs, xp) == 0) { /* EOF */
   1083  1.1       jtc 		if (s->type == SFILE)
   1084  1.1       jtc 			shf_fdclose(s->u.shf);
   1085  1.1       jtc 		s->str = NULL;
   1086  1.1       jtc 	} else if (interactive) {
   1087  1.1       jtc #ifdef HISTORY
   1088  1.1       jtc 		char *p = Xstring(s->xs, xp);
   1089  1.1       jtc 		if (cur_prompt == PS1)
   1090  1.1       jtc 			while (*p && ctype(*p, C_IFS) && ctype(*p, C_IFSWS))
   1091  1.1       jtc 				p++;
   1092  1.1       jtc 		if (*p) {
   1093  1.1       jtc # ifdef EASY_HISTORY
   1094  1.1       jtc 			if (cur_prompt == PS2)
   1095  1.1       jtc 				histappend(Xstring(s->xs, xp), 1);
   1096  1.1       jtc 			else
   1097  1.1       jtc # endif /* EASY_HISTORY */
   1098  1.1       jtc 			{
   1099  1.1       jtc 				s->line++;
   1100  1.1       jtc 				histsave(s->line, s->str, 1);
   1101  1.1       jtc 			}
   1102  1.1       jtc 		}
   1103  1.1       jtc #endif /* HISTORY */
   1104  1.1       jtc 	}
   1105  1.1       jtc 	if (interactive)
   1106  1.1       jtc 		set_prompt(PS2, (Source *) 0);
   1107  1.1       jtc }
   1108  1.1       jtc 
   1109  1.1       jtc void
   1110  1.1       jtc set_prompt(to, s)
   1111  1.1       jtc 	int to;
   1112  1.1       jtc 	Source *s;
   1113  1.1       jtc {
   1114  1.1       jtc 	cur_prompt = to;
   1115  1.1       jtc 
   1116  1.1       jtc 	switch (to) {
   1117  1.1       jtc 	case PS1: /* command */
   1118  1.1       jtc #ifdef KSH
   1119  1.1       jtc 		/* Substitute ! and !! here, before substitutions are done
   1120  1.1       jtc 		 * so ! in expanded variables are not expanded.
   1121  1.1       jtc 		 * NOTE: this is not what at&t ksh does (it does it after
   1122  1.1       jtc 		 * substitutions, POSIX doesn't say which is to be done.
   1123  1.1       jtc 		 */
   1124  1.1       jtc 		{
   1125  1.1       jtc 			struct shf *shf;
   1126  1.1       jtc 			char *ps1;
   1127  1.1       jtc 			Area *saved_atemp;
   1128  1.3  christos #ifdef __GNUC__
   1129  1.3  christos 			(void) &ps1;
   1130  1.3  christos #endif
   1131  1.1       jtc 
   1132  1.1       jtc 			ps1 = str_val(global("PS1"));
   1133  1.1       jtc 			shf = shf_sopen((char *) 0, strlen(ps1) * 2,
   1134  1.1       jtc 				SHF_WR | SHF_DYNAMIC, (struct shf *) 0);
   1135  1.1       jtc 			while (*ps1) {
   1136  1.1       jtc 				if (*ps1 != '!' || *++ps1 == '!')
   1137  1.1       jtc 					shf_putchar(*ps1++, shf);
   1138  1.1       jtc 				else
   1139  1.1       jtc 					shf_fprintf(shf, "%d",
   1140  1.1       jtc 						s ? s->line + 1 : 0);
   1141  1.1       jtc 			}
   1142  1.1       jtc 			ps1 = shf_sclose(shf);
   1143  1.1       jtc 			saved_atemp = ATEMP;
   1144  1.1       jtc 			newenv(E_ERRH);
   1145  1.1       jtc 			if (ksh_sigsetjmp(e->jbuf, 0)) {
   1146  1.1       jtc 				prompt = safe_prompt;
   1147  1.1       jtc 				/* Don't print an error - assume it has already
   1148  1.1       jtc 				 * been printed.  Reason is we may have forked
   1149  1.1       jtc 				 * to run a command and the child may be
   1150  1.1       jtc 				 * unwinding its stack through this code as it
   1151  1.1       jtc 				 * exits.
   1152  1.1       jtc 				 */
   1153  1.1       jtc 			} else
   1154  1.1       jtc 				prompt = str_save(substitute(ps1, 0),
   1155  1.1       jtc 						 saved_atemp);
   1156  1.1       jtc 			quitenv();
   1157  1.1       jtc 		}
   1158  1.1       jtc #else /* KSH */
   1159  1.1       jtc 		prompt = str_val(global("PS1"));
   1160  1.1       jtc #endif /* KSH */
   1161  1.1       jtc 		break;
   1162  1.1       jtc 
   1163  1.1       jtc 	case PS2: /* command continuation */
   1164  1.1       jtc 		prompt = str_val(global("PS2"));
   1165  1.1       jtc 		break;
   1166  1.1       jtc 	}
   1167  1.1       jtc }
   1168  1.1       jtc 
   1169  1.1       jtc /* See also related routine, promptlen() in edit.c */
   1170  1.1       jtc void
   1171  1.1       jtc pprompt(cp, ntruncate)
   1172  1.1       jtc 	const char *cp;
   1173  1.1       jtc 	int ntruncate;
   1174  1.1       jtc {
   1175  1.1       jtc #if 0
   1176  1.1       jtc 	char nbuf[32];
   1177  1.1       jtc 	int c;
   1178  1.1       jtc 
   1179  1.1       jtc 	while (*cp != 0) {
   1180  1.1       jtc 		if (*cp != '!')
   1181  1.1       jtc 			c = *cp++;
   1182  1.1       jtc 		else if (*++cp == '!')
   1183  1.1       jtc 			c = *cp++;
   1184  1.1       jtc 		else {
   1185  1.1       jtc 			int len;
   1186  1.1       jtc 			char *p;
   1187  1.1       jtc 
   1188  1.1       jtc 			shf_snprintf(p = nbuf, sizeof(nbuf), "%d",
   1189  1.1       jtc 				source->line + 1);
   1190  1.1       jtc 			len = strlen(nbuf);
   1191  1.1       jtc 			if (ntruncate) {
   1192  1.1       jtc 				if (ntruncate >= len) {
   1193  1.1       jtc 					ntruncate -= len;
   1194  1.1       jtc 					continue;
   1195  1.1       jtc 				}
   1196  1.1       jtc 				p += ntruncate;
   1197  1.1       jtc 				len -= ntruncate;
   1198  1.1       jtc 				ntruncate = 0;
   1199  1.1       jtc 			}
   1200  1.1       jtc 			shf_write(p, len, shl_out);
   1201  1.1       jtc 			continue;
   1202  1.1       jtc 		}
   1203  1.1       jtc 		if (ntruncate)
   1204  1.1       jtc 			--ntruncate;
   1205  1.1       jtc 		else
   1206  1.1       jtc 			shf_putc(c, shl_out);
   1207  1.1       jtc 	}
   1208  1.1       jtc #endif /* 0 */
   1209  1.2       tls 	shf_puts(cp + ntruncate, shl_out);
   1210  1.2       tls 	shf_flush(shl_out);
   1211  1.1       jtc }
   1212  1.1       jtc 
   1213  1.1       jtc /* Read the variable part of a ${...} expression (ie, up to but not including
   1214  1.1       jtc  * the :[-+?=#%] or close-brace.
   1215  1.1       jtc  */
   1216  1.1       jtc static char *
   1217  1.1       jtc get_brace_var(wsp, wp)
   1218  1.1       jtc 	XString *wsp;
   1219  1.1       jtc 	char *wp;
   1220  1.1       jtc {
   1221  1.1       jtc 	enum parse_state {
   1222  1.1       jtc 			   PS_INITIAL, PS_SAW_HASH, PS_IDENT,
   1223  1.1       jtc 			   PS_NUMBER, PS_VAR1, PS_END
   1224  1.1       jtc 			 }
   1225  1.1       jtc 		state;
   1226  1.1       jtc 	char c;
   1227  1.1       jtc 
   1228  1.1       jtc 	state = PS_INITIAL;
   1229  1.1       jtc 	while (1) {
   1230  1.2       tls 		c = getsc();
   1231  1.1       jtc 		/* State machine to figure out where the variable part ends. */
   1232  1.1       jtc 		switch (state) {
   1233  1.1       jtc 		  case PS_INITIAL:
   1234  1.1       jtc 			if (c == '#') {
   1235  1.1       jtc 				state = PS_SAW_HASH;
   1236  1.1       jtc 				break;
   1237  1.1       jtc 			}
   1238  1.1       jtc 			/* fall through.. */
   1239  1.1       jtc 		  case PS_SAW_HASH:
   1240  1.1       jtc 			if (letter(c))
   1241  1.1       jtc 				state = PS_IDENT;
   1242  1.1       jtc 			else if (digit(c))
   1243  1.1       jtc 				state = PS_NUMBER;
   1244  1.1       jtc 			else if (ctype(c, C_VAR1))
   1245  1.1       jtc 				state = PS_VAR1;
   1246  1.1       jtc 			else
   1247  1.1       jtc 				state = PS_END;
   1248  1.1       jtc 			break;
   1249  1.1       jtc 		  case PS_IDENT:
   1250  1.1       jtc 			if (!letnum(c)) {
   1251  1.1       jtc 				state = PS_END;
   1252  1.1       jtc 				if (c == '[') {
   1253  1.1       jtc 					char *tmp, *p;
   1254  1.1       jtc 
   1255  1.1       jtc 					if (!arraysub(&tmp))
   1256  1.1       jtc 						yyerror("missing ]\n");
   1257  1.1       jtc 					*wp++ = c;
   1258  1.1       jtc 					for (p = tmp; *p; ) {
   1259  1.1       jtc 						Xcheck(*wsp, wp);
   1260  1.1       jtc 						*wp++ = *p++;
   1261  1.1       jtc 					}
   1262  1.1       jtc 					afree(tmp, ATEMP);
   1263  1.2       tls 					c = getsc(); /* the ] */
   1264  1.1       jtc 				}
   1265  1.1       jtc 			}
   1266  1.1       jtc 			break;
   1267  1.1       jtc 		  case PS_NUMBER:
   1268  1.1       jtc 			if (!digit(c))
   1269  1.1       jtc 				state = PS_END;
   1270  1.1       jtc 			break;
   1271  1.1       jtc 		  case PS_VAR1:
   1272  1.1       jtc 			state = PS_END;
   1273  1.1       jtc 			break;
   1274  1.1       jtc 		  case PS_END: /* keep gcc happy */
   1275  1.1       jtc 			break;
   1276  1.1       jtc 		}
   1277  1.1       jtc 		if (state == PS_END) {
   1278  1.1       jtc 			*wp++ = '\0';	/* end of variable part */
   1279  1.1       jtc 			ungetsc(c);
   1280  1.1       jtc 			break;
   1281  1.1       jtc 		}
   1282  1.1       jtc 		Xcheck(*wsp, wp);
   1283  1.1       jtc 		*wp++ = c;
   1284  1.1       jtc 	}
   1285  1.1       jtc 	return wp;
   1286  1.1       jtc }
   1287  1.1       jtc 
   1288  1.1       jtc /*
   1289  1.1       jtc  * Save an array subscript - returns true if matching bracket found, false
   1290  1.1       jtc  * if eof or newline was found.
   1291  1.1       jtc  * (Returned string double null terminated)
   1292  1.1       jtc  */
   1293  1.1       jtc static int
   1294  1.1       jtc arraysub(strp)
   1295  1.1       jtc 	char **strp;
   1296  1.1       jtc {
   1297  1.1       jtc 	XString ws;
   1298  1.1       jtc 	char	*wp;
   1299  1.1       jtc 	char	c;
   1300  1.1       jtc 	int 	depth = 1;	/* we are just past the initial [ */
   1301  1.1       jtc 
   1302  1.1       jtc 	Xinit(ws, wp, 32, ATEMP);
   1303  1.1       jtc 
   1304  1.1       jtc 	do {
   1305  1.2       tls 		c = getsc();
   1306  1.1       jtc 		Xcheck(ws, wp);
   1307  1.1       jtc 		*wp++ = c;
   1308  1.1       jtc 		if (c == '[')
   1309  1.1       jtc 			depth++;
   1310  1.1       jtc 		else if (c == ']')
   1311  1.1       jtc 			depth--;
   1312  1.1       jtc 	} while (depth > 0 && c && c != '\n');
   1313  1.1       jtc 
   1314  1.1       jtc 	*wp++ = '\0';
   1315  1.1       jtc 	*strp = Xclose(ws, wp);
   1316  1.1       jtc 
   1317  1.1       jtc 	return depth == 0 ? 1 : 0;
   1318  1.1       jtc }
   1319  1.1       jtc 
   1320  1.1       jtc /* Unget a char: handles case when we are already at the start of the buffer */
   1321  1.1       jtc static const char *
   1322  1.2       tls ungetsc(c)
   1323  1.1       jtc 	int c;
   1324  1.1       jtc {
   1325  1.2       tls 	if (backslash_skip)
   1326  1.2       tls 		backslash_skip--;
   1327  1.1       jtc 	/* Don't unget eof... */
   1328  1.1       jtc 	if (source->str == null && c == '\0')
   1329  1.1       jtc 		return source->str;
   1330  1.1       jtc 	if (source->str > source->start)
   1331  1.1       jtc 		source->str--;
   1332  1.1       jtc 	else {
   1333  1.1       jtc 		Source *s;
   1334  1.1       jtc 
   1335  1.1       jtc 		s = pushs(SREREAD, source->areap);
   1336  1.2       tls 		s->ugbuf[0] = c; s->ugbuf[1] = '\0';
   1337  1.2       tls 		s->start = s->str = s->ugbuf;
   1338  1.1       jtc 		s->next = source;
   1339  1.1       jtc 		source = s;
   1340  1.1       jtc 	}
   1341  1.1       jtc 	return source->str;
   1342  1.1       jtc }
   1343  1.1       jtc 
   1344  1.2       tls 
   1345  1.1       jtc /* Called to get a char that isn't a \newline sequence. */
   1346  1.1       jtc static int
   1347  1.2       tls getsc_bn ARGS((void))
   1348  1.1       jtc {
   1349  1.2       tls 	int c, c2;
   1350  1.2       tls 
   1351  1.2       tls 	if (ignore_backslash_newline)
   1352  1.2       tls 		return getsc_();
   1353  1.2       tls 
   1354  1.2       tls 	if (backslash_skip == 1) {
   1355  1.2       tls 		backslash_skip = 2;
   1356  1.2       tls 		return getsc_();
   1357  1.2       tls 	}
   1358  1.2       tls 
   1359  1.2       tls 	backslash_skip = 0;
   1360  1.1       jtc 
   1361  1.1       jtc 	while (1) {
   1362  1.1       jtc 		c = getsc_();
   1363  1.2       tls 		if (c == '\\') {
   1364  1.2       tls 			if ((c2 = getsc_()) == '\n')
   1365  1.2       tls 				/* ignore the \newline; get the next char... */
   1366  1.2       tls 				continue;
   1367  1.2       tls 			ungetsc(c2);
   1368  1.2       tls 			backslash_skip = 1;
   1369  1.1       jtc 		}
   1370  1.2       tls 		return c;
   1371  1.1       jtc 	}
   1372  1.6   hubertf }
   1373  1.6   hubertf 
   1374  1.6   hubertf static Lex_state *
   1375  1.6   hubertf push_state_(si, old_end)
   1376  1.6   hubertf 	State_info *si;
   1377  1.6   hubertf 	Lex_state *old_end;
   1378  1.6   hubertf {
   1379  1.6   hubertf 	Lex_state	*new = alloc(sizeof(Lex_state) * STATE_BSIZE, ATEMP);
   1380  1.6   hubertf 
   1381  1.6   hubertf 	new[0].ls_info.base = old_end;
   1382  1.6   hubertf 	si->base = &new[0];
   1383  1.6   hubertf 	si->end = &new[STATE_BSIZE];
   1384  1.6   hubertf 	return &new[1];
   1385  1.6   hubertf }
   1386  1.6   hubertf 
   1387  1.6   hubertf static Lex_state *
   1388  1.6   hubertf pop_state_(si, old_end)
   1389  1.6   hubertf 	State_info *si;
   1390  1.6   hubertf 	Lex_state *old_end;
   1391  1.6   hubertf {
   1392  1.6   hubertf 	Lex_state *old_base = si->base;
   1393  1.6   hubertf 
   1394  1.6   hubertf 	si->base = old_end->ls_info.base - STATE_BSIZE;
   1395  1.6   hubertf 	si->end = old_end->ls_info.base;
   1396  1.6   hubertf 
   1397  1.6   hubertf 	afree(old_base, ATEMP);
   1398  1.6   hubertf 
   1399  1.6   hubertf 	return si->base + STATE_BSIZE - 1;;
   1400  1.1       jtc }
   1401