|
|
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.