ref: 67c88531267834b56ab84a6d797eb55fd83228bb
parent: 3e4d65567e5b609fa8532915fcde566c6a40b120
author: Ali Gholami Rudi <ali@rudi.ir>
date: Thu Apr 11 07:46:32 EDT 2013
eval: evaluate integer expressions
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,7 @@
all: xroff
%.o: %.c xroff.h
$(CC) -c $(CFLAGS) $<
-xroff: xroff.o dev.o font.o in.o cp.o tr.o ren.o out.o reg.o sbuf.o adj.o
+xroff: xroff.o dev.o font.o in.o cp.o tr.o ren.o out.o reg.o sbuf.o adj.o eval.o
$(CC) -o $@ $^ $(LDFLAGS)
clean:
rm -f *.o xroff
--- /dev/null
+++ b/eval.c
@@ -1,0 +1,143 @@
+#include <ctype.h>
+#include <stdio.h>
+#include "xroff.h"
+
+static int defunit = 0; /* default scale indicator */
+
+static int readunit(int c, int *mul, int *div)
+{
+ *mul = 1;
+ *div = 1;
+ switch (c) {
+ case 'i':
+ *mul = SC_IN;
+ return 0;
+ case 'c':
+ *mul = SC_IN * 50;
+ *div = 127;
+ return 0;
+ case 'p':
+ *mul = SC_IN;
+ *div = 72;
+ return 0;
+ case 'P':
+ *mul = SC_IN;
+ *div = 6;
+ return 0;
+ case 'v':
+ *mul = n_v;
+ return 0;
+ case 'm':
+ *mul = n_s * SC_IN;
+ *div = 72;
+ return 0;
+ case 'n':
+ *mul = n_s * SC_IN;
+ *div = 144;
+ return 0;
+ case 'u':
+ return 0;
+ }
+ return 1;
+}
+
+static int evalexpr(char **s);
+
+static int evalnum(char **_s)
+{
+ char *s = *_s;
+ int n = 0; /* the result */
+ int mag = 0; /* n should be divided by mag */
+ int mul, div;
+ while (isdigit(*s) || *s == '.') {
+ if (*s == '.') {
+ mag = 1;
+ s++;
+ continue;
+ }
+ mag *= 10;
+ n = n * 10 + *s++ - '0';
+ }
+ if (!readunit(*s, &mul, &div))
+ s++;
+ else
+ readunit(defunit, &mul, &div);
+ *_s = s;
+ /* this may overflow */
+ return n * mul / div / (mag > 0 ? mag : 1);
+}
+
+static int evaljmp(char **s, int c)
+{
+ if (**s == c) {
+ (*s)++;
+ return 0;
+ }
+ return 1;
+}
+
+static int evalisnum(char **s)
+{
+ return **s == '.' || isdigit(**s);
+}
+
+static int evalatom(char **s)
+{
+ if (!evaljmp(s, '-'))
+ return -evalatom(s);
+ if (!evaljmp(s, '+'))
+ return evalatom(s);
+ if (evalisnum(s))
+ return evalnum(s);
+ if (!evaljmp(s, '(')) {
+ int ret = evalexpr(s);
+ evaljmp(s, ')');
+ return ret;
+ }
+ return 0;
+}
+
+static int evalexpr(char **s)
+{
+ int ret = evalatom(s);
+ while (**s) {
+ if (!evaljmp(s, '+'))
+ ret += evalatom(s);
+ else if (!evaljmp(s, '-'))
+ ret -= evalatom(s);
+ else if (!evaljmp(s, '/'))
+ ret /= evalatom(s);
+ else if (!evaljmp(s, '*'))
+ ret *= evalatom(s);
+ else if (!evaljmp(s, '%'))
+ ret %= evalatom(s);
+ else if (!evaljmp(s, '<'))
+ ret = !evaljmp(s, '=') ? ret <= evalatom(s) : ret < evalatom(s);
+ else if (!evaljmp(s, '>'))
+ ret = !evaljmp(s, '=') ? ret >= evalatom(s) : ret > evalatom(s);
+ else if (!evaljmp(s, '=') + !evaljmp(s, '='))
+ ret = ret == evalatom(s);
+ else if (!evaljmp(s, '&'))
+ ret = ret && evalatom(s);
+ else if (!evaljmp(s, ':'))
+ ret = ret || evalatom(s);
+ else
+ break;
+ }
+ return ret;
+}
+
+int eval(char *s, int orig, int unit)
+{
+ int n;
+ int rel = 0; /* n should be added to orig */
+ if (*s == '+' || *s == '-') {
+ rel = *s == '+' ? 1 : -1;
+ s++;
+ }
+ defunit = unit;
+ n = evalexpr(&s);
+ if (rel)
+ return rel > 0 ? orig + n : orig - n;
+ return n;
+}
--- a/out.c
+++ b/out.c
@@ -95,7 +95,7 @@
} else if (strchr("sfhv", c[0])) {
s = escarg(s, arg, c[0]);
if (c[0] == 's') {
- out_ps(tr_int(arg, o_s, '\0'));
+ out_ps(eval(arg, o_s, '\0'));
continue;
}
if (c[0] == 'f') {
@@ -103,11 +103,11 @@
continue;
}
if (c[0] == 'h') {
- OUT("h%d", tr_int(arg, 0, 'm'));
+ OUT("h%d", eval(arg, 0, 'm'));
continue;
}
if (c[0] == 'v') {
- OUT("v%d", tr_int(arg, 0, 'm'));
+ OUT("v%d", eval(arg, 0, 'm'));
continue;
}
}
--- a/ren.c
+++ b/ren.c
@@ -201,7 +201,7 @@
{
if (args[0][0] == '.')
ren_br(1);
- down(args[1] ? tr_int(args[1], 0, 'v') : n_v);
+ down(args[1] ? eval(args[1], 0, 'v') : n_v);
}
void ren_page(int pg)
@@ -216,7 +216,7 @@
void tr_ne(char **args)
{
- int n = args[1] ? tr_int(args[1], 0, 'v') : n_v;
+ int n = args[1] ? eval(args[1], 0, 'v') : n_v;
ren_br(1);
if (!ren_traps(n_d, n_d + n, 1))
ren_pagelimit(n);
@@ -227,7 +227,7 @@
if (!cdiv) {
bp_force = 1;
if (args[1])
- bp_next = tr_int(args[1], n_pg, '\0');
+ bp_next = eval(args[1], n_pg, '\0');
push_ne(args[0][0] == '.');
}
}
@@ -234,7 +234,7 @@
static void ren_ps(char *s)
{
- int ps = !s || !*s || !strcmp("0", s) ? n_s0 : tr_int(s, n_s, '\0');
+ int ps = !s || !*s || !strcmp("0", s) ? n_s0 : eval(s, n_s, '\0');
n_s0 = n_s;
n_s = ps;
}
@@ -249,7 +249,7 @@
if (args[0][0] == '.')
ren_br(1);
if (args[1])
- n_i = tr_int(args[1], n_i, 'm');
+ n_i = eval(args[1], n_i, 'm');
}
static void ren_ft(char *s)
@@ -412,7 +412,7 @@
static int tpos_parse(char *s)
{
- int pos = tr_int(s, 0, 'v');
+ int pos = eval(s, 0, 'v');
return pos >= 0 ? pos : n_p + pos;
}
@@ -454,7 +454,7 @@
if (!cdiv)
return;
if (args[2]) {
- cdiv->tpos = tr_int(args[1], 0, 'v');
+ cdiv->tpos = eval(args[1], 0, 'v');
cdiv->treg = REG(args[2][0], args[2][1]);
} else {
cdiv->treg = -1;
--- a/tr.c
+++ b/tr.c
@@ -1,4 +1,3 @@
-#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -6,72 +5,6 @@
static int tr_nl = 1;
-static int unit_scale(int c, int n, int mag)
-{
- int mul = 1;
- int div = 1;
- switch (c) {
- case 'i':
- mul = SC_IN;
- break;
- case 'c':
- mul = SC_IN * 50;
- div = 127;
- break;
- case 'p':
- mul = SC_IN;
- div = 72;
- break;
- case 'P':
- mul = SC_IN;
- div = 6;
- break;
- case 'v':
- mul = n_v;
- break;
- case 'm':
- mul = n_s * SC_IN;
- div = 72;
- break;
- case 'n':
- mul = n_s * SC_IN;
- div = 144;
- break;
- }
- /* it may overflow */
- return n * mul / div / mag;
-}
-
-int tr_int(char *s, int orig, int unit)
-{
- int n = 0; /* the result */
- int mag = 0; /* n should be divided by mag */
- int rel = 0; /* n should be added to orig */
- int neg = *s == '-'; /* n should be negated */
- if (*s == '+' || *s == '-') {
- rel = 1;
- s++;
- }
- while (isdigit(*s) || *s == '.') {
- if (*s == '.') {
- mag = 1;
- s++;
- continue;
- }
- mag *= 10;
- n = n * 10 + *s++ - '0';
- }
- if (!mag)
- mag = 1;
- if (unit)
- n = unit_scale(*s ? *s : unit, n, mag);
- else
- n /= mag;
- if (neg)
- n = -n;
- return rel ? orig + n : n;
-}
-
/* skip everything until the end of line */
static void jmp_eol(void)
{
@@ -84,19 +17,19 @@
static void tr_ll(char **args)
{
if (args[1])
- n_l = tr_int(args[1], n_l, 'm');
+ n_l = eval(args[1], n_l, 'm');
}
static void tr_vs(char **args)
{
if (args[1])
- n_v = tr_int(args[1], n_v, 'p');
+ n_v = eval(args[1], n_v, 'p');
}
static void tr_pl(char **args)
{
if (args[1])
- n_p = tr_int(args[1], n_p, 'v');
+ n_p = eval(args[1], n_p, 'v');
}
static void tr_nr(char **args)
@@ -105,7 +38,7 @@
if (!args[2])
return;
id = REG(args[1][0], args[1][1]);
- *nreg(id) = tr_int(args[2], *nreg(id), 'u');
+ *nreg(id) = eval(args[2], *nreg(id), 'u');
}
static void tr_ds(char **args)
--- a/xroff.h
+++ b/xroff.h
@@ -25,7 +25,7 @@
/* number registers */
char *num_get(int id);
int *nreg(int id);
-int tr_int(char *s, int orig, int unit);
+int eval(char *s, int orig, int unit);
/* string registers */
void str_set(int id, char *s);