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