Category : C Source Code
Archive   : CSRC2.ZIP
Filename : EVAL.C

 
Output of file : EVAL.C contained in archive : CSRC2.ZIP
/*
* e v a l
*
* Read an expression and evaluate it. Prints the value in decimal,
* octal, and hex. Any C expression (with parentheses) may be
* evaluated. Uses code developed for the C preprocessor.
*
* Define "MAIN" to include the driver program.
*/

#define MAIN


/*)LIBRARY
*/

/*)BUILD $(TKBOPTIONS) = {
TASK = ...EVL
}
*/

#ifdef DOCUMENTATION

title eval Expression Evaluation
index Evaluate a C expression

synopsis

eval expression (as a main program)

int
eval(string, result)
char *string; /* String to evaluate */
union { /* Pointer to result */
long value; /* Result if no error */
char *error; /* Message if error */
} *result;

description

By setting a compile-time parameter, eval may be configured
as a main program that reads an expression, printing the
result in decimal, octal, and hexadecimal.

When compiled as a subroutine, eval() accepts a character
string argument, returning a long result (and an error indicator):

If eval() returns zero, the evaluation is stored
in result.value. Else, there is an error and and the value returned
is the index in string of the first byte not parsed, while
result.error is a pointer to an error message. (Note that,
if the error was discovered after the entire string was parsed,
the index may be greater than the length of the string.)

author

Martin Minow, using an algorithm developed by
Mike Lutz and Bob Harper of RPI.

#endif

#define EOS 0
#define TRUE 1
#define FALSE 0
/*
* If the main program source is removed, check that the #include
* at the start of eval() is reenabled as needed.
*/
#include

#ifdef MAIN

/*
* This is compiled to create the eval main program.
*/

#include
#ifdef vms
#include
static int ctrlc_typed = FALSE;
static jmp_buf environment;
#endif

static char line[513];
static int prompting;

main(argc, argv)
int argc;
char *argv[];
{
register char *linep;
register char *argp;

#ifdef vms
extern int ctrlc_trap();

signal(SIGINT, ctrlc_trap);
#endif
if (argc <= 1) {
#ifdef vms
if (setjmp(environment) == 0)
while (!ctrlc_typed) {
#else
for (;;) {
#endif
if (isatty(fileno(stdin))) {
printf("* ");
fflush(stdout);
}
#ifdef vms
if (gets(line) == NULL || ctrlc_typed)
break;
#else
if (gets(line) == NULL)
break;
#endif
else if (line[0] == '?') {
help();
}
else {
process();
}
}
}
else {
if (argv[1][0] == '?' || streq(argv[1], "-?") != FALSE) {
help();
}
else {
linep = line;
while (argc > 1) {
argp = *++argv;
while (*argp != EOS)
*linep++ = *argp++;
*linep++ = ' ';
argc--;
}
*linep = EOS;
process();
}
}
}

static
process()
/*
* Do the work -- argument is in line.
*/
{
int code;
union {
long value;
char *message;
} result;

if ((code = eval(line, &result)) != 0) {
printf("?%s in \"%s\"\n", result.message, line);
if (code >= strlen(line)) {
printf("Stopped after reading entire line\n");
}
else {
printf("Stopped at byte %d, \"%s\" not evaluated\n",
code, &line[code]);
}
printf("\"%s?\" for help\n", (prompting) ? "" : "eval ");
}
else if (result.value == 0)
printf("0\t0\t0\n");
else {
printf("%ld\t0%lo\t0x%lx\n",
result.value, result.value, result.value);
if (result.value < 0) {
printf("\tunsigned: %lu long", result.value);
if ((result.value & ~65535L) == ~65535L)
printf(", %lu short", result.value & 65535L);
if ((result.value & ~255L) == ~255L)
printf(", %lu char", result.value & 255L);
printf("\n");
}
}
}

static
help()
/*
* Give help
*/
{
printf("Evaluate an integer expression. Standard C syntax\n");
printf("is accepted, including parentheses. The result is\n");
printf("output in decimal, octal, and hexadecimal. When a\n");
printf("number is entered, a leading '0' means octal while\n");
printf("a leading '0x' or '0X' means hexadecimal.\n");
}

#ifdef vms
static
ctrlc_trap()
{
ctrlc_typed = TRUE;
longjmp(environment, TRUE);
}
#endif
#endif

/*
* Constant expression evaluator -- performs a standard recursive
* descent parse to evaluate any legal C constant expression. All
* operators without side-effects are implemented (thus ++, --, and all
* assignment operators are omitted).
*
* This code was originally written by Mike Lutz and was modified by
* Bob Harper to fit into this program and to conform to C language
* standards.
*/

/*
* This is defined at the start of the file so setjmp can be used in
* the main program.
* #include
*/

#define EOS 0
#define TRUE 1
#define FALSE 0
#define EQL 0
#define NEQ 1
#define LSS 2
#define LEQ 3
#define GTR 4
#define GEQ 5

static char *nxtch = EOS; /* Parser scan pointer */
static char *errmsg; /* Gets error message */
static jmp_buf env; /* Setjmp/longjmp save area */

extern long query(), lor(), land(), bor(), band(), bxor();
extern long eql(), relat(), shift(), primary(), term(), unary();
extern long factor(), const(), number(), experr();

/* ::= */


int
eval(string, result)
char *string; /* Argument */
union {
long value;
char *message;
} *result;
/*
* Evaluate driver
*/
{
int i;
long evaluate();

nxtch = string;
if (setjmp(env) == 0) {
result->value = evaluate();
return(0);
}
else {
result->message = errmsg;
i = nxtch - string;
return ((i <= 0) ? 1 : i);
}
}

static long
evaluate()
{
long rval;

rval = query();
if (skipws() == EOS)
return(rval);
experr("Ill-formed expression");
}

/* ::= | '?' ':' */

static long
query()
{
long bool, true_val, false_val;

bool = lor();
if (skipws() != '?') {
ungetch();
return(bool);
}

true_val = query();
if (skipws() != ':')
experr("Bad query syntax (':' not found)");

false_val = query();
return((bool != 0) ? true_val : false_val);
}

/* ::= { '||' } */

static long
lor()
{
register int c;
long vl, vr;

vl = land();
while ((c = skipws()) == '|' && getch() == '|') {
vr = land();
#ifdef decus
vl = (vl != 0 || vr != 0) ? 1 : 0;
#else
vl = vl || vr;
#endif
}
if (c == '|')
ungetch();
ungetch();
return(vl);
}

/* ::= { '&&' } */

static long
land()
{
register int c;
long vl, vr;

vl = bor();
while ((c = skipws()) == '&' && getch() == '&') {
vr = bor();
#ifdef decus
vl = (vl != 0 && vr != 0) ? 1 : 0;
#else
vl = vl && vr;
#endif
}
if (c == '&')
ungetch();
ungetch();
return(vl);
}

/* ::= { '|' } */

static long
bor()
{
register int c;
long vl, vr;

vl = bxor();
while ((c = skipws()) == '|' && getch() != '|') {
ungetch();
vr = bxor();
vl |= vr;
}

if (c == '|')
ungetch();
ungetch();
return(vl);
}

/* ::= { '^' } */

static long
bxor()
{
long vl, vr;

vl = band();
while (skipws() == '^') {
vr = band();
vl = vl ^ vr;
}

ungetch();
return(vl);
}

/* ::= { '&' } */

static long
band()
{
register int c;
long vl, vr;

vl = eql();
while ((c = skipws()) == '&' && getch() != '&') {
ungetch();
vr = eql();
vl &= vr;
}

if (c == '&')
ungetch();
ungetch();
return(vl);
}

/* ::= { } */

static long
eql()
{
register int rel;
long vl, vr;

vl = relat();
while ((rel = geteql()) != -1) {
vr = relat();

switch (rel) {

case EQL:
vl = (vl == vr);
break;
case NEQ:
vl = (vl != vr);
break;
}
}
return(vl);
}

/* ::= { } */

static long
relat()
{
register int rel;
long vl, vr;

vl = shift();
while ((rel = getrel()) != -1) {

vr = shift();
switch (rel) {

case LEQ:
vl = (vl <= vr);
break;
case LSS:
vl = (vl < vr);
break;
case GTR:
vl = (vl > vr);
break;
case GEQ:
vl = (vl >= vr);
break;
}
}
return(vl);
}

/* ::= { } */

static long
shift()
{
register int c;
long vl, vr;

vl = primary();
while (((c = skipws()) == '<' || c == '>') && c == getch()) {
vr = primary();

if (c == '<')
vl <<= vr;
else
vl >>= vr;
}

if (c == '<' || c == '>')
ungetch();
ungetch();
return(vl);
}

/* ::= { } */

static long
primary()
{
register int c;
long vl, vr;

vl = term();
while ((c = skipws()) == '+' || c == '-') {
vr = term();
if (c == '+')
vl += vr;
else
vl -= vr;
}

ungetch();
return(vl);
}

/* := { } */

static long
term()
{
register int c;
long vl, vr;

vl = unary();
while ((c = skipws()) == '*' || c == '/' || c == '%') {
vr = unary();

switch (c) {
case '*':
vl *= vr;
break;
case '/':
if (vr == 0)
experr("Division by zero");
else vl /= vr;
break;
case '%':
if (vr == 0)
experr("Modulus by zero");
else vl %= vr;
break;
}
}
ungetch();
return(vl);
}

/* ::= | */

static long
unary()
{
register int c;
long val;

if ((c = skipws()) == '!' || c == '~' || c == '-') {
val = unary();

switch (c) {
case '!': return((val == 0) ? 1 : 0);
case '~': return(~ val);
case '-': return(- val);
}
}

ungetch();
return(factor());
}

/* ::= | '(' ')' */

static long
factor()
{
long val;

if (skipws() == '(') {
val = query();
if (skipws() != ')')
experr("Missing right parenthesis");
return(val);
}

ungetch();
return(const());
}

/* ::= | '' */

static long
const()
{
/*
* Note: const() handles multi-byte constants
*/

register int i;
register int val;
register char c;
int v[sizeof (int)];


if (skipws() != '\'') {
ungetch();
return(number());
}
/*
* Multi-byte character constant
*/
for (i = 0; i < sizeof(int); i++) {
if ((c = getch()) == '\'') {
ungetch();
break;
}
if (c == '\\') {
switch (c = getch()) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
ungetch();
c = octal_number();
break;
case 'n':
c = 012;
break;
case 'r':
c = 015;
break;
case 't':
c = 011;
break;
case 'b':
c = 010;
break;
case 'f':
c = 014;
break;
}
}
v[i] = c;
}
if (i == 0 || getch() != '\'')
experr("Illegal character constant (missing \"'\")");
for (val = 0; --i >= 0;) {
val <<= 8;
val += v[i];
}
return(val);
}

/* ::= | */

static int
octal_number()
/*
* Note: returns an integer -- called only for '\xxx' constants.
*/
{
register int c;
register int val;
register int ndigits;

c = skipws();
val = 0;
ndigits = 0;
while (c >= '0' && c <= '7') {
val *= 8;
val += (c - '0');
c = getch();
ndigits++;
}
ungetch();
if (ndigits <= 0)
experr("Bad '\\xxx' constant");
else
return (val);
}

/* ::= | */

static long
number()
{
register int c;
long val;
register int ndigits;

c = skipws();
val = 0;
ndigits = 0;
if (c != '0') {
while (c >= '0' && c <= '9') {
val *= 10;
val += (c - '0');
c = getch();
ndigits++;
}
}
else {
ndigits++;
if ((c = tolower(getch())) == 'x') {
for (;(c = tolower(getch())) >= '0' &&
(c <= '9' || (c >= 'a' && c <= 'z'));
ndigits++) {
val *= 16;
val += ((c >= 'a') ? c - 'a' + 10 : c - '0');
}
}
else {
while (c >= '0' && c <= '7') {
val *= 8;
val += (c - '0');
ndigits++;
c = getch();
}
}
}
ungetch();
if (ndigits <= 0)
experr("Numeric constant expected");
else
return(val);
}

/* ::= '=' | '==' | '!=' */

static int
geteql()
{
register int c1, c2;

c1 = skipws(); c2 = getch();

switch (c1) {

case '=':
if (c2 != '=')
ungetch();
return(EQL);

case '!':
if (c2 == '=')
return(NEQ);
ungetch(); ungetch();
return(-1);

default:
ungetch(); ungetch();
return(-1);
}
}


/* ::= '<' | '>' | '<=' | '>=' */

static int
getrel()
{
register int c1, c2;

c1 = skipws();
c2 = getch();

switch (c1) {

case '<':
if (c2 == '=')
return(LEQ);
ungetch();
return(LSS);

case '>':
if (c2 == '=')
return(GEQ);
ungetch();
return(GTR);

default:
ungetch(); ungetch();
return(-1);
}
}

/* return next character from the expression string. */

static int
getch()
{
return(*nxtch++);
}

/* Put back the last character examined. */

static int
ungetch()
{
return(*--nxtch);
}

/* Skip over any white space and return terminating char. */

static int
skipws()
{
register char c;

while ((c = getch()) <= ' ' && c != EOS)
;
return(c);
}

/*
* Error handler - sets error flag and exits evaluation
*/

static long
experr(msg)
char *msg;
{
errmsg = msg;
longjmp(env, 1);
}


  3 Responses to “Category : C Source Code
Archive   : CSRC2.ZIP
Filename : EVAL.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/