From bd14770b0c8594ce5b0ab9b0b1249b72fc781dd3 Mon Sep 17 00:00:00 2001
From: Denys Vlasenko <dvlasenk@redhat.com>
Date: Mon, 13 Sep 2010 11:11:40 +0200
Subject: shell/math.c: small code shrink; fixed incomprehensible comments

function                                             old     new   delta
arith_apply                                         1334    1304     -30

Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
---
 shell/math.c | 225 ++++++++++++++++++++++++++++++-----------------------------
 1 file changed, 113 insertions(+), 112 deletions(-)

diff --git a/shell/math.c b/shell/math.c
index c698a442b..a9fbc8910 100644
--- a/shell/math.c
+++ b/shell/math.c
@@ -52,17 +52,18 @@
  * than a comparable parser written in yacc. The supported operators are
  * listed in #defines below. Parens, order of operations, and error handling
  * are supported. This code is thread safe. The exact expression format should
- * be that which POSIX specifies for shells. */
-
-/* The code uses a simple two-stack algorithm. See
+ * be that which POSIX specifies for shells.
+ *
+ * The code uses a simple two-stack algorithm. See
  * http://www.onthenet.com.au/~grahamis/int2008/week02/lect02.html
  * for a detailed explanation of the infix-to-postfix algorithm on which
  * this is based (this code differs in that it applies operators immediately
  * to the stack instead of adding them to a queue to end up with an
- * expression). */
-
-/* To use the routine, call it with an expression string and error return
- * pointer */
+ * expression).
+ *
+ * To use the routine, call it with an expression string and error return
+ * pointer
+ */
 
 /*
  * Aug 24, 2001              Manuel Novoa III
@@ -104,22 +105,21 @@
  *  (C) 2003 Vladimir Oleynik <dzo@simtreas.ru>
  *
  * - allow access to variable,
- *   used recursive find value indirection (c=2*2; a="c"; $((a+=2)) produce 6)
- * - realize assign syntax (VAR=expr, +=, *= etc)
- * - realize exponentiation (** operator)
- * - realize comma separated - expr, expr
- * - realise ++expr --expr expr++ expr--
- * - realise expr ? expr : expr (but, second expr calculate always)
+ *   use recursive value indirection: c="2*2"; a="c"; echo $((a+=2)) produce 6
+ * - implement assign syntax (VAR=expr, +=, *= etc)
+ * - implement exponentiation (** operator)
+ * - implement comma separated - expr, expr
+ * - implement ++expr --expr expr++ expr--
+ * - implement expr ? expr : expr (but second expr is always calculated)
  * - allow hexadecimal and octal numbers
- * - was restored loses XOR operator
- * - remove one goto label, added three ;-)
- * - protect $((num num)) as true zero expr (Manuel`s error)
+ * - restore lost XOR operator
+ * - protect $((num num)) as true zero expr (Manuel's error)
  * - always use special isspace(), see comment from bash ;-)
  */
 #include "libbb.h"
 #include "math.h"
 
-#define a_e_h_t arith_eval_hooks_t
+#define a_e_h_t   arith_eval_hooks_t
 #define lookupvar (math_hooks->lookupvar)
 #define setvar    (math_hooks->setvar   )
 //#define endofname (math_hooks->endofname)
@@ -130,103 +130,104 @@ typedef unsigned char operator;
  * precedence, and 3 high bits are an ID unique across operators of that
  * precedence. The ID portion is so that multiple operators can have the
  * same precedence, ensuring that the leftmost one is evaluated first.
- * Consider * and /. */
-
-#define tok_decl(prec,id) (((id)<<5)|(prec))
-#define PREC(op) ((op) & 0x1F)
-
-#define TOK_LPAREN tok_decl(0,0)
+ * Consider * and /
+ */
+#define tok_decl(prec,id)       (((id)<<5) | (prec))
+#define PREC(op)                ((op) & 0x1F)
 
-#define TOK_COMMA tok_decl(1,0)
+#define TOK_LPAREN              tok_decl(0,0)
 
-#define TOK_ASSIGN tok_decl(2,0)
-#define TOK_AND_ASSIGN tok_decl(2,1)
-#define TOK_OR_ASSIGN tok_decl(2,2)
-#define TOK_XOR_ASSIGN tok_decl(2,3)
-#define TOK_PLUS_ASSIGN tok_decl(2,4)
-#define TOK_MINUS_ASSIGN tok_decl(2,5)
-#define TOK_LSHIFT_ASSIGN tok_decl(2,6)
-#define TOK_RSHIFT_ASSIGN tok_decl(2,7)
+#define TOK_COMMA               tok_decl(1,0)
 
-#define TOK_MUL_ASSIGN tok_decl(3,0)
-#define TOK_DIV_ASSIGN tok_decl(3,1)
-#define TOK_REM_ASSIGN tok_decl(3,2)
+/* All assignments are right associative and have the same precedence,
+ * but there are 11 of them, which doesn't fit into 3 bits for unique id.
+ * Abusing another precedence level:
+ */
+#define TOK_ASSIGN              tok_decl(2,0)
+#define TOK_AND_ASSIGN          tok_decl(2,1)
+#define TOK_OR_ASSIGN           tok_decl(2,2)
+#define TOK_XOR_ASSIGN          tok_decl(2,3)
+#define TOK_PLUS_ASSIGN         tok_decl(2,4)
+#define TOK_MINUS_ASSIGN        tok_decl(2,5)
+#define TOK_LSHIFT_ASSIGN       tok_decl(2,6)
+#define TOK_RSHIFT_ASSIGN       tok_decl(2,7)
 
-/* all assign is right associativity and precedence eq, but (7+3)<<5 > 256 */
-#define convert_prec_is_assign(prec) do { if (prec == 3) prec = 2; } while (0)
+#define TOK_MUL_ASSIGN          tok_decl(3,0)
+#define TOK_DIV_ASSIGN          tok_decl(3,1)
+#define TOK_REM_ASSIGN          tok_decl(3,2)
 
-/* conditional is right associativity too */
-#define TOK_CONDITIONAL tok_decl(4,0)
-#define TOK_CONDITIONAL_SEP tok_decl(4,1)
+#define fix_assignment_prec(prec) do { if (prec == 3) prec = 2; } while (0)
 
-#define TOK_OR tok_decl(5,0)
+/* ternary conditional operator is right associative too */
+#define TOK_CONDITIONAL         tok_decl(4,0)
+#define TOK_CONDITIONAL_SEP     tok_decl(4,1)
 
-#define TOK_AND tok_decl(6,0)
+#define TOK_OR                  tok_decl(5,0)
 
-#define TOK_BOR tok_decl(7,0)
+#define TOK_AND                 tok_decl(6,0)
 
-#define TOK_BXOR tok_decl(8,0)
+#define TOK_BOR                 tok_decl(7,0)
 
-#define TOK_BAND tok_decl(9,0)
+#define TOK_BXOR                tok_decl(8,0)
 
-#define TOK_EQ tok_decl(10,0)
-#define TOK_NE tok_decl(10,1)
+#define TOK_BAND                tok_decl(9,0)
 
-#define TOK_LT tok_decl(11,0)
-#define TOK_GT tok_decl(11,1)
-#define TOK_GE tok_decl(11,2)
-#define TOK_LE tok_decl(11,3)
+#define TOK_EQ                  tok_decl(10,0)
+#define TOK_NE                  tok_decl(10,1)
 
-#define TOK_LSHIFT tok_decl(12,0)
-#define TOK_RSHIFT tok_decl(12,1)
+#define TOK_LT                  tok_decl(11,0)
+#define TOK_GT                  tok_decl(11,1)
+#define TOK_GE                  tok_decl(11,2)
+#define TOK_LE                  tok_decl(11,3)
 
-#define TOK_ADD tok_decl(13,0)
-#define TOK_SUB tok_decl(13,1)
+#define TOK_LSHIFT              tok_decl(12,0)
+#define TOK_RSHIFT              tok_decl(12,1)
 
-#define TOK_MUL tok_decl(14,0)
-#define TOK_DIV tok_decl(14,1)
-#define TOK_REM tok_decl(14,2)
+#define TOK_ADD                 tok_decl(13,0)
+#define TOK_SUB                 tok_decl(13,1)
 
-/* exponent is right associativity */
-#define TOK_EXPONENT tok_decl(15,1)
+#define TOK_MUL                 tok_decl(14,0)
+#define TOK_DIV                 tok_decl(14,1)
+#define TOK_REM                 tok_decl(14,2)
 
-/* For now unary operators. */
-#define UNARYPREC 16
-#define TOK_BNOT tok_decl(UNARYPREC,0)
-#define TOK_NOT tok_decl(UNARYPREC,1)
+/* exponent is right associative */
+#define TOK_EXPONENT            tok_decl(15,1)
 
-#define TOK_UMINUS tok_decl(UNARYPREC+1,0)
-#define TOK_UPLUS tok_decl(UNARYPREC+1,1)
+/* unary operators */
+#define UNARYPREC               16
+#define TOK_BNOT                tok_decl(UNARYPREC,0)
+#define TOK_NOT                 tok_decl(UNARYPREC,1)
 
-#define PREC_PRE (UNARYPREC+2)
+#define TOK_UMINUS              tok_decl(UNARYPREC+1,0)
+#define TOK_UPLUS               tok_decl(UNARYPREC+1,1)
 
-#define TOK_PRE_INC tok_decl(PREC_PRE, 0)
-#define TOK_PRE_DEC tok_decl(PREC_PRE, 1)
+#define PREC_PRE                (UNARYPREC+2)
 
-#define PREC_POST (UNARYPREC+3)
+#define TOK_PRE_INC             tok_decl(PREC_PRE, 0)
+#define TOK_PRE_DEC             tok_decl(PREC_PRE, 1)
 
-#define TOK_POST_INC tok_decl(PREC_POST, 0)
-#define TOK_POST_DEC tok_decl(PREC_POST, 1)
+#define PREC_POST               (UNARYPREC+3)
 
-#define SPEC_PREC (UNARYPREC+4)
+#define TOK_POST_INC            tok_decl(PREC_POST, 0)
+#define TOK_POST_DEC            tok_decl(PREC_POST, 1)
 
-#define TOK_NUM tok_decl(SPEC_PREC, 0)
-#define TOK_RPAREN tok_decl(SPEC_PREC, 1)
+#define SPEC_PREC               (UNARYPREC+4)
 
-#define NUMPTR (*numstackptr)
+#define TOK_NUM                 tok_decl(SPEC_PREC, 0)
+#define TOK_RPAREN              tok_decl(SPEC_PREC, 1)
 
 static int
 tok_have_assign(operator op)
 {
 	operator prec = PREC(op);
 
-	convert_prec_is_assign(prec);
+	fix_assignment_prec(prec);
 	return (prec == PREC(TOK_ASSIGN) ||
 			prec == PREC_PRE || prec == PREC_POST);
 }
 
 static int
-is_right_associativity(operator prec)
+is_right_associative(operator prec)
 {
 	return (prec == PREC(TOK_ASSIGN) || prec == PREC(TOK_EXPONENT)
 	        || prec == PREC(TOK_CONDITIONAL));
@@ -255,25 +256,25 @@ arith_lookup_val(v_n_t *t, a_e_h_t *math_hooks)
 
 		if (p) {
 			int errcode;
-
-			/* recursive try as expression */
 			chk_var_recursive_looped_t *cur;
 			chk_var_recursive_looped_t cur_save;
 
+			/* recursively try p as expression */
+
 			for (cur = prev_chk_var_recursive; cur; cur = cur->next) {
 				if (strcmp(cur->var, t->var) == 0) {
 					/* expression recursion loop detected */
 					return -5;
 				}
 			}
-			/* save current lookuped var name */
+			/* save current var name */
 			cur = prev_chk_var_recursive;
 			cur_save.var = t->var;
 			cur_save.next = cur;
 			prev_chk_var_recursive = &cur_save;
 
-			t->val = arith (p, &errcode, math_hooks);
-			/* restore previous ptr after recursiving */
+			t->val = arith(p, &errcode, math_hooks);
+			/* restore previous ptr after recursion */
 			prev_chk_var_recursive = cur;
 			return errcode;
 		}
@@ -283,21 +284,24 @@ arith_lookup_val(v_n_t *t, a_e_h_t *math_hooks)
 	return 0;
 }
 
-/* "applying" a token means performing it on the top elements on the integer
- * stack. For a unary operator it will only change the top element, but a
- * binary operator will pop two arguments and push a result */
+/* "Applying" a token means performing it on the top elements on the integer
+ * stack. For an unary operator it will only change the top element, but a
+ * binary operator will pop two arguments and push the result */
 static NOINLINE int
 arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr, a_e_h_t *math_hooks)
 {
+#define NUMPTR (*numstackptr)
+
 	v_n_t *numptr_m1;
 	arith_t numptr_val, rez;
 	int ret_arith_lookup_val;
 
 	/* There is no operator that can work without arguments */
-	if (NUMPTR == numstack) goto err;
+	if (NUMPTR == numstack)
+		goto err;
 	numptr_m1 = NUMPTR - 1;
 
-	/* check operand is var with noninteger value */
+	/* Check operand is var with noninteger value */
 	ret_arith_lookup_val = arith_lookup_val(numptr_m1, math_hooks);
 	if (ret_arith_lookup_val)
 		return ret_arith_lookup_val;
@@ -388,16 +392,13 @@ arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr, a_e_h_t *math_hoo
 			rez = rez ?
 				numptr_val : numptr_m1->contidional_second_val;
 		} else if (op == TOK_EXPONENT) {
+			arith_t c;
 			if (numptr_val < 0)
 				return -3;      /* exponent less than 0 */
-			else {
-				arith_t c = 1;
-
-				if (numptr_val)
-					while (numptr_val--)
-						c *= rez;
-				rez = c;
-			}
+			c = 1;
+			while (--numptr_val >= 0)
+			    c *= rez;
+			rez = c;
 		} else if (numptr_val==0)          /* zero divisor check */
 			return -2;
 		else if (op == TOK_DIV || op == TOK_DIV_ASSIGN)
@@ -422,11 +423,12 @@ arith_apply(operator op, v_n_t *numstack, v_n_t **numstackptr, a_e_h_t *math_hoo
 			rez++;
 	}
 	numptr_m1->val = rez;
-	/* protect geting var value, is number now */
+	/* erase var name, it is just a number now */
 	numptr_m1->var = NULL;
 	return 0;
  err:
 	return -1;
+#undef NUMPTR
 }
 
 /* longest must be first */
@@ -473,7 +475,6 @@ static const char op_tokens[] ALIGN1 = {
 	'(',        0, TOK_LPAREN,
 	0
 };
-/* ptr to ")" */
 #define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7])
 
 const char* FAST_FUNC
@@ -529,15 +530,15 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
 			 * result on the integer stack */
 
 			if (expr != ptr_to_rparen + 1) {
-				/* If we haven't done so already, */
-				/* append a closing right paren */
+				/* If we haven't done so already,
+				 * append a closing right paren
+				 * and let the loop process it */
 				expr = ptr_to_rparen;
-				/* and let the loop process it. */
 				continue;
 			}
-			/* At this point, we're done with the expression. */
+			/* At this point, we're done with the expression */
 			if (numstackptr != numstack + 1) {
-				/* ... but if there isn't, it's bad */
+				/* ...but if there isn't, it's bad */
 				goto err;
 			}
 			if (numstack->var) {
@@ -619,11 +620,11 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
 		/* We don't want an unary operator to cause recursive descent on the
 		 * stack, because there can be many in a row and it could cause an
 		 * operator to be evaluated before its argument is pushed onto the
-		 * integer stack. */
-		/* But for binary operators, "apply" everything on the operator
+		 * integer stack.
+		 * But for binary operators, "apply" everything on the operator
 		 * stack until we find an operator with a lesser priority than the
-		 * one we have just extracted. */
-		/* Left paren is given the lowest priority so it will never be
+		 * one we have just extracted.
+		 * Left paren is given the lowest priority so it will never be
 		 * "applied" in this way.
 		 * if associativity is right and priority eq, applied also skip
 		 */
@@ -641,17 +642,17 @@ arith(const char *expr, int *perrcode, a_e_h_t *math_hooks)
 					 * hit an open paren nor the bottom of the stack, pop
 					 * tokens and apply them */
 					if (prev_op == TOK_LPAREN) {
-						/* Any operator directly after a */
+						/* Any operator directly after a
+						 * close paren should consider itself binary */
 						lasttok = TOK_NUM;
-						/* close paren should consider itself binary */
 						goto next;
 					}
 				} else {
 					operator prev_prec = PREC(prev_op);
-					convert_prec_is_assign(prec);
-					convert_prec_is_assign(prev_prec);
+					fix_assignment_prec(prec);
+					fix_assignment_prec(prev_prec);
 					if (prev_prec < prec
-					 || (prev_prec == prec && is_right_associativity(prec))
+					 || (prev_prec == prec && is_right_associative(prec))
 					) {
 						stackptr++;
 						break;
-- 
cgit v1.2.3