bc: use more compact parsing data structures
authorDenys Vlasenko <vda.linux@googlemail.com>
Fri, 7 Dec 2018 11:57:32 +0000 (12:57 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Fri, 7 Dec 2018 11:57:32 +0000 (12:57 +0100)
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@googlemail.com>
miscutils/bc.c

index 0330c43e567e59c0dfd4a06d2355fe3a27c0e459..685427e58a5283ee54f539cd52860824d96f4fd2 100644 (file)
@@ -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: