#!/bin/sh # This is a shar archive. # The rest of this file is a shell script which will extract: # # 3_13.c 3_13.cmp 3_13.in 3_13a.c 3_13a1.c 3_13a2.c 3_13b.c 3_13b.cmp 3_13c.c 3_13d.c 3_13e.c 3_13f.c 3_13g.c 3_13h.c makefile # # To extract the files from this shell archive file simply # create a directory for this file, move the archive file # to it and enter the command # # sh filename # # The files will be extracted automatically. # Note: Do not use csh. # # Archive created: Mon Jul 30 22:58:09 EDT 1990 # echo x - 3_13.c sed 's/^X//' > 3_13.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include #include #include #ifndef RAND_MAX # define RAND_MAX 32767 #endif #include int no_of_errors; double error(char *s) { cerr << "error: " << s << "\n"; no_of_errors++; return 1; } #include "3_13a.c" const TBLSZ = 23; name *table[TBLSZ]; int lookhash(char *p) { int ii = 0; while (*p) ii = ii << 1 ^ *p++; if (ii < 0) ii = -ii; return ii % TBLSZ; } name *look(char *p, int ins=0) { int ii = lookhash(p); for (name *n = table[ii]; n; n=n->next) if (strcmp(p, n->string) == 0) return n; if (ins == 0) error("name not found"); name *nn = new name; nn->string = new char[strlen(p)+1]; strcpy(nn->string, p); nn->next = table[ii]; #include "3_13c.c" /* EXPAND4 */ nn->value = 1; table[ii] = nn; return nn; } inline name *insert(char *s) { return look(s, 1); } enum token_value { NAME, NUMBER, END, COMMA=',', PLUS='+', MINUS='-', MUL='*', DIV='/', PRINT=';', ASSIGN='=', LP='(', RP=')' }; token_value curr_tok; double number_value; const int namesize = 100; char name_string[namesize]; token_value get_token(); double expr(), term(), prim(); double expr() { double left = term(); for (;;) { switch (curr_tok) { case PLUS: get_token(); left += term(); break; case MINUS: get_token(); left -= term(); break; default: return left; } } } double term() { double left = prim(); for (;;) { switch (curr_tok) { case MUL: get_token(); left *= prim(); break; case DIV: get_token(); double d = prim(); if (d == 0) return error("divide by 0"); left /= d; break; default: return left; } } } double prim() { switch (curr_tok) { case NUMBER: get_token(); return number_value; #include "3_13b.c" case MINUS: get_token(); return -prim(); case LP: get_token(); double e = expr(); if (curr_tok != RP) return error(") expected"); get_token(); return e; case END: return 1; default: return error("primary expected"); } } token_value get_token() { char ch; do { if (!cin.get(ch)) return curr_tok = END; } while (ch != '\n' && isspace(ch)); switch (ch) { case ';': case '\n': cin >> WS; return curr_tok = PRINT; case '*': case '/': case '+': case '-': case '(': case ')': case '=': case ',': return curr_tok = ch; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '.': cin.putback(ch); cin >> number_value; return curr_tok = NUMBER; default: if (isalpha(ch)) { char *p = name_string; *p++ = ch; while (cin.get(ch) && isalnum(ch) && p < &name_string[namesize-1]) *p++ = ch; if (p == &name_string[namesize]) while (cin.get(ch) && isalnum(ch)) ; cin.putback(ch); *p = 0; return curr_tok = NAME; } error("bad token"); return curr_tok = PRINT; } } #include "3_13e.c" static double doexp(double e[]) { return exp(e[0]); } static double docos(double e[]) { return cos(e[0]); } static double dotan(double e[]) { return tan(e[0]); } static double doatan(double e[]) { return atan(e[0]); } static double dolog10(double e[]) { if (e[0] <= 0) return error("log10: requires non-positive number"); else return log10(e[0]); } static double doexp10(double e[]) { return pow(10, e[0]); } static double doasin(double e[]) { if (e[0] > 1 || e[0] < -1) return error("asin: requires |x| <= 1.0"); else return asin(e[0]); } static double doacos(double e[]) { if (e[0] > 1 || e[0] < -1) return error("acos: requires |x| <= 1.0"); else return acos(e[0]); } static double dopow(double e[]) { double x = e[0]; double y = e[1]; if (x == 0 && y <= 0) return error("pow: x == 0 requires y > 0"); else if (x < 0 && y != (double)(int)y) return error("pow: x < 0 requires int y"); else return pow(x, y); } #include "3_13d.c" int main(int argc, char **argv) { switch (argc) { case 1: break; case 2: cin = *new istream(strlen(argv[1]), argv[1]); break; default: error("too many arguments"); return 1; } // initialize known variables insert("pi")->value = 3.1415926535897932385; insert("e")->value = 2.7182818284590452354; #include "3_13f.c" /* EXPAND4 */ insertfunction("exp", 1, (d_f_va)doexp); insertfunction("log10", 1, (d_f_va)dolog10); insertfunction("pow", 2, (d_f_va)dopow); insertfunction("cos", 1, (d_f_va)docos); insertfunction("tan", 1, (d_f_va)dotan); insertfunction("asin", 1, (d_f_va)doasin); insertfunction("acos", 1, (d_f_va)doacos); insertfunction("atan", 1, (d_f_va)doatan); while (cin) { get_token(); if (curr_tok == END) break; if (curr_tok == PRINT) continue; cout << expr() << "\n"; } return no_of_errors; } !EOF! ls -l 3_13.c echo x - 3_13.cmp sed 's/^X//' > 3_13.cmp << '!EOF!' 8 -282.447 374.231 -374.231 3.14159 2.71828 3.36159e+162 2.57314 9.37959e+22 0.731689 0.931596 0.848062 0.722734 0.643501 0.866025 -0.287682 0.681639 55.0681 !EOF! ls -l 3_13.cmp echo x - 3_13.in sed 's/^X//' > 3_13.in << '!EOF!' 3 + 5 39.547 - 321.993921 foo = 374.2312 0 - foo pi e exp(foo) log10(foo) pow(34, 15) cos(.75) tan(.75) asin(.75) acos(.75) atan(.75) sqrt(.75) log(.75) sin(.75) random(34, 75) !EOF! ls -l 3_13.in echo x - 3_13a.c sed 's/^X//' > 3_13a.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ typedef double (*d_f_va)(double[]); const maxargs = 9; const variable = -1; struct name { char *string; name *next; int nargs; union { double value; d_f_va funcptr; }; }; !EOF! ls -l 3_13a.c echo x - 3_13a1.c sed 's/^X//' > 3_13a1.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ enum token_value { NAME, NUMBER, END, COMMA=',', PLUS='+', MINUS='-', MUL='*', DIV='/', PRINT=';', ASSIGN='=', LP='(', RP=')' }; !EOF! ls -l 3_13a1.c echo x - 3_13a2.c sed 's/^X//' > 3_13a2.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ case '*': case '+': case '(': // same as before case '/': case '-': case ')': case '=': case ',': // new return curr_tok=ch; !EOF! ls -l 3_13a2.c echo x - 3_13b.c sed 's/^X//' > 3_13b.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ case NAME: if (get_token() == ASSIGN) // same as before { name *n = insert(name_string); get_token(); n->value = expr(); return n->value; } else if (curr_tok == LP) // function calls { name *n = look(name_string); if (n->nargs == variable) return error("not a function"); get_token(); // skip LP double e[maxargs]; int i = 0; if (curr_tok != RP) e[i++] = expr(); while (curr_tok == COMMA) { get_token(); // skip COMMA e[i++] = expr(); if (i == maxargs) break; } if (curr_tok != RP) return error(") expected"); get_token(); // skip RP if (n->nargs != i) return error("wrong number of arguments"); return (*n->funcptr)(e); } else { name *n = look(name_string); if (n->nargs == variable) return n->value; else return error("( expected"); } !EOF! ls -l 3_13b.c echo x - 3_13b.cmp sed 's/^X//' > 3_13b.cmp << '!EOF!' 909.542 41.5882 !EOF! ls -l 3_13b.cmp echo x - 3_13c.c sed 's/^X//' > 3_13c.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ nn->nargs = variable; !EOF! ls -l 3_13c.c echo x - 3_13d.c sed 's/^X//' > 3_13d.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ void insertfunction(char *funcname, int nargs, d_f_va funcptr) { name *n = insert(funcname); n->nargs = nargs; n->funcptr = funcptr; } !EOF! ls -l 3_13d.c echo x - 3_13e.c sed 's/^X//' > 3_13e.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ /* declare helper functions for */ /* sqrt(), log(), sin() and random() */ #include // return the square root of e0 static double dosqrt(double e[]) { return (e[0] < 0) ? error("sqrt: requires non-negative number") : sqrt(e[0]); } // return the natural log of e0 static double dolog(double e[]) { return (e[0] <= 0) ? error("log: requires positive number") : log(e[0]); } // return the sin of e0 static double dosin(double e[]) { return sin(e[0]); } // return a random number between [e0, e1) static double dorandom(double e[]) { return rand() / ( (double) RAND_MAX+1) * (e[1] - e[0]) + e[0]; } !EOF! ls -l 3_13e.c echo x - 3_13f.c sed 's/^X//' > 3_13f.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ // initialize known functions insertfunction("sqrt", 1, dosqrt); insertfunction("log", 1, dolog); insertfunction("sin", 1, dosin); insertfunction("random", 2, dorandom); !EOF! ls -l 3_13f.c echo x - 3_13g.c sed 's/^X//' > 3_13g.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ #include // return e to the power of e0 static double doexp(double e[]) { return exp(e[0]); } // return the log base 10 of e0 static double dolog10(double e[]) { return (e[0] <= 0) ? error("log10: requires positive number") : log10(e[0]); } // return e0 to the power of e1 static double dopow(double e[]) { if ((e[0] == 0) && (e[1] <= 0)) return error("pow: if x==0, y must be >0"); if ((e[0] < 0) && (int(e[1]) != e[1])) return error("pow: if x<0, y must be integral"); return pow(e[0], e[1]); } // return the cosine of e0 static double docos(double e[]) { return cos(e[0]); } // return the tangent of e0 static double dotan(double e[]) { return tan(e[0]); } // return the arc sine of e0 static double doasin(double e[]) { return ((e[0] > -1) && (e[0] < 1)) ? asin(e[0]) : error("asin: requires number between -1 and 1"); } // return the arc cosine of e0 static double doacos(double e[]) { return ((e[0] > -1) && (e[0] < 1)) ? acos(e[0]) : error("acos: requires number between -1 and 1"); } // return the arc tangent of e0 static double doatan(double e[]) { return atan(e[0]); } !EOF! ls -l 3_13g.c echo x - 3_13h.c sed 's/^X//' > 3_13h.c << '!EOF!' /* Copyright (c) 1990 by AT&T Bell Telephone Laboratories, Incorporated. */ /* The C++ Answer Book */ /* Tony Hansen */ /* All rights reserved. */ // initialize more functions insertfunction("exp", 1, exp); insertfunction("log10", 1, dolog10); insertfunction("pow", 2, dopow); insertfunction("cos", 1, cos); insertfunction("tan", 1, tan); insertfunction("asin", 1, doasin); insertfunction("acos", 1, doacos); insertfunction("atan", 1, atan); !EOF! ls -l 3_13h.c echo x - makefile sed 's/^X//' > makefile << '!EOF!' CC= CC -I. -I../../CC all: 3_13 3_13: 3_13.c 3_13a.c 3_13c.c 3_13b.c 3_13e.c 3_13d.c 3_13f.c $(CC) -g +i 3_13.c -o3_13 -lm test: all 3_13.cmp 3_13.in 3_13b.cmp 3_13 < 3_13.in > 3_13.out cmp 3_13.out 3_13.cmp 3_13 "57.893 + 283.8829 * 3; 47 - 92 / 17" > 3_13b.out cmp 3_13b.out 3_13b.cmp echo tests done !EOF! ls -l makefile # The following exit is to ensure that extra garbage # after the end of the shar file will be ignored. exit 0