|
|
1.1 ! root 1: /* ! 2: * AWK ! 3: * Main routine. ! 4: * Lexical analysis of input. ! 5: * Program input routines. ! 6: * Error message routines. ! 7: */ ! 8: ! 9: #include "awk.h" ! 10: #include "y.tab.h" ! 11: ! 12: CHAR *readclass(); ! 13: NODE *instring(); ! 14: NODE *innumber(); ! 15: ! 16: /* ! 17: * Main routine of AWK. ! 18: */ ! 19: main(argc, argv) ! 20: int argc; ! 21: CHAR *argv[]; ! 22: { ! 23: register int i; ! 24: register CHAR *ap; ! 25: register FILE *fp; ! 26: register CHAR *prog = NULL; ! 27: register CHAR *progfile; ! 28: NODE *yyparse(); ! 29: ! 30: awkinit(); ! 31: while (argc>1 && *argv[1]=='-') { ! 32: if (argv[1][1] == '\0') ! 33: break; /* - is stdin */ ! 34: switch (argv[1][1]) { ! 35: case 'F': ! 36: sassign(FSp, &argv[1][2]); ! 37: break; ! 38: ! 39: case 'f': ! 40: if (argc < 2) ! 41: usage(); ! 42: if ((pfp = fopen(argv[2], "r")) == NULL) ! 43: awkerr("Cannot open %s", argv[2]); ! 44: setbuf(pfp, inbuf); ! 45: progfile = argv[2]; ! 46: argv++; ! 47: argc--; ! 48: break; ! 49: ! 50: case 'y': ! 51: yflag++; ! 52: break; ! 53: ! 54: default: ! 55: usage(); ! 56: } ! 57: argv++; ! 58: argc--; ! 59: } ! 60: if (argc>1 && pfp==NULL) { ! 61: prog = argv[1]; ! 62: argv++; ! 63: argc--; ! 64: } ! 65: if (pfp==NULL && prog==NULL) ! 66: usage(); ! 67: while (argc>1 && parameter(argv[1])) { ! 68: argv++; ! 69: argc--; ! 70: } ! 71: pgetinit(prog); ! 72: if (pfp != NULL) { ! 73: lineno = 1; ! 74: sassign(FILENAMEp, progfile); ! 75: } ! 76: yyparse(); ! 77: if (pfp != NULL) ! 78: fclose(pfp); ! 79: fsmapinit(FS); ! 80: runflag = 1; ! 81: beginflag = 1; ! 82: if (setjmp(nextenv) == 0) ! 83: awk(codep, NULL, SNULL); ! 84: beginflag = 0; ! 85: if (argc > 1) { ! 86: for (i=1; i<argc; i++) { ! 87: ap = argv[i]; ! 88: if (ap[0]=='-' && ap[1]=='\0') ! 89: fp = stdin; ! 90: else if ((fp = fopen(ap, "r")) == NULL) { ! 91: fprintf(stderr, "awk: cannot open %s\n", ap); ! 92: exit(1); ! 93: } ! 94: awk(codep, fp, ap); ! 95: } ! 96: } else ! 97: awk(codep, stdin, SNULL); ! 98: awkexit(0); ! 99: } ! 100: ! 101: /* ! 102: * Read a parameter from the command line. ! 103: * Return non-zero if the string is a parameter. ! 104: * We have to fudge a bit to make sure `yylex' ! 105: * is properly reset. ! 106: */ ! 107: parameter(s) ! 108: CHAR *s; ! 109: { ! 110: register CHAR *cp; ! 111: register int c; ! 112: NODE *left, *right; ! 113: ! 114: cp = s; ! 115: if (!isalpha(*cp)) ! 116: return (0); ! 117: for (; (c = *cp)!='='; cp++) { ! 118: if (c == '\0') ! 119: return (0); ! 120: if (isspace(c)) { ! 121: *cp = '\0'; ! 122: continue; ! 123: } ! 124: if (!(isalpha(c) || isdigit(c))) ! 125: return (0); ! 126: } ! 127: *cp++ = '\0'; ! 128: left = lookup(s); ! 129: while (isspace(c = *cp++)) ! 130: ; ! 131: pgetinit(cp); ! 132: if (c == '"') ! 133: right = instring(c); ! 134: else if (isdigit(c) || c=='.') ! 135: right = innumber(c); ! 136: else ! 137: awkerr("non-constant assignment to parameter `%s'", s); ! 138: xassign(left, right); ! 139: return (1); ! 140: } ! 141: ! 142: /* ! 143: * Leave awk and run the ! 144: * cleanup (`END') phase. ! 145: */ ! 146: awkexit(s) ! 147: int s; ! 148: { ! 149: register OFILE *ofp; ! 150: ! 151: beginflag = 0; ! 152: endflag = 1; ! 153: exitflag = 1; ! 154: if (setjmp(nextenv) == 0) ! 155: awk(codep, NULL, SNULL); ! 156: for (ofp = files; ofp < endof(files); ofp++) ! 157: if (ofp->of_fp != NULL) { ! 158: if (ofp->of_flag & OFPIPE) ! 159: pclose(ofp->of_fp); else ! 160: fclose(ofp->of_fp); ! 161: } ! 162: exit(s); ! 163: } ! 164: ! 165: /* ! 166: * Lexical analyser. ! 167: * This must have flags to ! 168: * determine when certain ! 169: * types of characters are ! 170: * special (e.g. reading regular ! 171: * expressions) ! 172: * Delete multiple newlines. ! 173: */ ! 174: yylex() ! 175: { ! 176: static int nlf = 1; ! 177: static int prev, next; ! 178: register CHAR *cp; ! 179: register int c; ! 180: register int t; ! 181: register NODE *np; ! 182: ! 183: if (lexre) ! 184: return (relex()); ! 185: again: ! 186: if (next) { ! 187: t = next; ! 188: next = 0; ! 189: } else if ((t = c = pgetc()) == EOF) ! 190: ; ! 191: else if (!isascii(c)) ! 192: awkerr("%o is an illegal character", c); ! 193: else if (isdigit(c) || c=='.') { ! 194: yylval.u_node = innumber(c); ! 195: t = NUMBER_; ! 196: } else if (isalpha(c)) { ! 197: cp = wordbuf; ! 198: do { ! 199: *cp++ = c; ! 200: c = pgetc(); ! 201: } while (isalpha(c) || isdigit(c)); ! 202: pungetc(c); ! 203: *cp = '\0'; ! 204: np = lookup(wordbuf); ! 205: if (np->t_op == AKEYW) ! 206: t = np->t_INT; ! 207: else if (np->t_op == AFUNC) { ! 208: t = FUNCTION_; ! 209: yylval.u_node = np; ! 210: } else { ! 211: t = ID_; ! 212: yylval.u_node = np; ! 213: } ! 214: } else switch (c) { ! 215: ! 216: case '"': ! 217: yylval.u_node = instring(c); ! 218: t = STRING_; ! 219: break; ! 220: ! 221: case '#': ! 222: while ((c = pgetc())!=EOF && c!='\n') ! 223: ; ! 224: pungetc(c); ! 225: goto again; ! 226: ! 227: case '{': ! 228: brlevel++; ! 229: break; ! 230: ! 231: case '}': ! 232: if (--brlevel < 0) { ! 233: awkerr("Unbalanced braces"); ! 234: brlevel = 0; ! 235: } ! 236: next = '}'; ! 237: t = ';'; ! 238: break; ! 239: ! 240: case '!': ! 241: if (checkop('~')) ! 242: t = NMATCH_; ! 243: else if (checkop('=')) ! 244: t = NE_; ! 245: break; ! 246: ! 247: case '|': ! 248: if (checkop('|')) ! 249: t = OROR_; ! 250: break; ! 251: ! 252: case '&': ! 253: if (checkop('&')) ! 254: t = ANDAND_; ! 255: break; ! 256: ! 257: case '+': ! 258: if (checkop('=')) ! 259: t = ASADD_; ! 260: else if (checkop('+')) ! 261: t = INC_; ! 262: break; ! 263: ! 264: case '-': ! 265: if (checkop('=')) ! 266: t = ASSUB_; ! 267: else if (checkop('-')) ! 268: t = DEC_; ! 269: break; ! 270: ! 271: case '*': ! 272: if (checkop('=')) ! 273: t = ASMUL_; ! 274: break; ! 275: ! 276: case '/': ! 277: if (checkop('=')) ! 278: t = ASDIV_; ! 279: break; ! 280: ! 281: case '%': ! 282: if (checkop('=')) ! 283: t = ASDIV_; ! 284: break; ! 285: ! 286: case '>': ! 287: if (checkop('=')) ! 288: t = GE_; ! 289: else if (checkop('>')) ! 290: t = FAPPEND_; ! 291: else if (outflag) ! 292: t = FOUT_; ! 293: break; ! 294: ! 295: case '<': ! 296: if (checkop('=')) ! 297: t = LE_; ! 298: break; ! 299: ! 300: case '=': ! 301: if (checkop('=')) ! 302: t = EQ_; ! 303: break; ! 304: ! 305: case '\n': ! 306: if (nlf || nlskip) ! 307: goto again; ! 308: if (brlevel) ! 309: t = ';'; ! 310: break; ! 311: ! 312: case ' ': ! 313: case '\t': ! 314: goto again; ! 315: } ! 316: nlf = nlskip = 0; ! 317: if (t==ELSE_ && prev!=';' && prev!='\n' && prev!='}') { ! 318: next = t; ! 319: t = ';'; ! 320: } else if (t == '\n') ! 321: nlf++; ! 322: if (t==';') { ! 323: outflag = 0; ! 324: if (prev == ';') ! 325: goto again; ! 326: } ! 327: return (prev = t); ! 328: } ! 329: ! 330: /* ! 331: * Part of lexical analyser ! 332: * for reading regular expressions. ! 333: */ ! 334: relex() ! 335: { ! 336: register int c; ! 337: register int n, max; ! 338: ! 339: switch (c = pgetc()) { ! 340: case '?': ! 341: return (REZOCL_); ! 342: ! 343: case '*': ! 344: return (RECLOS_); ! 345: ! 346: case '+': ! 347: return (RENECL_); ! 348: ! 349: case '^': ! 350: return (REBOL_); ! 351: ! 352: case '$': ! 353: return (REEOL_); ! 354: ! 355: case '.': ! 356: return (REANY_); ! 357: ! 358: case '|': ! 359: return (REOR_); ! 360: ! 361: case '(': ! 362: case ')': ! 363: case '/': ! 364: return (c); ! 365: ! 366: case '[': ! 367: yylval.u_charp = readclass(); ! 368: return (RECLASS_); ! 369: ! 370: case EOF: ! 371: case '\n': ! 372: awkerr("Non-terminated regular expression"); ! 373: ! 374: case '\\': ! 375: c = pgetc(); ! 376: if (c>='0' && c<='7') { ! 377: n = 0; ! 378: max = 3; ! 379: do { ! 380: n = (n<<3) + c - '0'; ! 381: if ((c=pgetc())<'0' || c>'7') ! 382: break; ! 383: } while (--max); ! 384: pungetc(c); ! 385: c = n; ! 386: } ! 387: default: ! 388: yylval.u_char = c; ! 389: return (RECHAR_); ! 390: } ! 391: } ! 392: ! 393: /* ! 394: * Check for dual-character operators. ! 395: * such as `+=' and return 1 if so. ! 396: * This looks for a match on the next ! 397: * character `nc'. ! 398: */ ! 399: checkop(nc) ! 400: int nc; ! 401: { ! 402: register int c; ! 403: ! 404: if ((c = pgetc()) == nc) ! 405: return (1); ! 406: pungetc(c); ! 407: return (0); ! 408: } ! 409: ! 410: /* ! 411: * Read in a character class from ! 412: * a regular expression (called from relex). ! 413: */ ! 414: CHAR * ! 415: readclass() ! 416: { ! 417: register CHAR *cc; ! 418: register c, i, pc; ! 419: int comp; ! 420: ! 421: cc = xalloc(NCLASS); ! 422: for (i=0; i<NCLASS; i++) ! 423: cc[i] = 0; ! 424: if ((c = pgetc()) != '^') { ! 425: comp = 0; ! 426: pungetc(c); ! 427: } else ! 428: comp = 1; ! 429: pc = EOF; ! 430: while ((c = pgetc()) != ']') { ! 431: if (c==EOF || c=='\n') ! 432: awkerr("Non-terminated character class"); ! 433: if (c=='-' && pc!=EOF) { ! 434: if ((c = pgetc()) == ']') ! 435: break; ! 436: for (i=pc; i<=c; i++) ! 437: cc[i/NBPC] |= 1<<(i%NBPC); ! 438: pc = EOF; ! 439: } else { ! 440: cc[c/NBPC] |= 1<<(c%NBPC); ! 441: pc = c; ! 442: } ! 443: } ! 444: if (comp) { ! 445: cc[0] ^= 1; ! 446: for (i=0; i<NCLASS; i++) ! 447: cc[i] ^= -1; ! 448: } ! 449: return (cc); ! 450: } ! 451: ! 452: /* ! 453: * Return a string read from ! 454: * the program file. ! 455: * The string is to be terminated ! 456: * with `ec'. ! 457: */ ! 458: NODE * ! 459: instring(ec) ! 460: register int ec; ! 461: { ! 462: register CHAR *cp; ! 463: register int c; ! 464: register int octal, nc; ! 465: ! 466: cp = wordbuf; ! 467: while ((c = pgetc()) != ec) { ! 468: if (c=='\n' || c==EOF) ! 469: awkerr("%s in string", c==EOF ? "EOF" : "Newline"); ! 470: if (c == '\\') { ! 471: switch (c = pgetc()) { ! 472: case 'r': ! 473: c = '\r'; ! 474: break; ! 475: ! 476: case 'n': ! 477: c = '\n'; ! 478: break; ! 479: ! 480: case 'b': ! 481: c = '\b'; ! 482: break; ! 483: ! 484: case 't': ! 485: c = '\t'; ! 486: break; ! 487: ! 488: default: ! 489: if (c>='0' && c<='7') { ! 490: octal = 0; ! 491: nc = 3; ! 492: for (;;) { ! 493: octal = octal*8 + c - '0'; ! 494: if (--nc <= 0) ! 495: break; ! 496: c = pgetc(); ! 497: if (c==ec || c<'0' || c>'7') { ! 498: pungetc(c); ! 499: break; ! 500: } ! 501: } ! 502: c = octal; ! 503: } ! 504: } ! 505: } ! 506: if (cp < &wordbuf[NWORD-1]) ! 507: *cp++ = c; ! 508: else { ! 509: awkerr("Character string too long"); ! 510: break; ! 511: } ! 512: } ! 513: *cp = '\0'; ! 514: cp = xalloc(strlen(wordbuf)+sizeof(CHAR)); ! 515: strcpy(cp, wordbuf); ! 516: return (snode(cp, T_ALLOC)); ! 517: } ! 518: ! 519: /* ! 520: * Read a number from the ! 521: * program file. ! 522: */ ! 523: NODE * ! 524: innumber(c) ! 525: register int c; ! 526: { ! 527: register CHAR *np; ! 528: register int floatflag = 0; ! 529: ! 530: np = wordbuf; ! 531: for (;;) { ! 532: if (c == '.') ! 533: floatflag++; ! 534: *np++ = c; ! 535: c = pgetc(); ! 536: if (c=='e' || c=='E') { ! 537: floatflag++; ! 538: *np++ = c; ! 539: if ((c = pgetc())=='-' || c=='+') { ! 540: *np++ = c; ! 541: c = pgetc(); ! 542: } ! 543: do { ! 544: *np++ = c; ! 545: c = pgetc(); ! 546: } while (c>='0' && c<='9'); ! 547: break; ! 548: } ! 549: if (c!='.' && !(c>='0' && c<='9')) ! 550: break; ! 551: } ! 552: pungetc(c); ! 553: *np = '\0'; ! 554: return (floatflag ? fnode(stof(wordbuf)) : inode(stoi(wordbuf))); ! 555: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.