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