blob: 9d1ae060eeefe78650c67e83c1b8e503e39ffa46 [file] [log] [blame]
Brian Kernighan87b94932012-12-22 10:35:39 -05001/****************************************************************
2Copyright (C) Lucent Technologies 1997
3All Rights Reserved
4
5Permission to use, copy, modify, and distribute this software and
6its documentation for any purpose and without fee is hereby
7granted, provided that the above copyright notice appear in all
8copies and that both that the copyright notice and this
9permission notice and warranty disclaimer appear in supporting
10documentation, and that the name Lucent Technologies or any of
11its entities not be used in advertising or publicity pertaining
12to distribution of the software without specific, written prior
13permission.
14
15LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22THIS SOFTWARE.
23****************************************************************/
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <ctype.h>
29#include "awk.h"
Arnold D. Robbins07f04382020-07-30 17:12:45 +030030#include "awkgram.tab.h"
Brian Kernighan87b94932012-12-22 10:35:39 -050031
32extern YYSTYPE yylval;
enh-google7b245a02020-02-28 03:18:29 -080033extern bool infunc;
Brian Kernighan87b94932012-12-22 10:35:39 -050034
35int lineno = 1;
36int bracecnt = 0;
37int brackcnt = 0;
38int parencnt = 0;
39
40typedef struct Keyword {
41 const char *word;
42 int sub;
43 int type;
44} Keyword;
45
zoulasc6a877092020-01-24 04:11:59 -050046const Keyword keywords[] = { /* keep sorted: binary searched */
Brian Kernighan87b94932012-12-22 10:35:39 -050047 { "BEGIN", XBEGIN, XBEGIN },
48 { "END", XEND, XEND },
49 { "NF", VARNF, VARNF },
50 { "atan2", FATAN, BLTIN },
51 { "break", BREAK, BREAK },
52 { "close", CLOSE, CLOSE },
53 { "continue", CONTINUE, CONTINUE },
54 { "cos", FCOS, BLTIN },
55 { "delete", DELETE, DELETE },
56 { "do", DO, DO },
57 { "else", ELSE, ELSE },
58 { "exit", EXIT, EXIT },
59 { "exp", FEXP, BLTIN },
60 { "fflush", FFLUSH, BLTIN },
61 { "for", FOR, FOR },
62 { "func", FUNC, FUNC },
63 { "function", FUNC, FUNC },
64 { "getline", GETLINE, GETLINE },
65 { "gsub", GSUB, GSUB },
66 { "if", IF, IF },
67 { "in", IN, IN },
68 { "index", INDEX, INDEX },
69 { "int", FINT, BLTIN },
70 { "length", FLENGTH, BLTIN },
71 { "log", FLOG, BLTIN },
72 { "match", MATCHFCN, MATCHFCN },
73 { "next", NEXT, NEXT },
74 { "nextfile", NEXTFILE, NEXTFILE },
75 { "print", PRINT, PRINT },
76 { "printf", PRINTF, PRINTF },
77 { "rand", FRAND, BLTIN },
78 { "return", RETURN, RETURN },
79 { "sin", FSIN, BLTIN },
80 { "split", SPLIT, SPLIT },
81 { "sprintf", SPRINTF, SPRINTF },
82 { "sqrt", FSQRT, BLTIN },
83 { "srand", FSRAND, BLTIN },
84 { "sub", SUB, SUB },
85 { "substr", SUBSTR, SUBSTR },
86 { "system", FSYSTEM, BLTIN },
87 { "tolower", FTOLOWER, BLTIN },
88 { "toupper", FTOUPPER, BLTIN },
89 { "while", WHILE, WHILE },
90};
91
92#define RET(x) { if(dbg)printf("lex %s\n", tokname(x)); return(x); }
93
zoulasc6a877092020-01-24 04:11:59 -050094static int peek(void)
Brian Kernighan87b94932012-12-22 10:35:39 -050095{
96 int c = input();
97 unput(c);
98 return c;
99}
100
zoulasc6a877092020-01-24 04:11:59 -0500101static int gettok(char **pbuf, int *psz) /* get next input token */
Brian Kernighan87b94932012-12-22 10:35:39 -0500102{
103 int c, retc;
104 char *buf = *pbuf;
105 int sz = *psz;
106 char *bp = buf;
107
108 c = input();
109 if (c == 0)
110 return 0;
111 buf[0] = c;
112 buf[1] = 0;
113 if (!isalnum(c) && c != '.' && c != '_')
114 return c;
115
116 *bp++ = c;
117 if (isalpha(c) || c == '_') { /* it's a varname */
118 for ( ; (c = input()) != 0; ) {
119 if (bp-buf >= sz)
120 if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, "gettok"))
121 FATAL( "out of space for name %.10s...", buf );
122 if (isalnum(c) || c == '_')
123 *bp++ = c;
124 else {
125 *bp = 0;
126 unput(c);
127 break;
128 }
129 }
130 *bp = 0;
131 retc = 'a'; /* alphanumeric */
132 } else { /* maybe it's a number, but could be . */
133 char *rem;
134 /* read input until can't be a number */
135 for ( ; (c = input()) != 0; ) {
136 if (bp-buf >= sz)
137 if (!adjbuf(&buf, &sz, bp-buf+2, 100, &bp, "gettok"))
138 FATAL( "out of space for number %.10s...", buf );
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600139 if (isdigit(c) || c == 'e' || c == 'E'
Brian Kernighan87b94932012-12-22 10:35:39 -0500140 || c == '.' || c == '+' || c == '-')
141 *bp++ = c;
142 else {
143 unput(c);
144 break;
145 }
146 }
147 *bp = 0;
148 strtod(buf, &rem); /* parse the number */
149 if (rem == buf) { /* it wasn't a valid number at all */
150 buf[1] = 0; /* return one character as token */
Todd C. Miller22ee26b2020-07-29 12:27:45 -0600151 retc = (uschar)buf[0]; /* character is its own type */
Brian Kernighan87b94932012-12-22 10:35:39 -0500152 unputstr(rem+1); /* put rest back for later */
153 } else { /* some prefix was a number */
154 unputstr(rem); /* put rest back for later */
155 rem[0] = 0; /* truncate buf after number part */
156 retc = '0'; /* type is number */
157 }
158 }
159 *pbuf = buf;
160 *psz = sz;
161 return retc;
162}
163
164int word(char *);
165int string(void);
166int regexpr(void);
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200167bool sc = false; /* true => return a } right now */
168bool reg = false; /* true => return a REGEXPR now */
Brian Kernighan87b94932012-12-22 10:35:39 -0500169
170int yylex(void)
171{
172 int c;
pfg52421942016-06-03 21:23:11 +0000173 static char *buf = NULL;
Brian Kernighan87b94932012-12-22 10:35:39 -0500174 static int bufsize = 5; /* BUG: setting this small causes core dump! */
175
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300176 if (buf == NULL && (buf = (char *) malloc(bufsize)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500177 FATAL( "out of space in yylex" );
178 if (sc) {
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200179 sc = false;
Brian Kernighan87b94932012-12-22 10:35:39 -0500180 RET('}');
181 }
182 if (reg) {
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200183 reg = false;
Brian Kernighan87b94932012-12-22 10:35:39 -0500184 return regexpr();
185 }
186 for (;;) {
187 c = gettok(&buf, &bufsize);
188 if (c == 0)
189 return 0;
190 if (isalpha(c) || c == '_')
191 return word(buf);
192 if (isdigit(c)) {
Arnold D. Robbinsc7eeb572020-01-05 21:18:36 +0200193 char *cp = tostring(buf);
Arnold Robbinscc9e9b62020-12-08 08:05:22 +0200194 double result;
195
196 if (is_number(cp, & result))
197 yylval.cp = setsymtab(buf, cp, result, CON|NUM, symtab);
198 else
199 yylval.cp = setsymtab(buf, cp, 0.0, STR, symtab);
Arnold D. Robbinsc7eeb572020-01-05 21:18:36 +0200200 free(cp);
Brian Kernighan87b94932012-12-22 10:35:39 -0500201 /* should this also have STR set? */
202 RET(NUMBER);
203 }
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600204
Brian Kernighan87b94932012-12-22 10:35:39 -0500205 yylval.i = c;
206 switch (c) {
207 case '\n': /* {EOL} */
Cody Peter Mello6fe0a042018-09-21 11:16:27 -0700208 lineno++;
Brian Kernighan87b94932012-12-22 10:35:39 -0500209 RET(NL);
210 case '\r': /* assume \n is coming */
211 case ' ': /* {WS}+ */
212 case '\t':
213 break;
214 case '#': /* #.* strip comments */
215 while ((c = input()) != '\n' && c != 0)
216 ;
217 unput(c);
Arnold D. Robbins768d6b52020-01-31 08:54:10 +0200218 /*
219 * Next line is a hack, itcompensates for
220 * unput's treatment of \n.
221 */
222 lineno++;
Brian Kernighan87b94932012-12-22 10:35:39 -0500223 break;
224 case ';':
225 RET(';');
226 case '\\':
227 if (peek() == '\n') {
228 input();
Cody Peter Mello6fe0a042018-09-21 11:16:27 -0700229 lineno++;
Brian Kernighan87b94932012-12-22 10:35:39 -0500230 } else if (peek() == '\r') {
231 input(); input(); /* \n */
232 lineno++;
233 } else {
234 RET(c);
235 }
236 break;
237 case '&':
238 if (peek() == '&') {
239 input(); RET(AND);
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600240 } else
Brian Kernighan87b94932012-12-22 10:35:39 -0500241 RET('&');
242 case '|':
243 if (peek() == '|') {
244 input(); RET(BOR);
245 } else
246 RET('|');
247 case '!':
248 if (peek() == '=') {
249 input(); yylval.i = NE; RET(NE);
250 } else if (peek() == '~') {
251 input(); yylval.i = NOTMATCH; RET(MATCHOP);
252 } else
253 RET(NOT);
254 case '~':
255 yylval.i = MATCH;
256 RET(MATCHOP);
257 case '<':
258 if (peek() == '=') {
259 input(); yylval.i = LE; RET(LE);
260 } else {
261 yylval.i = LT; RET(LT);
262 }
263 case '=':
264 if (peek() == '=') {
265 input(); yylval.i = EQ; RET(EQ);
266 } else {
267 yylval.i = ASSIGN; RET(ASGNOP);
268 }
269 case '>':
270 if (peek() == '=') {
271 input(); yylval.i = GE; RET(GE);
272 } else if (peek() == '>') {
273 input(); yylval.i = APPEND; RET(APPEND);
274 } else {
275 yylval.i = GT; RET(GT);
276 }
277 case '+':
278 if (peek() == '+') {
279 input(); yylval.i = INCR; RET(INCR);
280 } else if (peek() == '=') {
281 input(); yylval.i = ADDEQ; RET(ASGNOP);
282 } else
283 RET('+');
284 case '-':
285 if (peek() == '-') {
286 input(); yylval.i = DECR; RET(DECR);
287 } else if (peek() == '=') {
288 input(); yylval.i = SUBEQ; RET(ASGNOP);
289 } else
290 RET('-');
291 case '*':
292 if (peek() == '=') { /* *= */
293 input(); yylval.i = MULTEQ; RET(ASGNOP);
294 } else if (peek() == '*') { /* ** or **= */
295 input(); /* eat 2nd * */
296 if (peek() == '=') {
297 input(); yylval.i = POWEQ; RET(ASGNOP);
298 } else {
299 RET(POWER);
300 }
301 } else
302 RET('*');
303 case '/':
304 RET('/');
305 case '%':
306 if (peek() == '=') {
307 input(); yylval.i = MODEQ; RET(ASGNOP);
308 } else
309 RET('%');
310 case '^':
311 if (peek() == '=') {
312 input(); yylval.i = POWEQ; RET(ASGNOP);
313 } else
314 RET(POWER);
315
316 case '$':
317 /* BUG: awkward, if not wrong */
318 c = gettok(&buf, &bufsize);
319 if (isalpha(c)) {
320 if (strcmp(buf, "NF") == 0) { /* very special */
321 unputstr("(NF)");
322 RET(INDIRECT);
323 }
324 c = peek();
325 if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) {
326 unputstr(buf);
327 RET(INDIRECT);
328 }
329 yylval.cp = setsymtab(buf, "", 0.0, STR|NUM, symtab);
330 RET(IVAR);
331 } else if (c == 0) { /* */
332 SYNTAX( "unexpected end of input after $" );
333 RET(';');
334 } else {
335 unputstr(buf);
336 RET(INDIRECT);
337 }
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600338
Brian Kernighan87b94932012-12-22 10:35:39 -0500339 case '}':
340 if (--bracecnt < 0)
341 SYNTAX( "extra }" );
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200342 sc = true;
Brian Kernighan87b94932012-12-22 10:35:39 -0500343 RET(';');
344 case ']':
345 if (--brackcnt < 0)
346 SYNTAX( "extra ]" );
347 RET(']');
348 case ')':
349 if (--parencnt < 0)
350 SYNTAX( "extra )" );
351 RET(')');
352 case '{':
353 bracecnt++;
354 RET('{');
355 case '[':
356 brackcnt++;
357 RET('[');
358 case '(':
359 parencnt++;
360 RET('(');
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600361
Brian Kernighan87b94932012-12-22 10:35:39 -0500362 case '"':
363 return string(); /* BUG: should be like tran.c ? */
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600364
Brian Kernighan87b94932012-12-22 10:35:39 -0500365 default:
366 RET(c);
367 }
368 }
369}
370
371int string(void)
372{
373 int c, n;
374 char *s, *bp;
pfg52421942016-06-03 21:23:11 +0000375 static char *buf = NULL;
Brian Kernighan87b94932012-12-22 10:35:39 -0500376 static int bufsz = 500;
377
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300378 if (buf == NULL && (buf = (char *) malloc(bufsz)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500379 FATAL("out of space for strings");
380 for (bp = buf; (c = input()) != '"'; ) {
381 if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, "string"))
382 FATAL("out of space for string %.10s...", buf);
383 switch (c) {
384 case '\n':
385 case '\r':
386 case 0:
Cody Peter Mello6fe0a042018-09-21 11:16:27 -0700387 *bp = '\0';
Brian Kernighan87b94932012-12-22 10:35:39 -0500388 SYNTAX( "non-terminated string %.10s...", buf );
Brian Kernighan87b94932012-12-22 10:35:39 -0500389 if (c == 0) /* hopeless */
390 FATAL( "giving up" );
Cody Peter Mello6fe0a042018-09-21 11:16:27 -0700391 lineno++;
Brian Kernighan87b94932012-12-22 10:35:39 -0500392 break;
393 case '\\':
394 c = input();
395 switch (c) {
zoulascffee7782020-02-28 06:23:54 -0500396 case '\n': break;
Brian Kernighan87b94932012-12-22 10:35:39 -0500397 case '"': *bp++ = '"'; break;
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600398 case 'n': *bp++ = '\n'; break;
Brian Kernighan87b94932012-12-22 10:35:39 -0500399 case 't': *bp++ = '\t'; break;
400 case 'f': *bp++ = '\f'; break;
401 case 'r': *bp++ = '\r'; break;
402 case 'b': *bp++ = '\b'; break;
403 case 'v': *bp++ = '\v'; break;
Arnold D. Robbins944989b2020-01-06 00:01:46 -0700404 case 'a': *bp++ = '\a'; break;
Brian Kernighan87b94932012-12-22 10:35:39 -0500405 case '\\': *bp++ = '\\'; break;
406
407 case '0': case '1': case '2': /* octal: \d \dd \ddd */
408 case '3': case '4': case '5': case '6': case '7':
409 n = c - '0';
410 if ((c = peek()) >= '0' && c < '8') {
411 n = 8 * n + input() - '0';
412 if ((c = peek()) >= '0' && c < '8')
413 n = 8 * n + input() - '0';
414 }
415 *bp++ = n;
416 break;
417
418 case 'x': /* hex \x0-9a-fA-F + */
419 { char xbuf[100], *px;
420 for (px = xbuf; (c = input()) != 0 && px-xbuf < 100-2; ) {
421 if (isdigit(c)
422 || (c >= 'a' && c <= 'f')
423 || (c >= 'A' && c <= 'F'))
424 *px++ = c;
425 else
426 break;
427 }
428 *px = 0;
429 unput(c);
430 sscanf(xbuf, "%x", (unsigned int *) &n);
431 *bp++ = n;
432 break;
433 }
434
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600435 default:
Brian Kernighan87b94932012-12-22 10:35:39 -0500436 *bp++ = c;
437 break;
438 }
439 break;
440 default:
441 *bp++ = c;
442 break;
443 }
444 }
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600445 *bp = 0;
Brian Kernighan87b94932012-12-22 10:35:39 -0500446 s = tostring(buf);
Arnold D. Robbinsc7eeb572020-01-05 21:18:36 +0200447 *bp++ = ' '; *bp++ = '\0';
Brian Kernighan87b94932012-12-22 10:35:39 -0500448 yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab);
Arnold D. Robbinsc7eeb572020-01-05 21:18:36 +0200449 free(s);
Brian Kernighan87b94932012-12-22 10:35:39 -0500450 RET(STRING);
451}
452
453
zoulasc6a877092020-01-24 04:11:59 -0500454static int binsearch(char *w, const Keyword *kp, int n)
Brian Kernighan87b94932012-12-22 10:35:39 -0500455{
456 int cond, low, mid, high;
457
458 low = 0;
459 high = n - 1;
460 while (low <= high) {
461 mid = (low + high) / 2;
462 if ((cond = strcmp(w, kp[mid].word)) < 0)
463 high = mid - 1;
464 else if (cond > 0)
465 low = mid + 1;
466 else
467 return mid;
468 }
469 return -1;
470}
471
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600472int word(char *w)
Brian Kernighan87b94932012-12-22 10:35:39 -0500473{
zoulasc6a877092020-01-24 04:11:59 -0500474 const Keyword *kp;
Brian Kernighan87b94932012-12-22 10:35:39 -0500475 int c, n;
476
477 n = binsearch(w, keywords, sizeof(keywords)/sizeof(keywords[0]));
Brian Kernighan87b94932012-12-22 10:35:39 -0500478 if (n != -1) { /* found in table */
Alexander Richardsonad9bd2f2019-09-10 07:54:53 +0100479 kp = keywords + n;
Brian Kernighan87b94932012-12-22 10:35:39 -0500480 yylval.i = kp->sub;
481 switch (kp->type) { /* special handling */
482 case BLTIN:
483 if (kp->sub == FSYSTEM && safe)
484 SYNTAX( "system is unsafe" );
485 RET(kp->type);
486 case FUNC:
487 if (infunc)
488 SYNTAX( "illegal nested function" );
489 RET(kp->type);
490 case RETURN:
491 if (!infunc)
492 SYNTAX( "return not in function" );
493 RET(kp->type);
494 case VARNF:
495 yylval.cp = setsymtab("NF", "", 0.0, NUM, symtab);
496 RET(VARNF);
497 default:
498 RET(kp->type);
499 }
500 }
501 c = peek(); /* look for '(' */
502 if (c != '(' && infunc && (n=isarg(w)) >= 0) {
503 yylval.i = n;
504 RET(ARG);
505 } else {
506 yylval.cp = setsymtab(w, "", 0.0, STR|NUM|DONTFREE, symtab);
507 if (c == '(') {
508 RET(CALL);
509 } else {
510 RET(VAR);
511 }
512 }
513}
514
515void startreg(void) /* next call to yylex will return a regular expression */
516{
Arnold D. Robbins108224b2019-11-10 21:19:18 +0200517 reg = true;
Brian Kernighan87b94932012-12-22 10:35:39 -0500518}
519
520int regexpr(void)
521{
522 int c;
pfg52421942016-06-03 21:23:11 +0000523 static char *buf = NULL;
Brian Kernighan87b94932012-12-22 10:35:39 -0500524 static int bufsz = 500;
525 char *bp;
526
Arnold D. Robbins3b42cfa2020-10-13 20:52:43 +0300527 if (buf == NULL && (buf = (char *) malloc(bufsz)) == NULL)
Brian Kernighan87b94932012-12-22 10:35:39 -0500528 FATAL("out of space for rex expr");
529 bp = buf;
530 for ( ; (c = input()) != '/' && c != 0; ) {
531 if (!adjbuf(&buf, &bufsz, bp-buf+3, 500, &bp, "regexpr"))
532 FATAL("out of space for reg expr %.10s...", buf);
533 if (c == '\n') {
Cody Peter Mello6fe0a042018-09-21 11:16:27 -0700534 *bp = '\0';
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600535 SYNTAX( "newline in regular expression %.10s...", buf );
Brian Kernighan87b94932012-12-22 10:35:39 -0500536 unput('\n');
537 break;
538 } else if (c == '\\') {
Arnold D. Robbins795a06b2019-07-28 05:51:52 -0600539 *bp++ = '\\';
Brian Kernighan87b94932012-12-22 10:35:39 -0500540 *bp++ = input();
541 } else {
542 *bp++ = c;
543 }
544 }
545 *bp = 0;
546 if (c == 0)
547 SYNTAX("non-terminated regular expression %.10s...", buf);
548 yylval.s = tostring(buf);
549 unput('/');
550 RET(REGEXPR);
551}
552
553/* low-level lexical stuff, sort of inherited from lex */
554
555char ebuf[300];
556char *ep = ebuf;
557char yysbuf[100]; /* pushback buffer */
558char *yysptr = yysbuf;
pfg52421942016-06-03 21:23:11 +0000559FILE *yyin = NULL;
Brian Kernighan87b94932012-12-22 10:35:39 -0500560
561int input(void) /* get next lexical input character */
562{
563 int c;
564 extern char *lexprog;
565
566 if (yysptr > yysbuf)
567 c = (uschar)*--yysptr;
568 else if (lexprog != NULL) { /* awk '...' */
569 if ((c = (uschar)*lexprog) != 0)
570 lexprog++;
571 } else /* awk -f ... */
572 c = pgetc();
Cody Peter Mello6fe0a042018-09-21 11:16:27 -0700573 if (c == EOF)
Brian Kernighan87b94932012-12-22 10:35:39 -0500574 c = 0;
575 if (ep >= ebuf + sizeof ebuf)
576 ep = ebuf;
Cody Peter Mello6fe0a042018-09-21 11:16:27 -0700577 *ep = c;
578 if (c != 0) {
579 ep++;
580 }
581 return (c);
Brian Kernighan87b94932012-12-22 10:35:39 -0500582}
583
584void unput(int c) /* put lexical character back on input */
585{
zoulasc6a877092020-01-24 04:11:59 -0500586 if (c == '\n')
587 lineno--;
Brian Kernighan87b94932012-12-22 10:35:39 -0500588 if (yysptr >= yysbuf + sizeof(yysbuf))
589 FATAL("pushed back too much: %.20s...", yysbuf);
590 *yysptr++ = c;
591 if (--ep < ebuf)
592 ep = ebuf + sizeof(ebuf) - 1;
593}
594
595void unputstr(const char *s) /* put a string back on input */
596{
597 int i;
598
599 for (i = strlen(s)-1; i >= 0; i--)
600 unput(s[i]);
601}