|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 3744 (0xea0)
Types: TextFile
Notes: UNIX file
Names: »expr.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/nroff/expr.c«
/*
* Nroff/Troff.
* Expression reader.
*/
#include <stdio.h>
#include <ctype.h>
#include "roff.h"
#include "code.h"
#include "div.h"
#include "env.h"
/*
* Given a string containing an expression, a default unit, `mul'/`div',
* which is used as a multiplier whenever a number is found without a
* unit attached, an initial value, `num', used if the expression has a
* leading sign, a flag, `hvf', specifying whether the number is associated
* with the horizontal or the vertical which is used if the expression has
* an initial '|' and a default value `def' which is returned scaled by
* the default unit if no expression is specified. The expression is
* evaluated from left to right with no priorites excepting parentheses.
*/
number(str, mul, div, num, hvf, def)
char *str;
long mul, div;
{
register int n, c;
expp = str;
expmul = mul;
expdiv = div;
experr = 0;
while (isascii(*expp) && isspace(*expp))
expp++;
if ((c=*expp) == '\0')
return (unit(def*mul, div));
if (index("+-|", *expp))
++expp;
n = expseq();
if (*expp != '\0')
experr++;
if (experr) {
printe("Syntax error");
return (0);
}
switch (c) {
case '+':
n = num + n;
break;
case '-':
n = num - n;
break;
case '|':
n -= hvf ? cdivp->d_rpos : nlinsiz;
break;
}
return (n);
}
/*
* Compute an expression sequence.
*/
expseq()
{
register int n1, n2, c;
n1 = expval();
if (experr)
return (0);
for (;;) {
while ((c=*expp++)==' ' || c=='\t')
;
switch (c) {
case '<':
if (*expp == '=') {
expp++;
c = 'l';
}
break;
case '>':
if (*expp == '=') {
expp++;
c = 'g';
}
break;
case '=':
if (*expp == '=')
expp++;
break;
default:
if ((c != 0) && index("+-/*%&:", c))
break;
--expp;
return (n1);
}
n2 = expval();
if (experr)
return (0);
switch (c) {
case '+':
n1 += n2;
break;
case '-':
n1 -= n2;
break;
case '*':
n1 *= n2;
break;
case '/':
if (n2 == 0) {
printe("Attempted zero divide");
experr++;
return (0);
}
n1 /= n2;
break;
case '%':
if (n2 == 0) {
printe("Attempted zero modulus");
experr++;
return (0);
}
n1 %= n2;
break;
case '<':
n1 = n1 < n2;
break;
case '>':
n1 = n1 > n2;
break;
case 'l':
n1 = n1 <= n2;
break;
case 'g':
n1 = n1 >= n2;
break;
case '=':
n1 = n1 == n2;
break;
case '!':
n1 = n1 != n2;
break;
case '&':
n1 = n1 && n2;
break;
case ':':
n1 = n1 || n2;
break;
}
}
}
/*
* Get an operand.
*/
expval()
{
long mul, div, m, d;
register int n, c;
while (isascii(c=*expp++) && isspace(c))
;
if (c == '(') {
n = expseq();
if (*expp++ != ')') {
--expp;
experr++;
n = 0;
}
return (n);
}
m = 0;
d = 1;
while (isascii(c) && isdigit(c)) {
m = m*10 + c-'0';
c = *expp++;
}
if (c == '.') {
while (isascii(c=*expp++) && isdigit(c)) {
m = m*10 + c-'0';
d *= 10;
}
}
switch (c) {
case 'i':
mul = SMINCH;
div = SDINCH;
break;
case 'c':
mul = SMCENT;
div = SDCENT;
break;
case 'P':
mul = SMPICA;
div = SDPICA;
break;
case 'm':
mul = SMEMSP;
div = SDEMSP;
break;
case 'n':
mul = SMENSP;
div = SDENSP;
break;
case 'p':
mul = SMPOIN;
div = SDPOIN;
break;
case 'u':
mul = SMUNIT;
div = SDUNIT;
break;
case 'v':
mul = SMVLSP;
div = SDVLSP;
break;
default:
--expp;
mul = expmul;
div = expdiv;
}
while (isascii(c=*expp) && isalpha(c))
expp++;
n = unit(m*mul, d*div);
return (n);
}
/*
* Given a long numerator and denominator, divide the numerator by
* the denominator and return an int.
*/
unit(mul, div)
long mul, div;
{
if (div == 1)
return ((int) mul);
return ((int) (mul/div));
}