|
|
1.1 root 1: /*
2: * sh/lex.c
3: * Bourne shell.
4: * Lexical analysis.
5: */
6:
7: #include "sh.h"
8: #include <y.tab.h>
9:
10: /*
11: * Local externals.
12: */
13: int lastget = '\0'; /* Pushed back character */
14: int eolflag = 0; /* End of line */
15:
16: /*
17: * For processing here documents.
18: */
19: char *hereeof = NULL; /* Here document EOF mark */
20: int herefd; /* Here document fd */
21: char *heretmp; /* Here document tempfile name */
22: int hereqflag; /* Here document quoted */
23:
24: /*
25: * Keyword table.
26: */
27: typedef struct key {
28: int k_hash; /* Hash */
29: int k_lexv; /* Lexical value */
30: char *k_name; /* Keyword name */
31: } KEY;
32:
33: /*
34: * Keyword table.
35: */
36: KEY keytab[] ={
37: 0, _CASE, "case",
38: 0, _DO, "do",
39: 0, _DONE, "done",
40: 0, _ELIF, "elif",
41: 0, _ELSE, "else",
42: 0, _ESAC, "esac",
43: 0, _FI, "fi",
44: 0, _FOR, "for",
45: 0, _IF, "if",
46: 0, _IN, "in",
47: 0, _THEN, "then",
48: 0, _UNTIL, "until",
49: 0, _WHILE, "while",
50: 0, _OBRAC, "{",
51: 0, _CBRAC, "}"
52: };
53: #define NKEYS (sizeof(keytab) / sizeof(keytab[0]))
54:
55: /*
56: * Get the next lexical token.
57: */
58: yylex()
59: {
60: register int c;
61: register KEY *kp;
62: int hash;
63:
64: /* Initialize hash values in key table. */
65: if (keytab[0].k_hash == 0)
66: for (kp = &keytab[0]; kp < &keytab[NKEYS]; kp++)
67: kp->k_hash = ihash(kp->k_name);
68: again:
69: while ((c=getn())==' ' || c=='\t') ;
70: strp = strt;
71: if (c == '#' && readflag == 0) {
72: /*
73: * Ignore a '#'-delimited comment line.
74: * Lines which begin with a ':' token are lexed as usual;
75: * the built-in function s_colon() executes (i.e. ignores)
76: * lines starting with ':', while other ':' tokens get passed.
77: * The built-in "read" does not ignore comment lines.
78: */
79: do
80: c = getn();
81: while (c > 0 && c != '\n');
82: return c;
83: } else if (class(c, MDIGI)) {
84: *strp++ = c;
85: c = getn();
86: if (c=='>' || c=='<') {
87: *strp++ = c;
88: return lexiors(c);
89: }
90: ungetn(c);
91: return lexname();
92: }
93: if (!class(c, MNAME)) {
94: ungetn(c);
95: if ((c = lexname()) == 0)
96: goto again;
97: else if (c < 0)
98: return c;
99: hash = ihash(strt);
100: if (keyflag) {
101: for (kp = keytab; kp < &keytab[NKEYS]; kp++)
102: if (hash == kp->k_hash && strcmp(strt, kp->k_name) == 0)
103: return kp->k_lexv;
104: }
105: return c;
106: }
107: *strp++ = c;
108: *strp = '\0';
109: switch (c) {
110: case ';':
111: return isnext(c, _DSEMI);
112: case '>':
113: return lexiors(c);
114: case '<':
115: return lexiors(c);
116: case '&':
117: return isnext(c, _ANDF);
118: case '|':
119: #ifdef NAMEPIPE
120: if ( ! isnext(')', 0))
121: return _NCLOSE;
122: #endif
123: return isnext(c, _ORF);
124: #ifdef NAMEPIPE
125: case '(':
126: return isnext('|', _NOPEN);
127: #endif
128: default:
129: if (hereeof != NULL) {
130: /* Read here document. */
131: for (;;) {
132: strp = strt;
133: if ((c = collect('\n', 2)) < 0)
134: break;
135: *strp = '\0';
136: if (strcmp(strt, hereeof)==0)
137: break;
138: if (herefd < 0)
139: continue;
140: if (!hereqflag && strp > strt + 1 && strp[-2]=='\\')
141: *(strp-=2) = '\0';
142: if (!hereqflag && *strt=='\\' && strcmp(hereeof, strt+1)==0)
143: write(herefd, strt+1, strp-strt-1);
144: else
145: write(herefd, strt, strp-strt);
146: }
147: close(herefd);
148: cleanup(0, heretmp);
149: hereeof = NULL;
150: return '\n';
151: }
152: return c;
153: }
154: }
155:
156: isnext(c, t1)
157: register int c;
158: {
159: register int c2;
160:
161: if ((c2=getn()) == c) {
162: *strp++ = c2;
163: *strp = '\0';
164: return t1;
165: }
166: ungetn(c2);
167: return strp[-1];
168: }
169:
170: /*
171: * Scan a single argument.
172: * Return 0 if it's an escaped newline, EOF if EOF is found,
173: * or _NAME or _ASGN if any part of an argument is found.
174: */
175: lexname()
176: {
177: int q, asgn;
178: register int c, m;
179: register char *cp;
180:
181: q = 0;
182: asgn = 0;
183: m = MNQUO;
184: cp = strp;
185: for (;;) {
186: c = getn();
187: if (asgn==0)
188: asgn = class(c, MBVAR) ? 1 : -1;
189: else if (asgn==1)
190: asgn = class(c, MRVAR) ? 1 : (c=='=' ? 2 : -1);
191: if (cp >= strt + STRSIZE)
192: etoolong();
193: else
194: *cp++ = c;
195: if (!class(c, m))
196: continue;
197: switch (c) {
198: case '"':
199: m = (q^=1) ? MDQUO : MNQUO;
200: continue;
201: case '\'':
202: strp = cp;
203: if ((c = collect('\'', 1)) != '\'')
204: break;
205: cp = strp;
206: continue;
207: case '\\':
208: if ((c=getn()) < 0) {
209: syntax();
210: break;
211: }
212: if (c == '\n') {
213: ungetn((c=getn())<0 ? '\n' : c);
214: if (--cp == strp)
215: return 0;
216: continue;
217: }
218: *cp++ = c;
219: continue;
220: case '$':
221: if ((c=getn()) == '{') {
222: *cp++ = c;
223: strp = cp;
224: if ((c = collect('}', 0)) != '}')
225: break;
226: cp = strp;
227: continue;
228: }
229: ungetn(c);
230: continue;
231: case '`':
232: strp = cp;
233: if ((c = collect('`', 1)) != '`')
234: break;
235: cp = strp;
236: continue;
237: case '\n':
238: if (q)
239: continue;
240: break;
241: }
242: break;
243: }
244: if (c < 0)
245: return c;
246: if (q) {
247: emisschar('"');
248: *cp = '\0';
249: } else {
250: *--cp = '\0';
251: }
252: ungetn(c);
253: strp = cp;
254: #ifdef VERBOSE
255: if (vflag)
256: prints("\t<%d> <%s> %s\n", getpid(), (asgn==2 ? "ASGN" : "NAME"), strt);
257: #endif
258: if (errflag)
259: return _NULL;
260: else if (asgn==2)
261: return _ASGN;
262: else
263: return _NAME;
264: return (asgn==2 ? _ASGN : _NAME);
265: }
266:
267: /*
268: * Lex an io redirection string, including the file name if any.
269: * Called with one '>' or '<' in buffer, optionally preceded by
270: * a digit.
271: */
272: lexiors(c1)
273: {
274: register int c;
275: register char *name;
276: char *iors;
277:
278: *strp++ = c = getn();
279: if (c=='&') {
280: *strp++ = c = getn();
281: *strp = '\0';
282: if (c < 0) return c;
283: if (c!='-' && !class(c, MDIGI))
284: eredir();
285: return _IORS;
286: }
287: if (c==c1)
288: c1 += 0200;
289: else {
290: *--strp = '\0';
291: ungetn(c);
292: }
293: /* Collect file name */
294: while ((c=getn())==' '||c=='\t')
295: *strp++ = c;
296: ungetn(c);
297: name = strp;
298: if (c=='\n') {
299: eredir();
300: return _IORS;
301: }
302: while ((c = lexname())==0);
303: if (c < 0) return c;
304: if (c1!='<'+0200)
305: return _IORS;
306: #if 1
307: /*
308: * Set up here document processing.
309: * Modified by steve 1/25/91 so that
310: * the actual processing happens at the '\n' ending the line,
311: * otherwise the common "foo <<SHAR_EOF >baz\n" does not work.
312: * This code is anything but obvious, it could doubtless be simpler.
313: */
314: strp = strt;
315: /* Simplify quoted here document iors from ?<<file to ?<file. */
316: if (hereqflag = (strpbrk(name, "\"\\'") != NULL))
317: *++strp = *strt;
318: heretmp = name;
319: name = duplstr(name, 0);
320: strcpy(heretmp, shtmp());
321: iors = duplstr(strp, 0);
322: heretmp += iors - strp;
323: eval(name, EWORD);
324: hereeof = duplstr(strcat(strt, "\n"), 0);
325: if ((herefd = creat(heretmp, 0666)) < 0)
326: ecantmake(heretmp);
327: strcpy(strt, iors);
328: #else
329: /* Collect here document */
330: if ((c=getn())!='\n') {
331: eredir();
332: ++strp;
333: c = collect('\n', 1);
334: }
335: if (c < 0) return c;
336: bpp = savebuf();
337: strp = strt;
338: /* Simplify quoted to ?<file from ?<<file */
339: if (quote = (strpbrk(name, "\"\\'") != NULL))
340: *++strp = *strt;
341: tmp = name;
342: name = duplstr(name, 0);
343: strcpy(tmp, shtmp());
344: iors = duplstr(strp, 0);
345: tmp += iors - strp;
346: eval(name, EWORD);
347: name = duplstr(strcat(strt, "\n"), 0);
348: if ((hfd = creat(tmp, 0666)) < 0)
349: ecantmake(tmp);
350: for (;;) {
351: strp = strt;
352: if ((c = collect('\n', 2)) < 0)
353: break;
354: *strp = '\0';
355: if (strcmp(strt, name)==0)
356: break;
357: if (hfd < 0)
358: continue;
359: if (! quote && strp > strt + 1 && strp[-2]=='\\')
360: *(strp-=2) = '\0';
361: if (! quote && *strt=='\\' && strcmp(name, strt+1)==0)
362: write(hfd, strt+1, strp-strt-1);
363: else
364: write(hfd, strt, strp-strt);
365: }
366: close(hfd);
367: cleanup(0, tmp);
368: ungetn('\n');
369: strcpy(strt, iors);
370: freebuf(bpp);
371: /* Check for interrupt, since EOF is legal for once */
372: if (c < 0 && ! recover(ILEX)) return c;
373: #endif
374: return _IORS;
375: }
376:
377: /*
378: * Collect characters until the end character is found. If `f' is
379: * set, all characters are passed through otherwise '\' escapes the
380: * next character and newline is not allowed.
381: * If `f' is set to 2, then no error is desired.
382: */
383: collect(ec, f)
384: register int ec;
385: {
386: register int c;
387: register char *cp;
388:
389: cp = strp;
390: while ((c=getn()) != ec) {
391: if (c<0 || (c=='\n' && f==0)) {
392: if (--f <= 0)
393: emisschar(ec);
394: return c;
395: }
396: if (c=='\\' && f==0) {
397: if ((c=getn()) < 0) {
398: syntax();
399: return c;
400: }
401: if (c == '\n')
402: continue;
403: }
404: if (cp >= strt + STRSIZE)
405: etoolong();
406: else
407: *cp++ = c;
408: }
409: *cp++ = ec;
410: strp = cp;
411: return ec;
412: }
413:
414: /*
415: * Get a character.
416: */
417: getn()
418: {
419: register int c;
420: register int t;
421:
422: if (lastget != '\0') {
423: c = lastget;
424: lastget = '\0';
425: return c;
426: }
427: switch (t = sesp->s_type) {
428: case SSTR:
429: case SFILE:
430: yyline += eolflag;
431: eolflag = 0;
432: if (prpflag && sesp->s_flag) {
433: if (prpflag -= 1) {
434: prompt("\n");
435: prpflag -= 1;
436: }
437: prompt(comflag ? vps1 : vps2);
438: comflag = 0;
439: }
440: if ((c=getc(sesp->s_ifp))=='\n') {
441: if (sesp->s_flag) {
442: prpflag = 1;
443: yyline = 1;
444: } else
445: eolflag = 1;
446: }
447: if (vflag)
448: putc(c, stderr);
449: return c;
450: case SARGS:
451: case SARGV:
452: if (sesp->s_flag)
453: return EOF;
454: if ((c=*sesp->s_strp++) == '\0') {
455: if (t == SARGV
456: && (sesp->s_strp=*++sesp->s_argv) != NULL)
457: c = ' ';
458: else {
459: sesp->s_flag = 1;
460: c = '\n';
461: }
462: }
463: if (vflag)
464: putc(c, stderr);
465: return c;
466: }
467: }
468:
469: /*
470: * Unget a character.
471: */
472: ungetn(c)
473: {
474: lastget = c;
475: }
476:
477: /* end of sh/lex.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.