[git commit] bc: use more compact parsing data structures

Denys Vlasenko vda.linux at googlemail.com
Fri Dec 7 11:57:32 UTC 2018


commit: https://git.busybox.net/busybox/commit/?id=18c6b54f820923549135724fee6cf66c26929b07
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
dc_lex_token                                         697     701      +4
bc_parse_next_rel                                     20       -     -20
bc_parse_next_read                                    20       -     -20
bc_parse_next_print                                   20       -     -20
bc_parse_next_param                                   20       -     -20
bc_parse_next_for                                     20       -     -20
bc_parse_next_expr                                    20       -     -20
bc_parse_next_elem                                    20       -     -20
common_parse_expr                                     62      40     -22
bc_parse_expr                                         49      24     -25
dc_lex_regs                                           52      13     -39
bc_parse_name                                        581     539     -42
bc_parse_expr_empty_ok                              2157    2108     -49
dc_parse_insts                                       332      83    -249
dc_lex_tokens                                        364      91    -273
bc_parse_stmt                                       2261    1868    -393
------------------------------------------------------------------------------
(add/remove: 0/7 grow/shrink: 1/8 up/down: 4/-1232)         Total: -1228 bytes
   text	   data	    bss	    dec	    hex	filename
 987037	    485	   7296	 994818	  f2e02	busybox_old
 985814	    485	   7296	 993595	  f293b	busybox_unstripped

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 miscutils/bc.c | 62 +++++++++++++++++++++++++++++++++-------------------------
 1 file changed, 35 insertions(+), 27 deletions(-)

diff --git a/miscutils/bc.c b/miscutils/bc.c
index 0330c43e5..685427e58 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -632,11 +632,6 @@ typedef struct BcLex {
 	    BC_PARSE_FLAG_LOOP | BC_PARSE_FLAG_LOOP_INNER | BC_PARSE_FLAG_IF |   \
 	    BC_PARSE_FLAG_ELSE | BC_PARSE_FLAG_IF_END)))
 
-typedef struct BcParseNext {
-	uint32_t len;
-	BcLexType tokens[4];
-} BcParseNext;
-
 struct BcParse;
 
 struct BcProgram;
@@ -834,34 +829,40 @@ static const uint8_t bc_parse_ops[] = {
 #define bc_parse_op_PREC(i) (bc_parse_ops[i] & 0x0f)
 #define bc_parse_op_LEFT(i) (bc_parse_ops[i] & 0x10)
 
+// Byte array of up to 4 BC_LEX's, packed into 32-bit word
+typedef uint32_t BcParseNext;
+
 // These identify what tokens can come after expressions in certain cases.
-#define BC_PARSE_NEXT_TOKENS(...) .tokens = { __VA_ARGS__ }
-#define BC_PARSE_NEXT(a, ...)                         \
-	{                                                 \
-		.len = (a), BC_PARSE_NEXT_TOKENS(__VA_ARGS__) \
-	}
-static const BcParseNext bc_parse_next_expr =
-	BC_PARSE_NEXT(4, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF);
-static const BcParseNext bc_parse_next_param =
-	BC_PARSE_NEXT(2, BC_LEX_RPAREN, BC_LEX_COMMA);
-static const BcParseNext bc_parse_next_print =
-	BC_PARSE_NEXT(4, BC_LEX_COMMA, BC_LEX_NLINE, BC_LEX_SCOLON, BC_LEX_EOF);
-static const BcParseNext bc_parse_next_rel = BC_PARSE_NEXT(1, BC_LEX_RPAREN);
-static const BcParseNext bc_parse_next_elem = BC_PARSE_NEXT(1, BC_LEX_RBRACKET);
-static const BcParseNext bc_parse_next_for = BC_PARSE_NEXT(1, BC_LEX_SCOLON);
-static const BcParseNext bc_parse_next_read =
-	BC_PARSE_NEXT(2, BC_LEX_NLINE, BC_LEX_EOF);
+enum {
+#define BC_PARSE_NEXT4(a,b,c,d) ( (a) | ((b)<<8) | ((c)<<16) | ((((d)|0x80)<<24)) )
+#define BC_PARSE_NEXT2(a,b)     BC_PARSE_NEXT4(a,b,0xff,0xff)
+#define BC_PARSE_NEXT1(a)       BC_PARSE_NEXT4(a,0xff,0xff,0xff)
+	bc_parse_next_expr  = BC_PARSE_NEXT4(BC_LEX_NLINE,  BC_LEX_SCOLON, BC_LEX_RBRACE, BC_LEX_EOF),
+	bc_parse_next_param = BC_PARSE_NEXT2(BC_LEX_RPAREN, BC_LEX_COMMA),
+	bc_parse_next_print = BC_PARSE_NEXT4(BC_LEX_COMMA,  BC_LEX_NLINE,  BC_LEX_SCOLON, BC_LEX_EOF),
+	bc_parse_next_rel   = BC_PARSE_NEXT1(BC_LEX_RPAREN),
+	bc_parse_next_elem  = BC_PARSE_NEXT1(BC_LEX_RBRACKET),
+	bc_parse_next_for   = BC_PARSE_NEXT1(BC_LEX_SCOLON),
+	bc_parse_next_read  = BC_PARSE_NEXT2(BC_LEX_NLINE,  BC_LEX_EOF),
+#undef BC_PARSE_NEXT4
+#undef BC_PARSE_NEXT2
+#undef BC_PARSE_NEXT1
+};
 #endif // ENABLE_BC
 
 #if ENABLE_DC
-static const BcLexType dc_lex_regs[] = {
+static const //BcLexType - should be this type, but narrower type saves size:
+uint8_t
+dc_lex_regs[] = {
 	BC_LEX_OP_REL_EQ, BC_LEX_OP_REL_LE, BC_LEX_OP_REL_GE, BC_LEX_OP_REL_NE,
 	BC_LEX_OP_REL_LT, BC_LEX_OP_REL_GT, BC_LEX_SCOLON, BC_LEX_COLON,
 	BC_LEX_ELSE, BC_LEX_LOAD, BC_LEX_LOAD_POP, BC_LEX_OP_ASSIGN,
 	BC_LEX_STORE_PUSH,
 };
 
-static const BcLexType dc_lex_tokens[] = {
+static const //BcLexType - should be this type
+uint8_t
+dc_lex_tokens[] = {
 	BC_LEX_OP_MODULUS, BC_LEX_INVALID, BC_LEX_INVALID, BC_LEX_LPAREN,
 	BC_LEX_INVALID, BC_LEX_OP_MULTIPLY, BC_LEX_OP_PLUS, BC_LEX_INVALID,
 	BC_LEX_OP_MINUS, BC_LEX_INVALID, BC_LEX_OP_DIVIDE,
@@ -889,7 +890,9 @@ static const BcLexType dc_lex_tokens[] = {
 	BC_LEX_INVALID
 };
 
-static const BcInst dc_parse_insts[] = {
+static const //BcInst - should be this type. Using signed narrow type since BC_INST_INVALID is -1
+int8_t
+dc_parse_insts[] = {
 	BC_INST_INVALID, BC_INST_INVALID, BC_INST_INVALID, BC_INST_REL_GE,
 	BC_INST_INVALID, BC_INST_POWER, BC_INST_MULTIPLY, BC_INST_DIVIDE,
 	BC_INST_MODULUS, BC_INST_PLUS, BC_INST_MINUS,
@@ -4768,7 +4771,7 @@ static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags, BcParseNext ne
 	BcInst prev = BC_INST_PRINT;
 	BcLexType top, t = p->l.t.t;
 	size_t nexprs = 0, ops_bgn = p->ops.len;
-	uint32_t i, nparens, nrelops;
+	unsigned nparens, nrelops;
 	bool paren_first, paren_expr, rprn, done, get_token, assign, bin_last;
 
 	paren_first = p->l.t.t == BC_LEX_LPAREN;
@@ -4993,9 +4996,14 @@ static BcStatus bc_parse_expr_empty_ok(BcParse *p, uint8_t flags, BcParseNext ne
 	if (prev == BC_INST_BOOL_NOT || nexprs != 1)
 		return bc_error_bad_expression();
 
-	for (i = 0; i < next.len; ++i)
-		if (t == next.tokens[i])
+	// next is BcParseNext, byte array of up to 4 BC_LEX's, packed into 32-bit word
+	for (;;) {
+		if (t == (next & 0x7f))
 			goto ok;
+		if (next & 0x80) // last element?
+			break;
+		next >>= 8;
+	}
 	return bc_error_bad_expression();
  ok:
 


More information about the busybox-cvs mailing list