xref: /plan9/sys/src/cmd/bc.y (revision 033584b01144b418519c5713cd258b3ca2f7bccf)
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
cpeek(int c,int yes,int no)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
getch(void)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 	ifile++;
790 	if(ifile > sargc) {
791 		if(ifile >= sargc+2)
792 			getout();
793 		in = &bstdin;
794 		Binit(in, 0, OREAD);
795 		ln = 0;
796 		goto loop;
797 	}
798 	if(in)
799 		Bterm(in);
800 	if((in = Bopen(sargv[ifile], OREAD)) != 0){
801 		ln = 0;
802 		ss = sargv[ifile];
803 		goto loop;
804 	}
805 	yyerror("cannot open input file");
806 	return 0;		/* shut up ken */
807 }
808 
809 char*
bundle(int a,...)810 bundle(int a, ...)
811 {
812 	int i;
813 	char **q;
814 	va_list arg;
815 
816 	i = a;
817 	va_start(arg, a);
818 	q = bsp_nxt;
819 	if(bdebug)
820 		fprint(2, "bundle %d elements at %lx\n", i, q);
821 	while(i-- > 0) {
822 		if(bsp_nxt >= &bspace[bsp_max])
823 			yyerror("bundling space exceeded");
824 		*bsp_nxt++ = va_arg(arg, char*);
825 	}
826 	*bsp_nxt++ = 0;
827 	va_end(arg);
828 	yyval.cptr = (char*)q;
829 	return (char*)q;
830 }
831 
832 void
routput(char * p)833 routput(char *p)
834 {
835 	char **pp;
836 
837 	if(bdebug)
838 		fprint(2, "routput(%lx)\n", p);
839 	if((char**)p >= &bspace[0] && (char**)p < &bspace[bsp_max]) {
840 		/* part of a bundle */
841 		pp = (char**)p;
842 		while(*pp != 0)
843 			routput(*pp++);
844 	} else
845 		Bprint(&bstdout, p);	/* character string */
846 }
847 
848 void
output(char * p)849 output(char *p)
850 {
851 	routput(p);
852 	bsp_nxt = &bspace[0];
853 	Bprint(&bstdout, "\n");
854 	Bflush(&bstdout);
855 	cp = cary;
856 	crs = rcrs;
857 }
858 
859 void
conout(char * p,char * s)860 conout(char *p, char *s)
861 {
862 	Bprint(&bstdout, "[");
863 	routput(p);
864 	Bprint(&bstdout, "]s%s\n", s);
865 	Bflush(&bstdout);
866 	lev--;
867 }
868 
869 void
yyerror(char * s,...)870 yyerror(char *s, ...)
871 {
872 	if(ifile > sargc)
873 		ss = "stdin";
874 	Bprint(&bstdout, "c[%s:%d %s]pc\n", ss, ln+1, s);
875 	Bflush(&bstdout);
876 	cp = cary;
877 	crs = rcrs;
878 	bindx = 0;
879 	lev = 0;
880 	bsp_nxt = &bspace[0];
881 }
882 
883 void
pp(char * s)884 pp(char *s)
885 {
886 	/* puts the relevant stuff on pre and post for the letter s */
887 	bundle(3, "S", s, pre);
888 	pre = yyval.cptr;
889 	bundle(4, post, "L", s, "s.");
890 	post = yyval.cptr;
891 }
892 
893 void
tp(char * s)894 tp(char *s)
895 {
896 	/* same as pp, but for temps */
897 	bundle(3, "0S", s, pre);
898 	pre = yyval.cptr;
899 	bundle(4, post, "L", s, "s.");
900 	post = yyval.cptr;
901 }
902 
903 void
yyinit(int argc,char ** argv)904 yyinit(int argc, char **argv)
905 {
906 	Binit(&bstdout, 1, OWRITE);
907 	sargv = argv;
908 	sargc = argc - 1;
909 	if(sargc == 0) {
910 		in = &bstdin;
911 		Binit(in, 0, OREAD);
912 	} else if((in = Bopen(sargv[1], OREAD)) == 0)
913 		yyerror("cannot open input file");
914 	ifile = 1;
915 	ln = 0;
916 	ss = sargv[1];
917 }
918 
919 void
getout(void)920 getout(void)
921 {
922 	Bprint(&bstdout, "q");
923 	Bflush(&bstdout);
924 	exits(0);
925 }
926 
927 char*
getf(char * p)928 getf(char *p)
929 {
930 	return funtab[*p - 'a'];
931 }
932 
933 char*
geta(char * p)934 geta(char *p)
935 {
936 	return atab[*p - 'a'];
937 }
938 
939 void
main(int argc,char ** argv)940 main(int argc, char **argv)
941 {
942 	int p[2];
943 
944 	while(argc > 1 && *argv[1] == '-') {
945 		switch(argv[1][1]) {
946 		case 'd':
947 			bdebug++;
948 			break;
949 		case 'c':
950 			cflag++;
951 			break;
952 		case 'l':
953 			lflag++;
954 			break;
955 		case 's':
956 			sflag++;
957 			break;
958 		default:
959 			fprint(2, "Usage: bc [-cdls] [file ...]\n");
960 			exits("usage");
961 		}
962 		argc--;
963 		argv++;
964 	}
965 	if(lflag) {
966 		argv--;
967 		argc++;
968 		argv[1] = "/sys/lib/bclib";
969 	}
970 	if(cflag) {
971 		yyinit(argc, argv);
972 		for(;;)
973 			yyparse();
974 		/* not reached */
975 	}
976 	pipe(p);
977 	if(fork() == 0) {
978 		dup(p[1], 1);
979 		close(p[0]);
980 		close(p[1]);
981 		yyinit(argc, argv);
982 		for(;;)
983 			yyparse();
984 	}
985 	dup(p[0], 0);
986 	close(p[0]);
987 	close(p[1]);
988 	execl("/bin/dc", "dc", nil);
989 }
990