%{
%}
%{
#include <stdio.h>
#include <stdarg.h>
#include <limits.h>
#include <libintl.h>
#include <locale.h>
#include <signal.h>
static void getout(int) __NORETURN;
static int *bundle(int, ...);
static void usage(void);
int cpeek(char, int, char, int, char);
int yyerror(const char *);
#define STRING_SIZE (BC_STRING_MAX + 3)
FILE *in;
char cary[LINE_MAX+1];
char *cp = { cary };
char *cpend = &cary[LINE_MAX];
char string[STRING_SIZE];
char *str = { string };
int crs = '0';
int rcrs = '0';
int bindx = 0;
int lev = 0;
int ln;
int *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"
};
int *pre, *post;
int interact = 0;
%}
%union {
int *iptr;
char *cptr;
int cc;
}
%start start;
%type <iptr> stat def slist dlets e
%type <iptr> re fprefix cargs eora cons constant lora
%right '='
%left '+' '-'
%left '*' '/' '%'
%right '^'
%left UMINUS
%token <cptr> LETTER
%type <cptr> EQOP CRS
%token <cc> DIGIT SQRT LENGTH _IF FFF EQ
%token <cc> _WHILE _FOR NE LE GE INCR DECR
%token <cc> _RETURN _BREAK _DEFINE BASE OBASE SCALE
%token <cc> EQPL EQMI EQMUL EQDIV EQREM EQEXP
%token <cptr> _AUTO DOT
%token <cc> QSTR
%%
start :
| start stat tail
{
output($2);
}
| start def dargs ')' '{' dlist slist '}'
{
ttp = bundle(6, pre, $7, post, "0", numb[lev], "Q");
conout(ttp, (char *)$2);
rcrs = crs;
output((int *)"");
lev = bindx = 0;
}
;
dlist : tail
| dlist _AUTO dlets tail
;
stat : e
{
bundle(2, $1, "ps.");
}
|
{
bundle(1, "");
}
| QSTR
{
bundle(3, "[", $1, "]P");
}
| LETTER '=' e
{
bundle(3, $3, "s", $1);
}
| LETTER '[' e ']' '=' e
{
bundle(4, $6, $3, ":", geta($1));
}
| LETTER EQOP e
{
bundle(6, "l", $1, $3, $2, "s", $1);
}
| LETTER '[' e ']' EQOP e
{
bundle(8, $3, ";", geta($1), $6, $5, $3, ":", geta($1));
}
| _BREAK
{
bundle(2, numb[lev-bstack[bindx-1]], "Q");
}
| _RETURN '(' e ')'
{
bundle(4, $3, post, numb[lev], "Q");
}
| _RETURN '(' ')'
{
bundle(4, "0", post, numb[lev], "Q");
}
| _RETURN
{
bundle(4, "0", post, numb[lev], "Q");
}
| 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");
}
| '{' slist '}'
{
$$ = $2;
}
| FFF
{
bundle(1, "fY");
}
| error
{
bundle(1, "c");
}
| _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);
}
;
EQOP : EQPL
{
$$ = "+";
}
| EQMI
{
$$ = "-";
}
| EQMUL
{
$$ = "*";
}
| EQDIV
{
$$ = "/";
}
| EQREM
{
$$ = "%%";
}
| EQEXP
{
$$ = "^";
}
;
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!=");
}
;
e : e '+' e
{
bundle(3, $1, $3, "+");
}
| e '-' e
{
bundle(3, $1, $3, "-");
}
| '-' e %prec UMINUS
{
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, "^");
}
| 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");
}
| cons
{
bundle(2, " ", $1);
}
| DOT cons
{
bundle(2, " .", $2);
}
| cons DOT cons
{
bundle(4, " ", $1, ".", $3);
}
| cons DOT
{
bundle(3, " ", $1, ".");
}
| DOT
{
$<cptr>$ = "l.";
}
| LETTER
{
bundle(2, "l", $1);
}
| LETTER '=' e
{
bundle(3, $3, "ds", $1);
}
| LETTER EQOP e %prec '='
{
bundle(6, "l", $1, $3, $2, "ds", $1);
}
| LETTER '[' e ']' '=' e
{
bundle(5, $6, "d", $3, ":", geta($1));
}
| LETTER '[' e ']' EQOP e
{
bundle(9, $3, ";", geta($1), $6, $5, "d", $3, ":",
geta($1));
}
| LENGTH '(' e ')'
{
bundle(2, $3, "Z");
}
| SCALE '(' e ')'
{
bundle(2, $3, "X");
}
| '(' e ')'
{
$$ = $2;
}
| '?'
{
bundle(1, "?");
}
| SQRT '(' e ')'
{
bundle(2, $3, "v");
}
| '~' LETTER
{
bundle(2, "L", $2);
}
| SCALE '=' e
{
bundle(2, $3, "dk");
}
| SCALE EQOP e %prec '='
{
bundle(4, "K", $3, $2, "dk");
}
| BASE '=' e
{
bundle(2, $3, "di");
}
| BASE EQOP e %prec '='
{
bundle(4, "I", $3, $2, "di");
}
| OBASE '=' e
{
bundle(2, $3, "do");
}
| OBASE EQOP e %prec '='
{
bundle(4, "O", $3, $2, "do");
}
| SCALE
{
bundle(1, "K");
}
| BASE
{
bundle(1, "I");
}
| OBASE
{
bundle(1, "O");
}
;
cargs : eora
| cargs ',' eora
{
bundle(2, $1, $3);
}
;
eora : e
| LETTER '[' ']'
{
bundle(2, "l", geta($1));
}
;
cons : constant
{
*cp++ = '\0';
}
constant: '_'
{
checkbuffer();
$<cptr>$ = cp;
*cp++ = '_';
}
| DIGIT
{
checkbuffer();
$<cptr>$ = cp;
*cp++ = $1;
}
| constant DIGIT
{
checkbuffer();
*cp++ = $2;
}
;
CRS :
{
checkbuffer();
$$ = cp;
*cp++ = crs++;
*cp++ = '\0';
if (crs == '[')
crs += 3;
if (crs == 'a')
crs = '{';
if (crs >= 0241) {
(void) yyerror("program too big");
getout(1);
}
bstack[bindx++] = lev++;
}
;
def : _DEFINE LETTER '('
{
$$ = getf($2);
pre = (int *)"";
post = (int *)"";
lev = 1;
bstack[bindx = 0] = 0;
}
;
dargs :
| lora
{
pp($1);
}
| dargs ',' lora
{
pp($3);
}
;
dlets : lora
{
tp($1);
}
| dlets ',' lora
{
tp($3);
}
;
lora : LETTER
{
$<cptr>$ = $1;
}
| LETTER '[' ']'
{
$$ = geta($1);
}
;
%%
#define error 256
int peekc = -1;
int ifile;
int sargc;
char **sargv;
char funtab[52] = {
01, 0, 02, 0, 03, 0, 04, 0, 05, 0, 06, 0, 07, 0,
010, 0, 011, 0, 012, 0, 013, 0, 014, 0, 015, 0, 016, 0, 017, 0,
020, 0, 021, 0, 022, 0, 023, 0, 024, 0, 025, 0, 026, 0, 027, 0,
030, 0, 031, 0, 032, 0
};
unsigned char atab[52] = {
0241, 0, 0242, 0, 0243, 0, 0244, 0, 0245, 0, 0246, 0, 0247, 0, 0250, 0,
0251, 0, 0252, 0, 0253, 0, 0254, 0, 0255, 0, 0256, 0, 0257, 0, 0260, 0,
0261, 0, 0262, 0, 0263, 0, 0264, 0, 0265, 0, 0266, 0, 0267, 0, 0270, 0,
0271, 0, 0272, 0
};
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"
};
int
yylex(void)
{
int c, ch;
restart:
c = getch();
peekc = -1;
while (c == ' ' || c == '\t')
c = getch();
if (c == '\\') {
(void) getch();
goto restart;
}
if (c <= 'z' && c >= 'a') {
peekc = getch();
if (peekc >= 'a' && peekc <= 'z') {
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(0);
}
return (error);
skip:
peekc = -1;
while ((ch = getch()) >= 'a' && ch <= 'z')
;
peekc = ch;
return (c);
}
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 '=':
switch ((peekc = getch())) {
case '=':
c = EQ;
goto gotit;
case '+':
c = EQPL;
goto gotit;
case '-':
c = EQMI;
goto gotit;
case '*':
c = EQMUL;
goto gotit;
case '/':
c = EQDIV;
goto gotit;
case '%':
c = EQREM;
goto gotit;
case '^':
c = EQEXP;
goto gotit;
default:
return ('=');
gotit:
peekc = -1;
return (c);
}
case '+':
return (cpeek('+', INCR, '=', EQPL, '+'));
case '-':
return (cpeek('-', DECR, '=', EQMI, '-'));
case '*':
return (cpeek('=', EQMUL, '\0', 0, '*'));
case '%':
return (cpeek('=', EQREM, '\0', 0, '%'));
case '^':
return (cpeek('=', EQEXP, '\0', 0, '^'));
case '<':
return (cpeek('=', LE, '\0', 0, '<'));
case '>':
return (cpeek('=', GE, '\0', 0, '>'));
case '!':
return (cpeek('=', NE, '\0', 0, '!'));
case '/':
if ((peekc = getch()) == '=') {
peekc = -1;
return (EQDIV);
}
if (peekc == '*') {
peekc = -1;
while ((getch() != '*') || ((peekc = getch()) != '/'))
;
peekc = -1;
goto restart;
}
else
return (c);
case '"':
yylval.cptr = str;
while ((c = getch()) != '"') {
*str++ = c;
if (str >= &string[STRING_SIZE-1]) {
(void) yyerror("string space exceeded");
getout(1);
}
}
*str++ = '\0';
return (QSTR);
default:
return (c);
}
}
int
cpeek(char c1, int yes1, char c2, int yes2, char none)
{
int r;
peekc = getch();
if (peekc == c1)
r = yes1;
else if (peekc == c2)
r = yes2;
else
return (none);
peekc = -1;
return (r);
}
int
getch(void)
{
int ch;
char mbuf[LINE_MAX];
loop:
ch = (peekc < 0) ? getc(in) : peekc;
peekc = -1;
if (ch != EOF)
return (ch);
if (++ifile >= sargc) {
if (ifile >= sargc+1)
getout(0);
in = stdin;
ln = 0;
goto loop;
}
(void) fclose(in);
if ((in = fopen(sargv[ifile], "r")) != NULL) {
ln = 0;
ss = sargv[ifile];
goto loop;
}
(void) snprintf(mbuf, sizeof (mbuf), "can't open input file %s",
sargv[ifile]);
ln = -1;
ss = "command line";
(void) yyerror(mbuf);
getout(1);
}
#define b_sp_max 5000
int b_space[b_sp_max];
int *b_sp_nxt = { b_space };
int bdebug = 0;
static int *
bundle(int i, ...)
{
va_list ap;
int *q;
va_start(ap, i);
q = b_sp_nxt;
if (bdebug)
printf("bundle %d elements at %o\n", i, q);
while (i-- > 0) {
if (b_sp_nxt >= & b_space[b_sp_max])
(void) yyerror("bundling space exceeded");
*b_sp_nxt++ = va_arg(ap, int);
}
* b_sp_nxt++ = 0;
yyval.iptr = q;
va_end(ap);
return (q);
}
void
routput(int *p)
{
if (bdebug) printf("routput(%o)\n", p);
if (p >= &b_space[0] && p < &b_space[b_sp_max]) {
while (*p != 0)
routput((int *)*p++);
}
else
printf((char *)p);
}
void
output(int *p)
{
routput(p);
b_sp_nxt = & b_space[0];
printf("\n");
(void) fflush(stdout);
cp = cary;
crs = rcrs;
}
void
conout(int *p, char *s)
{
printf("[");
routput(p);
printf("]s%s\n", s);
(void) fflush(stdout);
lev--;
}
int
yyerror(const char *s)
{
if (ifile >= sargc)
ss = "teletype";
if (ss == 0 || *ss == 0)
(void) fprintf(stderr, gettext("%s on line %d\n"), s, ln+1);
else
(void) fprintf(stderr, gettext("%s on line %d, %s\n"),
s, ln+1, ss);
(void) fflush(stderr);
cp = cary;
crs = rcrs;
bindx = 0;
lev = 0;
b_sp_nxt = &b_space[0];
return (0);
}
void
checkbuffer(void)
{
if (cp >= cpend) {
(void) yyerror("line too long\n");
getout(1);
}
}
void
pp(int *s)
{
(void) bundle(3, "S", s, pre);
pre = yyval.iptr;
(void) bundle(4, post, "L", s, "s.");
post = yyval.iptr;
}
void
tp(int *s)
{
bundle(3, "0S", s, pre);
pre = yyval.iptr;
bundle(4, post, "L", s, "s.");
post = yyval.iptr;
}
void
yyinit(int argc, char **argv)
{
char mbuf[LINE_MAX];
(void) signal(SIGINT, SIG_IGN);
sargv = argv;
sargc = argc;
if (sargc == 0)
in = stdin;
else if ((in = fopen(sargv[0], "r")) == NULL) {
(void) snprintf(mbuf, sizeof (mbuf), "can't open input file %s",
sargv[0]);
ln = -1;
ss = "command line";
(void) yyerror(mbuf);
getout(1);
}
ifile = 0;
ln = 0;
ss = sargv[0];
}
static void
getout(int code)
{
printf("q");
(void) fflush(stdout);
exit(code);
}
int *
getf(char *p)
{
return ((int *) &funtab[2*(*p -0141)]);
}
int *
geta(char *p)
{
return ((int *) &atab[2*(*p - 0141)]);
}
int
main(int argc, char **argv)
{
int p[2];
int cflag = 0;
int lflag = 0;
int flag = 0;
char **av;
int filecounter = 0;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
while ((flag = getopt(argc, argv, "dcl")) != EOF) {
switch (flag) {
case 'd':
case 'c':
cflag++;
break;
case 'l':
lflag++;
break;
default:
fflush(stdout);
usage();
break;
}
}
argc -= optind;
av = &argv[optind];
for (filecounter = 0; filecounter < argc; filecounter++) {
if ((strlen(av[filecounter])) >= PATH_MAX) {
(void) fprintf(stderr,
gettext("File argument too long\n"));
exit(2);
}
}
if (lflag) {
av = &argv[optind-1];
av[0] = "/usr/lib/lib.b";
argc++;
}
if (cflag) {
yyinit(argc, av);
yyparse();
exit(0);
}
pipe(p);
if (fork() == 0) {
(void) close(1);
dup(p[1]);
(void) close(p[0]);
(void) close(p[1]);
yyinit(argc, av);
yyparse();
exit(0);
}
(void) close(0);
dup(p[0]);
(void) close(p[0]);
(void) close(p[1]);
#ifdef XPG6
execl("/usr/xpg6/bin/dc", "dc", "-", 0);
#else
execl("/usr/bin/dc", "dc", "-", 0);
#endif
return (1);
}
static void
usage(void)
{
(void) fprintf(stderr, gettext(
"usage: bc [ -c ] [ -l ] [ file ... ]\n"));
exit(2);
}