xref: /illumos-gate/usr/src/cmd/bc/bc.y (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
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 %}
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, (char *)$2);
107 			rcrs = crs;
108 			output((int *)"");
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 int
482 yylex(void)
483 {
484 	int c, ch;
485 
486 restart:
487 	c = getch();
488 	peekc = -1;
489 	while (c == ' ' || c == '\t')
490 		c = getch();
491 	if (c == '\\') {
492 		(void) getch();
493 		goto restart;
494 	}
495 	if (c <= 'z' && c >= 'a') {
496 		/* look ahead to look for reserved words */
497 		peekc = getch();
498 		if (peekc >= 'a' && peekc <= 'z') {
499 			/* must be reserved word */
500 			if (c == 'i' && peekc == 'f') {
501 				c = _IF;
502 				goto skip;
503 			}
504 			if (c == 'w' && peekc == 'h') {
505 				c = _WHILE;
506 				goto skip;
507 			}
508 			if (c == 'f' && peekc == 'o') {
509 				c = _FOR;
510 				goto skip;
511 			}
512 			if (c == 's' && peekc == 'q') {
513 				c = SQRT;
514 				goto skip;
515 			}
516 			if (c == 'r' && peekc == 'e') {
517 				c = _RETURN;
518 				goto skip;
519 			}
520 			if (c == 'b' && peekc == 'r') {
521 				c = _BREAK;
522 				goto skip;
523 			}
524 			if (c == 'd' && peekc == 'e') {
525 				c = _DEFINE;
526 				goto skip;
527 			}
528 			if (c == 's' && peekc == 'c') {
529 				c = SCALE;
530 				goto skip;
531 			}
532 			if (c == 'b' && peekc == 'a') {
533 				c = BASE;
534 				goto skip;
535 			}
536 			if (c == 'i' && peekc == 'b') {
537 				c = BASE;
538 				goto skip;
539 			}
540 			if (c == 'o' && peekc == 'b') {
541 				c = OBASE;
542 				goto skip;
543 			}
544 			if (c == 'd' && peekc == 'i') {
545 				c = FFF;
546 				goto skip;
547 			}
548 			if (c == 'a' && peekc == 'u') {
549 				c = _AUTO;
550 				goto skip;
551 			}
552 			if (c == 'l' && peekc == 'e') {
553 				c = LENGTH;
554 				goto skip;
555 			}
556 			if (c == 'q' && peekc == 'u') {
557 				getout(0);
558 			}
559 			/* could not be found */
560 			return (error);
561 
562 skip:	/* skip over rest of word */
563 			peekc = -1;
564 			while ((ch = getch()) >= 'a' && ch <= 'z')
565 				;
566 			peekc = ch;
567 			return (c);
568 		}
569 
570 		/* usual case; just one single letter */
571 
572 		yylval.cptr = letr[c-'a'];
573 		return (LETTER);
574 	}
575 
576 	if (c >= '0' && c <= '9' || c >= 'A' && c <= 'F') {
577 		yylval.cc = c;
578 		return (DIGIT);
579 	}
580 
581 	switch (c) {
582 	case '.':
583 		return (DOT);
584 
585 	case '=':
586 		switch ((peekc = getch())) {
587 		case '=':
588 			c = EQ;
589 			goto gotit;
590 
591 		case '+':
592 			c = EQPL;
593 			goto gotit;
594 
595 		case '-':
596 			c = EQMI;
597 			goto gotit;
598 
599 		case '*':
600 			c = EQMUL;
601 			goto gotit;
602 
603 		case '/':
604 			c = EQDIV;
605 			goto gotit;
606 
607 		case '%':
608 			c = EQREM;
609 			goto gotit;
610 
611 		case '^':
612 			c = EQEXP;
613 			goto gotit;
614 
615 		default:
616 			return ('=');
617 gotit:
618 			peekc = -1;
619 			return (c);
620 		}
621 
622 	case '+':
623 		return (cpeek('+', INCR, '=', EQPL, '+'));
624 
625 	case '-':
626 		return (cpeek('-', DECR, '=', EQMI, '-'));
627 
628 	case '*':
629 		return (cpeek('=', EQMUL, '\0', 0, '*'));
630 
631 	case '%':
632 		return (cpeek('=', EQREM, '\0', 0, '%'));
633 
634 	case '^':
635 		return (cpeek('=', EQEXP, '\0', 0, '^'));
636 
637 	case '<':
638 		return (cpeek('=', LE, '\0', 0, '<'));
639 
640 	case '>':
641 		return (cpeek('=', GE, '\0', 0, '>'));
642 
643 	case '!':
644 		return (cpeek('=', NE, '\0', 0, '!'));
645 
646 	case '/':
647 		if ((peekc = getch()) == '=') {
648 			peekc = -1;
649 			return (EQDIV);
650 		}
651 		if (peekc == '*') {
652 			peekc = -1;
653 			while ((getch() != '*') || ((peekc = getch()) != '/'))
654 				;
655 			peekc = -1;
656 			goto restart;
657 		}
658 		else
659 			return (c);
660 
661 	case '"':
662 		yylval.cptr = str;
663 		while ((c = getch()) != '"') {
664 			*str++ = c;
665 			if (str >= &string[STRING_SIZE-1]) {
666 				yyerror("string space exceeded");
667 				getout(1);
668 			}
669 		}
670 		*str++ = '\0';
671 		return (QSTR);
672 
673 	default:
674 		return (c);
675 	}
676 }
677 
678 int
679 cpeek(char c1, int yes1, char c2, int yes2, char none)
680 {
681 	int r;
682 
683 	peekc = getch();
684 	if (peekc == c1)
685 		r = yes1;
686 	else if (peekc == c2)
687 		r = yes2;
688 	else
689 		return (none);
690 	peekc = -1;
691 	return (r);
692 }
693 
694 
695 int
696 getch(void)
697 {
698 	int ch;
699 	char mbuf[LINE_MAX];
700 
701 loop:
702 	ch = (peekc < 0) ? getc(in) : peekc;
703 	peekc = -1;
704 	if (ch != EOF)
705 		return (ch);
706 
707 	if (++ifile >= sargc) {
708 		if (ifile >= sargc+1)
709 			getout(0);
710 		in = stdin;
711 		ln = 0;
712 		goto loop;
713 	}
714 
715 	(void) fclose(in);
716 	if ((in = fopen(sargv[ifile], "r")) != NULL) {
717 		ln = 0;
718 		ss = sargv[ifile];
719 		goto loop;
720 	}
721 	(void) snprintf(mbuf, sizeof (mbuf), "can't open input file %s",
722 		sargv[ifile]);
723 	ln = -1;
724 	ss = "command line";
725 	yyerror(mbuf);
726 	getout(1);
727 	/*NOTREACHED*/
728 }
729 
730 #define	b_sp_max	5000
731 int b_space[b_sp_max];
732 int *b_sp_nxt = { b_space };
733 
734 int	bdebug = 0;
735 
736 static int *
737 bundle(int i, ...)
738 {
739 	va_list ap;
740 	int *q;
741 
742 	va_start(ap, i);
743 	q = b_sp_nxt;
744 	if (bdebug)
745 		printf("bundle %d elements at %o\n", i, q);
746 	while (i-- > 0) {
747 		if (b_sp_nxt >= & b_space[b_sp_max])
748 			yyerror("bundling space exceeded");
749 		*b_sp_nxt++ = va_arg(ap, int);
750 	}
751 	* b_sp_nxt++ = 0;
752 	yyval.iptr = q;
753 	va_end(ap);
754 	return (q);
755 }
756 
757 void
758 routput(int *p)
759 {
760 	if (bdebug) printf("routput(%o)\n", p);
761 	if (p >= &b_space[0] && p < &b_space[b_sp_max]) {
762 		/* part of a bundle */
763 		while (*p != 0)
764 			routput((int *)*p++);
765 	}
766 	else
767 		printf((char *)p);	 /* character string */
768 }
769 
770 void
771 output(int *p)
772 {
773 	routput(p);
774 	b_sp_nxt = & b_space[0];
775 	printf("\n");
776 	(void) fflush(stdout);
777 	cp = cary;
778 	crs = rcrs;
779 }
780 
781 void
782 conout(int *p, char *s)
783 {
784 	printf("[");
785 	routput(p);
786 	printf("]s%s\n", s);
787 	(void) fflush(stdout);
788 	lev--;
789 }
790 
791 void
792 yyerror(char *s)
793 {
794 	if (ifile >= sargc)
795 		ss = "teletype";
796 
797 	if (ss == 0 || *ss == 0)
798 		(void) fprintf(stderr, gettext("%s on line %d\n"), s, ln+1);
799 	else
800 		(void) fprintf(stderr, gettext("%s on line %d, %s\n"),
801 		    s, ln+1, ss);
802 	(void) fflush(stderr);
803 
804 	cp = cary;
805 	crs = rcrs;
806 	bindx = 0;
807 	lev = 0;
808 	b_sp_nxt = &b_space[0];
809 }
810 
811 void
812 checkbuffer(void)
813 {
814 	/* Do not exceed the last char in input line buffer */
815 	if (cp >= cpend) {
816 		yyerror("line too long\n");
817 		getout(1);
818 	}
819 }
820 
821 void
822 pp(int *s)
823 {
824 	/* puts the relevant stuff on pre and post for the letter s */
825 
826 	(void) bundle(3, "S", s, pre);
827 	pre = yyval.iptr;
828 	(void) bundle(4, post, "L", s, "s.");
829 	post = yyval.iptr;
830 }
831 
832 void
833 tp(int *s)
834 {		/* same as pp, but for temps */
835 	bundle(3, "0S", s, pre);
836 	pre = yyval.iptr;
837 	bundle(4, post, "L", s, "s.");
838 	post = yyval.iptr;
839 }
840 
841 void
842 yyinit(int argc, char **argv)
843 {
844 	char	mbuf[LINE_MAX];
845 
846 	(void) signal(SIGINT, SIG_IGN);		/* ignore all interrupts */
847 
848 	sargv = argv;
849 	sargc = argc;
850 	if (sargc == 0)
851 		in = stdin;
852 	else if ((in = fopen(sargv[0], "r")) == NULL) {
853 		(void) snprintf(mbuf, sizeof (mbuf), "can't open input file %s",
854 			sargv[0]);
855 		ln = -1;
856 		ss = "command line";
857 		yyerror(mbuf);
858 		getout(1);
859 	}
860 	ifile = 0;
861 	ln = 0;
862 	ss = sargv[0];
863 }
864 
865 static void
866 getout(int code)
867 {
868 	printf("q");
869 	(void) fflush(stdout);
870 	exit(code);
871 }
872 
873 int *
874 getf(char *p)
875 {
876 	return ((int *) &funtab[2*(*p -0141)]);
877 }
878 
879 int *
880 geta(char *p)
881 {
882 	return ((int *) &atab[2*(*p - 0141)]);
883 }
884 
885 int
886 main(int argc, char **argv)
887 {
888 	int	p[2];
889 	int	cflag = 0;
890 	int	lflag = 0;
891 	int	flag = 0;
892 	char	**av;
893 	int 	filecounter = 0;
894 
895 	(void) setlocale(LC_ALL, "");
896 #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
897 #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it weren't */
898 #endif
899 	(void) textdomain(TEXT_DOMAIN);
900 
901 	while ((flag = getopt(argc, argv, "dcl")) != EOF) {
902 		switch (flag) {
903 		case 'd':
904 		case 'c':
905 			cflag++;
906 			break;
907 
908 		case 'l':
909 			lflag++;
910 			break;
911 
912 		default:
913 			fflush(stdout);
914 			usage();
915 			break;
916 		}
917 	}
918 
919 	argc -= optind;
920 	av = &argv[optind];
921 
922 	/*
923 	* argc is the count of arguments, which should be filenames,
924 	* remaining in argv. av is a pointer to the first of the
925 	* remaining arguments.
926 	*/
927 
928 	for (filecounter = 0; filecounter < argc; filecounter++) {
929 		if ((strlen(av[filecounter])) >= PATH_MAX) {
930 			(void) fprintf(stderr,
931 			    gettext("File argument too long\n"));
932 			exit(2);
933 		}
934 	}
935 
936 	if (lflag) {
937 		/*
938 		* if the user wants to include the math library, prepend
939 		* the math library filename to the argument list by
940 		* overwriting the last option (there must be at least one
941 		* supplied option if this is being done).
942 		*/
943 		av = &argv[optind-1];
944 		av[0] = "/usr/lib/lib.b";
945 		argc++;
946 	}
947 
948 	if (cflag) {
949 		yyinit(argc, av);
950 		yyparse();
951 		exit(0);
952 	}
953 
954 	pipe(p);
955 	if (fork() == 0) {
956 		(void) close(1);
957 		dup(p[1]);
958 		(void) close(p[0]);
959 		(void) close(p[1]);
960 		yyinit(argc, av);
961 		yyparse();
962 		exit(0);
963 	}
964 	(void) close(0);
965 	dup(p[0]);
966 	(void) close(p[0]);
967 	(void) close(p[1]);
968 #ifdef XPG6
969 	execl("/usr/xpg6/bin/dc", "dc", "-", 0);
970 #else
971 	execl("/usr/bin/dc", "dc", "-", 0);
972 #endif
973 
974 	return (1);
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