lex.c revision 1.3 1 1.1 christos /****************************************************************
2 1.1 christos Copyright (C) Lucent Technologies 1997
3 1.1 christos All Rights Reserved
4 1.1 christos
5 1.1 christos Permission to use, copy, modify, and distribute this software and
6 1.1 christos its documentation for any purpose and without fee is hereby
7 1.1 christos granted, provided that the above copyright notice appear in all
8 1.1 christos copies and that both that the copyright notice and this
9 1.1 christos permission notice and warranty disclaimer appear in supporting
10 1.1 christos documentation, and that the name Lucent Technologies or any of
11 1.1 christos its entities not be used in advertising or publicity pertaining
12 1.1 christos to distribution of the software without specific, written prior
13 1.1 christos permission.
14 1.1 christos
15 1.1 christos LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 1.1 christos INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17 1.1 christos IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18 1.1 christos SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 1.1 christos WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20 1.1 christos IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21 1.1 christos ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22 1.1 christos THIS SOFTWARE.
23 1.1 christos ****************************************************************/
24 1.1 christos
25 1.2 christos #if HAVE_NBTOOL_CONFIG_H
26 1.2 christos #include "nbtool_config.h"
27 1.2 christos #endif
28 1.2 christos
29 1.1 christos #include <stdio.h>
30 1.1 christos #include <stdlib.h>
31 1.1 christos #include <string.h>
32 1.1 christos #include <ctype.h>
33 1.1 christos #include "awk.h"
34 1.2 christos #include "awkgram.h"
35 1.1 christos
36 1.1 christos extern YYSTYPE yylval;
37 1.1 christos extern int infunc;
38 1.1 christos
39 1.1 christos int lineno = 1;
40 1.1 christos int bracecnt = 0;
41 1.1 christos int brackcnt = 0;
42 1.1 christos int parencnt = 0;
43 1.1 christos
44 1.1 christos typedef struct Keyword {
45 1.1 christos const char *word;
46 1.1 christos int sub;
47 1.1 christos int type;
48 1.1 christos } Keyword;
49 1.1 christos
50 1.2 christos int peek(void);
51 1.2 christos int gettok(char **, int *);
52 1.2 christos int binsearch(const char *, const Keyword *, int);
53 1.2 christos
54 1.2 christos const Keyword keywords[] ={ /* keep sorted: binary searched */
55 1.1 christos { "BEGIN", XBEGIN, XBEGIN },
56 1.1 christos { "END", XEND, XEND },
57 1.1 christos { "NF", VARNF, VARNF },
58 1.1 christos { "atan2", FATAN, BLTIN },
59 1.1 christos { "break", BREAK, BREAK },
60 1.1 christos { "close", CLOSE, CLOSE },
61 1.1 christos { "continue", CONTINUE, CONTINUE },
62 1.1 christos { "cos", FCOS, BLTIN },
63 1.1 christos { "delete", DELETE, DELETE },
64 1.1 christos { "do", DO, DO },
65 1.1 christos { "else", ELSE, ELSE },
66 1.1 christos { "exit", EXIT, EXIT },
67 1.1 christos { "exp", FEXP, BLTIN },
68 1.1 christos { "fflush", FFLUSH, BLTIN },
69 1.1 christos { "for", FOR, FOR },
70 1.1 christos { "func", FUNC, FUNC },
71 1.1 christos { "function", FUNC, FUNC },
72 1.2 christos { "gensub", GENSUB, GENSUB },
73 1.1 christos { "getline", GETLINE, GETLINE },
74 1.1 christos { "gsub", GSUB, GSUB },
75 1.1 christos { "if", IF, IF },
76 1.1 christos { "in", IN, IN },
77 1.1 christos { "index", INDEX, INDEX },
78 1.1 christos { "int", FINT, BLTIN },
79 1.1 christos { "length", FLENGTH, BLTIN },
80 1.1 christos { "log", FLOG, BLTIN },
81 1.1 christos { "match", MATCHFCN, MATCHFCN },
82 1.1 christos { "next", NEXT, NEXT },
83 1.1 christos { "nextfile", NEXTFILE, NEXTFILE },
84 1.1 christos { "print", PRINT, PRINT },
85 1.1 christos { "printf", PRINTF, PRINTF },
86 1.1 christos { "rand", FRAND, BLTIN },
87 1.1 christos { "return", RETURN, RETURN },
88 1.1 christos { "sin", FSIN, BLTIN },
89 1.1 christos { "split", SPLIT, SPLIT },
90 1.1 christos { "sprintf", SPRINTF, SPRINTF },
91 1.1 christos { "sqrt", FSQRT, BLTIN },
92 1.1 christos { "srand", FSRAND, BLTIN },
93 1.2 christos { "strftime", FSTRFTIME, BLTIN },
94 1.1 christos { "sub", SUB, SUB },
95 1.1 christos { "substr", SUBSTR, SUBSTR },
96 1.1 christos { "system", FSYSTEM, BLTIN },
97 1.2 christos { "systime", FSYSTIME, BLTIN },
98 1.1 christos { "tolower", FTOLOWER, BLTIN },
99 1.1 christos { "toupper", FTOUPPER, BLTIN },
100 1.1 christos { "while", WHILE, WHILE },
101 1.1 christos };
102 1.1 christos
103 1.1 christos #define RET(x) { if(dbg)printf("lex %s\n", tokname(x)); return(x); }
104 1.1 christos
105 1.1 christos int peek(void)
106 1.1 christos {
107 1.1 christos int c = input();
108 1.1 christos unput(c);
109 1.1 christos return c;
110 1.1 christos }
111 1.1 christos
112 1.1 christos int gettok(char **pbuf, int *psz) /* get next input token */
113 1.1 christos {
114 1.1 christos int c, retc;
115 1.2 christos uschar *buf = (uschar *) *pbuf;
116 1.1 christos int sz = *psz;
117 1.2 christos uschar *bp = buf;
118 1.1 christos
119 1.1 christos c = input();
120 1.1 christos if (c == 0)
121 1.1 christos return 0;
122 1.1 christos buf[0] = c;
123 1.1 christos buf[1] = 0;
124 1.1 christos if (!isalnum(c) && c != '.' && c != '_')
125 1.1 christos return c;
126 1.1 christos
127 1.1 christos *bp++ = c;
128 1.1 christos if (isalpha(c) || c == '_') { /* it's a varname */
129 1.1 christos for ( ; (c = input()) != 0; ) {
130 1.1 christos if (bp-buf >= sz)
131 1.1 christos if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, "gettok"))
132 1.1 christos FATAL( "out of space for name %.10s...", buf );
133 1.1 christos if (isalnum(c) || c == '_')
134 1.1 christos *bp++ = c;
135 1.1 christos else {
136 1.1 christos *bp = 0;
137 1.1 christos unput(c);
138 1.1 christos break;
139 1.1 christos }
140 1.1 christos }
141 1.1 christos *bp = 0;
142 1.1 christos retc = 'a'; /* alphanumeric */
143 1.1 christos } else { /* maybe it's a number, but could be . */
144 1.1 christos char *rem;
145 1.1 christos /* read input until can't be a number */
146 1.1 christos for ( ; (c = input()) != 0; ) {
147 1.1 christos if (bp-buf >= sz)
148 1.1 christos if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, "gettok"))
149 1.1 christos FATAL( "out of space for number %.10s...", buf );
150 1.1 christos if (isdigit(c) || c == 'e' || c == 'E'
151 1.1 christos || c == '.' || c == '+' || c == '-')
152 1.1 christos *bp++ = c;
153 1.1 christos else {
154 1.1 christos unput(c);
155 1.1 christos break;
156 1.1 christos }
157 1.1 christos }
158 1.1 christos *bp = 0;
159 1.1 christos strtod(buf, &rem); /* parse the number */
160 1.2 christos if (rem == (char *)buf) { /* it wasn't a valid number at all */
161 1.1 christos buf[1] = 0; /* return one character as token */
162 1.1 christos retc = buf[0]; /* character is its own type */
163 1.1 christos unputstr(rem+1); /* put rest back for later */
164 1.1 christos } else { /* some prefix was a number */
165 1.1 christos unputstr(rem); /* put rest back for later */
166 1.1 christos rem[0] = 0; /* truncate buf after number part */
167 1.1 christos retc = '0'; /* type is number */
168 1.1 christos }
169 1.1 christos }
170 1.1 christos *pbuf = buf;
171 1.1 christos *psz = sz;
172 1.1 christos return retc;
173 1.1 christos }
174 1.1 christos
175 1.1 christos int word(char *);
176 1.1 christos int string(void);
177 1.1 christos int regexpr(void);
178 1.1 christos int sc = 0; /* 1 => return a } right now */
179 1.1 christos int reg = 0; /* 1 => return a REGEXPR now */
180 1.1 christos
181 1.1 christos int yylex(void)
182 1.1 christos {
183 1.1 christos int c;
184 1.1 christos static char *buf = 0;
185 1.1 christos static int bufsize = 5; /* BUG: setting this small causes core dump! */
186 1.1 christos
187 1.2 christos if (buf == 0 && (buf = malloc(bufsize)) == NULL)
188 1.1 christos FATAL( "out of space in yylex" );
189 1.1 christos if (sc) {
190 1.1 christos sc = 0;
191 1.1 christos RET('}');
192 1.1 christos }
193 1.1 christos if (reg) {
194 1.1 christos reg = 0;
195 1.1 christos return regexpr();
196 1.1 christos }
197 1.1 christos for (;;) {
198 1.1 christos c = gettok(&buf, &bufsize);
199 1.1 christos if (c == 0)
200 1.1 christos return 0;
201 1.1 christos if (isalpha(c) || c == '_')
202 1.1 christos return word(buf);
203 1.1 christos if (isdigit(c)) {
204 1.3 christos yylval.cp = setsymtab(buf, buf, atof(buf), CON|NUM, symtab);
205 1.1 christos /* should this also have STR set? */
206 1.1 christos RET(NUMBER);
207 1.1 christos }
208 1.1 christos
209 1.1 christos yylval.i = c;
210 1.1 christos switch (c) {
211 1.1 christos case '\n': /* {EOL} */
212 1.1 christos RET(NL);
213 1.1 christos case '\r': /* assume \n is coming */
214 1.1 christos case ' ': /* {WS}+ */
215 1.1 christos case '\t':
216 1.1 christos break;
217 1.1 christos case '#': /* #.* strip comments */
218 1.1 christos while ((c = input()) != '\n' && c != 0)
219 1.1 christos ;
220 1.1 christos unput(c);
221 1.1 christos break;
222 1.1 christos case ';':
223 1.1 christos RET(';');
224 1.1 christos case '\\':
225 1.1 christos if (peek() == '\n') {
226 1.1 christos input();
227 1.1 christos } else if (peek() == '\r') {
228 1.1 christos input(); input(); /* \n */
229 1.1 christos lineno++;
230 1.1 christos } else {
231 1.1 christos RET(c);
232 1.1 christos }
233 1.1 christos break;
234 1.1 christos case '&':
235 1.1 christos if (peek() == '&') {
236 1.1 christos input(); RET(AND);
237 1.1 christos } else
238 1.1 christos RET('&');
239 1.1 christos case '|':
240 1.1 christos if (peek() == '|') {
241 1.1 christos input(); RET(BOR);
242 1.1 christos } else
243 1.1 christos RET('|');
244 1.1 christos case '!':
245 1.1 christos if (peek() == '=') {
246 1.1 christos input(); yylval.i = NE; RET(NE);
247 1.1 christos } else if (peek() == '~') {
248 1.1 christos input(); yylval.i = NOTMATCH; RET(MATCHOP);
249 1.1 christos } else
250 1.1 christos RET(NOT);
251 1.1 christos case '~':
252 1.1 christos yylval.i = MATCH;
253 1.1 christos RET(MATCHOP);
254 1.1 christos case '<':
255 1.1 christos if (peek() == '=') {
256 1.1 christos input(); yylval.i = LE; RET(LE);
257 1.1 christos } else {
258 1.1 christos yylval.i = LT; RET(LT);
259 1.1 christos }
260 1.1 christos case '=':
261 1.1 christos if (peek() == '=') {
262 1.1 christos input(); yylval.i = EQ; RET(EQ);
263 1.1 christos } else {
264 1.1 christos yylval.i = ASSIGN; RET(ASGNOP);
265 1.1 christos }
266 1.1 christos case '>':
267 1.1 christos if (peek() == '=') {
268 1.1 christos input(); yylval.i = GE; RET(GE);
269 1.1 christos } else if (peek() == '>') {
270 1.1 christos input(); yylval.i = APPEND; RET(APPEND);
271 1.1 christos } else {
272 1.1 christos yylval.i = GT; RET(GT);
273 1.1 christos }
274 1.1 christos case '+':
275 1.1 christos if (peek() == '+') {
276 1.1 christos input(); yylval.i = INCR; RET(INCR);
277 1.1 christos } else if (peek() == '=') {
278 1.1 christos input(); yylval.i = ADDEQ; RET(ASGNOP);
279 1.1 christos } else
280 1.1 christos RET('+');
281 1.1 christos case '-':
282 1.1 christos if (peek() == '-') {
283 1.1 christos input(); yylval.i = DECR; RET(DECR);
284 1.1 christos } else if (peek() == '=') {
285 1.1 christos input(); yylval.i = SUBEQ; RET(ASGNOP);
286 1.1 christos } else
287 1.1 christos RET('-');
288 1.1 christos case '*':
289 1.1 christos if (peek() == '=') { /* *= */
290 1.1 christos input(); yylval.i = MULTEQ; RET(ASGNOP);
291 1.1 christos } else if (peek() == '*') { /* ** or **= */
292 1.1 christos input(); /* eat 2nd * */
293 1.1 christos if (peek() == '=') {
294 1.1 christos input(); yylval.i = POWEQ; RET(ASGNOP);
295 1.1 christos } else {
296 1.1 christos RET(POWER);
297 1.1 christos }
298 1.1 christos } else
299 1.1 christos RET('*');
300 1.1 christos case '/':
301 1.1 christos RET('/');
302 1.1 christos case '%':
303 1.1 christos if (peek() == '=') {
304 1.1 christos input(); yylval.i = MODEQ; RET(ASGNOP);
305 1.1 christos } else
306 1.1 christos RET('%');
307 1.1 christos case '^':
308 1.1 christos if (peek() == '=') {
309 1.1 christos input(); yylval.i = POWEQ; RET(ASGNOP);
310 1.1 christos } else
311 1.1 christos RET(POWER);
312 1.1 christos
313 1.1 christos case '$':
314 1.1 christos /* BUG: awkward, if not wrong */
315 1.1 christos c = gettok(&buf, &bufsize);
316 1.1 christos if (isalpha(c)) {
317 1.1 christos if (strcmp(buf, "NF") == 0) { /* very special */
318 1.1 christos unputstr("(NF)");
319 1.1 christos RET(INDIRECT);
320 1.1 christos }
321 1.1 christos c = peek();
322 1.1 christos if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) {
323 1.1 christos unputstr(buf);
324 1.1 christos RET(INDIRECT);
325 1.1 christos }
326 1.1 christos yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab);
327 1.1 christos RET(IVAR);
328 1.1 christos } else if (c == 0) { /* */
329 1.1 christos SYNTAX( "unexpected end of input after $" );
330 1.1 christos RET(';');
331 1.1 christos } else {
332 1.1 christos unputstr(buf);
333 1.1 christos RET(INDIRECT);
334 1.1 christos }
335 1.1 christos
336 1.1 christos case '}':
337 1.1 christos if (--bracecnt < 0)
338 1.1 christos SYNTAX( "extra }" );
339 1.1 christos sc = 1;
340 1.1 christos RET(';');
341 1.1 christos case ']':
342 1.1 christos if (--brackcnt < 0)
343 1.1 christos SYNTAX( "extra ]" );
344 1.1 christos RET(']');
345 1.1 christos case ')':
346 1.1 christos if (--parencnt < 0)
347 1.1 christos SYNTAX( "extra )" );
348 1.1 christos RET(')');
349 1.1 christos case '{':
350 1.1 christos bracecnt++;
351 1.1 christos RET('{');
352 1.1 christos case '[':
353 1.1 christos brackcnt++;
354 1.1 christos RET('[');
355 1.1 christos case '(':
356 1.1 christos parencnt++;
357 1.1 christos RET('(');
358 1.1 christos
359 1.1 christos case '"':
360 1.1 christos return string(); /* BUG: should be like tran.c ? */
361 1.1 christos
362 1.1 christos default:
363 1.1 christos RET(c);
364 1.1 christos }
365 1.1 christos }
366 1.1 christos }
367 1.1 christos
368 1.1 christos int string(void)
369 1.1 christos {
370 1.1 christos int c, n;
371 1.2 christos uschar *s, *bp;
372 1.2 christos static uschar *buf = 0;
373 1.1 christos static int bufsz = 500;
374 1.1 christos
375 1.2 christos if (buf == 0 && (buf = malloc(bufsz)) == NULL)
376 1.1 christos FATAL("out of space for strings");
377 1.1 christos for (bp = buf; (c = input()) != '"'; ) {
378 1.1 christos if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, "string"))
379 1.1 christos FATAL("out of space for string %.10s...", buf);
380 1.1 christos switch (c) {
381 1.1 christos case '\n':
382 1.1 christos case '\r':
383 1.1 christos case 0:
384 1.1 christos SYNTAX( "non-terminated string %.10s...", buf );
385 1.1 christos lineno++;
386 1.1 christos if (c == 0) /* hopeless */
387 1.1 christos FATAL( "giving up" );
388 1.1 christos break;
389 1.1 christos case '\\':
390 1.1 christos c = input();
391 1.1 christos switch (c) {
392 1.2 christos case '\n': break;
393 1.1 christos case '"': *bp++ = '"'; break;
394 1.1 christos case 'n': *bp++ = '\n'; break;
395 1.1 christos case 't': *bp++ = '\t'; break;
396 1.1 christos case 'f': *bp++ = '\f'; break;
397 1.1 christos case 'r': *bp++ = '\r'; break;
398 1.1 christos case 'b': *bp++ = '\b'; break;
399 1.1 christos case 'v': *bp++ = '\v'; break;
400 1.1 christos case 'a': *bp++ = '\007'; break;
401 1.1 christos case '\\': *bp++ = '\\'; break;
402 1.1 christos
403 1.1 christos case '0': case '1': case '2': /* octal: \d \dd \ddd */
404 1.1 christos case '3': case '4': case '5': case '6': case '7':
405 1.1 christos n = c - '0';
406 1.1 christos if ((c = peek()) >= '0' && c < '8') {
407 1.1 christos n = 8 * n + input() - '0';
408 1.1 christos if ((c = peek()) >= '0' && c < '8')
409 1.1 christos n = 8 * n + input() - '0';
410 1.1 christos }
411 1.1 christos *bp++ = n;
412 1.1 christos break;
413 1.1 christos
414 1.1 christos case 'x': /* hex \x0-9a-fA-F + */
415 1.1 christos { char xbuf[100], *px;
416 1.1 christos for (px = xbuf; (c = input()) != 0 && px-xbuf < 100-2; ) {
417 1.1 christos if (isdigit(c)
418 1.1 christos || (c >= 'a' && c <= 'f')
419 1.1 christos || (c >= 'A' && c <= 'F'))
420 1.1 christos *px++ = c;
421 1.1 christos else
422 1.1 christos break;
423 1.1 christos }
424 1.1 christos *px = 0;
425 1.1 christos unput(c);
426 1.1 christos sscanf(xbuf, "%x", &n);
427 1.1 christos *bp++ = n;
428 1.1 christos break;
429 1.1 christos }
430 1.1 christos
431 1.2 christos default:
432 1.2 christos WARNING("warning: escape sequence `\\%c' "
433 1.2 christos "treated as plain `%c'", c, c);
434 1.1 christos *bp++ = c;
435 1.1 christos break;
436 1.1 christos }
437 1.1 christos break;
438 1.1 christos default:
439 1.1 christos *bp++ = c;
440 1.1 christos break;
441 1.1 christos }
442 1.1 christos }
443 1.1 christos *bp = 0;
444 1.1 christos s = tostring(buf);
445 1.1 christos *bp++ = ' '; *bp++ = 0;
446 1.1 christos yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab);
447 1.1 christos RET(STRING);
448 1.1 christos }
449 1.1 christos
450 1.1 christos
451 1.2 christos int binsearch(const char *w, const Keyword *kp, int n)
452 1.1 christos {
453 1.1 christos int cond, low, mid, high;
454 1.1 christos
455 1.1 christos low = 0;
456 1.1 christos high = n - 1;
457 1.1 christos while (low <= high) {
458 1.1 christos mid = (low + high) / 2;
459 1.1 christos if ((cond = strcmp(w, kp[mid].word)) < 0)
460 1.1 christos high = mid - 1;
461 1.1 christos else if (cond > 0)
462 1.1 christos low = mid + 1;
463 1.1 christos else
464 1.1 christos return mid;
465 1.1 christos }
466 1.1 christos return -1;
467 1.1 christos }
468 1.1 christos
469 1.1 christos int word(char *w)
470 1.1 christos {
471 1.2 christos const Keyword *kp;
472 1.1 christos int c, n;
473 1.1 christos
474 1.1 christos n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
475 1.1 christos /* BUG: this ought to be inside the if; in theory could fault (daniel barrett) */
476 1.1 christos kp = keywords + n;
477 1.1 christos if (n != -1) { /* found in table */
478 1.1 christos yylval.i = kp->sub;
479 1.1 christos switch (kp->type) { /* special handling */
480 1.1 christos case BLTIN:
481 1.1 christos if (kp->sub == FSYSTEM && safe)
482 1.1 christos SYNTAX( "system is unsafe" );
483 1.1 christos RET(kp->type);
484 1.1 christos case FUNC:
485 1.1 christos if (infunc)
486 1.1 christos SYNTAX( "illegal nested function" );
487 1.1 christos RET(kp->type);
488 1.1 christos case RETURN:
489 1.1 christos if (!infunc)
490 1.1 christos SYNTAX( "return not in function" );
491 1.1 christos RET(kp->type);
492 1.1 christos case VARNF:
493 1.1 christos yylval.cp = setsymtab("NF", "", 0.0, NUM, symtab);
494 1.1 christos RET(VARNF);
495 1.1 christos default:
496 1.1 christos RET(kp->type);
497 1.1 christos }
498 1.1 christos }
499 1.1 christos c = peek(); /* look for '(' */
500 1.1 christos if (c != '(' && infunc && (n=isarg(w)) >= 0) {
501 1.1 christos yylval.i = n;
502 1.1 christos RET(ARG);
503 1.1 christos } else {
504 1.1 christos yylval.cp = setsymtab(w, "", 0.0, STR|NUM|DONTFREE, symtab);
505 1.1 christos if (c == '(') {
506 1.1 christos RET(CALL);
507 1.1 christos } else {
508 1.1 christos RET(VAR);
509 1.1 christos }
510 1.1 christos }
511 1.1 christos }
512 1.1 christos
513 1.1 christos void startreg(void) /* next call to yylex will return a regular expression */
514 1.1 christos {
515 1.1 christos reg = 1;
516 1.1 christos }
517 1.1 christos
518 1.1 christos int regexpr(void)
519 1.1 christos {
520 1.1 christos int c;
521 1.2 christos static uschar *buf = 0;
522 1.1 christos static int bufsz = 500;
523 1.2 christos uschar *bp;
524 1.1 christos
525 1.2 christos if (buf == 0 && (buf = malloc(bufsz)) == NULL)
526 1.1 christos FATAL("out of space for rex expr");
527 1.1 christos bp = buf;
528 1.1 christos for ( ; (c = input()) != '/' && c != 0; ) {
529 1.1 christos if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, "regexpr"))
530 1.1 christos FATAL("out of space for reg expr %.10s...", buf);
531 1.1 christos if (c == '\n') {
532 1.1 christos SYNTAX( "newline in regular expression %.10s...", buf );
533 1.1 christos unput('\n');
534 1.1 christos break;
535 1.1 christos } else if (c == '\\') {
536 1.1 christos *bp++ = '\\';
537 1.1 christos *bp++ = input();
538 1.1 christos } else {
539 1.1 christos *bp++ = c;
540 1.1 christos }
541 1.1 christos }
542 1.1 christos *bp = 0;
543 1.1 christos if (c == 0)
544 1.1 christos SYNTAX("non-terminated regular expression %.10s...", buf);
545 1.1 christos yylval.s = tostring(buf);
546 1.1 christos unput('/');
547 1.1 christos RET(REGEXPR);
548 1.1 christos }
549 1.1 christos
550 1.1 christos /* low-level lexical stuff, sort of inherited from lex */
551 1.1 christos
552 1.1 christos char ebuf[300];
553 1.1 christos char *ep = ebuf;
554 1.1 christos char yysbuf[100]; /* pushback buffer */
555 1.1 christos char *yysptr = yysbuf;
556 1.1 christos FILE *yyin = 0;
557 1.1 christos
558 1.1 christos int input(void) /* get next lexical input character */
559 1.1 christos {
560 1.1 christos int c;
561 1.1 christos extern char *lexprog;
562 1.1 christos
563 1.1 christos if (yysptr > yysbuf)
564 1.1 christos c = (uschar)*--yysptr;
565 1.1 christos else if (lexprog != NULL) { /* awk '...' */
566 1.1 christos if ((c = (uschar)*lexprog) != 0)
567 1.1 christos lexprog++;
568 1.1 christos } else /* awk -f ... */
569 1.1 christos c = pgetc();
570 1.1 christos if (c == '\n')
571 1.1 christos lineno++;
572 1.1 christos else if (c == EOF)
573 1.1 christos c = 0;
574 1.1 christos if (ep >= ebuf + sizeof ebuf)
575 1.1 christos ep = ebuf;
576 1.1 christos return *ep++ = c;
577 1.1 christos }
578 1.1 christos
579 1.1 christos void unput(int c) /* put lexical character back on input */
580 1.1 christos {
581 1.1 christos if (c == '\n')
582 1.1 christos lineno--;
583 1.1 christos if (yysptr >= yysbuf + sizeof(yysbuf))
584 1.1 christos FATAL("pushed back too much: %.20s...", yysbuf);
585 1.1 christos *yysptr++ = c;
586 1.1 christos if (--ep < ebuf)
587 1.1 christos ep = ebuf + sizeof(ebuf) - 1;
588 1.1 christos }
589 1.1 christos
590 1.1 christos void unputstr(const char *s) /* put a string back on input */
591 1.1 christos {
592 1.1 christos int i;
593 1.1 christos
594 1.1 christos for (i = strlen(s)-1; i >= 0; i--)
595 1.1 christos unput(s[i]);
596 1.1 christos }
597