|
|
1.1 ! root 1: /* ! 2: * sh/lex.c ! 3: * Bourne shell. ! 4: * Lexical analysis. ! 5: */ ! 6: ! 7: #include "sh.h" ! 8: #include <y.tab.h> ! 9: ! 10: /* ! 11: * Local externals. ! 12: */ ! 13: int lastget = '\0'; /* Pushed back character */ ! 14: int eolflag = 0; /* End of line */ ! 15: ! 16: /* ! 17: * For processing here documents. ! 18: */ ! 19: char *hereeof = NULL; /* Here document EOF mark */ ! 20: int herefd; /* Here document fd */ ! 21: char *heretmp; /* Here document tempfile name */ ! 22: int hereqflag; /* Here document quoted */ ! 23: ! 24: /* ! 25: * Keyword table. ! 26: */ ! 27: typedef struct key { ! 28: int k_hash; /* Hash */ ! 29: int k_lexv; /* Lexical value */ ! 30: char *k_name; /* Keyword name */ ! 31: } KEY; ! 32: ! 33: /* ! 34: * Keyword table. ! 35: */ ! 36: KEY keytab[] ={ ! 37: 0, _CASE, "case", ! 38: 0, _DO, "do", ! 39: 0, _DONE, "done", ! 40: 0, _ELIF, "elif", ! 41: 0, _ELSE, "else", ! 42: 0, _ESAC, "esac", ! 43: 0, _FI, "fi", ! 44: 0, _FOR, "for", ! 45: 0, _IF, "if", ! 46: 0, _IN, "in", ! 47: 0, _THEN, "then", ! 48: 0, _UNTIL, "until", ! 49: 0, _WHILE, "while", ! 50: 0, _OBRAC, "{", ! 51: 0, _CBRAC, "}" ! 52: }; ! 53: #define NKEYS (sizeof(keytab) / sizeof(keytab[0])) ! 54: ! 55: /* ! 56: * Get the next lexical token. ! 57: */ ! 58: yylex() ! 59: { ! 60: register int c; ! 61: register KEY *kp; ! 62: int hash; ! 63: ! 64: /* Initialize hash values in key table. */ ! 65: if (keytab[0].k_hash == 0) ! 66: for (kp = &keytab[0]; kp < &keytab[NKEYS]; kp++) ! 67: kp->k_hash = ihash(kp->k_name); ! 68: again: ! 69: while ((c=getn())==' ' || c=='\t') ; ! 70: strp = strt; ! 71: if (c == '#' && readflag == 0) { ! 72: /* ! 73: * Ignore a '#'-delimited comment line. ! 74: * Lines which begin with a ':' token are lexed as usual; ! 75: * the built-in function s_colon() executes (i.e. ignores) ! 76: * lines starting with ':', while other ':' tokens get passed. ! 77: * The built-in "read" does not ignore comment lines. ! 78: */ ! 79: do ! 80: c = getn(); ! 81: while (c > 0 && c != '\n'); ! 82: return c; ! 83: } else if (class(c, MDIGI)) { ! 84: *strp++ = c; ! 85: c = getn(); ! 86: if (c=='>' || c=='<') { ! 87: *strp++ = c; ! 88: return lexiors(c); ! 89: } ! 90: ungetn(c); ! 91: return lexname(); ! 92: } ! 93: if (!class(c, MNAME)) { ! 94: ungetn(c); ! 95: if ((c = lexname()) == 0) ! 96: goto again; ! 97: else if (c < 0) ! 98: return c; ! 99: hash = ihash(strt); ! 100: if (keyflag) { ! 101: for (kp = keytab; kp < &keytab[NKEYS]; kp++) ! 102: if (hash == kp->k_hash && strcmp(strt, kp->k_name) == 0) ! 103: return kp->k_lexv; ! 104: } ! 105: return c; ! 106: } ! 107: *strp++ = c; ! 108: *strp = '\0'; ! 109: switch (c) { ! 110: case ';': ! 111: return isnext(c, _DSEMI); ! 112: case '>': ! 113: return lexiors(c); ! 114: case '<': ! 115: return lexiors(c); ! 116: case '&': ! 117: return isnext(c, _ANDF); ! 118: case '|': ! 119: #ifdef NAMEPIPE ! 120: if ( ! isnext(')', 0)) ! 121: return _NCLOSE; ! 122: #endif ! 123: return isnext(c, _ORF); ! 124: #ifdef NAMEPIPE ! 125: case '(': ! 126: return isnext('|', _NOPEN); ! 127: #endif ! 128: default: ! 129: if (hereeof != NULL) { ! 130: /* Read here document. */ ! 131: for (;;) { ! 132: strp = strt; ! 133: if ((c = collect('\n', 2)) < 0) ! 134: break; ! 135: *strp = '\0'; ! 136: if (strcmp(strt, hereeof)==0) ! 137: break; ! 138: if (herefd < 0) ! 139: continue; ! 140: if (!hereqflag && strp > strt + 1 && strp[-2]=='\\') ! 141: *(strp-=2) = '\0'; ! 142: if (!hereqflag && *strt=='\\' && strcmp(hereeof, strt+1)==0) ! 143: write(herefd, strt+1, strp-strt-1); ! 144: else ! 145: write(herefd, strt, strp-strt); ! 146: } ! 147: close(herefd); ! 148: cleanup(0, heretmp); ! 149: hereeof = NULL; ! 150: return '\n'; ! 151: } ! 152: return c; ! 153: } ! 154: } ! 155: ! 156: isnext(c, t1) ! 157: register int c; ! 158: { ! 159: register int c2; ! 160: ! 161: if ((c2=getn()) == c) { ! 162: *strp++ = c2; ! 163: *strp = '\0'; ! 164: return t1; ! 165: } ! 166: ungetn(c2); ! 167: return strp[-1]; ! 168: } ! 169: ! 170: /* ! 171: * Scan a single argument. ! 172: * Return 0 if it's an escaped newline, EOF if EOF is found, ! 173: * or _NAME or _ASGN if any part of an argument is found. ! 174: */ ! 175: lexname() ! 176: { ! 177: int q, asgn; ! 178: register int c, m; ! 179: register char *cp; ! 180: ! 181: q = 0; ! 182: asgn = 0; ! 183: m = MNQUO; ! 184: cp = strp; ! 185: for (;;) { ! 186: c = getn(); ! 187: if (asgn==0) ! 188: asgn = class(c, MBVAR) ? 1 : -1; ! 189: else if (asgn==1) ! 190: asgn = class(c, MRVAR) ? 1 : (c=='=' ? 2 : -1); ! 191: if (cp >= strt + STRSIZE) ! 192: etoolong(); ! 193: else ! 194: *cp++ = c; ! 195: if (!class(c, m)) ! 196: continue; ! 197: switch (c) { ! 198: case '"': ! 199: m = (q^=1) ? MDQUO : MNQUO; ! 200: continue; ! 201: case '\'': ! 202: strp = cp; ! 203: if ((c = collect('\'', 1)) != '\'') ! 204: break; ! 205: cp = strp; ! 206: continue; ! 207: case '\\': ! 208: if ((c=getn()) < 0) { ! 209: syntax(); ! 210: break; ! 211: } ! 212: if (c == '\n') { ! 213: ungetn((c=getn())<0 ? '\n' : c); ! 214: if (--cp == strp) ! 215: return 0; ! 216: continue; ! 217: } ! 218: *cp++ = c; ! 219: continue; ! 220: case '$': ! 221: if ((c=getn()) == '{') { ! 222: *cp++ = c; ! 223: strp = cp; ! 224: if ((c = collect('}', 0)) != '}') ! 225: break; ! 226: cp = strp; ! 227: continue; ! 228: } ! 229: ungetn(c); ! 230: continue; ! 231: case '`': ! 232: strp = cp; ! 233: if ((c = collect('`', 1)) != '`') ! 234: break; ! 235: cp = strp; ! 236: continue; ! 237: case '\n': ! 238: if (q) ! 239: continue; ! 240: break; ! 241: } ! 242: break; ! 243: } ! 244: if (c < 0) ! 245: return c; ! 246: if (q) { ! 247: emisschar('"'); ! 248: *cp = '\0'; ! 249: } else { ! 250: *--cp = '\0'; ! 251: } ! 252: ungetn(c); ! 253: strp = cp; ! 254: #ifdef VERBOSE ! 255: if (vflag) ! 256: prints("\t<%d> <%s> %s\n", getpid(), (asgn==2 ? "ASGN" : "NAME"), strt); ! 257: #endif ! 258: if (errflag) ! 259: return _NULL; ! 260: else if (asgn==2) ! 261: return _ASGN; ! 262: else ! 263: return _NAME; ! 264: return (asgn==2 ? _ASGN : _NAME); ! 265: } ! 266: ! 267: /* ! 268: * Lex an io redirection string, including the file name if any. ! 269: * Called with one '>' or '<' in buffer, optionally preceded by ! 270: * a digit. ! 271: */ ! 272: lexiors(c1) ! 273: { ! 274: register int c; ! 275: register char *name; ! 276: char *iors; ! 277: ! 278: *strp++ = c = getn(); ! 279: if (c=='&') { ! 280: *strp++ = c = getn(); ! 281: *strp = '\0'; ! 282: if (c < 0) return c; ! 283: if (c!='-' && !class(c, MDIGI)) ! 284: eredir(); ! 285: return _IORS; ! 286: } ! 287: if (c==c1) ! 288: c1 += 0200; ! 289: else { ! 290: *--strp = '\0'; ! 291: ungetn(c); ! 292: } ! 293: /* Collect file name */ ! 294: while ((c=getn())==' '||c=='\t') ! 295: *strp++ = c; ! 296: ungetn(c); ! 297: name = strp; ! 298: if (c=='\n') { ! 299: eredir(); ! 300: return _IORS; ! 301: } ! 302: while ((c = lexname())==0); ! 303: if (c < 0) return c; ! 304: if (c1!='<'+0200) ! 305: return _IORS; ! 306: #if 1 ! 307: /* ! 308: * Set up here document processing. ! 309: * Modified by steve 1/25/91 so that ! 310: * the actual processing happens at the '\n' ending the line, ! 311: * otherwise the common "foo <<SHAR_EOF >baz\n" does not work. ! 312: * This code is anything but obvious, it could doubtless be simpler. ! 313: */ ! 314: strp = strt; ! 315: /* Simplify quoted here document iors from ?<<file to ?<file. */ ! 316: if (hereqflag = (strpbrk(name, "\"\\'") != NULL)) ! 317: *++strp = *strt; ! 318: heretmp = name; ! 319: name = duplstr(name, 0); ! 320: strcpy(heretmp, shtmp()); ! 321: iors = duplstr(strp, 0); ! 322: heretmp += iors - strp; ! 323: eval(name, EWORD); ! 324: hereeof = duplstr(strcat(strt, "\n"), 0); ! 325: if ((herefd = creat(heretmp, 0666)) < 0) ! 326: ecantmake(heretmp); ! 327: strcpy(strt, iors); ! 328: #else ! 329: /* Collect here document */ ! 330: if ((c=getn())!='\n') { ! 331: eredir(); ! 332: ++strp; ! 333: c = collect('\n', 1); ! 334: } ! 335: if (c < 0) return c; ! 336: bpp = savebuf(); ! 337: strp = strt; ! 338: /* Simplify quoted to ?<file from ?<<file */ ! 339: if (quote = (strpbrk(name, "\"\\'") != NULL)) ! 340: *++strp = *strt; ! 341: tmp = name; ! 342: name = duplstr(name, 0); ! 343: strcpy(tmp, shtmp()); ! 344: iors = duplstr(strp, 0); ! 345: tmp += iors - strp; ! 346: eval(name, EWORD); ! 347: name = duplstr(strcat(strt, "\n"), 0); ! 348: if ((hfd = creat(tmp, 0666)) < 0) ! 349: ecantmake(tmp); ! 350: for (;;) { ! 351: strp = strt; ! 352: if ((c = collect('\n', 2)) < 0) ! 353: break; ! 354: *strp = '\0'; ! 355: if (strcmp(strt, name)==0) ! 356: break; ! 357: if (hfd < 0) ! 358: continue; ! 359: if (! quote && strp > strt + 1 && strp[-2]=='\\') ! 360: *(strp-=2) = '\0'; ! 361: if (! quote && *strt=='\\' && strcmp(name, strt+1)==0) ! 362: write(hfd, strt+1, strp-strt-1); ! 363: else ! 364: write(hfd, strt, strp-strt); ! 365: } ! 366: close(hfd); ! 367: cleanup(0, tmp); ! 368: ungetn('\n'); ! 369: strcpy(strt, iors); ! 370: freebuf(bpp); ! 371: /* Check for interrupt, since EOF is legal for once */ ! 372: if (c < 0 && ! recover(ILEX)) return c; ! 373: #endif ! 374: return _IORS; ! 375: } ! 376: ! 377: /* ! 378: * Collect characters until the end character is found. If `f' is ! 379: * set, all characters are passed through otherwise '\' escapes the ! 380: * next character and newline is not allowed. ! 381: * If `f' is set to 2, then no error is desired. ! 382: */ ! 383: collect(ec, f) ! 384: register int ec; ! 385: { ! 386: register int c; ! 387: register char *cp; ! 388: ! 389: cp = strp; ! 390: while ((c=getn()) != ec) { ! 391: if (c<0 || (c=='\n' && f==0)) { ! 392: if (--f <= 0) ! 393: emisschar(ec); ! 394: return c; ! 395: } ! 396: if (c=='\\' && f==0) { ! 397: if ((c=getn()) < 0) { ! 398: syntax(); ! 399: return c; ! 400: } ! 401: if (c == '\n') ! 402: continue; ! 403: } ! 404: if (cp >= strt + STRSIZE) ! 405: etoolong(); ! 406: else ! 407: *cp++ = c; ! 408: } ! 409: *cp++ = ec; ! 410: strp = cp; ! 411: return ec; ! 412: } ! 413: ! 414: /* ! 415: * Get a character. ! 416: */ ! 417: getn() ! 418: { ! 419: register int c; ! 420: register int t; ! 421: ! 422: if (lastget != '\0') { ! 423: c = lastget; ! 424: lastget = '\0'; ! 425: return c; ! 426: } ! 427: switch (t = sesp->s_type) { ! 428: case SSTR: ! 429: case SFILE: ! 430: yyline += eolflag; ! 431: eolflag = 0; ! 432: if (prpflag && sesp->s_flag) { ! 433: if (prpflag -= 1) { ! 434: prompt("\n"); ! 435: prpflag -= 1; ! 436: } ! 437: prompt(comflag ? vps1 : vps2); ! 438: comflag = 0; ! 439: } ! 440: if ((c=getc(sesp->s_ifp))=='\n') { ! 441: if (sesp->s_flag) { ! 442: prpflag = 1; ! 443: yyline = 1; ! 444: } else ! 445: eolflag = 1; ! 446: } ! 447: if (vflag) ! 448: putc(c, stderr); ! 449: return c; ! 450: case SARGS: ! 451: case SARGV: ! 452: if (sesp->s_flag) ! 453: return EOF; ! 454: if ((c=*sesp->s_strp++) == '\0') { ! 455: if (t == SARGV ! 456: && (sesp->s_strp=*++sesp->s_argv) != NULL) ! 457: c = ' '; ! 458: else { ! 459: sesp->s_flag = 1; ! 460: c = '\n'; ! 461: } ! 462: } ! 463: if (vflag) ! 464: putc(c, stderr); ! 465: return c; ! 466: } ! 467: } ! 468: ! 469: /* ! 470: * Unget a character. ! 471: */ ! 472: ungetn(c) ! 473: { ! 474: lastget = c; ! 475: } ! 476: ! 477: /* end of sh/lex.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.