bc.y - sbase - suckless unix tools
 (HTM) git clone git://git.suckless.org/sbase
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       bc.y (16970B)
       ---
            1 %{
            2 #include <libgen.h>
            3 #include <unistd.h>
            4 
            5 #include <assert.h>
            6 #include <ctype.h>
            7 #include <errno.h>
            8 #include <setjmp.h>
            9 #include <stdarg.h>
           10 #include <stdio.h>
           11 #include <stdlib.h>
           12 #include <string.h>
           13 
           14 #include "arg.h"
           15 #include "util.h"
           16 
           17 #define DIGITS   "0123456789ABCDEF"
           18 #define NESTED_MAX 10
           19 
           20 #define funid(f) ((f)[0] - 'a' + 1)
           21 
           22 int yydebug;
           23 
           24 typedef struct macro Macro;
           25 
           26 struct macro {
           27         int op;
           28         int id;
           29         int flowid;
           30         int nested;
           31 };
           32 
           33 static int yyerror(char *);
           34 static int yylex(void);
           35 
           36 static void quit(void);
           37 static char *code(char *, ...);
           38 static char *forcode(Macro *, char *, char *, char *, char *);
           39 static char *whilecode(Macro *, char *, char *);
           40 static char *ifcode(Macro *, char *, char *);
           41 static char *funcode(Macro *, char *, char *, char *);
           42 static char *param(char *, char *), *local(char *, char *);
           43 static Macro *define(char *, char *);
           44 static char *retcode(char *);
           45 static char *brkcode(void);
           46 static Macro *macro(int);
           47 
           48 static char *ftn(char *);
           49 static char *var(char *);
           50 static char *ary(char *);
           51 static void writeout(char *);
           52 
           53 static char *yytext, *buff, *unwind;
           54 static char *filename;
           55 static FILE *filep;
           56 static int lineno, nerr, flowid;
           57 static jmp_buf recover;
           58 static int nested, inhome;
           59 static Macro macros[NESTED_MAX];
           60 int cflag, dflag, lflag, sflag;
           61 
           62 %}
           63 
           64 %union {
           65         char *str;
           66         char id[2];
           67         Macro *macro;
           68 }
           69 
           70 %token <id> ID
           71 %token <str> STRING NUMBER
           72 %token <str> EQOP '+' '-' '*' '/' '%' '^' INCDEC
           73 %token HOME LOOP
           74 %token DOT
           75 %token EQ
           76 %token LE
           77 %token GE
           78 %token NE
           79 %token DEF
           80 %token BREAK
           81 %token QUIT
           82 %token LENGTH
           83 %token RETURN
           84 %token FOR
           85 %token IF
           86 %token WHILE
           87 %token SQRT
           88 %token SCALE
           89 %token IBASE
           90 %token OBASE
           91 %token AUTO PARAM
           92 %token PRINT
           93 
           94 %type <str> item statlst scolonlst
           95 %type <str> function assign nexpr expr exprstat rel stat ary cond
           96 %type <str> autolst arglst parlst
           97 %type <str> params param locals local
           98 %type <macro> def if for while
           99 
          100 %right        '=' EQOP
          101 %left        '+' '-'
          102 %left        '*' '/' '%'
          103 %right        '^'
          104 
          105 %start    program
          106 
          107 %%
          108 
          109 program  :
          110          | item program
          111          ;
          112 
          113 item     : scolonlst '\n'       {writeout($1);}
          114          | function             {writeout($1);}
          115          ;
          116 
          117 function : def parlst '{' '\n' autolst statlst '}' {$$ = funcode($1, $2, $5, $6);}
          118          ;
          119 
          120 scolonlst:                      {$$ = code("");}
          121          | stat
          122          | scolonlst ';' stat   {$$ = code("%s%s", $1, $3);}
          123          | scolonlst ';'
          124          ;
          125 
          126 statlst :                       {$$ = code("");}
          127         | stat
          128         | statlst '\n' stat     {$$ = code("%s%s", $1, $3);}
          129         | statlst ';' stat      {$$ = code("%s%s", $1, $3);}
          130         | statlst '\n'
          131         | statlst ';'
          132         ;
          133 
          134 stat    : exprstat
          135         | PRINT expr            {$$ = code("%sps.", $2);}
          136         | PRINT STRING          {$$ = code("[%s]P", $2);}
          137         | PRINT STRING ',' expr {$$ = code("[%s]P%sps.", $2, $4);}
          138         | STRING                {$$ = code("[%s]P", $1);}
          139         | BREAK                 {$$ = brkcode();}
          140         | QUIT                  {quit();}
          141         | RETURN                {$$ = retcode(code(" 0"));}
          142         | RETURN '(' expr ')'   {$$ = retcode($3);}
          143         | RETURN '(' ')'        {$$ = retcode(code(" 0"));}
          144         | while cond stat       {$$ = whilecode($1, $2, $3);}
          145         | if cond stat          {$$ = ifcode($1, $2, $3);}
          146         | '{' statlst '}'       {$$ = $2;}
          147         | for '(' expr ';' rel ';' expr ')' stat  {$$ = forcode($1, $3, $5, $7, $9);}
          148         ;
          149 
          150 while   : WHILE                 {$$ = macro(LOOP);}
          151         ;
          152 
          153 if      : IF                    {$$ = macro(IF);}
          154         ;
          155 
          156 for     : FOR                   {$$ = macro(LOOP);}
          157         ;
          158 
          159 def     : DEF ID                {$$ = macro(DEF);}
          160         ;
          161 
          162 parlst  : '(' ')'               {$$ = code("");}
          163         | '(' params ')'        {$$ = $2;}
          164         ;
          165 
          166 params  : param                 {$$ = param(NULL, $1);}
          167         | params ',' param      {$$ = param($1, $3);}
          168         ;
          169 
          170 param   : ID                    {$$ = var($1);}
          171         | ID '[' ']'            {$$ = ary($1);}
          172         ;
          173 
          174 autolst :                       {$$ = code("");}
          175         | AUTO locals '\n'      {$$ = $2;}
          176         | AUTO locals ';'       {$$ = $2;}
          177         ;
          178 
          179 locals  : local                 {$$ = local(NULL, $1);}
          180         | locals ',' local      {$$ = local($1, $3);}
          181         ;
          182 
          183 local   : ID                    {$$ = var($1);}
          184         | ID '[' ']'            {$$ = ary($1);}
          185         ;
          186 
          187 arglst  : expr
          188         | ID '[' ']'            {$$ = code("%s", ary($1));}
          189         | expr ',' arglst       {$$ = code("%s%s", $1, $3);}
          190         | ID '[' ']' ',' arglst {$$ = code("%s%s", ary($1), $5);}
          191         ;
          192 
          193 cond    : '(' rel ')'           {$$ = $2;}
          194         ;
          195 
          196 rel     : expr                  {$$ = code("%s 0!=", $1);}
          197         | expr EQ expr          {$$ = code("%s%s=", $1, $3);}
          198         | expr LE expr          {$$ = code("%s%s!<", $1, $3);}
          199         | expr GE expr          {$$ = code("%s%s!>", $1, $3);}
          200         | expr NE expr          {$$ = code("%s%s!=", $1, $3);}
          201         | expr '<' expr         {$$ = code("%s%s>", $1, $3);}
          202         | expr '>' expr         {$$ = code("%s%s<", $1, $3);}
          203         ;
          204 
          205 exprstat: nexpr                 {$$ = code("%s%ss.", $1, code(sflag ? "" : "p"));}
          206         | assign                {$$ = code("%ss.", $1);}
          207         ;
          208 
          209 expr    : nexpr
          210         | assign
          211         ;
          212 
          213 nexpr   : NUMBER                {$$ = code(" %s", code($1));}
          214         | ID                    {$$ = code("l%s", var($1));}
          215         | DOT                   {$$ = code("l.");}
          216         | SCALE                 {$$ = code("K");}
          217         | IBASE                 {$$ = code("I");}
          218         | OBASE                 {$$ = code("O");}
          219         | ID ary                {$$ = code("%s;%s", $2, ary($1));}
          220         | '(' expr ')'          {$$ = $2;}
          221         | ID '(' arglst ')'     {$$ = code("%sl%sx", $3, ftn($1));}
          222         | ID '(' ')'            {$$ = code("l%sx", ftn($1));}
          223         | '-' expr              {$$ = code("0%s-", $2);}
          224         | expr '+' expr         {$$ = code("%s%s+", $1, $3);}
          225         | expr '-' expr         {$$ = code("%s%s-", $1, $3);}
          226         | expr '*' expr         {$$ = code("%s%s*", $1, $3);}
          227         | expr '/' expr         {$$ = code("%s%s/", $1, $3);}
          228         | expr '%' expr         {$$ = code("%s%s%%", $1, $3);}
          229         | expr '^' expr         {$$ = code("%s%s^", $1, $3);}
          230         | LENGTH '(' expr ')'   {$$ = code("%sZ", $3);}
          231         | SQRT '(' expr ')'     {$$ = code("%sv", $3);}
          232         | SCALE '(' expr ')'    {$$ = code("%sX", $3);}
          233         | INCDEC ID             {$$ = code("l%s1%sds%s", var($2), code($1), var($2));}
          234         | INCDEC SCALE          {$$ = code("K1%sk", code($1));}
          235         | INCDEC IBASE          {$$ = code("I1%sdi", code($1));}
          236         | INCDEC OBASE          {$$ = code("O1%sdo", code($1));}
          237         | INCDEC ID ary         {$$ = code("%sdS_;%s1%sdL_:%s", $3, ary($2), code($1), ary($2));}
          238         | ID INCDEC             {$$ = code("l%sd1%ss%s", var($1), code($2), var($1));}
          239         | SCALE INCDEC          {$$ = code("Kd1%sk", code($2));}
          240         | IBASE INCDEC          {$$ = code("Id1%si", code($2));}
          241         | OBASE INCDEC          {$$ = code("Od1%so", code($2));}
          242         | ID ary INCDEC         {$$ = code("%sds.;%sd1%sl.:%s", $2, ary($1), code($3), ary($1));}
          243         ;
          244 
          245 assign  : ID '=' expr           {$$ = code("%sds%s", $3, var($1));}
          246         | SCALE '=' expr        {$$ = code("%sdk", $3);}
          247         | IBASE '=' expr        {$$ = code("%sdi", $3);}
          248         | OBASE '=' expr        {$$ = code("%sdo", $3);}
          249         | ID ary '=' expr       {$$ = code("%sd%s:%s", $4, $2, ary($1));}
          250         | ID EQOP expr          {$$ = code("%sl%s%sds%s", $3, var($1), code($2), var($1));}
          251         | SCALE EQOP expr       {$$ = code("%sK%sdk", $3, code($2));}
          252         | IBASE EQOP expr       {$$ = code("%sI%sdi", $3, code($2));}
          253         | OBASE EQOP expr       {$$ = code("%sO%sdo", $3, code($2));}
          254         | ID ary EQOP expr      {$$ = code("%s%sds.;%s%sdl.:s", $4, $2, ary($1), code($3), ary($1));}
          255         ;
          256 
          257 ary     : '[' expr ']'          {$$ = $2;}
          258         ;
          259 
          260 %%
          261 static int
          262 yyerror(char *s)
          263 {
          264         fprintf(stderr, "bc: %s:%d: %s\n", filename, lineno, s);
          265         nerr++;
          266         longjmp(recover, 1);
          267 }
          268 
          269 static void
          270 writeout(char *s)
          271 {
          272         if (write(1, s, strlen(s)) < 0)
          273                 goto err;
          274         if (write(1, (char[]){'\n'}, 1) < 0)
          275                 goto err;
          276         free(s);
          277         return;
          278         
          279 err:
          280         eprintf("writing to dc:");
          281 }
          282 
          283 static char *
          284 code(char *fmt, ...)
          285 {
          286         char *s, *t;
          287         va_list ap;
          288         int c, len, room;
          289 
          290         va_start(ap, fmt);
          291         room = BUFSIZ;
          292         for (s = buff; *fmt; s += len) {
          293                 len = 1;
          294                 if ((c = *fmt++) != '%')
          295                         goto append;
          296 
          297                 switch (*fmt++) {
          298                 case 'd':
          299                         c = va_arg(ap, int);
          300                         len = snprintf(s, room, "%d", c);
          301                         if (len < 0 || len >= room)
          302                                 goto err;
          303                         break;
          304                 case 'c':
          305                         c = va_arg(ap, int);
          306                         goto append;
          307                 case 's':
          308                         t = va_arg(ap, void *);
          309                         len = strlen(t);
          310                         if (len >= room)
          311                                 goto err;
          312                         memcpy(s, t, len);
          313                         free(t);
          314                         break;
          315                 case '%':
          316                 append:
          317                         if (room <= 1)
          318                                 goto err;
          319                         *s = c;
          320                         break;
          321                 default:
          322                         abort();
          323                 }
          324 
          325                 room -= len;
          326         }
          327         va_end(ap);
          328 
          329         *s = '\0';
          330         return estrdup(buff);
          331 
          332 err:
          333         eprintf("unable to code requested operation\n");
          334         return NULL;
          335 }
          336 
          337 static Macro *
          338 macro(int op)
          339 {
          340         int preop;
          341         Macro *d, *p;
          342 
          343         if (nested == NESTED_MAX)
          344                 yyerror("too much nesting");
          345 
          346         d = &macros[nested];
          347         d->op = op;
          348         d->nested = nested++;
          349 
          350         switch (op) {
          351         case HOME:
          352                 d->id = 0;
          353                 d->flowid = flowid;
          354                 inhome = 1;
          355                 break;
          356         case DEF:
          357                 inhome = 0;
          358                 d->id = funid(yytext);
          359                 d->flowid = macros[0].flowid;
          360                 break;
          361         default:
          362                 assert(nested > 1);
          363                 preop = d[-1].op;
          364                 d->flowid = d[-1].flowid;
          365                 if (preop != HOME && preop != DEF) {
          366                         if (d->flowid == 255)
          367                                 eprintf("too many control flow structures");
          368                         d->flowid++;
          369                 }
          370                 d->id = d->flowid;
          371                 if (!inhome) {
          372                         /* populate reserved id */
          373                         flowid = d->flowid;
          374                         for (p = d; p != macros; --p)
          375                                 p[-1].flowid++;
          376                 }
          377                 break;
          378         }
          379 
          380         return d;
          381 }
          382 
          383 static char *
          384 decl(int type, char *list, char *id)
          385 {
          386         char *i1, *i2;
          387 
          388         i1 = estrdup(id);
          389         i2 = estrdup(id);
          390         free(id);
          391 
          392         if (!unwind)
          393                 unwind = estrdup("");
          394         if (!list)
          395                 list = estrdup("");
          396 
          397         unwind = code("%sL%ss.", unwind, i1);
          398 
          399         return code((type == AUTO) ? "0S%s%s" : "S%s%s", i2, list);
          400 }
          401 
          402 static char *
          403 param(char *list, char *id)
          404 {
          405         return decl(PARAM, list, id);
          406 }
          407 
          408 static char *
          409 local(char *list, char *id)
          410 {
          411         return decl(AUTO, list, id);
          412 }
          413 
          414 static char *
          415 funcode(Macro *d, char *params, char *vars, char *body)
          416 {
          417         char *s;
          418 
          419         s = code("[%s%s%s%s]s%c",
          420                  vars, params,
          421                  body,
          422                  retcode(code(" 0")),
          423                  d->id);
          424         free(unwind);
          425         unwind = NULL;
          426         nested--;
          427         inhome = 0;
          428 
          429 
          430         return s;
          431 }
          432 
          433 static char *
          434 brkcode(void)
          435 {
          436         Macro *d;
          437 
          438         for (d = &macros[nested-1]; d->op != HOME && d->op != LOOP; --d)
          439                 ;
          440         if (d->op == HOME)
          441                 yyerror("break not in for or while");
          442         return code(" %dQ", nested  - d->nested);
          443 }
          444 
          445 static char *
          446 forcode(Macro *d, char *init, char *cmp, char *inc, char *body)
          447 {
          448         char *s;
          449 
          450         s = code("[%s%ss.%s%c]s%c",
          451                  body,
          452                  inc,
          453                  estrdup(cmp),
          454                  d->id, d->id);
          455         writeout(s);
          456 
          457         s = code("%ss.%s%c ", init, cmp, d->id);
          458         nested--;
          459 
          460         return s;
          461 }
          462 
          463 static char *
          464 whilecode(Macro *d, char *cmp, char *body)
          465 {
          466         char *s;
          467 
          468         s = code("[%s%s%c]s%c",
          469                  body,
          470                  estrdup(cmp),
          471                  d->id, d->id);
          472         writeout(s);
          473 
          474         s = code("%s%c ", cmp, d->id);
          475         nested--;
          476 
          477         return s;
          478 }
          479 
          480 static char *
          481 ifcode(Macro *d, char *cmp, char *body)
          482 {
          483         char *s;
          484 
          485         s = code("[%s]s%c", body, d->id);
          486         writeout(s);
          487 
          488         s = code("%s%c ", cmp, d->id);
          489         nested--;
          490 
          491         return s;
          492 }
          493 
          494 static char *
          495 retcode(char *expr)
          496 {
          497         char *s;
          498 
          499         if (nested < 2 || macros[1].op != DEF)
          500                 yyerror("return must be in a function");
          501         return code("%s %s %dQ", expr, estrdup(unwind), nested - 1);
          502 }
          503 
          504 static char *
          505 ary(char *s)
          506 {
          507         return code("%c", toupper(s[0]));
          508 }
          509 
          510 static char *
          511 ftn(char *s)
          512 {
          513         return code("%c", funid(s));
          514 }
          515 
          516 static char *
          517 var(char *s)
          518 {
          519         return code(s);
          520 }
          521 
          522 static void
          523 quit(void)
          524 {
          525         exit(nerr > 0 ? 1 : 0);
          526 }
          527 
          528 static void
          529 skipspaces(void)
          530 {
          531         int ch;
          532 
          533         while (isspace(ch = getc(filep))) {
          534                 if (ch == '\n') {
          535                         lineno++;
          536                         break;
          537                 }
          538         }
          539         ungetc(ch, filep);
          540 }
          541 
          542 static int
          543 iden(int ch)
          544 {
          545         static struct keyword {
          546                 char *str;
          547                 int token;
          548         } keywords[] = {
          549                 {"define", DEF},
          550                 {"break", BREAK},
          551                 {"quit", QUIT},
          552                 {"length", LENGTH},
          553                 {"return", RETURN},
          554                 {"for", FOR},
          555                 {"if", IF},
          556                 {"while", WHILE},
          557                 {"sqrt", SQRT},
          558                 {"scale", SCALE},
          559                 {"ibase", IBASE},
          560                 {"obase", OBASE},
          561                 {"auto", AUTO},
          562                 {"print", PRINT},
          563                 {NULL}
          564         };
          565         struct keyword *p;
          566         char *bp;
          567 
          568         ungetc(ch, filep);
          569         for (bp = yytext; bp < &yytext[BUFSIZ]; ++bp) {
          570                 ch = getc(filep);
          571                 if (!islower(ch))
          572                         break;
          573                 *bp = ch;
          574         }
          575 
          576         if (bp == &yytext[BUFSIZ])
          577                 yyerror("too long token");
          578         *bp = '\0';
          579         ungetc(ch, filep);
          580 
          581         if (strlen(yytext) == 1) {
          582                 strcpy(yylval.id, yytext);
          583                 return ID;
          584         }
          585 
          586         for (p = keywords; p->str && strcmp(p->str, yytext); ++p)
          587                 ;
          588 
          589         if (!p->str)
          590                 yyerror("invalid keyword");
          591 
          592         return p->token;
          593 }
          594 
          595 static char *
          596 digits(char *bp)
          597 {
          598         int ch;
          599         char *digits = DIGITS, *p;
          600 
          601         while (bp < &yytext[BUFSIZ]) {
          602                 ch = getc(filep);
          603                 p = strchr(digits, ch);
          604                 if (!p)
          605                         break;
          606                 *bp++ = ch;
          607         }
          608 
          609         if (bp == &yytext[BUFSIZ])
          610                 return NULL;
          611         ungetc(ch, filep);
          612 
          613         return bp;
          614 }
          615 
          616 static int
          617 number(int ch)
          618 {
          619         int d;
          620         char *bp;
          621 
          622         ungetc(ch, filep);
          623         if ((bp = digits(yytext)) == NULL)
          624                 goto toolong;
          625 
          626         if ((ch = getc(filep)) != '.') {
          627                 ungetc(ch, filep);
          628                 goto end;
          629         }
          630         *bp++ = '.';
          631 
          632         if ((bp = digits(bp)) == NULL)
          633                 goto toolong;
          634 
          635 end:
          636         if (bp ==  &yytext[BUFSIZ])
          637                 goto toolong;
          638         *bp = '\0';
          639         yylval.str = yytext;
          640 
          641         return NUMBER;
          642 
          643 toolong:
          644         yyerror("too long number");
          645         return 0;
          646 }
          647 
          648 static int
          649 string(int ch)
          650 {
          651         char *bp;
          652 
          653         for (bp = yytext; bp < &yytext[BUFSIZ]; ++bp) {
          654                 if ((ch = getc(filep)) == '"')
          655                         break;
          656                 *bp = ch;
          657         }
          658 
          659         if (bp == &yytext[BUFSIZ])
          660                 yyerror("too long string");
          661         *bp = '\0';
          662         yylval.str = estrdup(yytext);
          663 
          664         return STRING;
          665 }
          666 
          667 static int
          668 follow(int next, int yes, int no)
          669 {
          670         int ch;
          671 
          672         ch = getc(filep);
          673         if (ch == next)
          674                 return yes;
          675         ungetc(ch, filep);
          676         return no;
          677 }
          678 
          679 static int
          680 operand(int ch)
          681 {
          682         int peekc;
          683 
          684         switch (ch) {
          685         case '\n':
          686         case '{':
          687         case '}':
          688         case '[':
          689         case ']':
          690         case '(':
          691         case ')':
          692         case ',':
          693         case ';':
          694                 return ch;
          695         case '.':
          696                 peekc = ungetc(getc(filep), filep);
          697                 if (strchr(DIGITS, peekc))
          698                         return number(ch);
          699                 return DOT;
          700         case '"':
          701                 return string(ch);
          702         case '*':
          703                 yylval.str = "*";
          704                 return follow('=', EQOP, '*');
          705         case '/':
          706                 yylval.str = "/";
          707                 return follow('=', EQOP, '/');
          708         case '%':
          709                 yylval.str = "%";
          710                 return follow('=', EQOP, '%');
          711         case '=':
          712                 return follow('=', EQ, '=');
          713         case '+':
          714         case '-':
          715                 yylval.str = (ch == '+') ? "+" : "-";
          716                 if (follow('=', EQOP, ch) != ch)
          717                         return EQOP;
          718                 return follow(ch, INCDEC, ch);
          719         case '^':
          720                 yylval.str = "^";
          721                 return follow('=', EQOP, '^');
          722         case '<':
          723                 return follow('=', LE, '<');
          724         case '>':
          725                 return follow('=', GE, '>');
          726         case '!':
          727                 if (getc(filep) == '=')
          728                         return NE;
          729         default:
          730                 yyerror("invalid operand");
          731                 return 0;
          732         }
          733 }
          734 
          735 static void
          736 comment(void)
          737 {
          738         int c;
          739 
          740         for (;;) {
          741                 while ((c = getc(filep)) != '*') {
          742                         if (c == '\n')
          743                                 lineno++;
          744                 }
          745                 if ((c = getc(filep)) == '/')
          746                         break;
          747                 ungetc(c, filep);
          748         }
          749 }
          750 
          751 static int
          752 yylex(void)
          753 {
          754         int peekc, ch;
          755 
          756 repeat:
          757         skipspaces();
          758 
          759         ch = getc(filep);
          760         if (ch == EOF) {
          761                 return EOF;
          762         } else if (!isascii(ch)) {
          763                 yyerror("invalid input character");
          764         } else if (islower(ch)) {
          765                 return iden(ch);
          766         } else if (strchr(DIGITS, ch)) {
          767                 return number(ch);
          768         } else {
          769                 if (ch == '/') {
          770                         peekc = getc(filep);
          771                         if (peekc == '*') {
          772                                 comment();
          773                                 goto repeat;
          774                         }
          775                         ungetc(peekc, filep);
          776                 }
          777                 return operand(ch);
          778         }
          779 
          780         return 0;
          781 }
          782 
          783 static void
          784 spawn(void)
          785 {
          786         int fds[2];
          787         char errmsg[] = "bc:error execing dc\n";
          788 
          789         if (pipe(fds) < 0)
          790                 eprintf("creating pipe:");
          791 
          792         switch (fork()) {
          793         case -1:
          794                 eprintf("forking dc:");
          795         case 0:
          796                 close(1);
          797                 dup(fds[1]);
          798                 close(fds[0]);
          799                 close(fds[1]);
          800                 break;
          801         default:
          802                 close(0);
          803                 dup(fds[0]);
          804                 close(fds[0]);
          805                 close(fds[1]);
          806                 execlp("dc", "dc", (char *) NULL);
          807 
          808                 /* it shouldn't happen */
          809                 write(3, errmsg, sizeof(errmsg)-1);
          810                 _Exit(2);
          811         }
          812 }
          813 
          814 static void
          815 run(void)
          816 {
          817         if (setjmp(recover)) {
          818                 if (ferror(filep))
          819                         eprintf("%s:", filename);
          820                 if (feof(filep))
          821                         return;
          822         }
          823         yyparse();
          824 }
          825 
          826 static void
          827 bc(char *fname)
          828 {
          829         Macro *d;
          830 
          831         lineno = 1;
          832         nested = 0;
          833 
          834         macro(HOME);
          835         if (!fname) {
          836                 filename = "<stdin>";
          837                 filep = stdin;
          838         } else {
          839                 filename = fname;
          840                 if ((filep = fopen(fname, "r")) == NULL)
          841                         eprintf("%s:", fname);
          842         }
          843 
          844         run();
          845         fclose(filep);
          846 }
          847 
          848 static void
          849 usage(void)
          850 {
          851         eprintf("usage: %s [-cdls]\n", argv0);
          852 }
          853 
          854 int
          855 main(int argc, char *argv[])
          856 {
          857         ARGBEGIN {
          858         case 'c':
          859                 cflag = 1;
          860                 break;
          861         case 'd':
          862                 dflag = 1;
          863                 yydebug = 3;
          864                 break;
          865         case 'l':
          866                 lflag = 1;
          867                 break;
          868         case 's':
          869                 sflag = 1;
          870                 break;
          871         default:
          872                 usage();
          873         } ARGEND
          874 
          875         yytext = malloc(BUFSIZ);
          876         buff = malloc(BUFSIZ);
          877         if (!yytext || !buff)
          878                 eprintf("out of memory\n");
          879         flowid = 128;
          880 
          881         if (!cflag)
          882                 spawn();
          883         if (lflag)
          884                 bc(PREFIX "/bc.library");
          885 
          886         while (*argv)
          887                 bc(*argv++);
          888         bc(NULL);
          889 
          890         quit();
          891 }