Home | History | Annotate | Download | only in bc
      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