📄 lex.c
字号:
/*- * Copyright (c) 1980, 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)lex.c 8.1 (Berkeley) 5/31/93";#endif /* not lint */#include <sys/types.h>#include <sys/ioctl.h>#include <termios.h>#include <errno.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#if __STDC__# include <stdarg.h>#else# include <varargs.h>#endif#include "csh.h"#include "extern.h"/* * These lexical routines read input and form lists of words. * There is some involved processing here, because of the complications * of input buffering, and especially because of history substitution. */static Char *word __P((void));static int getC1 __P((int));static void getdol __P((void));static void getexcl __P((int));static struct Hist *findev __P((Char *, bool));static void setexclp __P((Char *));static int bgetc __P((void));static void bfree __P((void));static struct wordent *gethent __P((int));static int matchs __P((Char *, Char *));static int getsel __P((int *, int *, int));static struct wordent *getsub __P((struct wordent *));static Char *subword __P((Char *, int, bool *));static struct wordent *dosub __P((int, struct wordent *, bool));/* * Peekc is a peek character for getC, peekread for readc. * There is a subtlety here in many places... history routines * will read ahead and then insert stuff into the input stream. * If they push back a character then they must push it behind * the text substituted by the history substitution. On the other * hand in several places we need 2 peek characters. To make this * all work, the history routines read with getC, and make use both * of ungetC and unreadc. The key observation is that the state * of getC at the call of a history reference is such that calls * to getC from the history routines will always yield calls of * readc, unless this peeking is involved. That is to say that during * getexcl the variables lap, exclp, and exclnxt are all zero. * * Getdol invokes history substitution, hence the extra peek, peekd, * which it can ungetD to be before history substitutions. */static Char peekc = 0, peekd = 0;static Char peekread = 0;/* (Tail of) current word from ! subst */static Char *exclp = NULL;/* The rest of the ! subst words */static struct wordent *exclnxt = NULL;/* Count of remaining words in ! subst */static int exclc = 0;/* "Globp" for alias resubstitution */Char *alvecp = NULL;int aret = F_SEEK;/* * Labuf implements a general buffer for lookahead during lexical operations. * Text which is to be placed in the input stream can be stuck here. * We stick parsed ahead $ constructs during initial input, * process id's from `$$', and modified variable values (from qualifiers * during expansion in sh.dol.c) here. */static Char labuf[BUFSIZ];/* * Lex returns to its caller not only a wordlist (as a "var" parameter) * but also whether a history substitution occurred. This is used in * the main (process) routine to determine whether to echo, and also * when called by the alias routine to determine whether to keep the * argument list. */static bool hadhist = 0;/* * Avoid alias expansion recursion via \!# */int hleft;static Char getCtmp;#define getC(f) ((getCtmp = peekc) ? (peekc = 0, getCtmp) : getC1(f))#define ungetC(c) peekc = c#define ungetD(c) peekd = cintlex(hp) register struct wordent *hp;{ register struct wordent *wdp; int c; btell(&lineloc); hp->next = hp->prev = hp; hp->word = STRNULL; hadhist = 0; do c = readc(0); while (c == ' ' || c == '\t'); if (c == HISTSUB && intty) /* ^lef^rit from tty is short !:s^lef^rit */ getexcl(c); else unreadc(c); wdp = hp; /* * The following loop is written so that the links needed by freelex will * be ready and rarin to go even if it is interrupted. */ do { register struct wordent *new; new = (struct wordent *) xmalloc((size_t) sizeof(*wdp)); new->word = 0; new->prev = wdp; new->next = hp; wdp->next = new; wdp = new; wdp->word = word(); } while (wdp->word[0] != '\n'); hp->prev = wdp; return (hadhist);}voidprlex(fp, sp0) FILE *fp; struct wordent *sp0;{ register struct wordent *sp = sp0->next; for (;;) { (void) fprintf(fp, "%s", vis_str(sp->word)); sp = sp->next; if (sp == sp0) break; if (sp->word[0] != '\n') (void) fputc(' ', fp); }}voidcopylex(hp, fp) register struct wordent *hp; register struct wordent *fp;{ register struct wordent *wdp; wdp = hp; fp = fp->next; do { register struct wordent *new; new = (struct wordent *) xmalloc((size_t) sizeof(*wdp)); new->prev = wdp; new->next = hp; wdp->next = new; wdp = new; wdp->word = Strsave(fp->word); fp = fp->next; } while (wdp->word[0] != '\n'); hp->prev = wdp;}voidfreelex(vp) register struct wordent *vp;{ register struct wordent *fp; while (vp->next != vp) { fp = vp->next; vp->next = fp->next; xfree((ptr_t) fp->word); xfree((ptr_t) fp); } vp->prev = vp;}static Char *word(){ register Char c, c1; register Char *wp; Char wbuf[BUFSIZ]; register bool dolflg; register int i; wp = wbuf; i = BUFSIZ - 4;loop: while ((c = getC(DOALL)) == ' ' || c == '\t') continue; if (cmap(c, _META | _ESC)) switch (c) { case '&': case '|': case '<': case '>': *wp++ = c; c1 = getC(DOALL); if (c1 == c) *wp++ = c1; else ungetC(c1); goto ret; case '#': if (intty) break; c = 0; do { c1 = c; c = getC(0); } while (c != '\n'); if (c1 == '\\') goto loop; /* fall into ... */ case ';': case '(': case ')': case '\n': *wp++ = c; goto ret; case '\\': c = getC(0); if (c == '\n') { if (onelflg == 1) onelflg = 2; goto loop; } if (c != HIST) *wp++ = '\\', --i; c |= QUOTE; } c1 = 0; dolflg = DOALL; for (;;) { if (c1) { if (c == c1) { c1 = 0; dolflg = DOALL; } else if (c == '\\') { c = getC(0); if (c == HIST) c |= QUOTE; else { if (c == '\n') /* * if (c1 == '`') c = ' '; else */ c |= QUOTE; ungetC(c); c = '\\'; } } else if (c == '\n') { seterror(ERR_UNMATCHED, c1); ungetC(c); break; } } else if (cmap(c, _META | _QF | _QB | _ESC)) { if (c == '\\') { c = getC(0); if (c == '\n') { if (onelflg == 1) onelflg = 2; break; } if (c != HIST) *wp++ = '\\', --i; c |= QUOTE; } else if (cmap(c, _QF | _QB)) { /* '"` */ c1 = c; dolflg = c == '"' ? DOALL : DOEXCL; } else if (c != '#' || !intty) { ungetC(c); break; } } if (--i > 0) { *wp++ = c; c = getC(dolflg); } else { seterror(ERR_WTOOLONG); wp = &wbuf[1]; break; } }ret: *wp = 0; return (Strsave(wbuf));}static intgetC1(flag) register int flag;{ register Char c; while (1) { if ((c = peekc) != '\0') { peekc = 0; return (c); } if (lap) { if ((c = *lap++) == 0) lap = 0; else { if (cmap(c, _META | _QF | _QB)) c |= QUOTE; return (c); } } if ((c = peekd) != '\0') { peekd = 0; return (c); } if (exclp) { if ((c = *exclp++) != '\0') return (c); if (exclnxt && --exclc >= 0) { exclnxt = exclnxt->next; setexclp(exclnxt->word); return (' '); } exclp = 0; exclnxt = 0; } if (exclnxt) { exclnxt = exclnxt->next; if (--exclc < 0) exclnxt = 0; else setexclp(exclnxt->word); continue; } c = readc(0); if (c == '$' && (flag & DODOL)) { getdol(); continue; } if (c == HIST && (flag & DOEXCL)) { getexcl(0); continue; } break; } return (c);}static voidgetdol(){ register Char *np, *ep; Char name[4 * MAXVARLEN + 1]; register int c; int sc; bool special = 0, toolong; np = name, *np++ = '$'; c = sc = getC(DOEXCL); if (any("\t \n", c)) { ungetD(c); ungetC('$' | QUOTE); return; } if (c == '{') *np++ = c, c = getC(DOEXCL); if (c == '#' || c == '?') special++, *np++ = c, c = getC(DOEXCL); *np++ = c; switch (c) { case '<': case '$': case '!': if (special) seterror(ERR_SPDOLLT); *np = 0; addla(name); return; case '\n': ungetD(c); np--; seterror(ERR_NEWLINE); *np = 0; addla(name); return; case '*': if (special) seterror(ERR_SPSTAR); *np = 0; addla(name); return; default: toolong = 0; if (Isdigit(c)) {#ifdef notdef /* let $?0 pass for now */ if (special) { seterror(ERR_DIGIT); *np = 0; addla(name); return; }#endif /* we know that np < &name[4] */ ep = &np[MAXVARLEN]; while ((c = getC(DOEXCL)) != '\0'){ if (!Isdigit(c)) break; if (np < ep) *np++ = c; else toolong = 1; } } else if (letter(c)) { /* we know that np < &name[4] */ ep = &np[MAXVARLEN]; toolong = 0; while ((c = getC(DOEXCL)) != '\0') { /* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */ if (!letter(c) && !Isdigit(c)) break; if (np < ep) *np++ = c; else toolong = 1; } } else { *np = 0; seterror(ERR_VARILL); addla(name); return; } if (toolong) { seterror(ERR_VARTOOLONG); *np = 0; addla(name); return; } break; } if (c == '[') { *np++ = c; /* * Name up to here is a max of MAXVARLEN + 8. */ ep = &np[2 * MAXVARLEN + 8]; do { /* * Michael Greim: Allow $ expansion to take place in selector * expressions. (limits the number of characters returned) */ c = getC(DOEXCL | DODOL); if (c == '\n') { ungetD(c); np--; seterror(ERR_NLINDEX); *np = 0; addla(name); return; } if (np < ep) *np++ = c; } while (c != ']'); *np = '\0'; if (np >= ep) { seterror(ERR_SELOVFL); addla(name); return; } c = getC(DOEXCL); } /* * Name up to here is a max of 2 * MAXVARLEN + 8. */ if (c == ':') { /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -