/* ** Calculator demo — runtime extension loading. ** ** Demonstrates a base 4-operation calculator built with Lime, extended ** at runtime by loading a shared library (libcalc_power.so) that adds ** the ^ (exponentiation) operator via dlopen/dlclose. */ #define _GNU_SOURCE #include #include #include #include #include #include "tokenize.h" #include "calc.h" /* ** Lime parser interface functions (generated by Lime). ** Prefixed with the %name directive value: Calc. */ void *CalcAlloc(void *(*mallocProc)(size_t)); void CalcFree(void *p, void (*freeProc)(void *)); void Calc(void *yyp, int yymajor, int yyminor, int *result); /* ------------------------------------------------------------------ */ /* Plugin types (must match calc_power_ext.c) */ /* ------------------------------------------------------------------ */ typedef struct { int 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; } modify_prec; } u; } CalcGrammarModification; typedef struct { const char *name; const char *version; int (*eval)(const char *expr, int *result); const CalcGrammarModification *mods; uint32_t nmods; } CalcPowerPlugin; /* ------------------------------------------------------------------ */ /* Base parser helpers */ /* ------------------------------------------------------------------ */ /* ** Evaluate an expression with the base parser, printing the result. */ static void run_base(const char *expr) { int result = 0; void *parser = CalcAlloc(malloc); if (!parser) { printf(" %s = ERROR: out of memory\n", expr); return; } 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; Calc(parser, tok, value, &result); } Calc(parser, 0, 0, &result); CalcFree(parser, free); printf(" %s = %d\n", expr, result); } /* ** Evaluate an expression with the base parser, detecting and reporting ** syntax errors. Redirects stderr to a memory buffer so we can ** capture the "syntax error" message from the %syntax_error handler. */ static void run_base_check(const char *expr) { int result = 0; /* Redirect stderr to a buffer to detect syntax errors */ FILE *saved_stderr = stderr; char errbuf[256] = {0}; FILE *mem = fmemopen(errbuf, sizeof(errbuf), "w"); if (mem) stderr = mem; void *parser = CalcAlloc(malloc); if (!parser) { if (mem) { fclose(mem); stderr = saved_stderr; } printf(" %s = ERROR: out of memory\n", expr); return; } 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; Calc(parser, tok, value, &result); } Calc(parser, 0, 0, &result); CalcFree(parser, free); if (mem) { fflush(mem); fclose(mem); stderr = saved_stderr; } if (errbuf[0] != '\0') { printf(" %s = ERROR: %s", expr, errbuf); } else { printf(" %s = %d\n", expr, result); } } /* ------------------------------------------------------------------ */ /* Main */ /* ------------------------------------------------------------------ */ int main(void) { printf("Calculator with runtime extension loading\n"); /* --- Base parser --- */ printf("\n--- Base parser (4 operations) ---\n"); run_base("3 + 4 * 2"); run_base("(3 + 4) * 2"); run_base("100 / 10 - 3"); run_base("-42"); /* --- Load extension --- */ printf("\nLoading extension: libcalc_power.so ...\n"); void *handle = dlopen("./libcalc_power.so", RTLD_NOW); if (!handle) { fprintf(stderr, "dlopen failed: %s\n", dlerror()); return 1; } typedef const CalcPowerPlugin *(*EntryFn)(void); EntryFn entry = (EntryFn)dlsym(handle, "calc_power_entry"); if (!entry) { fprintf(stderr, "dlsym failed: %s\n", dlerror()); dlclose(handle); return 1; } const CalcPowerPlugin *plugin = entry(); printf(" Loaded: %s v%s (%u grammar modifications)\n", plugin->name, plugin->version, plugin->nmods); /* --- Extended parser --- */ printf("\n--- Extended parser (+ exponent) ---\n"); int result; plugin->eval("2 ^ 10", &result); printf(" 2 ^ 10 = %d\n", result); plugin->eval("2 ^ 3 ^ 2", &result); printf(" 2 ^ 3 ^ 2 = %d\n", result); plugin->eval("(1 + 1) ^ 10", &result); printf(" (1 + 1) ^ 10 = %d\n", result); /* --- Unload extension --- */ printf("\nUnloading extension ...\n"); dlclose(handle); /* --- Back to base parser --- */ printf("\n--- Back to base parser ---\n"); run_base_check("2 + 3"); run_base_check("2 ^ 3"); printf("\nDone.\n"); return 0; }