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