/*********************************************************** PROGRAMMER'S CALCULATOR - TSR-MODULE Copyright (c) 1992-94 by Omega Point, Inc. ************************************************************/ #include "cr.h" typedef dword (*fpl)(); #define CHK_STACK (0) /* Set to 0 if no stack check, 1 if check */ #define MAX_EXPR (80) #define MAX_RPN (20) #define MAX_SUSP (20) #define BIN_PREF (0x60) /* Back-Quote for binary input */ #define ASGN_PREF (0x27) /* Single Quote - Assignement operator */ #define TYPE_VAL (-1) /* Token type for value */ #define TYPE_ERR (-2) /* Token type for error */ #define RAD2 (0) #define RAD10 (1) #define RAD16 (2) #define WS1 (0) #define WS2 (1) #define WS4 (2) #if CHK_STACK word free_stk=0xffff; #endif char oper_stk[MAX_SUSP]; /* Suspended operators stack */ dword rpn_stk[MAX_RPN]; /* RPN stack values, out-string temp buffer */ char expr[MAX_EXPR+2]; /* User typed expression */ char *nxc; /* Input pointer for expression scan */ dword tok_val; /* Numeric token value */ dword last_val; /* Value of last expression */ int last_tok; /* Last token value */ int last_var; /* Last variable name */ dword vars[26]; /* 26-variables (A-Z) */ dword *rs; /* Current position on RPN stack (values) */ char *os; /* Current position on operator stack */ /** Configuration parameters **/ dword wmask=(dword)(-1); char sgn=1,radix=RAD10,wsz=WS4; /******************************************* OPERATOR EVALUATORS ********************************************/ dword cast_val(np) register dword *np; { if (sgn) { if (wsz==WS4) return(*np); else if (wsz==WS2) return((long)((int)(*np))); else return((long) ((char)(*np)) ); } else return(*np&wmask); } dword op_or(arg) register dword *arg; { return(arg[0]|arg[1]); } dword op_xor(arg) register dword *arg; { return(arg[0]^arg[1]); } dword op_and(arg) register dword *arg; { return(arg[0]&arg[1]); } dword op_shl(arg) register dword *arg; { return(arg[0]<<(int)arg[1]); } dword op_shr(arg) register dword *arg; { register cnt=*(((int*)arg)+2); if (sgn) { if (wsz==WS4) return((long)arg[0]>>cnt); else if (wsz==WS2) return( (long)(*((int*)arg)>>cnt)); else return( (long)(*((char*)arg)>>cnt)); } else return((wmask&arg[0])>>cnt); } dword op_rol(arg) register dword *arg; { register cnt=*(((int*)arg)+2); if (wsz==WS1) return((long)b_rol(*(int*)arg,cnt)); else if (wsz==WS2) return((long)w_rol(*(word*)arg,cnt)); else return(ww_rol(arg[0],cnt)); } dword op_ror(arg) register dword *arg; { register cnt=*(((int*)arg)+2); if (wsz==WS1) return((long)b_ror(*(int*)arg,cnt)); else if (wsz==WS2) return((long)w_ror(*(word*)arg,cnt)); else return(ww_ror(arg[0],cnt)); } dword op_add(arg) register dword *arg; { return(arg[0]+arg[1]); } dword op_sub(arg) register dword *arg; { return(arg[0]-arg[1]); } dword op_mul(arg) register dword *arg; { return(arg[0]*arg[1]); } dword op_div(arg) register dword *arg; { if (arg[1]) { if (sgn) return((long)arg[0]/(long)arg[1]); else return(arg[0]/arg[1]); } else return(-1); } dword op_mod(arg) register dword *arg; { if (arg[1]) { if (sgn) return((long)arg[0]%(long)arg[1]); else return(arg[0]%arg[1]); } else return (0); } dword op_not(arg) register dword *arg; { rs++; return(~arg[1]); } dword op_neg(arg) register dword *arg; { rs++; return(-arg[1]); } dword op_nul(arg) register dword *arg; { rs++; return(arg[1]); } dword op_asgn(arg) register dword *arg; { register vn=last_var; last_var=-1; if (vn<0) rs=rpn_stk; /* Force error if no variable given */ else vars[vn]=*arg; /* Else perform assignement */ return(*arg); } /** OPERATOR PRECEDENCE TABLES **/ /* ? | ^ & < > [ ] + - / % * \ ~ FF FE ( ) ' */ char fa[]={55,3,5,7, 9, 9, 9, 9,11,11,13,13,13,13,16,16,16,77, 0, 1 }; char ga[]={56,4,6,8,10,10,10,10,12,12,14,14,14,14,15,15,15, 0,-1,88 }; char oper[]="|^&<>[]+-/%ù\\~\xff\xfe()\x1a"; char oper2[]="<>[]"; fpl exe[]={op_nul,op_or,op_xor,op_and,op_shl,op_shr,op_rol,op_ror,op_add, op_sub,op_div,op_mod,op_mul,op_mod,op_not,op_neg,op_nul, op_nul,op_nul,op_asgn}; eval_oper() { rs-=1; *rs = exe[str_pos(*os,oper)](rs); *rs=cast_val(rs); os--; if (rs<=rpn_stk) return(0); else return(1); } /*********************************************** TOKEN EXTRACTION ************************************************/ low_ci() { register int c; register char *s=nxc; while (*s==0x20) s++; c=*s++; if ((c==';')||(!c)) return(0); nxc=s; if ((c>='A')&&(c<='Z')) return(c+0x20); else return(c); } /** Get next token from the expression string **/ next_tok() { /* Tok > 0 --> Oper,Tok=-1:value,Tok=-2:err,Tok=0 Done */ register char *s; register int c; c=low_ci(); if (!c) return(c); if (str_pos(c,oper2)) /* Check 2 char operators */ { if (c!=low_ci()) return(TYPE_ERR); else return(c); } if ((last_tok>=0)&&(last_tok!=')')) { if (c=='-') return(0xff); /* Unary Minus */ if (c=='+') return(0xfe); /* Unary + as NOP */ } if (str_pos(c,oper)) return(c); last_var=-1; if (c=='?') /* ? stands for LAST VALUE */ { tok_val=last_val; return(TYPE_VAL); } if ((c>='a')&&(c<='z')) /* Valid variable letters */ { last_var=c = c-'a'; tok_val=vars[c]; return(TYPE_VAL); } /*** Extract number ***/ s=nxc-1; if ((c<='9')&&(c>'0')) /* Decimal 1-9 starting digit */ { s=dec2ul(s,&tok_val); } else if (c=='0') /* Hex - Start with leading 0 */ { s++; if ((*s=='x')||(*s=='X')) s++; if ((*s=='+')||(*s=='-')) s--; s=hex2ul(s,&tok_val); } else if (c==BIN_PREF) /* Binary string */ { s=bin2ul(s+1,&tok_val); } else s=0; if (!s) return(TYPE_ERR); nxc=s; return(TYPE_VAL); } /************************************************** EXPRESSION EVALUATOR ***************************************************/ eval_expr(s) char *s; { int t,fp,gp; nxc=s; last_tok=0; rs=rpn_stk; *rs=0; os=oper_stk; *os='('; do { t=next_tok(); last_tok=t; if (t==TYPE_VAL) /* Variable */ { rs++; if (rs>=&rpn_stk[MAX_RPN]) return(0); *rs=cast_val(&tok_val); continue; } if (t==TYPE_ERR) /* Error in expression */ return(0); if (!t) /* End of string reached */ if (os>oper_stk) t=')'; else break; fp=fa[str_pos(t,oper)]; /* fp=Operator input precedence */ do { if (os0) *(++os)=(char)t; if (os>=&oper_stk[MAX_SUSP]) return(0); } while(1); if (rs!=rpn_stk+1) return(0); last_val=cast_val(rs); return(1); } /*************************************************** CALCULATOR COMMADS ****************************************************/ #define ALT_X (45<<8) #define CMD_EQU (-2) #define DEC_RL (12) #define HEX_RL (10) #define BIN_RL (37) byte atr_expr=0x1f,atr_rslt=0x4e; /* Screen Attributes */ byte atr_rad=0x4b; word sep_let=0x20; int sdx=80,sdy=1; /* Window size */ int x0=0,y0=24; /* Window Left Upper Corner */ int rx0=0,rlen=DEC_RL; /* Result x-pos, length */ int ex0=DEC_RL; /* Expression x-pos & length */ int expr_w=MAX_EXPR-DEC_RL; /* BIN DEC HEX */ char rlen_tbl[3*3]={12,21,39, 7,9,14, 6,8,12 }; char rad_let[3]={'B','D','H'}; cvt_num(nump,strp) char *strp; dword *nump; { register char *s=strp; register char *v; v=(char*)nump + (1 << wsz); if (radix==RAD2) { do { v--; s=b2bin(*((int *)v),s); *s++='.'; /* Separate in 8 digit chunks */ } while (v>(char*)nump); s[-1]=0x20; } else do { v--; s=b2hex(*((int *)v),s); } while (v>(char*)nump); } show_result(k) { register char *s=(char*)rpn_stk; dword tmp; rlen=rlen_tbl[3*radix+wsz]; ex0=rlen; expr_w=MAX_EXPR-rlen; *s=rad_let[radix]; *(word*)(s+1)=':'; vid_atr=atr_rad; crs_x=0; dsp(s); *(word*)(fil_chr(s,0x20,rlen)-1) = sep_let; s+=3; /* Leave extra 2 blanks for output formating */ *s='?'; /* Fill fo error case (will get overwritten ) */ if (k) { tmp=cast_val(&last_val); if (sgn && *(((int*)(&tmp))+1)<0) /* Signed & negative */ { s[-1]='-'; tmp= -((long)tmp); } tmp &= wmask; if (radix==RAD10) ul2dec(tmp,s); else cvt_num(&tmp,s); } vid_atr=atr_rslt; dsp(((char*)rpn_stk)+2); } /** KEY-FILTER FOR STRING EDITOR **/ word filter() { register word k,bk; while (!anykey()) if (_hkey_again) return(K_ESC); k=pckey(); bk=(byte)k; if (bk=='=') bk=CMD_EQU; /* We don't display '=' key */ if ((bk==0xd)&&(kbflag&3)) k=K_F10; /* Shift-CR, or F10 */ if (bk==ASGN_PREF) bk=0x221a; /* Make arrow (graphic char entry)*/ if (bk=='*') bk=0xf9; /* Make nice small multiply symbol */ if (bk>0x1f) k=bk; /* If plain ASCII - pass low part */ return(k); /* If cursor/func key - pass full key */ } /*************************************************** CALCULATOR COMMAND LOOP ****************************************************/ static int edit_pos=1,ok=1; char *stf_ptr; run_calc() { int k,stf; register n; register char *s; (int)stf_ptr=stf=0; /* Cancell any key stuffing */ do { show_result(ok); if (stf) /* Stuff-keys was set */ { n=radix; s=((char*)rpn_stk)+2; /* Point into sign field */ if (n!=RAD10) { if (n==RAD16) { s[-1]=*s; *s='0'; } s++; /* Skip leading 0 */ if (stf<0) /* C format */ { if (n==RAD16) ins_chr('x',s); } else /* ASM format */ { s=s+str_pos(sep_let,s); s--; if (n==RAD2) *s='b'; else *s='h'; } s=(char*)rpn_stk; } while (*s==0x20) s++; stf_ptr=s; add_tsc_event((long)1); return; } crs_x=ex0; vid_atr=atr_expr; if (!(*expr)) edit_pos=1; s=expr; k=edit_str(s,expr_w,&edit_pos,filter); s+=edit_pos; if (((byte)k)&&(k>0)) k=(byte)k; switch (k) { case ALT_X: if (unload_safe()) uninstall(); case 0x1b: return; case CK_RIGHT: n=str_pos(';',s); if (!n) edit_pos=-1; else edit_pos += n; break; case CK_LEFT: while (s>expr) if (*s--==';') break; if ((edit_pos=s-expr)<=0) edit_pos=str_len(expr)-1; break; case K_UP: move_win(-1); break; case K_DN: move_win(1); break; case 'U'-64: sgn=0; break; case 'S'-64: sgn=1; break; case 'B'-64: radix=RAD2;break; case 'D'-64: radix=RAD10;break; case 'H'-64: radix=RAD16;break; case 'C'-64: wsz=WS1; wmask=0xff; break; case 'I'-64: wsz=WS2; wmask=0xffff; break; case 'L'-64: wsz=WS4; wmask=(dword)-1; break; case K_F5: stf=-1;break; /* C format */ case K_F6: stf= 1;break; /* ASM format */ } s=expr; do{ n=str_pos(';',s); if (0==(ok=eval_expr(s))) { edit_pos=nxc-expr; break; } s+=n; } while (*s && n && (expr+edit_pos)>=s ); if (k==K_F10 && ok) expr[0]=0; } while(1); } /*********************************************** TSR MODE ENTRY/EXIT HANDLERS ************************************************/ /** Save/Restore foreground screen **/ extern word scr_buf[]; chg_scr(func) fp func; { crs_x=x0; crs_y=y0; (*func)(sdx,sdy,scr_buf); } /** MOVE EDIT WINDOW UP/DOWN **/ move_win(n) { chg_scr(put_blk); /* Restore screen */ y0+=n; if (y0<0) y0=scr_len-1; else if (y0>=scr_len) y0=0; chg_scr(get_blk); } /****************************************************************** HOTKEY SERVICE FUNCTION *******************************************************************/ isr() { #if CHK_STACK word n; if (free_stk==0xffff) _watch_stack(); else last_val=free_stk; #endif chk_video(); /* Update video param's */ save_crs(); /* Save foreground cursor */ chg_scr(get_blk); /* Save foreground screen */ _hkey_again=0; /* We use hotkey as ON/OFF button */ run_calc(); /* Do calculator command loop */ chg_scr(put_blk); /* Restore foreground screen */ restore_crs(); /* Restore foreground cursor */ #if CHK_STACK n=_unused_stack(); if (n