shithub: neatroff

Download patch

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);