|
|
1.1 ! root 1: /* ! 2: * lex/lex2.c ! 3: * lexical analyser and utilities ! 4: */ ! 5: ! 6: #include "lex.h" ! 7: #define CMAX 3 ! 8: ! 9: char cbuf[CMAX]; ! 10: int bufc = 0; ! 11: int lstchr = '\n'; ! 12: int line = 0; ! 13: ! 14: char * ! 15: alloc(n) ! 16: register n; ! 17: { ! 18: register char *pc; ! 19: ! 20: if ((pc=malloc(n)) == NULL) ! 21: error(outmem); ! 22: return (pc); ! 23: } ! 24: ! 25: char * ! 26: ralloc(pc, n) ! 27: char *pc; ! 28: { ! 29: if ((pc=realloc(pc, n)) == NULL) ! 30: error(outmem); ! 31: return (pc); ! 32: } ! 33: ! 34: /* ! 35: * lexical ananlyser for regular expressions ! 36: */ ! 37: yylex() ! 38: { ! 39: switch (yylval = next()) { ! 40: case '\\': ! 41: yylval = escape(); ! 42: return (LX_CHAR); ! 43: case '"': ! 44: inquotes = 1-inquotes; ! 45: return (LX_OPER); ! 46: case EOF: ! 47: error(eoferr); ! 48: default: ! 49: if (inquotes) ! 50: if (yylval == '\n') ! 51: error("%s in quoted string", illnln); ! 52: else ! 53: return (LX_CHAR); ! 54: } ! 55: switch (yylval) { ! 56: case '[': ! 57: yylval = getclas(); ! 58: return (LX_CLAS); ! 59: case '.': ! 60: return (LX_ANYC); ! 61: case ' ': ! 62: case '\t': ! 63: case '\n': ! 64: return (LX_TERM); ! 65: case '/': ! 66: return (indefs? LX_OPER : LX_TERM); ! 67: case '$': ! 68: if (!indefs && isspace(look(0))) ! 69: return (LX_TERM); ! 70: case '^': ! 71: case '<': ! 72: case '(': ! 73: case ')': ! 74: case '{': ! 75: case '*': ! 76: case '?': ! 77: case '+': ! 78: case '|': ! 79: return (LX_OPER); ! 80: default: ! 81: if (!isascii(yylval) || iscntrl(yylval)) ! 82: error("%s in regular expression", illchr); ! 83: return (LX_CHAR); ! 84: } ! 85: } ! 86: ! 87: /* ! 88: * get a backslashed character ! 89: */ ! 90: escape() ! 91: { ! 92: register c, i; ! 93: ! 94: switch (c = next()) { ! 95: case 'b': ! 96: return ('\b'); ! 97: case 'f': ! 98: return ('\f'); ! 99: case 'n': ! 100: return ('\n'); ! 101: case 'r': ! 102: return ('\r'); ! 103: case 't': ! 104: return ('\t'); ! 105: default: ! 106: if (isoctl(c)) { ! 107: for (i=0; c-='0', i<2 && isoctl(look(0)); ++i) ! 108: c = c * 8 + next(); ! 109: if (c > MAXUCHAR) ! 110: error(illoct); ! 111: } ! 112: return (c); ! 113: } ! 114: } ! 115: ! 116: /* ! 117: * read and store a class specification ! 118: */ ! 119: getclas() ! 120: { ! 121: register unsigned int c,d; ! 122: register unsigned char *index; ! 123: register int bit; ! 124: register int invert; ! 125: ! 126: if (clas == 0) { ! 127: classptr = alloc(MAXUCHAR+1); ! 128: index = classptr + (c = MAXUCHAR + 1); ! 129: while (c--) ! 130: *--index = 0; ! 131: } else if ((clas % NBCHAR) == 0) { ! 132: c = classindex(clas + NBCHAR); ! 133: classptr = ralloc(classptr, c); ! 134: index = classptr + c; ! 135: c = MAXUCHAR + 1; ! 136: while (c--) ! 137: *--index = 0; ! 138: } else ! 139: index = classptr + classindex(clas); ! 140: bit = classbit(clas); ! 141: if (look(0) == '^') { ! 142: invert = 1; ! 143: next(); ! 144: } else ! 145: invert = 0; ! 146: while ((c=next()) != ']') { ! 147: if (iscntrl(c)) ! 148: error("%s in class", illchr); ! 149: if (c == EOF) ! 150: error(eoferr); ! 151: if (c == '.') { ! 152: c = index['\n'] & bit; ! 153: for (d=0; d<=MAXUCHAR; ++d) ! 154: index[d] |= bit; ! 155: if (!c) ! 156: index['\n'] ^= bit; ! 157: } else { ! 158: if (c == '\\') ! 159: c = escape(); ! 160: d = c; ! 161: if (look(0) == '-') ! 162: if (next(), look(0) != ']') { ! 163: if ((d=next()) == '\\') ! 164: d = escape(); ! 165: if (d < c) ! 166: error(illrng); ! 167: } else ! 168: index['-'] |= bit; ! 169: do { ! 170: index[c] |= bit; ! 171: } while (c++ < d); ! 172: } ! 173: } ! 174: if (invert) { ! 175: for (d=0; d<=MAXUCHAR; ++d) ! 176: index[d] ^= bit; ! 177: } ! 178: return (clas++); ! 179: } ! 180: ! 181: /* ! 182: * get next character from input ! 183: */ ! 184: next() ! 185: { ! 186: static l = '\n'; ! 187: register c, i; ! 188: ! 189: if (l == '\n') ! 190: ++line; ! 191: if (bufc == 0) ! 192: c = lstchr = getc(filein); ! 193: else { ! 194: c = cbuf[0]; ! 195: for (i=1; i < bufc; i++) ! 196: cbuf[i-1] = cbuf[i]; ! 197: --bufc; ! 198: } ! 199: return (l=c); ! 200: } ! 201: ! 202: /* ! 203: * look into input for the n+1th character ! 204: * practically, n never exceeds 2 ! 205: */ ! 206: look(n) ! 207: register int n; ! 208: { ! 209: while (bufc <= n) ! 210: cbuf[bufc++] = lstchr = getc(filein); ! 211: return (cbuf[n]); ! 212: } ! 213: ! 214: /* ! 215: * delete input up to and including the next newline ! 216: */ ! 217: dnl() ! 218: { ! 219: while (next() != '\n') ! 220: ; ! 221: setltype(); ! 222: } ! 223: ! 224: /* ! 225: * eat up white space ! 226: */ ! 227: eatspc() ! 228: { ! 229: register c; ! 230: ! 231: while (c=look(0), c==' ' || c=='\t') ! 232: next(); ! 233: if (c == EOF) ! 234: error(eoferr); ! 235: } ! 236: ! 237: /* ! 238: * eat input until white space ! 239: */ ! 240: eatlbl() ! 241: { ! 242: register c; ! 243: ! 244: while (c=look(0), !isspace(c)) ! 245: next(); ! 246: if (c == '\n') ! 247: return (1); ! 248: return (0); ! 249: } ! 250: ! 251: /* ! 252: * copy an input line to the output file ! 253: */ ! 254: lcopy() ! 255: { ! 256: register c; ! 257: ! 258: do { ! 259: putc(c=next(), fileout); ! 260: } while (c != '\n'); ! 261: setltype(); ! 262: } ! 263: ! 264: /* ! 265: * set external variable ltype to the type of the next line ! 266: */ ! 267: setltype() ! 268: { ! 269: ltype = getltype(); ! 270: } ! 271: ! 272: /* ! 273: * return line type based on the first couple of characters ! 274: */ ! 275: getltype() ! 276: { ! 277: switch (look(0)) { ! 278: case '\t': ! 279: case '\n': ! 280: case ' ': ! 281: return (LN_LSPC); ! 282: case EOF: ! 283: return (LN_EOFL); ! 284: case '%': ! 285: switch (look(1)) { ! 286: case '%': ! 287: return (LN_DLIM); ! 288: case '{': ! 289: return (LN_LCOM); ! 290: case '}': ! 291: return (LN_RCOM); ! 292: case 's': ! 293: case 'S': ! 294: return (LN_SCON); ! 295: case 'c': ! 296: case 'C': ! 297: return (LN_CTXT); ! 298: case 'x': ! 299: case 'X': ! 300: return (LN_OPTN); ! 301: } ! 302: } ! 303: return (LN_DFLT); ! 304: } ! 305: ! 306: /* ! 307: * put out a #line command for the C preprocessor ! 308: */ ! 309: outlnum(i) ! 310: { ! 311: loutput(0, "#line %d", line+i); ! 312: } ! 313: ! 314: /* ! 315: * copy a user-specified action to the output ! 316: */ ! 317: getactn() ! 318: { ! 319: enum cstate { /* states of c source */ ! 320: start, slash, comment, star, bsl, dquote, squote ! 321: } pstate; ! 322: register enum cstate state; ! 323: register c; ! 324: int bct; ! 325: ! 326: for (state = start, bct = 0;;) { ! 327: if (EOF == (c = next())) ! 328: error(eoferr); ! 329: putc(c, fileout); ! 330: ! 331: switch (state) { ! 332: case slash: /* maybe a comment */ ! 333: if ('*' == c) { ! 334: state = comment; ! 335: break; ! 336: } ! 337: state = start; ! 338: case start: /* normal text state */ ! 339: switch (c) { ! 340: case '/': ! 341: state = slash; ! 342: break; ! 343: case '\\': ! 344: pstate = state; ! 345: state = bsl; ! 346: break; ! 347: case '"': ! 348: state = dquote; ! 349: break; ! 350: case '\'': ! 351: state = squote; ! 352: break; ! 353: case '{': ! 354: bct++; ! 355: break; ! 356: case '}': ! 357: if (--bct < 0) ! 358: error(actsyn); ! 359: break; ! 360: case '\n': ! 361: if (!bct) { ! 362: setltype(); ! 363: return; ! 364: } ! 365: } ! 366: break; ! 367: case star: /* saw * in comment */ ! 368: if ('/' == c) { ! 369: state = start; ! 370: break; ! 371: } ! 372: state = comment; ! 373: case comment: /* in comment */ ! 374: if ('*' == c) ! 375: state = star; ! 376: break; ! 377: case bsl: /* char after backslash */ ! 378: state = pstate; ! 379: break; ! 380: case dquote: /* in double quoted string */ ! 381: case squote: /* in single quoted string */ ! 382: switch (c) { ! 383: case '"': ! 384: if (dquote == state) ! 385: state = start; ! 386: break; ! 387: case '\'': ! 388: if (squote == state) ! 389: state = start; ! 390: break; ! 391: case '\n': ! 392: error(actsyn); ! 393: break; ! 394: case '\\': ! 395: pstate = state; ! 396: state = bsl; ! 397: } ! 398: } ! 399: } ! 400: } ! 401: ! 402: /* ! 403: * read an identifier ! 404: */ ! 405: char * ! 406: getident() ! 407: { ! 408: register c, i = 0; ! 409: register char *pc; ! 410: ! 411: eatspc(); ! 412: pc = alloc(NCBLK); ! 413: while (c=look(0), isalnum(c) || c=='_') { ! 414: pc[i++] = next(); ! 415: if (i%NCBLK == 0) ! 416: pc = ralloc((char *)pc, i+NCBLK); ! 417: } ! 418: pc[i] = '\0'; ! 419: eatspc(); ! 420: return (pc); ! 421: } ! 422: ! 423: /* ! 424: * interpret an identifier as the name of a ! 425: * start condition, try to return its value ! 426: */ ! 427: getstart() ! 428: { ! 429: register struct def *pd; ! 430: register char *pc; ! 431: ! 432: pd = scnstart; ! 433: pc = getident(); ! 434: do { ! 435: if (strcmp(pc, pd->d_name) == 0) { ! 436: free(pc); ! 437: return (pd->d_data); ! 438: } ! 439: } while ((pd=pd->d_next) != NULL); ! 440: error(undstc); ! 441: } ! 442: ! 443: /* ! 444: * add a string of identifiers to the start condition ! 445: * list, numbering them as we go, too bad if they ! 446: * are duplicates ! 447: */ ! 448: addstart() ! 449: { ! 450: register struct def *pd; ! 451: ! 452: if (eatlbl()) ! 453: return; ! 454: pd = scnstart; ! 455: while (look(0) != '\n') { ! 456: pd->d_next = alloc(sizeof(struct def)); ! 457: pd->d_next->d_data = pd->d_data + 1; ! 458: pd = pd->d_next; ! 459: pd->d_next = NULL; ! 460: pd->d_name = getident(); ! 461: } ! 462: } ! 463: ! 464: /* ! 465: * like addstart, except with names of contexts ! 466: */ ! 467: addcontext() ! 468: { ! 469: register struct def *pd; ! 470: ! 471: if (eatlbl()) ! 472: return; ! 473: pd = ctxstart; ! 474: while (pd->d_next != NULL) ! 475: pd = pd->d_next; ! 476: pd->d_next = alloc(sizeof(struct def)); ! 477: pd = pd->d_next; ! 478: for (;;) { ! 479: pd->d_name = getident(); ! 480: pd->d_data = 0; ! 481: if (look(0) == '\n') { ! 482: pd->d_next = NULL; ! 483: break; ! 484: } else { ! 485: pd->d_next = alloc(sizeof(struct def)); ! 486: pd = pd->d_next; ! 487: } ! 488: } ! 489: } ! 490: ! 491: /* ! 492: * this is called to mark the context name with its ! 493: * associated section of the nfa ! 494: */ ! 495: markcontext(t) ! 496: { ! 497: register char *pc; ! 498: register struct def *pd; ! 499: ! 500: eatlbl(); ! 501: pc = getident(); ! 502: pd = ctxstart; ! 503: while ((pd=pd->d_next) != NULL) ! 504: if (strcmp(pc, pd->d_name) == 0) { ! 505: pd->d_data = t; ! 506: free(pc); ! 507: return; ! 508: } ! 509: error(undctx); ! 510: } ! 511: ! 512: /* ! 513: * read the name of the definition, try ! 514: * to return where it starts ! 515: */ ! 516: getdefn() ! 517: { ! 518: register char *pc; ! 519: register struct def *pd; ! 520: ! 521: pc = getident(); ! 522: if (look(0) == '}') ! 523: next(); ! 524: else ! 525: error("%s in definition name", illchr); ! 526: for (pd=defstart; pd!=NULL; pd=pd->d_next) ! 527: if (strcmp(pc, pd->d_name) == 0) { ! 528: free(pc); ! 529: return (pd->d_data); ! 530: } ! 531: error(unddef); ! 532: } ! 533: ! 534: /* ! 535: * recursive, costly but elegant ! 536: */ ! 537: freedef(pd) ! 538: register struct def *pd; ! 539: { ! 540: if (pd != NULL) { ! 541: freedef(pd->d_next); ! 542: if (pd->d_name != NULL) ! 543: free(pd->d_name); ! 544: free((char *)pd); ! 545: } ! 546: } ! 547: ! 548: /* ! 549: * cleanup and abort ! 550: */ ! 551: /* VARARGS */ ! 552: error(s) ! 553: { ! 554: fprintf(stderr, "lex: "); ! 555: if (line) ! 556: fprintf(stderr, "%d: ", line); ! 557: fprintf(stderr, "%r\n", &s); ! 558: if (filein == stdin) ! 559: while (lstchr!='\n' && lstchr!=EOF) ! 560: next(); ! 561: if (fileout != stdout) ! 562: unlink(OUTFILE); ! 563: exit (1); ! 564: } ! 565: ! 566: usage() ! 567: { ! 568: fprintf(stderr, "Usage: lex [-tv] [filename]\n"); ! 569: exit (1); ! 570: } ! 571: ! 572: /* end of lex2.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.