/* mycalc.e Simple Epsilon expression evaluator - handles subset of C/EEL expressions Three main entry points: command eval_at_point(): Evaluates expression at point in current buffer & displays result. command eval(): Requests expression from user & evaluates; displays result. command stuff_eval(): Requests expression from user & evaluates; stuffs result into buffer at point. A recommended macro is (define-macro "stuff-last-eval" "F-2stuff-evalC-MlastC-M") I have F-2 bound to named-command. Uses Recursive Descent parsing. 04/11/92 PMW created */ /* Expression Grammer: expr := xor-expr := expr | xor-expr xor-expr := and-expr := xor-expr ^ and-expr and-expr := shift-expr := and-expr & shift-expr shift-expr := add-expr := shift-expr << add-expr := shift-expr >> add-expr add-expr := mul-expr := add-expr + mul-expr := add-expr - mul-expr mul-expr := unop-expr := mul-expr * unop-expr := mul-expr / unop-expr := mul-expr % unop-expr unop-expr := + prim-expr := - prim-expr prim-expr := literal := ( expr ) := last literal := int-const := char-const int-const = [0-9]+ = 0(X|x)[0-9a-fA-F]+ = 0[0-7]+ = 0(B|b)[01]+ char-const = '[ -~]' = '\x[0-9A-Fa-f]+' = '\[0-7]+' */ int NextECH; int PushedECH; char *EGetCH; int ValidExpr; char *ExprError; int ExprValue; #define PushECH() (PushedECH = 1) int eeGetFromPoint() { if (point < size()) { NextECH = curchar(); ++point; } else NextECH = -1; } evalAndSay(chFn) char *chFn; { do_eval(chFn); if (ValidExpr) { --point; re_search(-1, "[ \t]*"); say("Value is %d, 0x%x, 0%o", ExprValue, ExprValue, ExprValue); } else { maybe_ding(!0); say("Error: %s", ExprError); } } command eval_at_point() { evalAndSay("eeGetFromPoint"); } char eeBuf[255]; char *eeBufPtr; int eeGetFromString() { if (*eeBufPtr) { NextECH = *eeBufPtr; ++eeBufPtr; } else NextECH = -1; } command eval() { get_strdef(eeBuf, "Expression", eeBuf); eeBufPtr = eeBuf; evalAndSay("eeGetFromString"); } command stuff_eval() { char ansBuf[80]; int ans; get_strdef(eeBuf, "Expression", eeBuf); eeBufPtr = eeBuf; ans = do_eval("eeGetFromString"); if (!ValidExpr) { maybe_ding(!0); say("Error: %s", ExprError); } else { if (!has_arg) iter = 10; switch (iter) { case 8: sprintf(ansBuf, "0%o", ans); break; case 10: sprintf(ansBuf, "%d", ans); break; case 16: sprintf(ansBuf, "0x%x", ans); break; default: maybe_ding(!0); say("Error: Only 8, 10, 16 are valid output bases"); return; } stuff(ansBuf); iter = 0; } } /* do_eval computes the answer from evaluating an expression. getch is the name of a function that returns one character in the global NextECH NextECH is set to -1 when no more characters are available */ int do_eval(getch) char *getch; { EGetCH = getch; PushedECH = 0; ExprError = ""; ValidExpr = 1; return (ExprValue = ee_expr()); } int eeBaseGetCh() { if (!try_calling(EGetCH)) NextECH = -1; return NextECH; } /* shell to call EGetCH & skip whitespace NOTE: not used by char-const! */ int eeGetCh() { if (!PushedECH) { do { eeBaseGetCh(); } while (NextECH != -1 && (NextECH == ' ' || NextECH == '\t')); NextECH = tolower(NextECH); } else PushedECH = 0; return NextECH; } int ee_expr() { int a = ee_xor(); while (eeGetCh() == '|' && ValidExpr) a |= ee_xor(); PushECH(); return a; } int ee_xor() { int a = ee_and(); while (eeGetCh() == '^' && ValidExpr) a ^= ee_and(); PushECH(); return a; } int ee_and() { int a = ee_shift(); while (eeGetCh() == '&' && ValidExpr) a &= ee_shift(); PushECH(); return a; } int ee_shift() { int a = ee_add(); while ((eeGetCh() == '<' || NextECH == '>') && ValidExpr) { char pECH = NextECH; if (eeGetCh() != pECH) { ExprError = "Not \"<\" or \">\""; ValidExpr = 0; return 1; } if (pECH == '<') a <<= ee_add(); else a >>= ee_add(); } PushECH(); return a; } int ee_add() { int a = ee_mul(); while ((eeGetCh() == '+' || NextECH == '-') && ValidExpr) if (NextECH == '+') a += ee_mul(); else a -= ee_mul(); PushECH(); return a; } int ee_mul() { int a = ee_unop(); while ((eeGetCh() == '*' || NextECH == '/' || NextECH == '%') && ValidExpr) switch (NextECH) { case '*': a *= ee_unop(); break; case '/': a /= ee_unop(); break; case '%': a %= ee_unop(); break; } PushECH(); return a; } int ee_unop() { switch (eeGetCh()) { case '+': return ee_prim(); case '-': return -ee_prim(); default: PushECH(); return ee_prim(); } } int ee_prim() { if (eeGetCh() == '(') { int sub = ee_expr(); if (eeGetCh() == ')') return sub; else { ExprError = "Missing \")\""; ValidExpr = 0; return sub; } } else if (NextECH == 'l') { char *p = "ast"; while (*p && eeGetCh() == *p) ++p; if (*p) { ExprError == "Not \"last\""; ValidExpr = 0; return 1; } else return ExprValue; } else { PushECH(); return ee_literal(); } } int ee_literal() { if (eeGetCh() == '\'') { int ans; if (eeBaseGetCh() == '\\') { if (eeGetCh() == 'x') ans = ee_hex(); else { PushECH(); ans = ee_octal(); } } else ans = NextECH; if (eeGetCh() != '\'') { ExprError = "Missing \"'\""; ValidExpr = 0; return 1; } else return ans; } else { PushECH(); return ee_intconst(); } } int ee_intconst() { if (eeGetCh() == '0') { if (eeGetCh() == 'x') { return ee_hex(); } else if (NextECH == 'b') { return ee_bin(); } else { PushECH(); return ee_octal(); } } else { PushECH(); return ee_decimal(); } } int ee_hex() { int ans = 0; while ((eeGetCh() >= '0' && NextECH <= '9') || (NextECH >= 'a' && NextECH <= 'f')) { ans *= 16; if (NextECH > '9') ans += NextECH - 'a' + 10; else ans += NextECH - '0'; } PushECH(); return ans; } int ee_decimal() { int ans = 0; while ((eeGetCh() >= '0' && NextECH <= '9')) { ans *= 10; ans += NextECH - '0'; } PushECH(); return ans; } int ee_octal() { int ans = 0; while ((eeGetCh() >= '0' && NextECH <= '7')) { ans *= 8; ans += NextECH - '0'; } PushECH(); return ans; } int ee_bin() { int ans = 0; while ((eeGetCh() >= '0' && NextECH <= '1')) { ans *= 2; ans += NextECH - '0'; } PushECH(); return ans; }