Files
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

1079 lines
26 KiB
Plaintext

%{static char sccsid[] = "@(#)32 1.34 src/bos/usr/bin/bc/bc.y, cmdcalc, bos41J, 9521B_all 5/28/95 11:15:22"; %}
/*
* COMPONENT_NAME: (CMDCALC) calculators
*
* FUNCTIONS: bc
*
* ORIGINS: 3 26 27 71
*
* This module contains IBM CONFIDENTIAL code. -- (IBM
* Confidential Restricted when combined with the aggregated
* modules for this product)
* SOURCE MATERIALS
* (C) COPYRIGHT International Business Machines Corp. 1985, 1994
* All Rights Reserved
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*
* Copyright (c) 1984 AT&T
* All Rights Reserved
*
* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T
* The copyright notice above does not evidence any
* actual or intended publication of such source code.
*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
* (c) Copyright 1990, 1991, 1992 OPEN SOFTWARE FOUNDATION, INC.
* ALL RIGHTS RESERVED
*
* OSF/1 1.1
*/
/*
*
* NAME: bc [-c][-l][file ...]
*
* FUNCTION: Provides an interpreter for a arbitrary-precision arithmetic
* language.
* OPTIONS:
* -c Compiles file, but does not invoke dc.
* -l includes a library of math functions.
*
* COMMENTS: This is a yacc file. It should first be given to the
* yacc command, which will produce an LR(1) parsing
* program called y.tab.c. This file must then be compiled
* with the cc command.
* The yacc grammer file is divided into three sections,
* each of which is delimited by %%. These sections are:
* 1) Declarations: Defines the variables which are
* used in the rules.
* 2) rules: Contains strings and expressions to be
* matched in the file to yylex(provided in this
* program), and C commands to execute when a match
* is made.
* 3) Programs: Allows the user to define his/her
* own subroutines.
*
*/
/* "%{" and "%}" are used to enclose global variables. */
%{
static void getout(int);
static int bundle( int, ... );
extern int optind;
extern int getopt(int argc, char **argv, char *optstring);
%}
/* The following declarations give the associativity and precedence of
* the operators. The later the operators appear, the higher precedence
* they have. For example, "+" is left-associative and is of lower
* precedence than "*". */
%right '='
%left '+' '-'
%left '*' '/' '%'
%right '^'
%left UMINUS
%term LETTER DIGIT SQRT LENGTH _IF FFF EQ
%term _WHILE _FOR NE LE GE INCR DECR
%term _RETURN _BREAK _DEFINE BASE OBASE SCALE
%term EQPL EQMI EQMUL EQDIV EQREM EQEXP
%term _AUTO DOT
%term QSTR
%{
#include <stdio.h>
#include <locale.h>
#include <stdarg.h> /*for osf. Used for vproducing variable argument list*/
#include <nl_types.h>
#include <langinfo.h>/*needed to define radix char*/
#include <limits.h>
static nl_catd catd; /* global catalog descriptor */
#include "bc_msg.h"
#define MSGSTR(C,D) catgets(catd, MS_BC, C, D)
#define MATHPATH "/usr/lib/lib.b"
#define MAXIBASE 16
#define MINBASE 2
static FILE *in;
static char cary[BC_STRING_MAX+1], *cp = { cary };
static char string[BC_STRING_MAX+1], *str = {string};
static int base = 10;
static int obase = 10;
static int crs = '0';
static int rcrs = '0'; /* reset crs */
static int bindx = 0;
static int lev = 0;
static int ln;
static char *ss;
static int bstack[10] = { 0 };
static char *numb[15] = {
" 0", " 1", " 2", " 3", " 4", " 5",
" 6", " 7", " 8", " 9", " 10", " 11",
" 12", " 13", " 14" };
static int *pre, *post;
%}
/* The Rules section. */
/* This section is made up of grammer rules and actions. The actions are
* performed each time the parser recognizes the rule in the input
* stream. For example, in the first rule below, start is a non-terminal
* name and "start stat tail" are rules. If one of these rules are
* recognized, then the action "output( $2 )" is performed, where "$2"
* represents the value returned by the second rule("stat"). */
%%
start :
| start stat tail
= output( $2 );
| start def dargs ')' '{' dlist slist '}'
={ bundle( 6,pre, $7, post ,"0",numb[lev],"Q");
conout( $$, $2 );
rcrs = crs;
output( "" );
lev = bindx = 0;
}
;
dlist : tail
| dlist _AUTO dlets tail
;
stat : e
={ bundle(3, $1, "ps", dot); }
|
={ 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
= { int newbase;
if ((newbase = strtol(cary, "", (strlen(cary) > 1 ? base : MAXIBASE))) > MAXIBASE)
yyerror(MSGSTR(BADIBASE, "Input base value cannot exceed 16"));
else if (newbase < MINBASE)
yyerror(MSGSTR(MINIBASE, "Input base value cannot be less than 2"));
else {
base = newbase;
bundle(2,$3, "i");
}
}
| BASE EQOP e
= { int newbase;
if ((newbase = strtol(cary, "", (strlen(cary) > 1 ? base : MAXIBASE))) > MAXIBASE)
yyerror(MSGSTR(BADIBASE, "Input base value cannot exceed 16"));
else if (newbase < MINBASE)
yyerror(MSGSTR(MINIBASE, "Input base value cannot be less than 2"));
else {
base = newbase;
bundle(4,"I",$3,$2,"i");
}
}
| OBASE '=' e
= { int newbase;
if ((newbase = strtol(cary, "", (strlen(cary) > 1 ? base : MAXIBASE))) < MINBASE)
yyerror(MSGSTR(MINOBASE, "Output base value cannot be less than 2"));
else {
obase = newbase;
bundle(2,$3, "o");
}
}
| OBASE EQOP e
= { int newbase;
if ((newbase = strtol(cary, "", (strlen(cary) > 1 ? base : MAXIBASE))) < MINBASE)
yyerror(MSGSTR(MINOBASE, "Output base value cannot be less than 2"));
else {
obase = newbase;
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(6, $7, $5, "s", dot, $3, $2 );
conout( $$, $2 );
bundle(6, $1, "s", dot, $3, $2, " " );
}
| '~' LETTER '=' e
={ bundle(3,$4,"S",$2); }
;
EQOP : EQPL
={ $$ = (int)"+"; }
| EQMI
={ $$ = (int)"-"; }
| EQMUL
={ $$ = (int)"*"; }
| EQDIV
={ $$ = (int)"/"; }
| EQREM
={ $$ = (int)"%"; }
| EQEXP
={ $$ = (int)"^"; }
;
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
= { if (base < MAXIBASE) {
base++;
bundle(1,"Id1+i");
} else {
yyerror(MSGSTR(BADIBASE, "Input base value cannot exceed 16"));
bundle(1,"I");
}
}
| INCR BASE
= { if ( base < MAXIBASE ) {
base++;
bundle(1,"I1+di");
} else {
yyerror(MSGSTR(BADIBASE, "Input base value cannot exceed 16"));
bundle(1,"I");
}
}
| BASE DECR
= { if ( base > MINBASE ) {
base--;
bundle(1,"Id1-i");
} else {
yyerror(MSGSTR(MINIBASE, "Input base value cannot be less than 2"));
bundle(1,"I");
}
}
| DECR BASE
= { if ( base > MINBASE ) {
base--;
bundle(1,"I1-di");
} else {
yyerror(MSGSTR(MINIBASE, "Input base value cannot be less than 2"));
bundle(1,"I");
}
}
| OBASE INCR
= bundle(1,"Od1+o");
| INCR OBASE
= bundle(1,"O1+do");
| OBASE DECR
= { if ( obase > MINBASE ) {
obase--;
bundle(1,"Od1-o");
} else {
yyerror(MSGSTR(MINOBASE, "Output base value cannot be less than 2"));
bundle(1,"O");
}
}
| DECR OBASE
= { if ( obase > MINBASE ) {
obase--;
bundle(1,"O1-do");
} else {
yyerror(MSGSTR(MINOBASE, "Output base value cannot be less than 2"));
bundle(1,"O");
}
}
| LETTER '(' cargs ')'
= bundle(4, $3, "l", getf($1), "x" );
| LETTER '(' ')'
= bundle(3, "l", getf($1), "x" );
| cons
={ bundle(2, " ", $1 ); }
| DOT cons
={ bundle(3," ", dot, $2 ); }
| cons DOT cons
={ bundle(4, " ", $1, dot , $3 ); }
| cons DOT
={ bundle(3, " ", $1, dot ); }
| DOT
={ bundle(2, "l", dot ); }
| 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"); /* must be before '(' e ')' */
| '(' 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
= { int newbase;
if ((newbase = strtol(cary, "", (strlen(cary) > 1 ? base : MAXIBASE))) > MAXIBASE)
yyerror(MSGSTR(BADIBASE, "Input base value cannot exceed 16"));
else if (newbase < MINBASE)
yyerror(MSGSTR(MINIBASE, "Input base value cannot be less than 2"));
else {
base = newbase;
bundle(2,$3,"di");
}
}
| BASE EQOP e %prec '='
= { int newbase;
if ((newbase = strtol(cary, "", (strlen(cary) > 1 ? base : MAXIBASE))) > MAXIBASE)
yyerror(MSGSTR(BADIBASE, "Input base value cannot exceed 16"));
else if (newbase < MINBASE)
yyerror(MSGSTR(MINIBASE, "Input base value cannot be less than 2"));
else {
base = newbase;
bundle(4,"I",$3,$2,"di");
}
}
| OBASE '=' e
= { int newbase;
if ((newbase = strtol(cary, "", (strlen(cary) > 1 ? base : MAXIBASE))) < MINBASE)
yyerror(MSGSTR(MINOBASE, "Output base value cannot be less than 2"));
else {
obase = newbase;
bundle(2,$3,"do");
}
}
| OBASE EQOP e %prec '='
= { int newbase;
if ((newbase = strtol(cary, "", (strlen(cary) > 1 ? base : MAXIBASE))) < MINBASE)
yyerror(MSGSTR(MINOBASE, "Output base value cannot be less than 2"));
else {
obase = newbase;
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:
'_'
={ $$ = (int)cp; *cp++ = '_'; }
| DIGIT
={ $$ = (int)cp; *cp++ = $1; }
| constant DIGIT
={ *cp++ = $2; }
;
CRS :
={ $$ = (int)cp; *cp++ = crs++; *cp++ = '\0';
if(crs == '[')crs+=3;
if(crs == 'a')crs='{';
if(crs >= 0241) {
yyerror(MSGSTR(TOOBIG,
"bc: program too big"));
getout(1);
}
bstack[bindx++] = lev++; }
;
def : _DEFINE LETTER '('
={ $$ = (int)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
| LETTER '[' ']'
={ $$ = (int)geta($1); }
;
/* The Program section. */
/* This section contains the C language programs which perform the functions
* used by the actions in the rules section. */
%%
# define error 256
static int peekc = -1;
static int sargc;
static int ifile = 0;
static char **sargv;
/* The 'dc' command allows any character to be used as a register name.
The 'bc' command uses characters for specific purposes.
(See the yacc rule for CRS to see how names for control statements
are generated.)
0 Not used
01-032 Function names
033-047(')
048('0')-0132('Z') Control (if, while, ...) statements
0133('[')-0135(']')
0136('^')-0140('`') Control statements
0141('a')-0172('z') Simple variables
0173('{')-0240 Control statements
0241-0272 Array names
0273-0377
*/
/* Function names [a-z] are mapped to 'dc' register names 01-032.
This range must be distinct from the range used for array names
and simple variable names. */
#define x(x) {x-0140,'\0'}
static char funtab[26][2] = {
x('a'),x('b'),x('c'),x('d'),x('e'),x('f'),x('g'),x('h'),x('i'),
x('j'),x('k'),x('l'),x('m'),x('n'),x('o'),x('p'),x('q'),x('r'),
x('s'),x('t'),x('u'),x('v'),x('w'),x('x'),x('y'),x('z')};
/* Array names [a-z] are mapped to 'dc' register names 0241-0272.
This range must be distinct from the range used for function names
and simple variable names. */
#undef x
#define x(x) {x+0100,'\0'}
static char atab[26][2] = {
x('a'),x('b'),x('c'),x('d'),x('e'),x('f'),x('g'),x('h'),x('i'),
x('j'),x('k'),x('l'),x('m'),x('n'),x('o'),x('p'),x('q'),x('r'),
x('s'),x('t'),x('u'),x('v'),x('w'),x('x'),x('y'),x('z')};
#undef x
/* Simple variable names are mapped to themselves.
Array names and function names cannot map to themselves. */
static 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" } ;
static char *dot; /*This character is used for the decimal(radix) character*/
/*
* NAME: yylex
*
* FUNCTION: This is the lexical analyzer. It reads the input
* stream and sends tokens (with values, if required)
* to the parser that yacc generates.
*
* RETURN VALUE: Returns an integer (called a token number) which
* represents the kind of token that was read.
*
*/
yylex(){
int c, ch;
while(1) {
c = getch();
peekc = -1;
while( c == ' ' || c == '\t' ) c = getch();
if(c == '\\'){
int chr = getch();
/* The following code supports multi-line number tokens */
/* If you encounter a backslash followed by a newline and */
/* The previous character was a digit and the next charac */
/* is a digit, then ignore the backslash and the newline. */
if ( chr == '\n' ) {
chr = getch();
if( chr>= '0' && chr <= '9' || chr>= 'A' && chr<= 'F' ){
yylval = chr;
return( DIGIT );
} else
c = chr;
}
}
if( c<= 'z' && c >= 'a' ) {
/* look ahead for reserved words */
peekc = getch();
if( peekc >= 'a' && peekc <= 'z' ){ /* must be reserved word */
if( c=='i' && peekc=='f' ){ c=_IF; }
else if( c=='w' && peekc=='h' ){ c=_WHILE; }
else if( c=='f' && peekc=='o' ){ c=_FOR; }
else if( c=='s' && peekc=='q' ){ c=SQRT; }
else if( c=='r' && peekc=='e' ){ c=_RETURN; }
else if( c=='b' && peekc=='r' ){ c=_BREAK; }
else if( c=='d' && peekc=='e' ){ c=_DEFINE; }
else if( c=='s' && peekc=='c' ){ c= SCALE; }
else if( c=='b' && peekc=='a' ){ c=BASE; }
else if( c=='i' && peekc == 'b'){ c=BASE; }
else if( c=='o' && peekc=='b' ){ c=OBASE; }
else if( c=='d' && peekc=='i' ){ c=FFF; }
else if( c=='a' && peekc=='u' ){ c=_AUTO; }
else if( c == 'l' && peekc=='e'){ c=LENGTH; }
else if( c == 'q' && peekc == 'u'){getout(0);}
/* could not be found */
else return( error );
/* skip over rest of word. */
peekc = -1;
while( (ch = getch()) >= 'a' && ch <= 'z' );
peekc = ch;
return( c );
}
/* usual case; single letter */
yylval = (int)letr[c-'a'];
return( LETTER );
}
if( c>= '0' && c <= '9' || c>= 'A' && c<= 'F' ){
yylval = c;
return( DIGIT );
}
/* Parse out the operators. */
switch( c ){
case '=':
switch( peekc = getch() ){
case '=': c=EQ; peekc = -1; return(c);
case '+': c=EQPL; peekc = -1; return(c);
case '-': c=EQMI; peekc = -1; return(c);
case '*': c=EQMUL; peekc = -1; return(c);
case '/': c=EQDIV; peekc = -1; return(c);
case '%': c=EQREM; peekc = -1; return(c);
case '^': c=EQEXP; peekc = -1; return(c);
default: return( '=' );
}
case '+': return( cpeek2( '+', INCR, '=', EQPL, '+' ) );
case '-': return( cpeek2( '-', DECR, '=', EQMI, '-' ) );
case '<': return( cpeek( '=', LE, '<' ) );
case '>': return( cpeek( '=', GE, '>' ) );
case '!': return( cpeek( '=', NE, '!' ) );
case '%': return( cpeek( '=', EQREM, '%' ) );
case '^': return( cpeek( '=', EQEXP, '^' ) );
case '*': return( cpeek( '=', EQMUL, '*' ) );
case '/':
if((peekc = getch()) == '*'){
peekc = -1;
while((getch() != '*') || ((peekc = getch()) != '/'));
peekc = -1;
break;
} else if (peekc == '='){
peekc=-1;
c=EQDIV;
}
return(c);
case '"': /* If a string is encountered, then read it in until the
* second set of double quotes is found. */
yylval = (int)str;
while((c=getch()) != '"') {
*str++ = c;
if (str > &string[BC_STRING_MAX]) {
yyerror(MSGSTR(NOSTRSPC,
"bc:string space exceeded"));
}
}
*str++ = '\0';
return(QSTR);
default:
if (c == *dot)
return( DOT );
else
return( c );
}
}
}
/*
* NAME: cpeek
*
* FUNCTION: This function is used to parse operators which are made up
* of more than one character. For example, a call to this
* function might be "cpeek( "=", LE, "<" )". When this call
* is made, it has already been determined that a "<" sign
* has been found. This function says that if the next
* character is an equal sign, then the operator is "<=".
* If the next character is not an equal sign, the the
* operator is simply "<".
*
* RETURN VALUE: yes) The next character read is the same as the first
* arguement.
* no) The next character read is not the same as the
* first arguement.
*
*/
static cpeek( c, yes, no ){
if( (peekc=getch()) != c ) return( no );
else {
peekc = -1;
return( yes );
}
}
/*
* NAME: cpeek2
*
* FUNCTION: This function is used to parse operators which are made up
* of more than one character. This function determines whether there
* is a two character operator, what the value of the second character
* is and returns the rule which corresponds to the two character
* operator or decrements the character counter and returns
* the original character.
* RETURN VALUE: return1) The first specified rule.
* return2) The second specified rule.
* default) The next character is not part of the operator.
*
*/
static cpeek2( next1,return1,next2,return2,orig) {
if( cpeek(next1,return1,orig)==return1)
return(return1);
else if(peekc == next2){
peekc = -1;
return(return2);
}
else
return(orig);
}
/*
* NAME: getch
*
* FUNCTION: Reads in a character.
*
* RETURN VALUE: The character read in.
*
*/
static getch(){
int ch;
int cont=1;
while(cont) {
ch = (peekc < 0) ? getc(in) : peekc;
peekc = -1;
if(ch != EOF)return(ch);
++ifile;
if (ifile <= sargc+1) {
fclose(in);
if(sargv[ifile] == NULL){
in = stdin;
ss = "stdin";
ln = 0;
} else if((in = fopen(sargv[ifile],"r")) != NULL) {
ln = 0;
ss = sargv[ifile];
} else {
fprintf(stderr, "%s %s\n", MSGSTR(NOINFILE,
"bc: cannot open input file"),
sargv[ifile]);
cont = 0;
}
} else
getout(0);
}
}
/*
* NAME: bundle
*
* FUNCTION: Stores the arguements into the bundling space.
*
* RETURN VALUE: The location in the bundling space where the args
* are stored. Allows for variable length arg list.
*
*/
# define b_sp_max 9000 /* must be this large to handle worst case expression */
/* containing 1+1+1+... up to LINE_MAX bytes */
static int b_space [ b_sp_max ];
static int * b_sp_nxt = { b_space };
static int bdebug = 0;
bundle(int i,...){
va_list ap;
int *q;
va_start(ap, i);
q = b_sp_nxt;
if( bdebug ) fprintf(stderr, MSGSTR(BUND, "bundle %d elements at %x\n"),i, q );
while(i-- > 0){
if( b_sp_nxt >= & b_space[b_sp_max] )
yyerror(MSGSTR(NOBUNDLE,
"bc: bundling space exceeded"));
* b_sp_nxt++ = va_arg(ap, int);
}
* b_sp_nxt++ = 0;
yyval = (int)q;
return( (int)q );
}
/*
* NAME: routput
*
* FUNCTION: This is a recursive function. It prints the contents of the
* bundling space from "p" until the end.
*
* RETURN VALUE: none
*
*/
static routput(p) int *p; {
if( bdebug ) fprintf(stderr, MSGSTR(ROUT, "routput(%o)\n"), p );
if( p >= &b_space[0] && p < &b_space[b_sp_max]){
/* part of a bundle */
while( *p != 0 ) routput( *p++ );
}
else printf("%s",p ); /* character string */
}
/*
* NAME: output
*
* FUNCTION: Prints out the contents of the budling space from "*p" on.
*
* RETURN VALUE: none
*
*/
static output( p ) int *p; {
routput( p );
b_sp_nxt = & b_space[0];
printf( "\n" );
fflush(stdout);
cp = cary;
crs = rcrs;
}
static conout( p, s ) int *p; char *s; {
printf("[");
routput( p );
printf("]s%s\n", s );
fflush(stdout);
lev--;
}
/*
* NAME: yyerror
*
* FUNCTION: Handles errors which occur during parser operation.
*
* RETURN VALUE: none
*
*/
yyerror( s ) char *s; {
char errmsg[256];
sprintf(errmsg, MSGSTR(INVINP, "%s on line %d %s"), s, ln+1, ss );
fprintf(stderr, "%s\n", errmsg );
fflush(stderr);
cp = cary;
crs = rcrs;
bindx = 0;
lev = 0;
b_sp_nxt = &b_space[0];
}
/*
* NAME: pp
*
* FUNCTION: Puts the relevant stuff on pre and post for the letter s.
*
* RETURN VALUE: none
*
*/
static pp( s ) char *s; {
bundle(3, "S", s, pre );
pre = (int *)yyval;
bundle(5, post, "L", s, "s", dot );
post = (int *)yyval;
}
/*
* NAME: tp
*
* FUNCTION: Same as pp, but for temps.
*
* RETURN VALUE: none
*
*/
static tp( s ) char *s; {
bundle(3, "0S", s, pre );
pre = (int *)yyval;
bundle(5, post, "L", s, "s", dot );
post = (int *)yyval;
}
/*
* NAME: getout
*
* FUNCTION: exits the program.
*
* RETURN VALUE: none
*
*/
static void getout(int stat){
printf("q");
fflush(stdout);
exit(stat);
}
static int *
getf(p) char *p;{
return((int *)&funtab[(*p - 'a')]);
}
static int *
geta(p) char *p;{
return((int *)&atab[(*p - 'a')]);
}
/*
* NAME: main
*
* FUNCTION: Parses out the options which are used to call bc.
*
* RETURN VALUE: none
*
*/
main(argc, argv)
char **argv;
{
int p[2];
int opt;
unsigned short cflag=0;
unsigned short sargv_indx = 0;
pid_t pid;
(void)setlocale(LC_ALL, "");
(void)setlocale(LC_NUMERIC, "C");
/*define radix */
dot = ".";
/*open message catalogue*/
catd = catopen(MF_BC, NL_CAT_LOCALE);
/* Takes care of any specified options. These can be either
* "c" for binary calculator ('d' for backward compatibility)
* or "l" to include a library. Check here for readable file
* name on input line. This is a bit faster than waiting until
* after the call to dc and eliminates a core dump caused due
* to the fork/execl. Also values greater than 0 are returned
* on error conditions.*/
while ((opt = getopt(argc, argv, "cdl")) != EOF) {
switch(opt) {
case 'c':
case 'd':
cflag=1;
break;
case 'l':
ss = MATHPATH;
if((in = fopen(MATHPATH,"r")) == NULL)
fprintf(stderr, "%s %s\n", MSGSTR(NOINFILE, "bc: cannot open input file"), MATHPATH);
break;
case '?':
fprintf(stderr, MSGSTR(USAGE,"usage:bc [-cl] [files...]\n"));
fflush(stderr);
exit(1);
break;
}
}
/* XPG4 says all files on the command line must be accessible
or we exit without taking an action. */
{
int filename_index;
FILE *file_stream;
/* Loop through the file names. */
for(filename_index=optind; argv[filename_index] !=
NULL; filename_index++)
{
/* If we can't read the file then exit non-zero. */
if ((file_stream = fopen(argv[filename_index],"r")) == NULL)
{
fprintf(stderr, "%s %s\n", MSGSTR(NOINFILE, "bc: cannot open input file"), argv[filename_index]);
exit(1);
}
/* Close the file and keep going. */
(void)fclose(file_stream);
}
}
sargc = argc - optind; /* the number of files on command line */
sargv = argv + optind - 1;
if ((in == NULL) && (argv[optind] != NULL)) {
if((in = fopen(argv[optind],"r")) == NULL) {
fprintf(stderr, "%s %s\n", MSGSTR(NOINFILE, "bc: cannot open input file"), argv[optind]);
in = stdin;
ss = "stdin";
} else {
++ifile;
ss = argv[optind];
}
}
else if ( in == NULL ) {
++ifile;
in = stdin;
ss = "stdin";
}
if (cflag == 1) {
signal( 2, (int(*)())1 ); /* ignore all interrupts */
ln = 0;
yyparse();
exit(0);
}
pipe(p);
pid = fork();
if (pid < 0) {
perror("bc");
exit(1);
}
if (pid == 0) { /* The child process */
close(1);
dup(p[1]);
close(p[0]);
close(p[1]);
signal( 2, (int(*)())1 ); /* ignore all interrupts */
ln = 0;
yyparse();
exit(0);
}
close(0);
dup(p[0]);
close(p[0]);
close(p[1]);
catclose(catd);
execl("/usr/bin/dc", "dc", "-", 0);
}