Category : OS/2 Files
Archive   : EMXTST8F.ZIP
Filename : CALC.C

 
Output of file : CALC.C contained in archive : EMXTST8F.ZIP
/* calc.c (emx+gcc) -- Copyright (c) 1992-1993 by Eberhard Mattes */

#include
#include
#include
#include
#include
#include

#define FALSE 0
#define TRUE 1

#define T_EOF 0
#define T_NAME 1
#define T_NUMBER 2
#define T_LPAR 3
#define T_RPAR 4
#define T_ASSIGN 5
#define T_OPERATOR 6
#define T_EOL 7
#define T_HELP 8
#define T_QUIT 9

struct keyword
{
char *name;
int token;
double (*unary)(double x);
double (*binary)(double x, double y);
int u_bp, b_bp;
};

static FILE *parse_f;
static char parse_buffer[512];
static char tokstr[512];
static const unsigned char *parse_ptr;
static int parse_line;
static int parse_cont;
static int interactive;
static int token;
static int calc_errno;
static const struct keyword *tokptr;
static double toknum;
static jmp_buf main_loop;

static double f_add (double x, double y);
static double f_sub (double x, double y);
static double f_mul (double x, double y);
static double f_div (double x, double y);
static double f_shl (double x, double y);
static double f_shr (double x, double y);
static double f_and (double x, double y);
static double f_or (double x, double y);
static double f_eq (double x, double y);
static double f_ne (double x, double y);
static double f_lt (double x, double y);
static double f_le (double x, double y);
static double f_gt (double x, double y);
static double f_ge (double x, double y);
static double f_neg (double x);
static double f_not (double x);
static void volatile syntax (const char *msg);
static int get_line (void);
static void get_token (int more);
static void check (int t, const char *msg);
static double factor (void);
static double expr (void);
static double expr1 (int min_bp);
static void help (void);


static struct keyword keywords[] =
{
{"+", T_OPERATOR, NULL, f_add, 0, 10},
{"++", T_OPERATOR, NULL, hypot, 0, 10},
{"-", T_OPERATOR, f_neg, f_sub, 12, 10},
{"*", T_OPERATOR, NULL, f_mul, 0, 14},
{"/", T_OPERATOR, NULL, f_div, 0, 14},
{"%", T_OPERATOR, NULL, fmod, 0, 14},
{"=", T_OPERATOR, NULL, f_eq, 0, 8},
{"<>", T_OPERATOR, NULL, f_ne, 0, 8},
{"!=", T_OPERATOR, NULL, f_ne, 0, 8},
{"<", T_OPERATOR, NULL, f_lt, 0, 8},
{"<=", T_OPERATOR, NULL, f_le, 0, 8},
{">", T_OPERATOR, NULL, f_gt, 0, 8},
{">=", T_OPERATOR, NULL, f_ge, 0, 8},
{"^", T_OPERATOR, NULL, pow, 0, 21},
{"**", T_OPERATOR, NULL, pow, 0, 21},
{"<<", T_OPERATOR, NULL, f_shl, 0, 16},
{">>", T_OPERATOR, NULL, f_shr, 0, 16},
{"&", T_OPERATOR, NULL, f_and, 0, 4},
{"|", T_OPERATOR, NULL, f_or, 0, 2},
{"!", T_OPERATOR, f_not, NULL, 6, 0},
{"(", T_LPAR, NULL, NULL, 0, 0},
{")", T_RPAR, NULL, NULL, 0, 0},
{"or", T_OPERATOR, NULL, f_or, 0, 2},
{"and", T_OPERATOR, NULL, f_and, 0, 4},
{"not", T_OPERATOR, f_not, NULL, 6, 0},
{"exp", T_OPERATOR, exp, NULL, 18, 0},
{"log", T_OPERATOR, log10, NULL, 18, 0},
{"ln", T_OPERATOR, log, NULL, 18, 0},
{"cos", T_OPERATOR, cos, NULL, 18, 0},
{"sin", T_OPERATOR, sin, NULL, 18, 0},
{"tan", T_OPERATOR, tan, NULL, 18, 0},
{"cosh", T_OPERATOR, cosh, NULL, 18, 0},
{"sinh", T_OPERATOR, sinh, NULL, 18, 0},
{"tanh", T_OPERATOR, tanh, NULL, 18, 0},
{"acos", T_OPERATOR, acos, NULL, 18, 0},
{"asin", T_OPERATOR, asin, NULL, 18, 0},
{"atan", T_OPERATOR, atan, NULL, 18, 0},
{"cbrt", T_OPERATOR, cbrt, NULL, 18, 0},
{"sqrt", T_OPERATOR, sqrt, NULL, 18, 0},
{"ceil", T_OPERATOR, ceil, NULL, 18, 0},
{"floor", T_OPERATOR, floor, NULL, 18, 0},
{"round", T_OPERATOR, rint, NULL, 18, 0},
{"trunc", T_OPERATOR, trunc, NULL, 18, 0},
{"abs", T_OPERATOR, fabs, NULL, 18, 0},
{"help", T_HELP, NULL, NULL, 0, 0},
{"quit", T_QUIT, NULL, NULL, 0, 0},
{NULL, 0, NULL, NULL, 0, 0}
};


static void volatile syntax (const char *msg)
{
fprintf (stderr, "%s (Token %s, line %d)\n", msg, tokstr, parse_line);
if (interactive)
longjmp (main_loop, 1);
else
exit (2);
}


static int get_line (void)
{
char *p;

if (interactive != 0)
{
if (parse_cont)
printf (">> ");
else
printf ("%d> ", interactive++);
fflush (stdout);
}
if (fgets (parse_buffer, sizeof (parse_buffer), parse_f) == NULL)
{
if (!ferror (parse_f))
return (FALSE);
perror ("fgets");
exit (2);
}
p = strchr (parse_buffer, '\n');
if (p != NULL) *p = 0;
parse_ptr = parse_buffer;
++parse_line; parse_cont = TRUE;
return (TRUE);
}


static int find_token (const struct keyword *table)
{
while (table->name != NULL)
if (strcmp (tokstr, table->name) == 0)
{
token = table->token;
tokptr = table;
return (TRUE);
}
else
++table;
return (FALSE);
}


static int find_prefix (void)
{
size_t len;
int j;
const struct keyword *table;

len = strlen (tokstr); j = 0;
for (table = keywords; table->name != NULL; ++table)
if (strlen (table->name) >= len &&
memcmp (table->name, tokstr, len) == 0)
++j;
return (j);
}


static int find_exact (void)
{
size_t len;
int j;
const struct keyword *table;

len = strlen (tokstr); j = 0;
for (table = keywords; table->name != NULL; ++table)
if (strlen (table->name) == len && strcmp (table->name, tokstr) == 0)
{
token = table->token;
tokptr = table;
++j;
}
return (j);
}

static void get_token (int more)
{
const unsigned char *start;
char *p;
int i, j;

for (;;)
{
if (*parse_ptr == ' ' || *parse_ptr == '\t')
++parse_ptr;
else if (*parse_ptr == 0 || *parse_ptr == '#')
{
if (!more)
{
strcpy (tokstr, "<>");
token = T_EOL;
return;
}
if (!get_line ())
{
strcpy (tokstr, "<>");
token = T_EOF;
return;
}
}
else
break;
}
if (*parse_ptr >= 0x80 || isalpha (*parse_ptr))
{
start = parse_ptr++;
while (*parse_ptr >= 0x80 || isalnum (*parse_ptr) || *parse_ptr == '_')
++parse_ptr;
i = parse_ptr - start;
if (i+1 > sizeof (tokstr))
syntax ("Name too long");
memcpy (tokstr, start, i);
tokstr[i] = 0;
if (!find_token (keywords))
token = T_NAME;
}
else if (isdigit (*parse_ptr))
{
errno = 0;
toknum = strtod (parse_ptr, &p);
if (errno != 0)
syntax ("Invalid number");
token = T_NUMBER;
i = p - (char *)parse_ptr + 1;
if (i > sizeof (tokstr))
i = sizeof (tokstr);
_strncpy (tokstr, parse_ptr, i);
parse_ptr = p;
}
else
{
tokstr[0] = *parse_ptr++;
i = 1;
for (;;)
{
tokstr[i] = 0;
j = find_prefix ();
if (j == 0 || *parse_ptr == 0)
break;
tokstr[i++] = *parse_ptr++;
}
while (find_exact () != 1)
{
if (i == 1)
syntax ("Invalid character");
--i; --parse_ptr;
tokstr[i] = 0;
}
}
}


static void check (int t, const char *msg)
{
while (token == T_EOL)
get_token (TRUE);
if (token != t)
{
char buf[100];

sprintf (buf, "`%s' expected", msg);
syntax (buf);
}
}


static double factor (void)
{
double x;
const struct keyword *ptr;

switch (token)
{
case T_NUMBER:
x = toknum;
get_token (FALSE);
return (x);
case T_NAME:
syntax ("Variables not yet implemented");
case T_LPAR:
get_token (TRUE);
x = expr ();
check (T_RPAR, ")");
get_token (FALSE);
return (x);
case T_OPERATOR:
if (tokptr->unary == NULL)
syntax ("Unary operator expected");
ptr = tokptr;
get_token (TRUE);
x = expr1 (ptr->u_bp);
errno = 0;
x = ptr->unary (x);
if (errno != 0)
calc_errno = errno;
return (x);
default:
syntax ("Operand expected");
}
}


static double expr1 (int min_bp)
{
double x, y;
const struct keyword *ptr;

min_bp &= ~1;
x = factor ();
while (token == T_OPERATOR && tokptr->binary != NULL &&
tokptr->b_bp > min_bp)
{
ptr = tokptr;
get_token (TRUE);
y = expr1 (ptr->b_bp);
errno = 0;
x = ptr->binary (x, y);
if (errno != 0)
calc_errno = errno;
}
return (x);
}


static double expr (void)
{
return (expr1 (0));
}


static double f_add (double x, double y)
{
return (x + y);
}


static double f_sub (double x, double y)
{
return (x - y);
}


static double f_mul (double x, double y)
{
return (x * y);
}


static double f_div (double x, double y)
{
return (x / y);
}


static double f_shl (double x, double y)
{
return (ldexp (x, (int)y));
}


static double f_shr (double x, double y)
{
return (ldexp (x, (int)(-y)));
}


static double f_eq (double x, double y)
{
return (x == y ? 1.0 : 0.0);
}


static double f_ne (double x, double y)
{
return (x != y ? 1.0 : 0.0);
}


static double f_lt (double x, double y)
{
return (x < y ? 1.0 : 0.0);
}


static double f_le (double x, double y)
{
return (x <= y ? 1.0 : 0.0);
}


static double f_gt (double x, double y)
{
return (x > y ? 1.0 : 0.0);
}


static double f_ge (double x, double y)
{
return (x >= y ? 1.0 : 0.0);
}


static double f_neg (double x)
{
return (-x);
}


static double f_and (double x, double y)
{
return (x != 0.0 && y != 0.0 ? 1.0 : 0.0);
}


static double f_or (double x, double y)
{

return (x != 0.0 || y != 0.0 ? 1.0 : 0.0);
}


static double f_not (double x)
{
return (x == 0.0 ? 1.0 : 0.0);
}


static void help (void)
{
puts ("This is the emx calculator. "
"Copyright (c) 1992-1993 by Eberhard Mattes.\n");
puts ("Commands:");
puts (" help display help");
puts (" quit exit the emx calculator");
puts (" evaluate the expression and print it\n");
puts ("Operators: (ordered by precedence):");
puts (" ( ) change order of evaluation");
puts (" ^ ** compute power");
puts (" sin cos tan sinh cosh tanh asin acos atan exp log ln");
puts (" cbrt sqrt abs ceil floor round trunc");
puts (" << >> shift left, shift right");
puts (" * / % multiplication, division, modulus");
puts (" - change sign");
puts (" + - ++ addition, subtraction, hypot");
puts (" = != < <= > >= compare numbers");
puts (" ! not logical not");
puts (" & and logical and");
puts (" | or logical or");
puts ("All operators but ^ and ** are left-associative");
}


int main (int argc, char *argv[])
{
double x;

if (argc == 1)
{
parse_f = stdin;
interactive = 1;
}
else if (argc == 2)
{
interactive = 0;
parse_f = fopen (argv[1], "rt");
if (parse_f == NULL)
{
fprintf (stderr, "Cannot open input file %s\n", argv[1]);
return (2);
}
}
else
{
fprintf (stderr, "Usage: calc [filename]\n");
return (1);
}
parse_line = 0;
if (interactive)
printf ("Type `help' for help.\n");
for (;;)
{
setjmp (main_loop);
if (interactive)
printf ("\n");
parse_cont = FALSE;
parse_buffer[0] = 0; parse_ptr = parse_buffer;
calc_errno = 0;
get_token (TRUE);
if (token == T_EOF || token == T_QUIT)
break;
else if (token == T_HELP)
help ();
else
{
x = expr ();
if (token != T_EOL)
syntax ("extra characters at end of line");
if (interactive)
printf ("==> ");
printf ("%g", x);
if (calc_errno != 0)
printf (" (%s)", strerror (calc_errno));
printf ("\n");
}
}
return (0);
}


  3 Responses to “Category : OS/2 Files
Archive   : EMXTST8F.ZIP
Filename : CALC.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/