home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume27
/
calc-2.9.0
/
part10
< prev
next >
Wrap
Text File
|
1993-12-07
|
60KB
|
2,523 lines
Newsgroups: comp.sources.unix
From: dbell@canb.auug.org.au (David I. Bell)
Subject: v27i137: calc-2.9.0 - arbitrary precision C-like programmable calculator, Part10/19
References: <1.755316719.21314@gw.home.vix.com>
Sender: unix-sources-moderator@gw.home.vix.com
Approved: vixie@gw.home.vix.com
Submitted-By: dbell@canb.auug.org.au (David I. Bell)
Posting-Number: Volume 27, Issue 137
Archive-Name: calc-2.9.0/part10
#!/bin/sh
# this is part 10 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file calc2.9.0/string.c continued
#
CurArch=10
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
exit 1; fi
( read Scheck
if test "$Scheck" != $CurArch
then echo "Please unpack part $Scheck next!"
exit 1;
else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file calc2.9.0/string.c"
sed 's/^X//' << 'SHAR_EOF' >> calc2.9.0/string.c
X
X testlen = strlen(test);
X index = 1;
X while (*format) {
X len = strlen(format);
X if ((len == testlen) && (*format == *test) &&
X (strcmp(format, test) == 0))
X return index;
X format += (len + 1);
X index++;
X }
X return 0;
X}
X
X
X/*
X * Add a possibly new literal string to the literal string pool.
X * Returns the new string address which is guaranteed to be always valid.
X * Duplicate strings will repeatedly return the same address.
X */
Xchar *
Xaddliteral(str)
X char *str;
X{
X register char **table; /* table of strings */
X char *newstr; /* newly allocated string */
X long count; /* number of strings */
X long len; /* length of string to allocate */
X
X len = strlen(str);
X if (len <= 1)
X return charstr(*str);
X /*
X * See if the string is already in the table.
X */
X table = literals.l_table;
X count = literals.l_count;
X while (count-- > 0) {
X if ((str[0] == table[0][0]) && (str[1] == table[0][1]) &&
X (strcmp(str, table[0]) == 0))
X return table[0];
X table++;
X }
X /*
X * Make the table of string pointers larger if necessary.
X */
X if (literals.l_count >= literals.l_maxcount) {
X count = literals.l_maxcount + STR_TABLECHUNK;
X if (literals.l_maxcount)
X table = (char **) realloc(literals.l_table, count * sizeof(char *));
X else
X table = (char **) malloc(count * sizeof(char *));
X if (table == NULL)
X math_error("Cannot allocate string literal table");
X literals.l_table = table;
X literals.l_maxcount = count;
X }
X table = literals.l_table;
X /*
X * If the new string is very long, allocate it manually.
X */
X len = (len + 2) & ~1; /* add room for null and round up to word */
X if (len >= STR_UNIQUE) {
X newstr = (char *)malloc(len);
X if (newstr == NULL)
X math_error("Cannot allocate large literal string");
X strcpy(newstr, str);
X table[literals.l_count++] = newstr;
X return newstr;
X }
X /*
X * If the remaining space in the allocate string is too small,
X * then allocate a new one.
X */
X if (literals.l_avail < len) {
X newstr = (char *)malloc(STR_CHUNK);
X if (newstr == NULL)
X math_error("Cannot allocate new literal string");
X literals.l_alloc = newstr;
X literals.l_avail = STR_CHUNK;
X }
X /*
X * Allocate the new string from the allocate string.
X */
X newstr = literals.l_alloc;
X literals.l_avail -= len;
X literals.l_alloc += len;
X table[literals.l_count++] = newstr;
X strcpy(newstr, str);
X return newstr;
X}
X
X
X/*
X * Calculate a trivial hash value for a string.
X */
XHASH
Xhashstr(cp)
X char *cp;
X{
X int len;
X HASH hash;
X
X len = strlen(cp);
X hash = len * 300007;
X while (len-- > 0)
X hash = hash * 300017 + *cp++ + 300043;
X return hash;
X}
X
X/* END CODE */
SHAR_EOF
echo "File calc2.9.0/string.c is complete"
chmod 0644 calc2.9.0/string.c || echo "restore of calc2.9.0/string.c fails"
set `wc -c calc2.9.0/string.c`;Sum=$1
if test "$Sum" != "6923"
then echo original size 6923, current size $Sum;fi
echo "x - extracting calc2.9.0/string.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/string.h &&
X/*
X * Copyright (c) 1993 David I. Bell
X * Permission is granted to use, distribute, or modify this source,
X * provided that this copyright notice remains intact.
X */
X
X#ifndef CALCSTRING_H
X#define CALCSTRING_H
X
X#include "zmath.h"
X
X
Xtypedef struct {
X char *h_list; /* list of strings separated by nulls */
X long h_used; /* characters used so far */
X long h_avail; /* characters available for use */
X long h_count; /* number of strings */
X} STRINGHEAD;
X
X
Xextern void initstr MATH_PROTO((STRINGHEAD *hp));
Xextern char *addstr MATH_PROTO((STRINGHEAD *hp, char *str));
Xextern char *namestr MATH_PROTO((STRINGHEAD *hp, long n));
Xextern long findstr MATH_PROTO((STRINGHEAD *hp, char *str));
Xextern char *charstr MATH_PROTO((int ch));
Xextern char *addliteral MATH_PROTO((char *str));
Xextern long stringindex MATH_PROTO((char *str1, char *str2));
Xextern HASH hashstr MATH_PROTO((char *cp));
X
X#endif
X
X/* END CODE */
SHAR_EOF
chmod 0644 calc2.9.0/string.h || echo "restore of calc2.9.0/string.h fails"
set `wc -c calc2.9.0/string.h`;Sum=$1
if test "$Sum" != "905"
then echo original size 905, current size $Sum;fi
echo "x - extracting calc2.9.0/symbol.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/symbol.c &&
X/*
X * Copyright (c) 1993 David I. Bell
X * Permission is granted to use, distribute, or modify this source,
X * provided that this copyright notice remains intact.
X *
X * Global and local symbol routines.
X */
X
X#include "calc.h"
X#include "token.h"
X#include "symbol.h"
X#include "string.h"
X#include "opcodes.h"
X#include "func.h"
X
X#define HASHSIZE 37 /* size of hash table */
X
X
Xstatic int filescope; /* file scope level for static variables */
Xstatic int funcscope; /* function scope level for static variables */
Xstatic STRINGHEAD localnames; /* list of local variable names */
Xstatic STRINGHEAD globalnames; /* list of global variable names */
Xstatic STRINGHEAD paramnames; /* list of parameter variable names */
Xstatic GLOBAL *globalhash[HASHSIZE]; /* hash table for globals */
X
Xstatic void fitprint MATH_PROTO((NUMBER *num, long digits, long width));
Xstatic void unscope MATH_PROTO((void));
X
X
X/*
X * Hash a symbol name so we can find it in the hash table.
X * Args are the symbol name and the symbol name size.
X */
X#define HASHSYM(n, s) ((unsigned)((n)[0]*123 + (n)[s-1]*135 + (s)*157) % HASHSIZE)
X
X
X/*
X * Initialize the global symbol table.
X */
Xvoid
Xinitglobals()
X{
X int i; /* index counter */
X
X for (i = 0; i < HASHSIZE; i++)
X globalhash[i] = NULL;
X initstr(&globalnames);
X filescope = SCOPE_STATIC;
X funcscope = 0;
X}
X
X
X/*
X * Define a possibly new global variable which may or may not be static.
X * If it did not already exist, it is created with a value of zero.
X * The address of the global symbol structure is returned.
X */
XGLOBAL *
Xaddglobal(name, isstatic)
X char *name; /* name of global variable */
X BOOL isstatic; /* TRUE if symbol is static */
X{
X GLOBAL *sp; /* current symbol pointer */
X GLOBAL **hp; /* hash table head address */
X long len; /* length of string */
X int newfilescope; /* file scope being looked for */
X int newfuncscope; /* function scope being looked for */
X
X newfilescope = SCOPE_GLOBAL;
X newfuncscope = 0;
X if (isstatic) {
X newfilescope = filescope;
X newfuncscope = funcscope;
X }
X len = strlen(name);
X if (len <= 0)
X return NULL;
X hp = &globalhash[HASHSYM(name, len)];
X for (sp = *hp; sp; sp = sp->g_next) {
X if ((sp->g_len == len) && (strcmp(sp->g_name, name) == 0)
X && (sp->g_filescope == newfilescope)
X && (sp->g_funcscope == newfuncscope))
X return sp;
X }
X sp = (GLOBAL *) malloc(sizeof(GLOBAL));
X if (sp == NULL)
X return sp;
X sp->g_name = addstr(&globalnames, name);
X sp->g_len = len;
X sp->g_filescope = newfilescope;
X sp->g_funcscope = newfuncscope;
X sp->g_value.v_num = qlink(&_qzero_);
X sp->g_value.v_type = V_NUM;
X sp->g_next = *hp;
X *hp = sp;
X return sp;
X}
X
X
X/*
X * Look up the name of a global variable and return its address.
X * Since the same variable may appear in different scopes, we search
X * for the one with the highest function scope value within the current
X * file scope level (or which is global). Returns NULL if the symbol
X * was not found.
X */
XGLOBAL *
Xfindglobal(name)
X char *name; /* name of global variable */
X{
X GLOBAL *sp; /* current symbol pointer */
X GLOBAL *bestsp; /* found symbol with highest scope */
X long len; /* length of string */
X
X bestsp = NULL;
X len = strlen(name);
X for (sp = globalhash[HASHSYM(name, len)]; sp; sp = sp->g_next) {
X if ((sp->g_len != len) || strcmp(sp->g_name, name))
X continue;
X if (sp->g_filescope == SCOPE_GLOBAL) {
X if (bestsp == NULL)
X bestsp = sp;
X continue;
X }
X if (sp->g_filescope != filescope)
X continue;
X if ((bestsp == NULL) || (sp->g_funcscope > bestsp->g_funcscope))
X bestsp = sp;
X }
X return bestsp;
X}
X
X
X/*
X * Return the name of a global variable given its address.
X */
Xchar *
Xglobalname(sp)
X GLOBAL *sp; /* address of global pointer */
X{
X if (sp)
X return sp->g_name;
X return "";
X}
X
X
X/*
X * Show the value of all global variables, typing only the head and
X * tail of very large numbers. Only truly global symbols are shown.
X */
Xvoid
Xshowglobals()
X{
X GLOBAL **hp; /* hash table head address */
X register GLOBAL *sp; /* current global symbol pointer */
X long count; /* number of global variables shown */
X NUMBER *num, *den;
X long digits;
X
X count = 0;
X for (hp = &globalhash[HASHSIZE-1]; hp >= globalhash; hp--) {
X for (sp = *hp; sp; sp = sp->g_next) {
X if (sp->g_value.v_type != V_NUM)
X continue;
X if (sp->g_filescope != SCOPE_GLOBAL)
X continue;
X if (count++ == 0) {
X printf("\nName Digits Value\n");
X printf( "---- ------ -----\n");
X }
X printf("%-8s ", sp->g_name);
X num = qnum(sp->g_value.v_num);
X digits = qdigits(num);
X printf("%-7ld ", digits);
X fitprint(num, digits, 60L);
X qfree(num);
X if (!qisint(sp->g_value.v_num)) {
X den = qden(sp->g_value.v_num);
X digits = qdigits(den);
X printf("\n %-6ld /", digits);
X fitprint(den, digits, 60L);
X qfree(den);
X }
X printf("\n");
X }
X }
X printf(count ? "\n" : "No global variables defined.\n");
X}
X
X
X/*
X * Print an integer which is guaranteed to fit in the specified number
X * of columns, using imbedded '...' characters if it is too large.
X */
Xstatic void
Xfitprint(num, digits, width)
X NUMBER *num; /* number to print */
X long digits, width;
X{
X long show, used;
X NUMBER *p, *t, *div, *val;
X
X if (digits <= width) {
X qprintf("%r", num);
X return;
X }
X show = (width / 2) - 2;
X t = itoq(10L);
X p = itoq((long) (digits - show));
X div = qpowi(t, p);
X val = qquo(num, div);
X qprintf("%r...", val);
X qfree(p);
X qfree(div);
X qfree(val);
X p = itoq(show);
X div = qpowi(t, p);
X val = qmod(num, div);
X used = qdigits(val);
X while (used++ < show) printf("0");
X qprintf("%r", val);
X qfree(p);
X qfree(div);
X qfree(val);
X qfree(t);
X}
X
X
X/*
X * Write all normal global variables to an output file.
X * Note: Currently only simple types are saved.
X * Returns nonzero on error.
X */
Xwriteglobals(name)
X char *name;
X{
X FILE *fp;
X GLOBAL **hp; /* hash table head address */
X register GLOBAL *sp; /* current global symbol pointer */
X int savemode; /* saved output mode */
X
X fp = f_open(name, "w");
X if (fp == NULL)
X return 1;
X math_setfp(fp);
X for (hp = &globalhash[HASHSIZE-1]; hp >= globalhash; hp--) {
X for (sp = *hp; sp; sp = sp->g_next) {
X switch (sp->g_value.v_type) {
X case V_NUM:
X case V_COM:
X case V_STR:
X break;
X default:
X continue;
X }
X math_fmt("%s = ", sp->g_name);
X savemode = math_setmode(MODE_HEX);
X printvalue(&sp->g_value, PRINT_UNAMBIG);
X math_setmode(savemode);
X math_str(";\n");
X }
X }
X math_setfp(stdout);
X if (fclose(fp))
X return 1;
X return 0;
X}
X
X
X/*
X * Reset the file and function scope levels back to the original values.
X * This is called on errors to forget any static variables which were being
X * defined.
X */
Xvoid
Xresetscopes()
X{
X filescope = SCOPE_STATIC;
X funcscope = 0;
X unscope();
X}
X
X
X/*
X * Enter a new file scope level so that newly defined static variables
X * will have the appropriate scope, and so that previously defined static
X * variables will temporarily be unaccessible. This should only be called
X * when the function scope level is zero.
X */
Xvoid
Xenterfilescope()
X{
X filescope++;
X funcscope = 0;
X}
X
X
X/*
X * Exit from a file scope level. This deletes from the global symbol table
X * all of the static variables that were defined within this file scope level.
X * The function scope level is also reset to zero.
X */
Xvoid
Xexitfilescope()
X{
X if (filescope > SCOPE_STATIC)
X filescope--;
X funcscope = 0;
X unscope();
X}
X
X
X/*
X * Enter a new function scope level within the current file scope level.
X * This allows newly defined static variables to override previously defined
X * static variables in the same file scope level.
X */
Xvoid
Xenterfuncscope()
X{
X funcscope++;
X}
X
X
X/*
X * Exit from a function scope level. This deletes static symbols which were
X * defined within the current function scope level, and makes previously
X * defined symbols with the same name within the same file scope level
X * accessible again.
X */
Xvoid
Xexitfuncscope()
X{
X if (funcscope > 0)
X funcscope--;
X unscope();
X}
X
X
X/*
X * Remove all the symbols from the global symbol table which have file or
X * function scopes larger than the current scope levels. Their memory
X * remains allocated since their values still actually exist.
X */
Xstatic void
Xunscope()
X{
X GLOBAL **hp; /* hash table head address */
X register GLOBAL *sp; /* current global symbol pointer */
X GLOBAL *prevsp; /* previous kept symbol pointer */
X
X for (hp = &globalhash[HASHSIZE-1]; hp >= globalhash; hp--) {
X prevsp = NULL;
X for (sp = *hp; sp; sp = sp->g_next) {
X if ((sp->g_filescope == SCOPE_GLOBAL) ||
X (sp->g_filescope < filescope) ||
X ((sp->g_filescope == filescope) &&
X (sp->g_funcscope <= funcscope)))
X {
X prevsp = sp;
X continue;
X }
X
X /*
X * This symbol needs removing.
X */
X if (prevsp)
X prevsp->g_next = sp->g_next;
X else
X *hp = sp->g_next;
X }
X }
X}
X
X
X/*
X * Initialize the local and parameter symbol table information.
X */
Xvoid
Xinitlocals()
X{
X initstr(&localnames);
X initstr(¶mnames);
X curfunc->f_localcount = 0;
X curfunc->f_paramcount = 0;
X}
X
X
X/*
X * Add a possibly new local variable definition.
X * Returns the index of the variable into the local symbol table.
X * Minus one indicates the symbol could not be added.
X */
Xlong
Xaddlocal(name)
X char *name; /* name of local variable */
X{
X long index; /* current symbol index */
X
X index = findstr(&localnames, name);
X if (index >= 0)
X return index;
X index = localnames.h_count;
X (void) addstr(&localnames, name);
X curfunc->f_localcount++;
X return index;
X}
X
X
X/*
X * Find a local variable name and return its index.
X * Returns minus one if the variable name is not defined.
X */
Xlong
Xfindlocal(name)
X char *name; /* name of local variable */
X{
X return findstr(&localnames, name);
X}
X
X
X/*
X * Return the name of a local variable.
X */
Xchar *
Xlocalname(n)
X long n;
X{
X return namestr(&localnames, n);
X}
X
X
X/*
X * Add a possibly new parameter variable definition.
X * Returns the index of the variable into the parameter symbol table.
X * Minus one indicates the symbol could not be added.
X */
Xlong
Xaddparam(name)
X char *name; /* name of parameter variable */
X{
X long index; /* current symbol index */
X
X index = findstr(¶mnames, name);
X if (index >= 0)
X return index;
X index = paramnames.h_count;
X (void) addstr(¶mnames, name);
X curfunc->f_paramcount++;
X return index;
X}
X
X
X/*
X * Find a parameter variable name and return its index.
X * Returns minus one if the variable name is not defined.
X */
Xlong
Xfindparam(name)
X char *name; /* name of parameter variable */
X{
X return findstr(¶mnames, name);
X}
X
X
X/*
X * Return the name of a parameter variable.
X */
Xchar *
Xparamname(n)
X long n;
X{
X return namestr(¶mnames, n);
X}
X
X
X/*
X * Return the type of a variable name.
X * This is either local, parameter, global, static, or undefined.
X */
Xsymboltype(name)
X char *name; /* variable name to find */
X{
X GLOBAL *sp;
X
X if (findlocal(name) >= 0)
X return SYM_LOCAL;
X if (findparam(name) >= 0)
X return SYM_PARAM;
X sp = findglobal(name);
X if (sp) {
X if (sp->g_filescope == SCOPE_GLOBAL)
X return SYM_GLOBAL;
X return SYM_STATIC;
X }
X return SYM_UNDEFINED;
X}
X
X/* END CODE */
SHAR_EOF
chmod 0644 calc2.9.0/symbol.c || echo "restore of calc2.9.0/symbol.c fails"
set `wc -c calc2.9.0/symbol.c`;Sum=$1
if test "$Sum" != "11019"
then echo original size 11019, current size $Sum;fi
echo "x - extracting calc2.9.0/symbol.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/symbol.h &&
X/*
X * Copyright (c) 1993 David I. Bell
X * Permission is granted to use, distribute, or modify this source,
X * provided that this copyright notice remains intact.
X */
X
X#ifndef SYMBOL_H
X#define SYMBOL_H
X
X#include "zmath.h"
X
X
X/*
X * Symbol Declarations.
X */
X#define SYM_UNDEFINED 0 /* undefined symbol */
X#define SYM_PARAM 1 /* parameter symbol */
X#define SYM_LOCAL 2 /* local symbol */
X#define SYM_GLOBAL 3 /* global symbol */
X#define SYM_STATIC 4 /* static symbol */
X
X#define SCOPE_GLOBAL 0 /* file scope level for global variables */
X#define SCOPE_STATIC 1 /* lowest file scope for static variables */
X
X
Xtypedef struct global GLOBAL;
Xstruct global {
X int g_len; /* length of symbol name */
X short g_filescope; /* file scope level of symbol (0 if global) */
X short g_funcscope; /* function scope level of symbol */
X char *g_name; /* global symbol name */
X VALUE g_value; /* global symbol value */
X GLOBAL *g_next; /* next symbol in hash chain */
X};
X
X
X/*
X * Routines to search for global symbols.
X */
Xextern GLOBAL *addglobal MATH_PROTO((char *name, BOOL isstatic));
Xextern GLOBAL *findglobal MATH_PROTO((char *name));
X
X
X/*
X * Routines to return names of variables.
X */
Xextern char *localname MATH_PROTO((long n));
Xextern char *paramname MATH_PROTO((long n));
Xextern char *globalname MATH_PROTO((GLOBAL *sp));
X
X
X/*
X * Routines to handle entering and leaving of scope levels.
X */
Xextern void resetscopes MATH_PROTO((void));
Xextern void enterfilescope MATH_PROTO((void));
Xextern void exitfilescope MATH_PROTO((void));
Xextern void enterfuncscope MATH_PROTO((void));
Xextern void exitfuncscope MATH_PROTO((void));
X
X
X/*
X * Other routines.
X */
Xextern long addlocal MATH_PROTO((char *name));
Xextern long findlocal MATH_PROTO((char *name));
Xextern long addparam MATH_PROTO((char *name));
Xextern long findparam MATH_PROTO((char *name));
Xextern void initlocals MATH_PROTO((void));
Xextern void initglobals MATH_PROTO((void));
Xextern int writeglobals MATH_PROTO((char *name));
Xextern int symboltype MATH_PROTO((char *name));
Xextern void showglobals MATH_PROTO((void));
X
X#endif
X
X/* END CODE */
SHAR_EOF
chmod 0644 calc2.9.0/symbol.h || echo "restore of calc2.9.0/symbol.h fails"
set `wc -c calc2.9.0/symbol.h`;Sum=$1
if test "$Sum" != "2081"
then echo original size 2081, current size $Sum;fi
echo "x - extracting calc2.9.0/token.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/token.c &&
X/*
X * Copyright (c) 1993 David I. Bell
X * Permission is granted to use, distribute, or modify this source,
X * provided that this copyright notice remains intact.
X *
X * Read input file characters into tokens
X */
X
X#include "stdarg.h"
X#include "calc.h"
X#include "token.h"
X#include "string.h"
X
X
X#define isletter(ch) ((((ch) >= 'a') && ((ch) <= 'z')) || \
X (((ch) >= 'A') && ((ch) <= 'Z')))
X#define isdigit(ch) (((ch) >= '0') && ((ch) <= '9'))
X#define issymbol(ch) (isletter(ch) || isdigit(ch) || ((ch) == '_'))
X
X
X/*
X * Current token.
X */
Xstatic struct {
X short t_type; /* type of token */
X char *t_str; /* string value or symbol name */
X long t_numindex; /* index of numeric value */
X} curtoken;
X
X
Xstatic BOOL rescan; /* TRUE to reread current token */
Xstatic BOOL newlines; /* TRUE to return newlines as tokens */
Xstatic BOOL allsyms; /* TRUE if always want a symbol token */
Xstatic STRINGHEAD strings; /* list of constant strings */
Xstatic char *numbuf; /* buffer for numeric tokens */
Xstatic long numbufsize; /* current size of numeric buffer */
X
Xlong errorcount; /* number of compilation errors */
X
X
X/*
X * Table of keywords
X */
Xstruct keyword {
X char *k_name; /* keyword name */
X int k_token; /* token number */
X};
X
Xstatic struct keyword keywords[] = {
X "if", T_IF,
X "else", T_ELSE,
X "for", T_FOR,
X "while", T_WHILE,
X "do", T_DO,
X "continue", T_CONTINUE,
X "break", T_BREAK,
X "goto", T_GOTO,
X "return", T_RETURN,
X "local", T_LOCAL,
X "global", T_GLOBAL,
X "static", T_STATIC,
X "switch", T_SWITCH,
X "case", T_CASE,
X "default", T_DEFAULT,
X "quit", T_QUIT,
X "exit", T_QUIT,
X "define", T_DEFINE,
X "read", T_READ,
X "show", T_SHOW,
X "help", T_HELP,
X "write", T_WRITE,
X "mat", T_MAT,
X "obj", T_OBJ,
X "print", T_PRINT,
X NULL, 0
X};
X
X
Xstatic void eatcomment MATH_PROTO((void));
Xstatic void eatstring MATH_PROTO((int quotechar));
Xstatic int eatsymbol MATH_PROTO((void));
Xstatic int eatnumber MATH_PROTO((void));
X
X
X/*
X * Initialize all token information.
X */
Xvoid
Xinittokens()
X{
X initstr(&strings);
X newlines = FALSE;
X allsyms = FALSE;
X rescan = FALSE;
X setprompt(PROMPT1);
X}
X
X
X/*
X * Set the new token mode according to the specified flag, and return the
X * previous value of the flag.
X */
Xint
Xtokenmode(flag)
X{
X int oldflag;
X
X oldflag = TM_DEFAULT;
X if (newlines)
X oldflag |= TM_NEWLINES;
X if (allsyms)
X oldflag |= TM_ALLSYMS;
X newlines = FALSE;
X allsyms = FALSE;
X if (flag & TM_NEWLINES)
X newlines = TRUE;
X if (flag & TM_ALLSYMS)
X allsyms = TRUE;
X setprompt(newlines ? PROMPT1 : PROMPT2);
X return oldflag;
X}
X
X
X/*
X * Routine to read in the next token from the input stream.
X * The type of token is returned as a value. If the token is a string or
X * symbol name, information is saved so that the value can be retrieved.
X */
Xint
Xgettoken()
X{
X int ch; /* current input character */
X int type; /* token type */
X
X if (rescan) { /* rescanning */
X rescan = FALSE;
X return curtoken.t_type;
X }
X curtoken.t_str = NULL;
X curtoken.t_numindex = 0;
X type = T_NULL;
X while (type == T_NULL) {
X ch = nextchar();
X if (allsyms && ((ch!=' ') && (ch!=';') && (ch!='"') && (ch!='\n'))) {
X reread();
X type = eatsymbol();
X break;
X }
X switch (ch) {
X case ' ':
X case '\t':
X case '\0':
X break;
X case '\n':
X if (newlines)
X type = T_NEWLINE;
X break;
X case EOF: type = T_EOF; break;
X case '{': type = T_LEFTBRACE; break;
X case '}': type = T_RIGHTBRACE; break;
X case '(': type = T_LEFTPAREN; break;
X case ')': type = T_RIGHTPAREN; break;
X case '[': type = T_LEFTBRACKET; break;
X case ']': type = T_RIGHTBRACKET; break;
X case ';': type = T_SEMICOLON; break;
X case ':': type = T_COLON; break;
X case ',': type = T_COMMA; break;
X case '?': type = T_QUESTIONMARK; break;
X case '"':
X case '\'':
X type = T_STRING;
X eatstring(ch);
X break;
X case '^':
X switch (nextchar()) {
X case '=': type = T_POWEREQUALS; break;
X default: type = T_POWER; reread();
X }
X break;
X case '=':
X switch (nextchar()) {
X case '=': type = T_EQ; break;
X default: type = T_ASSIGN; reread();
X }
X break;
X case '+':
X switch (nextchar()) {
X case '+': type = T_PLUSPLUS; break;
X case '=': type = T_PLUSEQUALS; break;
X default: type = T_PLUS; reread();
X }
X break;
X case '-':
X switch (nextchar()) {
X case '-': type = T_MINUSMINUS; break;
X case '=': type = T_MINUSEQUALS; break;
X default: type = T_MINUS; reread();
X }
X break;
X case '*':
X switch (nextchar()) {
X case '=': type = T_MULTEQUALS; break;
X case '*':
X switch (nextchar()) {
X case '=': type = T_POWEREQUALS; break;
X default: type = T_POWER; reread();
X }
X break;
X default: type = T_MULT; reread();
X }
X break;
X case '/':
X switch (nextchar()) {
X case '/':
X switch (nextchar()) {
X case '=': type = T_SLASHSLASHEQUALS; break;
X default: reread(); type = T_SLASHSLASH; break;
X }
X break;
X case '=': type = T_DIVEQUALS; break;
X case '*': eatcomment(); break;
X default: type = T_DIV; reread();
X }
X break;
X case '%':
X switch (nextchar()) {
X case '=': type = T_MODEQUALS; break;
X default: type = T_MOD; reread();
X }
X break;
X case '<':
X switch (nextchar()) {
X case '=': type = T_LE; break;
X case '<':
X switch (nextchar()) {
X case '=': type = T_LSHIFTEQUALS; break;
X default: reread(); type = T_LEFTSHIFT; break;
X }
X break;
X default: type = T_LT; reread();
X }
X break;
X case '>':
X switch (nextchar()) {
X case '=': type = T_GE; break;
X case '>':
X switch (nextchar()) {
X case '=': type = T_RSHIFTEQUALS; break;
X default: reread(); type = T_RIGHTSHIFT; break;
X }
X break;
X default: type = T_GT; reread();
X }
X break;
X case '&':
X switch (nextchar()) {
X case '&': type = T_ANDAND; break;
X case '=': type = T_ANDEQUALS; break;
X default: type = T_AND; reread(); break;
X }
X break;
X case '|':
X switch (nextchar()) {
X case '|': type = T_OROR; break;
X case '=': type = T_OREQUALS; break;
X default: type = T_OR; reread(); break;
X }
X break;
X case '!':
X switch (nextchar()) {
X case '=': type = T_NE; break;
X default: type = T_NOT; reread(); break;
X }
X break;
X case '\\':
X switch (nextchar()) {
X case '\n': setprompt(PROMPT2); break;
X default: scanerror(T_NULL, "Unknown token character '%c'", ch);
X }
X break;
X default:
X if (isletter(ch)) {
X reread();
X type = eatsymbol();
X break;
X }
X if (isdigit(ch) || (ch == '.')) {
X reread();
X type = eatnumber();
X break;
X }
X scanerror(T_NULL, "Unknown token character '%c'", ch);
X }
X }
X curtoken.t_type = (short)type;
X return type;
X}
X
X
X/*
X * Continue to eat up a comment string.
X * The leading slash-asterisk has just been scanned at this point.
X */
Xstatic void
Xeatcomment()
X{
X int ch;
X
X for (;;) {
X ch = nextchar();
X if (ch == '*') {
X ch = nextchar();
X if (ch == '/')
X return;
X reread();
X }
X if ((ch == EOF) || (ch == '\0') ||
X (newlines && (ch == '\n') && inputisterminal())) {
X reread();
X scanerror(T_NULL, "Unterminated comment");
X return;
X }
X }
X}
X
X
X/*
X * Read in a string and add it to the literal string pool.
X * The leading single or double quote has been read in at this point.
X */
Xstatic void
Xeatstring(quotechar)
X{
X register char *cp; /* current character address */
X int ch; /* current character */
X char buf[MAXSTRING+1]; /* buffer for string */
X
X cp = buf;
X for (;;) {
X ch = nextchar();
X switch (ch) {
X case '\0':
X case EOF:
X case '\n':
X reread();
X scanerror(T_NULL, "Unterminated string constant");
X *cp = '\0';
X curtoken.t_str = addliteral(buf);
X return;
X
X case '\\':
X ch = nextchar();
X switch (ch) {
X case 'n': ch = '\n'; break;
X case 'r': ch = '\r'; break;
X case 't': ch = '\t'; break;
X case 'b': ch = '\b'; break;
X case 'f': ch = '\f'; break;
X case '\n':
X setprompt(PROMPT2);
X continue;
X case EOF:
X reread();
X continue;
X }
X *cp++ = (char)ch;
X break;
X
X case '"':
X case '\'':
X if (ch == quotechar) {
X *cp = '\0';
X curtoken.t_str = addliteral(buf);
X return;
X }
X /* fall into default case */
X
X default:
X *cp++ = (char)ch;
X }
X }
X}
X
X
X/*
X * Read in a symbol name which may or may not be a keyword.
X * If allsyms is set, keywords are not looked up and almost all chars
X * will be accepted for the symbol. Returns the type of symbol found.
X */
Xstatic int
Xeatsymbol()
X{
X register struct keyword *kp; /* pointer to current keyword */
X register char *cp; /* current character pointer */
X int ch; /* current character */
X int cc; /* character count */
X static char buf[SYMBOLSIZE+1]; /* temporary buffer */
X
X cp = buf;
X cc = SYMBOLSIZE;
X if (allsyms) {
X for (;;) {
X ch = nextchar();
X if ((ch == ' ') || (ch == ';') || (ch == '\n'))
X break;
X if (cc-- > 0)
X *cp++ = (char)ch;
X }
X reread();
X *cp = '\0';
X if (cc < 0)
X scanerror(T_NULL, "Symbol too long");
X curtoken.t_str = buf;
X return T_SYMBOL;
X }
X for (;;) {
X ch = nextchar();
X if (!issymbol(ch))
X break;
X if (cc-- > 0)
X *cp++ = (char)ch;
X }
X reread();
X *cp = '\0';
X if (cc < 0)
X scanerror(T_NULL, "Symbol too long");
X for (kp = keywords; kp->k_name; kp++)
X if (strcmp(kp->k_name, buf) == 0)
X return kp->k_token;
X curtoken.t_str = buf;
X return T_SYMBOL;
X}
X
X
X/*
X * Read in and remember a possibly numeric constant value.
X * The constant is inserted into a constant table so further uses
X * of the same constant will not take more memory. This can also
X * return just a period, which is used for element accesses and for
X * the old numeric value.
X */
Xstatic int
Xeatnumber()
X{
X register char *cp; /* current character pointer */
X long len; /* parsed size of number */
X long res; /* result of parsing number */
X
X if (numbufsize == 0) {
X numbuf = (char *)malloc(128+1);
X if (numbuf == NULL)
X math_error("Cannot allocate number buffer");
X numbufsize = 128;
X }
X cp = numbuf;
X len = 0;
X for (;;) {
X if (len >= numbufsize) {
X cp = (char *)realloc(numbuf, numbufsize + 1001);
X if (cp == NULL)
X math_error("Cannot reallocate number buffer");
X numbuf = cp;
X numbufsize += 1000;
X cp = &numbuf[len];
X }
X *cp = nextchar();
X *(++cp) = '\0';
X if ((numbuf[0] == '.') && isletter(numbuf[1])) {
X reread();
X return T_PERIOD;
X }
X res = qparse(numbuf, QPF_IMAG);
X if (res < 0) {
X reread();
X scanerror(T_NULL, "Badly formatted number");
X curtoken.t_numindex = addnumber("0");
X return T_NUMBER;
X }
X if (res != ++len)
X break;
X }
X cp[-1] = '\0';
X reread();
X if ((numbuf[0] == '.') && (numbuf[1] == '\0')) {
X curtoken.t_numindex = 0;
X return T_OLDVALUE;
X }
X cp -= 2;
X res = T_NUMBER;
X if ((*cp == 'i') || (*cp == 'I')) {
X *cp = '\0';
X res = T_IMAGINARY;
X }
X curtoken.t_numindex = addnumber(numbuf);
X return res;
X}
X
X
X/*
X * Return the string value of the current token.
X */
Xchar *
Xtokenstring()
X{
X return curtoken.t_str;
X}
X
X
X/*
X * Return the constant index of a numeric token.
X */
Xlong
Xtokennumber()
X{
X return curtoken.t_numindex;
X}
X
X
X/*
X * Push back the token just read so that it will be seen again.
X */
Xvoid
Xrescantoken()
X{
X rescan = TRUE;
X}
X
X
X/*
X * Describe an error message.
X * Then skip to the next specified token (or one more powerful).
X */
X#ifdef VARARGS
X# define VA_ALIST skip, fmt, va_alist
X# define VA_DCL int skip; char *fmt; va_dcl
X#else
X# ifdef __STDC__
X# define VA_ALIST int skip, char *fmt, ...
X# define VA_DCL
X# else
X# define VA_ALIST skip, fmt
X# define VA_DCL int skip; char *fmt;
X# endif
X#endif
X/*VARARGS*/
Xvoid
Xscanerror(VA_ALIST)
X VA_DCL
X{
X va_list ap;
X char *name; /* name of file with error */
X char buf[MAXERROR+1];
X
X errorcount++;
X name = inputname();
X if (name)
X fprintf(stderr, "\"%s\", line %ld: ", name, linenumber());
X#ifdef VARARGS
X va_start(ap);
X#else
X va_start(ap, fmt);
X#endif
X vsprintf(buf, fmt, ap);
X va_end(ap);
X fprintf(stderr, "%s\n", buf);
X switch (skip) {
X case T_NULL:
X return;
X case T_COMMA:
X rescan = TRUE;
X for (;;) {
X switch (gettoken()) {
X case T_NEWLINE:
X case T_SEMICOLON:
X case T_LEFTBRACE:
X case T_RIGHTBRACE:
X case T_EOF:
X case T_COMMA:
X rescan = TRUE;
X return;
X }
X }
X default:
X fprintf(stderr, "Unknown skip token for scanerror\n");
X /* fall into semicolon case */
X /*FALLTHRU*/
X case T_SEMICOLON:
X rescan = TRUE;
X for (;;) switch (gettoken()) {
X case T_NEWLINE:
X case T_SEMICOLON:
X case T_LEFTBRACE:
X case T_RIGHTBRACE:
X case T_EOF:
X rescan = TRUE;
X return;
X }
X }
X}
X
X/* END CODE */
SHAR_EOF
chmod 0644 calc2.9.0/token.c || echo "restore of calc2.9.0/token.c fails"
set `wc -c calc2.9.0/token.c`;Sum=$1
if test "$Sum" != "12451"
then echo original size 12451, current size $Sum;fi
echo "x - extracting calc2.9.0/token.h (Text)"
sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/token.h &&
X/*
X * Copyright (c) 1993 David I. Bell
X * Permission is granted to use, distribute, or modify this source,
X * provided that this copyright notice remains intact.
X */
X
X#ifndef TOKEN_H
X#define TOKEN_H
X
X#include "zmath.h"
X
X
X/*
X * Token types
X */
X#define T_NULL 0 /* null token */
X#define T_LEFTPAREN 1 /* left parenthesis "(" */
X#define T_RIGHTPAREN 2 /* right parenthesis ")" */
X#define T_LEFTBRACE 3 /* left brace "{" */
X#define T_RIGHTBRACE 4 /* right brace "}" */
X#define T_SEMICOLON 5 /* end of statement ";" */
X#define T_EOF 6 /* end of file */
X#define T_COLON 7 /* label character ":" */
X#define T_ASSIGN 8 /* assignment "=" */
X#define T_PLUS 9 /* plus sign "+" */
X#define T_MINUS 10 /* minus sign "-" */
X#define T_MULT 11 /* multiply sign "*" */
X#define T_DIV 12 /* divide sign "/" */
X#define T_MOD 13 /* modulo sign "%" */
X#define T_POWER 14 /* power sign "^" or "**" */
X#define T_EQ 15 /* equality "==" */
X#define T_NE 16 /* notequal "!=" */
X#define T_LT 17 /* less than "<" */
X#define T_GT 18 /* greater than ">" */
X#define T_LE 19 /* less than or equals "<=" */
X#define T_GE 20 /* greater than or equals ">=" */
X#define T_LEFTBRACKET 21 /* left bracket "[" */
X#define T_RIGHTBRACKET 22 /* right bracket "]" */
X#define T_SYMBOL 23 /* symbol name */
X#define T_STRING 24 /* string value (double quotes) */
X#define T_NUMBER 25 /* numeric real constant */
X#define T_PLUSEQUALS 26 /* plus equals "+=" */
X#define T_MINUSEQUALS 27 /* minus equals "-=" */
X#define T_MULTEQUALS 28 /* multiply equals "*=" */
X#define T_DIVEQUALS 29 /* divide equals "/=" */
X#define T_MODEQUALS 30 /* modulo equals "%=" */
X#define T_PLUSPLUS 31 /* plusplus "++" */
X#define T_MINUSMINUS 32 /* minusminus "--" */
X#define T_COMMA 33 /* comma "," */
X#define T_ANDAND 34 /* logical and "&&" */
X#define T_OROR 35 /* logical or "||" */
X#define T_OLDVALUE 36 /* old value from previous calculation */
X#define T_SLASHSLASH 37 /* integer divide "//" */
X#define T_NEWLINE 38 /* newline character */
X#define T_SLASHSLASHEQUALS 39 /* integer divide equals "//=" */
X#define T_AND 40 /* arithmetic and "&" */
X#define T_OR 41 /* arithmetic or "|" */
X#define T_NOT 42 /* logical not "!" */
X#define T_LEFTSHIFT 43 /* left shift "<<" */
X#define T_RIGHTSHIFT 44 /* right shift ">>" */
X#define T_ANDEQUALS 45 /* and equals "&=" */
X#define T_OREQUALS 46 /* or equals "|= */
X#define T_LSHIFTEQUALS 47 /* left shift equals "<<=" */
X#define T_RSHIFTEQUALS 48 /* right shift equals ">>= */
X#define T_POWEREQUALS 49 /* power equals "^=" or "**=" */
X#define T_PERIOD 50 /* period "." */
X#define T_IMAGINARY 51 /* numeric imaginary constant */
X#define T_AMPERSAND 52 /* ampersand "&" */
X#define T_QUESTIONMARK 53 /* question mark "?" */
X
X
X/*
X * Keyword tokens
X */
X#define T_IF 101 /* if keyword */
X#define T_ELSE 102 /* else keyword */
X#define T_WHILE 103 /* while keyword */
X#define T_CONTINUE 104 /* continue keyword */
X#define T_BREAK 105 /* break keyword */
X#define T_GOTO 106 /* goto keyword */
X#define T_RETURN 107 /* return keyword */
X#define T_LOCAL 108 /* local keyword */
X#define T_GLOBAL 109 /* global keyword */
X#define T_STATIC 110 /* static keyword */
X#define T_DO 111 /* do keyword */
X#define T_FOR 112 /* for keyword */
X#define T_SWITCH 113 /* switch keyword */
X#define T_CASE 114 /* case keyword */
X#define T_DEFAULT 115 /* default keyword */
X#define T_QUIT 116 /* quit keyword */
X#define T_DEFINE 117 /* define keyword */
X#define T_READ 118 /* read keyword */
X#define T_SHOW 119 /* show keyword */
X#define T_HELP 120 /* help keyword */
X#define T_WRITE 121 /* write keyword */
X#define T_MAT 122 /* mat keyword */
X#define T_OBJ 123 /* obj keyword */
X#define T_PRINT 124 /* print keyword */
X
X
X#define iskeyword(n) ((n) > 100) /* TRUE if token is a keyword */
X
X
X/*
X * Flags returned describing results of expression parsing.
X */
X#define EXPR_RVALUE 0x0001 /* result is an rvalue */
X#define EXPR_CONST 0x0002 /* result is constant */
X#define EXPR_ASSIGN 0x0004 /* result is an assignment */
X
X#define isrvalue(n) ((n) & EXPR_RVALUE) /* TRUE if expression is rvalue */
X#define islvalue(n) (((n) & EXPR_RVALUE) == 0) /* TRUE if expr is lvalue */
X#define isconst(n) ((n) & EXPR_CONST) /* TRUE if expr is constant */
X#define isassign(n) ((n) & EXPR_ASSIGN) /* TRUE if expr is an assignment */
X
X
X/*
X * Flags for modes for tokenizing.
X */
X#define TM_DEFAULT 0x0 /* normal mode */
X#define TM_NEWLINES 0x1 /* treat any newline as a token */
X#define TM_ALLSYMS 0x2 /* treat almost everything as a symbol */
X
X
Xextern long errorcount; /* number of errors found */
X
Xextern char *tokenstring MATH_PROTO((void));
Xextern long tokennumber MATH_PROTO((void));
Xextern void inittokens MATH_PROTO((void));
Xextern int tokenmode MATH_PROTO((int flag));
Xextern int gettoken MATH_PROTO((void));
Xextern void rescantoken MATH_PROTO((void));
X
X#ifdef VARARGS
Xextern void scanerror();
X#else
Xextern void scanerror MATH_PROTO((int, char *, ...));
X#endif
X
X#endif
X
X/* END CODE */
SHAR_EOF
chmod 0644 calc2.9.0/token.h || echo "restore of calc2.9.0/token.h fails"
set `wc -c calc2.9.0/token.h`;Sum=$1
if test "$Sum" != "5031"
then echo original size 5031, current size $Sum;fi
echo "x - extracting calc2.9.0/value.c (Text)"
sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/value.c &&
X/*
X * Copyright (c) 1993 David I. Bell
X * Permission is granted to use, distribute, or modify this source,
X * provided that this copyright notice remains intact.
X *
X * Generic value manipulation routines.
X */
X
X#include "value.h"
X#include "opcodes.h"
X#include "func.h"
X#include "symbol.h"
X#include "string.h"
X
X
X/*
X * Free a value and set its type to undefined.
X */
Xvoid
Xfreevalue(vp)
X register VALUE *vp; /* value to be freed */
X{
X int type; /* type of value being freed */
X
X type = vp->v_type;
X vp->v_type = V_NULL;
X switch (type) {
X case V_NULL:
X case V_ADDR:
X case V_FILE:
X break;
X case V_STR:
X if (vp->v_subtype == V_STRALLOC)
X free(vp->v_str);
X break;
X case V_NUM:
X qfree(vp->v_num);
X break;
X case V_COM:
X comfree(vp->v_com);
X break;
X case V_MAT:
X matfree(vp->v_mat);
X break;
X case V_LIST:
X listfree(vp->v_list);
X break;
X case V_ASSOC:
X assocfree(vp->v_assoc);
X break;
X case V_OBJ:
X objfree(vp->v_obj);
X break;
X default:
X math_error("Freeing unknown value type");
X }
X}
X
X
X/*
X * Copy a value from one location to another.
X * This overwrites the specified new value without checking it.
X */
Xvoid
Xcopyvalue(oldvp, newvp)
X register VALUE *oldvp; /* value to be copied from */
X register VALUE *newvp; /* value to be copied into */
X{
X newvp->v_type = V_NULL;
X switch (oldvp->v_type) {
X case V_NULL:
X break;
X case V_FILE:
X newvp->v_file = oldvp->v_file;
X break;
X case V_NUM:
X newvp->v_num = qlink(oldvp->v_num);
X break;
X case V_COM:
X newvp->v_com = clink(oldvp->v_com);
X break;
X case V_STR:
X newvp->v_str = oldvp->v_str;
X if (oldvp->v_subtype == V_STRALLOC) {
X newvp->v_str = (char *)malloc(strlen(oldvp->v_str) + 1);
X if (newvp->v_str == NULL)
X math_error("Cannot get memory for string copy");
X strcpy(newvp->v_str, oldvp->v_str);
X }
X break;
X case V_MAT:
X newvp->v_mat = matcopy(oldvp->v_mat);
X break;
X case V_LIST:
X newvp->v_list = listcopy(oldvp->v_list);
X break;
X case V_ASSOC:
X newvp->v_assoc = assoccopy(oldvp->v_assoc);
X break;
X case V_ADDR:
X newvp->v_addr = oldvp->v_addr;
X break;
X case V_OBJ:
X newvp->v_obj = objcopy(oldvp->v_obj);
X break;
X default:
X math_error("Copying unknown value type");
X }
X newvp->v_subtype = oldvp->v_subtype;
X newvp->v_type = oldvp->v_type;
X
X}
X
X
X/*
X * Negate an arbitrary value.
X * Result is placed in the indicated location.
X */
Xvoid
Xnegvalue(vp, vres)
X VALUE *vp, *vres;
X{
X vres->v_type = V_NULL;
X switch (vp->v_type) {
X case V_NUM:
X vres->v_num = qneg(vp->v_num);
X vres->v_type = V_NUM;
X return;
X case V_COM:
X vres->v_com = cneg(vp->v_com);
X vres->v_type = V_COM;
X return;
X case V_MAT:
X vres->v_mat = matneg(vp->v_mat);
X vres->v_type = V_MAT;
X return;
X case V_OBJ:
X *vres = objcall(OBJ_NEG, vp, NULL_VALUE, NULL_VALUE);
X return;
X default:
X math_error("Illegal value for negation");
X }
X}
X
X
X/*
X * Add two arbitrary values together.
X * Result is placed in the indicated location.
X */
Xvoid
Xaddvalue(v1, v2, vres)
X VALUE *v1, *v2, *vres;
X{
X COMPLEX *c;
X
X vres->v_type = V_NULL;
X switch (TWOVAL(v1->v_type, v2->v_type)) {
X case TWOVAL(V_NUM, V_NUM):
X vres->v_num = qadd(v1->v_num, v2->v_num);
X vres->v_type = V_NUM;
X return;
X case TWOVAL(V_COM, V_NUM):
X vres->v_com = caddq(v1->v_com, v2->v_num);
X vres->v_type = V_COM;
X return;
X case TWOVAL(V_NUM, V_COM):
X vres->v_com = caddq(v2->v_com, v1->v_num);
X vres->v_type = V_COM;
X return;
X case TWOVAL(V_COM, V_COM):
X vres->v_com = cadd(v1->v_com, v2->v_com);
X vres->v_type = V_COM;
X c = vres->v_com;
X if (!cisreal(c))
X return;
X vres->v_num = qlink(c->real);
X vres->v_type = V_NUM;
X comfree(c);
X return;
X case TWOVAL(V_MAT, V_MAT):
X vres->v_mat = matadd(v1->v_mat, v2->v_mat);
X vres->v_type = V_MAT;
X return;
X default:
X if ((v1->v_type != V_OBJ) && (v2->v_type != V_OBJ))
X math_error("Non-compatible values for add");
X *vres = objcall(OBJ_ADD, v1, v2, NULL_VALUE);
X return;
X }
X}
X
X
X/*
X * Subtract one arbitrary value from another one.
X * Result is placed in the indicated location.
X */
Xvoid
Xsubvalue(v1, v2, vres)
X VALUE *v1, *v2, *vres;
X{
X COMPLEX *c;
X
X vres->v_type = V_NULL;
X switch (TWOVAL(v1->v_type, v2->v_type)) {
X case TWOVAL(V_NUM, V_NUM):
X vres->v_num = qsub(v1->v_num, v2->v_num);
X vres->v_type = V_NUM;
X return;
X case TWOVAL(V_COM, V_NUM):
X vres->v_com = csubq(v1->v_com, v2->v_num);
X vres->v_type = V_COM;
X return;
X case TWOVAL(V_NUM, V_COM):
X c = csubq(v2->v_com, v1->v_num);
X vres->v_com = cneg(c);
X comfree(c);
X vres->v_type = V_COM;
X return;
X case TWOVAL(V_COM, V_COM):
X vres->v_com = csub(v1->v_com, v2->v_com);
X vres->v_type = V_COM;
X c = vres->v_com;
X if (!cisreal(c))
X return;
X vres->v_num = qlink(c->real);
X vres->v_type = V_NUM;
X comfree(c);
X return;
X case TWOVAL(V_MAT, V_MAT):
X vres->v_mat = matsub(v1->v_mat, v2->v_mat);
X vres->v_type = V_MAT;
X return;
X default:
X if ((v1->v_type != V_OBJ) && (v2->v_type != V_OBJ))
X math_error("Non-compatible values for subtract");
X *vres = objcall(OBJ_SUB, v1, v2, NULL_VALUE);
X return;
X }
X}
X
X
X/*
X * Multiply two arbitrary values together.
X * Result is placed in the indicated location.
X */
Xvoid
Xmulvalue(v1, v2, vres)
X VALUE *v1, *v2, *vres;
X{
X COMPLEX *c;
X
X vres->v_type = V_NULL;
X switch (TWOVAL(v1->v_type, v2->v_type)) {
X case TWOVAL(V_NUM, V_NUM):
X vres->v_num = qmul(v1->v_num, v2->v_num);
X vres->v_type = V_NUM;
X return;
X case TWOVAL(V_COM, V_NUM):
X vres->v_com = cmulq(v1->v_com, v2->v_num);
X vres->v_type = V_COM;
X break;
X case TWOVAL(V_NUM, V_COM):
X vres->v_com = cmulq(v2->v_com, v1->v_num);
X vres->v_type = V_COM;
X break;
X case TWOVAL(V_COM, V_COM):
X vres->v_com = cmul(v1->v_com, v2->v_com);
X vres->v_type = V_COM;
X break;
X case TWOVAL(V_MAT, V_MAT):
X vres->v_mat = matmul(v1->v_mat, v2->v_mat);
X vres->v_type = V_MAT;
X return;
X case TWOVAL(V_MAT, V_NUM):
X case TWOVAL(V_MAT, V_COM):
X vres->v_mat = matmulval(v1->v_mat, v2);
X vres->v_type = V_MAT;
X return;
X case TWOVAL(V_NUM, V_MAT):
X case TWOVAL(V_COM, V_MAT):
X vres->v_mat = matmulval(v2->v_mat, v1);
X vres->v_type = V_MAT;
X return;
X default:
X if ((v1->v_type != V_OBJ) && (v2->v_type != V_OBJ))
X math_error("Non-compatible values for multiply");
X *vres = objcall(OBJ_MUL, v1, v2, NULL_VALUE);
X return;
X }
X c = vres->v_com;
X if (cisreal(c)) {
X vres->v_num = qlink(c->real);
X vres->v_type = V_NUM;
X comfree(c);
X }
X}
X
X
X/*
X * Square an arbitrary value.
X * Result is placed in the indicated location.
X */
Xvoid
Xsquarevalue(vp, vres)
X VALUE *vp, *vres;
X{
X COMPLEX *c;
X
X vres->v_type = V_NULL;
X switch (vp->v_type) {
X case V_NUM:
X vres->v_num = qsquare(vp->v_num);
X vres->v_type = V_NUM;
X return;
X case V_COM:
X vres->v_com = csquare(vp->v_com);
X vres->v_type = V_COM;
X c = vres->v_com;
X if (!cisreal(c))
X return;
X vres->v_num = qlink(c->real);
X vres->v_type = V_NUM;
X comfree(c);
X return;
X case V_MAT:
X vres->v_mat = matsquare(vp->v_mat);
X vres->v_type = V_MAT;
X return;
X case V_OBJ:
X *vres = objcall(OBJ_SQUARE, vp, NULL_VALUE, NULL_VALUE);
X return;
X default:
X math_error("Illegal value for squaring");
X }
X}
X
X
X/*
X * Invert an arbitrary value.
X * Result is placed in the indicated location.
X */
Xvoid
Xinvertvalue(vp, vres)
X VALUE *vp, *vres;
X{
X vres->v_type = V_NULL;
X switch (vp->v_type) {
X case V_NUM:
X vres->v_num = qinv(vp->v_num);
X vres->v_type = V_NUM;
X return;
X case V_COM:
X vres->v_com = cinv(vp->v_com);
X vres->v_type = V_COM;
X return;
X case V_MAT:
X vres->v_mat = matinv(vp->v_mat);
X vres->v_type = V_MAT;
X return;
X case V_OBJ:
X *vres = objcall(OBJ_INV, vp, NULL_VALUE, NULL_VALUE);
X return;
X default:
X math_error("Illegal value for inverting");
X }
X}
X
X
X/*
X * Round an arbitrary value to the specified number of decimal places.
X * Result is placed in the indicated location.
X */
Xvoid
Xroundvalue(v1, v2, vres)
X VALUE *v1, *v2, *vres;
X{
X long places;
X NUMBER *q;
X COMPLEX *c;
X
X switch (v2->v_type) {
X case V_NUM:
X q = v2->v_num;
X if (qisfrac(q) || zisbig(q->num))
X math_error("Bad number of places for round");
X places = qtoi(q);
X break;
X case V_INT:
X places = v2->v_int;
X break;
X default:
X math_error("Bad value type for places in round");
X }
X if (places < 0)
X math_error("Negative number of places in round");
X vres->v_type = V_NULL;
X switch (v1->v_type) {
X case V_NUM:
X if (qisint(v1->v_num))
X vres->v_num = qlink(v1->v_num);
X else
X vres->v_num = qround(v1->v_num, places);
X vres->v_type = V_NUM;
X return;
X case V_COM:
X if (cisint(v1->v_com)) {
X vres->v_com = clink(v1->v_com);
X vres->v_type = V_COM;
X return;
X }
X vres->v_com = cround(v1->v_com, places);
X vres->v_type = V_COM;
X c = vres->v_com;
X if (cisreal(c)) {
X vres->v_num = qlink(c->real);
X vres->v_type = V_NUM;
X comfree(c);
X }
X return;
X case V_MAT:
X vres->v_mat = matround(v1->v_mat, places);
X vres->v_type = V_MAT;
X return;
X case V_OBJ:
X *vres = objcall(OBJ_ROUND, v1, v2, NULL_VALUE);
X return;
X default:
X math_error("Illegal value for round");
X }
X}
X
X
X/*
X * Round an arbitrary value to the specified number of binary places.
X * Result is placed in the indicated location.
X */
Xvoid
Xbroundvalue(v1, v2, vres)
X VALUE *v1, *v2, *vres;
X{
X long places;
X NUMBER *q;
X COMPLEX *c;
X
X switch (v2->v_type) {
X case V_NUM:
X q = v2->v_num;
X if (qisfrac(q) || zisbig(q->num))
X math_error("Bad number of places for bround");
X places = qtoi(q);
X break;
X case V_INT:
X places = v2->v_int;
X break;
X default:
X math_error("Bad value type for places in bround");
X }
X if (places < 0)
X math_error("Negative number of places in bround");
X vres->v_type = V_NULL;
X switch (v1->v_type) {
X case V_NUM:
X if (qisint(v1->v_num))
X vres->v_num = qlink(v1->v_num);
X else
X vres->v_num = qbround(v1->v_num, places);
X vres->v_type = V_NUM;
X return;
X case V_COM:
X if (cisint(v1->v_com)) {
X vres->v_com = clink(v1->v_com);
X vres->v_type = V_COM;
X return;
X }
X vres->v_com = cbround(v1->v_com, places);
X vres->v_type = V_COM;
X c = vres->v_com;
X if (cisreal(c)) {
X vres->v_num = qlink(c->real);
X vres->v_type = V_NUM;
X comfree(c);
X }
X return;
X case V_MAT:
X vres->v_mat = matbround(v1->v_mat, places);
X vres->v_type = V_MAT;
X return;
X case V_OBJ:
X *vres = objcall(OBJ_BROUND, v1, v2, NULL_VALUE);
X return;
X default:
X math_error("Illegal value for bround");
X }
X}
X
X
X/*
X * Take the integer part of an arbitrary value.
X * Result is placed in the indicated location.
X */
Xvoid
Xintvalue(vp, vres)
X VALUE *vp, *vres;
X{
X COMPLEX *c;
X
X vres->v_type = V_NULL;
X switch (vp->v_type) {
X case V_NUM:
X if (qisint(vp->v_num))
X vres->v_num = qlink(vp->v_num);
X else
X vres->v_num = qint(vp->v_num);
X vres->v_type = V_NUM;
X return;
X case V_COM:
X if (cisint(vp->v_com)) {
X vres->v_com = clink(vp->v_com);
X vres->v_type = V_COM;
X return;
X }
X vres->v_com = cint(vp->v_com);
X vres->v_type = V_COM;
X c = vres->v_com;
X if (cisreal(c)) {
X vres->v_num = qlink(c->real);
X vres->v_type = V_NUM;
X comfree(c);
X }
X return;
X case V_MAT:
X vres->v_mat = matint(vp->v_mat);
X vres->v_type = V_MAT;
X return;
X case V_OBJ:
X *vres = objcall(OBJ_INT, vp, NULL_VALUE, NULL_VALUE);
X return;
X default:
X math_error("Illegal value for int");
X }
X}
X
X
X/*
X * Take the fractional part of an arbitrary value.
X * Result is placed in the indicated location.
X */
Xvoid
Xfracvalue(vp, vres)
X VALUE *vp, *vres;
X{
X vres->v_type = V_NULL;
X switch (vp->v_type) {
X case V_NUM:
X if (qisint(vp->v_num))
X vres->v_num = qlink(&_qzero_);
X else
X vres->v_num = qfrac(vp->v_num);
X vres->v_type = V_NUM;
X return;
X case V_COM:
X if (cisint(vp->v_com)) {
X vres->v_num = clink(&_qzero_);
X vres->v_type = V_NUM;
X return;
X }
X vres->v_com = cfrac(vp->v_com);
X vres->v_type = V_COM;
X return;
X case V_MAT:
X vres->v_mat = matfrac(vp->v_mat);
X vres->v_type = V_MAT;
X return;
X case V_OBJ:
X *vres = objcall(OBJ_FRAC, vp, NULL_VALUE, NULL_VALUE);
X return;
X default:
X math_error("Illegal value for frac function");
X }
X}
X
X
X/*
X * Increment an arbitrary value by one.
X * Result is placed in the indicated location.
X */
Xvoid
Xincvalue(vp, vres)
X VALUE *vp, *vres;
X{
X switch (vp->v_type) {
X case V_NUM:
X vres->v_num = qinc(vp->v_num);
X vres->v_type = V_NUM;
X return;
X case V_COM:
X vres->v_com = caddq(vp->v_com, &_qone_);
X vres->v_type = V_COM;
X return;
X case V_OBJ:
X *vres = objcall(OBJ_INC, vp, NULL_VALUE, NULL_VALUE);
X return;
X default:
X math_error("Illegal value for incrementing");
X }
X}
X
X
X/*
X * Decrement an arbitrary value by one.
X * Result is placed in the indicated location.
X */
Xvoid
Xdecvalue(vp, vres)
X VALUE *vp, *vres;
X{
X switch (vp->v_type) {
X case V_NUM:
X vres->v_num = qdec(vp->v_num);
X vres->v_type = V_NUM;
X return;
X case V_COM:
X vres->v_com = caddq(vp->v_com, &_qnegone_);
X vres->v_type = V_COM;
X return;
X case V_OBJ:
X *vres = objcall(OBJ_DEC, vp, NULL_VALUE, NULL_VALUE);
X return;
X default:
X math_error("Illegal value for decrementing");
X }
X}
X
X
X/*
X * Produce the 'conjugate' of an arbitrary value.
X * Result is placed in the indicated location.
X * (Example: complex conjugate.)
X */
Xvoid
Xconjvalue(vp, vres)
X VALUE *vp, *vres;
X{
X vres->v_type = V_NULL;
X switch (vp->v_type) {
X case V_NUM:
X vres->v_num = qlink(vp->v_num);
X vres->v_type = V_NUM;
X return;
X case V_COM:
X vres->v_com = comalloc();
X vres->v_com->real = qlink(vp->v_com->real);
X vres->v_com->imag = qneg(vp->v_com->imag);
X vres->v_type = V_COM;
X return;
X case V_MAT:
X vres->v_mat = matconj(vp->v_mat);
X vres->v_type = V_MAT;
X return;
X case V_OBJ:
X *vres = objcall(OBJ_CONJ, vp, NULL_VALUE, NULL_VALUE);
X return;
X default:
X math_error("Illegal value for conjugation");
X }
X}
X
X
X/*
X * Take the square root of an arbitrary value within the specified error.
X * Result is placed in the indicated location.
X */
Xvoid
Xsqrtvalue(v1, v2, vres)
X VALUE *v1, *v2, *vres;
X{
X NUMBER *q, *tmp;
X COMPLEX *c;
X
X if (v2->v_type != V_NUM)
X math_error("Non-real epsilon for sqrt");
X q = v2->v_num;
X if (qisneg(q) || qiszero(q))
X math_error("Illegal epsilon value for sqrt");
X switch (v1->v_type) {
X case V_NUM:
X if (!qisneg(v1->v_num)) {
X vres->v_num = qsqrt(v1->v_num, q);
X vres->v_type = V_NUM;
X return;
X }
X tmp = qneg(v1->v_num);
X c = comalloc();
X c->imag = qsqrt(tmp, q);
X qfree(tmp);
X vres->v_com = c;
X vres->v_type = V_COM;
X break;
X case V_COM:
X vres->v_com = csqrt(v1->v_com, q);
X vres->v_type = V_COM;
X break;
X case V_OBJ:
X *vres = objcall(OBJ_SQRT, v1, v2, NULL_VALUE);
X return;
X default:
X math_error("Bad value for taking square root");
X }
X c = vres->v_com;
X if (cisreal(c)) {
X vres->v_num = qlink(c->real);
X vres->v_type = V_NUM;
X comfree(c);
X }
X}
X
X
X/*
X * Take the Nth root of an arbitrary value within the specified error.
X * Result is placed in the indicated location.
X */
Xvoid
Xrootvalue(v1, v2, v3, vres)
X VALUE *v1; /* value to take root of */
X VALUE *v2; /* value specifying root to take */
X VALUE *v3; /* value specifying error */
X VALUE *vres;
X{
X NUMBER *q1, *q2;
X COMPLEX ctmp;
X
X if ((v2->v_type != V_NUM) || (v3->v_type != V_NUM))
X math_error("Non-real arguments for root");
X q1 = v2->v_num;
X q2 = v3->v_num;
X if (qisneg(q1) || qiszero(q1) || qisfrac(q1))
X math_error("Non-positive or non-integral root");
X if (qisneg(q2) || qiszero(q2))
X math_error("Non-positive epsilon for root");
X switch (v1->v_type) {
X case V_NUM:
X if (!qisneg(v1->v_num) || zisodd(q1->num)) {
X vres->v_num = qroot(v1->v_num, q1, q2);
X vres->v_type = V_NUM;
X return;
X }
X ctmp.real = v1->v_num;
X ctmp.imag = &_qzero_;
X ctmp.links = 1;
X vres->v_com = croot(&ctmp, q1, q2);
X vres->v_type = V_COM;
X return;
X case V_COM:
X vres->v_com = croot(v1->v_com, q1, q2);
X vres->v_type = V_COM;
X return;
X case V_OBJ:
X *vres = objcall(OBJ_ROOT, v1, v2, v3);
X return;
X default:
X math_error("Taking root of bad value");
X }
X}
X
X
X/*
X * Take the absolute value of an arbitrary value within the specified error.
X * Result is placed in the indicated location.
X */
Xvoid
Xabsvalue(v1, v2, vres)
X VALUE *v1, *v2, *vres;
X{
X NUMBER *q, *epsilon;
X
X if (v2->v_type != V_NUM)
X math_error("Bad epsilon type for abs");
X epsilon = v2->v_num;
X if (qiszero(epsilon) || qisneg(epsilon))
X math_error("Non-positive epsilon for abs");
X switch (v1->v_type) {
X case V_NUM:
X if (qisneg(v1->v_num))
X q = qneg(v1->v_num);
X else
X q = qlink(v1->v_num);
X break;
X case V_COM:
X q = qhypot(v1->v_com->real, v1->v_com->imag, epsilon);
X break;
X case V_OBJ:
X *vres = objcall(OBJ_ABS, v1, v2, NULL_VALUE);
X return;
X default:
X math_error("Illegal value for absolute value");
X }
X vres->v_num = q;
X vres->v_type = V_NUM;
X}
X
X
X/*
X * Calculate the norm of an arbitrary value.
X * Result is placed in the indicated location.
X * The norm is the square of the absolute value.
X */
Xvoid
Xnormvalue(vp, vres)
X VALUE *vp, *vres;
X{
X NUMBER *q1, *q2;
X
X vres->v_type = V_NULL;
X switch (vp->v_type) {
X case V_NUM:
X vres->v_num = qsquare(vp->v_num);
X vres->v_type = V_NUM;
X return;
X case V_COM:
X q1 = qsquare(vp->v_com->real);
X q2 = qsquare(vp->v_com->imag);
X vres->v_num = qadd(q1, q2);
X vres->v_type = V_NUM;
X qfree(q1);
X qfree(q2);
X return;
X case V_OBJ:
X *vres = objcall(OBJ_NORM, vp, NULL_VALUE, NULL_VALUE);
X return;
X default:
X math_error("Illegal value for norm");
X }
X}
X
X
X/*
X * Shift a value left or right by the specified number of bits.
X * Negative shift value means shift the direction opposite the selected dir.
X * Right shifts are defined to lose bits off the low end of the number.
X * Result is placed in the indicated location.
X */
Xvoid
Xshiftvalue(v1, v2, rightshift, vres)
X VALUE *v1, *v2, *vres;
X BOOL rightshift; /* TRUE if shift right instead of left */
X{
X COMPLEX *c;
X long n;
X VALUE tmp;
X
X if (v2->v_type != V_NUM)
X math_error("Non-real shift value");
X if (qisfrac(v2->v_num))
X math_error("Non-integral shift value");
X if (v1->v_type != V_OBJ) {
X if (zisbig(v2->v_num->num))
X math_error("Very large shift value");
X n = qtoi(v2->v_num);
X }
X if (rightshift)
X n = -n;
X switch (v1->v_type) {
X case V_NUM:
X vres->v_num = qshift(v1->v_num, n);
X vres->v_type = V_NUM;
X return;
X case V_COM:
X c = cshift(v1->v_com, n);
X if (!cisreal(c)) {
X vres->v_com = c;
X vres->v_type = V_COM;
X return;
X }
X vres->v_num = qlink(c->real);
X vres->v_type = V_NUM;
X comfree(c);
X return;
X case V_MAT:
X vres->v_mat = matshift(v1->v_mat, n);
X vres->v_type = V_MAT;
X return;
X case V_OBJ:
X if (!rightshift) {
X *vres = objcall(OBJ_SHIFT, v1, v2, NULL_VALUE);
X return;
X }
X tmp.v_num = qneg(v2->v_num);
X tmp.v_type = V_NUM;
X *vres = objcall(OBJ_SHIFT, v1, &tmp, NULL_VALUE);
X qfree(tmp.v_num);
X return;
X default:
X math_error("Bad value for shifting");
X }
X}
X
X
X/*
X * Scale a value by a power of two.
X * Result is placed in the indicated location.
X */
Xvoid
Xscalevalue(v1, v2, vres)
X VALUE *v1, *v2, *vres;
X{
X long n;
X
X if (v2->v_type != V_NUM)
X math_error("Non-real scaling factor");
X if (qisfrac(v2->v_num))
X math_error("Non-integral scaling factor");
X if (v1->v_type != V_OBJ) {
X if (zisbig(v2->v_num->num))
X math_error("Very large scaling factor");
X n = qtoi(v2->v_num);
X }
X switch (v1->v_type) {
X case V_NUM:
X vres->v_num = qscale(v1->v_num, n);
X vres->v_type = V_NUM;
X return;
X case V_COM:
X vres->v_com = cscale(v1->v_com, n);
X vres->v_type = V_NUM;
X return;
X case V_MAT:
X vres->v_mat = matscale(v1->v_mat, n);
X vres->v_type = V_MAT;
X return;
X case V_OBJ:
X *vres = objcall(OBJ_SCALE, v1, v2, NULL_VALUE);
X return;
X default:
X math_error("Bad value for scaling");
X }
X}
X
X
X/*
X * Raise a value to an integral power.
X * Result is placed in the indicated location.
X */
Xvoid
Xpowivalue(v1, v2, vres)
X VALUE *v1, *v2, *vres;
X{
X NUMBER *q;
X COMPLEX *c;
X
X vres->v_type = V_NULL;
X if (v2->v_type != V_NUM)
X math_error("Raising value to non-real power");
X q = v2->v_num;
X if (qisfrac(q))
X math_error("Raising value to non-integral power");
X switch (v1->v_type) {
X case V_NUM:
X vres->v_num = qpowi(v1->v_num, q);
X vres->v_type = V_NUM;
X return;
X case V_COM:
X vres->v_com = cpowi(v1->v_com, q);
X vres->v_type = V_COM;
X c = vres->v_com;
X if (!cisreal(c))
X return;
X vres->v_num = qlink(c->real);
X vres->v_type = V_NUM;
X comfree(c);
X return;
X case V_MAT:
X vres->v_mat = matpowi(v1->v_mat, q);
X vres->v_type = V_MAT;
X return;
X case V_OBJ:
X *vres = objcall(OBJ_POW, v1, v2, NULL_VALUE);
X return;
X default:
X math_error("Illegal value for raising to integer power");
X }
X}
X
X
X/*
SHAR_EOF
echo "End of part 10"
echo "File calc2.9.0/value.c is continued in part 11"
echo "11" > s2_seq_.tmp
exit 0