|
|
1.1 root 1: /*
2: * sed/sed2.c
3: * A stream editor.
4: * Compiler.
5: */
6:
7: #include <stdio.h>
8: #include <ctype.h>
9: #include <string.h>
10: #include "sed.h"
11:
12: FIL *codefil();
13: char *codetrn();
14: LAB *codelab();
15: char *duplstr();
16: SUB *codesub();
17:
18: /*
19: * Compile a file of commands.
20: */
21: compfil(name)
22: char *name;
23: {
24: register FILE *fp;
25: register int c;
26: register char *cp;
27:
28: if ((fp=fopen(name, "r")) == NULL) {
29: fprintf(stderr, "Cannot open %s\n", name);
30: exit(1);
31: }
32: cp = linebuf;
33: while ((c=getc(fp)) != EOF) {
34: if (cp >= &linebuf[LHPSIZE-2]) {
35: printc("Line too long");
36: cp = linebuf;
37: while ((c=getc(fp))!='\n' && c!=EOF)
38: ;
39: if (c == EOF)
40: break;
41: }
42: if (c == '\n' || c == ';') {
43: *cp = '\0';
44: ncp = linebuf;
45: compcom();
46: cp = linebuf;
47: if (c == ';')
48: --lno;
49: continue;
50: }
51: if (c == '\\') {
52: if ((c=getc(fp))!='\n' && c!='\\' && c!=';') {
53: ungetc(c, fp);
54: c = '\\';
55: }
56: }
57: *cp++ = c;
58: }
59: if (cp != linebuf) {
60: *cp++ = '\0';
61: ncp = linebuf;
62: compcom();
63: }
64: }
65:
66: /*
67: * Compile a string.
68: */
69: compstr(cp) register char *cp;
70: {
71: register int c;
72: register char *lp;
73:
74: do {
75: lp = linebuf;
76: while ((c = *cp++) != '\0' && c != '\n' && c != ';') {
77: if (c == '\\' && (*cp == ';' || *cp == '\n'))
78: c = *cp++; /* "\;" means ';' */
79: *lp++ = c;
80: }
81: *lp = '\0';
82: ncp = linebuf;
83: compcom();
84: } while (c != '\0');
85: }
86:
87: /*
88: * Compile a command and return a pointer to the compiled
89: * structure.
90: */
91: compcom()
92: {
93: QCL *qp;
94: int nadd;
95: register COM *cp;
96: register LAB *lp;
97: register int c;
98:
99: lno++;
100: while (isascii(c=getn()) && isspace(c))
101: ;
102: if (c == '\0')
103: return;
104: ungetn(c);
105: cp = (COM *)salloc(sizeof (COM));
106: if (getaddr(&cp->c_a[0]) == 0)
107: goto err;
108: nadd = addnone ? 0 : 1;
109: if ((c=getn()) == ',') {
110: if (addnone!=0 || getaddr(&cp->c_a[1])==0 || addnone!=0)
111: goto err;
112: c = getn();
113: nadd++;
114: }
115: while (isascii(c) && isspace(c))
116: c = getn();
117: if (c == '!') {
118: cp->c_notf = 1;
119: c = getn();
120: } else
121: cp->c_notf = 0;
122: cp->c_name = c;
123: cp->c_nadd = nadd;
124: switch (c) {
125: case '{':
126: qp = (QCL *)salloc(sizeof (QCL));
127: qp->q_next = qcbp;
128: qcbp = qp;
129: qp->q_comp = cp;
130: if ((c=getn()) != '\0') {
131: *compp = cp;
132: compp = &cp->c_next;
133: ungetn(c);
134: compcom();
135: return;
136: }
137: break;
138: case '}':
139: if ((qp=qcbp) == NULL) {
140: printc("Too many `}'");
141: goto err;
142: }
143: qcbp = qcbp->q_next;
144: if (codenwl() == 0)
145: goto err;
146: qp->q_comp->c_p.p_com = qp->q_comp->c_next;
147: qp->q_comp->c_next = cp;
148: free(qp);
149: break;
150: case '=':
151: if (codenwl() == 0)
152: goto err;
153: break;
154: case ':':
155: if ((lp=codelab()) == NULL)
156: goto err;
157: if (lp->l_comp != NULL) {
158: printc("Label %s multiply defined", pattbuf);
159: goto err;
160: }
161: lp->l_comp = cp;
162: break;
163: case 'a':
164: if (nadd > 1)
165: goto adr;
166: if (getn() != '\n')
167: goto syn;
168: if (codelin() == 0)
169: goto err;
170: cp->c_p.p_buf = duplstr(pattbuf);
171: if (cp->c_a[0].a_lno == 0+1) {
172: cp->c_name = 'i';
173: cp->c_a[0].a_lno = 1+1;
174: }
175: break;
176: case 'b':
177: if ((lp=codelab()) == NULL)
178: goto err;
179: cp->c_p.p_lab = lp;
180: lp->l_refc++;
181: break;
182: case 'c':
183: if (getn() != '\n')
184: goto syn;
185: if (codelin() == 0)
186: goto err;
187: cp->c_p.p_buf = duplstr(pattbuf);
188: break;
189: case 'd':
190: case 'D':
191: case 'g':
192: case 'G':
193: case 'h':
194: case 'H':
195: if (codenwl() == 0)
196: goto err;
197: break;
198: case 'i':
199: if (nadd > 1)
200: goto adr;
201: if (getn() != '\n')
202: goto syn;
203: if (codelin() == 0)
204: goto err;
205: cp->c_p.p_buf = duplstr(pattbuf);
206: break;
207: case 'l':
208: case 'n':
209: case 'N':
210: case 'p':
211: case 'P':
212: if (codenwl() == 0)
213: goto err;
214: break;
215: case 'q':
216: if (nadd > 1)
217: goto adr;
218: if (codenwl() == 0)
219: goto err;
220: break;
221: case 'r':
222: if (nadd > 1)
223: goto adr;
224: if (codelin() == 0)
225: goto err;
226: if (pattbuf[0] != ' ')
227: goto err;
228: cp->c_p.p_buf = duplstr(&pattbuf[1]);
229: break;
230: case 's':
231: if ((cp->c_p.p_sub=codesub()) == NULL)
232: goto err;
233: break;
234: case 't':
235: if ((lp=codelab()) == NULL)
236: goto err;
237: cp->c_p.p_lab = lp;
238: lp->l_refc++;
239: break;
240: case 'w':
241: if ((cp->c_p.p_fil=codefil()) == NULL)
242: goto err;
243: break;
244: case 'x':
245: if (codenwl() == 0)
246: goto err;
247: break;
248: case 'y':
249: if ((cp->c_p.p_buf=codetrn()) == NULL)
250: goto err;
251: break;
252: default:
253: printc("Bad command");
254: goto err;
255: }
256: *compp = cp;
257: compp = &cp->c_next;
258: return;
259:
260: syn:
261: printc("Syntax error");
262: free(cp);
263: return;
264:
265: adr:
266: printc("Bad address");
267: err:
268: free(cp);
269: }
270:
271: /*
272: * Read a line address and compile it into the given address
273: * pointer.
274: */
275: getaddr(ap)
276: register ADD *ap;
277: {
278: register int c, n;
279:
280: addnone = 0;
281: if ((c=getn()) == '/') {
282: if (compile('/') == 0)
283: return 0;
284: ap->a_lno = 0;
285: ap->a_pat = duplstr(pattbuf);
286: return 1;
287: }
288: if (c == '$') {
289: ap->a_lno = HUGE;
290: return 1;
291: }
292: if (isascii(c) && isdigit(c)) {
293: n = 0;
294: do {
295: n = n*10 + c-'0';
296: } while (isascii(c=getn()) && isdigit(c));
297: ungetn(c);
298: ap->a_lno = n+1;
299: return 1;
300: }
301: ungetn(c);
302: addnone = 1;
303: return 1;
304: }
305:
306: /*
307: * There shouldn't be any more input left.
308: */
309: codenwl()
310: {
311: if (getn() != '\0') {
312: printc("Syntax error");
313: return 0;
314: }
315: return 1;
316: }
317:
318: /*
319: * Parse a label, put it into the label table and return
320: * a pointer to the entry.
321: */
322: LAB *
323: codelab()
324: {
325: char name[LNMSIZE];
326: register LAB *lp;
327: register int c;
328: register char *np;
329:
330: while (isascii(c=getn()) && isspace(c))
331: ;
332: np = name;
333: while (c != '\0') {
334: if (np < &name[LNMSIZE-1])
335: *np++ = c;
336: c = getn();
337: }
338: *np = '\0';
339: for (lp=labp; lp; lp=lp->l_next) {
340: if (strcmp(lp->l_name, name) == 0)
341: return lp;
342: }
343: lp = (LAB *)salloc(sizeof (LAB));
344: lp->l_next = labp;
345: labp = lp;
346: strcpy(lp->l_name, name);
347: lp->l_comp = NULL;
348: lp->l_refc = 0;
349: return lp;
350: }
351:
352: /*
353: * Parse a file name that will be used to write on and set it
354: * up in our write table.
355: */
356: FIL *
357: codefil()
358: {
359: char name[FNMSIZE];
360: register FIL *fp;
361: register int c;
362: register char *np;
363:
364: while (isascii(c=getn()) && isspace(c))
365: ;
366: np = name;
367: while (c != '\0') {
368: if (np >= &name[FNMSIZE-1]) {
369: printc("Line buffer overflow");
370: return NULL;
371: }
372: *np++ = c;
373: c = getn();
374: }
375: *np = '\0';
376: for (fp=filp; fp; fp=fp->f_next) {
377: if (strcmp(fp->f_name, name) == 0)
378: return fp;
379: }
380: fp = (FIL *)salloc(sizeof (FIL));
381: fp->f_next = filp;
382: filp = fp;
383: strcpy(fp->f_name, name);
384: fp->f_filp = NULL;
385: return fp;
386: }
387:
388: /*
389: * Get a line of text for commands such as the append.
390: */
391: codelin()
392: {
393: register int c;
394: register char *pp;
395:
396: pp = pattbuf;
397: while ((c=getn()) != '\0') {
398: if (pp >= &pattbuf[LHPSIZE-1]) {
399: printc("Line buffer overflow");
400: return 0;
401: }
402: *pp++ = c;
403: }
404: *pp = '\0';
405: return 1;
406: }
407:
408: /*
409: * Compile the substitute command.
410: */
411: SUB *
412: codesub()
413: {
414: int nth, ec;
415: register SUB *sp;
416: register int c;
417: register char *pp;
418:
419: nth = 1;
420: if (isascii(c=getn()) && isdigit(c)) {
421: nth = 0;
422: while (isascii(c) && isdigit(c)) {
423: nth = nth*10 + c-'0';
424: c = getn();
425: }
426: }
427: if ((ec=c) == '\n') {
428: ungetn(c);
429: printc("Syntax error");
430: return NULL;
431: }
432: if (compile(ec) == 0)
433: return NULL;
434: pp = holdbuf;
435: while ((c=getn()) != ec) {
436: if (pp >= &holdbuf[LHPSIZE-4]) {
437: printc("Pattern buffer overflow");
438: return NULL;
439: }
440: switch (c) {
441: case '\0':
442: ungetn(c);
443: printc("Syntax error");
444: return NULL;
445: case '&':
446: *pp++ = '\\';
447: *pp++ = '0';
448: continue;
449: case '\\':
450: if ((c=getn()) == '\\') {
451: *pp++ = '\\';
452: *pp++ = '\\';
453: continue;
454: }
455: if (c >= '1' && c <= '9') {
456: *pp++ = '\\';
457: *pp++ = c;
458: continue;
459: }
460: default:
461: *pp++ = c;
462: continue;
463: }
464: }
465: *pp++ = '\0';
466: sp = (SUB *)salloc(sizeof (SUB));
467: sp->s_pat = duplstr(pattbuf);
468: sp->s_rep = duplstr(holdbuf);
469: sp->s_nth = nth;
470: sp->s_cop = 0;
471: sp->s_fil = NULL;
472: while ((c=getn()) != '\0') {
473: switch (c) {
474: case 'g':
475: sp->s_nth = 0;
476: continue;
477: case 'p':
478: sp->s_cop = 1;
479: continue;
480: case 'w':
481: sp->s_fil = codefil();
482: continue;
483: default:
484: printc("Bad flag in substitute");
485: free(sp->s_pat);
486: free(sp->s_rep);
487: free(sp);
488: return NULL;
489: }
490: }
491: return sp;
492: }
493:
494: /*
495: * Compile a regular expression. `ec' is the character upon which
496: * the regular expression ends. If an error is encountered, the
497: * pattern is cleared and input characters are thrown away until
498: * a new line is found.
499: */
500: compile(ec)
501: {
502: int bstack[NBRC], bcount, blevel, n;
503: register int c;
504: register char *pp, *lpp;
505:
506: bcount = 1;
507: blevel = 0;
508: pp = &pattbuf[0];
509: if ((c=getn()) == ec) {
510: if (*pp == CSNUL) {
511: printc("No saved pattern");
512: goto err;
513: }
514: return 1;
515: }
516: if (c == '^') {
517: *pp++ = CSSOL;
518: c = getn();
519: }
520: while (c != ec) {
521: if (pp > &pattbuf[LHPSIZE-4])
522: goto ovf;
523: switch (c) {
524: case '\0':
525: case '.':
526: if ((c=getn()) != '*') {
527: *pp++ = CSDOT;
528: continue;
529: }
530: *pp++ = CMDOT;
531: c = getn();
532: continue;
533: case '$':
534: if ((c=getn()) != ec) {
535: ungetn(c);
536: c = '$';
537: goto character;
538: }
539: *pp++ = CSEOL;
540: continue;
541: case '[':
542: lpp = pp;
543: if ((c=getn()) == '^')
544: *pp++ = CSNCL;
545: else {
546: ungetn(c);
547: *pp++ = CSCCL;
548: }
549: *pp++ = 0;
550: if ((c=getn()) == ']')
551: *pp++ = c;
552: else
553: ungetn(c);
554: while ((c=getn()) != ']') {
555: if (c == '\n')
556: goto nwl;
557: if (c!='-' || pp==lpp+2) {
558: if (pp >= &pattbuf[LHPSIZE-4])
559: goto ovf;
560: *pp++ = c;
561: if (sflag && isascii(c) && isallet(c))
562: *pp++ = toother(c);
563: continue;
564: }
565: if ((c=getn()) == '\n')
566: goto nwl;
567: if (c == ']') {
568: *pp++ = '-';
569: ungetn(c);
570: continue;
571: }
572: if ((n=pp[-1]) > c)
573: goto syn;
574: while (++n <= c) {
575: if (pp >= &pattbuf[LHPSIZE-4])
576: goto ovf;
577: *pp++ = n;
578: if (sflag && isascii(c) && isallet(c))
579: *pp++ = toother(c);
580: }
581: }
582: if ((c=getn()) == '*') {
583: (*lpp)++;
584: c = getn();
585: }
586: if ((n=pp-(lpp+2)) > 255) {
587: printc("Character class too large");
588: goto err;
589: }
590: *++lpp = n;
591: continue;
592: case '\\':
593: switch (c=getn()) {
594: case '\n':
595: goto nwl;
596: case '(':
597: if (bcount > NBRC) {
598: printc("Too many \\(");
599: goto err;
600: }
601: *pp++ = CSOPR;
602: *pp++ = bstack[blevel++] = bcount++;
603: c = getn();
604: continue;
605: case ')':
606: if (blevel == 0)
607: goto syn;
608: *pp++ = CSCPR;
609: *pp++ = bstack[--blevel];
610: c = getn();
611: continue;
612: case 'n':
613: c = '\n';
614: goto character;
615: default:
616: if (isascii(c) && isdigit(c)) {
617: *pp++ = CSBRN;
618: *pp++ = c-'0';
619: c = getn();
620: continue;
621: }
622: }
623: case '*':
624: default:
625: character:
626: if (sflag && isascii(c) && isallet(c)) {
627: *pp++ = CSSCC;
628: if (isupper(c))
629: c = tolower(c);
630: } else
631: *pp++ = CSCHR;
632: *pp++ = c;
633: if ((c=getn()) == '*') {
634: pp[-2]++;
635: c = getn();
636: }
637: }
638: }
639: *pp++ = CSNUL;
640: return 1;
641: ovf:
642: printc("Pattern buffer overflow");
643: pattbuf[0] = CSNUL;
644: return 0;
645: nwl:
646: ungetn(c);
647: syn:
648: printc("Syntax error");
649: err:
650: pattbuf[0] = CSNUL;
651: return 0;
652: }
653:
654: /*
655: * Compile the translate command.
656: */
657: char *
658: codetrn()
659: {
660: int ec;
661: char *trnp;
662: register int c, n;
663: register char *bp;
664:
665: trnp = salloc(256);
666: bp = trnp;
667: for (n=0; n<256; n++)
668: *bp++ = n;
669: if ((ec=getn()) == '\0') {
670: printc("Syntax error");
671: return NULL;
672: }
673: bp = pattbuf;
674: while ((c=getn()) != ec) {
675: if (c == '\0') {
676: printc("Syntax error");
677: return NULL;
678: }
679: if (bp >= &pattbuf[LHPSIZE-1]) {
680: printc("Code buffer overflow");
681: return NULL;
682: }
683: *bp++ = c&0377;
684: }
685: bp = pattbuf;
686: while ((c=getn()) != ec) {
687: if (c == '\0') {
688: printc("Syntax error");
689: return NULL;
690: }
691: if (*bp == '\0') {
692: printc("Right part of translate too long");
693: return NULL;
694: }
695: trnp[*bp++] = c;
696: }
697: return trnp;
698: }
699:
700: /*
701: * Given a string, return a pointer to a copy of it.
702: */
703: char *
704: duplstr(s) register char *s;
705: {
706: return strcpy(salloc(strlen(s)+1), s);
707: }
708:
709: /*
710: * Get a character.
711: */
712: getn()
713: {
714: register int c;
715:
716: if ((c = *ncp++) == '\0')
717: --ncp;
718: return c;
719: }
720:
721: /*
722: * Unget a character.
723: */
724: ungetn(c)
725: {
726: if (*ncp!='\0' || c!='\0')
727: *--ncp = c;
728: }
729:
730: /*
731: * Go through the command list fixing up labels and files.
732: */
733: load()
734: {
735: register LAB *lp;
736: register FIL *fp;
737:
738: *compp = NULL;
739: if (qcbp != NULL)
740: printc("Missing `}'");
741: for (lp=labp; lp; lp=lp->l_next) {
742: if (lp->l_comp == NULL)
743: printc("Undefined label %s", lp->l_name);
744: }
745: for (fp=filp; fp; fp=fp->f_next) {
746: if (fp->f_filp == NULL)
747: if ((fp->f_filp=fopen(fp->f_name, "w")) == NULL)
748: printc("Cannot open %s", fp->f_name);
749: }
750: }
751:
752: /*
753: * Print out a compile error message.
754: */
755: printc(s)
756: {
757: nerr++;
758: fprintf(stderr, "%d: %r", lno, &s);
759: putc('\n', stderr);
760: }
761:
762: /* end of sed/sed2.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.