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