Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

%{
        #include        <u.h>
        #include        <libc.h>
        #include        <bio.h>

        #define bsp_max 5000

        Biobuf  *in;
        Biobuf  bstdin;
        Biobuf  bstdout;
        char    cary[1000];
        char*   cp = { cary };
        char    string[1000];
        char*   str = { string };
        int     crs = 128;
        int     rcrs = 128;     /* reset crs */
        int     bindx = 0;
        int     lev = 0;
        int     ln;
        char*   ttp;
        char*   ss = "";
        int     bstack[10] = { 0 };
        char*   numb[15] =
        {
                " 0", " 1", " 2", " 3", " 4", " 5",
                " 6", " 7", " 8", " 9", " 10", " 11",
                " 12", " 13", " 14"
        };
        char*   pre;
        char*   post;

        long    peekc = -1;
        int     sargc;
        int     ifile;
        char**  sargv;

        char    *funtab[] =
        {
                "<1>","<2>","<3>","<4>","<5>",
                "<6>","<7>","<8>","<9>","<10>",
                "<11>","<12>","<13>","<14>","<15>",
                "<16>","<17>","<18>","<19>","<20>",
                "<21>","<22>","<23>","<24>","<25>",
                "<26>"
        };
        char    *atab[] =
        {
                "<221>","<222>","<223>","<224>","<225>",
                "<226>","<227>","<228>","<229>","<230>",
                "<231>","<232>","<233>","<234>","<235>",
                "<236>","<237>","<238>","<239>","<240>",
                "<241>","<242>","<243>","<244>","<245>",
                "<246>"
        };
        char*   letr[26] =
        {
                "a","b","c","d","e","f","g","h","i","j",
                "k","l","m","n","o","p","q","r","s","t",
                "u","v","w","x","y","z"
        };
        char*   dot = { "." };
        char*   bspace[bsp_max];
        char**  bsp_nxt = bspace;
        int     bdebug = 0;
        int     lflag;
        int     cflag;
        int     sflag;

        char*   bundle(int, ...);
        void    conout(char*, char*);
        int     cpeek(int, int, int);
        int     getch(void);
        char*   geta(char*);
        char*   getf(char*);
        void    getout(void);
        void    output(char*);
        void    pp(char*);
        void    routput(char*);
        void    tp(char*);
        void    yyerror(char*, ...);
        int     yyparse(void);

        typedef void*   pointer;
        #pragma varargck        type    "lx"    pointer

%}
%union
{
        char*   cptr;
        int     cc;
}

%type   <cptr>  pstat stat stat1 def slist dlets e ase nase
%type   <cptr>  slist re fprefix cargs eora cons constant lora
%type   <cptr>  crs

%token  <cptr>  LETTER EQOP _AUTO DOT
%token  <cc>    DIGIT SQRT LENGTH _IF FFF EQ
%token  <cc>    _PRINT _WHILE _FOR NE LE GE INCR DECR
%token  <cc>    _RETURN _BREAK _DEFINE BASE OBASE SCALE
%token  <cc>    QSTR ERROR

%right  '=' EQOP
%left   '+' '-'
%left   '*' '/' '%'
%right  '^'
%left   UMINUS

%%
start:
        start stuff
|       stuff

stuff:
        pstat tail
        {
                output($1);
        }
|       def dargs ')' '{' dlist slist '}'
        {
                ttp = bundle(6, pre, $6, post , "0", numb[lev], "Q");
                conout(ttp, (char*)$1);
                rcrs = crs;
                output("");
                lev = bindx = 0;
        }

dlist:
        tail
|       dlist _AUTO dlets tail

stat:
        stat1
|       nase
        {
                if(sflag)
                        bundle(2, $1, "s.");
        }

pstat:
        stat1
        {
                if(sflag)
                        bundle(2, $1, "0");
        }
|       nase
        {
                if(!sflag)
                        bundle(2, $1, "ps.");
        }

stat1:
        {
                bundle(1, "");
        }
|       ase
        {
                bundle(2, $1, "s.");
        }
|       SCALE '=' e
        {
                bundle(2, $3, "k");
        }
|       SCALE EQOP e
        {
                bundle(4, "K", $3, $2, "k");
        }
|       BASE '=' e
        {
                bundle(2, $3, "i");
        }
|       BASE EQOP e
        {
                bundle(4, "I", $3, $2, "i");
        }
|       OBASE '=' e
        {
                bundle(2, $3, "o");
        }
|       OBASE EQOP e
        {
                bundle(4, "O", $3, $2, "o");
        }
|       QSTR
        {
                bundle(3, "[", $1, "]P");
        }
|       _BREAK
        {
                bundle(2, numb[lev-bstack[bindx-1]], "Q");
        }
|       _PRINT e
        {
                bundle(2, $2, "ps.");
        }
|       _RETURN e
        {
                bundle(4, $2, post, numb[lev], "Q");
        }
|       _RETURN
        {
                bundle(4, "0", post, numb[lev], "Q");
        }
|       '{' slist '}'
        {
                $$ = $2;
        }
|       FFF
        {
                bundle(1, "fY");
        }
|       _IF crs BLEV '(' re ')' stat
        {
                conout($7, $2);
                bundle(3, $5, $2, " ");
        }
|       _WHILE crs '(' re ')' stat BLEV
        {
                bundle(3, $6, $4, $2);
                conout($$, $2);
                bundle(3, $4, $2, " ");
        }
|       fprefix crs re ';' e ')' stat BLEV
        {
                bundle(5, $7, $5, "s.", $3, $2);
                conout($$, $2);
                bundle(5, $1, "s.", $3, $2, " ");
        }
|       '~' LETTER '=' e
        {
                bundle(3, $4, "S", $2);
        }

fprefix:
        _FOR '(' e ';'
        {
                $$ = $3;
        }

BLEV:
        =
        {
                --bindx;
        }

slist:
        stat
|       slist tail stat
        {
                bundle(2, $1, $3);
        }

tail:
        '\n'
        {
                ln++;
        }
|       ';'

re:
        e EQ e
        {
                $$ = bundle(3, $1, $3, "=");
        }
|       e '<' e
        {
                bundle(3, $1, $3, ">");
        }
|       e '>' e
        {
                bundle(3, $1, $3, "<");
        }
|       e NE e
        {
                bundle(3, $1, $3, "!=");
        }
|       e GE e
        {
                bundle(3, $1, $3, "!>");
        }
|       e LE e
        {
                bundle(3, $1, $3, "!<");
        }
|       e
        {
                bundle(2, $1, " 0!=");
        }

nase:
        '(' e ')'
        {
                $$ = $2;
        }
|       cons
        {
                bundle(3, " ", $1, " ");
        }
|       DOT cons
        {
                bundle(3, " .", $2, " ");
        }
|       cons DOT cons
        {
                bundle(5, " ", $1, ".", $3, " ");
        }
|       cons DOT
        {
                bundle(4, " ", $1, ".", " ");
        }
|       DOT
        {
                $<cptr>$ = "l.";
        }
|       LETTER '[' e ']'
        {
                bundle(3, $3, ";", geta($1));
        }
|       LETTER INCR
        {
                bundle(4, "l", $1, "d1+s", $1);
        }
|       INCR LETTER
        {
                bundle(4, "l", $2, "1+ds", $2);
        }
|       DECR LETTER
        {
                bundle(4, "l", $2, "1-ds", $2);
        }
|       LETTER DECR
        {
                bundle(4, "l", $1, "d1-s", $1);
        }
|       LETTER '[' e ']' INCR
        {
                bundle(7, $3, ";", geta($1), "d1+" ,$3, ":" ,geta($1));
        }
|       INCR LETTER '[' e ']'
        {
                bundle(7, $4, ";", geta($2), "1+d", $4, ":", geta($2));
        }
|       LETTER '[' e ']' DECR
        {
                bundle(7, $3, ";", geta($1), "d1-", $3, ":", geta($1));
        }
|       DECR LETTER '[' e ']'
        {
                bundle(7, $4, ";", geta($2), "1-d", $4, ":" ,geta($2));
        }
|       SCALE INCR
        {
                bundle(1, "Kd1+k");
        }
|       INCR SCALE
        {
                bundle(1, "K1+dk");
        }
|       SCALE DECR
        {
                bundle(1, "Kd1-k");
        }
|       DECR SCALE
        {
                bundle(1, "K1-dk");
        }
|       BASE INCR
        {
                bundle(1, "Id1+i");
        }
|       INCR BASE
        {
                bundle(1, "I1+di");
        }
|       BASE DECR
        {
                bundle(1, "Id1-i");
        }
|       DECR BASE
        {
                bundle(1, "I1-di");
        }
|       OBASE INCR
        {
                bundle(1, "Od1+o");
        }
|       INCR OBASE
        {
                bundle(1, "O1+do");
        }
|       OBASE DECR
        {
                bundle(1, "Od1-o");
        }
|       DECR OBASE
        {
                bundle(1, "O1-do");
        }
|       LETTER '(' cargs ')'
        {
                bundle(4, $3, "l", getf($1), "x");
        }
|       LETTER '(' ')'
        {
                bundle(3, "l", getf($1), "x");
        }
|       LETTER = {
                bundle(2, "l", $1);
        }
|       LENGTH '(' e ')'
        {
                bundle(2, $3, "Z");
        }
|       SCALE '(' e ')'
        {
                bundle(2, $3, "X");
        }
|       '?'
        {
                bundle(1, "?");
        }
|       SQRT '(' e ')'
        {
                bundle(2, $3, "v");
        }
|       '~' LETTER
        {
                bundle(2, "L", $2);
        }
|       SCALE
        {
                bundle(1, "K");
        }
|       BASE
        {
                bundle(1, "I");
        }
|       OBASE
        {
                bundle(1, "O");
        }
|       '-' e
        {
                bundle(3, " 0", $2, "-");
        }
|       e '+' e
        {
                bundle(3, $1, $3, "+");
        }
|       e '-' e
        {
                bundle(3, $1, $3, "-");
        }
|       e '*' e
        {
                bundle(3, $1, $3, "*");
        }
|       e '/' e
        {
                bundle(3, $1, $3, "/");
        }
|       e '%' e
        {
                bundle(3, $1, $3, "%%");
        }
|       e '^' e
        {
                bundle(3, $1, $3, "^");
        }

ase:
        LETTER '=' e
        {
                bundle(3, $3, "ds", $1);
        }
|       LETTER '[' e ']' '=' e
        {
                bundle(5, $6, "d", $3, ":", geta($1));
        }
|       LETTER EQOP e
        {
                bundle(6, "l", $1, $3, $2, "ds", $1);
        }
|       LETTER '[' e ']' EQOP e
        {
                bundle(9, $3, ";", geta($1), $6, $5, "d", $3, ":", geta($1));
        }

e:
        ase
|       nase

cargs:
        eora
|       cargs ',' eora
        {
                bundle(2, $1, $3);
        }

eora:
        e
|       LETTER '[' ']'
        {
                bundle(2, "l", geta($1));
        }

cons:
        constant
        {
                *cp++ = 0;
        }

constant:
        '_'
        {
                $<cptr>$ = cp;
                *cp++ = '_';
        }
|       DIGIT
        {
                $<cptr>$ = cp;
                *cp++ = $1;
        }
|       constant DIGIT
        {
                *cp++ = $2;
        }

crs:
        =
        {
                $$ = cp;
                *cp++ = '<';
                *cp++ = crs/100+'0';
                *cp++ = (crs%100)/10+'0';
                *cp++ = crs%10+'0';
                *cp++ = '>';
                *cp++ = '\0';
                if(crs++ >= 220) {
                        yyerror("program too big");
                        getout();
                }
                bstack[bindx++] = lev++;
        }

def:
        _DEFINE LETTER '('
        {
                $$ = getf($2);
                pre = (char*)"";
                post = (char*)"";
                lev = 1;
                bindx = 0;
                bstack[bindx] = 0;
        }

dargs:
|       lora
        {
                pp((char*)$1);
        }
|       dargs ',' lora
        {
                pp((char*)$3);
        }

dlets:
        lora
        {
                tp((char*)$1);
        }
|       dlets ',' lora
        {
                tp((char*)$3);
        }

lora:
        LETTER
        {
                $<cptr>$=$1;
        }
|       LETTER '[' ']'
        {
                $$ = geta($1);
        }

%%

int
yylex(void)
{
        int c, ch;

restart:
        c = getch();
        peekc = -1;
        while(c == ' ' || c == '\t')
                c = getch();
        if(c == '\\') {
                getch();
                goto restart;
        }
        if(c >= 'a' && c <= 'z') {
                /* look ahead to look for reserved words */
                peekc = getch();
                if(peekc >= 'a' && peekc <= 'z') { /* must be reserved word */
                        if(c=='p' && peekc=='r') {
                                c = _PRINT;
                                goto skip;
                        }
                        if(c=='i' && peekc=='f') {
                                c = _IF;
                                goto skip;
                        }
                        if(c=='w' && peekc=='h') {
                                c = _WHILE;
                                goto skip;
                        }
                        if(c=='f' && peekc=='o') {
                                c = _FOR;
                                goto skip;
                        }
                        if(c=='s' && peekc=='q') {
                                c = SQRT;
                                goto skip;
                        }
                        if(c=='r' && peekc=='e') {
                                c = _RETURN;
                                goto skip;
                        }
                        if(c=='b' && peekc=='r') {
                                c = _BREAK;
                                goto skip;
                        }
                        if(c=='d' && peekc=='e') {
                                c = _DEFINE;
                                goto skip;
                        }
                        if(c=='s' && peekc=='c') {
                                c = SCALE;
                                goto skip;
                        }
                        if(c=='b' && peekc=='a') {
                                c = BASE;
                                goto skip;
                        }
                        if(c=='i' && peekc=='b') {
                                c = BASE;
                                goto skip;
                        }
                        if(c=='o' && peekc=='b') {
                                c = OBASE;
                                goto skip;
                        }
                        if(c=='d' && peekc=='i') {
                                c = FFF;
                                goto skip;
                        }
                        if(c=='a' && peekc=='u') {
                                c = _AUTO;
                                goto skip;
                        }
                        if(c=='l' && peekc=='e') {
                                c = LENGTH;
                                goto skip;
                        }
                        if(c=='q' && peekc=='u')
                                getout();
                        /* could not be found */
                        return ERROR;

                skip:   /* skip over rest of word */
                        peekc = -1;
                        for(;;) {
                                ch = getch();
                                if(ch < 'a' || ch > 'z')
                                        break;
                        }
                        peekc = ch;
                        return c;
                }

                /* usual case; just one single letter */
                yylval.cptr = letr[c-'a'];
                return LETTER;
        }
        if((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F')) {
                yylval.cc = c;
                return DIGIT;
        }
        switch(c) {
        case '.':
                return DOT;
        case '*':
                yylval.cptr = "*";
                return cpeek('=', EQOP, c);
        case '%':
                yylval.cptr = "%%";
                return cpeek('=', EQOP, c);
        case '^':
                yylval.cptr = "^";
                return cpeek('=', EQOP, c);
        case '+':
                ch = cpeek('=', EQOP, c);
                if(ch == EQOP) {
                        yylval.cptr = "+";
                        return ch;
                }
                return cpeek('+', INCR, c);
        case '-':
                ch = cpeek('=', EQOP, c);
                if(ch == EQOP) {
                        yylval.cptr = "-";
                        return ch;
                }
                return cpeek('-', DECR, c);
        case '=':
                return cpeek('=', EQ, '=');
        case '<':
                return cpeek('=', LE, '<');
        case '>':
                return cpeek('=', GE, '>');
        case '!':
                return cpeek('=', NE, '!');
        case '/':
                ch = cpeek('=', EQOP, c);
                if(ch == EQOP) {
                        yylval.cptr = "/";
                        return ch;
                }
                if(peekc == '*') {
                        peekc = -1;
                        for(;;) {
                                ch = getch();
                                if(ch == '*') {
                                        peekc = getch();
                                        if(peekc == '/') {
                                                peekc = -1;
                                                goto restart;
                                        }
                                }
                        }
                }
                return c;
        case '"':
                yylval.cptr = str;
                while((c=getch()) != '"'){
                        *str++ = c;
                        if(str >= &string[999]){
                                yyerror("string space exceeded");
                                getout();
                        }
                }
                *str++ = 0;
                return QSTR;
        default:
                return c;
        }
}

int
cpeek(int c, int yes, int no)
{

        peekc = getch();
        if(peekc == c) {
                peekc = -1;
                return yes;
        }
        return no;
}

int
getch(void)
{
        long ch;

loop:
        ch = peekc;
        if(ch < 0){
                if(in == 0)
                        ch = -1;
                else
                        ch = Bgetc(in);
        }
        peekc = -1;
        if(ch >= 0)
                return ch;
        ifile++;
        if(ifile > sargc) {
                if(ifile >= sargc+2)
                        getout();
                in = &bstdin;
                Binit(in, 0, OREAD);
                ln = 0;
                goto loop;
        }
        if(in)
                Bterm(in);
        if((in = Bopen(sargv[ifile], OREAD)) != 0){
                ln = 0;
                ss = sargv[ifile];
                goto loop;
        }
        yyerror("cannot open input file");
        return 0;               /* shut up ken */
}

char*
bundle(int a, ...)
{
        int i;
        char **q;
        va_list arg;
        
        i = a;
        va_start(arg, a);
        q = bsp_nxt;
        if(bdebug)
                fprint(2, "bundle %d elements at %lx\n", i, q);
        while(i-- > 0) {
                if(bsp_nxt >= &bspace[bsp_max])
                        yyerror("bundling space exceeded");
                *bsp_nxt++ = va_arg(arg, char*);
        }
        *bsp_nxt++ = 0;
        va_end(arg);
        yyval.cptr = (char*)q;
        return (char*)q;
}

void
routput(char *p)
{
        char **pp;
        
        if(bdebug)
                fprint(2, "routput(%lx)\n", p);
        if((char**)p >= &bspace[0] && (char**)p < &bspace[bsp_max]) {
                /* part of a bundle */
                pp = (char**)p;
                while(*pp != 0)
                        routput(*pp++);
        } else
                Bprint(&bstdout, p);    /* character string */
}

void
output(char *p)
{
        routput(p);
        bsp_nxt = &bspace[0];
        Bprint(&bstdout, "\n");
        Bflush(&bstdout);
        cp = cary;
        crs = rcrs;
}

void
conout(char *p, char *s)
{
        Bprint(&bstdout, "[");
        routput(p);
        Bprint(&bstdout, "]s%s\n", s);
        Bflush(&bstdout);
        lev--;
}

void
yyerror(char *s, ...)
{
        if(ifile > sargc)
                ss = "stdin";
        Bprint(&bstdout, "c[%s:%d %s]pc\n", ss, ln+1, s);
        Bflush(&bstdout);
        cp = cary;
        crs = rcrs;
        bindx = 0;
        lev = 0;
        bsp_nxt = &bspace[0];
}

void
pp(char *s)
{
        /* puts the relevant stuff on pre and post for the letter s */
        bundle(3, "S", s, pre);
        pre = yyval.cptr;
        bundle(4, post, "L", s, "s.");
        post = yyval.cptr;
}

void
tp(char *s)
{
        /* same as pp, but for temps */
        bundle(3, "0S", s, pre);
        pre = yyval.cptr;
        bundle(4, post, "L", s, "s.");
        post = yyval.cptr;
}

void
yyinit(int argc, char **argv)
{
        Binit(&bstdout, 1, OWRITE);
        sargv = argv;
        sargc = argc - 1;
        if(sargc == 0) {
                in = &bstdin;
                Binit(in, 0, OREAD);
        } else if((in = Bopen(sargv[1], OREAD)) == 0)
                yyerror("cannot open input file");
        ifile = 1;
        ln = 0;
        ss = sargv[1];
}

void
getout(void)
{
        Bprint(&bstdout, "q");
        Bflush(&bstdout);
        exits(0);
}

char*
getf(char *p)
{
        return funtab[*p - 'a'];
}

char*
geta(char *p)
{
        return atab[*p - 'a'];
}

void
main(int argc, char **argv)
{
        int p[2];

        while(argc > 1 && *argv[1] == '-') {
                switch(argv[1][1]) {
                case 'd':
                        bdebug++;
                        break;
                case 'c':
                        cflag++;
                        break;
                case 'l':
                        lflag++;
                        break;
                case 's':
                        sflag++;
                        break;
                default:
                        fprint(2, "Usage: bc [-cdls] [file ...]\n");
                        exits("usage");
                }
                argc--;
                argv++;
        }
        if(lflag) {
                argv--;
                argc++;
                argv[1] = "/sys/lib/bclib";
        }
        if(cflag) {
                yyinit(argc, argv);
                for(;;)
                        yyparse();
                /* not reached */
        }
        pipe(p);
        if(fork() == 0) {
                dup(p[1], 1);
                close(p[0]);
                close(p[1]);
                yyinit(argc, argv);
                for(;;)
                        yyparse();
        }
        dup(p[0], 0);
        close(p[0]);
        close(p[1]);
        execl("/bin/dc", "dc", nil);
}