xref: /illumos-gate/usr/src/cmd/bc/bc.y (revision b390fe2c)
1 %{
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License, Version 1.0 only
7  * (the "License").  You may not use this file except in compliance
8  * with the License.
9  *
10  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11  * or http://www.opensolaris.org/os/licensing.
12  * See the License for the specific language governing permissions
13  * and limitations under the License.
14  *
15  * When distributing Covered Code, include this CDDL HEADER in each
16  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17  * If applicable, add the following below this CDDL HEADER, with the
18  * fields enclosed by brackets "[]" replaced with your own identifying
19  * information: Portions Copyright [yyyy] [name of copyright owner]
20  *
21  * CDDL HEADER END
22  */
23 %}
24 /*
25  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 
29 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
30 /*	  All Rights Reserved  	*/
31 
32 %{
33 #pragma ident	"%Z%%M%	%I%	%E% SMI"
34 %}
35 %{
36 #include <stdio.h>
37 #include <stdarg.h>
38 #include <limits.h>
39 #include <libintl.h>
40 #include <locale.h>
41 #include <signal.h>
42 
43 static void getout(int)	__NORETURN;
44 static int *bundle(int, ...);
45 static void usage(void);
46 
47 int	cpeek(char, int, char, int, char);
48 void	yyerror(char *);
49 
50 %}
51 %union {
52 	int *iptr;
53 	char *cptr;
54 	int cc;
55 	}
56 %start start;
57 %type <iptr> stat, def, slist, dlets, e
58 %type <iptr> slist, re, fprefix, cargs, eora, cons, constant, lora
59 %right '='
60 %left '+' '-'
61 %left '*' '/' '%'
62 %right '^'
63 %left UMINUS
64 
65 %token <cptr> LETTER
66 %type <cptr> EQOP, CRS
67 %token <cc> DIGIT, SQRT, LENGTH, _IF, FFF, EQ
68 %token <cc> _WHILE _FOR NE LE GE INCR DECR
69 %token <cc> _RETURN _BREAK _DEFINE BASE OBASE SCALE
70 %token <cc> EQPL EQMI EQMUL EQDIV EQREM EQEXP
71 %token <cptr> _AUTO DOT
72 %token <cc> QSTR
73 
74 %{
75 #define	STRING_SIZE	(BC_STRING_MAX + 3)	/* string plus quotes */
76 						/* plus NULL */
77 
78 FILE	*in;
79 char	cary[LINE_MAX+1];
80 char	*cp = { cary };
81 char	*cpend = &cary[LINE_MAX];	/* last address (not the null char) */
82 char	string[STRING_SIZE];
83 char	*str = { string };
84 int	crs = '0';
85 int	rcrs = '0';		/* reset crs */
86 int	bindx = 0;
87 int	lev = 0;			/* current scope level */
88 int	ln;				/* line number of current file */
89 int	*ttp;
90 char	*ss;				/* current input source */
91 int	bstack[10] = { 0 };
92 char	*numb[15] = {
93 	" 0", " 1", " 2", " 3", " 4", " 5",
94 	" 6", " 7", " 8", " 9", " 10", " 11",
95 	" 12", " 13", " 14"
96 };
97 int	*pre, *post;
98 int	interact = 0;			/* talking to a tty? */
99 %}
100 %%
101 start	:
102 	| start stat tail
103 		= {
104 			output($2);
105 		}
106 	| start def dargs ')' '{' dlist slist '}'
107 		= {
108 			ttp = bundle(6, pre, $7, post, "0", numb[lev], "Q");
109 			conout(ttp, (char *)$2);
110 			rcrs = crs;
111 			output((int *)"");
112 			lev = bindx = 0;
113 		}
114 	;
115 
116 dlist	: tail
117 	| dlist _AUTO dlets tail
118 	;
119 
120 stat	: e
121 		= bundle(2, $1, "ps.");
122 	|
123 		= bundle(1, "");
124 	| QSTR
125 		= bundle(3, "[", $1, "]P");
126 	| LETTER '=' e
127 		= bundle(3, $3, "s", $1);
128 	| LETTER '[' e ']' '=' e
129 		= bundle(4, $6, $3, ":", geta($1));
130 	| LETTER EQOP e
131 		= bundle(6, "l", $1, $3, $2, "s", $1);
132 	| LETTER '[' e ']' EQOP e
133 		= bundle(8, $3, ";", geta($1), $6, $5, $3, ":", geta($1));
134 	| _BREAK
135 		= bundle(2, numb[lev-bstack[bindx-1]], "Q");
136 	| _RETURN '(' e ')'
137 		= bundle(4, $3, post, numb[lev], "Q");
138 	| _RETURN '(' ')'
139 		= bundle(4, "0", post, numb[lev], "Q");
140 	| _RETURN
141 		= bundle(4, "0", post, numb[lev], "Q");
142 	| SCALE '=' e
143 		= bundle(2, $3, "k");
144 	| SCALE EQOP e
145 		= bundle(4, "K", $3, $2, "k");
146 	| BASE '=' e
147 		= bundle(2, $3, "i");
148 	| BASE EQOP e
149 		= bundle(4, "I", $3, $2, "i");
150 	| OBASE '=' e
151 		= bundle(2, $3, "o");
152 	| OBASE EQOP e
153 		= bundle(4, "O", $3, $2, "o");
154 	| '{' slist '}'
155 		= {
156 			$$ = $2;
157 		}
158 	| FFF
159 		= bundle(1, "fY");
160 	| error
161 		= bundle(1, "c");
162 	| _IF CRS BLEV '(' re ')' stat
163 		= {
164 			conout($7, $2);
165 			bundle(3, $5, $2, " ");
166 		}
167 	| _WHILE CRS '(' re ')' stat BLEV
168 		= {
169 			bundle(3, $6, $4, $2);
170 			conout($$, $2);
171 			bundle(3, $4, $2, " ");
172 		}
173 	| fprefix CRS re ';' e ')' stat BLEV
174 		= {
175 			bundle(5, $7, $5, "s.", $3, $2);
176 			conout($$, $2);
177 			bundle(5, $1, "s.", $3, $2, " ");
178 		}
179 	| '~' LETTER '=' e
180 		= bundle(3, $4, "S", $2);
181 	;
182 
183 EQOP	: EQPL
184 		= {
185 			$$ = "+";
186 		}
187 	| EQMI
188 		= {
189 			$$ = "-";
190 		}
191 	| EQMUL
192 		= {
193 			$$ = "*";
194 		}
195 	| EQDIV
196 		= {
197 			$$ = "/";
198 		}
199 	| EQREM
200 		= {
201 			$$ = "%%";
202 		}
203 	| EQEXP
204 		= {
205 			$$ = "^";
206 		}
207 	;
208 
209 fprefix	: _FOR '(' e ';'
210 		= {
211 			$$ = $3;
212 		}
213 	;
214 
215 BLEV	:
216 		= --bindx;
217 	;
218 
219 slist	: stat
220 	| slist tail stat
221 		= bundle(2, $1, $3);
222 	;
223 
224 tail	: '\n'
225 		= {
226 			ln++;
227 		}
228 	| ';'
229 	;
230 
231 re	: e EQ e
232 		= {
233 			$$ = bundle(3, $1, $3, "=");
234 		}
235 	| e '<' e
236 		= bundle(3, $1, $3, ">");
237 	| e '>' e
238 		= bundle(3, $1, $3, "<");
239 	| e NE e
240 		= bundle(3, $1, $3, "!=");
241 	| e GE e
242 		= bundle(3, $1, $3, "!>");
243 	| e LE e
244 		= bundle(3, $1, $3, "!<");
245 	| e
246 		= bundle(2, $1, " 0!=");
247 	;
248 
249 e	: e '+' e
250 		= bundle(3, $1, $3, "+");
251 	| e '-' e
252 		= bundle(3, $1, $3, "-");
253 	| '-' e		%prec UMINUS
254 		= bundle(3, " 0", $2, "-");
255 	| e '*' e
256 		= bundle(3, $1, $3, "*");
257 	| e '/' e
258 		= bundle(3, $1, $3, "/");
259 	| e '%' e
260 		= bundle(3, $1, $3, "%%");
261 	| e '^' e
262 		= bundle(3, $1, $3, "^");
263 	| LETTER '[' e ']'
264 		= bundle(3, $3, ";", geta($1));
265 	| LETTER INCR
266 		= bundle(4, "l", $1, "d1+s", $1);
267 	| INCR LETTER
268 		= bundle(4, "l", $2, "1+ds", $2);
269 	| DECR LETTER
270 		= bundle(4, "l", $2, "1-ds", $2);
271 	| LETTER DECR
272 		= bundle(4, "l", $1, "d1-s", $1);
273 	| LETTER '[' e ']' INCR
274 		= bundle(7, $3, ";", geta($1), "d1+", $3, ":", geta($1));
275 	| INCR LETTER '[' e ']'
276 		= bundle(7, $4, ";", geta($2), "1+d", $4, ":", geta($2));
277 	| LETTER '[' e ']' DECR
278 		= bundle(7, $3, ";", geta($1), "d1-", $3, ":", geta($1));
279 	| DECR LETTER '[' e ']'
280 		= bundle(7, $4, ";", geta($2), "1-d", $4, ":", geta($2));
281 	| SCALE INCR
282 		= bundle(1, "Kd1+k");
283 	| INCR SCALE
284 		= bundle(1, "K1+dk");
285 	| SCALE DECR
286 		= bundle(1, "Kd1-k");
287 	| DECR SCALE
288 		= bundle(1, "K1-dk");
289 	| BASE INCR
290 		= bundle(1, "Id1+i");
291 	| INCR BASE
292 		= bundle(1, "I1+di");
293 	| BASE DECR
294 		= bundle(1, "Id1-i");
295 	| DECR BASE
296 		= bundle(1, "I1-di");
297 	| OBASE INCR
298 		= bundle(1, "Od1+o");
299 	| INCR OBASE
300 		= bundle(1, "O1+do");
301 	| OBASE DECR
302 		= bundle(1, "Od1-o");
303 	| DECR OBASE
304 		= bundle(1, "O1-do");
305 	| LETTER '(' cargs ')'
306 		= bundle(4, $3, "l", getf($1), "x");
307 	| LETTER '(' ')'
308 		= bundle(3, "l", getf($1), "x");
309 	| cons
310 		= bundle(2, " ", $1);
311 	| DOT cons
312 		= bundle(2, " .", $2);
313 	| cons DOT cons
314 		= bundle(4, " ", $1, ".", $3);
315 	| cons DOT
316 		= bundle(3, " ", $1, ".");
317 	| DOT
318 		= {
319 			$<cptr>$ = "l.";
320 		}
321 	| LETTER
322 		= bundle(2, "l", $1);
323 	| LETTER '=' e
324 		= bundle(3, $3, "ds", $1);
325 	| LETTER EQOP e		%prec '='
326 		= bundle(6, "l", $1, $3, $2, "ds", $1);
327 	| LETTER '[' e ']' '=' e
328 		= bundle(5, $6, "d", $3, ":", geta($1));
329 	| LETTER '[' e ']' EQOP e
330 		= {
331 			bundle(9, $3, ";", geta($1), $6, $5, "d", $3, ":",
332 			    geta($1));
333 		}
334 	| LENGTH '(' e ')'
335 		= bundle(2, $3, "Z");
336 	| SCALE '(' e ')'
337 		= bundle(2, $3, "X");	/* must be before '(' e ')' */
338 	| '(' e ')'
339 		= {
340 			$$ = $2;
341 		}
342 	| '?'
343 		= bundle(1, "?");
344 	| SQRT '(' e ')'
345 		= bundle(2, $3, "v");
346 	| '~' LETTER
347 		= bundle(2, "L", $2);
348 	| SCALE '=' e
349 		= bundle(2, $3, "dk");
350 	| SCALE EQOP e		%prec '='
351 		= bundle(4, "K", $3, $2, "dk");
352 	| BASE '=' e
353 		= bundle(2, $3, "di");
354 	| BASE EQOP e		%prec '='
355 		= bundle(4, "I", $3, $2, "di");
356 	| OBASE '=' e
357 		= bundle(2, $3, "do");
358 	| OBASE EQOP e		%prec '='
359 		= bundle(4, "O", $3, $2, "do");
360 	| SCALE
361 		= bundle(1, "K");
362 	| BASE
363 		= bundle(1, "I");
364 	| OBASE
365 		= bundle(1, "O");
366 	;
367 
368 cargs	: eora
369 	| cargs ',' eora
370 		= bundle(2, $1, $3);
371 	;
372 eora	: e
373 	| LETTER '[' ']'
374 		= bundle(2, "l", geta($1));
375 	;
376 
377 cons	: constant
378 		= {
379 			*cp++ = '\0';
380 		}
381 
382 constant: '_'
383 		= {
384 			checkbuffer();
385 			$<cptr>$ = cp;
386 			*cp++ = '_';
387 		}
388 	| DIGIT
389 		= {
390 			checkbuffer();
391 			$<cptr>$ = cp;
392 			*cp++ = $1;
393 		}
394 	| constant DIGIT
395 		= {
396 			checkbuffer();
397 			*cp++ = $2;
398 		}
399 	;
400 
401 CRS	:
402 		= {
403 			checkbuffer();
404 			$$ = cp;
405 			*cp++ = crs++;
406 			*cp++ = '\0';
407 			if (crs == '[')
408 				crs += 3;
409 			if (crs == 'a')
410 				crs = '{';
411 			if (crs >= 0241) {
412 				yyerror("program too big");
413 				getout(1);
414 			}
415 			bstack[bindx++] = lev++;
416 		}
417 	;
418 
419 def	: _DEFINE LETTER '('
420 		= {
421 			$$ = getf($2);
422 			pre = (int *)"";
423 			post = (int *)"";
424 			lev = 1;
425 			bstack[bindx = 0] = 0;
426 		}
427 	;
428 
429 dargs	:		/* empty */
430 	| lora
431 		= {
432 			pp($1);
433 		}
434 	| dargs ',' lora
435 		= {
436 			pp($3);
437 		}
438 	;
439 
440 dlets	: lora
441 		= tp($1);
442 	| dlets ',' lora
443 		= tp($3);
444 	;
445 
446 lora	: LETTER
447 		= {
448 			$<cptr>$ = $1;
449 		}
450 	| LETTER '[' ']'
451 		= {
452 			$$ = geta($1);
453 		}
454 	;
455 
456 %%
457 #define	error	256
458 
459 int	peekc = -1;
460 int	ifile;			/* current index into sargv */
461 int	sargc;			/* size of sargv[] */
462 char	**sargv;		/* saved arg list without options */
463 
464 char funtab[52] = {
465 	01, 0, 02, 0, 03, 0, 04, 0, 05, 0, 06, 0, 07, 0,
466 	010, 0, 011, 0, 012, 0, 013, 0, 014, 0, 015, 0, 016, 0, 017, 0,
467 	020, 0, 021, 0, 022, 0, 023, 0, 024, 0, 025, 0, 026, 0, 027, 0,
468 	030, 0, 031, 0, 032, 0
469 };
470 
471 unsigned char atab[52] = {
472 	0241, 0, 0242, 0, 0243, 0, 0244, 0, 0245, 0, 0246, 0, 0247, 0, 0250, 0,
473 	0251, 0, 0252, 0, 0253, 0, 0254, 0, 0255, 0, 0256, 0, 0257, 0, 0260, 0,
474 	0261, 0, 0262, 0, 0263, 0, 0264, 0, 0265, 0, 0266, 0, 0267, 0, 0270, 0,
475 	0271, 0, 0272, 0
476 };
477 
478 char *letr[26] = {
479 	"a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
480 	"k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
481 	"u", "v", "w", "x", "y", "z"
482 };
483 
484 int
485 yylex(void)
486 {
487 	int c, ch;
488 
489 restart:
490 	c = getch();
491 	peekc = -1;
492 	while (c == ' ' || c == '\t')
493 		c = getch();
494 	if (c == '\\') {
495 		(void) getch();
496 		goto restart;
497 	}
498 	if (c <= 'z' && c >= 'a') {
499 		/* look ahead to look for reserved words */
500 		peekc = getch();
501 		if (peekc >= 'a' && peekc <= 'z') {
502 			/* must be reserved word */
503 			if (c == 'i' && peekc == 'f') {
504 				c = _IF;
505 				goto skip;
506 			}
507 			if (c == 'w' && peekc == 'h') {
508 				c = _WHILE;
509 				goto skip;
510 			}
511 			if (c == 'f' && peekc == 'o') {
512 				c = _FOR;
513 				goto skip;
514 			}
515 			if (c == 's' && peekc == 'q') {
516 				c = SQRT;
517 				goto skip;
518 			}
519 			if (c == 'r' && peekc == 'e') {
520 				c = _RETURN;
521 				goto skip;
522 			}
523 			if (c == 'b' && peekc == 'r') {
524 				c = _BREAK;
525 				goto skip;
526 			}
527 			if (c == 'd' && peekc == 'e') {
528 				c = _DEFINE;
529 				goto skip;
530 			}
531 			if (c == 's' && peekc == 'c') {
532 				c = SCALE;
533 				goto skip;
534 			}
535 			if (c == 'b' && peekc == 'a') {
536 				c = BASE;
537 				goto skip;
538 			}
539 			if (c == 'i' && peekc == 'b') {
540 				c = BASE;
541 				goto skip;
542 			}
543 			if (c == 'o' && peekc == 'b') {
544 				c = OBASE;
545 				goto skip;
546 			}
547 			if (c == 'd' && peekc == 'i') {
548 				c = FFF;
549 				goto skip;
550 			}
551 			if (c == 'a' && peekc == 'u') {
552 				c = _AUTO;
553 				goto skip;
554 			}
555 			if (c == 'l' && peekc == 'e') {
556 				c = LENGTH;
557 				goto skip;
558 			}
559 			if (c == 'q' && peekc == 'u') {
560 				getout(0);
561 			}
562 			/* could not be found */
563 			return (error);
564 
565 skip:	/* skip over rest of word */
566 			peekc = -1;
567 			while ((ch = getch()) >= 'a' && ch <= 'z')
568 				;
569 			peekc = ch;
570 			return (c);
571 		}
572 
573 		/* usual case; just one single letter */
574 
575 		yylval.cptr = letr[c-'a'];
576 		return (LETTER);
577 	}
578 
579 	if (c >= '0' && c <= '9' || c >= 'A' && c <= 'F') {
580 		yylval.cc = c;
581 		return (DIGIT);
582 	}
583 
584 	switch (c) {
585 	case '.':
586 		return (DOT);
587 
588 	case '=':
589 		switch ((peekc = getch())) {
590 		case '=':
591 			c = EQ;
592 			goto gotit;
593 
594 		case '+':
595 			c = EQPL;
596 			goto gotit;
597 
598 		case '-':
599 			c = EQMI;
600 			goto gotit;
601 
602 		case '*':
603 			c = EQMUL;
604 			goto gotit;
605 
606 		case '/':
607 			c = EQDIV;
608 			goto gotit;
609 
610 		case '%':
611 			c = EQREM;
612 			goto gotit;
613 
614 		case '^':
615 			c = EQEXP;
616 			goto gotit;
617 
618 		default:
619 			return ('=');
620 gotit:
621 			peekc = -1;
622 			return (c);
623 		}
624 
625 	case '+':
626 		return (cpeek('+', INCR, '=', EQPL, '+'));
627 
628 	case '-':
629 		return (cpeek('-', DECR, '=', EQMI, '-'));
630 
631 	case '*':
632 		return (cpeek('=', EQMUL, '\0', 0, '*'));
633 
634 	case '%':
635 		return (cpeek('=', EQREM, '\0', 0, '%'));
636 
637 	case '^':
638 		return (cpeek('=', EQEXP, '\0', 0, '^'));
639 
640 	case '<':
641 		return (cpeek('=', LE, '\0', 0, '<'));
642 
643 	case '>':
644 		return (cpeek('=', GE, '\0', 0, '>'));
645 
646 	case '!':
647 		return (cpeek('=', NE, '\0', 0, '!'));
648 
649 	case '/':
650 		if ((peekc = getch()) == '=') {
651 			peekc = -1;
652 			return (EQDIV);
653 		}
654 		if (peekc == '*') {
655 			peekc = -1;
656 			while ((getch() != '*') || ((peekc = getch()) != '/'))
657 				;
658 			peekc = -1;
659 			goto restart;
660 		}
661 		else
662 			return (c);
663 
664 	case '"':
665 		yylval.cptr = str;
666 		while ((c = getch()) != '"') {
667 			*str++ = c;
668 			if (str >= &string[STRING_SIZE-1]) {
669 				yyerror("string space exceeded");
670 				getout(1);
671 			}
672 		}
673 		*str++ = '\0';
674 		return (QSTR);
675 
676 	default:
677 		return (c);
678 	}
679 }
680 
681 int
682 cpeek(char c1, int yes1, char c2, int yes2, char none)
683 {
684 	int r;
685 
686 	peekc = getch();
687 	if (peekc == c1)
688 		r = yes1;
689 	else if (peekc == c2)
690 		r = yes2;
691 	else
692 		return (none);
693 	peekc = -1;
694 	return (r);
695 }
696 
697 
698 int
699 getch(void)
700 {
701 	int ch;
702 	char mbuf[LINE_MAX];
703 
704 loop:
705 	ch = (peekc < 0) ? getc(in) : peekc;
706 	peekc = -1;
707 	if (ch != EOF)
708 		return (ch);
709 
710 	if (++ifile >= sargc) {
711 		if (ifile >= sargc+1)
712 			getout(0);
713 		in = stdin;
714 		ln = 0;
715 		goto loop;
716 	}
717 
718 	(void) fclose(in);
719 	if ((in = fopen(sargv[ifile], "r")) != NULL) {
720 		ln = 0;
721 		ss = sargv[ifile];
722 		goto loop;
723 	}
724 	(void) snprintf(mbuf, sizeof (mbuf), "can't open input file %s",
725 		sargv[ifile]);
726 	ln = -1;
727 	ss = "command line";
728 	yyerror(mbuf);
729 	getout(1);
730 	/*NOTREACHED*/
731 }
732 
733 #define	b_sp_max	5000
734 int b_space[b_sp_max];
735 int *b_sp_nxt = { b_space };
736 
737 int	bdebug = 0;
738 
739 static int *
740 bundle(int i, ...)
741 {
742 	va_list ap;
743 	int *q;
744 
745 	va_start(ap, i);
746 	q = b_sp_nxt;
747 	if (bdebug)
748 		printf("bundle %d elements at %o\n", i, q);
749 	while (i-- > 0) {
750 		if (b_sp_nxt >= & b_space[b_sp_max])
751 			yyerror("bundling space exceeded");
752 		*b_sp_nxt++ = va_arg(ap, int);
753 	}
754 	* b_sp_nxt++ = 0;
755 	yyval.iptr = q;
756 	va_end(ap);
757 	return (q);
758 }
759 
760 void
761 routput(int *p)
762 {
763 	if (bdebug) printf("routput(%o)\n", p);
764 	if (p >= &b_space[0] && p < &b_space[b_sp_max]) {
765 		/* part of a bundle */
766 		while (*p != 0)
767 			routput((int *)*p++);
768 	}
769 	else
770 		printf((char *)p);	 /* character string */
771 }
772 
773 void
774 output(int *p)
775 {
776 	routput(p);
777 	b_sp_nxt = & b_space[0];
778 	printf("\n");
779 	(void) fflush(stdout);
780 	cp = cary;
781 	crs = rcrs;
782 }
783 
784 void
785 conout(int *p, char *s)
786 {
787 	printf("[");
788 	routput(p);
789 	printf("]s%s\n", s);
790 	(void) fflush(stdout);
791 	lev--;
792 }
793 
794 void
795 yyerror(char *s)
796 {
797 	if (ifile >= sargc)
798 		ss = "teletype";
799 
800 	if (ss == 0 || *ss == 0)
801 		(void) fprintf(stderr, gettext("%s on line %d\n"), s, ln+1);
802 	else
803 		(void) fprintf(stderr, gettext("%s on line %d, %s\n"),
804 		    s, ln+1, ss);
805 	(void) fflush(stderr);
806 
807 	cp = cary;
808 	crs = rcrs;
809 	bindx = 0;
810 	lev = 0;
811 	b_sp_nxt = &b_space[0];
812 }
813 
814 void
815 checkbuffer(void)
816 {
817 	/* Do not exceed the last char in input line buffer */
818 	if (cp >= cpend) {
819 		yyerror("line too long\n");
820 		getout(1);
821 	}
822 }
823 
824 void
825 pp(int *s)
826 {
827 	/* puts the relevant stuff on pre and post for the letter s */
828 
829 	(void) bundle(3, "S", s, pre);
830 	pre = yyval.iptr;
831 	(void) bundle(4, post, "L", s, "s.");
832 	post = yyval.iptr;
833 }
834 
835 void
836 tp(int *s)
837 {		/* same as pp, but for temps */
838 	bundle(3, "0S", s, pre);
839 	pre = yyval.iptr;
840 	bundle(4, post, "L", s, "s.");
841 	post = yyval.iptr;
842 }
843 
844 void
845 yyinit(int argc, char **argv)
846 {
847 	char	mbuf[LINE_MAX];
848 
849 	(void) signal(SIGINT, SIG_IGN);		/* ignore all interrupts */
850 
851 	sargv = argv;
852 	sargc = argc;
853 	if (sargc == 0)
854 		in = stdin;
855 	else if ((in = fopen(sargv[0], "r")) == NULL) {
856 		(void) snprintf(mbuf, sizeof (mbuf), "can't open input file %s",
857 			sargv[0]);
858 		ln = -1;
859 		ss = "command line";
860 		yyerror(mbuf);
861 		getout(1);
862 	}
863 	ifile = 0;
864 	ln = 0;
865 	ss = sargv[0];
866 }
867 
868 static void
869 getout(int code)
870 {
871 	printf("q");
872 	(void) fflush(stdout);
873 	exit(code);
874 }
875 
876 int *
877 getf(char *p)
878 {
879 	return ((int *) &funtab[2*(*p -0141)]);
880 }
881 
882 int *
883 geta(char *p)
884 {
885 	return ((int *) &atab[2*(*p - 0141)]);
886 }
887 
888 int
889 main(int argc, char **argv)
890 {
891 	int	p[2];
892 	int	cflag = 0;
893 	int	lflag = 0;
894 	int	flag = 0;
895 	char	**av;
896 	int 	filecounter = 0;
897 
898 	(void) setlocale(LC_ALL, "");
899 #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
900 #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
901 #endif
902 	(void) textdomain(TEXT_DOMAIN);
903 
904 	while ((flag = getopt(argc, argv, "dcl")) != EOF) {
905 		switch (flag) {
906 		case 'd':
907 		case 'c':
908 			cflag++;
909 			break;
910 
911 		case 'l':
912 			lflag++;
913 			break;
914 
915 		default:
916 			fflush(stdout);
917 			usage();
918 			break;
919 		}
920 	}
921 
922 	argc -= optind;
923 	av = &argv[optind];
924 
925 	/*
926 	* argc is the count of arguments, which should be filenames,
927 	* remaining in argv. av is a pointer to the first of the
928 	* remaining arguments.
929 	*/
930 
931 	for (filecounter = 0; filecounter < argc; filecounter++) {
932 		if ((strlen(av[filecounter])) >= PATH_MAX) {
933 			(void) fprintf(stderr,
934 			    gettext("File argument too long\n"));
935 			exit(2);
936 		}
937 	}
938 
939 	if (lflag) {
940 		/*
941 		* if the user wants to include the math library, prepend
942 		* the math library filename to the argument list by
943 		* overwriting the last option (there must be at least one
944 		* supplied option if this is being done).
945 		*/
946 		av = &argv[optind-1];
947 		av[0] = "/usr/lib/lib.b";
948 		argc++;
949 	}
950 
951 	if (cflag) {
952 		yyinit(argc, av);
953 		yyparse();
954 		exit(0);
955 	}
956 
957 	pipe(p);
958 	if (fork() == 0) {
959 		(void) close(1);
960 		dup(p[1]);
961 		(void) close(p[0]);
962 		(void) close(p[1]);
963 		yyinit(argc, av);
964 		yyparse();
965 		exit(0);
966 	}
967 	(void) close(0);
968 	dup(p[0]);
969 	(void) close(p[0]);
970 	(void) close(p[1]);
971 #ifdef XPG6
972 	execl("/usr/xpg6/bin/dc", "dc", "-", 0);
973 #else
974 	execl("/usr/bin/dc", "dc", "-", 0);
975 #endif
976 
977 	return (1);
978 }
979 
980 static void
981 usage(void)
982 {
983 	(void) fprintf(stderr, gettext(
984 	    "usage: bc [ -c ] [ -l ] [ file ... ]\n"));
985 	exit(2);
986 }
987