lex.c revision 1.8 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.8 christos extern bool 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.6 christos const Keyword keywords[] = { /* keep sorted: binary searched */
51 1.1 christos { "BEGIN", XBEGIN, XBEGIN },
52 1.1 christos { "END", XEND, XEND },
53 1.1 christos { "NF", VARNF, VARNF },
54 1.6 christos { "and", FAND, BLTIN },
55 1.1 christos { "atan2", FATAN, BLTIN },
56 1.1 christos { "break", BREAK, BREAK },
57 1.1 christos { "close", CLOSE, CLOSE },
58 1.6 christos { "compl", FCOMPL, BLTIN },
59 1.1 christos { "continue", CONTINUE, CONTINUE },
60 1.1 christos { "cos", FCOS, BLTIN },
61 1.1 christos { "delete", DELETE, DELETE },
62 1.1 christos { "do", DO, DO },
63 1.1 christos { "else", ELSE, ELSE },
64 1.1 christos { "exit", EXIT, EXIT },
65 1.1 christos { "exp", FEXP, BLTIN },
66 1.1 christos { "fflush", FFLUSH, BLTIN },
67 1.1 christos { "for", FOR, FOR },
68 1.1 christos { "func", FUNC, FUNC },
69 1.1 christos { "function", FUNC, FUNC },
70 1.2 christos { "gensub", GENSUB, GENSUB },
71 1.1 christos { "getline", GETLINE, GETLINE },
72 1.1 christos { "gsub", GSUB, GSUB },
73 1.1 christos { "if", IF, IF },
74 1.1 christos { "in", IN, IN },
75 1.1 christos { "index", INDEX, INDEX },
76 1.1 christos { "int", FINT, BLTIN },
77 1.1 christos { "length", FLENGTH, BLTIN },
78 1.1 christos { "log", FLOG, BLTIN },
79 1.6 christos { "lshift", FLSHIFT, BLTIN },
80 1.1 christos { "match", MATCHFCN, MATCHFCN },
81 1.8 christos { "mktime", FMKTIME, BLTIN },
82 1.1 christos { "next", NEXT, NEXT },
83 1.1 christos { "nextfile", NEXTFILE, NEXTFILE },
84 1.6 christos { "or", FFOR, BLTIN },
85 1.1 christos { "print", PRINT, PRINT },
86 1.1 christos { "printf", PRINTF, PRINTF },
87 1.1 christos { "rand", FRAND, BLTIN },
88 1.1 christos { "return", RETURN, RETURN },
89 1.6 christos { "rshift", FRSHIFT, BLTIN },
90 1.1 christos { "sin", FSIN, BLTIN },
91 1.1 christos { "split", SPLIT, SPLIT },
92 1.1 christos { "sprintf", SPRINTF, SPRINTF },
93 1.1 christos { "sqrt", FSQRT, BLTIN },
94 1.1 christos { "srand", FSRAND, BLTIN },
95 1.2 christos { "strftime", FSTRFTIME, BLTIN },
96 1.1 christos { "sub", SUB, SUB },
97 1.1 christos { "substr", SUBSTR, SUBSTR },
98 1.1 christos { "system", FSYSTEM, BLTIN },
99 1.2 christos { "systime", FSYSTIME, BLTIN },
100 1.1 christos { "tolower", FTOLOWER, BLTIN },
101 1.1 christos { "toupper", FTOUPPER, BLTIN },
102 1.1 christos { "while", WHILE, WHILE },
103 1.6 christos { "xor", FXOR, BLTIN },
104 1.1 christos };
105 1.1 christos
106 1.1 christos #define RET(x) { if(dbg)printf("lex %s\n", tokname(x)); return(x); }
107 1.1 christos
108 1.6 christos static int peek(void)
109 1.1 christos {
110 1.1 christos int c = input();
111 1.1 christos unput(c);
112 1.1 christos return c;
113 1.1 christos }
114 1.1 christos
115 1.6 christos static int gettok(char **pbuf, int *psz) /* get next input token */
116 1.1 christos {
117 1.1 christos int c, retc;
118 1.6 christos char *buf = *pbuf;
119 1.1 christos int sz = *psz;
120 1.6 christos char *bp = buf;
121 1.1 christos
122 1.1 christos c = input();
123 1.1 christos if (c == 0)
124 1.1 christos return 0;
125 1.1 christos buf[0] = c;
126 1.1 christos buf[1] = 0;
127 1.1 christos if (!isalnum(c) && c != '.' && c != '_')
128 1.1 christos return c;
129 1.1 christos
130 1.1 christos *bp++ = c;
131 1.1 christos if (isalpha(c) || c == '_') { /* it's a varname */
132 1.1 christos for ( ; (c = input()) != 0; ) {
133 1.1 christos if (bp-buf >= sz)
134 1.1 christos if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, "gettok"))
135 1.1 christos FATAL( "out of space for name %.10s...", buf );
136 1.1 christos if (isalnum(c) || c == '_')
137 1.1 christos *bp++ = c;
138 1.1 christos else {
139 1.1 christos *bp = 0;
140 1.1 christos unput(c);
141 1.1 christos break;
142 1.1 christos }
143 1.1 christos }
144 1.1 christos *bp = 0;
145 1.1 christos retc = 'a'; /* alphanumeric */
146 1.1 christos } else { /* maybe it's a number, but could be . */
147 1.1 christos char *rem;
148 1.1 christos /* read input until can't be a number */
149 1.1 christos for ( ; (c = input()) != 0; ) {
150 1.1 christos if (bp-buf >= sz)
151 1.1 christos if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, "gettok"))
152 1.1 christos FATAL( "out of space for number %.10s...", buf );
153 1.5 christos if (isdigit(c) || c == 'e' || c == 'E'
154 1.1 christos || c == '.' || c == '+' || c == '-')
155 1.1 christos *bp++ = c;
156 1.1 christos else {
157 1.1 christos unput(c);
158 1.1 christos break;
159 1.1 christos }
160 1.1 christos }
161 1.1 christos *bp = 0;
162 1.1 christos strtod(buf, &rem); /* parse the number */
163 1.6 christos if (rem == buf) { /* it wasn't a valid number at all */
164 1.1 christos buf[1] = 0; /* return one character as token */
165 1.8 christos retc = (uschar)buf[0]; /* character is its own type */
166 1.1 christos unputstr(rem+1); /* put rest back for later */
167 1.1 christos } else { /* some prefix was a number */
168 1.1 christos unputstr(rem); /* put rest back for later */
169 1.1 christos rem[0] = 0; /* truncate buf after number part */
170 1.1 christos retc = '0'; /* type is number */
171 1.1 christos }
172 1.1 christos }
173 1.1 christos *pbuf = buf;
174 1.1 christos *psz = sz;
175 1.1 christos return retc;
176 1.1 christos }
177 1.1 christos
178 1.1 christos int word(char *);
179 1.1 christos int string(void);
180 1.1 christos int regexpr(void);
181 1.6 christos bool sc = false; /* true => return a } right now */
182 1.6 christos bool reg = false; /* true => return a REGEXPR now */
183 1.1 christos
184 1.1 christos int yylex(void)
185 1.1 christos {
186 1.1 christos int c;
187 1.6 christos static char *buf = NULL;
188 1.1 christos static int bufsize = 5; /* BUG: setting this small causes core dump! */
189 1.1 christos
190 1.8 christos if (buf == NULL && (buf = (char *) malloc(bufsize)) == NULL)
191 1.1 christos FATAL( "out of space in yylex" );
192 1.1 christos if (sc) {
193 1.6 christos sc = false;
194 1.1 christos RET('}');
195 1.1 christos }
196 1.1 christos if (reg) {
197 1.6 christos reg = false;
198 1.1 christos return regexpr();
199 1.1 christos }
200 1.1 christos for (;;) {
201 1.1 christos c = gettok(&buf, &bufsize);
202 1.1 christos if (c == 0)
203 1.1 christos return 0;
204 1.1 christos if (isalpha(c) || c == '_')
205 1.1 christos return word(buf);
206 1.1 christos if (isdigit(c)) {
207 1.6 christos char *cp = tostring(buf);
208 1.8 christos double result;
209 1.8 christos
210 1.8 christos if (is_number(cp, & result))
211 1.8 christos yylval.cp = setsymtab(buf, cp, result, CON|NUM, symtab);
212 1.8 christos else
213 1.8 christos yylval.cp = setsymtab(buf, cp, 0.0, STR, symtab);
214 1.6 christos free(cp);
215 1.1 christos /* should this also have STR set? */
216 1.1 christos RET(NUMBER);
217 1.1 christos }
218 1.5 christos
219 1.1 christos yylval.i = c;
220 1.1 christos switch (c) {
221 1.1 christos case '\n': /* {EOL} */
222 1.6 christos lineno++;
223 1.1 christos RET(NL);
224 1.1 christos case '\r': /* assume \n is coming */
225 1.1 christos case ' ': /* {WS}+ */
226 1.1 christos case '\t':
227 1.1 christos break;
228 1.1 christos case '#': /* #.* strip comments */
229 1.1 christos while ((c = input()) != '\n' && c != 0)
230 1.1 christos ;
231 1.1 christos unput(c);
232 1.6 christos /*
233 1.8 christos * Next line is a hack, it compensates for
234 1.6 christos * unput's treatment of \n.
235 1.6 christos */
236 1.6 christos lineno++;
237 1.1 christos break;
238 1.1 christos case ';':
239 1.1 christos RET(';');
240 1.1 christos case '\\':
241 1.1 christos if (peek() == '\n') {
242 1.1 christos input();
243 1.6 christos lineno++;
244 1.1 christos } else if (peek() == '\r') {
245 1.1 christos input(); input(); /* \n */
246 1.1 christos lineno++;
247 1.1 christos } else {
248 1.1 christos RET(c);
249 1.1 christos }
250 1.1 christos break;
251 1.1 christos case '&':
252 1.1 christos if (peek() == '&') {
253 1.1 christos input(); RET(AND);
254 1.5 christos } else
255 1.1 christos RET('&');
256 1.1 christos case '|':
257 1.1 christos if (peek() == '|') {
258 1.1 christos input(); RET(BOR);
259 1.1 christos } else
260 1.1 christos RET('|');
261 1.1 christos case '!':
262 1.1 christos if (peek() == '=') {
263 1.1 christos input(); yylval.i = NE; RET(NE);
264 1.1 christos } else if (peek() == '~') {
265 1.1 christos input(); yylval.i = NOTMATCH; RET(MATCHOP);
266 1.1 christos } else
267 1.1 christos RET(NOT);
268 1.1 christos case '~':
269 1.1 christos yylval.i = MATCH;
270 1.1 christos RET(MATCHOP);
271 1.1 christos case '<':
272 1.1 christos if (peek() == '=') {
273 1.1 christos input(); yylval.i = LE; RET(LE);
274 1.1 christos } else {
275 1.1 christos yylval.i = LT; RET(LT);
276 1.1 christos }
277 1.1 christos case '=':
278 1.1 christos if (peek() == '=') {
279 1.1 christos input(); yylval.i = EQ; RET(EQ);
280 1.1 christos } else {
281 1.1 christos yylval.i = ASSIGN; RET(ASGNOP);
282 1.1 christos }
283 1.1 christos case '>':
284 1.1 christos if (peek() == '=') {
285 1.1 christos input(); yylval.i = GE; RET(GE);
286 1.1 christos } else if (peek() == '>') {
287 1.1 christos input(); yylval.i = APPEND; RET(APPEND);
288 1.1 christos } else {
289 1.1 christos yylval.i = GT; RET(GT);
290 1.1 christos }
291 1.1 christos case '+':
292 1.1 christos if (peek() == '+') {
293 1.1 christos input(); yylval.i = INCR; RET(INCR);
294 1.1 christos } else if (peek() == '=') {
295 1.1 christos input(); yylval.i = ADDEQ; RET(ASGNOP);
296 1.1 christos } else
297 1.1 christos RET('+');
298 1.1 christos case '-':
299 1.1 christos if (peek() == '-') {
300 1.1 christos input(); yylval.i = DECR; RET(DECR);
301 1.1 christos } else if (peek() == '=') {
302 1.1 christos input(); yylval.i = SUBEQ; RET(ASGNOP);
303 1.1 christos } else
304 1.1 christos RET('-');
305 1.1 christos case '*':
306 1.1 christos if (peek() == '=') { /* *= */
307 1.1 christos input(); yylval.i = MULTEQ; RET(ASGNOP);
308 1.1 christos } else if (peek() == '*') { /* ** or **= */
309 1.1 christos input(); /* eat 2nd * */
310 1.1 christos if (peek() == '=') {
311 1.1 christos input(); yylval.i = POWEQ; RET(ASGNOP);
312 1.1 christos } else {
313 1.1 christos RET(POWER);
314 1.1 christos }
315 1.1 christos } else
316 1.1 christos RET('*');
317 1.1 christos case '/':
318 1.1 christos RET('/');
319 1.1 christos case '%':
320 1.1 christos if (peek() == '=') {
321 1.1 christos input(); yylval.i = MODEQ; RET(ASGNOP);
322 1.1 christos } else
323 1.1 christos RET('%');
324 1.1 christos case '^':
325 1.1 christos if (peek() == '=') {
326 1.1 christos input(); yylval.i = POWEQ; RET(ASGNOP);
327 1.1 christos } else
328 1.1 christos RET(POWER);
329 1.1 christos
330 1.1 christos case '$':
331 1.1 christos /* BUG: awkward, if not wrong */
332 1.1 christos c = gettok(&buf, &bufsize);
333 1.1 christos if (isalpha(c)) {
334 1.1 christos if (strcmp(buf, "NF") == 0) { /* very special */
335 1.1 christos unputstr("(NF)");
336 1.1 christos RET(INDIRECT);
337 1.1 christos }
338 1.1 christos c = peek();
339 1.1 christos if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) {
340 1.1 christos unputstr(buf);
341 1.1 christos RET(INDIRECT);
342 1.1 christos }
343 1.1 christos yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab);
344 1.1 christos RET(IVAR);
345 1.1 christos } else if (c == 0) { /* */
346 1.1 christos SYNTAX( "unexpected end of input after $" );
347 1.1 christos RET(';');
348 1.1 christos } else {
349 1.1 christos unputstr(buf);
350 1.1 christos RET(INDIRECT);
351 1.1 christos }
352 1.5 christos
353 1.1 christos case '}':
354 1.1 christos if (--bracecnt < 0)
355 1.1 christos SYNTAX( "extra }" );
356 1.6 christos sc = true;
357 1.1 christos RET(';');
358 1.1 christos case ']':
359 1.1 christos if (--brackcnt < 0)
360 1.1 christos SYNTAX( "extra ]" );
361 1.1 christos RET(']');
362 1.1 christos case ')':
363 1.1 christos if (--parencnt < 0)
364 1.1 christos SYNTAX( "extra )" );
365 1.1 christos RET(')');
366 1.1 christos case '{':
367 1.1 christos bracecnt++;
368 1.1 christos RET('{');
369 1.1 christos case '[':
370 1.1 christos brackcnt++;
371 1.1 christos RET('[');
372 1.1 christos case '(':
373 1.1 christos parencnt++;
374 1.1 christos RET('(');
375 1.5 christos
376 1.1 christos case '"':
377 1.1 christos return string(); /* BUG: should be like tran.c ? */
378 1.5 christos
379 1.1 christos default:
380 1.1 christos RET(c);
381 1.1 christos }
382 1.1 christos }
383 1.1 christos }
384 1.1 christos
385 1.1 christos int string(void)
386 1.1 christos {
387 1.1 christos int c, n;
388 1.6 christos char *s, *bp;
389 1.6 christos static char *buf = NULL;
390 1.1 christos static int bufsz = 500;
391 1.1 christos
392 1.8 christos if (buf == NULL && (buf = (char *) malloc(bufsz)) == NULL)
393 1.1 christos FATAL("out of space for strings");
394 1.1 christos for (bp = buf; (c = input()) != '"'; ) {
395 1.1 christos if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, "string"))
396 1.1 christos FATAL("out of space for string %.10s...", buf);
397 1.1 christos switch (c) {
398 1.1 christos case '\n':
399 1.1 christos case '\r':
400 1.1 christos case 0:
401 1.6 christos *bp = '\0';
402 1.1 christos SYNTAX( "non-terminated string %.10s...", buf );
403 1.1 christos if (c == 0) /* hopeless */
404 1.1 christos FATAL( "giving up" );
405 1.6 christos lineno++;
406 1.1 christos break;
407 1.1 christos case '\\':
408 1.1 christos c = input();
409 1.1 christos switch (c) {
410 1.7 christos case '\n': break;
411 1.1 christos case '"': *bp++ = '"'; break;
412 1.5 christos case 'n': *bp++ = '\n'; break;
413 1.1 christos case 't': *bp++ = '\t'; break;
414 1.1 christos case 'f': *bp++ = '\f'; break;
415 1.1 christos case 'r': *bp++ = '\r'; break;
416 1.1 christos case 'b': *bp++ = '\b'; break;
417 1.1 christos case 'v': *bp++ = '\v'; break;
418 1.6 christos case 'a': *bp++ = '\a'; break;
419 1.1 christos case '\\': *bp++ = '\\'; break;
420 1.1 christos
421 1.1 christos case '0': case '1': case '2': /* octal: \d \dd \ddd */
422 1.1 christos case '3': case '4': case '5': case '6': case '7':
423 1.1 christos n = c - '0';
424 1.1 christos if ((c = peek()) >= '0' && c < '8') {
425 1.1 christos n = 8 * n + input() - '0';
426 1.1 christos if ((c = peek()) >= '0' && c < '8')
427 1.1 christos n = 8 * n + input() - '0';
428 1.1 christos }
429 1.1 christos *bp++ = n;
430 1.1 christos break;
431 1.1 christos
432 1.8 christos case 'x': /* hex \x0-9a-fA-F (exactly two) */
433 1.8 christos {
434 1.8 christos int i;
435 1.8 christos
436 1.8 christos if (!isxdigit(peek())) {
437 1.8 christos unput(c);
438 1.8 christos break;
439 1.8 christos }
440 1.8 christos n = 0;
441 1.8 christos for (i = 0; i < 2; i++) {
442 1.8 christos c = input();
443 1.8 christos if (c == 0)
444 1.8 christos break;
445 1.8 christos if (isxdigit(c)) {
446 1.8 christos c = tolower(c);
447 1.8 christos n *= 16;
448 1.8 christos if (isdigit(c))
449 1.8 christos n += (c - '0');
450 1.8 christos else
451 1.8 christos n += 10 + (c - 'a');
452 1.8 christos } else {
453 1.8 christos unput(c);
454 1.8 christos break;
455 1.8 christos }
456 1.8 christos }
457 1.8 christos if (i)
458 1.8 christos *bp++ = n;
459 1.8 christos break;
460 1.8 christos }
461 1.8 christos
462 1.8 christos case 'u': /* utf \u0-9a-fA-F (1..8) */
463 1.8 christos {
464 1.8 christos int i;
465 1.8 christos
466 1.8 christos n = 0;
467 1.8 christos for (i = 0; i < 8; i++) {
468 1.8 christos c = input();
469 1.8 christos if (!isxdigit(c) || c == 0)
470 1.8 christos break;
471 1.8 christos c = tolower(c);
472 1.8 christos n *= 16;
473 1.8 christos if (isdigit(c))
474 1.8 christos n += (c - '0');
475 1.1 christos else
476 1.8 christos n += 10 + (c - 'a');
477 1.1 christos }
478 1.1 christos unput(c);
479 1.8 christos bp += runetochar(bp, n);
480 1.1 christos break;
481 1.1 christos }
482 1.1 christos
483 1.2 christos default:
484 1.1 christos *bp++ = c;
485 1.1 christos break;
486 1.1 christos }
487 1.1 christos break;
488 1.1 christos default:
489 1.1 christos *bp++ = c;
490 1.1 christos break;
491 1.1 christos }
492 1.1 christos }
493 1.5 christos *bp = 0;
494 1.1 christos s = tostring(buf);
495 1.6 christos *bp++ = ' '; *bp++ = '\0';
496 1.1 christos yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab);
497 1.6 christos free(s);
498 1.1 christos RET(STRING);
499 1.1 christos }
500 1.1 christos
501 1.1 christos
502 1.6 christos static int binsearch(char *w, const Keyword *kp, int n)
503 1.1 christos {
504 1.1 christos int cond, low, mid, high;
505 1.1 christos
506 1.1 christos low = 0;
507 1.1 christos high = n - 1;
508 1.1 christos while (low <= high) {
509 1.1 christos mid = (low + high) / 2;
510 1.1 christos if ((cond = strcmp(w, kp[mid].word)) < 0)
511 1.1 christos high = mid - 1;
512 1.1 christos else if (cond > 0)
513 1.1 christos low = mid + 1;
514 1.1 christos else
515 1.1 christos return mid;
516 1.1 christos }
517 1.1 christos return -1;
518 1.1 christos }
519 1.1 christos
520 1.5 christos int word(char *w)
521 1.1 christos {
522 1.2 christos const Keyword *kp;
523 1.1 christos int c, n;
524 1.1 christos
525 1.1 christos n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
526 1.1 christos if (n != -1) { /* found in table */
527 1.4 kamil kp = keywords + n;
528 1.1 christos yylval.i = kp->sub;
529 1.1 christos switch (kp->type) { /* special handling */
530 1.1 christos case BLTIN:
531 1.1 christos if (kp->sub == FSYSTEM && safe)
532 1.1 christos SYNTAX( "system is unsafe" );
533 1.1 christos RET(kp->type);
534 1.1 christos case FUNC:
535 1.1 christos if (infunc)
536 1.1 christos SYNTAX( "illegal nested function" );
537 1.1 christos RET(kp->type);
538 1.1 christos case RETURN:
539 1.1 christos if (!infunc)
540 1.1 christos SYNTAX( "return not in function" );
541 1.1 christos RET(kp->type);
542 1.1 christos case VARNF:
543 1.1 christos yylval.cp = setsymtab("NF", "", 0.0, NUM, symtab);
544 1.1 christos RET(VARNF);
545 1.1 christos default:
546 1.1 christos RET(kp->type);
547 1.1 christos }
548 1.1 christos }
549 1.1 christos c = peek(); /* look for '(' */
550 1.1 christos if (c != '(' && infunc && (n=isarg(w)) >= 0) {
551 1.1 christos yylval.i = n;
552 1.1 christos RET(ARG);
553 1.1 christos } else {
554 1.1 christos yylval.cp = setsymtab(w, "", 0.0, STR|NUM|DONTFREE, symtab);
555 1.1 christos if (c == '(') {
556 1.1 christos RET(CALL);
557 1.1 christos } else {
558 1.1 christos RET(VAR);
559 1.1 christos }
560 1.1 christos }
561 1.1 christos }
562 1.1 christos
563 1.1 christos void startreg(void) /* next call to yylex will return a regular expression */
564 1.1 christos {
565 1.6 christos reg = true;
566 1.1 christos }
567 1.1 christos
568 1.1 christos int regexpr(void)
569 1.1 christos {
570 1.1 christos int c;
571 1.6 christos static char *buf = NULL;
572 1.1 christos static int bufsz = 500;
573 1.6 christos char *bp;
574 1.1 christos
575 1.8 christos if (buf == NULL && (buf = (char *) malloc(bufsz)) == NULL)
576 1.8 christos FATAL("out of space for reg expr");
577 1.1 christos bp = buf;
578 1.1 christos for ( ; (c = input()) != '/' && c != 0; ) {
579 1.1 christos if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, "regexpr"))
580 1.1 christos FATAL("out of space for reg expr %.10s...", buf);
581 1.1 christos if (c == '\n') {
582 1.6 christos *bp = '\0';
583 1.5 christos SYNTAX( "newline in regular expression %.10s...", buf );
584 1.1 christos unput('\n');
585 1.1 christos break;
586 1.1 christos } else if (c == '\\') {
587 1.5 christos *bp++ = '\\';
588 1.1 christos *bp++ = input();
589 1.1 christos } else {
590 1.1 christos *bp++ = c;
591 1.1 christos }
592 1.1 christos }
593 1.1 christos *bp = 0;
594 1.1 christos if (c == 0)
595 1.1 christos SYNTAX("non-terminated regular expression %.10s...", buf);
596 1.1 christos yylval.s = tostring(buf);
597 1.1 christos unput('/');
598 1.1 christos RET(REGEXPR);
599 1.1 christos }
600 1.1 christos
601 1.1 christos /* low-level lexical stuff, sort of inherited from lex */
602 1.1 christos
603 1.1 christos char ebuf[300];
604 1.1 christos char *ep = ebuf;
605 1.1 christos char yysbuf[100]; /* pushback buffer */
606 1.1 christos char *yysptr = yysbuf;
607 1.6 christos FILE *yyin = NULL;
608 1.1 christos
609 1.1 christos int input(void) /* get next lexical input character */
610 1.1 christos {
611 1.1 christos int c;
612 1.1 christos extern char *lexprog;
613 1.1 christos
614 1.1 christos if (yysptr > yysbuf)
615 1.1 christos c = (uschar)*--yysptr;
616 1.1 christos else if (lexprog != NULL) { /* awk '...' */
617 1.1 christos if ((c = (uschar)*lexprog) != 0)
618 1.1 christos lexprog++;
619 1.1 christos } else /* awk -f ... */
620 1.1 christos c = pgetc();
621 1.6 christos if (c == EOF)
622 1.1 christos c = 0;
623 1.1 christos if (ep >= ebuf + sizeof ebuf)
624 1.1 christos ep = ebuf;
625 1.6 christos *ep = c;
626 1.6 christos if (c != 0) {
627 1.6 christos ep++;
628 1.6 christos }
629 1.6 christos return (c);
630 1.1 christos }
631 1.1 christos
632 1.1 christos void unput(int c) /* put lexical character back on input */
633 1.1 christos {
634 1.6 christos if (c == '\n')
635 1.1 christos lineno--;
636 1.1 christos if (yysptr >= yysbuf + sizeof(yysbuf))
637 1.1 christos FATAL("pushed back too much: %.20s...", yysbuf);
638 1.1 christos *yysptr++ = c;
639 1.1 christos if (--ep < ebuf)
640 1.1 christos ep = ebuf + sizeof(ebuf) - 1;
641 1.1 christos }
642 1.1 christos
643 1.1 christos void unputstr(const char *s) /* put a string back on input */
644 1.1 christos {
645 1.1 christos int i;
646 1.1 christos
647 1.1 christos for (i = strlen(s)-1; i >= 0; i--)
648 1.1 christos unput(s[i]);
649 1.1 christos }
650