/* ** Calculator bitwise extension -- shared library plugin. ** ** Exports a CalcBitwisePlugin struct via calc_bitwise_entry(). The host ** program loads this .so with dlopen, calls calc_bitwise_entry() to get ** the plugin descriptor, and uses the eval() function to parse ** expressions that include bitwise operators (&, |, ^, <<, >>). ** ** The ^ (CARET) token is interpreted as bitwise XOR here, which ** intentionally conflicts with the power extension where ^ means ** exponentiation. This demonstrates grammar extension conflicts. */ #include "tokenize.h" #include "calc_bitwise.h" #include #include #include /* ** Lime parser interface functions (generated by Lime). ** Prefixed with the %name directive value: CalcBitwise. */ void *CalcBitwiseAlloc(void *(*mallocProc)(size_t)); void CalcBitwiseFree(void *p, void (*freeProc)(void *)); void CalcBitwise(void *yyp, int yymajor, int yyminor, int *result); /* ------------------------------------------------------------------ */ /* Extension descriptor (GrammarModification pattern) */ /* ------------------------------------------------------------------ */ typedef enum { MOD_ADD_RULE = 0, MOD_ADD_TOKEN = 1, MOD_MODIFY_PRECEDENCE = 2, } CalcGrammarModType; typedef struct { CalcGrammarModType type; const char *description; union { struct { const char *lhs; const char **rhs; int nrhs; const char *code; int precedence; } add_rule; struct { const char *name; const char *lexeme; int token_code; } add_token; struct { const char *symbol; int new_precedence; int new_assoc; /* 0=none, 1=left, 2=right, 3=nonassoc */ } modify_prec; } u; } CalcGrammarModification; /* RHS arrays for the bitwise production rules */ static const char *rhs_caret[] = { "expr", "CARET", "expr", NULL }; static const char *rhs_ampersand[] = { "expr", "AMPERSAND", "expr", NULL }; static const char *rhs_pipe[] = { "expr", "PIPE", "expr", NULL }; static const char *rhs_lshift[] = { "expr", "LSHIFT", "expr", NULL }; static const char *rhs_rshift[] = { "expr", "RSHIFT", "expr", NULL }; static CalcGrammarModification bitwise_mods[] = { /* --- Token additions --- */ { .type = MOD_ADD_TOKEN, .description = "Caret (bitwise XOR) operator", .u.add_token = { .name = "CARET", .lexeme = "^", .token_code = 8, }, }, { .type = MOD_ADD_TOKEN, .description = "Ampersand (bitwise AND) operator", .u.add_token = { .name = "AMPERSAND", .lexeme = "&", .token_code = 9, }, }, { .type = MOD_ADD_TOKEN, .description = "Pipe (bitwise OR) operator", .u.add_token = { .name = "PIPE", .lexeme = "|", .token_code = 10, }, }, { .type = MOD_ADD_TOKEN, .description = "Left-shift operator", .u.add_token = { .name = "LSHIFT", .lexeme = "<<", .token_code = 11, }, }, { .type = MOD_ADD_TOKEN, .description = "Right-shift operator", .u.add_token = { .name = "RSHIFT", .lexeme = ">>", .token_code = 12, }, }, /* --- Rule additions --- */ { .type = MOD_ADD_RULE, .description = "expr -> expr CARET expr (bitwise XOR)", .u.add_rule = { .lhs = "expr", .rhs = rhs_caret, .nrhs = 3, .code = "A = B ^ C;", .precedence = -1, }, }, { .type = MOD_ADD_RULE, .description = "expr -> expr AMPERSAND expr (bitwise AND)", .u.add_rule = { .lhs = "expr", .rhs = rhs_ampersand, .nrhs = 3, .code = "A = B & C;", .precedence = -1, }, }, { .type = MOD_ADD_RULE, .description = "expr -> expr PIPE expr (bitwise OR)", .u.add_rule = { .lhs = "expr", .rhs = rhs_pipe, .nrhs = 3, .code = "A = B | C;", .precedence = -1, }, }, { .type = MOD_ADD_RULE, .description = "expr -> expr LSHIFT expr (left shift)", .u.add_rule = { .lhs = "expr", .rhs = rhs_lshift, .nrhs = 3, .code = "A = B << C;", .precedence = -1, }, }, { .type = MOD_ADD_RULE, .description = "expr -> expr RSHIFT expr (right shift)", .u.add_rule = { .lhs = "expr", .rhs = rhs_rshift, .nrhs = 3, .code = "A = B >> C;", .precedence = -1, }, }, /* --- Precedence modifications --- */ { .type = MOD_MODIFY_PRECEDENCE, .description = "Set PIPE precedence (left-associative, lowest)", .u.modify_prec = { .symbol = "PIPE", .new_precedence = 1, .new_assoc = 1, /* left */ }, }, { .type = MOD_MODIFY_PRECEDENCE, .description = "Set CARET precedence (left-associative, above |)", .u.modify_prec = { .symbol = "CARET", .new_precedence = 2, .new_assoc = 1, /* left */ }, }, { .type = MOD_MODIFY_PRECEDENCE, .description = "Set AMPERSAND precedence (left-associative, above ^)", .u.modify_prec = { .symbol = "AMPERSAND", .new_precedence = 3, .new_assoc = 1, /* left */ }, }, { .type = MOD_MODIFY_PRECEDENCE, .description = "Set LSHIFT/RSHIFT precedence (left-associative, above &)", .u.modify_prec = { .symbol = "LSHIFT", .new_precedence = 4, .new_assoc = 1, /* left */ }, }, { .type = MOD_MODIFY_PRECEDENCE, .description = "Set RSHIFT precedence (left-associative, same as <<)", .u.modify_prec = { .symbol = "RSHIFT", .new_precedence = 4, .new_assoc = 1, /* left */ }, }, }; #define BITWISE_MOD_COUNT (sizeof(bitwise_mods) / sizeof(bitwise_mods[0])) /* ------------------------------------------------------------------ */ /* eval() -- tokenize and parse with the CalcBitwise parser */ /* ------------------------------------------------------------------ */ static int bitwise_eval(const char *expr, int *out) { void *parser = CalcBitwiseAlloc(malloc); if (!parser) return -1; int result = 0; int pos = 0; int len = (int)strlen(expr); while (pos < len) { int value = 0; int tok = calc_next_token(expr, &pos, len, &value); if (tok == 0) break; CalcBitwise(parser, tok, value, &result); } /* Signal end of input */ CalcBitwise(parser, 0, 0, &result); CalcBitwiseFree(parser, free); *out = result; return 0; } /* ------------------------------------------------------------------ */ /* Plugin entry point */ /* ------------------------------------------------------------------ */ typedef struct CalcBitwisePlugin { const char *name; const char *version; int (*eval)(const char *expr, int *result); const CalcGrammarModification *mods; uint32_t nmods; } CalcBitwisePlugin; static const CalcBitwisePlugin plugin = { .name = "bitwise_operators", .version = "1.0", .eval = bitwise_eval, .mods = bitwise_mods, .nmods = BITWISE_MOD_COUNT, }; const CalcBitwisePlugin *calc_bitwise_entry(void) { return &plugin; }