diff options
Diffstat (limited to 'Build/source/texk/ps2pk/strexpr.c')
-rw-r--r-- | Build/source/texk/ps2pk/strexpr.c | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/Build/source/texk/ps2pk/strexpr.c b/Build/source/texk/ps2pk/strexpr.c new file mode 100644 index 00000000000..ebfcc8fcdf5 --- /dev/null +++ b/Build/source/texk/ps2pk/strexpr.c @@ -0,0 +1,292 @@ +/* + * File: strexpr.c + * Purpose: calculate value from algebraic string expression + * (Stripped down from expr.c from J.T. Conklin <jtc@netbsd.org>.) + * Version: 1.0 (Nov 1995) + * Author: Piet Tutelaers + */ + +#include <stdio.h> /* sprintf() */ +#include <stdlib.h> /* free(), malloc() */ +#include <string.h> /* strchr(), strcpy() */ +#include <ctype.h> /* isdigit(), isspace() */ +#include "basics.h" /* fatal() */ + +const char *OPERATORS = "+-*/%()"; + +enum token { + ADD, SUB, MUL, DIV, MOD, LP, RP, OPERAND, EOI +}; + +struct val { + enum { + integer, + string + } type; + + union { + char *s; + int i; + } u; +}; + +enum token token; +struct val *tokval; +char *pexpr; + +struct val * +make_int(int i) +{ + struct val *vp; + + vp = (struct val *) malloc(sizeof(*vp)); + if (vp == NULL) fatal("expression error\n"); + vp->type = integer; + vp->u.i = i; + return vp; +} + + +struct val * +make_str(char *s) +{ + char operand[32]; int i; + + struct val *vp; + + vp = (struct val *) malloc(sizeof(*vp)); + if (vp == NULL) fatal("expression error\n"); + + pexpr = s; i = 0; + while (1) { + if (isspace(*pexpr) || *pexpr == '\0') break; + if (strchr(OPERATORS, *pexpr) != NULL) break; + if (i == 30) fatal("operand too large\n"); + operand[i++] = *pexpr++; + } + if (i == 0) fatal("invalid operand\n"); + operand[i] = '\0'; + vp->u.s = malloc(i+1); + if (vp->u.s == NULL) fatal("Out of memory\n"); + strcpy(vp->u.s, operand); + vp->type = string; + return vp; +} + + +void +free_value(struct val *vp) +{ + if (vp->type == string) + free(vp->u.s); + free(vp); +} + + +/* determine if vp is an integer; if so, return it's value in *r */ +int +is_integer(struct val *vp, int *r) +{ + char *s; + int neg; + int i; + + if (vp->type == integer) { + *r = vp->u.i; + return 1; + } + + /* + * POSIX.2 defines an "integer" as an optional unary minus + * followed by digits. + */ + s = vp->u.s; + i = 0; + + neg = (*s == '-'); + if (neg) + s++; + + while (*s) { + if (!isdigit(*s)) + return 0; + + i *= 10; + i += *s - '0'; + + s++; + } + + if (neg) + i *= -1; + + *r = i; + return 1; +} + + +/* coerce to vp to an integer */ +int +to_integer(struct val *vp) +{ + int r; + + if (vp->type == integer) + return 1; + + if (is_integer(vp, &r)) { + free(vp->u.s); + vp->u.i = r; + vp->type = integer; + return 1; + } + + return 0; +} + + +/* coerce to vp to an string */ +void +to_string(struct val *vp) +{ + char *tmp; + + if (vp->type == string) + return; + + tmp = malloc(25); + if (tmp == NULL) fatal("Out of memory\n"); + sprintf(tmp, "%d", vp->u.i); + vp->type = string; + vp->u.s = tmp; +} + +void +nexttoken() +{ + char *i; /* index */ + + while (isspace(*pexpr)) pexpr++; + + if (*pexpr == '\0') { + token = EOI; + return; + } + + if ((i = strchr(OPERATORS, *pexpr)) != NULL) { + pexpr++; + token = i - OPERATORS; + return; + } + tokval = make_str(pexpr); + token = OPERAND; + return; +} + +struct val * +eval6() +{ + struct val *eval3(void); + struct val *v; + + if (token == OPERAND) { + nexttoken(); + return tokval; + + } else if (token == LP) { + nexttoken(); + v = eval3(); + + if (token != RP) + fatal("missing parenthesis in expression\n"); + nexttoken(); + return v; + } else fatal("expression error\n"); + /* NOTREACHED */ +} + +/* Parse and evaluate multiplication and division expressions */ +struct val * +eval4() +{ + struct val *l, *r; + enum token op; + + l = eval6(); + while ((op = token) == MUL || op == DIV || op == MOD) { + nexttoken(); + r = eval6(); + + if (!to_integer(l) || !to_integer(r)) { + fatal("non-numeric argument\n"); + } + + if (op == MUL) { + l->u.i *= r->u.i; + } else { + if (r->u.i == 0) { + fatal("division by zero\n"); + } + if (op == DIV) { + l->u.i /= r->u.i; + } else { + l->u.i %= r->u.i; + } + } + + free_value(r); + } + + return l; +} + +/* Parse and evaluate addition and subtraction expressions */ +struct val * +eval3() +{ + struct val *l, *r; + enum token op; + + l = eval4(); + while ((op = token) == ADD || op == SUB) { + nexttoken(); + r = eval4(); + + if (!to_integer(l) || !to_integer(r)) { + fatal("non-numeric argument\n"); + } + + if (op == ADD) { + l->u.i += r->u.i; + } else { + l->u.i -= r->u.i; + } + + free_value(r); + } + + return l; +} + +/* + * Evaluate the algebraic expression contained in <expression>. The + * value will be assigned to <result>. When errors are encountered + * non-zero is returned (if program is not aborted) otherwise zero. + */ +int strexpr(int *result, char *expression) { + struct val *vp; + + pexpr = expression; + + nexttoken(); + vp = eval3(); + + if (token != EOI) return 1; + + if (vp->type == integer || to_integer(vp)) { + *result = vp->u.i; + return 0; + } + + return 1; +} |