xref: /illumos-gate/usr/src/cmd/bc/bc.y (revision 724c5feb)
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 void	yyerror(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 				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
yylex(void)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 				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
cpeek(char c1,int yes1,char c2,int yes2,char none)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
getch(void)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 	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 *
bundle(int i,...)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 			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
routput(int * p)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
output(int * p)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
conout(int * p,char * s)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 void
yyerror(char * s)959 yyerror(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 }
977 
978 void
checkbuffer(void)979 checkbuffer(void)
980 {
981 	/* Do not exceed the last char in input line buffer */
982 	if (cp >= cpend) {
983 		yyerror("line too long\n");
984 		getout(1);
985 	}
986 }
987 
988 void
pp(int * s)989 pp(int *s)
990 {
991 	/* puts the relevant stuff on pre and post for the letter s */
992 
993 	(void) bundle(3, "S", s, pre);
994 	pre = yyval.iptr;
995 	(void) bundle(4, post, "L", s, "s.");
996 	post = yyval.iptr;
997 }
998 
999 void
tp(int * s)1000 tp(int *s)
1001 {		/* same as pp, but for temps */
1002 	bundle(3, "0S", s, pre);
1003 	pre = yyval.iptr;
1004 	bundle(4, post, "L", s, "s.");
1005 	post = yyval.iptr;
1006 }
1007 
1008 void
yyinit(int argc,char ** argv)1009 yyinit(int argc, char **argv)
1010 {
1011 	char	mbuf[LINE_MAX];
1012 
1013 	(void) signal(SIGINT, SIG_IGN);		/* ignore all interrupts */
1014 
1015 	sargv = argv;
1016 	sargc = argc;
1017 	if (sargc == 0)
1018 		in = stdin;
1019 	else if ((in = fopen(sargv[0], "r")) == NULL) {
1020 		(void) snprintf(mbuf, sizeof (mbuf), "can't open input file %s",
1021 			sargv[0]);
1022 		ln = -1;
1023 		ss = "command line";
1024 		yyerror(mbuf);
1025 		getout(1);
1026 	}
1027 	ifile = 0;
1028 	ln = 0;
1029 	ss = sargv[0];
1030 }
1031 
1032 static void
getout(int code)1033 getout(int code)
1034 {
1035 	printf("q");
1036 	(void) fflush(stdout);
1037 	exit(code);
1038 }
1039 
1040 int *
getf(char * p)1041 getf(char *p)
1042 {
1043 	return ((int *) &funtab[2*(*p -0141)]);
1044 }
1045 
1046 int *
geta(char * p)1047 geta(char *p)
1048 {
1049 	return ((int *) &atab[2*(*p - 0141)]);
1050 }
1051 
1052 int
main(int argc,char ** argv)1053 main(int argc, char **argv)
1054 {
1055 	int	p[2];
1056 	int	cflag = 0;
1057 	int	lflag = 0;
1058 	int	flag = 0;
1059 	char	**av;
1060 	int	filecounter = 0;
1061 
1062 	(void) setlocale(LC_ALL, "");
1063 #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
1064 #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
1065 #endif
1066 	(void) textdomain(TEXT_DOMAIN);
1067 
1068 	while ((flag = getopt(argc, argv, "dcl")) != EOF) {
1069 		switch (flag) {
1070 		case 'd':
1071 		case 'c':
1072 			cflag++;
1073 			break;
1074 
1075 		case 'l':
1076 			lflag++;
1077 			break;
1078 
1079 		default:
1080 			fflush(stdout);
1081 			usage();
1082 			break;
1083 		}
1084 	}
1085 
1086 	argc -= optind;
1087 	av = &argv[optind];
1088 
1089 	/*
1090 	* argc is the count of arguments, which should be filenames,
1091 	* remaining in argv. av is a pointer to the first of the
1092 	* remaining arguments.
1093 	*/
1094 
1095 	for (filecounter = 0; filecounter < argc; filecounter++) {
1096 		if ((strlen(av[filecounter])) >= PATH_MAX) {
1097 			(void) fprintf(stderr,
1098 			    gettext("File argument too long\n"));
1099 			exit(2);
1100 		}
1101 	}
1102 
1103 	if (lflag) {
1104 		/*
1105 		* if the user wants to include the math library, prepend
1106 		* the math library filename to the argument list by
1107 		* overwriting the last option (there must be at least one
1108 		* supplied option if this is being done).
1109 		*/
1110 		av = &argv[optind-1];
1111 		av[0] = "/usr/lib/lib.b";
1112 		argc++;
1113 	}
1114 
1115 	if (cflag) {
1116 		yyinit(argc, av);
1117 		yyparse();
1118 		exit(0);
1119 	}
1120 
1121 	pipe(p);
1122 	if (fork() == 0) {
1123 		(void) close(1);
1124 		dup(p[1]);
1125 		(void) close(p[0]);
1126 		(void) close(p[1]);
1127 		yyinit(argc, av);
1128 		yyparse();
1129 		exit(0);
1130 	}
1131 	(void) close(0);
1132 	dup(p[0]);
1133 	(void) close(p[0]);
1134 	(void) close(p[1]);
1135 #ifdef XPG6
1136 	execl("/usr/xpg6/bin/dc", "dc", "-", 0);
1137 #else
1138 	execl("/usr/bin/dc", "dc", "-", 0);
1139 #endif
1140 
1141 	return (1);
1142 }
1143 
1144 static void
usage(void)1145 usage(void)
1146 {
1147 	(void) fprintf(stderr, gettext(
1148 	    "usage: bc [ -c ] [ -l ] [ file ... ]\n"));
1149 	exit(2);
1150 }
1151