9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

bc.y (13425B)


      1 %{
      2 	#include	<u.h>
      3 	#include	<libc.h>
      4 	#include	<bio.h>
      5 
      6 	#define	bsp_max	5000
      7 
      8 	Biobuf	*in;
      9 	Biobuf	bstdin;
     10 	Biobuf	bstdout;
     11 	char	cary[1000];
     12 	char*	cp = { cary };
     13 	char	string[1000];
     14 	char*	str = { string };
     15 	int	crs = 128;
     16 	int	rcrs = 128;	/* reset crs */
     17 	int	bindx = 0;
     18 	int	lev = 0;
     19 	int	ln;
     20 	char*	ttp;
     21 	char*	ss = "";
     22 	int	bstack[10] = { 0 };
     23 	char*	numb[15] =
     24 	{
     25 		" 0", " 1", " 2", " 3", " 4", " 5",
     26 		" 6", " 7", " 8", " 9", " 10", " 11",
     27 		" 12", " 13", " 14"
     28 	};
     29 	char*	pre;
     30 	char*	post;
     31 
     32 	long	peekc = -1;
     33 	int	sargc;
     34 	int	ifile;
     35 	char**	sargv;
     36 
     37 	char	*funtab[] =
     38 	{
     39 		"<1>","<2>","<3>","<4>","<5>",
     40 		"<6>","<7>","<8>","<9>","<10>",
     41 		"<11>","<12>","<13>","<14>","<15>",
     42 		"<16>","<17>","<18>","<19>","<20>",
     43 		"<21>","<22>","<23>","<24>","<25>",
     44 		"<26>"
     45 	};
     46 	char	*atab[] =
     47 	{
     48 		"<221>","<222>","<223>","<224>","<225>",
     49 		"<226>","<227>","<228>","<229>","<230>",
     50 		"<231>","<232>","<233>","<234>","<235>",
     51 		"<236>","<237>","<238>","<239>","<240>",
     52 		"<241>","<242>","<243>","<244>","<245>",
     53 		"<246>"
     54 	};
     55 	char*	letr[26] =
     56 	{
     57 		"a","b","c","d","e","f","g","h","i","j",
     58 		"k","l","m","n","o","p","q","r","s","t",
     59 		"u","v","w","x","y","z"
     60 	};
     61 	char*	dot = { "." };
     62 	char*	bspace[bsp_max];
     63 	char**	bsp_nxt = bspace;
     64 	int	bdebug = 0;
     65 	int	lflag;
     66 	int	cflag;
     67 	int	sflag;
     68 
     69 	char*	bundle(int, ...);
     70 	void	conout(char*, char*);
     71 	int	cpeek(int, int, int);
     72 	int	getch(void);
     73 	char*	geta(char*);
     74 	char*	getf(char*);
     75 	void	getout(void);
     76 	void	output(char*);
     77 	void	pp(char*);
     78 	void	routput(char*);
     79 	void	tp(char*);
     80 	void	yyerror(char*, ...);
     81 	int	yyparse(void);
     82 
     83 	typedef	void*	pointer;
     84 	#pragma	varargck	type	"lx"	pointer
     85 
     86 %}
     87 %union
     88 {
     89 	char*	cptr;
     90 	int	cc;
     91 }
     92 
     93 %type	<cptr>	pstat stat stat1 def slist dlets e ase nase
     94 %type	<cptr>	slist re fprefix cargs eora cons constant lora
     95 %type	<cptr>	crs
     96 
     97 %token	<cptr>	LETTER EQOP _AUTO DOT
     98 %token	<cc>	DIGIT SQRT LENGTH _IF FFF EQ
     99 %token	<cc>	_PRINT _WHILE _FOR NE LE GE INCR DECR
    100 %token	<cc>	_RETURN _BREAK _DEFINE BASE OBASE SCALE
    101 %token	<cc>	QSTR ERROR
    102 
    103 %right	'=' EQOP
    104 %left	'+' '-'
    105 %left	'*' '/' '%'
    106 %right	'^'
    107 %left	UMINUS
    108 
    109 %%
    110 start:
    111 	start stuff
    112 |	stuff
    113 
    114 stuff:
    115 	pstat tail
    116 	{
    117 		output($1);
    118 	}
    119 |	def dargs ')' '{' dlist slist '}'
    120 	{
    121 		ttp = bundle(6, pre, $6, post , "0", numb[lev], "Q");
    122 		conout(ttp, (char*)$1);
    123 		rcrs = crs;
    124 		output("");
    125 		lev = bindx = 0;
    126 	}
    127 
    128 dlist:
    129 	tail
    130 |	dlist _AUTO dlets tail
    131 
    132 stat:
    133 	stat1
    134 |	nase
    135 	{
    136 		if(sflag)
    137 			bundle(2, $1, "s.");
    138 	}
    139 
    140 pstat:
    141 	stat1
    142 	{
    143 		if(sflag)
    144 			bundle(2, $1, "0");
    145 	}
    146 |	nase
    147 	{
    148 		if(!sflag)
    149 			bundle(2, $1, "ps.");
    150 	}
    151 
    152 stat1:
    153 	{
    154 		bundle(1, "");
    155 	}
    156 |	ase
    157 	{
    158 		bundle(2, $1, "s.");
    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 |	QSTR
    185 	{
    186 		bundle(3, "[", $1, "]P");
    187 	}
    188 |	_BREAK
    189 	{
    190 		bundle(2, numb[lev-bstack[bindx-1]], "Q");
    191 	}
    192 |	_PRINT e
    193 	{
    194 		bundle(2, $2, "ps.");
    195 	}
    196 |	_RETURN e
    197 	{
    198 		bundle(4, $2, post, numb[lev], "Q");
    199 	}
    200 |	_RETURN
    201 	{
    202 		bundle(4, "0", post, numb[lev], "Q");
    203 	}
    204 |	'{' slist '}'
    205 	{
    206 		$$ = $2;
    207 	}
    208 |	FFF
    209 	{
    210 		bundle(1, "fY");
    211 	}
    212 |	_IF crs BLEV '(' re ')' stat
    213 	{
    214 		conout($7, $2);
    215 		bundle(3, $5, $2, " ");
    216 	}
    217 |	_WHILE crs '(' re ')' stat BLEV
    218 	{
    219 		bundle(3, $6, $4, $2);
    220 		conout($$, $2);
    221 		bundle(3, $4, $2, " ");
    222 	}
    223 |	fprefix crs re ';' e ')' stat BLEV
    224 	{
    225 		bundle(5, $7, $5, "s.", $3, $2);
    226 		conout($$, $2);
    227 		bundle(5, $1, "s.", $3, $2, " ");
    228 	}
    229 |	'~' LETTER '=' e
    230 	{
    231 		bundle(3, $4, "S", $2);
    232 	}
    233 
    234 fprefix:
    235 	_FOR '(' e ';'
    236 	{
    237 		$$ = $3;
    238 	}
    239 
    240 BLEV:
    241 	=
    242 	{
    243 		--bindx;
    244 	}
    245 
    246 slist:
    247 	stat
    248 |	slist tail stat
    249 	{
    250 		bundle(2, $1, $3);
    251 	}
    252 
    253 tail:
    254 	'\n'
    255 	{
    256 		ln++;
    257 	}
    258 |	';'
    259 
    260 re:
    261 	e EQ e
    262 	{
    263 		$$ = bundle(3, $1, $3, "=");
    264 	}
    265 |	e '<' e
    266 	{
    267 		bundle(3, $1, $3, ">");
    268 	}
    269 |	e '>' e
    270 	{
    271 		bundle(3, $1, $3, "<");
    272 	}
    273 |	e NE e
    274 	{
    275 		bundle(3, $1, $3, "!=");
    276 	}
    277 |	e GE e
    278 	{
    279 		bundle(3, $1, $3, "!>");
    280 	}
    281 |	e LE e
    282 	{
    283 		bundle(3, $1, $3, "!<");
    284 	}
    285 |	e
    286 	{
    287 		bundle(2, $1, " 0!=");
    288 	}
    289 
    290 nase:
    291 	'(' e ')'
    292 	{
    293 		$$ = $2;
    294 	}
    295 |	cons
    296 	{
    297 		bundle(3, " ", $1, " ");
    298 	}
    299 |	DOT cons
    300 	{
    301 		bundle(3, " .", $2, " ");
    302 	}
    303 |	cons DOT cons
    304 	{
    305 		bundle(5, " ", $1, ".", $3, " ");
    306 	}
    307 |	cons DOT
    308 	{
    309 		bundle(4, " ", $1, ".", " ");
    310 	}
    311 |	DOT
    312 	{
    313 		$<cptr>$ = "l.";
    314 	}
    315 |	LETTER '[' e ']'
    316 	{
    317 		bundle(3, $3, ";", geta($1));
    318 	}
    319 |	LETTER INCR
    320 	{
    321 		bundle(4, "l", $1, "d1+s", $1);
    322 	}
    323 |	INCR LETTER
    324 	{
    325 		bundle(4, "l", $2, "1+ds", $2);
    326 	}
    327 |	DECR LETTER
    328 	{
    329 		bundle(4, "l", $2, "1-ds", $2);
    330 	}
    331 |	LETTER DECR
    332 	{
    333 		bundle(4, "l", $1, "d1-s", $1);
    334 	}
    335 |	LETTER '[' e ']' INCR
    336 	{
    337 		bundle(7, $3, ";", geta($1), "d1+" ,$3, ":" ,geta($1));
    338 	}
    339 |	INCR LETTER '[' e ']'
    340 	{
    341 		bundle(7, $4, ";", geta($2), "1+d", $4, ":", geta($2));
    342 	}
    343 |	LETTER '[' e ']' DECR
    344 	{
    345 		bundle(7, $3, ";", geta($1), "d1-", $3, ":", geta($1));
    346 	}
    347 |	DECR LETTER '[' e ']'
    348 	{
    349 		bundle(7, $4, ";", geta($2), "1-d", $4, ":" ,geta($2));
    350 	}
    351 |	SCALE INCR
    352 	{
    353 		bundle(1, "Kd1+k");
    354 	}
    355 |	INCR SCALE
    356 	{
    357 		bundle(1, "K1+dk");
    358 	}
    359 |	SCALE DECR
    360 	{
    361 		bundle(1, "Kd1-k");
    362 	}
    363 |	DECR SCALE
    364 	{
    365 		bundle(1, "K1-dk");
    366 	}
    367 |	BASE INCR
    368 	{
    369 		bundle(1, "Id1+i");
    370 	}
    371 |	INCR BASE
    372 	{
    373 		bundle(1, "I1+di");
    374 	}
    375 |	BASE DECR
    376 	{
    377 		bundle(1, "Id1-i");
    378 	}
    379 |	DECR BASE
    380 	{
    381 		bundle(1, "I1-di");
    382 	}
    383 |	OBASE INCR
    384 	{
    385 		bundle(1, "Od1+o");
    386 	}
    387 |	INCR OBASE
    388 	{
    389 		bundle(1, "O1+do");
    390 	}
    391 |	OBASE DECR
    392 	{
    393 		bundle(1, "Od1-o");
    394 	}
    395 |	DECR OBASE
    396 	{
    397 		bundle(1, "O1-do");
    398 	}
    399 |	LETTER '(' cargs ')'
    400 	{
    401 		bundle(4, $3, "l", getf($1), "x");
    402 	}
    403 |	LETTER '(' ')'
    404 	{
    405 		bundle(3, "l", getf($1), "x");
    406 	}
    407 |	LETTER = {
    408 		bundle(2, "l", $1);
    409 	}
    410 |	LENGTH '(' e ')'
    411 	{
    412 		bundle(2, $3, "Z");
    413 	}
    414 |	SCALE '(' e ')'
    415 	{
    416 		bundle(2, $3, "X");
    417 	}
    418 |	'?'
    419 	{
    420 		bundle(1, "?");
    421 	}
    422 |	SQRT '(' e ')'
    423 	{
    424 		bundle(2, $3, "v");
    425 	}
    426 |	'~' LETTER
    427 	{
    428 		bundle(2, "L", $2);
    429 	}
    430 |	SCALE
    431 	{
    432 		bundle(1, "K");
    433 	}
    434 |	BASE
    435 	{
    436 		bundle(1, "I");
    437 	}
    438 |	OBASE
    439 	{
    440 		bundle(1, "O");
    441 	}
    442 |	'-' e
    443 	{
    444 		bundle(3, " 0", $2, "-");
    445 	}
    446 |	e '+' e
    447 	{
    448 		bundle(3, $1, $3, "+");
    449 	}
    450 |	e '-' e
    451 	{
    452 		bundle(3, $1, $3, "-");
    453 	}
    454 |	e '*' e
    455 	{
    456 		bundle(3, $1, $3, "*");
    457 	}
    458 |	e '/' e
    459 	{
    460 		bundle(3, $1, $3, "/");
    461 	}
    462 |	e '%' e
    463 	{
    464 		bundle(3, $1, $3, "%%");
    465 	}
    466 |	e '^' e
    467 	{
    468 		bundle(3, $1, $3, "^");
    469 	}
    470 
    471 ase:
    472 	LETTER '=' e
    473 	{
    474 		bundle(3, $3, "ds", $1);
    475 	}
    476 |	LETTER '[' e ']' '=' e
    477 	{
    478 		bundle(5, $6, "d", $3, ":", geta($1));
    479 	}
    480 |	LETTER EQOP e
    481 	{
    482 		bundle(6, "l", $1, $3, $2, "ds", $1);
    483 	}
    484 |	LETTER '[' e ']' EQOP e
    485 	{
    486 		bundle(9, $3, ";", geta($1), $6, $5, "d", $3, ":", geta($1));
    487 	}
    488 
    489 e:
    490 	ase
    491 |	nase
    492 
    493 cargs:
    494 	eora
    495 |	cargs ',' eora
    496 	{
    497 		bundle(2, $1, $3);
    498 	}
    499 
    500 eora:
    501 	e
    502 |	LETTER '[' ']'
    503 	{
    504 		bundle(2, "l", geta($1));
    505 	}
    506 
    507 cons:
    508 	constant
    509 	{
    510 		*cp++ = 0;
    511 	}
    512 
    513 constant:
    514 	'_'
    515 	{
    516 		$<cptr>$ = cp;
    517 		*cp++ = '_';
    518 	}
    519 |	DIGIT
    520 	{
    521 		$<cptr>$ = cp;
    522 		*cp++ = $1;
    523 	}
    524 |	constant DIGIT
    525 	{
    526 		*cp++ = $2;
    527 	}
    528 
    529 crs:
    530 	=
    531 	{
    532 		$$ = cp;
    533 		*cp++ = '<';
    534 		*cp++ = crs/100+'0';
    535 		*cp++ = (crs%100)/10+'0';
    536 		*cp++ = crs%10+'0';
    537 		*cp++ = '>';
    538 		*cp++ = '\0';
    539 		if(crs++ >= 220) {
    540 			yyerror("program too big");
    541 			getout();
    542 		}
    543 		bstack[bindx++] = lev++;
    544 	}
    545 
    546 def:
    547 	_DEFINE LETTER '('
    548 	{
    549 		$$ = getf($2);
    550 		pre = (char*)"";
    551 		post = (char*)"";
    552 		lev = 1;
    553 		bindx = 0;
    554 		bstack[bindx] = 0;
    555 	}
    556 
    557 dargs:
    558 |	lora
    559 	{
    560 		pp((char*)$1);
    561 	}
    562 |	dargs ',' lora
    563 	{
    564 		pp((char*)$3);
    565 	}
    566 
    567 dlets:
    568 	lora
    569 	{
    570 		tp((char*)$1);
    571 	}
    572 |	dlets ',' lora
    573 	{
    574 		tp((char*)$3);
    575 	}
    576 
    577 lora:
    578 	LETTER
    579 	{
    580 		$<cptr>$=$1;
    581 	}
    582 |	LETTER '[' ']'
    583 	{
    584 		$$ = geta($1);
    585 	}
    586 
    587 %%
    588 
    589 int
    590 yylex(void)
    591 {
    592 	int c, ch;
    593 
    594 restart:
    595 	c = getch();
    596 	peekc = -1;
    597 	while(c == ' ' || c == '\t')
    598 		c = getch();
    599 	if(c == '\\') {
    600 		getch();
    601 		goto restart;
    602 	}
    603 	if(c >= 'a' && c <= 'z') {
    604 		/* look ahead to look for reserved words */
    605 		peekc = getch();
    606 		if(peekc >= 'a' && peekc <= 'z') { /* must be reserved word */
    607 			if(c=='p' && peekc=='r') {
    608 				c = _PRINT;
    609 				goto skip;
    610 			}
    611 			if(c=='i' && peekc=='f') {
    612 				c = _IF;
    613 				goto skip;
    614 			}
    615 			if(c=='w' && peekc=='h') {
    616 				c = _WHILE;
    617 				goto skip;
    618 			}
    619 			if(c=='f' && peekc=='o') {
    620 				c = _FOR;
    621 				goto skip;
    622 			}
    623 			if(c=='s' && peekc=='q') {
    624 				c = SQRT;
    625 				goto skip;
    626 			}
    627 			if(c=='r' && peekc=='e') {
    628 				c = _RETURN;
    629 				goto skip;
    630 			}
    631 			if(c=='b' && peekc=='r') {
    632 				c = _BREAK;
    633 				goto skip;
    634 			}
    635 			if(c=='d' && peekc=='e') {
    636 				c = _DEFINE;
    637 				goto skip;
    638 			}
    639 			if(c=='s' && peekc=='c') {
    640 				c = SCALE;
    641 				goto skip;
    642 			}
    643 			if(c=='b' && peekc=='a') {
    644 				c = BASE;
    645 				goto skip;
    646 			}
    647 			if(c=='i' && peekc=='b') {
    648 				c = BASE;
    649 				goto skip;
    650 			}
    651 			if(c=='o' && peekc=='b') {
    652 				c = OBASE;
    653 				goto skip;
    654 			}
    655 			if(c=='d' && peekc=='i') {
    656 				c = FFF;
    657 				goto skip;
    658 			}
    659 			if(c=='a' && peekc=='u') {
    660 				c = _AUTO;
    661 				goto skip;
    662 			}
    663 			if(c=='l' && peekc=='e') {
    664 				c = LENGTH;
    665 				goto skip;
    666 			}
    667 			if(c=='q' && peekc=='u')
    668 				getout();
    669 			/* could not be found */
    670 			return ERROR;
    671 
    672 		skip:	/* skip over rest of word */
    673 			peekc = -1;
    674 			for(;;) {
    675 				ch = getch();
    676 				if(ch < 'a' || ch > 'z')
    677 					break;
    678 			}
    679 			peekc = ch;
    680 			return c;
    681 		}
    682 
    683 		/* usual case; just one single letter */
    684 		yylval.cptr = letr[c-'a'];
    685 		return LETTER;
    686 	}
    687 	if((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
    688 		yylval.cc = c;
    689 		return DIGIT;
    690 	}
    691 	switch(c) {
    692 	case '.':
    693 		return DOT;
    694 	case '*':
    695 		yylval.cptr = "*";
    696 		return cpeek('=', EQOP, c);
    697 	case '%':
    698 		yylval.cptr = "%%";
    699 		return cpeek('=', EQOP, c);
    700 	case '^':
    701 		yylval.cptr = "^";
    702 		return cpeek('=', EQOP, c);
    703 	case '+':
    704 		ch = cpeek('=', EQOP, c);
    705 		if(ch == EQOP) {
    706 			yylval.cptr = "+";
    707 			return ch;
    708 		}
    709 		return cpeek('+', INCR, c);
    710 	case '-':
    711 		ch = cpeek('=', EQOP, c);
    712 		if(ch == EQOP) {
    713 			yylval.cptr = "-";
    714 			return ch;
    715 		}
    716 		return cpeek('-', DECR, c);
    717 	case '=':
    718 		return cpeek('=', EQ, '=');
    719 	case '<':
    720 		return cpeek('=', LE, '<');
    721 	case '>':
    722 		return cpeek('=', GE, '>');
    723 	case '!':
    724 		return cpeek('=', NE, '!');
    725 	case '/':
    726 		ch = cpeek('=', EQOP, c);
    727 		if(ch == EQOP) {
    728 			yylval.cptr = "/";
    729 			return ch;
    730 		}
    731 		if(peekc == '*') {
    732 			peekc = -1;
    733 			for(;;) {
    734 				ch = getch();
    735 				if(ch == '*') {
    736 					peekc = getch();
    737 					if(peekc == '/') {
    738 						peekc = -1;
    739 						goto restart;
    740 					}
    741 				}
    742 			}
    743 		}
    744 		return c;
    745 	case '"':
    746 		yylval.cptr = str;
    747 		while((c=getch()) != '"'){
    748 			*str++ = c;
    749 			if(str >= &string[999]){
    750 				yyerror("string space exceeded");
    751 				getout();
    752 			}
    753 		}
    754 		*str++ = 0;
    755 		return QSTR;
    756 	default:
    757 		return c;
    758 	}
    759 }
    760 
    761 int
    762 cpeek(int c, int yes, int no)
    763 {
    764 
    765 	peekc = getch();
    766 	if(peekc == c) {
    767 		peekc = -1;
    768 		return yes;
    769 	}
    770 	return no;
    771 }
    772 
    773 int
    774 getch(void)
    775 {
    776 	long ch;
    777 
    778 loop:
    779 	ch = peekc;
    780 	if(ch < 0){
    781 		if(in == 0)
    782 			ch = -1;
    783 		else
    784 			ch = Bgetc(in);
    785 	}
    786 	peekc = -1;
    787 	if(ch >= 0)
    788 		return ch;
    789 
    790 	ifile++;
    791 	if(ifile >= sargc) {
    792 		if(ifile >= sargc+1)
    793 			getout();
    794 		in = &bstdin;
    795 		Binit(in, 0, OREAD);
    796 		ln = 0;
    797 		goto loop;
    798 	}
    799 	if(in)
    800 		Bterm(in);
    801 	if((in = Bopen(sargv[ifile], OREAD)) != 0){
    802 		ln = 0;
    803 		ss = sargv[ifile];
    804 		goto loop;
    805 	}
    806 	fprint(2, "open %s: %r\n", sargv[ifile]);
    807 	yyerror("cannot open input file");
    808 	return 0;		/* shut up ken */
    809 }
    810 
    811 char*
    812 bundle(int a, ...)
    813 {
    814 	int i;
    815 	char **q;
    816 	va_list arg;
    817 	
    818 	i = a;
    819 	va_start(arg, a);
    820 	q = bsp_nxt;
    821 	if(bdebug)
    822 		fprint(2, "bundle %d elements at %lx\n", i, q);
    823 	while(i-- > 0) {
    824 		if(bsp_nxt >= &bspace[bsp_max])
    825 			yyerror("bundling space exceeded");
    826 		*bsp_nxt++ = va_arg(arg, char*);
    827 	}
    828 	*bsp_nxt++ = 0;
    829 	va_end(arg);
    830 	yyval.cptr = (char*)q;
    831 	return (char*)q;
    832 }
    833 
    834 void
    835 routput(char *p)
    836 {
    837 	char **pp;
    838 	
    839 	if(bdebug)
    840 		fprint(2, "routput(%lx)\n", p);
    841 	if((char**)p >= &bspace[0] && (char**)p < &bspace[bsp_max]) {
    842 		/* part of a bundle */
    843 		pp = (char**)p;
    844 		while(*pp != 0)
    845 			routput(*pp++);
    846 	} else
    847 		Bprint(&bstdout, p);	/* character string */
    848 }
    849 
    850 void
    851 output(char *p)
    852 {
    853 	routput(p);
    854 	bsp_nxt = &bspace[0];
    855 	Bprint(&bstdout, "\n");
    856 	Bflush(&bstdout);
    857 	cp = cary;
    858 	crs = rcrs;
    859 }
    860 
    861 void
    862 conout(char *p, char *s)
    863 {
    864 	Bprint(&bstdout, "[");
    865 	routput(p);
    866 	Bprint(&bstdout, "]s%s\n", s);
    867 	Bflush(&bstdout);
    868 	lev--;
    869 }
    870 
    871 void
    872 yyerror(char *s, ...)
    873 {
    874 	if(ifile > sargc)
    875 		ss = "teletype";
    876 	Bprint(&bstdout, "c[%s:%d, %s]pc\n", s, ln+1, ss);
    877 	Bflush(&bstdout);
    878 	cp = cary;
    879 	crs = rcrs;
    880 	bindx = 0;
    881 	lev = 0;
    882 	bsp_nxt = &bspace[0];
    883 }
    884 
    885 void
    886 pp(char *s)
    887 {
    888 	/* puts the relevant stuff on pre and post for the letter s */
    889 	bundle(3, "S", s, pre);
    890 	pre = yyval.cptr;
    891 	bundle(4, post, "L", s, "s.");
    892 	post = yyval.cptr;
    893 }
    894 
    895 void
    896 tp(char *s)
    897 {
    898 	/* same as pp, but for temps */
    899 	bundle(3, "0S", s, pre);
    900 	pre = yyval.cptr;
    901 	bundle(4, post, "L", s, "s.");
    902 	post = yyval.cptr;
    903 }
    904 
    905 void
    906 yyinit(int argc, char **argv)
    907 {
    908 	Binit(&bstdout, 1, OWRITE);
    909 	sargv = argv;
    910 	sargc = argc;
    911 	if(sargc == 0) {
    912 		in = &bstdin;
    913 		Binit(in, 0, OREAD);
    914 	} else if((in = Bopen(sargv[0], OREAD)) == 0)
    915 		yyerror("cannot open input file");
    916 	ifile = 0;
    917 	ln = 0;
    918 	ss = sargv[0];
    919 }
    920 
    921 void
    922 getout(void)
    923 {
    924 	Bprint(&bstdout, "q");
    925 	Bflush(&bstdout);
    926 	exits(0);
    927 }
    928 
    929 char*
    930 getf(char *p)
    931 {
    932 	return funtab[*p - 'a'];
    933 }
    934 
    935 char*
    936 geta(char *p)
    937 {
    938 	return atab[*p - 'a'];
    939 }
    940 
    941 void
    942 main(int argc, char **argv)
    943 {
    944 	int p[2];
    945 
    946 	ARGBEGIN{
    947 	case 'd':
    948 		bdebug++;
    949 		break;
    950 	case 'c':
    951 		cflag++;
    952 		break;
    953 	case 'l':
    954 		lflag++;
    955 		break;
    956 	case 's':
    957 		sflag++;
    958 		break;
    959 	default:
    960 		fprint(2, "Usage: bc [-l] [-c] [file ...]\n");
    961 		exits("usage");
    962 	}ARGEND
    963 	
    964 	if(lflag) {
    965 		argc++;
    966 		argv--;
    967 		*argv = unsharp("#9/lib/bclib");
    968 	}
    969 	if(cflag) {
    970 		yyinit(argc, argv);
    971 		for(;;)
    972 			yyparse();
    973 		exits(0);
    974 	}
    975 	pipe(p);
    976 	if(fork() == 0) {
    977 		dup(p[1], 1);
    978 		close(p[0]);
    979 		close(p[1]);
    980 		yyinit(argc, argv);
    981 		for(;;)
    982 			yyparse();
    983 	}
    984 	dup(p[0], 0);
    985 	close(p[0]);
    986 	close(p[1]);
    987 	execl(unsharp("#9/bin/dc"), "dc", nil);
    988 }