;*****************************************************************
;*                PgmrCalc - Programmers Calculator              *
;*                                                               *
;*                                                               *
;*  Written by:   Gary T. Desrosiers                             *
;*                desrosi@pcnet.com                              *
;*                http://www.pcnet.com/~desrosi                  *
;*                                                               *
;*  Date Written: April 8th, 1997                                *
;*                                                               *
;*  Description:  Programmers calculator                         *
;*                 - Base conversion functions                   *
;*                 - Boolean functions                           *
;*                 - Bit shifts and rotates                      *
;*                 - Programmable with "C" style expression      *
;*                   interpreter.                                *
;*                 - 24 user re-definable keys                   *
;*                 - Cut/Paste support                           *
;*                 - Saved preferences                           *
;*                                                               *
;*  Version 2.0 Changes: May - July, 1997                        *
;*                - Added infix expression interpreter           *
;*                - Key remapping dialog                         *
;*                - Function declaration dialog                  *
;*                - Add 24 user re-definable keys                *
;*                - Signed/unsigned mode                         *
;*                - Changed default floating point mode to       *
;*                   decimal binary and added FP mode as option  *
;*                - Added cut/paste                              *
;*                - Saved preferences                            *
;*                                                               *
;*  Version 2.01: August 4th, 1997                               *
;*                Added a much requested feature,                *
;*                 The ability to "cycle" thru the base          *
;*                 pushbuttons using the pageup/pagedown         *
;*                 physical buttons.                             *
;*                                                               *
;*  Version 2.02: August 17th, 1997                              *
;*                Added MAC() builtin networking function per    *
;*                request.                                       *
;*                                                               *
;*                                                               *
;*  Version 2.50  August 30th, 1997                              *
;*                Converted to NewFloatMgr double precision      *
;*                 floating point routines when using PalmOS2.0. *
;*                                                               *
;*                Added support for Rick Huebner's MathLib:      *
;*                  Sin, Cos, Tan, ASin, ACos, ATan, Sqrt, Pow,  *
;*                  Sinh, Cosh, Tanh, Log, Log10, Exp, Cbrt      * 
;*                                                               *
;*                Added Degree/Radian option                     *
;*                                                               *
;*                Error indicator for Floating-point NaNs        *
;*                                                               *
;*                Added cancel button to Inp() panel             *
;*                                                               *
;*                Assorted bug fixes                             *
;*                                                               *
;*  Version 2.51  September 1st, 1997                            *
;*                Fatal exception when MathLib is not installed  *
;*                 on PalmPilot devices and floating point mode  *
;*                 is selected.                                  *
;*                                                               *
;*  Version 2.60  September 15th, 1997                           *
;*                Re-worked expression interpreter and added     *
;*                '=' token to allow for variable assignments.   *
;*                 Ex. A=2*Disp                                  *
;*                     A=B=2*Disp                                *
;*                 Which is exactly like 'C' does it except that *
;*                 the variable is defined automatically if not  *
;*                 already defined.                              *
;*                 Additionally, Late binding expressions can be *
;*                 entered using:                                *
;*                 Ex. A="2*Disp"                                *
;*                     A=B="2*Disp"                              *
;*                 So, what's the difference? A=Disp puts the    *
;*                 current contents of Disp in A as a constant.  *
;*                 A="Disp" puts the contents of Disp into A when*
;*                 the expression executes. i.e. Late bound.     *
;*                                                               *
;*                                                               *
;*                Now using a database to save state instead of  *
;*                 app preferences. This was done for backup     *
;*                 purposes and to facilitate saving expressions *
;*                 that were not assigned to keys which was not  *
;*                 done previously.                              *
;*                                                               *
;*                                                               *
;* Version 2.61   September 19th                                 *
;*                Bug fixes - Stack reuse problem                *
;*                                                               *
;* Version 2.62   September 23rd                                 *
;*                Bug fixes - Pilot 1000/5000 assignment problem *
;*                                                               *
;* Version 2.70   September 20th - October 22nd                  *
;*                Added control structures to interpreter        *
;*                   if, do, while, for, block{} and stmt;       *
;*                Added pre and post increment++ and decrement-- *
;*                  and +=, -=, *=, /=, %=, &=, |=, ^=           *
;*                  operators to expression interpreter          *
;*                Added scrollbar to display                     *
;*                Added grads mode                               *
;*                Changed status display area                    *
;*                Added option for symbol case insensitivity     *
;*                Added option to display floating point numbers *
;*                 in hex.                                       *
;*                Reworked all symbol table and stack management *
;*                 to minimize memory requirements and increase  *
;*                 speed.                                        *
;*                Added ASCII chart                              *
;*                Modified Pow() function to work with binaries  *
;*                                                               *
;*                Things that didn't make it into this release   *
;*                that will get done eventually...               *
;*                                                               *
;*                     Cut/paste in other input dialogs          *
;*                     Scroll area in expression inputs          *
;*                     More programmable keys                    *
;*                     int() and sgn() functions                 *
;*                     function to change base (set base)        *
;*                     get/store programs in notepad             *
;*                                                               *
;*                                                               *
;* Version 2.71   February 2nd, 1998                             *
;*                Fixed reported bug, '-', and '.' was switched  *
;*                in ascii chart and exception was occuring in   *
;*                preferences dialog when backspacing over base. *
;*                Added tab as whitespace in supr().             *
;*                                                               *
;* ------------------------------------------------------------- *
;*  Tools used to compile the source...                          *
;*    pilrc (resource compiler) v2.0a available at:              *
;*        http://www.scumby.com/scumbysoft/pilot/pilrc/index.htm *
;*    pila (assembler) v1.0 available in the ASDK on my site at: *
;*        http://www.pcnet.com/~desrosi/asdk1a1.zip              *
;*                                                               *
;*  Documentation on the calculator available at                 *
;*        http://www.pcnet.com/~desrosi/pgmrcalc_v2.html         *
;*                                                               *
;* ------------------------------------------------------------- *
;*  Note:        Set tabs to 8 when editing this file            *
;*****************************************************************
        include "Pilot.inc"
        include "Startup.inc"
        include "mathlib.inc"
        include "newfloatmgr.inc"
        include "pgmrcalc.inc"
AppType equ     'PgMc'
        Appl    "PgmrCalc", AppType

sysFtrCreator equ 'psys'
sysTrapSysLibLoad equ 41644 ;pilot.inc doesnt define this systrap

DBType equ 'Data'

struct FloatType
man.l                           ;unsigned 32 bit
exp.w                           ;signed 16 bit
sign.b                          ;+/- 1	
endstruct

struct PGM
pgmtext.l
stack.l
pgmidx.w
tokidx.w
returnVal.8 ;8byte boundry required
ignore.w
returnFlag.b
AtEof.b
endstruct

PGMSIZE equ sizeof(PGM)

struct BUILTIN
Name.l
Routine.l
Args.l
endstruct

BUILTINSIZE equ sizeof(BUILTIN)

struct KEYTAB
KeyText.l
KeySym.l
KeyCode.w
filler.w
endstruct

KEYTABSIZE equ sizeof(KEYTAB)

; Symbol table flags
SYMIMMEDIATE    equ 1
SYMNORESULT     equ 2
SYMSTATIC       equ 4

STARTINGSTACK  equ 8*8                                 ;starting stack allocation
STACKINCREMENT equ 8*4                                 ;increment when stack fills
MAXSTACK       equ 8*100                               ;maximum that stack grows to


           data

global	   TStr.40
alpha	   dc.b	'ABCDEF'
drg        dc.b 'Deg',0,'Rad',0,'Grd',0
instr      ds.b	2

SymPrevName dc.b 'Prev',0
SymOp1Name dc.b 'Op1',0                                 ;Operand 1
Op1        dc.b '0',0
           ds.b 40

SymROName  dc.b 'Disp',0                                ;Display/Operand 2
SymOp2Name dc.b 'Op2',0
Op2        dc.b '0',0
           ds.b 40

Static     dc.l SymOp1Name
           dc.l Op1
           dc.l SymPrevName
           dc.l Op1
           dc.l SymOp2Name
           dc.l Op2
           dc.l SymROName
           dc.l Op2
           dc.l 0 

SymMName   dc.b 'MStore',0                              ;Memory Store
SymMExpr   dc.b 'M=Disp',0
SymMText   dc.b 'M',0

SymMAddName dc.b 'MAdd',0                               ;Memory Add
SymMAddExpr dc.b 'M=M+Disp,Disp',0
SymMAddText dc.b 'M+',0
        
SymMSubName dc.b 'MSub',0                               ;Memory Subtract
SymMSubExpr dc.b 'M=M-Disp,Disp',0
SymMSubText dc.b 'M-',0

SymMRName  dc.b 'MRecall',0                             ;Memory Recall
SymMRExpr  dc.b 'M',0
SymMRText  dc.b 'MR',0

SymAddName dc.b 'Add',0                                 ;Add
SymAddExpr dc.b 'Op1+Op2',0
SymAddText dc.b '+',0

SymSubName dc.b 'Sub',0                                 ;Subtract
SymSubExpr dc.b 'Op1-Op2',0
SymSubText dc.b '-',0

SymMulName dc.b 'Mul',0                                 ;Multiply
SymMulExpr dc.b 'Op1*Op2',0
SymMulText dc.b '*',0

SymDivName dc.b 'Div',0                                 ;Divide
SymDivExpr dc.b 'Op1/Op2',0
SymDivText dc.b '/',0

SymModName dc.b 'Mod',0                                 ;Modulus
SymModExpr dc.b 'Op1%Op2',0

SymAndName dc.b 'And',0                                 ;Boolean And
SymAndExpr dc.b 'Op1&Op2',0

SymOrName  dc.b 'Or',0                                  ;Boolean Or
SymOrExpr  dc.b 'Op1|Op2',0

SymXorName dc.b 'Xor',0                                 ;Boolean Exclusive Or
SymXorExpr dc.b 'Op1^Op2',0

SymLSName  dc.b 'Lsft',0                                ;Left Shift
SymLSExpr  dc.b 'Disp<<1',0
SymLSText  dc.b '<<',0

SymRSName  dc.b 'Rsft',0                                ;Right Shift
SymRSExpr  dc.b 'Disp>>1',0
SymRSText  dc.b '>>',0

SymLRName  dc.b 'Lrot',0                                ;Left Rotate
SymLRExpr  dc.b 'Disp<<<1',0
SymLRText  dc.b '<<<',0

SymRRName  dc.b 'Rrot',0                                ;Right Rotate
SymRRExpr  dc.b 'Disp>>>1',0
SymRRText  dc.b '>>>',0

SymNegName dc.b 'Neg',0                                 ;Negate (Twos complement)
SymNegExpr dc.b '-Disp',0
SymNegText dc.b '+/-',0

SymNotName dc.b 'Not',0                                 ;Not (Ones Complement)
SymNotExpr dc.b '~Disp',0
SymNotText dc.b '~',0

SymClrName dc.b 'Clr',0                                 ;Clear 
SymClrExpr dc.b 'Clr()',0

SymCEName  dc.b 'CE',0                                  ;Clear Entry
SymCEExpr  dc.b 'CE()',0

SymPctName dc.b 'Pct',0                                 ;Percent
SymPctExpr dc.b 'Pct(Op1,Disp)',0
SymPctText dc.b '%',0

SymMACName dc.b 'MAC',0                                 ;Calc Network Media Access Bit inversions
SymMACExpr dc.b 'MAC(Disp)',0
SymMACText dc.b 'mac',0

SymACosName dc.b 'ACos',0                               ;Arc Cosine
SymACosExpr dc.b 'ACos(Disp)',0
SymACosText dc.b 'acos',0

SymASinName dc.b 'ASin',0                               ;Arc Sine
SymASinExpr dc.b 'ASin(Disp)',0
SymASinText dc.b 'asin',0

SymATanName dc.b 'ATan',0                               ;Arc Tangent
SymATanExpr dc.b 'ATan(Disp)',0
SymATanText dc.b 'atan',0

SymCosName dc.b 'Cos',0                                 ;Cosine
SymCosExpr dc.b 'Cos(Disp)',0
SymCosText dc.b 'cos',0

SymSinName dc.b 'Sin',0                                 ;Sine
SymSinExpr dc.b 'Sin(Disp)',0
SymSinText dc.b 'sin',0

SymTanName dc.b 'Tan',0                                 ;Tangent
SymTanExpr dc.b 'Tan(Disp)',0
SymTanText dc.b 'tan',0

SymACoshName dc.b 'ACosh',0                             ;Hyperbolic Arc Cosine
SymACoshExpr dc.b 'ACosh(Disp)',0
SymACoshText dc.b 'acosh',0

SymASinhName dc.b 'ASinh',0                             ;Hyperbolic Arc Sine
SymASinhExpr dc.b 'ASinh(Disp)',0
SymASinhText dc.b 'asinh',0

SymATanhName dc.b 'ATanh',0                             ;Hyperbolic Tangent
SymATanhExpr dc.b 'ATanh(Disp)',0
SymATanhText dc.b 'atanh',0

SymCoshName dc.b 'Cosh',0                               ;Hyperbolic Cosine
SymCoshExpr dc.b 'Cosh(Disp)',0
SymCoshText dc.b 'cosh',0

SymSinhName dc.b 'Sinh',0                               ;Hyperbolic Sine
SymSinhExpr dc.b 'Sinh(Disp)',0
SymSinhText dc.b 'sinh',0

SymTanhName dc.b 'Tanh',0                               ;Hyperbolic Tangent
SymTanhExpr dc.b 'Tanh(Disp)',0
SymTanhText dc.b 'tanh',0

SymLogName dc.b 'Log',0                                 ;Natural Logorithm
SymLogExpr dc.b 'Log(Disp)',0
SymLogText dc.b 'ln',0

SymLog10Name dc.b 'Log10',0                             ;Base 10 Logorithm
SymLog10Expr dc.b 'Log10(Disp)',0
SymLog10Text dc.b 'log',0

SymPowName dc.b 'Pow',0                                 ;x**y (Powers)
SymPowExpr dc.b 'Pow(Op1,Disp)',0
SymPowText dc.b 'pow',0

SymExpName dc.b 'Exp',0                                 ;Exponent
SymExpExpr dc.b 'Exp(Disp)',0
SymExpText dc.b 'exp',0

SymCbrtName dc.b 'Cbrt',0                               ;Cubed Root
SymCbrtExpr dc.b 'Cbrt(Disp)',0
SymCbrtText dc.b 'cbrt',0

SymSqrtName dc.b 'Sqrt',0                               ;Square Root
SymSqrtExpr dc.b 'Sqrt(Disp)',0
SymSqrtText dc.b 'sqrt',0

SymTempName dc.b 'Tmp',0                                ;name of symbol that DoInp uses
SymExprName dc.b 'Expr',0                               ;Expression input dialog
SymExprExpr dc.b 'Inp("Enter Expression")',0
SymExprText dc.b '?',0

LeftRight     dc.b 4,0 ;$03=left arrow, $04=right arrow, half add value=$07
Zero          dc.b '0',0
StackUnderflow dc.b 'Stack Underflow, possible missing argument',0
StackOverflow dc.b 'Stack Overflow',0
ErrorDBZ      dc.b 'Attempt to divide by zero',0
MissingLParen dc.b 'Missing left parenthisis',0
MissingRParen dc.b 'Missing right parenthisis',0
MissingLCurly dc.b 'Missing left curly brace',0
MissingRCurly dc.b 'Missing right curly brace',0
MissingNum    dc.b 'Numeric expected but not found',0
NoResult      dc.b 'No result from expression',0
Incomplete    dc.b 'Expression not completely processed, invalid token',0
MissingQuote  dc.b 'Missing Quote',0
ExpectedNum   dc.b 'Expected numeric constant',0
ExpectedString dc.b 'Expected string',0
ExpectedID    dc.b 'Expected identifier/symbol',0
AssignError   dc.b 'Assignment requires a quoted string, an expression, or a numeric value',0
KeyDef        dc.b 'Key not defined',0
InvalidRelop  dc.b 'Invalid relational operator',0
ExpectNUMID   dc.b 'Expected a numeric, expression, or varaible',0
ExpectedSemi  dc.b 'Expected semi-colon',0
ExpectedWhile dc.b 'Expected while after do statement',0
TokenError    dc.b 'Token poped from stack is unknown',0
tokfor        dc.b 'for',0
tokwhile      dc.b 'while',0
tokdo         dc.b 'do',0
tokif         dc.b 'if',0
tokelse       dc.b 'else',0
tokplusequal  dc.b '+=',0
tokminusequal dc.b '-=',0
toktimesequal dc.b '*=',0
tokmodequal   dc.b '%=',0
tokdivequal   dc.b '/=',0
tokandequal   dc.b '&=',0
tokorequal    dc.b '|=',0
tokxorequal   dc.b '^=',0
tokle         dc.b '<=',0
tokge         dc.b '>=',0
tokne         dc.b '!=',0
tokequal      dc.b '==',0
tokLshift     dc.b '<<',0
tokRshift     dc.b '>>',0
tokLRotate    dc.b '<<<',0
tokRRotate    dc.b '>>>',0
tokInc        dc.b '++',0
tokDec        dc.b '--',0
SquareDot     dc.b $95,0
MsgError      dc.b 'Error',0
BuiltInReturn dc.b 'return',0
BuiltInInp    dc.b 'Inp',0
BuiltInClr    dc.b 'Clr',0
BuiltInCE     dc.b 'CE',0
BuiltInPct    dc.b 'Pct',0
BuiltInMAC    dc.b 'MAC',0
BuiltInACos   dc.b 'ACos',0
BuiltInASin   dc.b 'ASin',0
BuiltInATan   dc.b 'ATan',0
BuiltInCos    dc.b 'Cos',0
BuiltInSin    dc.b 'Sin',0
BuiltInTan    dc.b 'Tan',0
BuiltInACosh  dc.b 'ACosh',0
BuiltInASinh  dc.b 'ASinh',0
BuiltInATanh  dc.b 'ATanh',0
BuiltInCosh   dc.b 'Cosh',0
BuiltInSinh   dc.b 'Sinh',0
BuiltInTanh   dc.b 'Tanh',0
BuiltInPow    dc.b 'Pow',0
BuiltInSqrt   dc.b 'Sqrt',0
BuiltInLog    dc.b 'Log',0
BuiltInLog10  dc.b 'Log10',0
BuiltInExp    dc.b 'Exp',0
BuiltInCbrt   dc.b 'Cbrt',0

MathLibName   dc.b 'MathLib',0

DBName        dc.b 'PgMcDB',0

       include "ascii.inc"

       align 4

global romVersion.l
                                                
global BuiltInTab.l		                ;built in function table
global BuiltInIdx.l		                ; and index

global hDB.l                                    ;handle to database

global usecount.l                               ;use count assoc with math library
global tempAccum.l                              ;temporary variable accumulator used in DoInp()
global MathLibRef.w                             ;reference to Rick Huebner's math library

global KeyTab.l			                ;pointer to key assignments
global KeyPage.w		                ;0 = 1st page, 1 = 2nd page
                                                
global ClipLen.w		                ;work variable for clipboard
global CurrentBase.w		                ;Current display base or $7fff for floating point display
global NumOps.w			                ;Number of operands
global DecimalFlag.w		                ;Decimal Point Present Yet?
global LastWasOp.w		                ;Last input num (0) or op(1)
global LastOp.w			                ;Last operation + - x /
global DegreeFlag.w                             ;kidcDegrees, kidcRadians, or kidcGrads
global RoundingFlag.w                           ;kidcNearest, kidcTowardZero, kidcUpward, kidcDownward
global ScrollPos.w                              ;position of cursor/scroller
global ScrollCapture.b                          ;0 = no capture, 1=capture
global ErrorFlag.b		                ;=1, error has occurred in program
global UnsignedResults.b                        ;0 = signed results, 1 = unsigned results
global DisplayFloatInHex.b                      ;0 = normal floating point display, 1 = display floats in hex
global SymbolCase.b                             ;0 = Case not sensitive, 1 = Case sensitive

       align 8			                ;Floating variables

;      rads to degs                                                
r2d    dc.l     $404ca5dc                       ;57.295779 or 180/pi()
       dc.l     $1615ebfa                       ; in double prec floating point

;      rads to grads
r2g    dc.l     $404fd4bb                       ;63.661977 or 200/pi()
       dc.l     $a98eda23
                                                 
Hundred dc.l    $c8000000                       ;Pilot version 1.0 constant of 100.0
        dc.w    $ffe7
        dc.b    $01
        dc.b    0

HundredV2 dc.l  $40590000,$0                    ;PalmPilot constant of 100.0

OneV2   dc.l    $3ff00000,$0                    ;PalmPilot constant of 1

One     dc.l    $80000000                       ;Pilot version 1.0 constant of 1.0
        dc.w    $ffe1
        dc.b    $01
        dc.b    0

global fpnTemp.8        	                ;Temporary float
 
       align 8
 
global TempPop.8

       align 8

global searchState.32                           ;DmSearchStatePtr

       code


;********************************************************************************
;*                            P I L O T M A I N                                 * 
;********************************************************************************

proc PilotMain(cmd.w, cmdPBP.l, launchFlags.w)
local   err.w
local   evt.EventType
beginproc
        cmp.w   #sysAppLaunchCmdNormalLaunch,cmd(a6)            ;sysAppLaunchCmdNormalLaunch?
        bne     Return                 				;not a normal launch, bag out
        systrap FtrGet(#sysFtrCreator.l, #sysFtrNumROMVersion.w, &romVersion(a5))
        cmp.b   #2,romVersion(a5)                               ;msb has version
        bge.s   Ver2                                            ;ver 2.0 or better...
        systrap FplInit()					;initialize floating point environment for v1.0
        bra.s   NoMath
Ver2
        systrap SysLibFind(&MathLibName(a5),&MathLibRef(a5))
        tst.b   d0
        beq.s   MathFnd
        systrap SysLibLoad(#LibType.l,#MathLibCreator.l,&MathLibRef(a5))
        tst.b   d0
        bne     MathLibNotFound
MathFnd
        systrap MathLibOpen(MathLibRef(a5).w,#MathLibVersion.l)
        tst.b   d0
        beq.s   MathOK
MathLibNotFound
NoMath  clr.w   MathLibRef(a5)
MathOK  
	call	Initialization()				;Initialize calculator
	systrap	MemPtrNew(#BUILTINSIZE*25.l)	                ;room for the 25 built in functions
	move.l	a0,BuiltInTab(a5)
	clr.l	BuiltInIdx(a5)
	cmpa.l	#0,a0
	bne.s	BuiltInOK1
        systrap FrmAlert(#ErrorMem.w)
	bra	Return
BuiltInOK1
	systrap MemPtrNew(#KEYTABSIZE*24.l)	        ;there are two pages of 12 keys
	move.l	a0,KeyTab(a5)
	cmpa.l	#0,a0
	bne.s	MemOK3
	systrap	FrmAlert(#ErrorMem.w)
	bra	Return
MemOK3
	systrap	MemSet(a0.l,#KEYTABSIZE*24.l,#0.b)      ;clear memory

        move.w  #kidcDegrees,DegreeFlag(a5)             ;set to degrees
        move.w  #kidcNearest,RoundingFlag(a5)           ;set rounding to nearest
	move.w	#10,CurrentBase(a5)			;mode default is decimal
	clr.w	KeyPage(a5)				;page 1 of 2 default
        move.w  #131,ScrollPos(a5)                      
        clr.l   tempAccum(a5)                           ;clear temp variable accum
        clr.b   DisplayFloatInHex(a5)                   ;don't display floats in hex by default
        move.b  #true,SymbolCase(a5)                    ;symbols case sensitive by default

; This "fixes up" the static table displacements to make them address pointers
        move.l  a5,d0
        lea.l   Static(a5),a0
StaInit tst.l   (a0)                                    ;end of statics?
        beq.s   StaInitx
        add.l   d0,(a0)                                 ;add a5 value to displacement
        lea.l   4(a0),a0                                ;next pointer
        bra.s   StaInit 
StaInitx

        call    OpenDatabase()                          ;try to open db
        tst.l   hDB(a5)                                 ;db open ok?
        beq.s   PMNoPrevDB
        call    LoadPreferences()                       ;restore saved state
        call    LoadKeyTabDB()                          ;restore keytab settings
        bra     PmAddBuiltin

PMNoPrevDB
        call    CreateDatabase()                        ;create a new database
        tst.l   hDB(a5)                                 ;create work ok?
        bne.s   PMSetDefaults
        systrap FrmAlert(#CreateDBError.w)              ;tell user db not created
        bra     Return
PMSetDefaults
        call    SetSymbolDefaults()                     ;setup default symbols

PmAddBuiltin
        call	AddBuiltIn(&BuiltInReturn(a5),&DoReturn(pc),#1.w)
        call	AddBuiltIn(&BuiltInInp(a5),&DoInp(pc),#1.w)
	call	AddBuiltIn(&BuiltInClr(a5),&DoClr(pc),#0.w)
	call	AddBuiltIn(&BuiltInCE(a5),&DoCE(pc),#0.w)
	call	AddBuiltIn(&BuiltInPct(a5),&DoPct(pc),#1.w)
        call	AddBuiltIn(&BuiltInCos(a5),&DoCos(pc),#1.w)
        call	AddBuiltIn(&BuiltInSin(a5),&DoSin(pc),#1.w)
        call	AddBuiltIn(&BuiltInTan(a5),&DoTan(pc),#1.w)
        call	AddBuiltIn(&BuiltInLog(a5),&DoLog(pc),#1.w)
        call	AddBuiltIn(&BuiltInLog10(a5),&DoLog10(pc),#1.w)
        call	AddBuiltIn(&BuiltInExp(a5),&DoExp(pc),#1.w)
        call	AddBuiltIn(&BuiltInCbrt(a5),&DoCbrt(pc),#1.w)
        call	AddBuiltIn(&BuiltInPow(a5),&DoPow(pc),#1.w)
        call	AddBuiltIn(&BuiltInSqrt(a5),&DoSqrt(pc),#1.w)
        call	AddBuiltIn(&BuiltInCosh(a5),&DoCosh(pc),#1.w)
        call	AddBuiltIn(&BuiltInSinh(a5),&DoSinh(pc),#1.w)
        call	AddBuiltIn(&BuiltInTanh(a5),&DoTanh(pc),#1.w)
        call	AddBuiltIn(&BuiltInACosh(a5),&DoACosh(pc),#1.w)
        call	AddBuiltIn(&BuiltInASinh(a5),&DoASinh(pc),#1.w)
        call	AddBuiltIn(&BuiltInATanh(a5),&DoATanh(pc),#1.w)
        call	AddBuiltIn(&BuiltInACos(a5),&DoACos(pc),#1.w)
        call	AddBuiltIn(&BuiltInASin(a5),&DoASin(pc),#1.w)
        call	AddBuiltIn(&BuiltInATan(a5),&DoATan(pc),#1.w)
	call	AddBuiltIn(&BuiltInMAC(a5),&DoMAC(pc),#1.w)

        systrap FrmGotoForm(#kidfMain.w)
EvtLoop
	systrap EvtGetEvent(&evt(a6), #evtWaitForever.w)
        systrap SysHandleEvent(&evt(a6))
        tst.b   d0					;handled?
        bne.s   EvtDone					;yep
        systrap MenuHandleEvent(&0, &evt(a6),&err(a6))
        tst.b   d0					;handled?
        bne.s   EvtDone					;yep
	call	ApplicationHandleEvent(&evt(a6))
	tst.b	d0
	bne.s	EvtDone
	systrap	FrmDispatchEvent(&evt(a6))
EvtDone cmpi.w  #appStopEvent,evt+EventType.eType(a6)   ;time to stop?
        bne.s   EvtLoop 

        systrap MemPtrNew(#64.l)                        ;get a buf
        move.l  a0,-(a7)
        move.l  a0,a3                                   ;put in a4 as working ptr
        move.w  #$8270,(a3)+                            ;set to version 2.60
        move.w  CurrentBase(a5),(a3)+                   ;save current base first
        move.w  DegreeFlag(a5),(a3)+                    ;save degree/radian flag
        move.w  KeyPage(a5),(a3)+                       ;save key page
        move.w  RoundingFlag(a5),(a3)+                  ;rounding flag
        move.b  UnsignedResults(a5),(a3)+               ;save unsigned results flag
        move.b  DisplayFloatInHex(a5),(a3)+             ;save float/hex flag
        move.b  SymbolCase(a5),(a3)+                    ;save symbol case flag
        systrap StrCopy(a3.l,&Op2(a5))                  ;copy string
        systrap StrLen(&Op2(a5))     
        ext.l   d0   
        lea.l   (a3,d0),a3                              ;increment pointer
        move.b  #0,(a3)                                 ;make sure term null
        add.l   #14,d0                                  ;sum of sizes before the Display + null term at eos
        move.l  (a7)+,a3
        call    SetAppInfo(a3.l,d0.l)
        systrap MemPtrFree(a3.l) 
        call    CloseDatabase()
	movea.l	BuiltInTab(a5),a0
	cmpa.l	#0,a0
	beq.s	NoFree1
	systrap	MemPtrFree(a0.l)
NoFree1	
	call	FreeKeyTab()		                ;free key table
	movea.l	KeyTab(a5),a0
	cmpa.l	#0,a0
	beq.s	FreMath
	systrap	MemPtrFree(a0.l)
FreMath tst.w   MathLibRef(a5)
        beq.s   FreFlot
        systrap MathLibClose(MathLibRef(a5).w,&usecount(a5))
        tst.l   usecount(a5)
        bne.s   FreFlot
        systrap SysLibRemove(MathLibRef(a5).w)
FreFlot cmp.b   #2,romVersion(a5)
        bge.s   Return
        systrap FplFree()		                ;clean up floating point env.
Return  moveq   #0,d0
endproc

proc LoadPreferences()
local pLPAppInfo.l
local LPVer.w
beginproc
        movem.l a3,-(a7)
        call    GetAppInfo()                            ;load app info segment ptr in a0
        cmpa.l  #0,a0                                   ;no app info?
        beq.s   LCPx                                    ;done
        move.l  a0,a3
        move.l  a0,pLPAppInfo(a6)                       ;save ptr for unlock
        move.w  (a3)+,LPVer(a6)                         ;get first word
        cmp.w   #$8270,LPVer(a6)                        ;is it our version?
        ble.s   LCPV300                                 ;yep, continue
        systrap FrmAlert(#VersionError.w)               ;say bad thing
        bra     LCPx
LCPV300 move.w  (a3)+,CurrentBase(a5)                   ;restore current base
        move.w  (a3)+,DegreeFlag(a5)                    ;restore degree/radian flags
        move.w  (a3)+,KeyPage(a5)                       ;restore key page number
        tst.w   KeyPage(a5)                             ;page 1 or 2?
        beq.s   LCPc
	eor.b	#07,LeftRight(a5)                       ;make sure arrow pointing correctly
LCPc    move.w  (a3)+,RoundingFlag(a5)                  ;restore rounding flag
        move.b  (a3)+,UnsignedResults(a5)               ;restore unsigned flag
        cmp.w   #$8270,LPVer(a6)                        ;is it a previous version?
        bne.s   LPSkip
        move.b  (a3)+,DisplayFloatInHex(a5)             ;save float/hex flag
        move.b  (a3)+,SymbolCase(a5)                    ;save symbol case flag
LPSkip
        systrap StrCopy(&Op2(a5),a3.l)                  ;copy previous display contents
        systrap MemPtrUnlock(pLPAppInfo(a6).l)          ;unlock chunk
LCPx    movem.l (a7)+,a3
endproc

proc LoadKeyTabDB()
local pLKTRec.l
local iLKTRecIdx.w
local bLKTKey.w
local LKTSymbol.20
local LKTText.20
beginproc
        movem.l a3,-(a7)
; Load key tab data which are the first 24 records in the DB

        clr.w   iLKTRecIdx(a6)                          ;clear record index
LKTLoop
        call    GetRecord(iLKTRecIdx(a6).w)             ;read record n
        cmpa.l  #0,a0
        beq.s   LKTx
        move.l  a0,a3
        move.l  a0,pLKTRec(a6)                          ;for unlock
        move.b  (a3)+,bLKTKey(a6)                       ;save key #
        systrap StrCopy(&LKTSymbol(a6),a3.l)            ;copy symbol
        systrap StrLen(a3.l)                            ;get length
        addq.w  #1,d0
        lea.l   (a3,d0),a3                              ;increment past it
        systrap StrCopy(&LKTText(a6),a3.l)              ;copy key text
        systrap MemPtrUnlock(pLKTRec(a6).l)             ;unlock prev record
        clr.w   d0
        move.b  bLKTKey(a6),d0                          ;key # rel to 0
        add.w   #KEY0,d0                                ;make relative to KEY0
	call	SetKeyTab(&LKTSymbol(a6).l,&LKTText(a6).l,d0.w)
        addq.w  #1,iLKTRecIdx(a6)                       ;increment record ptr
        cmp.w   #24,iLKTRecIdx(a6)                      ;done yet?
	blt.s	LKTLoop
LKTx    movem.l (a7)+,a3
endproc

proc SetSymbolDefaults()
beginproc
	call	SetKeyTab(&SymAndName(a5),&SymAndName(a5),#KEY0.w)
	call	SetKeyTab(&SymCEName(a5),&SymCEName(a5),#KEY1.w)
	call	SetKeyTab(&SymClrName(a5),&SymClrName(a5),#KEY2.w)
	call	SetKeyTab(&SymOrName(a5),&SymOrName(a5),#KEY3.w)
	call	SetKeyTab(&SymLSName(a5),&SymLSText(a5),#KEY4.w)
	call	SetKeyTab(&SymRSName(a5),&SymRSText(a5),#KEY5.w)
	call	SetKeyTab(&SymXorName(a5),&SymXorName(a5),#KEY6.w)
	call	SetKeyTab(&SymAddName(a5),&SymAddText(a5),#KEY7.w)
	call	SetKeyTab(&SymSubName(a5),&SymSubText(a5),#KEY8.w)
	call	SetKeyTab(&SymNegName(a5),&SymNegText(a5),#KEY9.w)
	call	SetKeyTab(&SymMulName(a5),&SymMulText(a5),#KEY10.w)
	call	SetKeyTab(&SymDivName(a5),&SymDivText(a5),#KEY11.w)

        tst.w   MathLibRef(a5)                          ;Any Mathlib?
        beq     SkipTrigKeyTab

	call	SetKeyTab(&SymPctName(a5),&SymPctText(a5),#KEY12.w)
	call	SetKeyTab(&SymExprName(a5),&SymExprText(a5),#KEY13.w)
	call	SetKeyTab(&SymClrName(a5),&SymClrName(a5),#KEY14.w)
	call	SetKeyTab(&SymASinName(a5),&SymASinText(a5),#KEY15.w)
	call	SetKeyTab(&SymACosName(a5),&SymACosText(a5),#KEY16.w)
	call	SetKeyTab(&SymATanName(a5),&SymATanText(a5),#KEY17.w)
	call	SetKeyTab(&SymSinName(a5),&SymSinText(a5),#KEY18.w)
	call	SetKeyTab(&SymCosName(a5),&SymCosText(a5),#KEY19.w)
	call	SetKeyTab(&SymTanName(a5),&SymTanText(a5),#KEY20.w)
       	call	SetKeyTab(&SymSqrtName(a5),&SymSqrtText(a5),#KEY21.w)
	call	SetKeyTab(&SymLog10Name(a5),&SymLog10Text(a5),#KEY22.w)
	call	SetKeyTab(&SymLogName(a5),&SymLogText(a5),#KEY23.w)
        bra     KTDefaultDone

SkipTrigKeyTab
	call	SetKeyTab(&SymPctName(a5),&SymPctText(a5),#KEY12.w)
	call	SetKeyTab(&SymCEName(a5),&SymCEName(a5),#KEY13.w)
	call	SetKeyTab(&SymClrName(a5),&SymClrName(a5),#KEY14.w)
	call	SetKeyTab(&SymExprName(a5),&SymExprText(a5),#KEY15.w)
	call	SetKeyTab(&SymLRName(a5),&SymLRText(a5),#KEY16.w)
	call	SetKeyTab(&SymRRName(a5),&SymRRText(a5),#KEY17.w)
	call	SetKeyTab(&SymNegName(a5),&SymNegText(a5),#KEY18.w)
	call	SetKeyTab(&SymMName(a5),&SymMText(a5),#KEY19.w)
	call	SetKeyTab(&SymMAddName(a5),&SymMAddText(a5),#KEY20.w)
       	call	SetKeyTab(&SymNotName(a5),&SymNotText(a5),#KEY21.w)
	call	SetKeyTab(&SymMSubName(a5),&SymMSubText(a5),#KEY22.w)
	call	SetKeyTab(&SymMRName(a5),&SymMRText(a5),#KEY23.w)

KTDefaultDone
        tst.w   MathLibRef(a5)                          ;Any MathLib?
        beq     SkipTrigFunc

 	call	AddSymbol(&SymACosName(a5),&SymACosExpr(a5),#SYMIMMEDIATE.w)
 	call	AddSymbol(&SymASinName(a5),&SymASinExpr(a5),#SYMIMMEDIATE.w)
 	call	AddSymbol(&SymATanName(a5),&SymATanExpr(a5),#SYMIMMEDIATE.w)
 	call	AddSymbol(&SymCosName(a5),&SymCosExpr(a5),#SYMIMMEDIATE.w)
 	call	AddSymbol(&SymSinName(a5),&SymSinExpr(a5),#SYMIMMEDIATE.w)
 	call	AddSymbol(&SymTanName(a5),&SymTanExpr(a5),#SYMIMMEDIATE.w)
 	call	AddSymbol(&SymACoshName(a5),&SymACoshExpr(a5),#SYMIMMEDIATE.w)
 	call	AddSymbol(&SymASinhName(a5),&SymASinhExpr(a5),#SYMIMMEDIATE.w)
 	call	AddSymbol(&SymATanhName(a5),&SymATanhExpr(a5),#SYMIMMEDIATE.w)
 	call	AddSymbol(&SymCoshName(a5),&SymCoshExpr(a5),#SYMIMMEDIATE.w)
 	call	AddSymbol(&SymSinhName(a5),&SymSinhExpr(a5),#SYMIMMEDIATE.w)
 	call	AddSymbol(&SymTanhName(a5),&SymTanhExpr(a5),#SYMIMMEDIATE.w)
 	call	AddSymbol(&SymLogName(a5),&SymLogExpr(a5),#SYMIMMEDIATE.w)
 	call	AddSymbol(&SymLog10Name(a5),&SymLog10Expr(a5),#SYMIMMEDIATE.w)
 	call	AddSymbol(&SymExpName(a5),&SymExpExpr(a5),#SYMIMMEDIATE.w)
 	call	AddSymbol(&SymCbrtName(a5),&SymCbrtExpr(a5),#SYMIMMEDIATE.w)
 	call	AddSymbol(&SymPowName(a5),&SymPowExpr(a5),#0.w)
 	call	AddSymbol(&SymSqrtName(a5),&SymSqrtExpr(a5),#SYMIMMEDIATE.w)
SkipTrigFunc
	call	AddSymbol(&SymMACName(a5),&SymMACExpr(a5),#SYMIMMEDIATE.w)
	call	AddSymbol(&SymMRName(a5),&SymMRExpr(a5),#SYMIMMEDIATE.w)
	call	AddSymbol(&SymMSubName(a5),&SymMSubExpr(a5),#SYMIMMEDIATE.w)
	call	AddSymbol(&SymMAddName(a5),&SymMAddExpr(a5),#SYMIMMEDIATE.w)
	call	AddSymbol(&SymMName(a5),&SymMExpr(a5),#SYMIMMEDIATE.w)
	call	AddSymbol(&SymExprName(a5),&SymExprExpr(a5),#SYMIMMEDIATE.w)
	call	AddSymbol(&SymPctName(a5),&SymPctExpr(a5),#SYMIMMEDIATE.w)
	call	AddSymbol(&SymNegName(a5),&SymNegExpr(a5),#SYMIMMEDIATE.w)
	call	AddSymbol(&SymNotName(a5),&SymNotExpr(a5),#SYMIMMEDIATE.w)
	call	AddSymbol(&SymRSName(a5),&SymRSExpr(a5),#SYMIMMEDIATE.w)
	call	AddSymbol(&SymLSName(a5),&SymLSExpr(a5),#SYMIMMEDIATE.w)
 	call	AddSymbol(&SymRRName(a5),&SymRRExpr(a5),#SYMIMMEDIATE.w)
	call	AddSymbol(&SymLRName(a5),&SymLRExpr(a5),#SYMIMMEDIATE.w)
	call	AddSymbol(&SymXorName(a5),&SymXorExpr(a5),#0.w)
	call	AddSymbol(&SymOrName(a5),&SymOrExpr(a5),#0.w)
	call	AddSymbol(&SymAndName(a5),&SymAndExpr(a5),#0.w)
	call	AddSymbol(&SymModName(a5),&SymModExpr(a5),#0.w)
	move.w	#SYMIMMEDIATE|SYMNORESULT,d0
	call	AddSymbol(&SymCEName(a5),&SymCEExpr(a5),d0.w)
	move.w	#SYMIMMEDIATE|SYMNORESULT,d0
	call	AddSymbol(&SymClrName(a5),&SymClrExpr(a5),d0.w)
	call	AddSymbol(&SymDivName(a5),&SymDivExpr(a5),#0.w)
	call	AddSymbol(&SymMulName(a5),&SymMulExpr(a5),#0.w)
	call	AddSymbol(&SymSubName(a5),&SymSubExpr(a5),#0.w)
	call	AddSymbol(&SymAddName(a5),&SymAddExpr(a5),#0.w)

endproc

proc ApplicationHandleEvent(pevt.l)
local formID.w
beginproc
	movem.l	d2/a3,-(a7)
        movea.l pevt(a6),a0				;a0 = pevt
        move.w  EventType.eType(a0),d0
        cmp.w	#frmLoadEvent,d0 			;frmLoadEvent?
	bne	AHENotHandled
	move.w	EventType.data+frmLoad.formID(a0),formID(a6)
        systrap FrmInitForm(formID(a6).w)
	move.l	a0,a3
        systrap FrmSetActiveForm(a0.l)
	cmp.w	#kidfMain,formID(a6)
	bne.s	ChkPgm
	systrap	FrmSetEventHandler(a3.l,&MainFormHandleEvent(pc))
	move.b	#1,d0
	bra.s	AHEDone
ChkPgm  cmp.w	#kidfProgram,formID(a6)
	bne.s	ChkMnt
	systrap	FrmSetEventHandler(a3.l,&ProgramHandleEvent(pc))
	move.b	#1,d0
	bra.s	AHEDone
ChkMnt  cmp.w	#kidfSymbolMaint,formID(a6)
	bne.s	ChkOpt
	systrap	FrmSetEventHandler(a3.l,&SymbolHandleEvent(pc))
	move.b	#1,d0
	bra.s	AHEDone
ChkOpt  cmp.w   #kidfOptions,formID(a6)
        bne.s   ChkAsc
        systrap FrmSetEventHandler(a3.l,&OptionsHandleEvent(pc))
        move.b  #1,d0
        bra.s   AHEDone
ChkAsc  cmp.w   #kidfAscii,formID(a6)
        bne.s   AHENotHandled
        systrap FrmSetEventHandler(a3.l,&AsciiHandleEvent(pc))
        move.b  #1,d0
        bra.s   AHEDone
AHENotHandled	
        clr.b   d0
AHEDone movem.l	(a7)+,d2/a3
endproc

proc SymbolHandleEvent(pevt.l)
local SHESelText.l
local SHESymbol.l
local SHEExpr.l
local SHEmem.l
local SHETemp.l
local SHEsize.w
local SHERecIdx.w
beginproc
	movem.l	a3-a4/d2,-(a7)
        movea.l pevt(a6),a0				;a0 = pevt
        move.w  EventType.eType(a0),d0
	cmp.w   #frmOpenEvent,d0
        bne	SHENotOpen
	cmp.w	#kidfSymbolMaint,EventType.data+frmOpen.formID(a0)
	bne	SHENotHandled
	systrap	FrmGetActiveForm()
        move.l  a0,a3
        systrap FrmGetObjectIndex(a3.l, #kidcImmed.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
	systrap	CtlSetValue(a0.l,#1.w) ;check immediate and avoid confusion later
        systrap FrmGetObjectIndex(a3.l,#kidbadd.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
        systrap CtlSetUsable(a0.l,#1.b)
        systrap FrmGetObjectIndex(a3.l,#kidbreplace.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
        systrap CtlSetUsable(a0.l,#0.b)
        systrap FrmGetObjectIndex(a3.l,#kidbdelete.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
        systrap CtlSetUsable(a0.l,#0.b)
        systrap FrmDrawForm(a3.l)
	bra	SHEat
SHENotOpen
	cmp.w   #ctlSelectEvent,d0
        bne     SHENotSelect
	cmp.w	#kidcSymbolTable,EventType.data+ctlSelect.controlID(a0)
	bne	SHECheckButtons
	systrap	MemPtrNew(#1024.l)
	cmpa.l	#0,a0
	bne.s	SHEMemOK1
        systrap FrmAlert(#ErrorMem.w)
	bra	SHEat
SHEMemOK1
        move.l  a0,SHEmem(a6)                           ;save for MemPtrFree
        call    CreateSymbolLst(a0.l)                   ;create list
        move.w  d0,SHEsize(a6)                          ;save list size
        systrap FrmGetActiveForm()
	move.l	a0,a3
        systrap FrmGetObjectIndex(a3.l, #kidcSymbolList.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
	systrap	LstSetListChoices(a0.l,SHEmem(a6).l,SHEsize(a6).w)
        systrap MemPtrFree(SHEmem(a6).l)                ;free buffer
	bra	SHENotHandled			        ;Can't complete must say not handled

SHECheckButtons
	cmp.w   #kidbok,EventType.data+ctlSelect.controlID(a0)
	bne.s	SHECheckReplace
	systrap	FrmUpdateForm(#kidfMain.w,#frmRedrawUpdateCode.w)
	systrap	FrmReturnToForm(#kidfMain.w)
	bra	SHEat
	
SHECheckReplace
	cmp.w	#kidbreplace,EventType.data+ctlSelect.controlID(a0)
	bne	SHECheckAdd
        systrap FrmGetActiveForm()
	move.l	a0,a3
        systrap FrmGetObjectIndex(a3.l, #kidcSymbol.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
        systrap FldGetTextPtr(a0.l)
        cmpa.l  #0,a0
        beq     SHEBadInput
        cmp.b   #0,(a0)
        beq     SHEBadInput
	move.l	a0,SHESymbol(a6)
	move.l	a0,a4
	call	ValidateSymbol(a0.l)
	tst.b	d0
	bne	SHEBadSymbol
	call	GetSymbol(a4.l)
	tst.w	d0				        ;symbol already exists?
	beq	SHEAddSymbol                            
        systrap FrmGetObjectIndex(a3.l, #kidcExpr.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
        systrap FldGetTextPtr(a0.l)
        cmpa.l  #0,a0
        beq     SHEBadInput
        cmp.b   #0,(a0)
        beq     SHEBadInput
	move.l	a0,SHEExpr(a6)
        systrap FrmGetObjectIndex(a3.l, #kidcImmed.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
	systrap	CtlGetValue(a0.l)
	ext.l	d0
	call	ReplaceSymbol(SHESymbol(a6).l,SHEExpr(a6).l,d0.w)
	systrap	FrmAlert(#OperationDone.w)
	bra	SHEat

SHEBadSymbol
	systrap	FrmAlert(#BadSymbol.w)
	bra	SHEat

SHECheckAdd
	cmp.w	#kidbadd,EventType.data+ctlSelect.controlID(a0)
	bne	SHECheckDelete
SHEAddSymbol
        systrap FrmGetActiveForm()
	move.l	a0,a3
        systrap FrmGetObjectIndex(a3.l, #kidcSymbol.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
        systrap FldGetTextPtr(a0.l)
        cmpa.l  #0,a0
        beq     SHEBadInput
        cmp.b   #0,(a0)
        beq     SHEBadInput
	move.l	a0,SHESymbol(a6)
	call	GetSymbol(a0.l)
	tst.w	d0
	bne	SHEAlreadyExists
	call	ValidateSymbol(SHESymbol(a6).l)
	tst.b	d0
	bne.s	SHEBadSymbol
        systrap FrmGetActiveForm()
	move.l	a0,a3
        systrap FrmGetObjectIndex(a3.l, #kidcExpr.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
        systrap FldGetTextPtr(a0.l)
        cmpa.l  #0,a0
        beq     SHEBadInput
        cmp.b   #0,(a0)
        beq     SHEBadInput
	move.l	a0,SHEExpr(a6)
        systrap FrmGetActiveForm()
	move.l	a0,a3
        systrap FrmGetObjectIndex(a3.l, #kidcImmed.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
	systrap	CtlGetValue(a0.l)
	call	AddSymbol(SHESymbol(a6).l,SHEExpr(a6).l,d0.w)
        cmp.b   #true,d0
        bne.s   SHEDupSym
	systrap	FrmAlert(#OperationDone.w)
	bra	SHEat

SHEDupSym
	systrap FrmCustomAlert(#DupID.w,SHESymbol(a6).l,&0,&0)
        bra     SHEat

SHEAlreadyExists
	systrap	FrmAlert(#SymbolExists.w)
	bra	SHEat


SHECheckDelete
	cmp.w	#kidbdelete,EventType.data+ctlSelect.controlID(a0)
	bne	SHEat
	systrap	FrmGetActiveForm()
	move.l	a0,a4
        systrap FrmGetObjectIndex(a4.l, #kidcSymbol.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        systrap FldGetTextPtr(a0.l)
        cmpa.l  #0,a0
        beq     SHEBadInput
        cmp.b   #0,(a0)
        beq     SHEBadInput
	call	DeleteSymbol(a0.l)
	tst.b	d0
	beq.s	SHEDeleteOk
	systrap	FrmAlert(#OperationFailed.w)
	bra	SHEat
SHEDeleteOk
	systrap	FrmAlert(#OperationDone.w)
	bra	SHEat

SHENotSelect
	cmp.w	#popSelectEvent,d0
	bne	SHENotHandled
	cmp.w	#kidcSymbolTable,EventType.data+lstSelect.listID(a0)
	bne	SHENotHandled
	;Fill in the Symbol and Expr fields from the symbol table	
	systrap	FrmGetActiveForm()
	move.l	a0,a4
        systrap FrmGetObjectIndex(a4.l, #kidcSymbolList.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
	movea.l	pevt(a6),a1
        systrap LstGetSelectionText(a0.l,EventType.data+popSelect.selection(a1).w)
        move.l  a0,SHESelText(a6)
        systrap FrmGetObjectIndex(a4.l, #kidcImmed.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
	move.l	a0,a4
        call    GetSymbol(SHESelText(a6).l)             ;read record selected
        move.w  d0,SHERecIdx(a6)                        ;save rec no
        call    GetSymbolFlags(d0.w)                    ;retrieve the flags
	and.l	#SYMIMMEDIATE,d0                        ;is this immediate?
	systrap	CtlSetValue(a4.l,d0.w)                  ;set appropriately
	systrap	CtlDrawControl(a4.l)

	systrap	FrmGetActiveForm()
	move.l	a0,a4
        systrap FrmGetObjectIndex(a4.l, #kidcExpr.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
	move.l	a0,a4
	systrap	FldFreeMemory(a4.l)
	call    GetSymbolPgm(SHERecIdx(a6).w)           ;get pgm text
        move.l  a0,SHETemp(a6)                          ;save 
	systrap	StrLen(a0.l)
	systrap	FldInsert(a4.l,SHETemp(a6).l,d0.w)      ;insert pgm text
        systrap MemPtrFree(SHETemp(a6).l)               ;free storage

	systrap	FrmGetActiveForm()
	move.l	a0,a4
        systrap FrmGetObjectIndex(a4.l, #kidcSymbol.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
	move.l	a0,a4
	systrap	FldFreeMemory(a4.l)
        call    GetSymbolName(SHERecIdx(a6).w)          ;get symbol name
        move.l  a0,SHETemp(a6)                          ;save it
	systrap	StrLen(a0.l)
	systrap	FldInsert(a4.l,SHETemp(a6).l,d0.w)
        systrap MemPtrFree(SHETemp(a6).l)               ;free storage

	systrap	FrmGetActiveForm()
        move.l  a0,a4
        systrap FrmGetObjectIndex(a4.l,#kidbreplace.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        systrap CtlShowControl(a0.l)

        systrap FrmGetObjectIndex(a4.l,#kidbdelete.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        systrap CtlShowControl(a0.l)

SHEat	move.b	#1,d0
	bra.s	SHEDone
SHEBadInput
	systrap SndPlaySystemSound(#sndError.b)	
SHENotHandled
	clr.b	d0
SHEDone	movem.l	(a7)+,a3-a4/d2
endproc

 
proc ProgramHandleEvent(pevt.l)
local PGMSelText.l
local pKeyTab.l
local PGMmem.l
local PGMTemp.l
local PGMsize.w
beginproc
	movem.l	a3-a4/d2,-(a7)
        movea.l pevt(a6),a0				;a0 = pevt
        move.w  EventType.eType(a0),d0
	cmp.w   #frmOpenEvent,d0
        bne.s	PGMNotOpen
	cmp.w	#kidfProgram,EventType.data+frmOpen.formID(a0)
	bne	PGMNotHandled
	systrap	FrmGetActiveForm()
	move.l	a0,a3
        systrap FrmDrawForm(a3.l)
        systrap FrmGetObjectIndex(a3.l, #kidcKeySelection.w)	;reset any 
        systrap FrmGetObjectPtr(a3.l,d0.w)                      ; selection in the
        systrap LstSetSelection(a0.l,#$ffff.w)                  ;  key listbox
	call	RefreshFromKeyTab(a3.l)				;set button labels
        systrap FrmGetObjectIndex(a3.l, #kidbpageselect.w)	;set direction key
        systrap FrmGetObjectPtr(a3.l,d0.w)
	systrap	CtlSetLabel(a0.l,&LeftRight(a5))
	bra	PGMEat
PGMNotOpen
        cmp.w   #lstSelectEvent,d0
        beq     PGMEnableReprogram
	cmp.w   #ctlSelectEvent,d0
        bne     PGMNotSelect
	cmp.w   #kidbok,EventType.data+ctlSelect.controlID(a0)
	bne.s	PGMCheckSelectPopup
	systrap	FrmUpdateForm(#kidfMain.w,#frmRedrawUpdateCode.w)
	systrap	FrmReturnToForm(#kidfMain.w)
	bra	PGMEat

PGMCheckSelectPopup
	cmp.w	#kidcSymbolTable,EventType.data+ctlSelect.controlID(a0)
	bne	PGMCheckArrows
	systrap	MemPtrNew(#1024.l)
	cmpa.l	#0,a0
	bne.s	PGMMemOK1
        systrap FrmAlert(#ErrorMem.w)
	bra	PGMEat
PGMMemOK1
        move.l  a0,PGMmem(a6)                           ;save address of list
        call    CreateSymbolLst(a0.l)                   ;create list of symbols
        move.w  d0,PGMsize(a6)                          ;save size of list
        systrap FrmGetActiveForm()
	move.l	a0,a3
        systrap FrmGetObjectIndex(a3.l, #kidcSymbolList.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
	systrap	LstSetListChoices(a0.l,PGMmem(a6).l,PGMsize(a6).w)
        systrap MemPtrFree(PGMmem(a6).l)
	bra	PGMNotHandled

PGMNotSelect
	cmp.w	#popSelectEvent,d0
	bne	PGMNotHandled
	cmp.w	#kidcSymbolTable,EventType.data+lstSelect.listID(a0)
	bne	PGMNotHandled
	systrap	FrmGetActiveForm()
	move.l	a0,a4
        systrap FrmGetObjectIndex(a4.l, #kidcSymbolList.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
	movea.l	pevt(a6),a1
        systrap LstGetSelectionText(a0.l,EventType.data+popSelect.selection(a1).w)
        move.l  a0,PGMSelText(a6)
        systrap FrmGetObjectIndex(a4.l, #kidcSymbol.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
	move.l	a0,a4
        systrap FldSetSelection(a4.l,#0.w,#0.w) ;I don't know why but we get a DmWriteCheck if this not done
	systrap	FldFreeMemory(a4.l)
        call    GetSymbol(PGMSelText(a6).l)             ;read record selected
        call    GetSymbolName(d0.w)                     ;get symbol name
        move.l  a0,PGMTemp(a6)                          ;save in temp
	systrap	StrLen(a0.l)
	systrap	FldInsert(a4.l,PGMTemp(a6).l,d0.w)
        systrap MemPtrFree(PGMTemp(a6).l)               ;free storage
	bra	PGMEat

PGMCheckArrows
	cmp.w	#kidbpageselect,EventType.data+ctlSelect.controlID(a0)
	bne.s	PGMCheckReprogram
	systrap	FrmGetActiveForm()
	move.l	a0,a4
        systrap FrmGetObjectIndex(a4.l, #kidbpageselect.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
	move.l	a0,a3
	systrap	CtlGetLabel(a3.l)
	cmpa.l	#0,a0
	beq	PGMNotHandled
	eor.b	#07,LeftRight(a5)
	systrap	CtlSetLabel(a3.l,&LeftRight(a5))
	eor.w	#1,KeyPage(a5)
	call	RefreshFromKeyTab(a4.l)			;set button labels
	bra	PGMEat

PGMCheckReprogram
	cmp.w	#kidbreprogram,EventType.data+ctlSelect.controlID(a0)
	bne.s	PGMKeySelect
	call	ReprogramKey()
	systrap	FrmGetActiveForm()
	call	RefreshFromKeyTab(a0.l)			;set button labels
	bra	PGMEat

PGMKeySelect
        move.w  EventType.data+ctlSelect.controlID(a0),d2
        call    AdjustForPage(d2.w)
        move.w  d0,d2
	call	FindKeyTabSymbol(d2.w)
	cmpa.l	#0,a0					;is it there?
	beq	PGMBeep
	move.l	a1,pKeyTab(a6)				;we need the KEYTAB ptr
	sub.w	#KEY0,d2			        ;Relative to 0
        systrap FrmGetActiveForm()
        move.l  a0,a4
        systrap FrmGetObjectIndex(a4.l, #kidcKeySelection.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        systrap LstSetSelection(a0.l,d2.w)

	systrap	FrmGetActiveForm()
	move.l	a0,a4
        systrap FrmGetObjectIndex(a4.l, #kidcKeyText.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
	move.l	a0,a4
	systrap	FldFreeMemory(a4.l)
	movea.l	pKeyTab(a6),a3
	movea.l	KEYTAB.KeyText(a3),a3
	systrap	StrLen(a3.l)
	systrap	FldInsert(a4.l,a3.l,d0.w)

	systrap	FrmGetActiveForm()
	move.l	a0,a4
        systrap FrmGetObjectIndex(a4.l, #kidcSymbol.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
	move.l	a0,a4
	systrap	FldFreeMemory(a4.l)
	movea.l	pKeyTab(a6),a3
	movea.l	KEYTAB.KeySym(a3),a3
	call	GetSymbol(a3.l)
	tst.w	d0
	beq.s	PGMEat
        call    GetSymbolName(d0.w)
        move.l  a0,PGMTemp(a6)
	systrap	StrLen(a0.l)
	systrap	FldInsert(a4.l,PGMTemp(a6).l,d0.w)
        systrap MemPtrFree(PGMTemp(a6).l)

PGMEnableReprogram
	systrap	FrmGetActiveForm()
	move.l	a0,a4
        systrap FrmGetObjectIndex(a4.l, #kidbreprogram.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
	move.l	a0,a4
	systrap	CtlShowControl(a4.l)
	bra.s	PGMEat
PGMBeep
	systrap SndPlaySystemSound(#sndError.b)	

PGMEat  move.b	#1,d0
	bra.s	PGMDone
PGMNotHandled
	clr.b	d0
PGMDone movem.l	(a7)+,a3-a4/d2
endproc

proc ReprogramKey()
local RKSymbol.l
local RKKeyText.l
local RKExpr.l
beginproc
	movem.l	d2/a3-a4,-(a7)
        systrap FrmGetActiveForm()
	move.l	a0,a4
        systrap FrmGetObjectIndex(a4.l, #kidcSymbol.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        systrap FldGetTextPtr(a0.l)
        cmpa.l  #0,a0
        beq     RKError
        cmp.b   #0,(a0)
        beq     RKError
	move.l	a0,RKSymbol(a6)
        call    GetSymbol(a0.l)
        tst.w   d0
        beq     RKBadSymbol
	systrap	StrLen(RKSymbol(a6).l)
	tst.w	d0
	beq	RKError
        systrap FrmGetActiveForm()
	move.l	a0,a4
        systrap FrmGetObjectIndex(a4.l, #kidcKeyText.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        systrap FldGetTextPtr(a0.l)
        cmpa.l  #0,a0
        beq     RKError
        cmp.b   #0,(a0)
        beq     RKError
	move.l	a0,RKKeyText(a6)
	systrap	StrLen(a0.l)
	tst.w	d0
	beq	RKError
        systrap FrmGetObjectIndex(a4.l, #kidcKeySelection.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        systrap LstGetSelection(a0.l)
        tst.w   d0                                      ;no key selection?
        blt.s   RKError
        add.w   #KEY0,d0                                ;relative to rsc of keys
	call	SetKeyTab(RKSymbol(a6).l,RKKeyText(a6).l,d0.w)
	systrap	FrmAlert(#OperationDone.w)
	systrap	FrmGetActiveForm()
	move.l	a0,a4
        systrap FrmGetObjectIndex(a4.l, #kidbreprogram.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
	systrap	CtlHideControl(a0.l)
	bra.s	RKx
RKBadSymbol
	systrap FrmCustomAlert(#NoSym.w,RKSymbol(a6).l,&KeyDef(a5),&0)
        bra.s   RKx
RKError
        systrap FrmAlert(#ReprogramError.w)
RKx	movem.l	(a7)+,d2/a3-a4
endproc

proc CreateSymbolLst(pList.l)
local pCSLRec.l
local iBSLIdx.w
local CSLNumEnt.w
beginproc
        move.l  a3,-(a7)
        systrap DmNumRecords(hDB(a5).l)
        sub.w   #24,d0                                  ;-keytab = num symbols in db
        move.w  d0,CSLNumEnt(a6)                        ;save # entries
        lsl.l   #2,d0                                   ;*4 
        movea.l pList(a6),a3
        lea.l   (a3,d0),a4                              ;a4 points to freespace area
	move.w	#24,iBSLIdx(a6)                         ;position to 1st symbol record
BSLLoop
        call    GetRecord(iBSLIdx(a6).w)                ;get record
        cmpa.l  #0,a0                                   ;end?
        beq.s   BSLDone
        move.l  a0,pCSLRec(a6)
        systrap StrCopy(a4.l,a0.l)                      ;copy symbol name
        systrap StrLen(a4.l)                            ;get length of string
        move.l  a4,(a3)+                                ;save pointer in list
        lea.l   (a4,d0),a4
        clr.b   (a4)+                                   ;increment past zero term
        systrap MemPtrUnlock(pCSLRec(a6).l)             ;unlock rec
        addq.w  #1,iBSLIdx(a6)                          ;increment record number
	bra.s	BSLLoop
BSLDone move.w  CSLNumEnt(a6),d0                        ;d0 is num entries
        movea.l pList(a6),a0
BSLx    move.l  (a7)+,a3
endproc



proc OptionsHandleEvent(pevt.l)
beginproc
	movem.l	a3-a4/d2,-(a7)
        movea.l pevt(a6),a0				;a0 = pevt
        move.w  EventType.eType(a0),d0
	cmp.w   #frmOpenEvent,d0
        bne	OPTNotOpen
	cmp.w	#kidfOptions,EventType.data+frmOpen.formID(a0)
	bne	OPTNotHandled
	systrap	FrmGetActiveForm()
        move.l  a0,a4
        systrap FrmDrawForm(a4.l)
	systrap	FrmSetControlGroupSelection(a4.l,#2.b,RoundingFlag(a5).w)
	systrap	FrmSetControlGroupSelection(a4.l,#1.b,DegreeFlag(a5).w)
        systrap FrmGetObjectIndex(a4.l, #kidcBase.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        move.l  a0,a3
        cmp.w   #$7fff,CurrentBase(a5)
        beq.s   OPTInFPMode
        move.w  CurrentBase(a5),d0
        ext.l   d0
        systrap StrIToA(&TStr(a5),d0.l)
        systrap StrLen(&TStr(a5))
        move.w  d0,d2
        systrap FldInsert(a3.l,&TStr(a5),d2.w)
        systrap FldSetInsPtPosition(a3.l,d2.w)
        systrap FldSetUsable(a3.l,#1.b)
        bra.s   OPTInit1
OPTInFPMode
        systrap FldSetUsable(a3.l,#0.b)
OPTInit1
        systrap FldDrawField(a3.l)

        systrap FrmGetObjectIndex(a4.l, #kidcFloatInHex.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        move.b  DisplayFloatInHex(a5),d0
        ext.w   d0
        systrap CtlSetValue(a0.l,d0.w)

        systrap FrmGetObjectIndex(a4.l, #kidcUnsigned.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        move.b  UnsignedResults(a5),d0
        ext.w   d0
        systrap CtlSetValue(a0.l,d0.w)

        systrap FrmGetObjectIndex(a4.l, #kidcSymbolCase.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        move.b  SymbolCase(a5),d0
        ext.w   d0
        systrap CtlSetValue(a0.l,d0.w)

        systrap FrmGetObjectIndex(a4.l, #kidcFPMode.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        cmp.w   #$7fff,CurrentBase(a5)
        bne.s   OPTInitNoFP
        systrap CtlSetValue(a0.l,#1.w)
        bra.s   OPTInitx
OPTInitNoFP
        systrap CtlSetValue(a0.l,#0.w)
OPTInitx
        systrap FrmGetObjectIndex(a4.l,#kidcBase.w)
        systrap FrmSetFocus(a4.l,d0.w)
	bra	OPTEat
OPTNotOpen
	cmp.w   #ctlSelectEvent,d0
        bne     OPTNotHandled
        cmp.w   #kidcFPMode,EventType.data+ctlSelect.controlID(a0)
        bne.s   OPTCheckButtons
        systrap FrmGetActiveForm()
        move.l  a0,a4
        systrap FrmGetObjectIndex(a4.l, #kidcFPMode.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        systrap CtlGetValue(a0.l)
        move.b  d0,d2
        eor.b   #1,d2                                   ;if FP mode, disable base field else enable
        systrap FrmGetObjectIndex(a4.l, #kidcBase.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        move.l  a0,a3
        systrap FldSetUsable(a3.l,d2.b)
        systrap FldDrawField(a3.l)
        bra     OPTEat
OPTCheckButtons
	cmp.w   #kidbok,EventType.data+ctlSelect.controlID(a0)
	bne	OPTCheckCancel
        systrap FrmGetActiveForm()
        move.l  a0,a4
        move.w  #kidcDegrees,DegreeFlag(a5)             ;default to degrees
        move.w  #kidcNearest,RoundingFlag(a5)           ;default rounding to nearest
	systrap	FrmGetControlGroupSelection(a4.l,#2.b)  ;get rounding selection
        cmp.b   #$ff,d0                                 ;no selection?
        beq.s   OPTNoSelRounding
        ext.w   d0
        systrap FrmGetObjectId(a4.l,d0.w)
        move.w  d0,RoundingFlag(a5)
OPTNoSelRounding
	systrap	FrmGetControlGroupSelection(a4.l,#1.b)  ;get degree/radians
        cmp.b   #$ff,d0                                 ;no selection?
        beq.s   OPTNoSelMode
        ext.w   d0
        systrap FrmGetObjectId(a4.l,d0.w)
        move.w  d0,DegreeFlag(a5)
OPTNoSelMode
        systrap FrmGetObjectIndex(a4.l, #kidcFPMode.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        systrap CtlGetValue(a0.l)
        tst.b   d0
        beq.s   OPTSetNumericBase
        move.w  #$7fff,CurrentBase(a5)                  ;set floating point mode
        bra.s   OPTOK2
OPTSetNumericBase
        systrap FrmGetObjectIndex(a4.l, #kidcBase.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        systrap FldGetTextPtr(a0.l)
        cmpa.l  #0,a0
        beq     OPTError
        systrap StrAToI(a0.l)
        cmp.l   #2,d0
        blt     OPTBadBase
        cmp.l   #16,d0
        bgt     OPTBadBase
        move.w  d0,CurrentBase(a5)
OPTOK2  
        systrap FrmGetObjectIndex(a4.l, #kidcUnsigned.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        systrap CtlGetValue(a0.l)
        move.b  d0,UnsignedResults(a5)

        systrap FrmGetObjectIndex(a4.l, #kidcSymbolCase.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        systrap CtlGetValue(a0.l)
        move.b  d0,SymbolCase(a5)

        systrap FrmGetObjectIndex(a4.l, #kidcFloatInHex.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
        systrap CtlGetValue(a0.l)
        move.b  d0,DisplayFloatInHex(a5)

	systrap	FrmUpdateForm(#kidfMain.w,#frmRedrawUpdateCode.w)
	systrap	FrmReturnToForm(#kidfMain.w)
	bra	OPTEat
OPTCheckCancel
	cmp.w   #kidbcancel,EventType.data+ctlSelect.controlID(a0)
	bne.s	OPTNotHandled
	systrap	FrmUpdateForm(#kidfMain.w,#frmRedrawUpdateCode.w)
	systrap	FrmReturnToForm(#kidfMain.w)
	bra.s   OPTEat
OPTBadBase
        systrap FrmAlert(#kidrBaseError.w)
OPTError
	systrap SndPlaySystemSound(#sndError.b)	
OPTEat  move.b	#1,d0
	bra.s	OPTDone
OPTNotHandled
	clr.b	d0
OPTDone movem.l	(a7)+,a3-a4/d2
endproc


proc AsciiHandleEvent(pevt.l)
local pASCbuf.l
local ASCItem.w
local ASCTempBuf.20
beginproc
	movem.l	a3-a4/d2,-(a7)
        movea.l pevt(a6),a0				;a0 = pevt
        move.w  EventType.eType(a0),d0
	cmp.w   #frmOpenEvent,d0
        bne	ASCNotOpen
	cmp.w	#kidfAscii,EventType.data+frmOpen.formID(a0)
	bne	ASCNotHandled
	systrap	MemPtrNew(#512.l)	                ;128*(4 byte pointers)  for list
	cmpa.l  #0,a0
        beq     ASCReturn
        move.l	a0,ASCListCharItem(a5)                  ;save all allocations in globals for free
	move.l	a0,a4
	lea.l	asc(a5),a3
ascloop tst.b	(a3)			;               ;create list of characters to display
	beq.s	ascloopx
	move.l	a3,(a4)+
	systrap	StrLen(a3.l)
	lea.l	1(a3,d0),a3
	bra.s	ascloop
ascloopx
        systrap FrmGetActiveForm()
        move.l  a0,a3
        systrap FrmGetObjectIndex(a3.l, #kidcListCharacter.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
	systrap	LstSetListChoices(a0.l,ASCListCharItem(a5).l,#128.w) ;populate list

	systrap	MemPtrNew(#512.l)	                ;128*(4 byte pointers) for list
	cmpa.l  #0,a0
        beq     ASCReturn
	move.l	a0,ASCListDecItem(a5)                   ;save for freee
	move.l	a0,a4

	systrap	MemPtrNew(#512.l)	                ;get buffer for data
	cmpa.l  #0,a0
        beq     ASCReturn
	move.l	a0,ASCListDecData(a5)	                ;save for free
	move.l	a0,pASCbuf(a6)
	clr.l	d2              
ascloop2
	movea.l	pASCbuf(a6),a3
	move.l	a3,(a4)+
	systrap	StrIToA(a3.l,d2.l)	                ;generate list of decimals
	systrap	StrLen(a3.l)
	lea.l	1(a3,d0),a3
	move.l	a3,pASCbuf(a6)
	addq.l	#1,d2
	cmp.w	#128,d2
	blt.s	ascloop2

        systrap FrmGetActiveForm()
        move.l  a0,a3
        systrap FrmGetObjectIndex(a3.l, #kidcListDecimal.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
	systrap	LstSetListChoices(a0.l,ASCListDecItem(a5).l,#128.w)

	systrap	MemPtrNew(#512.l)	                ;128*(4 byte pointers) for list
	cmpa.l  #0,a0
        beq     ASCReturn
	move.l	a0,ASCListHexItem(a5)
	systrap	MemPtrNew(#512.l)	                ;get another buffer
	cmpa.l  #0,a0
        beq     ASCReturn
	move.l	a0,ASCListHexData(a5)	                ;for data

	move.l	a0,pASCbuf(a6)
	move.l	ASCListHexItem(a5),a4
	clr.l	d2
ascloop3                                                ;generate list of hex numbers
	call	OutputConversion(d2.l,#16.l,&ASCTempBuf(a6),#20.l)
	systrap	StrLen(a3.l)
	movea.l	pASCbuf(a6),a0
	move.l	a0,(a4)+
	systrap	StrCopy(a0.l,a3.l)
	systrap	StrLen(a3.l)
	ext.l	d0
	add.l	d0,pASCbuf(a6)
	addq.l	#1,pASCbuf(a6)
	addq.l	#1,d2
	cmp.w	#128,d2
	blt.s   ascloop3

        systrap FrmGetActiveForm()
        move.l  a0,a3
        systrap FrmGetObjectIndex(a3.l, #kidcListHex.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
	systrap	LstSetListChoices(a0.l,ASCListHexItem(a5).l,#128.w)
	
        systrap FrmDrawForm(a3.l)
        bra     ASCEat
ASCNotOpen
        cmp.w   #lstSelectEvent,d0
        bne     ASCNotListSelect
	move.l  a0,a4
        systrap FrmGetActiveForm()
        move.l  a0,a3
        systrap FrmGetObjectIndex(a3.l, #kidcListDecimal.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
	systrap LstSetSelection(a0.l,EventType.data+lstSelect.selection(a4).w)

        systrap FrmGetObjectIndex(a3.l, #kidcListHex.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
	systrap LstSetSelection(a0.l,EventType.data+lstSelect.selection(a4).w)

        systrap FrmGetObjectIndex(a3.l, #kidcListCharacter.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
	systrap LstSetSelection(a0.l,EventType.data+lstSelect.selection(a4).w)
        bra     ASCEat
ASCNotListSelect
        cmp.w   #ctlSelectEvent,d0
        bne.s   ASCNotCtlSelect
	cmp.w   #kidbok,EventType.data+ctlSelect.controlID(a0)
        bne     ASCNotHandled     
        systrap MemPtrFree(ASCListDecItem(a5).l)
        systrap MemPtrFree(ASCListDecData(a5).l)
        systrap MemPtrFree(ASCListHexItem(a5).l)
        systrap MemPtrFree(ASCListHexData(a5).l)
        systrap MemPtrFree(ASCListCharItem(a5).l)
ASCReturn
	systrap	FrmUpdateForm(#kidfMain.w,#frmRedrawUpdateCode.w)
	systrap	FrmReturnToForm(#kidfMain.w)
        bra     ASCNotHandled
ASCNotCtlSelect
	cmp.w	#keyDownEvent,d0
	bne	ASCNotHandled
	move.w	EventType.data+keyDown.chr(a0),d0
        move.w  #-10,ASCItem(a6)
        cmp.w   #pageUpChr,EventType.data+keyDown.chr(a0) 
        beq     ASCPageUp                                  
        cmp.w   #pageDownChr,EventType.data+keyDown.chr(a0)
        bne     ASCNotHandled
        move.w  #10,ASCItem(a6)
ASCPageUp
        systrap FrmGetActiveForm()
        move.l  a0,a3
        systrap FrmGetObjectIndex(a3.l, #kidcListDecimal.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
        move.l  a0,a4
        systrap LstGetSelection(a4.l)
        cmp.w   #-1,d0                                  ;no selection?
        beq.s   ASCEat                                  ;ignore
        add.w   ASCItem(a6),d0                          ;page
        cmp.w   #0,d0                                   ;check if
        bge.s   ASCLowerOK                              ; less then zero
        clr.w   d0
ASCLowerOK
        cmp.w   #127,d0                                 ;check if
        ble.s   ASCUpperOK                              ; over limit
        move.w  #127,d0
ASCUpperOK
        move.w  d0,ASCItem(a6)
        systrap LstSetSelection(a4.l,d0.w)
        systrap FrmGetObjectIndex(a3.l, #kidcListHex.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
        systrap LstSetSelection(a0.l,ASCItem(a6).w)
        systrap FrmGetObjectIndex(a3.l, #kidcListCharacter.w)
        systrap FrmGetObjectPtr(a3.l,d0.w)
        systrap LstSetSelection(a0.l,ASCItem(a6).w)
ASCEat  move.b	#1,d0
	bra.s	ASCDone
ASCNotHandled
	clr.b	d0
ASCDone movem.l	(a7)+,a3-a4/d2
endproc


proc MainFormHandleEvent(pevt.l)
local MFHTemp.l
local rect.RectangleType
local MFHRecIdx.w
beginproc
        movem.l a3-a4/d2,-(a7)             		;save regs
        movea.l pevt(a6),a0				;a0 = pevt
	move.w  EventType.eType(a0),d0
        cmp.w   #penDownEvent,d0
        beq     MainPenDown
        cmp.w   #penUpEvent,d0
        beq     MainPenUp
        cmp.w   #penMoveEvent,d0
        beq     MainPenMove
	cmp.w	#frmUpdateEvent,d0
	bne	NotUpdate
	cmp.w	#kidfMain,EventType.data+frmUpdate.formID(a0)
	bne	MFHNotHandled
	systrap	FrmGetActiveForm()
	move.l	a0,a3
	call	RefreshFromKeyTab(a3.l)			;set button labels
        systrap FrmGetObjectIndex(a3.l, #kidbpageselect.w) ;set direction key
        systrap FrmGetObjectPtr(a3.l,d0.w)
	systrap	CtlSetLabel(a0.l,&LeftRight(a5))
	move.w	#5,rect.topLeft.x(a6)
	move.w	#5,rect.topLeft.y(a6)
	move.w	#148,rect.extent.x(a6)
	move.w	#25,rect.extent.y(a6)
	systrap	WinDrawRectangleFrame(#5.w,&rect(a6))	;Draw the frame around the display
        
SetBasePushbutton
	systrap	FrmGetControlGroupSelection(a3.l,#1.b)	;get current selection 
        cmp.b   #$ff,d0                                 ;any selected?
        beq.s   SBPNone
        ext.w   d0                                      ;byte->word
	systrap	FrmGetObjectPtr(a3.l,d0.w)		;get object pointer
	systrap	CtlSetValue(a0.l,#0.w)			;reset button
SBPNone cmp.w   #10,CurrentBase(a5)
        bne.s   UDF2
	systrap	FrmSetControlGroupSelection(a3.l,#1.b,#10.w)
	bra	MFHDisp
UDF2	cmp.w	#2,CurrentBase(a5)
	bne.s	UDF8
	systrap	FrmSetControlGroupSelection(a3.l,#1.b,#2.w)
	bra	MFHDisp
UDF8	cmp.w	#8,CurrentBase(a5)
	bne.s	UDF16
	systrap	FrmSetControlGroupSelection(a3.l,#1.b,#8.w) 
	bra	MFHDisp
UDF16	cmp.w	#16,CurrentBase(a5)
	bne	MFHDisp
	systrap	FrmSetControlGroupSelection(a3.l,#1.b,#16.w) 
	bra	MFHDisp

MainPenDown
        cmp.w   #25,EventType.screenY(a0)
        blt     MFHNotHandled
        cmp.w   #30,EventType.screenY(a0)
        bgt     MFHNotHandled
        move.w  EventType.screenX(a0),ScrollPos(a5)
        move.b  #1,ScrollCapture(a5)
        bra     MFHNotHandled

MainPenMove
        tst.b   ScrollCapture(a5)
        beq     MFHNotHandled
        cmp.w	#14,EventType.screenX(a0)
        ble     MFHNotHandled
        cmp.w   #135,EventType.screenX(a0)
        bge     MFHNotHandled
        clr.l   d1                                      ;clear for divide
        move.w  ScrollPos(a5),d1                        ;get old scroll position
        divs.w  #9,d1                                   ;/9 for width of each digit
        muls.w  #9,d1                                   ;*9 "click" in position
        move.w  EventType.screenX(a0),ScrollPos(a5)     ;save new scroll position
        clr.l   d0                                      ;clear for divide
        move.w  ScrollPos(a5),d0                        ;get new scroll position
        divs.w  #9,d0                                   ;/9 for width of each digit
        muls.w  #9,d0                                   ;*9 "clicks" in position
        cmp.w   d0,d1                                   ;"position" changed?
        bne     MFHDisp                                 ;yep, redisplay everything
        move.w  d1,rect.topLeft.x(a6)                   
	move.w	#26,rect.topLeft.y(a6)                  
        move.w  #135,d0
        sub.w   d1,d0
	move.w	d0,rect.extent.x(a6)
	move.w	#3,rect.extent.y(a6)
	systrap	WinEraseRectangle(&rect(a6),#0.w)       ;clear old scrollbar area
	move.w	ScrollPos(a5),d0                        ;get scroll position
        ext.l   d0
        divu.w  #9,d0                                   ;/9
        muls.w  #9,d0                                   ;*9 causes "click" in position
        addq.w  #5,d0                                   ;1st digit starts here
        move.w  d0,rect.topLeft.x(a6)
	move.w	#26,rect.topLeft.y(a6)
	move.w	#8,rect.extent.x(a6)
	move.w	#3,rect.extent.y(a6)
        systrap WinDrawRectangle(&rect(a6),#0.w)        ;draw the tab indicating the current position
        systrap WinDrawLine(rect.topLeft.x(a6).w,#27.w,#135.w,#27.w) ;draw a line all the way to the right
        bra     MFHNotHandled

MainPenUp        
        tst.b   ScrollCapture(a5)
        beq     MFHNotHandled
        cmp.w	#14,EventType.screenX(a0)
        ble     MFHNotHandled
        cmp.w   #135,EventType.screenX(a0)
        bge     MFHNotHandled
        clr.b   ScrollCapture(a5)
        move.w  EventType.screenX(a0),ScrollPos(a5)
        bra     MFHDisp


NotUpdate
	cmp.w   #frmOpenEvent,d0
        bne.s	NotOpen
	cmp.w	#kidfMain,EventType.data+frmOpen.formID(a0)
	bne	MFHNotHandled
        systrap FrmGetActiveForm()
	move.l	a0,a3
        systrap FrmDrawForm(a3.l)
	call	RefreshFromKeyTab(a3.l)			;set button labels
        systrap FrmGetObjectIndex(a3.l, #kidbpageselect.w) ;set direction key
        systrap FrmGetObjectPtr(a3.l,d0.w)
	systrap	CtlSetLabel(a0.l,&LeftRight(a5))
	move.w	#5,rect.topLeft.x(a6)
	move.w	#5,rect.topLeft.y(a6)
	move.w	#148,rect.extent.x(a6)
	move.w	#25,rect.extent.y(a6)
	systrap	WinDrawRectangleFrame(#5.w,&rect(a6))	;Draw the frame around the display
        bra     SetBasePushbutton

NotOpen cmp.w   #menuEvent,d0
        bne     MFH1
        cmp.w   #kidmAscii,EventType.data+menu.itemID(a0)
        bne.s   NotAscii
        systrap FrmPopupForm(#kidfAscii.w)
        bra     MFHEat
NotAscii
        cmp.w   #kidmOptions,EventType.data+menu.itemID(a0)
        bne.s   NotOptions
        systrap FrmPopupForm(#kidfOptions.w)
        bra     MFHEat
NotOptions
	cmp.w	#kidbprogram,EventType.data+menu.itemID(a0)
	bne.s	NotProgram
	systrap	FrmPopupForm(#kidfProgram.w)
	bra	MFHEat
NotProgram
	cmp.w	#kidbpf,EventType.data+menu.itemID(a0)
	bne.s	NotProgramFunctions
	systrap	FrmPopupForm(#kidfSymbolMaint.w)
	bra	MFHEat

NotProgramFunctions	
;	move.l	a0,-(a7)
;	systrap	MenuGetActiveMenu()			;get MenuBarPtr
;	clr.l	d0
;	move.w	MenuBarType.curItem(a0),d0		;current item index
;	movea.l	MenuBarType.menus(a0),a0		;MenuPullDownPtr
;	movea.l	MenuPullDownType.items(a0),a0		;MenuItemType
;	lsl.l	#3,d0					;*8
;	lea.l	(a0,d0),a0				;address of string
;	move.l  MenuItemType.itemStr(a0),pCmdString(a5)
;	move.l	(a7)+,a0
        cmp.w   #kidmAbout,EventType.data+menu.itemID(a0)
        bne.s   NotAbout				;if not about then process as operation
        systrap FrmAlert(#kidrAboutAlert.w)		;display about dialog
        bra     MFHEat

NotAbout
	cmp.w	#kidbcopy,EventType.data+menu.itemID(a0)
	bne.s	NotCopy
	systrap	StrLen(&Op2(a5))
	systrap	ClipboardAddItem(#0.w,&Op2(a5),d0.w)
	bra	MFHEat
NotCopy
	cmp.w	#kidbpaste,EventType.data+menu.itemID(a0)
	bne	OpKey
	systrap	ClipboardGetItem(#0.w,&ClipLen(a5))
	cmpa.l	#0,a0
	beq	MFHEat
	move.l	a0,a3
	systrap	MemHandleLock(a3.l)
        lea     Op2(a5),a1
        move.w  ClipLen(a5),d2
PasteMv move.b  (a0)+,(a1)+
        subq.w  #1,d2
        bne.s   PasteMv
        move.b  #0,(a1)
	systrap	MemHandleUnlock(a3.l)
	bra	NumDisp

MFH1	cmp.w	#ctlEnterEvent,d0
	bne	MFH2
	cmp.w	#kidcbackspace,EventType.data+ctlEnter.controlID(a0)	;BS key right of display?
	bne	MFHNotHandled				;no other EnterEvents to do
Bkspc	tst.b	Op2(a5)					;is the display empty?
	beq	beep
	cmp.w	#$7fff,CurrentBase(a5)			;floating point?
	beq.s	BSFP					;use floating point, else binary
	call	InputConversion(&Op2(a5),#10.w)		;Convert display to binary in d0
	move.w	CurrentBase(a5),d1			;divide by
	ext.l	d1					; current base
	call	LongDivide(d0.l,d1.l)			;  to shift right
	call	UpdateDisplay(d0.l)			;And update display with new value
	bra	BSClick					;Make it audible
BSFP
	systrap	StrLen(&Op2(a5))			;get length of display
	subq.w	#1,d0					;Basckspace by decrementing length
	cmp.b	#'.',Op2(a5,d0)				;are we at a dot?
	bne.s	BSNDot					;no, continue
	clr.w	DecimalFlag(a5)				;otherwise, clear decimal pt flag
BSNDot	clr.b	Op2(a5,d0)				;set end of string
        call    FPIAsciiToFloat(&fpnTemp(a5),&Op2(a5))  ;convert ascii to float
	call	UpdateDisplay(&fpnTemp(a5))		;Update display with new value
BSClick
	clr.w	LastWasOp(a5)				;set last input to num
	systrap SndPlaySystemSound(#sndClick.b)		;make a clicking noise
	bra	MFHEat					;end of event

MFH2	cmpi.w	#keyDownEvent,d0			;user wrote in the giraffe area?
	bne	MFH3					;no, then check next event type
	move.w	EventType.data+keyDown.chr(a0),d0	;get key
;---------------------------------------------------------------------------------
;Modification for 2.01 release, PageDown/PageUp buttons on the Pilot cycle thru  *
;the basees Float->Dec->Hex->Bin->Oct->back to float.                            *
;Thanks to Odd Gripenstam for suggesting this great idea.                        *
;--------------------------------------------------------------------------------*
        cmp.w   #pageUpChr,EventType.data+keyDown.chr(a0)       ;Page up and
        beq     DoPageUp                                        ; page down cycle
        cmp.w   #pageDownChr,EventType.data+keyDown.chr(a0)     ;  thru base pushbuttons
        bne     NotHardKey
DoPageDown
	systrap	FrmGetActiveForm()                      ;SetBasePushbutton
	move.l	a0,a3                                   ; expects formptr in a3
        cmp.w   #$7fff,CurrentBase(a5)                  ;is base floating?
        bne     DPD1                                    ;no, try next
        move.w  #10,CurrentBase(a5)                     ;from float to dec
        bra     SetBasePushbutton       
DPD1    cmp.w   #10,CurrentBase(a5)                     ;is base dec?
        bne.s   DPD2
        move.w  #16,CurrentBase(a5)                     ;from dec to hex
        bra     SetBasePushbutton
DPD2    cmp.w   #16,CurrentBase(a5)                     ;is base hex?
        bne.s   DPD3
        move.w  #2,CurrentBase(a5)                      ;from hex to bin
        bra     SetBasePushbutton
DPD3    cmp.w   #2,CurrentBase(a5)                      ;is base bin?
        bne.s   DPD4
        move.w  #8,CurrentBase(a5)                      ;from bin to oct
        bra     SetBasePushbutton
DPD4    cmp.w   #8,CurrentBase(a5)                      ;is base oct?
        bne     SetDec
        move.w  #$7fff,CurrentBase(a5)                  ;from oct to float
        bra     SetBasePushbutton
DoPageUp
	systrap	FrmGetActiveForm()                      ;SetBasePushbutton
	move.l	a0,a3                                   ;expects formptr in a3
        cmp.w   #$7fff,CurrentBase(a5)                  ;is base floating?
        bne.s   DPU1
        move.w  #8,CurrentBase(a5)                      ;from float to oct
        bra     SetBasePushbutton
DPU1    cmp.w   #8,CurrentBase(a5)                      ;is base oct?
        bne.s   DPU2
        move.w  #2,CurrentBase(a5)                      ;from oct to bin
        bra     SetBasePushbutton
DPU2    cmp.w   #2,CurrentBase(a5)                      ;is base bin?
        bne.s   DPU3
        move.w  #16,CurrentBase(a5)                     ;from bin to hex
        bra     SetBasePushbutton
DPU3    cmp.w   #16,CurrentBase(a5)                     ;is base hex?
        bne.s   DPU4
        move.w  #10,CurrentBase(a5)                     ;from hex to dec
        bra     SetBasePushbutton
DPU4    cmp.w   #10,CurrentBase(a5)                     ;is base dec?
        bne     SetDec
        move.w  #$7fff,CurrentBase(a5)                  ;from dec to float
        bra     SetBasePushbutton
SetDec  move.w  #10,CurrentBase(a5)                     ;default if none of the
        bra     SetBasePushbutton                       ; above...
NotHardKey
	cmpi.w	#08,d0					;see if backspace?
	beq	Bkspc					;yes, it's backspace
	cmpi.w	#'.',d0					;a dot?
	beq	Dot					;yes, then process it
	cmpi.w	#'0',d0					;0-9?
	blt	beep
	cmpi.w	#'9',d0		
	ble	SimKey
	cmpi.w	#'A',d0					;A-F?
	blt	beep
	cmpi.w	#'F',d0
	ble	SimKey
	cmpi.w	#'a',d0
	blt	beep
	cmpi.w	#'f',d0
	bgt	beep
	and.w	#$00df,d0				;Convert lowercase a-f to A-F
	bra	SimKey					;simulate the button

MFH3	cmp.w   #ctlSelectEvent,d0			;select events for button presses?
        bne     MFHNotHandled
	cmp.w	#kidcSymbolTable,EventType.data+ctlSelect.controlID(a0) ;Mr hack
	beq	MFHNotHandled
OpKey	cmp.w   #kidchex,EventType.data+ctlSelect.controlID(a0) ;check if Dec, Hex, Bin, or Oct
	bgt.s 	NotBase
	;resources are 2, 8, 10, or 16
	move.w	EventType.data+ctlSelect.controlID(a0),CurrentBase(a5) ;set currentbase
	cmp.w	#$7fff,CurrentBase(a5)			;use floating point?
	beq.s	BaseFP                                  ;equal, then convert floating point
	call	InputConversion(&Op2(a5),#10.w)	        ;Convert to binary in d0.l
	call	UpdateDisplay(d0.l)			;update display with new value
	bra	MFHEat					;event complete
BaseFP  
        call    FPIAsciiToFloat(&fpnTemp(a5),&Op2(a5))  ;convert ascii to float
	call	UpdateDisplay(&fpnTemp(a5))		;Update display with new value
	bra	MFHEat					;event complete

NotBase	cmp.w   #kidbdot,EventType.data+ctlSelect.controlID(a0) ;Dot pressed?
	bne.s 	NoDot					;no, try next key
Dot	cmp.w	#$7fff,CurrentBase(a5)			;are we in floating point mode?
	bne.s	beep					;dot is invalid key when not in dec mode
	tst.w	LastWasOp(a5)				;check if last thing was operation?
	beq.s	DotCont					;no, then continue
	clr.b	Op2(a5)					;else clear display first
	bra.s	DotSet					;and go set decimalflag
DotCont	tst.w	DecimalFlag(a5)				;already dot?
	beq.s	DotSet					;no, then set flag
beep							;user pressed dot more than once
	systrap SndPlaySystemSound(#sndError.b)		; in a single numeric input
	bra	MFHEat

DotSet	move.w	#1,DecimalFlag(a5)			;decimal encountered flag
	move.w	EventType.data+ctlSelect.controlID(a0),d0 ;move buttonpress event to d0
	bra.s	NumInp					;continue, this is numeric input

NoDot  	move.w	EventType.data+ctlSelect.controlID(a0),d0 ;get key
	cmp.w   #kidb0,d0				;Is it 0-9, A-F?
	blt	NoDigit
        cmp.w   #kidb9,d0
	ble.s 	SimKey
	cmp.w	#kidbA,d0
	blt	NoDigit
	cmp.w	#kidbF,d0
	bgt	NoDigit
		
SimKey	move.w	d0,d1					;move to d1
	sub.w	#$30,d1					;Resources are Ascii values
	cmp.w	#$9,d1					;if not num
	ble.s	DgtNum					;  then A-F
	subq.w  #7,d1					;     sub 7 to make $00-$0F
DgtNum	cmp.w	CurrentBase(a5),d1			;compare key to base
	bge.s	beep					;key must be less than selected base
	tst.w	LastWasOp(a5)				;was last input operation?
	beq.s	NumInp					;no, then continue
	clr.b	Op2(a5)					;else clear display
	clr.w	DecimalFlag(a5)				; and decimal flag
NumInp	move.b	d0,instr(a5)				;move to temp buffer
	clr.b   instr+1(a5)				;null terminate string
	clr.w	LastWasOp(a5)				;set last input to num
        systrap StrLen(&Op2(a5))
        cmp.w   #32,d0                                  ;max input?
        bge     beep
	cmp.w	#$7fff,CurrentBase(a5)                               
	beq.s	InpConvFP
	call	InputConversion(&Op2(a5),#10.w)		;Convert to binary in d0.l
	clr.l	d1
	move.w	CurrentBase(a5),d1
	call	OutputConversion(d0.l,d1.l,&TStr(a5),#40.l)
	systrap	StrCopy(&TStr(a5),a3.l)
	systrap	StrCat(&TStr(a5),&instr(a5))		;concatinate to display
	call	InputConversion(&TStr(a5),CurrentBase(a5).w)
	call	UpdateDisplay(d0.l)
	bra	MFHEat
InpConvFP
	systrap	StrCat(&Op2(a5),&instr(a5))
NumDisp	cmp.w	#$7fff,CurrentBase(a5)			;use floating point?
	beq.s	NumFP
	call	InputConversion(&Op2(a5),CurrentBase(a5).w) ;Convert to binary in d0.l
	call	UpdateDisplay(d0.l)			;Update display with new value
	bra	MFHEat					;event complete
NumFP   
        call    FPIAsciiToFloat(&fpnTemp(a5),&Op2(a5))  ;convert ascii to float
	call	UpdateDisplay(&fpnTemp(a5))		;Update display with new value
	bra	MFHEat					;event complete
	
NoDigit	cmp.w	#kidbpageselect,EventType.data+ctlSelect.controlID(a0)
	bne	Oper
	systrap	FrmGetActiveForm()
	move.l	a0,a4
        systrap FrmGetObjectIndex(a4.l, #kidbpageselect.w)
        systrap FrmGetObjectPtr(a4.l,d0.w)
	eor.b	#$07,LeftRight(a5)
	systrap	CtlSetLabel(a0.l,&LeftRight(a5))
	eor.w	#1,KeyPage(a5)
	call	RefreshFromKeyTab(a4.l)
	bra	MFHEat

Oper	
        call    AdjustForPage(EventType.data+ctlSelect.controlID(a0).w)
	call	FindKeyTabSymbol(d0.w)
	cmpa.l	#0,a0					;is it there?
	beq	Oper2					;no?
	call    GetSymbol(a0.l)                         ;get symbol record
        move.w  d0,MFHRecIdx(a6)                        ;save record number
        call    GetSymbolFlags(d0.w)
	and.l	#SYMIMMEDIATE,d0			;now or later?	
	beq.s	Oper2					;not immediate
        tst.w   LastWasOp(a5)                           ;if last was operation
        beq.s   Oper1
       	systrap	StrCopy(&Op1(a5),&Op2(a5))              ;then treat
        clr.w   LastWasOp(a5)                           ; this immediate
	clr.w	DecimalFlag(a5)				;  as num input
Oper1           
	clr.b	ErrorFlag(a5)			        ;set error to false
	call	DoPgm(MFHRecIdx(a6).w,#0.w)             ;evaluate
        move.l  d0,TempPop(a5)                          ;save results
        move.l  d1,TempPop+4(a5)                                   
        call    GetSymbolFlags(MFHRecIdx(a6).w)         ;get symbol flags
	and.l	#SYMNORESULT,d0
	bne	MFHDisp					;no result
	cmp.w	#$7fff,CurrentBase(a5)
	bne.s	OperBin
        clr.w   DecimalFlag(a5)
	call	UpdateDisplay(&TempPop(a5))
	bra	MFHEat
OperBin	
	call	UpdateDisplay(TempPop(a5).l)
	bra	MFHEat

Oper2	tst.w	LastWasOp(a5)				;LastWasOp was num?
	bne.s	LNotNum
	addq.w	#1,NumOps(a5)				;increments number of args
LNotNum	cmp.w	#1,NumOps(a5)				;num args = 1?
	bne.s	ChkTwo					;no, then continue
	systrap	StrCopy(&Op1(a5),&Op2(a5))
	bra	MFHDone					;done, go update display

ChkTwo	cmp.w	#2,NumOps(a5)				;two operands?
	bne.s	MFHOpX

Oper3	cmp.w   #kidbequal,LastOp(a5)                   ;equal is a pseudo-op
        beq.s   Oper3x                                          
	call	FindKeyTabSymbol(LastOp(a5).w)          ;get KEYTAB assoc with op
	cmpa.l	#0,a0					;is it there?
	beq	MFHEat					;no? just ignore
        call    GetSymbol(a0.l)                         ;get symbol assoc with key
        move.w  d0,MFHRecIdx(a6)                        ;save rec num
	clr.b	ErrorFlag(a5)			        ;set error to false
	call	DoPgm(MFHRecIdx(a6).w,#0.w)             ;evaluate
        move.l  d0,TempPop(a5)                          ;save results
        move.l  d1,TempPop+4(a5)                                   
	cmp.w	#$7fff,CurrentBase(a5)
	bne.s	Oper2Bin
        clr.w   DecimalFlag(a5)
	call	UpdateDisplay(&TempPop(a5))
	bra.s	Oper3x
Oper2Bin	
	call	UpdateDisplay(TempPop(a5).l)
Oper3x
	systrap	StrCopy(&Op1(a5),&Op2(a5))
MFHOpX  move.w	#1,NumOps(a5)	
MFHDone	movea.l pevt(a6),a0				;a0 = pevt
        call    AdjustForPage(EventType.data+ctlSelect.controlID(a0).w)
	move.w	d0,LastOp(a5)				;save in last operation field
	move.w	#1,LastWasOp(a5)			;set to last was operation

MFHDisp	cmp.w	#$7fff,CurrentBase(a5)
	bne.s	MFHBin
        call    FPIAsciiToFloat(&fpnTemp(a5),&Op2(a5))  ;convert ascii to float
	call	UpdateDisplay(&fpnTemp(a5))
	bra.s	MFHEat
MFHBin
	call	InputConversion(&Op2(a5),#10.w)
	call	UpdateDisplay(d0.l)

MFHEat	moveq.l	#1,d0					;set d0 to say we took event
	bra.s	MFHReturn				;and return
MFHNotHandled	
        clr.b   d0					;set d0 to say event not handled
MFHReturn
        movem.l (a7)+,a3-a4/d2				;restore regs
endproc


;
; Execute program
;
; Input:  recidx is record index of symbol to execute
; Output: if binary mode then d0 contains the result of the expression
;         if floating point mode, then d0/d1 contains floating point result
;
proc DoPgm(recidx.w,ignoreflag.w)
local PgmRet.8
local TempExpr.PGM
beginproc
        move.l  d2,-(a7)
        cmp.b   #2,romVersion(a5)
        blt.s   PgmV1
        clr.l   d0
        move.w  RoundingFlag(a5),d0
        sub.w   #kidcNearest,d0
        move.l  d0,-(a7)
        moveq.l #sysFloatEm_fp_round,d2                 ;set rounding mode
	trap	#15					
	dc.w	sysTrapFlpEmDispatch		
	addq.l	#4,a7
PgmV1
	systrap	MemHandleNew(#STARTINGSTACK.l)	                ;Allocate a stack for this pgm
	cmpa.l	#0,a0
	bne.s	PgmStackOK
        systrap FrmAlert(#ErrorMem.w)
        move.b  #true,ErrorFlag(a5)                     ;set error flag
	bra	DoPgmx
PgmStackOK
        move.l  a0,PGM.stack+TempExpr(a6)                ;set stack handle
        call    GetSymbolPgm(recidx(a6).w)              ;get pgm pointer
	move.l	a0,PGM.pgmtext+TempExpr(a6)             ;set in PGM
        clr.w	PGM.tokidx+TempExpr(a6)		        ;reset stack index
	clr.w	PGM.pgmidx+TempExpr(a6)	                ;clear index
	clr.b	PGM.returnFlag+TempExpr(a6)             ;clear return flag
	clr.b	PGM.AtEof+TempExpr(a6)		        ;clear eof flag
        move.w  ignoreflag(a6),d0
        move.w  d0,PGM.ignore+TempExpr(a6)              ;set ignore flag to arg
	call	stmt(&TempExpr(a6))		        ;interpret statement
        systrap MemPtrFree(PGM.pgmtext+TempExpr(a6).l)  ;free storage
        call    GetSymbolFlags(recidx(a6).w)            ;get symbol flags
	and.b	#SYMNORESULT,d0			        ;need a result
	bne.s	DoPgmx				        ;no, just exit
        tst.b   PGM.returnFlag+TempExpr(a6)             ;did the pgm explicitly return something?
        beq.s   PgmNoRet
        move.l  PGM.returnVal+TempExpr(a6),d0           ;load
        move.l  PGM.returnVal+4+TempExpr(a6),d1         ; return value
        bra.s   DoPgmPopOK                              
PgmNoRet
	call	popNum(&TempExpr(a6))           	;pop entry from stack
	tst.b	d2				        ;any result?
	beq.s	DoPgmPopOK
	call	Error(&TempExpr(a6),&NoResult(a5))
	bra.s	DoPgmx
DoPgmPopOK
        tst.b   PGM.AtEof+TempExpr(a6)                  ;make sure entire expression
        bne.s   DoPgmOK                                 ; was processed
	call	Error(&TempExpr(a6),&Incomplete(a5))    ;else, incomplete.
	move.b	#true,ErrorFlag(a5)
        bra.s   DoPgmx
DoPgmOK
	move.l  d0,PgmRet(a6)                           ;save our result 
        move.l  d1,PgmRet+4(a6)
DoPgmFree
        systrap MemHandleFree(PGM.stack+TempExpr(a6).l)  ;free stack
        move.l  PgmRet(a6),d0
        move.l  PgmRet+4(a6),d1
DoPgmx
        move.l  (a7)+,d2                                ;restore regs used
endproc

;+---------------------------------------------+
;| Statement syntax                            |
;|                                             |
;| <stmt>:                                     | 
;|  | for(<expr>;<relop>;<expr>) <stmt>        |
;|  | do <stmt> while(<relop>);                |
;|  | while(<relop>) <stmt>                    |
;|  | if(<relop>) <stmt> [else] <stmt>         |
;|  | { <stmt> [<stmt>] ... }                  |
;|  | <expr>;                                  |
;|                                             |
;| <relop>:                                    |
;|  | <expr> <= <expr>                         |
;|  | <expr> >= <expr>                         |
;|  | <expr> <  <expr>                         |
;|  | <expr> >  <expr>                         |
;|  | <expr> == <expr>                         |
;|  | <expr> != <expr>                         |
;|                                             |
;+---------------------------------------------+
proc stmt(pExpr.l)
beginproc
        call    matchString(pExpr(a6).l,&tokwhile(a5))  ;check for 'while'
        tst.b   d0
        beq.s   NotWhile
        call    DoWhile(pExpr(a6).l)                    ;do while stmt
        bra     Stmtx
NotWhile
        call    matchString(pExpr(a6).l,&tokfor(a5))    ;check for 'for'
        tst.b   d0
        beq.s   NotFor
        call    DoFor(pExpr(a6).l)                      ;do for stmt
        bra     Stmtx
NotFor
        call    matchString(pExpr(a6).l,&tokif(a5))     ;check for 'if'
        tst.b   d0
        beq.s   NotIf
        call    DoIf(pExpr(a6).l)                       ;do if stmt
        bra     Stmtx
NotIf
        call    matchString(pExpr(a6).l,&tokdo(a5))     ;check for 'do'
        tst.b   d0
        beq.s   NotDo
        call    DoDo(pExpr(a6).l)                       ;do do (gak!) stmt
        bra     Stmtx
NotDo   move.b  #'{',d0                                 ;left curly brace?
        call    match(pExpr(a6).l,d0.b)                 ; is block code
        tst.b   d0                      
        beq.s   NotBlock
DoBlock movea.l pExpr(a6),a0
        tst.b   PGM.AtEof(a0)                           ;eof?
        beq.s   NotEnd
        call    Error(pExpr(a6).l,&MissingRCurly(a5))   ;say missing right curly brace
        bra.s   Stmtx                                   ;and done
NotEnd  
        clr.w   PGM.tokidx(a0)                          ;reset stack
        call    stmt(pExpr(a6).l)                       ;do stmts
        move.b  #'}',d0
        call    match(pExpr(a6).l,d0.b)                 ;  until end of block
        beq.s   DoBlock
        bra.s   Stmtx                                   ;done with block

NotBlock
        call    level0(pExpr(a6).l)                     ;do expression
        call    supr(pExpr(a6).l,#0.l)
        movea.l pExpr(a6),a0
        tst.b   PGM.AtEof(a0)                           ;end of program reached?
        bne.s   Stmtx                                   ;implicit semi-colon or end of stmt
        move.b  #';',d0
        call    match(pExpr(a6).l,d0.b)                 ;check for match on stmt terminator
        tst.b   d0                                      ;is it there?
        bne.s   Stmtx                                   ;yep, continue;
        call    Error(pExpr(a6).l,&ExpectedSemi(a5))    ;say missing semi-colon
Stmtx
endproc

proc DoDo(pExpr.l)
local ddStmtIdx.w
beginproc
        ;stmt() already matched up to the left paren after the token 'do'
        movea.l pExpr(a6),a0
        clr.w   PGM.tokidx(a0)                          ;reset stack
        move.w  PGM.pgmidx(a0),ddStmtIdx(a6)            ;save the position of stmt
DDLoop  movea.l pExpr(a6),a0
        move.w  ddStmtIdx(a6),PGM.pgmidx(a0)            ;reset statment starting point
        clr.b   PGM.AtEof(a0)                           ;clear eof flag
        clr.w   PGM.tokidx(a0)                          ;clear stack
        call    stmt(pExpr(a6).l)                       ;do statement
        call    matchString(pExpr(a6).l,&tokwhile(a5))  ;must match while statement
        tst.b   d0
        bne.s   DDWhile                                 ;continue with while relop
        call    Error(pExpr(a6).l,&ExpectedWhile(a5))   ;'Expected while after do'
        bra.s   DoDox                                   ;done
DDWhile move.b  #'(',d0                                 ;now need a left paren
        call    match(pExpr(a6).l,d0.b)                 
        tst.b   d0
        bne.s   DD1
        call    Error(pExpr(a6).l,&MissingLParen(a5))   ;"Missing left parenthisis"
        bra.s   DoDox
DD1
        call    Relop(pExpr(a6).l)        
        move.l  d0,d2                                   ;result in d2
        move.b  #')',d0                                 ;now need right paren
        call    match(pExpr(a6).l,d0.b)                 
        tst.b   d0
        bne.s   DD2
        call    Error(pExpr(a6).l,&MissingRParen(a5))   ;"Missing right parenthisis"
        bra.s   DoDox
DD2     tst.b   d2                                      ;=1 means relop is true
        bne     DDLoop
        move.b  #';',d0                                 ;make sure that
        call    match(pExpr(a6).l,d0.b)                 ; it's terminated by ';'
        tst.b   d0      
        bne.s   DoDox                                     
        call    Error(pExpr(a6).l,&ExpectedSemi(a5))    ;"Expected semi-colon"
DoDox
endproc


proc DoWhile(pExpr.l)
local dwRelopIdx.w
local dwStmtIdx.w
beginproc
        ;stmt() already matched up to the left paren after the token 'while'
        movea.l pExpr(a6),a0
        clr.w   PGM.tokidx(a0)                          ;reset stack
        move.b  #'(',d0                                 ;now need a left paren
        call    match(pExpr(a6).l,d0.b)                 
        tst.b   d0
        bne.s   DW1
        call    Error(pExpr(a6).l,&MissingLParen(a5))   ;"Missing left parenthisis"
        bra     DWx
DW1     movea.l pExpr(a6),a0                            ;save position of the beginning 
        move.w  PGM.pgmidx(a0),dwRelopIdx(a6)           ;of the relop expression in while(:)
        call    Relop(pExpr(a6).l)                      ;do relop
        move.b  d0,d2
        move.b  #')',d0                                 ;now need right paren
        call    match(pExpr(a6).l,d0.b)                 
        tst.b   d0
        bne.s   DW2
        call    Error(pExpr(a6).l,&MissingRParen(a5))   ;"Missing right parenthisis"
        bra     DWx
DW2     movea.l pExpr(a6),a0
        move.w  PGM.pgmidx(a0),dwStmtIdx(a6)            ;save the position of stmt
        move.b  d2,d0
        bra.s   DWTstRelop
DWLoop 
        movea.l pExpr(a6),a0
        move.w  dwRelopIdx(a6),PGM.pgmidx(a0)           ;get position of relop to execute
        clr.b   PGM.AtEof(a0)                           ;clear eof flag
        clr.w   PGM.ignore(a0)                          ;clear ignore
        call    Relop(a0.l)                             ;execute relop
DWTstRelop
        tst.b   d0                                      ;=1 means relop is true.
        beq.s   DWDone                                  ;not true means done.
        tst.b   ErrorFlag(a5)                           ;any errors, then stop too
        bne.s   DWDone
        movea.l pExpr(a6),a0
        move.w  dwStmtIdx(a6),PGM.pgmidx(a0)            ;reset to start of statmement
        tst.w   PGM.ignore(a0)
        bne.s   DWIgnore
        clr.b   PGM.AtEof(a0)                           ;clear eof flag
        clr.w   PGM.tokidx(a0)                          ;reset stack
        call    stmt(pExpr(a6).l)                       ;do stmt
        bra.s   DWLoop
DWDone  movea.l pExpr(a6),a0
        addq.w  #1,PGM.ignore(a0)                       ;set to ignore
        move.w  dwStmtIdx(a6),PGM.pgmidx(a0)            ;reset to start of statement
        clr.b   PGM.AtEof(a0)                           ;make sure not at eof
        call    stmt(pExpr(a6).l)                       ;do stmt as if really executing it
        movea.l pExpr(a6),a0
        subq.w  #1,PGM.ignore(a0)                       ;clear ignore flag
        bra.s   DWx
DWIgnore
        movea.l pExpr(a6),a0
        move.w  dwStmtIdx(a6),PGM.pgmidx(a0)            ;reset to start of statmement
        clr.b   PGM.AtEof(a0)                           ;clear eof flag
        call    stmt(pExpr(a6).l)                       ;call stmt with ignore set
DWx
endproc

proc DoFor(pExpr.l)
local dfTermIdx.w
local dfRelopIdx.w
local dfStmtIdx.w
beginproc
        ;stmt() already matched up to the left paren after the token 'for'
        movea.l pExpr(a6),a0
        clr.w   PGM.tokidx(a0)                          ;reset stack
        move.b  #'(',d0                                 ;now need a left paren
        call    match(pExpr(a6).l,d0.b)                 
        tst.b   d0
        bne.s   DF1
        call    Error(pExpr(a6).l,&MissingLParen(a5))   ;"Missing left parenthisis"
        bra     DFx
DF1     
        call    level0(pExpr(a6).l)                     ;execute initial expression
        move.b  #';',d0                                 ;make sure that
        call    match(pExpr(a6).l,d0.b)                 ; it's terminated by ';'
        tst.b   d0      
        bne.s   DF2                                     
        call    Error(pExpr(a6).l,&ExpectedSemi(a5))    ;"Expected semi-colon"
        bra     DFx
DF2     movea.l pExpr(a6),a0
        move.w  PGM.pgmidx(a0),dfRelopIdx(a6)           ;save index of relop expression
        call    Relop(pExpr(a6).l)                      ;do relop
        move.b  d0,d2                                   ;save result in d2
        move.b  #';',d0                                 ;make sure that
        call    match(pExpr(a6).l,d0.b)                 ; it's terminated by ';'
        tst.b   d0      
        bne.s   DF3                                     
        call    Error(pExpr(a6).l,&ExpectedSemi(a5))    ;"Expected semi-colon"
        bra     DFx
DF3     movea.l pExpr(a6),a0                            ;save position of the beginning 
        move.w  PGM.pgmidx(a0),dfTermIdx(a6)            ;of the terminating expression
        addq.w  #1,PGM.ignore(a0)                       ;set ignore
        call    level0(pExpr(a6).l)                     ;do term expression as if really executing it
        movea.l pExpr(a6),a0
        subq.w  #1,PGM.ignore(a0)                       ;clear ignore flag

        move.b  #')',d0                                 ;now need right paren
        call    match(pExpr(a6).l,d0.b)                 
        tst.b   d0
        bne.s   DF4
        call    Error(pExpr(a6).l,&MissingRParen(a5))   ;"Missing right parenthisis"
        bra     DFx
DF4
        movea.l pExpr(a6),a0
        move.w  PGM.pgmidx(a0),dfStmtIdx(a6)            ;save index of start of statement
        bra.s   DFCont
DFLoop        
        movea.l pExpr(a6),a0
        move.w  dfStmtIdx(a6),PGM.pgmidx(a0)            ;reset to start of stmt
        clr.w   PGM.tokidx(a0)                          ;clear stack
DFCont
        clr.b   PGM.AtEof(a0)                           ;reset eof flag
        clr.w   PGM.tokidx(a0)                          ;reset stack

        tst.b   d2                                      ;=1 means relop is true.
        beq.s   DFDone                                  ;not true means done.

        tst.b   ErrorFlag(a5)                           ;any errors, then stop too
        bne.s   DFDone

        tst.w   PGM.ignore(a0)
        bne.s   DFIgnore

        call    stmt(pExpr(a6).l)                       ;do stmt

        movea.l pExpr(a6),a0
        move.w  dfTermIdx(a6),PGM.pgmidx(a0)            ;get position of terminating expression
        clr.b   PGM.AtEof(a0)                           ;clear eof flag
        clr.w   PGM.ignore(a0)                          ;clear ignore
        call    level0(a0.l)                            ;execute terminating expression

        movea.l pExpr(a6),a0
        move.w  dfRelopIdx(a6),PGM.pgmidx(a0)           ;get position of relop to execute
        clr.b   PGM.AtEof(a0)                           ;clear eof flag
        clr.w   PGM.ignore(a0)                          ;clear ignore
        call    Relop(a0.l)                             ;execute relop
        move.b  d0,d2                                   ;put result in d2
        bra.s   DFLoop

DFDone  
        movea.l pExpr(a6),a0
        move.w  dfStmtIdx(a6),PGM.pgmidx(a0)            ;reset index of start of statement
        addq.w  #1,PGM.ignore(a0)                       ;set to ignore
        clr.b   PGM.AtEof(a0)
        call    stmt(pExpr(a6).l)                       ;do stmt as if really executing it
        movea.l pExpr(a6),a0
        subq.w  #1,PGM.ignore(a0)                       ;clear ignore flag
        bra.s   DFx
DFIgnore
        call    stmt(pExpr(a6).l)                       ;call stmt with ignore set
DFx
endproc

proc DoIf(pExpr.l)
beginproc
        ;stmt() already matched up to the left paren after the token 'if'
        movea.l pExpr(a6),a0
        clr.w   PGM.tokidx(a0)                          ;reset stack
        move.b  #'(',d0                                 ;now need a left paren
        call    match(pExpr(a6).l,d0.b)                 
        tst.b   d0
        bne.s   DI1
        call    Error(pExpr(a6).l,&MissingLParen(a5))   ;"Missing left parenthisis"
        bra     DIx
DI1     
        call    Relop(pExpr(a6).l)                      ;do relop
        move.b  d0,d2                                   ;save result in d2
        move.b  #')',d0                                 ;now need right paren
        call    match(pExpr(a6).l,d0.b)                 
        tst.b   d0
        bne.s   DI2
        call    Error(pExpr(a6).l,&MissingRParen(a5))   ;"Missing right parenthisis"
        bra.s   DIx
DI2
        movea.l pExpr(a6),a0
        tst.b   d2                                      ;relop true (=1)
        bne.s   DITrue
        addq.w  #1,PGM.ignore(a0)                       ;set to ignore
        call    stmt(pExpr(a6).l)                       ;do stmt as if really executing it
        movea.l pExpr(a6),a0
        subq.w  #1,PGM.ignore(a0)
        call    matchString(pExpr(a6).l,&tokelse(a5))  ;check for 'else'
        tst.b   d0
        beq.s   DIx
        call    stmt(pExpr(a6).l)                       ;do stmt as if really executing it
        bra.s   DIx
DITrue
        call    stmt(pExpr(a6).l)                       ;do stmt as if really executing it
        call    matchString(pExpr(a6).l,&tokelse(a5))  ;check for 'else'
        tst.b   d0
        beq.s   DIx
        movea.l pExpr(a6),a0
        addq.w  #1,PGM.ignore(a0)                       ;set to ignore
        call    stmt(pExpr(a6).l)                       ;do stmt as if really executing it
        movea.l pExpr(a6),a0
        subq.w  #1,PGM.ignore(a0)
DIx
endproc


;+--------- Recursive descent expression interpreter -----------------+
;|                                                                    | 
;| Precedence of operators from lowest to highest                     |
;|  operators with like precedence are on the same line               |
;|                                                                    |
;|lowest                                                              |
;| expr sep                                 ,                         |
;| assignment                               = += -= /= %= &= |= ^=    |
;| and/or/xor                               & | ^                     |
;| lshift/rshift/lrotate/rrotate            << >> <<< >>>             |
;| add/sub                                  + -                       |
;| mul/div/mod                              * / %                     |
;| unary operators pos/neg/not              + - ~                     |   
;| prefix/postfix increment/decrement       ++ --                     |
;| parenthisis                              ( )                       |
;|highest	                           numerics, ids,             |
;|                                         builtins,                  |
;|                                         and strings                |
;| Numeric forms:                                                     |
;|       \x<hex digits>                     hexadecimal               |
;|       \b<binary digits>                  binary                    |
;|       \<octal digits>                    octal                     |
;|       <decimal digits>                   decimal                   |
;|                                                                    |
;+--------------------------------------------------------------------+

proc level0(pExpr.l)
beginproc
	call	level1(pExpr(a6).l)
	move.b	#',',d0
	call	match(pExpr(a6).l,d0.b)
	tst.b	d0
	beq.s	level0x
	call	level0(pExpr(a6).l)
level0x
endproc

proc level1(pExpr.l)
beginproc
        call    level2(pExpr(a6).l)
        call    level1a(pExpr(a6).l)
endproc

proc level1a(pExpr.l)
beginproc
        call    matchString(pExpr(a6).l,&tokequal(a5))  ;check for '=='
        tst.b   d0
        beq.s   level1a1
        call    putBack(pExpr(a6).l,#2.l)               ;put it back, this is a relop
        bra     level1ax
level1a1
        call    matchString(pExpr(a6).l,&tokplusequal(a5))  ;check for '+='
        tst.b   d0
        beq.s   level1a2
        call    level2(pExpr(a6).l)
        call    level1a(pExpr(a6).l)
        call    DoOpAssign(pExpr(a6).l,&DoADD(pc))      ;Add then assignment
        bra     level1ax
level1a2
        call    matchString(pExpr(a6).l,&tokminusequal(a5))  ;check for '-='
        tst.b   d0
        beq.s   level1a3
        call    level2(pExpr(a6).l)
        call    level1a(pExpr(a6).l)
        call    DoOpAssign(pExpr(a6).l,&DoSUB(pc))      ;Subtract then assignment
        bra     level1ax
level1a3
        call    matchString(pExpr(a6).l,&toktimesequal(a5))  ;check for '*='
        tst.b   d0
        beq.s   level1a4
        call    level2(pExpr(a6).l)
        call    level1a(pExpr(a6).l)
        call    DoOpAssign(pExpr(a6).l,&DoMUL(pc))      ;Multiply then assignment
        bra     level1ax
level1a4
        call    matchString(pExpr(a6).l,&tokdivequal(a5))  ;check for '/='
        tst.b   d0
        beq.s   level1a5
        call    level2(pExpr(a6).l)
        call    level1a(pExpr(a6).l)
        call    DoOpAssign(pExpr(a6).l,&DoDIV(pc))      ;Divide then assignment
        bra     level1ax
level1a5
        call    matchString(pExpr(a6).l,&tokmodequal(a5))  ;check for '%='
        tst.b   d0
        beq.s   level1a6
        call    level2(pExpr(a6).l)
        call    level1a(pExpr(a6).l)
        call    DoOpAssign(pExpr(a6).l,&DoMOD(pc))      ;Modulus then assignment
        bra     level1ax
level1a6
        call    matchString(pExpr(a6).l,&tokandequal(a5))  ;check for '&='
        tst.b   d0
        beq.s   level1a7
        call    level2(pExpr(a6).l)
        call    level1a(pExpr(a6).l)
        call    DoOpAssign(pExpr(a6).l,&DoAND(pc))      ;And then assignment
        bra     level1ax
level1a7
        call    matchString(pExpr(a6).l,&tokorequal(a5))  ;check for '|='
        tst.b   d0
        beq.s   level1a8
        call    level2(pExpr(a6).l)
        call    level1a(pExpr(a6).l)
        call    DoOpAssign(pExpr(a6).l,&DoOR(pc))      ;or then assignment
        bra.s   level1ax
level1a8
        call    matchString(pExpr(a6).l,&tokxorequal(a5))  ;check for '^='
        tst.b   d0
        beq.s   level1a9
        call    level2(pExpr(a6).l)
        call    level1a(pExpr(a6).l)
        call    DoOpAssign(pExpr(a6).l,&DoXOR(pc))      ;Xor then assignment
        bra.s   level1ax
level1a9
        move.b  #'=',d0
	call	match(pExpr(a6).l,d0.b)
	tst.b	d0
	beq.s	level1ax
        call    level2(pExpr(a6).l)
        call    level1a(pExpr(a6).l)
        call    DoAssignment(pExpr(a6).l)               ;Assignment, all of which are right recursive 
level1ax
endproc

proc level2(pExpr.l)
beginproc
	call	level3(pExpr(a6).l)
	call	level2a(pExpr(a6).l)
endproc

proc level2a(pExpr.l)
beginproc
        call    matchString(pExpr(a6).l,&tokandequal(a5))  ;check for '&='
        tst.b   d0
        beq.s   level2a1
        call    putBack(pExpr(a6).l,#2.l)               ;put it back
        bra     level2ax
level2a1
        call    matchString(pExpr(a6).l,&tokorequal(a5))  ;check for '|='
        tst.b   d0
        beq.s   level2a2
        call    putBack(pExpr(a6).l,#2.l)               ;put it back
        bra     level2ax
level2a2
        call    matchString(pExpr(a6).l,&tokxorequal(a5))  ;check for '^='
        tst.b   d0
        beq.s   level2a3
        call    putBack(pExpr(a6).l,#2.l)               ;put it back
        bra     level2ax
level2a3
	move.b	#'&',d0
	call	match(pExpr(a6).l,d0.b)
	tst.b	d0
	beq.s	l2NotAnd
	call	level3(pExpr(a6).l)
	call	DoAND(pExpr(a6).l)
	call	level2a(pExpr(a6).l)
	bra.s	level2ax
l2NotAnd
	move.b	#'|',d0
	call	match(pExpr(a6).l,d0.b)
	tst.b	d0
	beq.s	l2NotOr
	call	level3(pExpr(a6).l)
	call	DoOR(pExpr(a6).l)
	call	level2a(pExpr(a6).l)
	bra.s	level2ax
l2NotOr	
	move.b	#'^',d0
	call	match(pExpr(a6).l,d0.b)
	tst.b	d0
	beq.s	level2ax
	call	level3(pExpr(a6).l)
	call	DoXOR(pExpr(a6).l)
	call	level2a(pExpr(a6).l)
level2ax
endproc

proc level3(pExpr.l)
beginproc
	call	level4(pExpr(a6).l)
	call	level3a(pExpr(a6).l)
endproc

proc level3a(pExpr.l)
beginproc
        call    matchString(pExpr(a6).l,&tokLRotate(a5))
        tst.b   d0
        bne     l3LRotate
        call    matchString(pExpr(a6).l,&tokRRotate(a5))
        tst.b   d0
        bne     l3RRotate
	call	matchString(pExpr(a6).l,&tokLshift(a5))
	tst.b	d0
	beq.s	l3NotLShift
	call	level4(pExpr(a6).l)
	call	DoBoolean(pExpr(a6).l,#LSHIFT.w)
	call	level3a(pExpr(a6).l)
	bra.s   level3ax
l3NotLShift
	call	matchString(pExpr(a6).l,&tokRshift(a5))
	tst.b	d0
	beq.s	level3ax
	call	level4(pExpr(a6).l)
	call	DoBoolean(pExpr(a6).l,#RSHIFT.w)
	call	level3a(pExpr(a6).l)
	bra.s	level3ax
l3LRotate
	call	level4(pExpr(a6).l)
	call	DoBoolean(pExpr(a6).l,#LROTATE.w)
	call	level3a(pExpr(a6).l)
	bra.s	level3ax
l3RRotate
	call	level4(pExpr(a6).l)
	call	DoBoolean(pExpr(a6).l,#RROTATE.w)
	call	level3a(pExpr(a6).l)
level3ax
endproc

proc level4(pExpr.l)
beginproc
	call	level5(pExpr(a6).l)
	call	level4a(pExpr(a6).l)
endproc

proc level4a(pExpr.l)
beginproc
        call    matchString(pExpr(a6).l,&tokplusequal(a5))  ;check for '+='
        tst.b   d0
        beq.s   level4a1
        call    putBack(pExpr(a6).l,#2.l)               ;put it back
        bra     level4ax
level4a1
        call    matchString(pExpr(a6).l,&tokminusequal(a5))  ;check for '-='
        tst.b   d0
        beq.s   level4a2
        call    putBack(pExpr(a6).l,#2.l)               ;put it back
        bra.s   level4ax
level4a2
	move.b	#'+',d0
	call	match(pExpr(a6).l,d0.b)
	tst.b	d0
	beq.s	l4NotAdd
	call	level5(pExpr(a6).l)
	call	DoADD(pExpr(a6).l)
	call	level4a(pExpr(a6).l)
	bra.s	level4ax
l4NotAdd
	move.b	#'-',d0
	call	match(pExpr(a6).l,d0.b)
	tst.b	d0
	beq.s	level4ax
	call	level5(pExpr(a6).l)
	call	DoSUB(pExpr(a6).l)
	call	level4a(pExpr(a6).l)
level4ax
endproc

proc level5(pExpr.l)
beginproc
	call	level6(pExpr(a6).l)
	call	level5a(pExpr(a6).l)
endproc

proc level5a(pExpr.l)
beginproc
        call    matchString(pExpr(a6).l,&toktimesequal(a5))  ;check for '*='
        tst.b   d0
        beq.s   level5a1
        call    putBack(pExpr(a6).l,#2.l)               ;put it back
        bra     level5ax
level5a1
        call    matchString(pExpr(a6).l,&tokdivequal(a5))  ;check for '/='
        tst.b   d0
        beq.s   level5a2
        call    putBack(pExpr(a6).l,#2.l)               ;put it back
        bra     level5ax
level5a2
        call    matchString(pExpr(a6).l,&tokmodequal(a5))  ;check for '%='
        tst.b   d0
        beq.s   level5a3
        call    putBack(pExpr(a6).l,#2.l)               ;put it back
        bra     level5ax
level5a3
	move.b	#'*',d0
	call	match(pExpr(a6).l,d0.b)
	tst.b	d0
	beq.s	l5NotMul
	call	level6(pExpr(a6).l)
	call	DoMUL(pExpr(a6).l)
	call	level5a(pExpr(a6).l)
	bra.s	level5ax
l5NotMul
	move.b	#'/',d0
	call	match(pExpr(a6).l,d0.b)
	tst.b	d0
	beq.s	l5NotDiv
	call	level6(pExpr(a6).l)
	call	DoDIV(pExpr(a6).l)
	call	level5a(pExpr(a6).l)
	bra.s	level5ax
l5NotDiv
	move.b	#'%',d0
	call	match(pExpr(a6).l,d0.b)
	tst.b	d0
	beq.s	level5ax
	call	level6(pExpr(a6).l)
	call	DoMOD(pExpr(a6).l)
	call	level5a(pExpr(a6).l)
level5ax
endproc

proc level6(pExpr.l)
beginproc
        call    matchString(pExpr(a6).l,&tokDec(a5))    ;check for prefix --
        tst.b   d0
        beq.s   l6NotPreDec
	call	level7(pExpr(a6).l)
        call    DoIncDec(pExpr(a6).l,#PREFIX.w,#DEC.w)
        bra     level6x
l6NotPreDec
        call    matchString(pExpr(a6).l,&tokminusequal(a5))  ;check for '-='
        tst.b   d0
        beq.s   level61
        call    putBack(pExpr(a6).l,#2.l)               ;put it back
        bra     level6x
level61
	move.b	#'-',d0
	call	match(pExpr(a6).l,d0.b)
	tst.b	d0
	beq.s	l6NotNeg
	call	level7(pExpr(a6).l)
	call	DoNEG(pExpr(a6).l)
	bra  	level6x
l6NotNeg	
	move.b	#'~',d0
	call	match(pExpr(a6).l,d0.b)
	tst.b	d0
	beq.s	l6NotNot
	call	level7(pExpr(a6).l)
	call	DoBoolean(pExpr(a6).l,#NOT.w)
	bra	level6x
l6NotNot
        call    matchString(pExpr(a6).l,&tokInc(a5))    ;check for prefix ++
        tst.b   d0
        beq.s   l6NotPreInc
	call	level7(pExpr(a6).l)
        call    DoIncDec(pExpr(a6).l,#PREFIX.w,#INC.w)
        bra     level6x
l6NotPreInc
        call    matchString(pExpr(a6).l,&tokplusequal(a5))  ;check for '+='
        tst.b   d0
        beq.s   level62
        call    putBack(pExpr(a6).l,#2.l)               ;put it back
        bra.s   level6x
level62
	move.b	#'+',d0
	call	match(pExpr(a6).l,d0.b)                 ;match or don't match (dosn't matter) the prefix + sign
	call	level7(pExpr(a6).l)                     ;call the next level of higher precedence
        call    matchString(pExpr(a6).l,&tokInc(a5))    ;check for postfix ++
        tst.b   d0
        beq.s   l6NotPostInc
        call    DoIncDec(pExpr(a6).l,#POSTFIX.w,#INC.w)
        bra.s   level6x
l6NotPostInc
        call    matchString(pExpr(a6).l,&tokDec(a5))    ;check for postfix --
        tst.b   d0
        beq.s   level6x
        call    DoIncDec(pExpr(a6).l,#POSTFIX.w,#DEC.w)
level6x
endproc

proc level7(pExpr.l)
beginproc
	move.b	#'(',d0
	call	match(pExpr(a6).l,d0.b)
	tst.b	d0
	beq.s	l7NotLParen
	call	level0(pExpr(a6).l)
	move.b	#')',d0
	call	match(pExpr(a6).l,d0.b)
	tst.b	d0
	bne.s	level7x
	call	Error(pExpr(a6).l,&MissingRParen(a5))
	bra.s	level7x
l7NotLParen
	call	String(pExpr(a6).l)
	tst.b	d0
	bne.s	level7x
	call	Builtin(pExpr(a6).l)
	tst.b	d0
	bne.s	level7x
	call	id(pExpr(a6).l)
	tst.b	d0
	bne.s	level7x
	call	num(pExpr(a6).l)
level7x
endproc

proc Relop(pExpr.l)
beginproc
        call    level0(pExpr(a6).l)                     ;expression on left side
        call    matchString(pExpr(a6).l,&tokle(a5))     ;check for '<='
	tst.b	d0
	beq.s	relop2
        call    level0(pExpr(a6).l)                     ;right side expression
        call    compare(pExpr(a6).l,#tLE.w)
        bra     ROx
relop2
        call    matchString(pExpr(a6).l,&tokge(a5))     ;check for '>='
	tst.b	d0
	beq.s	relop3
        call    level0(pExpr(a6).l)                     ;right side expression
        call    compare(pExpr(a6).l,#tGE.w)
        bra     ROx
relop3
        move.b  #'<',d0
        call    match(pExpr(a6).l,d0.b)                 ;check for '<'
	tst.b	d0
	beq.s	relop4
        call    level0(pExpr(a6).l)                     ;right side expression
        call    compare(pExpr(a6).l,#tLT.w)
        bra     ROx
relop4
        move.b  #'>',d0
        call    match(pExpr(a6).l,d0.b)                 ;check for '>'
	tst.b	d0
	beq.s	relop5
        call    level0(pExpr(a6).l)                     ;right side expression
        call    compare(pExpr(a6).l,#tGT.w)
        bra.s   ROx
relop5
        call    matchString(pExpr(a6).l,&tokequal(a5))  ;check for '=='
	tst.b	d0
	beq.s	relop6
        call    level0(pExpr(a6).l)                     ;right side expression
        call    compare(pExpr(a6).l,#tEQUAL.w)
        bra.s   ROx
relop6
        call    matchString(pExpr(a6).l,&tokne(a5))     ;check for '!='
	tst.b	d0
	beq.s	relop7
        call    level0(pExpr(a6).l)                     ;right side expression
        call    compare(pExpr(a6).l,#tNE.w)
        bra.s   ROx
relop7
        call    Error(pExpr(a6).l,&InvalidRelop(a5))    ;Invalid relop
ROx
endproc

proc compare(pExpr.l,comptype.w)
local Cop1.8
local Cop2.8
beginproc
        movem.l d2/a3,-(a7)
        call    popToken(pExpr(a6).l)                   ;get next token
        cmp.w   #tNUM,d0                                ;is it a NUM?
        beq.s   Cnum1                                   ;yep
        cmp.w   #tID,d0                                 ;ID?
        beq.s   Cid1                                    ;yes, then must eval it
	call	Error(pExpr(a6).l,&ExpectNUMID(a5))     ;expected numeric, expression, or variable
        bra     Cx
Cid1    
        call    popEntry(pExpr(a6).l)                   ;get id in d0
        movea.l pExpr(a6),a1                            ;get parent pgm ptr
	call	DoPgm(d0.w,PGM.ignore(a1).w)	        ;do program/propagate ignore
        bra.s   CSave1
Cnum1
        call    popEntry(pExpr(a6).l)                   ;get num entry
CSave1  move.l  d0,Cop1(a6)
        move.l  d1,Cop1+4(a6)

        call    popToken(pExpr(a6).l)                   ;get next token
        cmp.w   #tNUM,d0                                ;is it a NUM?
        beq.s   Cnum2                                   ;yep
        cmp.w   #tID,d0                                 ;ID?
        beq.s   Cid2                                    ;yes, then must eval it
	call	Error(pExpr(a6).l,&ExpectNUMID(a5))     ;expected numeric, expression, or variable
        bra     Cx
Cid2    
        call    popEntry(pExpr(a6).l)                   ;get id in d0
        movea.l pExpr(a6),a1                            ;get parent pgm ptr
	call	DoPgm(d0.w,PGM.ignore(a1).w)	        ;do program
        bra.s   CSave2
Cnum2   
        call    popEntry(pExpr(a6).l)                   ;pop num
CSave2  move.l  d0,Cop2(a6)
        move.l  d1,Cop2+4(a6)
        cmp.w   #$7fff,CurrentBase(a5)
        beq.s   CFloat
        move.l  Cop2(a6),d0
        cmp.l   Cop1(a6),d0
        bra.s   CCheck
CFloat
        call    FPICompare(&Cop2(a6),&Cop1(a6))         ;compare operands
CCheck  beq.s   Cequal
        blt.s   Cless
        cmp.w   #tGT,comptype(a6)                       ;it's greater than, is that the expectation?
        beq.s   Ctrue
        cmp.w   #tGE,comptype(a6)                       ;is greater than, expects >= this is good too
        beq.s   Ctrue
        bra.s   Cfalse
Cequal
        cmp.w   #tEQUAL,comptype(a6)                    ;it's equal, is that the expectation?
        beq.s   Ctrue
        cmp.w   #tLE,comptype(a6)                       ;is equal, expects <= this is good too
        beq.s   Ctrue
        cmp.w   #tGE,comptype(a6)                       ;is equal, expects >= this is good too
        beq.s   Ctrue
        bra.s   Cfalse
Cless
        cmp.w   #tLT,comptype(a6)                       ;it's less, is that the expectation?
        beq.s   Ctrue
        cmp.w   #tLE,comptype(a6)                       ;is less, expects <= this is good too
        beq.s   Ctrue
        bra.s   Cfalse
Ctrue   move.b  #true,d0
        bra.s   Cx
Cfalse  move.b  #false,d0
Cx      movem.l (a7)+,a3 
endproc


;
; Report error in expression processing
; Input:  pExpr points to expression in error
;         pMsgText points to a message to display
; Output: None
;
proc Error(pExpr.l,pMsgText.l)
local Position.8
beginproc
	move.l	a3,-(a7)
	tst.b	ErrorFlag(a5)			        ;if there's already been
	bne.s	Errorx				        ; an error, then don't speak 
	movea.l	pExpr(a6),a3			        ;address of expression struct
	move.w	PGM.pgmidx(a3),d0		        ;get position were at
	addq.w	#1,d0				        ;make it 1 relative
        ext.l   d0
	systrap	StrIToA(&Position(a6),d0.l)	        ;convert to ascii
	movea.l	PGM.pgmtext(a3),a1		        ;get expression text
        systrap FrmCustomAlert(#ErrorAlert.w,pMsgText(a6).l,a0.l,a1.l)
	move.b	#true,ErrorFlag(a5)		        ;flag error
Errorx	move.l	(a7)+,a3
endproc

proc String(pExpr.l)
local StringStr.40
beginproc
	movem.l	d2/a3,-(a7)
	move.b	#'"',d0
	call	match(pExpr(a6).l,d0.b)
	tst.b	d0
	beq	Stringx					;not string, exit
	movea.l	pExpr(a6),a0
	movea.l	PGM.pgmtext(a0),a1
	move.w	PGM.pgmidx(a0),d0
	lea	(a1,d0),a0				;a0 -> string within expr
	lea	StringStr(a6),a1			;a1 -> dest string
StringMove
	cmp.b	#0,(a0)
	beq.s	StringDone
	cmp.b	#'"',(a0)
	beq.s	StringDone
	move.b	(a0)+,(a1)+
	bra.s	StringMove
StringDone
	move.b	#0,(a1)					;terminating null
	systrap	StrLen(&StringStr(a6))
	move.l	d0,d2
	movea.l pExpr(a6),a0
	add.w	d0,PGM.pgmidx(a0)			;increment expressing index
	move.b	#'"',d0
	call	match(pExpr(a6).l,d0.b)
	tst.b	d0
	bne.s	StringOK
	call	Error(pExpr(a6).l,&MissingQuote(a5))
	bra.s   Stringx
StringOK
	addq.l	#1,d2					;add 1 to string len for null
	systrap	MemPtrNew(d2.l)
	cmpa.l	#0,a0
	bne.s	StringMemOK
        systrap FrmAlert(#ErrorMem.w)
	bra.s	Stringx
StringMemOK
	move.l	a0,a3
	systrap	StrCopy(a3.l,&StringStr(a6))
        call    pushString(pExpr(a6).l,a3.l)
        move.b  #true,d0                                ;signal string found
Stringx
	movem.l	(a7)+,d2/a3
endproc

proc id(pExpr.l)
local idTempNum.8
local idTempString.40
beginproc
	movem.l	d2/a3,-(a7)
	call	supr(pExpr(a6).l,#0.l)
	movea.l	pExpr(a6),a0
	movea.l	PGM.pgmtext(a0),a3
	clr.l	d2				
	move.w	PGM.pgmidx(a0),d1
	move.b	(a3,d1),d0			        ;first char must be alpha to be a symbol
	cmp.b	#'A',d0
	blt	idFalse
	cmp.b	#'Z',d0
	ble.s	idOK
	cmp.b	#'a',d0
	blt	idFalse
	cmp.b	#'z',d0
	bgt	idFalse
	bra	idOK

idLoop	move.w	PGM.pgmidx(a0),d1
	move.b	(a3,d1),d0			        ;loop through all alpha/num till end of id
	cmp.b	#'0',d0
	blt	idDone
	cmp.b	#'9',d0
	ble.s	idOK
	cmp.b	#'A',d0
	blt.s	idDone
	cmp.b	#'Z',d0
	ble.s	idOK
	cmp.b	#'a',d0
	blt.s	idDone
	cmp.b	#'z',d0
	bgt.s	idDone
idOK	move.b	d0,idTempString(a6,d2)
	addq.l	#1,d2
	addq.w	#1,PGM.pgmidx(a0)		        ;increment pointer
	bra.s	idLoop
idDone	move.b	#0,idTempString(a6,d2)		        ;terminating null
; first lookup symbol in static table
        lea.l   Static(a5),a3                           ;get starting address of table
Staloop tst.l   (a3)                                    ;done?
        beq.s   NotStatic
        movea.l (a3),a0                                 ;get pointer to name string
        tst.b   SymbolCase(a5)                          ;case sensitive or not?
        bne.s   StaCase                                 ;it's case sensitive...
        systrap StrCaselessCompare(a0.l,&idTempString(a6)) ;compare against input
        bra.s   StaCmpDone
StaCase
        systrap StrCompare(a0.l,&idTempString(a6))      ;compare with case sensitivity
StaCmpDone
        tst.w   d0                                      ;found?
        beq.s   StaticFound
        lea.l   8(a3),a3                                ;next entry
        bra.s   Staloop                                 ;continue
StaticFound
        movea.l 4(a3),a3                                ;address of number
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP mode?
	bne.s	Stabin
        call    FPIAsciiToFloat(&idTempNum(a6),a3.l)    ;convert ascii to float
	call	pushNum(pExpr(a6).l,&idTempNum(a6),CurrentBase(a5).w)	;push onto stack
	bra.s	idTrue
Stabin
	call	InputConversion(a3.l,#10.w)
	call	pushNum(pExpr(a6).l,d0.l,#16.w)		;push num on stack
        bra.s   idTrue
NotStatic
        call    GetSymbol(&idTempString(a6))            ;lookup symbol
        tst.w   d0                                      ;is it there?
        bne.s   idMatched                               ;yep, go push the addr
        call    AddSymbol(&idTempString(a6),&Zero(a5),#SYMIMMEDIATE.w)
        call    GetSymbol(&idTempString(a6))
idMatched
        call    pushID(pExpr(a6).l,d0.w)                ;push address of symbol table entry
idTrue	move.b	#true,d0
	bra.s	idx	
idFalse move.b	#false,d0
idx	movem.l	(a7)+,d2/a3
endproc


proc Builtin(pExpr.l)
local BIExprIdx.l
local BITempString.40
beginproc
	movem.l	d2/a3,-(a7)
	call	supr(pExpr(a6).l,#0.l)
	movea.l	pExpr(a6),a0
	movea.l	PGM.pgmtext(a0),a3
	clr.l	d2				
	move.w	PGM.pgmidx(a0),d1
	move.l	d1,BIExprIdx(a6)
	move.b	(a3,d1),d0			        ;first char must be alpha to be a symbol
	cmp.b	#'A',d0
	blt	BIFalse
	cmp.b	#'Z',d0
	ble.s	BIOK
	cmp.b	#'a',d0
	blt	BIFalse
	cmp.b	#'z',d0
	bgt	BIFalse
	bra.s   BIOK

BILoop	move.l	BIExprIdx(a6),d1
	move.b	(a3,d1),d0			        ;loop through all alpha/num till end of id
	cmp.b	#'0',d0
	blt.s	BIDone
	cmp.b	#'9',d0
	ble.s	BIOK
	cmp.b	#'A',d0
	blt.s	BIDone
	cmp.b	#'Z',d0
	ble.s	BIOK
	cmp.b	#'a',d0
	blt.s	BIDone
	cmp.b	#'z',d0
	bgt.s	BIDone
BIOK	move.b	d0,BITempString(a6,d2)
	addq.l	#1,d2
	addq.l	#1,BIExprIdx(a6)		        ;increment pointer
	bra.s	BILoop
BIDone	move.b	#0,BITempString(a6,d2)		        ;terminating null
	move.l	BuiltInIdx(a5),d2		        ;count of symbols in symbol table
	movea.l	BuiltInTab(a5),a3		        ;get starting address of symbol table
BILookup
	movea.l	BUILTIN.Name(a3),a0		        ;get address of symbol name
        tst.b   SymbolCase(a5)                          ;is it case sensitive?
        beq.s   BINoCase
	systrap StrCompare(&BITempString(a6),a0.l)      ;compare to current expression
        bra.s   BICmpDone
BINoCase
	systrap StrCaselessCompare(&BITempString(a6),a0.l) ;compare to current expression
BICmpDone
	tst.w	d0
	beq.s	BIMatched
	lea	BUILTINSIZE(a3),a3		        ;point to next entry
	subq.l	#1,d2
	bne.s	BILookup		
	bra.s 	BIFalse				        ;not found
BIMatched
	systrap	StrLen(&BITempString(a6))
	movea.l	pExpr(a6),a0
	add.w	d0,PGM.pgmidx(a0)
	move.b	#'(',d0
	call	match(pExpr(a6).l,d0.b)
	tst.b	d0
	bne.s	BIDoExpr
	call	Error(pExpr(a6).l,&MissingLParen(a5))
	bra.s	BIx
BIDoExpr
	tst.l	BUILTIN.Args(a3)		        ;any args?
	beq.s	NoArgs
        call	level0(pExpr(a6).l)		        ;do expression
NoArgs	move.b	#')',d0
	call	match(pExpr(a6).l,d0.b)
	tst.b	d0
	bne.s	BICallRoutine
	call	Error(pExpr(a6).l,&MissingRParen(a5))
	bra.s	BIx
BICallRoutine
	movea.l	BUILTIN.Routine(a3),a0		        ;get routine pointer in d0
	move.l	pExpr(a6),-(a7)			        ;arg is pExpr
	jsr	(a0)				        ;call builtin function
	addq.l	#4,a7
BITrue	move.b	#true,d0
	bra.s	BIx	
BIFalse move.b	#false,d0
BIx	movem.l	(a7)+,d2/a3
endproc


;
; Add a new built in function to the BuiltInTab
; Input:  pNewBuiltInName points to a null terminated string to add as the new builtin
;         pNewRtn points to the routine
;	  ArgCount is number of arguments that the routine takes
; Output: None
;
proc AddBuiltIn(pNewBuiltInName.l,pBuiltInRtn.l,BINumArgs.w)
beginproc
	move.l	a3,-(a7)
	movea.l	BuiltInTab(a5),a3
	move.l	BuiltInIdx(a5),d0
	mulu.w	#BUILTINSIZE,d0
	lea	(a3,d0),a3			        ;point to free builtin entry
	movea.l	pNewBuiltInName(a6),a0
	move.l	a0,BUILTIN.Name(a3)
	movea.l	pBuiltInRtn(a6),a0
	move.l	a0,BUILTIN.Routine(a3)
        clr.l   d0
	move.w	BINumArgs(a6),d0
	move.l	d0,BUILTIN.Args(a3)
	addq.l	#1,BuiltInIdx(a5)
	move.l	(a7)+,a3
endproc


proc num(pExpr.l)
local numTemp.8
local numIbase.w
local numTempString.40
beginproc
	movem.l	d2/a3,-(a7)			        ;save regs
	call	supr(pExpr(a6).l,#0.l)                  
	movea.l	pExpr(a6),a0                            
	movea.l	PGM.pgmtext(a0),a3                        
	move.w	PGM.pgmidx(a0),d1                     
	move.b	(a3,d1),d0			        ;get next char of expression
	move.w	#10,numIbase(a6)		        ;default to base 10
	cmp.b	#'\',d0				        ;escape sequence?
	bne.s	nParse                                  
	addq.w	#1,PGM.pgmidx(a0)		        ;increment pointer
	addq.l	#1,d1                                   
	move.b	(a3,d1),d0			        ;get next byte
	move.w	#8,numIbase(a6)			        ;default to octal
	cmp.b	#'x',d0				        ;is it hexadecimal?
	beq.s	nHex				        ;yes, it's hex
	cmp.b	#'b',d0				        ;is it binary?
	bne.s	nParse				        ;no, it's octal then
	move.w	#2,numIbase(a6)			        ;set binary mode
	bra.s	nInc	                                
nHex	move.w	#16,numIbase(a6)		        ;otherwise it's hex
nInc	addq.w	#1,PGM.pgmidx(a0)		        ;increment pointer
nParse	clr.l	d2				        ;index into str
numloop1                                                
	move.w	PGM.pgmidx(a0),d1                     
	move.b	(a3,d1),d0			        ;get next char of expression
	call	validate(numIbase(a6).w,d0.w)           
	tst.b	d1				        ;if not valid input
	bne.s	num2				        ; then done
dgtok	move.b	d0,numTempString(a6,d2)                 
	addq.l	#1,d2                                   
	addq.w	#1,PGM.pgmidx(a0)		        ;increment pointer
	bra.s	numloop1			        ;continue
num2	cmp.b	#'e',d0				        ;exponent entered?
	bne.s	num3
	cmp.w	#10,numIbase(a6)		        ;decimal?
	bne.s	num3                                    
	move.b	d0,numTempString(a6,d2)		        ;move 'e' to str
	addq.l	#1,d2				        ;inc indx
	addq.w	#1,PGM.pgmidx(a0)		        ;inc expr idx
	move.w	PGM.pgmidx(a0),d1		        ;get idx in d1
	move.b	(a3,d1),d0			        ;get next char
	cmp.b	#'-',d0
	bne.s	num2a	
	move.b	d0,numTempString(a6,d2)
	addq.l	#1,d2
	addq.w	#1,PGM.pgmidx(a0)
num2a
	move.w	PGM.pgmidx(a0),d1
	move.b	(a3,d1),d0
	call	validate(numIbase(a6).w,d0.w)
	tst.b	d1
	bne.s	num3
	move.b	d0,numTempString(a6,d2)
	addq.l	#1,d2
	addq.w	#1,PGM.pgmidx(a0)		        ;increment pointer
	bra.s	num2a                                   
num3	move.b	#0,numTempString(a6,d2)		        ;terminating null
	tst.b	numTempString(a6)		        ;string length > 0?
	bne.s	numgood
	call	Error(pExpr(a6).l,&MissingNum(a5))
	bra 	numx
numgood	cmp.w	#$7fff,CurrentBase(a5)		        ;FP mode?
	bne.s	numbin
	;it's floating point mode mode
	cmp.w	#10,numIbase(a6)		        ;is the number entered decimal?
	beq.s	numAToF
	;but it's not decimal input
	call	InputConversion(&numTempString(a6),numIbase(a6).w)
        call    FPILongToFloat(&numTemp(a6),d0.l)
	bra.s	numFloatPush
numAToF 
        call    FPIAsciiToFloat(&numTemp(a6),&numTempString(a6)) ;convert ascii to float
numFloatPush
	call	pushNum(pExpr(a6).l,&numTemp(a6),CurrentBase(a5).w)	;push onto stack
	bra.s	numx
numbin
	call	InputConversion(&numTempString(a6),numIbase(a6).w)
	call	pushNum(pExpr(a6).l,d0.l,#16.w)		        ;push num on stack
numx	movem.l	(a7)+,d2/a3			        ;restore regs
endproc

proc validate(valBase.w,ch.w)
beginproc
	move.w	ch(a6),d0
	cmp.b	#'.',d0
	bne.s	valid1
	cmp.w	#10,valBase(a6)
	bne.s	valbad
	bra.s	valgood		
valid1	cmp.b	#'0',d0
	blt.s	valbad
	cmp.b	#'9',d0
	bgt.s	valalpha
	sub.b	#'0',d0
	bra.s	valcont
valalpha
	cmp.w	#10,valBase(a6)
	beq.s	valbad
	cmp.b	#'A',d0
	blt.s	valbad
	cmp.b	#'F',d0
	ble.s	alphaok
	cmp.b	#'a',d0
	blt.s	valbad
	cmp.b	#'f',d0
	bgt.s	valbad
	and.b	#$df,d0
alphaok sub.b	#$41,d0
valcont	move.w	valBase(a6),d1
	cmp.b	d1,d0
	bge.s	valbad
valgood	clr.b	d1
	bra.s	validatex
valbad  move.b	#1,d1
validatex
	move.w	ch(a6),d0	
endproc

proc match(pExpr.l,MatchChar.w)
beginproc
	move.l	a3,-(a7)
	call	supr(pExpr(a6).l,#0.l)
	movea.l	pExpr(a6),a0
	movea.l	PGM.pgmtext(a0),a3
	move.w	PGM.pgmidx(a0),d0
	move.b	MatchChar(a6),d1
	cmp.b	(a3,d0),d1
	bne.s	MatchFalse
	call	supr(pExpr(a6).l,#1.l)
	move.b	#true,d0
	bra.s	MatchX
MatchFalse
	move.b	#false,d0
MatchX	move.l	(a7)+,a3
endproc

proc putBack(pExpr.l,PBNumChars.l)
beginproc
        movea.l pExpr(a6),a0
        move.l  PBNumChars(a6),d0
	sub.w	d0,PGM.pgmidx(a0)
endproc

proc matchString(pExpr.l,pMatchString.l)
beginproc
	movem.l	a3/d2-d3,-(a7)
	call	supr(pExpr(a6).l,#0.l)                  ;suppress any spaces
        systrap StrLen(pMatchString(a6).l)              ;get length of string
        move.l  d0,d2                                   ;save in d2
        tst.l   d2
        beq.s   MatchStringFalse                        ;null string we're comparing?
	movea.l	pExpr(a6),a0
	move.w	PGM.pgmidx(a0),d0
	movea.l	PGM.pgmtext(a0),a0
        lea.l   (a0,d0),a3                              ;a3 points to current position in expr
        movea.l pMatchString(a6),a0                     ;point to string to match
MSLoop  tst.b   (a3)                                    ;null?
        beq.s   MatchStringFalse
        move.b  (a0)+,d0
        cmp.b   (a3)+,d0
        bne.s   MatchStringFalse
        subq.l  #1,d2
        bne.s   MSLoop
        systrap StrLen(pMatchString(a6).l)              ;get length again
        ext.l   d0
	call	supr(pExpr(a6).l,d0.l)                  ;suppress to length of string
	move.b	#true,d0
	bra.s	MSx
MatchStringFalse
	move.b	#false,d0
MSx	movem.l	(a7)+,a3/d2-d3
endproc



proc supr(pExpr.l,NumChars.l)
beginproc
	movem.l	d1/a3,-(a7)
	movea.l	pExpr(a6),a0
	tst.b	PGM.AtEof(a0)
	bne.s	suprx			                ;if at end of expression, done
	move.l	NumChars(a6),d0                         
	add.w	d0,PGM.pgmidx(a0)	                ;supress this many character
	movea.l	PGM.pgmtext(a0),a3	                ;address of expression text in a3
suprloop                                                
	move.w	PGM.pgmidx(a0),d1                     
	cmp.b	#' ',(a3,d1)		                ;space in expression?
	beq.s	DoSupress 
        cmp.b   #$0a,(a3,d1)                            ;line feed?
        beq.s   DoSupress                              
        cmp.b   #$09,(a3,d1)                            ;tab?
        beq.s   DoSupress                              
	cmp.b	#0,(a3,d1)		                ;end of string (null)
	bne.s	suprx                                   
	move.b	#true,PGM.AtEof(a0)	                ;set end of expression flag
	bra.s	suprx
DoSupress
	add.w	#1,PGM.pgmidx(a0)
	bra.s	suprloop
suprx
	movem.l	(a7)+,d1/a3
endproc


;*******************************************************************************
;*                               Math Functions                                *
;*******************************************************************************

proc DoIncDec(pExpr.l,prepost.w,incdec.w)
local PreVal.8
local wID.w
beginproc
        move.l  d2,-(a7)
        call    popID(pExpr(a6).l)
        tst.b   d2
        bne     DIDx
        move.w  d0,wID(a6)
        cmp.w   #POSTFIX,prepost(a6)                    ;do we need to calc a prefix value?
        bne.s   DIDNoPreVal
        call    pushID(pExpr(a6).l,wID(a6).w)
        call    popNum(pExpr(a6).l)                     ;need value of id
	move.l	d0,PreVal(a6)
	move.l	d1,PreVal+4(a6)                         ;save prefix value
DIDNoPreVal
        call    pushID(pExpr(a6).l,wID(a6).w)           ;one for add, 
        call    pushID(pExpr(a6).l,wID(a6).w)           ; one for assignment
        cmp.b   #2,romVersion(a5)
        bge.s   DIDV2
        call    pushNum(pExpr(a6).l,&One(a5),#$7fff.w)
        bra.s   DIDo
DIDV2
        call    pushNum(pExpr(a6).l,&OneV2(a5),#$7fff.w)
DIDo    cmp.w   #INC,incdec(a6)                         ;increment or decrement?
        bne.s   DoDecrement
        call    DoADD(pExpr(a6).l)
        bra.s   DIDCont
DoDecrement
        call    DoSUB(pExpr(a6).l)
DIDCont
        call    DoAssignment(pExpr(a6).l)    
        cmp.w   #PREFIX,prepost(a6)                     ;prefix returns sum
        beq.s   DIDx                                    ;which is on stack now
        call    popNum(pExpr(a6).l)                     ;pop unneeded result
        call    pushEntry(pExpr(a6).l,PreVal(a6).l,PreVal+4(a6).l) ;push prefix value
        call    pushEntry(pExpr(a6).l,#tNUM.l,#0.l)                 ;push token for NUM
DIDx    move.l  (a7)+,d2
endproc


proc DoReturn(pExpr.l)
beginproc
        move.l  d2,-(a7)
        movea.l pExpr(a6),a0
        tst.w   PGM.ignore(a0)                          ;are we ignoring?
        bne.s   DRx        
        call    popNum(pExpr(a6).l)                     ;get return value
        tst.b   d2
        bne.s   DRx                                     ;if error, just ignore return
        movea.l pExpr(a6),a0
        move.l  d0,PGM.returnVal(a0)                    ;save
        move.l  d1,PGM.returnVal+4(a0)                  ;  value
        move.b  #true,PGM.returnFlag(a0)                ;say we explicitly returned something
        addq.w  #1,PGM.ignore(a0)                       ;ignore rest of program
DRx     move.l  (a7)+,d2
endproc

proc DoOpAssign(pExpr.l,pRoutine.l)
local DOAValue.8
local DOAID.w
beginproc
        move.l  d2,-(a7)
        call    popNum(pExpr(a6).l)
        tst.b   d2
        bne.s   DOAx
        move.l  d0,DOAValue(a6)                         ;save
        move.l  d1,DOAValue+4(a6)                       ; value
        call    popID(pExpr(a6).l)                      ;pop the identifier
        tst.b   d2
        bne.s   DOAx
        move.w  d0,DOAID(a6)                            ;save ID
        call    pushID(pExpr(a6).l,d0.w)                ;push ID
        call    pushID(pExpr(a6).l,DOAID(a6).w)         ;push again
        cmp.w   #$7fff,CurrentBase(a5)                  ;float mode?
        bne.s   DOABinMode
        call    pushNum(pExpr(a6).l,&DOAValue(a6),#$7fff.w) ;push num back
        bra.s   DOACont
DOABinMode
        call    pushNum(pExpr(a6).l,DOAValue(a6).l,CurrentBase(a5).w) ;push bin num back
DOACont move.l  pExpr(a6),-(a7)                         ;arg
        movea.l pRoutine(a6),a0
        jsr     (a0)                                    ;call routine
        addq.l  #4,a7                                  
        call    DoAssignment(pExpr(a6).l)
DOAx    move.l  (a7)+,d2
endproc

proc DoAssignment(pExpr.l)
local DAOp2.8
local DATemp.l
local DARecIdx.w
local DATempBuf.40
beginproc
        movem.l d2/a3-a4,-(a7)
DApopTok
        call    popToken(pExpr(a6).l)                   ;get next token
        cmp.w   #tNUM,d0                                ;is it a NUM?
        beq.s   DAnum                                   ;yep, do assignment
        cmp.w   #tSTRING,d0                             ;is it a STRING entry?
        beq     DAstring
        cmp.w   #tID,d0                                 ;ID?
        beq.s   DAid                                    ;yes, then must eval it
	call	Error(pExpr(a6).l,&AssignError(a5))
        bra     DAx
DAid    
        call    popEntry(pExpr(a6).l)                   ;pop id entry
        movea.l pExpr(a6),a1                            ;get parent pgm ptr
	call	DoPgm(d0.w,PGM.ignore(a1).w)	        ;do program
        bra.s   DAnumVal
DAnum   
        call    popEntry(pExpr(a6).l)                   ;pop num value
DAnumVal
        move.l  d0,DAOp2(a6)
        move.l  d1,DAOp2+4(a6)
        lea.l   DAOp2(a6),a0
        cmp.w   #$7fff,CurrentBase(a5)                  ;is it float mode?
        beq.s   DAConv
        call    OutputConversion(d0.l,#10.l,&DATempBuf(a6).l,#40.l)
        systrap StrCopy(&TStr(a5),a3.l)
        bra.s   DACont
DAConv
        call    Conv(a0.l,&TStr(a5))
DACont
        call    popID(pExpr(a6).l)
        tst.b   d2
        bne     DAx
        move.w  d0,DARecIdx(a6)
        movea.l pExpr(a6),a1
        tst.w   PGM.ignore(a1)
        bne     DAIgnore3
        call    GetSymbolName(DARecIdx(a6).w)
        move.l  a0,DATemp(a6)
        call    ReplaceSymbol(a0.l,&TStr(a5),#SYMIMMEDIATE.w)
        systrap MemPtrFree(DATemp(a6).l)
        cmp.w   #$7fff,CurrentBase(a5)
        beq.s   DAPushFloat
        call    pushNum(pExpr(a6).l,DAOp2(a6).l,CurrentBase(a5).w)
        bra     DAx
DAPushFloat
        call    pushNum(pExpr(a6).l,&DAOp2(a6),CurrentBase(a5).w)
        bra.s   DAx
DAstring
        call    popEntry(pExpr(a6).l)                   ;get string ptr in a0
        move.l  d0,a4                                   ;save in a4
        call    popID(pExpr(a6).l)
        tst.b   d2
        bne.s   DAx
        move.w  d0,DARecIdx(a6)
        movea.l pExpr(a6),a1
        tst.w   PGM.ignore(a1)
        bne.s   DAIgnore2
        call    GetSymbolName(DARecIdx(a6).w)
        move.l  a0,DATemp(a6)
        call    ReplaceSymbol(a0.l,a4.l,#SYMIMMEDIATE.w)
        systrap MemPtrFree(DATemp(a6).l)
DAIgnore2 
	systrap	MemPtrFree(a4.l)        		;free string
DAIgnore3
        call    pushNum(pExpr(a6).l,#0.l,#16.w)         ;assignment of string returns 0
DAx     movem.l (a7)+,d2/a3-a4
endproc



; This isn't a math function but instead gets an input from the user via a dialog
; and pushes the result onto the stack
;
proc DoInp(pExpr.l)
local DoInpResult.8
local pDoInpPrompt.l
local pDoInpExpr.l
local DoInpSym.8
beginproc
	movem.l	d2/a3-a4,-(a7)
        call    popString(pExpr(a6).l)
        tst.b   d2
        bne     DoInpx
        movea.l pExpr(a6),a0
        tst.w   PGM.ignore(a0)
        bne     DoInpx
	move.l	d0,pDoInpPrompt(a6)
	systrap	FrmInitForm(#kidfInp.w)			;init dialog
	move.l	a0,a3					;put FormPtr in a safe place
        systrap FrmGetObjectIndex(a3.l,#kidcInp.w)      ;get index of input field
        systrap FrmSetFocus(a3.l,d0.w)                  ;set focus to field
	systrap	FrmSetTitle(a3.l,pDoInpPrompt(a6).l)    ;set title
	systrap	FrmDoDialog(a3.l)			;do it
        cmp.w   #kidbok,d0
        beq.s   DoInpCont
	move.b	#true,ErrorFlag(a5)
        bra     DoInpFree        
DoInpCont
        systrap FrmGetObjectIndex(a3.l, #kidcInp.w)	;get field index
        systrap FrmGetObjectPtr(a3.l,d0.w)		;get pointer
        systrap FldGetTextPtr(a0.l)			;get address of text
	cmpa.l	#0,a0					;is it null?
	beq     DoInpFree
        move.l  a0,a3
        systrap StrCopy(&DoInpSym(a6),&SymTempName(a5)) ;prefix of temp var name
        addq.l  #1,tempAccum(a5)                        ;increment variable
        systrap StrLen(&DoInpSym(a6))
        lea.l   DoInpSym(a6,d0),a0
        systrap StrIToA(a0.l,tempAccum(a5).l)           ;create temp variable name
        call    AddSymbol(&DoInpSym(a6),a3.l,#SYMIMMEDIATE.w)
        call    GetSymbol(&DoInpSym(a6))
	call	DoPgm(d0.w,#0.w)        	        ;execute program
        cmp.w   #$7fff,CurrentBase(a5)                  ;floating mode?
        bne.s   DoInpPushBin
        move.l  d0,DoInpResult(a6)
        move.l  d1,DoInpResult+4(a6)
        call    pushNum(pExpr(a6).l,&DoInpResult(a6),CurrentBase(a5).w)
        bra.s   DoInpFree
DoInpPushBin
        call    pushNum(pExpr(a6).l,d0.l,CurrentBase(a5).w)
DoInpFree
        call    DeleteSymbol(&DoInpSym(a6))             ;delete symbol
	systrap	MemPtrFree(pDoInpPrompt(a6).l)		;free prompt string
DoInpx	movem.l	(a7)+,d2/a3-a4
endproc

;
; Clear calculator, no return
;
proc DoClr()
beginproc
	call	Initialization()			;initialize calculator
DoClrx
endproc

;
; Clear last entry, no return
;
proc DoCE()
beginproc
	tst.w	LastWasOp(a5)				;Last input operation?
	bne.s	DoCEOp					;yes, logic is different
	move.b	#0,Op2(a5)				;clear display
	bra.s	DoCEx
DoCEOp	clr.w	LastOp(a5)				;no last op
	clr.w	NumOps(a5)				;no ops yet
DoCEx
endproc


;
; Return percent x of y
;
proc DoPct(pExpr.l)
local PctOp1.8
local PctOp2.8
local PctTemp.8
beginproc
	movem.l	d2/a3-a4,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne     PctBin
	call	popNum(pExpr(a6).l)		        ;get arg 1
	tst.b	d2
	bne	Pctx
	move.l	d0,PctOp1(a6)			        ;save 
        move.l  d1,PctOp1+4(a6)                         ; arg 1
	call	popNum(pExpr(a6).l)		        ;get arg 2
	tst.b	d2
	bne	Pctx
	move.l	d0,PctOp2(a6)
        move.l  d1,PctOp2+4(a6)
;	result = arg1*arg2/100
        cmp.b   #2,romVersion(a5)
        bge.s   DoPctV2
        call    FPIDiv(&PctTemp(a6),&PctOp1(a6),&Hundred(a5))
        bra.s   DoPct2
DoPctV2
        call    FPIDiv(&PctTemp(a6),&PctOp1(a6),&HundredV2(a5))
DoPct2
        call    FPIMul(&PctTemp(a6),&PctTemp(a6),&PctOp2(a6))
	call	pushNum(pExpr(a6).l,&PctTemp(a6),CurrentBase(a5).w)
	bra.s	Pctx
PctBin
;	result = operand2*operand1/100			;formula is different for binary %
	call	popNum(pExpr(a6).l)			
	tst.b	d2
	bne.s	Pctx
	move.l	d0,PctOp1(a6)
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne.s	Pctx
	call	LongMultiply(d0.l,PctOp1(a6).l)		;operand1*operand2
	call	LongDivide(d0.l,#100.l)			;/100
	call	pushNum(pExpr(a6).l,d0.l,CurrentBase(a5).w)
Pctx	movem.l	(a7)+,d2/a3-a4
endproc

;
; Helper function for radians to degrees conversion
;
proc ConvertToProperMode(pFPNum.l)
beginproc
        movem.l a0/d0-d2,-(a7)
        cmp.w   #kidcDegrees,DegreeFlag(a5)             ;are we in degree mode?
        bne.s   CTPMCheckGrads                          ;no, try grads
        movea.l pFPNum(a6),a0
        call    FPIDiv(a0.l,a0.l,&r2d(a5))              ;FPNum/(180/pi)
        bra.s   CTPMx
CTPMCheckGrads
        cmp.w   #kidcGrads,DegreeFlag(a5)               ;are we in grads mode?
        bne.s   CTPMx                                   ;no, then don't do anything
        movea.l pFPNum(a6),a0
        call    FPIDiv(a0.l,a0.l,&r2g(a5))              ;FPNum/(200/pi)
CTPMx   movem.l (a7)+,a0/d0-d2
endproc

;
; Helper function for radians to degrees
;
proc ConvertFromProperMode(pFPNum.l)
beginproc
        movem.l a0/d0-d2,-(a7)
        cmp.w   #kidcDegrees,DegreeFlag(a5)             ;are we in degree mode?
        bne.s   CFPMCheckGrads
        movea.l pFPNum(a6),a0
        call    FPIMul(a0.l,a0.l,&r2d(a5))              ;FPNum*(180/pi)
        bra.s   CFPMx
CFPMCheckGrads
        cmp.w   #kidcGrads,DegreeFlag(a5)               ;are we in grads mode?
        bne.s   CFPMx                                   ;no, then don't do anything
        movea.l pFPNum(a6),a0
        call    FPIMul(a0.l,a0.l,&r2g(a5))              ;FPNum/(200/pi)
CFPMx   movem.l (a7)+,a0/d0-d2
endproc


;
; Arc Cosine
;
proc DoACos(pExpr.l)
local DoACosTemp.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	ACosError
	call	popNum(pExpr(a6).l)		        ;get arg
	tst.b	d2
	bne.s	DoACosx
        pea.l   DoACosTemp(a6)
	move.l	d1,-(a7)
	move.l	d0,-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibACos
	lea.l	14(a7),a7
        call    ConvertFromProperMode(&DoACosTemp(a6))
	call	pushNum(pExpr(a6).l,&DoACosTemp(a6),CurrentBase(a5).w)
	bra.s	DoACosx
ACosError
	movea.l	BUILTIN.Name(a3),a0		        ;get address of symbol name
	systrap FrmCustomAlert(#ModeError.w,a0.l,&0,&0)
DoACosx move.l  (a7)+,d2
endproc

;
; Arc Sine
;
proc DoASin(pExpr.l)
local DoASinTemp.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	ASinError
	call	popNum(pExpr(a6).l)		        ;get arg
	tst.b	d2
	bne.s	DoASinx
        pea.l   DoASinTemp(a6)
	move.l	d1,-(a7)
	move.l	d0,-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibASin
	lea.l	14(a7),a7
        call    ConvertFromProperMode(&DoASinTemp(a6))
	call	pushNum(pExpr(a6).l,&DoASinTemp(a6),CurrentBase(a5).w)
	bra.s	DoASinx
ASinError
	movea.l	BUILTIN.Name(a3),a0		        ;get address of symbol name
	systrap FrmCustomAlert(#ModeError.w,a0.l,&0,&0)
DoASinx move.l  (a7)+,d2
endproc


;
; Arc Tangent
;
proc DoATan(pExpr.l)
local DoATanTemp.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	ATanError
	call	popNum(pExpr(a6).l)		        ;get arg
	tst.b	d2
	bne.s	DoATanx
        pea.l   DoATanTemp(a6)
	move.l	d1,-(a7)
	move.l	d0,-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibATan
	lea.l	14(a7),a7
        call    ConvertFromProperMode(&DoATanTemp(a6))
	call	pushNum(pExpr(a6).l,&DoATanTemp(a6),CurrentBase(a5).w)
	bra.s	DoATanx
ATanError
	movea.l	BUILTIN.Name(a3),a0		        ;get address of symbol name
	systrap FrmCustomAlert(#ModeError.w,a0.l,&0,&0)
DoATanx move.l  (a7)+,d2
endproc


;
; Cosine
;
proc DoCos(pExpr.l)
local DoCosTemp.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	CosError
	call	popNum(pExpr(a6).l)		        ;get arg
	tst.b	d2
	bne.s	DoCosx
        move.l  d0,DoCosTemp(a6)
        move.l  d1,DoCosTemp+4(a6)
        call    ConvertToProperMode(&DoCosTemp(a6))
        pea.l   DoCosTemp(a6)
	move.l	DoCosTemp+4(a6),-(a7)
	move.l	DoCosTemp(a6),-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibCos
	lea.l	14(a7),a7
	call	pushNum(pExpr(a6).l,&DoCosTemp(a6),CurrentBase(a5).w)
	bra.s	DoCosx
CosError
	movea.l	BUILTIN.Name(a3),a0		;get address of symbol name
	systrap FrmCustomAlert(#ModeError.w,a0.l,&0,&0)
DoCosx  move.l  (a7)+,d2
endproc


;
; Sine
;
proc DoSin(pExpr.l)
local DoSinTemp.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	SinError
	call	popNum(pExpr(a6).l)		        ;get arg
	tst.b	d2
	bne.s	DoSinx
        move.l  d0,DoSinTemp(a6)
        move.l  d1,DoSinTemp+4(a6)
        call    ConvertToProperMode(&DoSinTemp(a6))
        pea.l   DoSinTemp(a6)
	move.l	DoSinTemp+4(a6),-(a7)
	move.l	DoSinTemp(a6),-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibSin
	lea.l	14(a7),a7
	call	pushNum(pExpr(a6).l,&DoSinTemp(a6),CurrentBase(a5).w)
	bra.s	DoSinx
SinError
	movea.l	BUILTIN.Name(a3),a0		        ;get address of symbol name
	systrap FrmCustomAlert(#ModeError.w,a0.l,&0,&0)
DoSinx  move.l  (a7)+,d2
endproc


;
; Tangent
;
proc DoTan(pExpr.l)
local DoTanTemp.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	TanError
	call	popNum(pExpr(a6).l)		        ;get arg
	tst.b	d2
	bne.s	DoTanx
        move.l  d0,DoTanTemp(a6)
        move.l  d1,DoTanTemp+4(a6)
        call    ConvertToProperMode(&DoTanTemp(a6))
        pea.l   DoTanTemp(a6)
	move.l	DoTanTemp+4(a6),-(a7)
	move.l	DoTanTemp(a6),-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibTan
	lea.l	14(a7),a7
	call	pushNum(pExpr(a6).l,&DoTanTemp(a6),CurrentBase(a5).w)
	bra.s	DoTanx
TanError
	movea.l	BUILTIN.Name(a3),a0		        ;get address of symbol name
	systrap FrmCustomAlert(#ModeError.w,a0.l,&0,&0)
DoTanx  move.l  (a7)+,d2
endproc


;
; e**x 
;
proc DoExp(pExpr.l)
local DoExpTemp.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	ExpError
	call	popNum(pExpr(a6).l)		        ;get arg
	tst.b	d2
	bne.s	DoExpx
        pea.l   DoExpTemp(a6)
	move.l	d1,-(a7)
	move.l	d0,-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibExp
	lea.l	14(a7),a7
	call	pushNum(pExpr(a6).l,&DoExpTemp(a6),CurrentBase(a5).w)
	bra.s	DoExpx
ExpError
	movea.l	BUILTIN.Name(a3),a0		        ;get address of symbol name
	systrap FrmCustomAlert(#ModeError.w,a0.l,&0,&0)
DoExpx  move.l  (a7)+,d2
endproc


;
; Cube root
;
proc DoCbrt(pExpr.l)
local DoCbrtTemp.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	CbrtError
	call	popNum(pExpr(a6).l)		        ;get arg
	tst.b	d2
	bne.s	DoCbrtx
        pea.l   DoCbrtTemp(a6)
	move.l	d1,-(a7)
	move.l	d0,-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibCbrt
	lea.l	14(a7),a7
	call	pushNum(pExpr(a6).l,&DoCbrtTemp(a6),CurrentBase(a5).w)
	bra.s	DoCbrtx
CbrtError
	movea.l	BUILTIN.Name(a3),a0		        ;get address of symbol name
	systrap FrmCustomAlert(#ModeError.w,a0.l,&0,&0)
DoCbrtx move.l  (a7)+,d2
endproc


;
; Hyperbolic Arc Cosine
;
proc DoACosh(pExpr.l)
local DoACoshTemp.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	ACoshError
	call	popNum(pExpr(a6).l)		        ;get arg
	tst.b	d2
	bne.s	DoACoshx
        pea.l   DoACoshTemp(a6)
	move.l	d1,-(a7)
	move.l	d0,-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibACosH
	lea.l	14(a7),a7
	call	pushNum(pExpr(a6).l,&DoACoshTemp(a6),CurrentBase(a5).w)
	bra.s	DoACoshx
ACoshError
	movea.l	BUILTIN.Name(a3),a0		        ;get address of symbol name
	systrap FrmCustomAlert(#ModeError.w,a0.l,&0,&0)
DoACoshx 
        move.l (a7)+,d2
endproc


;
; Hyperbolic Arc Sine
;
proc DoASinh(pExpr.l)
local DoASinhTemp.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	ASinhError
	call	popNum(pExpr(a6).l)		        ;get arg
	tst.b	d2
	bne.s	DoASinhx
        pea.l   DoASinhTemp(a6)
	move.l	d1,-(a7)
	move.l	d0,-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibASinH
	lea.l	14(a7),a7
	call	pushNum(pExpr(a6).l,&DoASinhTemp(a6),CurrentBase(a5).w)
	bra.s	DoASinhx
ASinhError
	movea.l	BUILTIN.Name(a3),a0		        ;get address of symbol name
	systrap FrmCustomAlert(#ModeError.w,a0.l,&0,&0)
DoASinhx
        move.l  (a7)+,d2
endproc


;
; Hyperbolic Arc Tangent
;
proc DoATanh(pExpr.l)
local DoATanhTemp.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	ATanhError
	call	popNum(pExpr(a6).l)		        ;get arg
	tst.b	d2
	bne.s	DoATanhx
        pea.l   DoATanhTemp(a6)
	move.l	d1,-(a7)
	move.l	d0,-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibATanH
	lea.l	14(a7),a7
	call	pushNum(pExpr(a6).l,&DoATanhTemp(a6),CurrentBase(a5).w)
	bra.s	DoATanhx
ATanhError
	movea.l	BUILTIN.Name(a3),a0		        ;get address of symbol name
	systrap FrmCustomAlert(#ModeError.w,a0.l,&0,&0)
DoATanhx
        move.l  (a7)+,d2
endproc


;
; Hyperbolic Cosine
;
proc DoCosh(pExpr.l)
local DoCoshTemp.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	CoshError
	call	popNum(pExpr(a6).l)		        ;get arg
	tst.b	d2
	bne.s	DoCoshx
        pea.l   DoCoshTemp(a6)
	move.l	d1,-(a7)
	move.l	d0,-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibCosH
	lea.l	14(a7),a7
	call	pushNum(pExpr(a6).l,&DoCoshTemp(a6),CurrentBase(a5).w)
	bra.s	DoCoshx
CoshError
	movea.l	BUILTIN.Name(a3),a0		        ;get address of symbol name
	systrap FrmCustomAlert(#ModeError.w,a0.l,&0,&0)
DoCoshx move.l  (a7)+,d2
endproc


;
; Hyperbolic Sine
;
proc DoSinh(pExpr.l)
local DoSinhTemp.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	SinhError
	call	popNum(pExpr(a6).l)		        ;get arg
	tst.b	d2
	bne.s	DoSinhx
        pea.l   DoSinhTemp(a6)
	move.l	d1,-(a7)
	move.l	d0,-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibSinH
	lea.l	14(a7),a7
	call	pushNum(pExpr(a6).l,&DoSinhTemp(a6),CurrentBase(a5).w)
	bra.s	DoSinhx
SinhError
	movea.l	BUILTIN.Name(a3),a0		        ;get address of symbol name
	systrap FrmCustomAlert(#ModeError.w,a0.l,&0,&0)
DoSinhx move.l  (a3)+,d2
endproc


;
; Hyperbolic Tangent
;
proc DoTanh(pExpr.l)
local DoTanhTemp.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	TanhError
	call	popNum(pExpr(a6).l)		        ;get arg
	tst.b	d2
	bne.s	DoTanhx
        pea.l   DoTanhTemp(a6)
	move.l	d1,-(a7)
	move.l	d0,-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibTanH
	lea.l	14(a7),a7
	call	pushNum(pExpr(a6).l,&DoTanhTemp(a6),CurrentBase(a5).w)
	bra.s	DoTanhx
TanhError
	movea.l	BUILTIN.Name(a3),a0		        ;get address of symbol name
	systrap FrmCustomAlert(#ModeError.w,a0.l,&0,&0)
DoTanhx move.l  (a7)+,d2
endproc


;
; Natural Logorithm
;
proc DoLog(pExpr.l)
local DoLogTemp.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	LogError
	call	popNum(pExpr(a6).l)		        ;get arg
	tst.b	d2
	bne.s	DoLogx
        pea.l   DoLogTemp(a6)
	move.l	d1,-(a7)
	move.l	d0,-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibLog
	lea.l	14(a7),a7
	call	pushNum(pExpr(a6).l,&DoLogTemp(a6),CurrentBase(a5).w)
	bra.s	DoLogx
LogError
	movea.l	BUILTIN.Name(a3),a0		        ;get address of symbol name
	systrap FrmCustomAlert(#ModeError.w,a0.l,&0,&0)
DoLogx  move.l  (a7)+,d2
endproc


;
; Base 10 Logorithm
;
proc DoLog10(pExpr.l)
local DoLog10Temp.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	Log10Error
	call	popNum(pExpr(a6).l)		        ;get arg
	tst.b	d2
	bne.s	DoLog10x
        pea.l   DoLog10Temp(a6)
	move.l	d1,-(a7)
	move.l	d0,-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibLog10
	lea.l	14(a7),a7
	call	pushNum(pExpr(a6).l,&DoLog10Temp(a6),CurrentBase(a5).w)
	bra.s	DoLog10x
Log10Error
	movea.l	BUILTIN.Name(a3),a0		        ;get address of symbol name
	systrap FrmCustomAlert(#ModeError.w,a0.l,&0,&0)
DoLog10x
        move.l  (a7)+,d2
endproc


;
; Square root
;
proc DoSqrt(pExpr.l)
local DoSqrtTemp.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	SqrtError
	call	popNum(pExpr(a6).l)		        ;get arg
	tst.b	d2
	bne.s	DoSqrtx
        pea.l   DoSqrtTemp(a6)
	move.l	d1,-(a7)
	move.l	d0,-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibSqrt
	lea.l	14(a7),a7
	call	pushNum(pExpr(a6).l,&DoSqrtTemp(a6),CurrentBase(a5).w)
	bra.s	DoSqrtx
SqrtError
	movea.l	BUILTIN.Name(a3),a0		        ;get address of symbol name
	systrap FrmCustomAlert(#ModeError.w,a0.l,&0,&0)
DoSqrtx move.l  (a7)+,d2
endproc


;
; x**y
;
proc DoPow(pExpr.l)
local DPOp1.8
local DPOp2.8
local DoPowTemp.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	PowBin
	call	popNum(pExpr(a6).l)		        ;get arg 1
	tst.b	d2
	bne	DoPowx
        move.l  d0,DPOp1(a6)
        move.l  d1,DPOp1+4(a6)
	call	popNum(pExpr(a6).l)		        ;get arg 2
	tst.b	d2
	bne	DoPowx
        pea.l   DoPowTemp(a6)
	move.l	DPOp1+4(a6),-(a7)
	move.l	DPOp1(a6),-(a7)
	move.l	d1,-(a7)
	move.l	d0,-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibPow
	lea.l	22(a7),a7
	call	pushNum(pExpr(a6).l,&DoPowTemp(a6),CurrentBase(a5).w)
	bra	DoPowx
PowBin
	call	popNum(pExpr(a6).l)			
	tst.b	d2
	bne	DoPowx
	move.l	d0,DPOp1(a6)
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne.s	DoPowx
	move.l	d0,DPOp2(a6)
        call    FPILongToFloat(&DPOp1(a6),DPOp1(a6).l)
        call    FPILongToFloat(&DPOp2(a6),DPOp2(a6).l)
        pea.l   DoPowTemp(a6)
	move.l	DPOp1+4(a6),-(a7)
	move.l	DPOp1(a6),-(a7)
	move.l	DPOp2+4(a6),-(a7)
	move.l	DPOp2(a6),-(a7)
        move.w  MathLibRef(a5),-(a7)
	trap	#15					
	dc.w	sysTrapMathLibPow
	lea.l	22(a7),a7
        call    FPIFloatToLong(&DoPowTemp(a6))
	call	pushNum(pExpr(a6).l,d0.l,CurrentBase(a5).w)
        bra.s   DoPowx
PowError
	movea.l	BUILTIN.Name(a3),a0		        ;get address of symbol name
	systrap FrmCustomAlert(#ModeError.w,a0.l,&0,&0)
DoPowx  move.l  (a7)+,d2
endproc

;
; x+y
;
proc DoADD(pExpr.l)
local DoAddTemp.8
local DoAddOp1.8
local DoAddOp2.8
beginproc
	movem.l	d2/a3,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	AddBin
	call	popNum(pExpr(a6).l)		        ;get arg 1
	tst.b	d2
	bne 	DoADDx
	move.l	d0,DoAddOp1(a6)                         ;save operand 1
        move.l  d1,DoAddOp1+4(a6)
	call	popNum(pExpr(a6).l)		        ;get arg 2
	tst.b	d2
	bne	DoADDx
        move.l  d0,DoAddOp2(a6)
        move.l  d1,DoAddOp2+4(a6)
        call    FPIAdd(&DoAddTemp(a6),&DoAddOp1(a6),&DoAddOp2(a6))
	call	pushNum(pExpr(a6).l,&DoAddTemp(a6),CurrentBase(a5).w)
	bra.s	DoADDx
AddBin	
	call	popNum(pExpr(a6).l)			
	tst.b	d2
	bne.s	DoADDx
	move.l	d0,DoAddOp1(a6)
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne.s	DoADDx
	add.l	d0,DoAddOp1(a6)
	call	pushNum(pExpr(a6).l,DoAddOp1(a6).l,CurrentBase(a5).w)
DoADDx
	movem.l	(a7)+,d2/a3
endproc

;
; x-y
;
proc DoSUB(pExpr.l)
local DoSubTemp.8
local DoSubOp1.8
local DoSubOp2.8
beginproc
	movem.l	d2/a3,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	SubBin
	call	popNum(pExpr(a6).l)		        ;get arg 1
	tst.b	d2
	bne	DoSUBx
	move.l	d0,DoSubOp2(a6)                         ;save operand 1
        move.l  d1,DoSubOp2+4(a6)
	call	popNum(pExpr(a6).l)		        ;get arg 2
	tst.b	d2
	bne.s	DoSUBx
	move.l	d0,DoSubOp1(a6)                         ;save operand 1
        move.l  d1,DoSubOp1+4(a6)
        call    FPISub(&DoSubTemp(a6),&DoSubOp1(a6),&DoSubOp2(a6))
	call	pushNum(pExpr(a6).l,&DoSubTemp(a6),CurrentBase(a5).w)
	bra.s	DoSUBx
SubBin	
	call	popNum(pExpr(a6).l)			
	tst.b	d2
	bne.s	DoSUBx
	move.l	d0,DoSubOp2(a6)
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne.s	DoSUBx
        move.l  DoSubOp2(a6),d1
	sub.l	d1,d0
	call	pushNum(pExpr(a6).l,d0.l,CurrentBase(a5).w)
DoSUBx
	movem.l	(a7)+,d2/a3
endproc

;
; x*y
;
proc DoMUL(pExpr.l)
local DoMulTemp.8
local DoMulOp1.8
local DoMulOp2.8
beginproc
	movem.l	d2/a3,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	MulBin
	call	popNum(pExpr(a6).l)		        ;get arg 1
	tst.b	d2
	bne	DoMULx
        move.l  d0,DoMulOp1(a6)                         ;save operand 1
        move.l  d1,DoMulOp1+4(a6)      
	call	popNum(pExpr(a6).l)		        ;get arg 2
	tst.b	d2
	bne	DoMULx
        move.l  d0,DoMulOp2(a6)                         ;save operand 1
        move.l  d1,DoMulOp2+4(a6)      
        call    FPIMul(&DoMulTemp(a6),&DoMulOp1(a6),&DoMulOp2(a6))
	call	pushNum(pExpr(a6).l,&DoMulTemp(a6),CurrentBase(a5).w)
	bra.s	DoMULx
MulBin	
	call	popNum(pExpr(a6).l)			
	tst.b	d2
	bne.s	DoMULx
	move.l	d0,DoMulOp1(a6)
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne.s	DoMULx
	call	LongMultiply(d0.l,DoMulOp1(a6).l)
	call	pushNum(pExpr(a6).l,d0.l,CurrentBase(a5).w)
DoMULx
	movem.l	(a7)+,d2/a3
endproc

;
; x/y
;
proc DoDIV(pExpr.l)
local DoDivTemp.8
local DoDivOp1.8
local DoDivOp2.8
beginproc
	movem.l	d2/a3,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	DivBin
	call	popNum(pExpr(a6).l)		        ;get arg 1
	tst.b	d2
	bne	DoDIVx
	move.l	d0,DoDivOp1(a6)                          ;save operand 1
        move.l  d1,DoDivOp1+4(a6)
	call	popNum(pExpr(a6).l)		        ;get arg 2
	tst.b	d2
	bne	DoDIVx
	move.l	d0,DoDivOp2(a6)                          ;save operand 1
        move.l  d1,DoDivOp2+4(a6)
        call    FPIDiv(&DoDivTemp(a6),&DoDivOp2(a6),&DoDivOp1(a6))
	call	pushNum(pExpr(a6).l,&DoDivTemp(a6),CurrentBase(a5).w)
	bra.s	DoDIVx
DivBin	
	call	popNum(pExpr(a6).l)			
	tst.b	d2
	bne.s	DoDIVx
	move.l	d0,DoDivOp1(a6)
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne.s	DoDIVx
        cmp.l   #0,DoDivOp1(a6)
        bne.s   DivBinOK
	call	Error(pExpr(a6).l,&ErrorDBZ(a5))
        bra.s   DoDIVx
DivBinOK
	call	LongDivide(d0.l,DoDivOp1(a6).l)
	call	pushNum(pExpr(a6).l,d0.l,CurrentBase(a5).w)
DoDIVx
	movem.l	(a7)+,d2/a3
endproc

;
; x mod y
;
proc DoMOD(pExpr.l)
local MODTemp.8
local MODTemp2.8
local MODOp1.8
local MODOp2.8
beginproc
	movem.l	d2/a3,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne	ModBin
	call	popNum(pExpr(a6).l)		        ;get arg 2
	tst.b	d2
	bne	DoMODx
	move.l	d0,MODOp2(a6)
        move.l  d1,MODOp2+4(a6)
	call	popNum(pExpr(a6).l)		        ;get arg 1
	tst.b	d2
	bne	DoMODx
	move.l	d0,MODOp1(a6)
        move.l  d1,MODOp1+4(a6)
        call    FPIDiv(&MODTemp2(a6),&MODOp1(a6),&MODOp2(a6)) 
        call    FPIFloatToLong(&MODTemp2(a6))                 
        call    FPILongToFloat(&MODTemp2(a6),d0.l)             
        call    FPIMul(&MODTemp2(a6),&MODOp2(a6),&MODTemp2(a6))
        call    FPISub(&MODTemp(a6),&MODOp1(a6),&MODTemp2(a6))
	call	pushNum(pExpr(a6).l,&MODTemp(a6),CurrentBase(a5).w)
	bra.s	DoMODx
ModBin	
	call	popNum(pExpr(a6).l)			
	tst.b	d2
	bne.s	DoMODx
	move.l	d0,MODOp1(a6)
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne.s	DoMODx
	call	LongRemainder(d0.l,MODOp1(a6).l)
	call	pushNum(pExpr(a6).l,d0.l,CurrentBase(a5).w)
DoMODx
	movem.l	(a7)+,d2/a3
endproc

;
; -x
;
proc DoNEG(pExpr.l)
local DoNegTemp.8
local NEGOp1.8
beginproc
        move.l  d2,-(a7)
	cmp.w	#$7fff,CurrentBase(a5)		        ;FP?
	bne.s	NegBin
	call	popNum(pExpr(a6).l)		        ;get arg
	tst.b	d2
	bne.s	DoNEGx
        move.l  d0,NEGOp1(a6)
        move.l  d1,NEGOp1+4(a6)
        call    FPINeg(&NEGOp1(a6))
	call	pushNum(pExpr(a6).l,a0.l,CurrentBase(a5).w)
	bra.s	DoNEGx
NegBin	
	call	popNum(pExpr(a6).l)			
	tst.b	d2
	bne.s	DoNEGx
	neg.l	d0
	call	pushNum(pExpr(a6).l,d0.l,CurrentBase(a5).w)
DoNEGx  move.l  (a7)+,d2
endproc

proc DoAND(pExpr.l)
local DoANDOp1.l
beginproc
        move.l  d2,-(a7)
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne.s	DoANDx
	move.l	d0,DoANDOp1(a6)
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne.s	DoANDx
	and.l	d0,DoANDOp1(a6)
	call	pushNum(pExpr(a6).l,DoANDOp1(a6).l,#16.w)
DoANDx  move.l  (a7)+,d2
endproc

proc DoOR(pExpr.l)
local DoOROp1.l
beginproc
        move.l  d2,-(a7)
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne.s	DoORx
	move.l	d0,DoOROp1(a6)
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne.s	DoORx
	or.l	d0,DoOROp1(a6)
	call	pushNum(pExpr(a6).l,DoOROp1(a6).l,#16.w)
DoORx   move.l  (a7)+,d2
endproc

proc DoXOR(pExpr.l)
local DoXOROp1.l
beginproc
        move.l  d2,-(a7)
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne.s	DoXORx
	move.l	d0,DoXOROp1(a6)
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne.s	DoXORx
	eor.l	d0,DoXOROp1(a6)
	call	pushNum(pExpr(a6).l,DoXOROp1(a6).l,#16.w)
DoXORx  move.l  (a7)+,d2
endproc

;
; Boolean functions: and, or, xor, left shift, right shift,
;                    left rotate, and right rotate
;
proc DoBoolean(pExpr.l,op.w)
local DoBoolOp1.l
beginproc
	move.l	d2,-(a7)		                ;save reg d2
	cmp.w	#NOT,op(a6)
	bne.s	ChkLShift
	call	popNum(pExpr(a6).l)	                ;get last stack entry
	tst.b	d2
	bne	DoBx
	not.l	d0			                ;not and new result
	bra	PushResult
ChkLShift
	cmp.w	#LSHIFT,op(a6)
	bne.s	ChkRShift
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne	DoBx
	move.l	d0,DoBoolOp1(a6)
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne	DoBx
        move.l  DoBoolOp1(a6),d2
	lsl.l	d2,d0
	bra	PushResult
ChkRShift
	cmp.w	#RSHIFT,op(a6)
	bne.s	ChkLRotate
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne	DoBx
	move.l	d0,DoBoolOp1(a6)
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne.s	DoBx
        move.l  DoBoolOp1(a6),d2
	lsr.l	d2,d0
	bra.s	PushResult
ChkLRotate
	cmp.w	#LROTATE,op(a6)
	bne.s	ChkRRotate
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne	DoBx
	move.l	d0,DoBoolOp1(a6)
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne	DoBx
        move.l  DoBoolOp1(a6),d2
	rol.l	d2,d0
	bra.s	PushResult
ChkRRotate
	cmp.w	#RROTATE,op(a6)
	bne.s	DoBx
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne.s	DoBx
	move.l	d0,DoBoolOp1(a6)
	call	popNum(pExpr(a6).l)
	tst.b	d2
	bne.s	DoBx
        move.l  DoBoolOp1(a6),d2
	ror.l	d2,d0
PushResult		
	call	pushNum(pExpr(a6).l,d0.l,#16.w)
DoBx
	move.l	(a7)+,d2
endproc

;
; This function is used to flip network MAC addresses that get
; bit reversed when bridged between token-ring and ethernet
;
; The routine takes a number such as ECA2 and flips it to 3745
; 1110 1100 1010 0010
;    \  /      \  /
;    /  \      /  \
; 0011 0111 0100 0101
;
; Each bytes is essentially reversed and then repackaged
;
proc DoMAC(pExpr.l)
local bitResult.l
beginproc
        movem.l d1-d3,-(a7)                             ;save regs
        cmp.w   #$7fff,CurrentBase(a5)                  ;floating mode?
        beq.s   MACx                                    ;can't do this in fp mode
	call	popNum(pExpr(a6).l)	                ;get arg
	tst.b	d2                                      
	bne.s	MACx                                    
        clr.l   bitResult(a6)                           ;clear result field
        clr.l   d3                                      ;counter
bytloop move.b  #8,d1                                   
bitloop lsl.l   #1,d0                                   ;shift the bit into carry
        roxr.l  #1,d2                                   ;and rotate it into d2
        subq.b  #1,d1                                   
        bne.s   bitloop                                 
        swap    d2                                      ;put result in bits 8-15
        lsr.w   #8,d2                                   ;put result in bits 0-7
        move.b  d2,bitResult(a6,d3)                     ;save byte
        addq.w  #1,d3                                   
        cmp.w   #4,d3                                   ;done?
        blt.s   bytloop                                 
       	call	pushNum(pExpr(a6).l,bitResult(a6).l,#16.w)
MACx    movem.l (a7)+,d1-d3                             ;restore regs
endproc

;******************************************************************************
;*            S T A C K   M A N I P U L A T I O N   F U N C T I O N S         *
;******************************************************************************

proc pushNum(pExpr.l,NewEntry.l,EntryBase.w)
beginproc
        call    pushNumericValue(pExpr(a6).l,NewEntry(a6).l,EntryBase(a6).w) ;first push the number
        call    pushEntry(pExpr(a6).l,#tNUM.l,#0.l)                 ;push token for NUM
endproc

proc popNum(pExpr.l)
beginproc
popNumTok
        call    popToken(pExpr(a6).l)                   ;get next token
        cmp.w   #tID,d0                                 ;is it an ID entry?
        beq.s   popNUMID
        cmp.w   #tNUM,d0                                ;is it a NUM?
        beq.s   popNUMEnt                               ;yep, do it
	call	Error(pExpr(a6).l,&ExpectedNum(a5))
        move.b  #1,d2                                   ;indicate failure
        bra.s   popNUMx
popNUMEnt  
        call    popEntry(pExpr(a6).l)                   ;get num in d0/d1
        bra.s   popNUMx
popNUMID
        call    popEntry(pExpr(a6).l)                   ;get ID in d0
        movea.l pExpr(a6),a1                            ;get parent pgm ptr
	call	DoPgm(d0.w,PGM.ignore(a1).w)	        ;do program
        clr.b   d2
popNUMx 
endproc

proc popString(pExpr.l)
beginproc
        call    popToken(pExpr(a6).l)                   ;get next token
        cmp.w   #tSTRING,d0                             ;is it a STRING?
        beq.s   popSTRINGEnt                            ;yep, do it
	call	Error(pExpr(a6).l,&ExpectedString(a5))
        move.b  #1,d2                                   ;indicate failure
        bra.s   popStringx
popSTRINGEnt
        call    popEntry(pExpr(a6).l)                   ;get string in d0
        move.l  d0,a0                                   ;put it in a0
popStringx
endproc

proc popID(pExpr.l)
beginproc
        call    popToken(pExpr(a6).l)                   ;get next token
        cmp.w   #tID,d0                                 ;is it a ID?
        beq.s   popIDEnt                                ;yep, do it
	call	Error(pExpr(a6).l,&ExpectedID(a5))
        move.b  #1,d2                                   ;indicate failure
        bra.s   popIDx
popIDEnt
        call    popEntry(pExpr(a6).l)                   ;get entry
popIDx
endproc


proc pushString(pExpr.l,NewString.l)
beginproc
        call    pushEntry(pExpr(a6).l,NewString(a6).l,#0.l)        ;push address of string
        call    pushEntry(pExpr(a6).l,#tSTRING.l,#0.l)             ;push token for STRING
endproc

proc pushID(pExpr.l,NewID.w)
beginproc
        move.w  NewID(a6),d0
        ext.l   d0
        call    pushEntry(pExpr(a6).l,d0.l,#0.l)                   ;push address of ID
        call    pushEntry(pExpr(a6).l,#tID.l,#0.l)                 ;push token for ID
endproc

proc pushEntry(pExpr.l,aLong1.l,aLong2.l)
beginproc
        move.l  a3,-(a7)
        movea.l pExpr(a6),a3                            ;get pgm ptr
	cmp.w	#MAXSTACK,PGM.tokidx(a3)                ;are we at maxstack?
	blt.s	pushEntryOK
pushOvfl
	call	Error(pExpr(a6).l,&StackOverflow(a5))   ;"Stack Overflow"
	move.b	#true,d2		        	;error
	bra.s   pushEntryx
pushEntryOK
        systrap MemHandleLock(PGM.stack(a3).l)           ;lock chunk
	move.w	PGM.tokidx(a3),d0		        ;get stack index
	move.l	aLong1(a6),(a0,d0)	        	;push entry
        move.l  aLong2(a6),4(a0,d0)                     ; and second word, if any
	addq.w	#8,PGM.tokidx(a3)	        	;increment stack position
        systrap MemHandleUnlock(PGM.stack(a3).l)         ;unlock chunk
        systrap MemHandleSize(PGM.stack(a3).l)           ;get chunk size
        cmp.w   PGM.tokidx(a3),d0                       ;compare against stack index
        bgt.s   pushEntryx                              ;if bigger, than we're all set
        add.w   #STACKINCREMENT,d0                      ;add increment
        cmp.w   #MAXSTACK,d0                            ;over?
        bge     pushOvfl
        ext.l   d0                                      ;size is a long for resize
        systrap MemHandleResize(PGM.stack(a3).l,d0.l)    ;resize stack
        tst.b   d0
        bne.s   pushOvfl                                ;if stack can't grow, then overflowed
pushEntryx
        move.l  (a7)+,a3
endproc

proc popEntry(pExpr.l)
local popTempd0.l
local popTempd1.l
beginproc
        move.l  a3,-(a7)
        movea.l pExpr(a6),a3                            ;get pgm ptr
        clr.b   d1
	cmp.w	#8,PGM.tokidx(a3)	        	;is there an entry to pop?
	bge.s	popEntryOK
	call	Error(pExpr(a6).l,&StackUnderflow(a5))	;"Stack Underflow"
        move.b  #1,d2                                   ;indicate failure
	bra.s	popEntryx
popEntryOK
        systrap MemHandleLock(PGM.stack(a3).l)           ;lock chunk
	subq.w	#8,PGM.tokidx(a3)
        move.w  PGM.tokidx(a3),d0
        lea.l   (a0,d0),a0                              ;point to entry
	move.l	(a0),popTempd0(a6)                      ;save 
        move.l  4(a0),popTempd1(a6)
        systrap MemHandleUnlock(PGM.stack(a3).l)         ;unlock chunk
        move.l  popTempd0(a6),d0                        ;entry in d0/d1 
        move.l  popTempd1(a6),d1                        
        clr.b   d2                                      ;indicate success
popEntryx
        move.l  (a7)+,a3
endproc


; Pops the next token from the stack

proc popToken(pExpr.l)
beginproc
        call    popEntry(pExpr(a6).l)                   ;get token of entry
        tst.b   d2
        bne.s   popTokenx                               ;just return on popentry failure
        cmp.w   #tNUM,d0                                ;is it a numeric constant?
        beq.s   popTokenx
        cmp.w   #tSTRING,d0
        beq.s   popTokenx
        cmp.w   #tID,d0
        beq.s   popTokenx
	call	Error(pExpr(a6).l,&TokenError(a5))      ;"Token error..."
popTokenx
endproc


;
; Push numeric entry on the stack
;  if binary mode, NewEntry(a6) contains the 32 bit value to push
;  if decimal mode, NewEntry(a6) contains a pointer to the float to push
;  if the stack is full then an error is generated.
;
; returns, d1 = 0 on success else d1 = 1
;
proc pushNumericValue(pExpr.l,NewEntry.l,EntryBase.w)
local TempPush.8
beginproc
	cmp.w	#$7fff,CurrentBase(a5)		        ;is it FP mode?
	bne.s	PushBin
	cmp.w	#$7fff,EntryBase(a6)		        ;is NewEntry float?
	beq.s	push10
	; convert this binary to float
        call    FPILongToFloat(&TempPush(a6),NewEntry(a6).l)
        lea.l   TempPush(a6),a0
	bra.s	pushFlt	
push10	movea.l	NewEntry(a6),a0			        ;get address of float to push
pushFlt	move.l  0(a0),d0
        move.l  4(a0),d1
        call    pushEntry(pExpr(a6).l,d0.l,d1.l)
	bra.s	PushOK
PushBin	cmp.w	#$7fff,EntryBase(a6)		        ;is NewEntry float?
	bne.s	pushbn2				        ;no, then binary
	movea.l	NewEntry(a6),a0			        ;get address of float
        call    FPIFloatToULong(a0.l)
	bra.s	pushbn3				        ;d0 = converted float
pushbn2 move.l	NewEntry(a6),d0			        ;get entry to push on stack
pushbn3	
        call    pushEntry(pExpr(a6).l,d0.l,#0.l)        ;push it
PushOK	clr.b	d1
pushx 
endproc


;******************************************************************************
;*            S Y M B O L   M A N I P U L A T I O N   F U N C T I O N S       *
;******************************************************************************

proc FreeKeyTab()
beginproc
	movem.l	d3/a3,-(a7)
	move.l	#24,d3				        ;count of key tab entries
	movea.l	KeyTab(a5),a3			        ;get starting address of key tab
FKTFree	                                                
	movea.l	KEYTAB.KeyText(a3),a0		        ;get address of key name
	cmpa.l	#0,a0                                   
	beq.s	FKTFreSym                                 
	systrap	MemPtrFree(a0.l)		        ;free it
FKTFreSym
        movea.l KEYTAB.KeySym(a3),a0
        cmpa.l  #0,a0
        beq.s   FKTNext
        systrap MemPtrFree(a0.l)
FKTNext	lea	KEYTABSIZE(a3),a3		        ;point to next entry
	subq.l	#1,d3
	bne.s	FKTFree		
FKTx	movem.l	(a7)+,d3/a3
endproc


proc SetKeyTab(pSymName.l,pKeyText.l,KeyCode.w)
local KeyTabRec.l
local KeyTabIdx.w
beginproc
	movem.l	d2/a3-a4,-(a7)
	movea.l	KeyTab(a5),a3
	move.w	KeyCode(a6),d0
	sub.w	#KEY0,d0			        ;Relative to 0
	mulu.w	#KEYTABSIZE,d0                          
	lea	(a3,d0),a3			        ;point to correct entry
	movea.l	pKeyText(a6),a4                         
	systrap	StrLen(a4.l)
        ext.l   d0                            
	addq.l	#1,d0                                   
	systrap	MemPtrNew(d0.l)			        ;allocate space for key text
	move.l	a0,KEYTAB.KeyText(a3)                   
	systrap	StrCopy(a0.l,a4.l)		        ;copy text
	movea.l	pSymName(a6),a4
	systrap	StrLen(a4.l)
        ext.l   d0
	addq.l	#1,d0
	systrap	MemPtrNew(d0.l)
	move.l	a0,KEYTAB.KeySym(a3)
	systrap	StrCopy(a0.l,a4.l)
	move.w	KeyCode(a6),d0			        ;save
	move.w	d0,KEYTAB.KeyCode(a3)		        ; key code
        
        ;
        ; Now that the KEYTAB entry is created, update the database record
        ; 
        move.w  KeyCode(a6),d0
        sub.w   #KEY0,d0
        move.w  d0,KeyTabIdx(a6)                        ;save record number

        systrap MemPtrNew(#32.l)                        ;get a buffer larger than we need
        move.l  a0,a4
        move.l  a0,KeyTabRec(a6)                        ;and save it in local 
        move.w  KeyTabIdx(a6),d0
        move.b  d0,(a4)+                                ;save key #

        systrap StrCopy(a4.l,KEYTAB.KeySym(a3).l)       ;copy string
        systrap StrLen(KEYTAB.KeySym(a3).l)             ;get the string length
        lea.l   (a4,d0),a4                              ;increment pointer
        move.b  #0,(a4)+                                ;make sure term null
        
        ; now, copy the key table text

        systrap StrCopy(a4.l,KEYTAB.KeyText(a3).l)      ;copy string
        systrap StrLen(KEYTAB.KeySym(a3).l)             ;get the string length
        lea.l   (a4,d0),a4                              ;increment pointer
        move.b  #0,(a4)+                                ;make sure term null
        suba.l  KeyTabRec(a6),a4                        ;calculate length

        call    ReplaceRecord(&KeyTabIdx(a6),KeyTabRec(a6).l,a4.l)

        systrap MemPtrFree(KeyTabRec(a6).l)             ;free storage

	movem.l	(a7)+,d2/a3-a4
endproc

proc RefreshFromKeyTab(pForm.l)
beginproc
	movem.l	d4/a3-a4,-(a7)
	move.l	#12,d4
	movea.l	KeyTab(a5),a3
	tst.w	KeyPage(a5)
	beq.s	RFKTLoop
	lea.l	KEYTABSIZE*12(a3),a3
RFKTLoop
	move.w	KEYTAB.KeyCode(a3),d0
	bne.s	RFKTNotEmpty
	lea	SquareDot(a5),a4
	bra.s	RFKTCont
RFKTNotEmpty
	movea.l	KEYTAB.KeyText(a3),a4
RFKTCont
	tst.w	KeyPage(a5)
	beq.s	RFKTSetLbl
	sub.w	#12,d0
RFKTSetLbl
        systrap FrmGetObjectIndex(pForm(a6).l,d0.w)
        systrap FrmGetObjectPtr(pForm(a6).l,d0.w)
        systrap	CtlSetLabel(a0.l,a4.l)
RFKTNext
	lea	KEYTABSIZE(a3),a3
	subq.l	#1,d4
	bne.s	RFKTLoop
	movem.l	(a7)+,d4/a3-a4
endproc

proc AdjustForPage(KeyCode.w)
beginproc
	move.w	KeyCode(a6),d0
	cmp.w	#KEY0,d0
	blt.s	AFPx
	cmp.w	#KEY11,d0
	bgt.s	AFPx
	tst.w	KeyPage(a5)			        ;page 1?
	beq.s	AFPx
	add.w	#12,d0				        ;add resource id for 2nd page lookup
AFPx
endproc

proc FindKeyTabSymbol(KeyCode.w)
beginproc
	lea	0,a0
	move.w	KeyCode(a6),d0
	cmp.w	#KEY0,d0
	blt.s	KTx
	cmp.w	#KEY23,d0
	bgt.s	KTx
	sub.w	#KEY0,d0			        ;rel to 0
	mulu.w	#KEYTABSIZE,d0                          
	movea.l	KeyTab(a5),a0			        ;get starting address of table
	lea	(a0,d0),a1			        ;point to entry
	movea.l	KEYTAB.KeySym(a1),a0                    ;get symbol addr
KTx
endproc


proc DeleteSymbol(pDelSymName.l)
beginproc
	movem.l	d2/a3-a4,-(a7)
        call    GetSymbol(pDelSymName(a6).l)            ;get symbol entry and rec number
        tst.w   d0                                      ;found?
        beq.s   DSx                                     ;no, already deleted
        systrap DmRemoveRecord(hDB(a5).l,d0.w)          ;remove the record
DSx	movem.l	(a7)+,d2/a3-a4
endproc


proc GetSymbolName(recidx.w)
beginproc
        movem.l a3-a4,-(a7)
        call    GetRecord(recidx(a6).w)                 ;read record n
        move.l  a0,a3
        cmp.l   #0,a0                                   ;done?
        beq.s   GSNx                                    ;yep, symbol not found
        systrap StrLen(a3.l)
        ext.l   d0
        addq.l  #1,d0
        systrap MemPtrNew(d0.l)
        move.l  a0,a4
        systrap StrCopy(a0.l,a3.l)
        systrap MemPtrUnlock(a3.l)                      ;unlock record
        movea.l a4,a0                                   ;it's up to caller to free storage
GSNx    movem.l (a7)+,a3-a4
endproc

proc GetSymbolPgm(recidx.w)
local GSPTemp.l
beginproc
        movem.l a3-a4,-(a7)
        call    GetRecord(recidx(a6).w)                 ;read record n
        move.l  a0,GSPTemp(a6)                          ;save for unlock
        move.l  a0,a3
        cmp.l   #0,a0                                   ;done?
        beq.s   GSPx                                    ;yep, symbol not found
        systrap StrLen(a3.l)                            ;get length
        addq.l  #1,d0
        lea.l   (a3,d0),a3                              ;increment past it
        systrap StrLen(a3.l)
        ext.l   d0
        addq.l  #1,d0
        systrap MemPtrNew(d0.l)
        move.l  a0,a4
        systrap StrCopy(a0.l,a3.l)
        systrap MemPtrUnlock(GSPTemp(a6).l)             ;unlock record
        movea.l a4,a0                                   ;it's up to caller to free storage
GSPx    movem.l (a7)+,a3-a4
endproc

proc GetSymbolFlags(recidx.w)
local GSFTemp.l
local GSFlags.w
beginproc
        movem.l a3-a4,-(a7)
        call    GetRecord(recidx(a6).w)                 ;read record n
        move.l  a0,GSFTemp(a6)                          ;save for unlock
        move.l  a0,a3
        cmp.l   #0,a0                                   ;done?
        beq.s   GSFx                                    ;yep, symbol not found
        systrap StrLen(a3.l)                            ;get length
        addq.l  #1,d0
        lea.l   (a3,d0),a3                              ;increment past it
        systrap StrLen(a3.l)                            ;get length
        addq.l  #1,d0
        lea.l   (a3,d0),a3                              ;increment past it
        move.b  (a3),GSFlags(a6)
        systrap MemPtrUnlock(GSFTemp(a6).l)             ;unlock record
        move.b  GSFlags(a6),d0                          ;return with flags in d0
GSFx    movem.l (a7)+,a3-a4
endproc

;
; Add a new symbol to the symbol table
; Input:  pNewName points to a null terminated string to add as the new symbol
;         pNewExpr points to a null terminated string that is the expression text
; Output: d0.b = true on success, , d0.b = false on duplicate symbol or maximum symbols allowed
;
proc AddSymbol(pNewName.l,pNewExpr.l,NewSymFlags.w)
local pASName.l
local pASExpr.l
local pASBuf.l
local iASRecIdx.w
beginproc
	movem.l	d2/a3-a4,-(a7)
        call    GetSymbol(pNewName(a6).l)               ;check if symbol already exists
        tst.w   d0                                      ;does it exist?
        beq.s   ASAdd
        systrap FrmCustomAlert(#DupID.w,pNewName(a6).l,&0,&0)
        bra     ASErr
ASAdd
        systrap MemPtrNew(#512.l)
        move.l  a0,a4
        move.l  a0,pASBuf(a6)                           ;reload the buffer ptr

        systrap StrCopy(a4.l,pNewName(a6).l)            ;copy string
        systrap StrLen(pNewName(a6).l)                  ;get the string length
        cmp.w   #8,d0                                   ;max is 8 characters
        bgt     ASErr
        lea.l   (a4,d0),a4                              ;increment pointer
        move.b  #0,(a4)+                                ;make sure term null

        systrap StrCopy(a4.l,pNewExpr(a6).l)            ;copy string
        systrap StrLen(pNewExpr(a6).l)                  ;get the string length
        lea.l   (a4,d0),a4                              ;increment pointer
        move.b  #0,(a4)+                                ;make sure term null

        move.w  NewSymFlags(a6),d0                      ;save flags
        move.b  d0,(a4)+

        suba.l  pASBuf(a6),a4                           ;calculate length

        move.w  #24,iASRecIdx(a6)                       ;write to beginning of DB just after KEYTAB

        call    WriteRecord(&iASRecIdx(a6),pASBuf(a6).l,a4.l)

        systrap MemPtrFree(pASBuf(a6).l)                ;free buffer

        move.b  #true,d0                                ;indicate success
        bra.s   AddSymbolx

ASErr	move.b  #false,d0                               ;flag failed
AddSymbolx
	movem.l	(a7)+,d2/a3-a4
endproc

proc ValidateSymbol(pSym.l)
beginproc
	systrap	StrLen(pSym(a6).l)
	tst.w	d0
	beq.s	VSErr
	cmp.w	#8,d0
	bgt.s	VSErr
	movea.l	pSym(a6),a0
	cmp.b	#'A',(a0)
	blt.s	VSErr
	cmp.b	#'Z',(a0)
	ble.s	VSOK1
	cmp.b	#'a',(a0)
	blt.s	VSErr
	cmp.b	#'z',(a0)
	bgt.s	VSErr
VSOK1	tst.b	(a0)
	beq.s	VSEnd
	cmp.b	#'0',(a0)
	blt.s	VSErr
	cmp.b	#'9',(a0)
	ble.s	VSOK2
	cmp.b	#'A',(a0)
	blt.s	VSErr
	cmp.b	#'Z',(a0)
	ble.s	VSOK2
	cmp.b	#'a',(a0)
	blt.s	VSErr
	cmp.b	#'z',(a0)
	bgt.s	VSErr
VSOK2	lea	1(a0),a0
	bra.s	VSOK1
VSEnd	move.l	#false,d0
	bra.s	VSx
VSErr	move.b	#true,d0
VSx	
endproc


proc ReplaceSymbol(pSymbolName.l,pNewExpr.l,SymFlags.w)
local pRSBuf.l
local RSRecIdx.w
beginproc
	move.l	a3,-(a7)	
	call	GetSymbol(pSymbolName(a6).l)	        ;get pointer to symbol
	tst.w	d0				        ;found?
	beq  	RSErr
        move.w  d0,RSRecIdx(a6)                         ;save record index
        systrap DmRemoveRecord(hDB(a5).l,RSRecIdx(a6).w) ;remove record
        systrap MemPtrNew(#512.l)
        cmpa.l  #0,a0
        beq     RSErr
        move.l  a0,a3
        move.l  a0,pRSBuf(a6)                           ;reload the buffer ptr
        systrap StrCopy(a3.l,pSymbolName(a6).l)         ;copy string
        systrap StrLen(pSymbolName(a6).l)               ;get the string length
        cmp.w   #8,d0                                   ;max is 8 characters
        bgt     RSErr
        lea.l   (a3,d0),a3                              ;increment pointer
        move.b  #0,(a3)+                                ;make sure term null
        systrap StrCopy(a3.l,pNewExpr(a6).l)            ;copy string
        systrap StrLen(pNewExpr(a6).l)                  ;get the string length
        lea.l   (a3,d0),a3                              ;increment pointer
        move.b  #0,(a3)+                                ;make sure term null
        move.w  SymFlags(a6),d0                         ;save flags
        move.b  d0,(a3)+
        suba.l  pRSBuf(a6),a3                           ;calculate length
        call    WriteRecord(&RSRecIdx(a6),pRSBuf(a6).l,a3.l)
        systrap MemPtrFree(pRSBuf(a6).l)                ;free buffer
        move.b  #true,d0                                ;indicate success
        bra.s   RSx
RSErr   move.b  #false,d0
RSx	move.l	(a7)+,a3
endproc

;
;Finds the symbol passed as the argument in the symbol table and
; returns the record number in d0.w
; if the symbol isn't found then d0 = 0
;
proc GetSymbol(pSymbolName.l)
local pGSRec.l
local GSRecIdx.w
beginproc
	movem.l	d2/a3,-(a7)
        move.w  #24,GSRecIdx(a6)                        ;start with the first symbol entry right after the keytab
GSLoop
        call    GetRecord(GSRecIdx(a6).w)               ;read record n
        move.l  a0,pGSRec(a6)                           ;for unload
        cmp.l   #0,a0                                   ;done?
        beq.s   GetSymbolNF                             ;yep, symbol not found
        tst.b   SymbolCase(a5)                          ;case sensitive?
        beq.s   GSCmpNoCase
        systrap StrCompare(pSymbolName(a6).l,a0.l)      ;compare symbol names
        bra.s   GSCmpCont
GSCmpNoCase
        systrap StrCaselessCompare(pSymbolName(a6).l,a0.l) ;compare symbol names
GSCmpCont        
        tst.l   d0                                      ;equal?
        beq.s   GetSymbolFnd
        addq.w  #1,GSRecIdx(a6)                         ;increment record ptr
        systrap MemPtrUnlock(pGSRec(a6).l)              ;unlock record
        bra.s   GSLoop
GetSymbolNF
        clr.w   d0                                      ;assume not found
        bra.s   GetSymbolx
GetSymbolFnd
        systrap MemPtrUnlock(pGSRec(a6).l)              ;unlock record
        move.w  GSRecIdx(a6),d0                         ;record number in d0
GetSymbolx
	movem.l	(a7)+,d2/a3
endproc


;
; Draw the digits, frame, and indicators within the display area.
;  in binary mode, the argument is the binary number
;  in floating point mode, the argument is a pointer to the float
;	
proc UpdateDisplay(fpn.l)
local UDStrtPos.w
local res.w
local UDTempString.40
local rect.RectangleType
beginproc
	movem.l	d2-d3/a3,-(a7)
        tst.b   ErrorFlag(a5)                           ;error occurred in expression?
        bne     UDErr                                   ;yup, no valid result then
	cmp.w	#$7fff,CurrentBase(a5)			;floating point display mode?
	beq.s	UDFP					;yes, continue
	call	OutputConversion(fpn(a6).l,#10.l,&UDTempString(a6),#40.l)
	systrap	StrCopy(&Op2(a5),a3.l)			;new Op2
	clr.l	d0
	move.w	CurrentBase(a5),d0
	call	OutputConversion(fpn(a6).l,d0.l,&UDTempString(a6),#40.l) ;convert new value to display
	bra	UDDisp					;continue
UDFP	movea.l	pFpn(a6),a0                             ;a0 = ptr to float
        tst.b   DisplayFloatInHex(a5)                   ;display this float in hex?
        beq.s   UDNX
        move.l  (a0),d0                                 ;convert word 1 of the 64 bit float
        call    OutputConversion(d0.l,#16.l,&UDTempString(a6),#40.l)
        systrap StrCopy(&TStr(a5),a3.l)
        movea.l pFpn(a6),a0
        move.l  4(a0),d0                                ;convert word 2 of the 64 bit float
        call    OutputConversion(d0.l,#16.l,&UDTempString(a6),#40.l)
        systrap StrCat(&TStr(a5),a3.l)                  ;concatinate them together
        lea.l   TStr(a5),a3                             ;a3 must point to the buffer
        bra     UDDisp
UDNX    cmp.b   #2,romVersion(a5)
        blt.s   UDFPOK                                  ;v1 doesnt have this call
        tst.w   MathLibRef(a5)                          ;mathlib installed?
        beq.s   UDFPOK                                  ;no, then don't call IsNaN
        pea.l   res(a6)                                 ;result of call
        move.l	4(a0),-(a7)                             ;push float
	move.l	(a0),-(a7)
        move.w  MathLibRef(a5),-(a7)        
	trap	#15					
	dc.w	sysTrapMathLibIsNaN                     ;check if non-a-number
	lea.l	10(a7),a7
        tst.w   res(a6)                                 ;if non a number
        beq.s   UDFPOK                                  ; then
UDErr	move.w	#6,rect.topLeft.x(a6)
	move.w	#6,rect.topLeft.y(a6)
	move.w	#140,rect.extent.x(a6)
	move.w	#23,rect.extent.y(a6)
	systrap	WinEraseRectangle(&rect(a6),#0.w)	;erase rectangle 
	call    DrawBitmap(#kidberror.w,#100.w,#11.w)   ;draw "Error"
        bra     DspDone
UDFPOK	lea	Op2(a5),a3				;set address in a3
        tst.w	DecimalFlag(a5)				;user previously pressed dec pt.
	beq.s	UDNDot					;no, continue
	systrap	StrLen(a3.l)				;get length of readout
	subq.l	#1,d0					;-1
	cmp.b	#'0',(a3,d0)				;pressing .00000
	beq.s	UDDisp					;yes, display asis
	cmp.b	#'.',(a3,d0)				;pressing .
	beq.s	UDDisp					;yes, display asis
UDNDot
	call	Conv(fpn(a6).l,a3.l)			;otherwise, convert float
UDDisp	move.w	#6,rect.topLeft.x(a6)
	move.w	#6,rect.topLeft.y(a6)
	move.w	#140,rect.extent.x(a6)
	move.w	#23,rect.extent.y(a6)
	systrap	WinEraseRectangle(&rect(a6),#0.w)	;erase rectangle
        systrap StrLen(a3.l)
        cmp.w   #14,d0
        ble.s   UDNoScroller
	move.w	ScrollPos(a5),d0
        divu.w  #9,d0
        muls.w  #9,d0
        add.w   #5,d0
        move.w  d0,rect.topLeft.x(a6)
	move.w	#26,rect.topLeft.y(a6)
	move.w	#8,rect.extent.x(a6)
	move.w	#3,rect.extent.y(a6)
        systrap WinDrawRectangle(&rect(a6),#0.w)
        systrap WinDrawLine(rect.topLeft.x(a6).w,#27.w,#135.w,#27.w)
	move.w	ScrollPos(a5),d0
        divu.w  #9,d0
        move.w  #14,d2
        sub.w   d0,d2
        systrap StrLen(a3.l)
        sub.w   d2,d0
        move.b  #0,(a3,d0)
        bra.s   UDDisp2
UDNoScroller
        move.w  #131,ScrollPos(a5)
UDDisp2
	systrap	StrLen(a3.l)				;get string length of display
	move.l	d0,d3					;save string length for later
	lsl.l	#3,d0					;*8 for character width
	add.l	d3,d0					;+1 spacer for each char
	move.l	#140,d2					;ending position of display
	sub.l	d0,d2					;d2 holds starting position 
        move.w  d2,UDStrtPos(a6)                        ;save for later test
DspLoop	move.b	(a3)+,d0				;move next char to d0
	ext.w	d0					;make word
        cmp.w   #6,d2                                   ;don't draw 
        blt.s   DspSkip                                 ; outside rectangle       
	call    DrawBitmap(d0.w,d2.w,#10.w)		;draw a char
DspSkip	add.l	#9,d2					;increment xpos
	subq.l	#1,d3					;dec length
	bne.s	DspLoop					;continue till input exausted	
DspDone
	systrap	FntSetFont(#stdFont.b)			;set font to standard
        cmp.w   #$7fff,CurrentBase(a5)                  ;floating point mode?
        beq.s   DspFloatMode
        move.w  CurrentBase(a5),d0
        ext.l   d0
        systrap StrIToA(&UDTempString(a6),d0.l)         ;convert base to character for display
DspStatus
        systrap StrLen(&UDTempString(a6))
        systrap FntCharsWidth(&UDTempString(a6),d0.w)
        add.w   #8,d0                                   ;+starting xpos
        cmp.w   UDStrtPos(a6),d0                        ;compare to left strtng pos of disp
        bgt.s   DspPending
        systrap StrLen(&UDTempString(a6))
 	systrap WinDrawChars(&UDTempString(a6),d0.w,#8.w,#18.w) 
        bra.s   DspPending
DspFloatMode
        move.w  DegreeFlag(a5),d0                       ;get mode
        sub.w   #kidcDegrees,d0                         ;make relative to zero
        lsl.l   #2,d0                                   ;*4
        lea.l   drg(a5,d0),a0                           ;address of string to display
        systrap StrCopy(&UDTempString(a6),a0.l)         ;copy string
        bra.s   DspStatus
DspPending
 	tst.w	LastWasOp(a5)                           ;was the last and operation?
 	beq.s	UDDone                                  ;no, then done
 	tst.w	LastOp(a5)				;any pending operations?
 	beq.s	UDDone					;nope, done
	call	FindKeyTabSymbol(LastOp(a5).w)          ;get function name
        cmpa.l  #0,a0                                   ;any?
        beq.s   UDDone                                  ;no, then pass on the display
	movea.l	KEYTAB.KeyText(a1),a3                   ;get text ptr
        cmpa.l  #0,a3                                   ;null?
        beq.s   UDDone                                  ;yes, then pass
        systrap StrLen(a3.l)
        systrap FntCharsWidth(a3.l,d0.w)
        add.w   #8,d0                                   ;+starting xpos
        cmp.w   UDStrtPos(a6),d0                        ;compare to left strtng pos of disp
        bgt.s   UDDone
 	systrap	StrLen(a3.l)                            ;get length of string
 	systrap WinDrawChars(a3.l,d0.w,#8.w,#6.w)	;display the function name
UDDone	clr.w	DecimalFlag(a5)				;clear decimal flag
	lea	Op2(a5),a0					
ChkDec	tst.b	(a0)					;end?
	beq.s	DecChkX					;yes, done
	cmp.b	#'.',(a0)+				;do we have a dec pt?		
	bne.s	ChkDec					;no, continue
	move.w	#1,DecimalFlag(a5)			;yes, set result has dec pt
DecChkX	movem.l	(a7)+,d2-d3/a3				;restore regs
endproc

proc InputConversion(pInput.l,iBase.w)
local InputResult.l
local NegFlag.w
beginproc
	clr.l	InputResult(a6)				;clear input value
	movea.l	pInput(a6),a3				;input pointer
	clr.b	NegFlag(a6)				;assume positive
	cmp.b	#'-',(a3)				;neg?
	bne.s	ICChkUnsigned	
	move.b	(a3)+,NegFlag(a6)			;set negative
ICChkUnsigned
        tst.b   UnsignedResults(a5)                     ;user wants unsigned results?
        beq.s   ICLoop                                  ;yes, so it's never negative
        clr.b   NegFlag(a6)                             ;
ICLoop	tst.b	(a3)					;input exausted?
	beq.s	ICDone					;yes, input conversion done
	cmp.b	#'.',(a3)				;stop on .
	beq.s	ICDone		
	clr	d1		
	move.w	iBase(a6),d1					
	subq.w	#1,d1					;input base-1 in d1
	move.l	InputResult(a6),d0				
ICMul	tst.w	d1					;InputResult = InputResult * iBase
	beq.s	ICMulx						
	add.l	d0,InputResult(a6)
	subq.w	#1,d1
	bra.s	ICMul
ICMulx	clr.l	d0
	cmp.b	#'9',(a3)				;pInput <= '9'
	bgt.s	ICAlpha
	move.b	(a3)+,d0
	and.b	#$0f,d0
	add.l	d0,InputResult(a6)			;InputResult += (pInput&0x0f)
	bra.s	ICLoop
ICAlpha	move.b	(a3)+,d0
	and.b	#$0f,d0
	add.b	#9,d0
	add.l	d0,InputResult(a6)			;InputResult += (pInput&0x0f)+9
	bra.s	ICLoop
ICDone
	move.l	InputResult(a6),d0			;d0 is result
	tst.b	NegFlag(a6)
	beq.s	ICx
	neg.l	d0					;negate result
ICx
endproc

proc OutputConversion(input.l,oBase.l,pOutput.l,len.l)
local OCNegFlag.w
beginproc
        clr.w   OCNegFlag(a6)                           ;assume positive
        tst.b   UnsignedResults(a5)                     ;check if wanted on unsigned
        bne.s   OCPlus                                  ;yes, it's unsigned display mode
        cmp.l   #10,oBase(a6)
        bne.s   OCPlus
        tst.l   input(a6)                               ;is operand negative?
        bpl.s   OCPlus                                  ;no it's positive...
        neg.l   input(a6)                               ;negate (make positive) the arg
        move.b  #$ff,OCNegFlag(a6)                      ;set flag to negative
OCPlus	movea.l	pOutput(a6),a3				;pointer to output buffer
        move.l	len(a6),d0				;get length of output buffer
	lea.l	(a3,d0),a3				;point to end
	move.b	#0,-(a3)				;null terminator
OCLoop	
	call	LongRemainder(input(a6).l,oBase(a6).l)	;get remainder of input/oBase
	cmp.w	#9,d0					;if > 9
	bgt.s	OCAlpha					;then A-F form
	or.b	#$30,d0					;make char
	move.b	d0,-(a3)				;*output |= 0x30
	bra.s	OCLoopx
OCAlpha	sub.b	#10,d0
	move.b	alpha(a5,d0),-(a3)			;*output = alpha[*output-10]
OCLoopx	
	call	LongDivide(input(a6).l,oBase(a6).l)	;input = input/oBase
	move.l	d0,input(a6)
	bgt.s	OCLoop					;while(input)
        tst.b   OCNegFlag(a6)                           ;are we working with neg num?
        beq.s   OCExit                                  ;nope, then done
        move.b  #'-',-(a3)                              ;include a neg sign
OCExit
endproc

;
; Draw bitmap resource at x,y location
;
proc DrawBitmap(resource.w,x.w,y.w)
beginproc
	movem.l	a3/d2-d3,-(a7)				;save regs used
	move.l  #'Tbmp',d0				;bitmap resource id
   	systrap DmGetResource(d0.l, resource(a6).w)	;get the resource
	cmpa.l	#0,a0					;success?
	beq.s   DrawBitmapError				;programmer screwed up
	move.l	a0,a3					;move to a3
	systrap MemHandleLock(a0.l)			;lock resource
	cmpa.l	#0,a0					;did it happen?
	beq.s	DrawBitmapError				;programmer screwed up
	systrap WinDrawBitmap(a0.l,x(a6).w,y(a6).w)	;draw the bitmap at the specified coord
	systrap MemHandleUnlock(a3.l)			;unlock handle
	systrap DmReleaseResource(a3.l)			;release resource
DrawBitmapError
	movem.l	(a7)+,a3/d2-d3				;restore reg
endproc


proc Initialization()
beginproc
	move.b	#$30,Op1(a5)				;Op1 = 0
	move.b	#0,Op1+1(a5)
	move.b	#$30,Op2(a5)				;Op2 = 0
	move.b	#0,Op2+1(a5)
	clr.w	DecimalFlag(a5)				;clear decimal flag
	clr.w	LastOp(a5)				;no last op
	clr.w	NumOps(a5)				;no ops yet
	clr.w	LastWasOp(a5)				; = "none"
        clr.b   ErrorFlag(a5)                           ;clear expression error flag
endproc

proc Conv(pFpn.l,pResult.l)
local CVTempString.40
local expNegFlag.w
beginproc
	movem.l	d2/a3-a4,-(a7)
        call    FPIFloatToAscii(pResult(a6).l,pFpn(a6).l)
;The result will be [-]x[.]yyyyyyy[e[-]zz] or 0
	movea.l	pResult(a6),a3				;a3 -> source field
	lea	CVTempString(a6),a4			;a4 -> destination string
	cmp.b	#'0',(a3)				;result zero?
	beq	CnvZero					;yes, make sure dec pt ok
	clr.b	expNegFlag(a6)				;clear exponent flag
	cmp.b	#'-',(a3)				;neg mantissa result?
	bne.s 	notNeg
	move.b	(a3)+,(a4)+				;negative result
notNeg  cmp.b	#'-',10(a3)				;is exponent negative?
	bne.s	expPos
	move.b	#'-',expNegFlag(a6)			;save sign of exponent
	pea	11(a3)
	bra.s	doExpCv
expPos	pea	10(a3)
doExpCv trap	#15					;convert exponent to int in d0
	dc.w	sysTrapStrAToI
	addq.l	#4,a7
	cmp.l	#7,d0					;only convert +/- 7 exponents
	bgt	ConvXit					;exponent out of range, just display
manPos	tst.b	expNegFlag(a6)				;exponent neg?
	beq.s	expIsP
	move.b	#'0',(a4)+				;put in the decimal point
	move.b	#'.',(a4)+
	subq.l	#1,d0					;exp-1 digits left 
neLoop	tst.l	d0			
	beq.s	moveMan
	move.b	#'0',(a4)+				;move leading zeros
	subq.l	#1,d0
	bra.s	neLoop
expIsP  cmp.b	#'.',(a3)				;don't move the dec pt in the input stream
	bne.s	expIsPm
	lea	1(a3),a3				;inc input stream ptr
	bra.s	expIsP					;continue...
expIsPm	move.b	(a3)+,(a4)+				;move input stream to output
	dbeq	d0,expIsP				;continue
	move.b	#'.',(a4)+				;here's where the dp goes
moveMan	cmp.b	#'.',(a3)				;is it the dec pt on input?
	bne.s	moveMn2					;yes, then skip
	lea	1(a3),a3
	bra.s	moveMan
moveMn2	cmp.b	#'e',(a3)				;end?
	beq.s	moveEnd
	move.b	(a3)+,(a4)+				;move input to output
	bra.s	moveMan
moveEnd	cmp.b	#'0',-(a4)				;Righthand zero suppress
	beq.s	moveEnd
	cmp.b	#'.',(a4)				;if x.0 form
	bne.s	EndDgt
	tst.w	DecimalFlag(a5)				;should we display the dot?
	bne.s	EndDgt
	clr.b	(a4)					;c-string type terminate string
	bra.s	Reslt
CnvZero	
        tst.w	DecimalFlag(a5)				;decimal entered?
	beq.s	ConvXit					;no, continue
	move.b	#'0',(a4)
        move.b	#'.',(a4)
EndDgt  move.b	#0,1(a4)	
Reslt	
	systrap	StrCopy(pResult(a6).l,&CVTempString(a6))
ConvXit
	movem.l	(a7)+,a3-a4/d2
endproc


;********************************************************************************
;*                   B I N A R Y   M A T H   F U N C T I O N S                  *
;********************************************************************************

proc LongRemainder(dividend.l,divisor.l)
beginproc
     	call	LongDivide(dividend(a6).l,divisor(a6).l)
     	move.l	divisor(a6),d1
     	call	LongMultiply(d0.l,d1.l)
     	move.l	dividend(a6),d1
     	sub.l	d0,d1
     	move.l	d1,d0
endproc

proc LongMultiply(arg1.l,arg2.l)
beginproc
  	move.w	arg1(a6),d0
     	mulu.w	arg2+2(a6),d0
     	move.w	arg1+2(a6),d1
     	mulu.w	arg2(a6),d1
     	add.w	d1,d0
     	swap	d0
     	clr.w	d0
     	move.w	arg1+2(a6),d1
     	mulu.w	arg2+2(a6),d1
     	add.l	d1,d0
endproc

proc LongDivide(dividend.l,divisor.l)
beginproc
	move.l	d2,-(a7)				;save reg used
     	move.l	divisor(a6),d1				;divisor
     	move.l	dividend(a6),d0				;dividend	
     	cmpi.l	#$10000,d1				;anticipate overflow?
     	bcc.s	Ovfl					;yes, handle it
     	move.l	d0,d2					;dividend to d2
     	clr.w	d2					;upper divide first
     	swap	d2					;upper to lower
     	divu.w	d1,d2					;divide by divisor result to d2
     	move.w	d2,d0					;move result to d0
     	swap	d0					;quotient to upper, remainder to lower
     	move.w	dividend+2(a6),d2			;get lower portion of dividend
     	divu.w	d1,d2					;divide it
     	move.w	d2,d0					;result to d0
     	bra.s	DivExit					;return					
Ovfl  	move.l	d1,d2					;save divisor in d2
Shft  	lsr.l	#1,d1					;right shift divisor
     	lsr.l	#1,d0					;and dividend 
     	cmpi.l	#$10000,d1				;until no overflow exists
     	bcc.s	Shft					;no overflow condition
     	divu.w	d1,d0					;dividend/divisor -> remainder|quotient)
     	andi.l	#$ffff,d0				;isolate quotient
  	move.l	d2,d1					;saved divisor to d1
     	mulu.w	d0,d1					;quotient * divisor lower -> d1
     	swap	d2					;divisor upper to lower
     	mulu.w	d0,d2					;quotient * divisor upper -> d2
     	swap	d2					;test
     	btst.l	#0,d2					;negative?
     	bne.s	DecRslt					;no, then done
     	add.l	d2,d1				
     	bcs.s	DecRslt
     	cmp.l	dividend(a6),d1
     	bls.s	DivExit
DecRslt subq.l	#1,d0
DivExit	move.l	(a7)+,d2				;restore used reg	
endproc



;********************************************************************************
;*                F L O A T I N G   P O I N T   I N T E R F A C E               * 
;*                                                                              *
;*            Eliminates version differences between Pilot and PlamPilot        *
;********************************************************************************


;
;
; Compare two floating point numbers and return
;  to caller with the condition codes set
; 
;
proc FPICompare(pFloat1.l,pFloat2.l)
beginproc
        cmp.b   #2,romVersion(a5)
        bge.s   CMPV2
	movea.l	pFloat1(a6),a0
	movea.l	pFloat2(a6),a1
	move.b	FloatType.sign(a0),d0
	cmp.b	FloatType.sign(a1),d0
	beq.s	FCsignEqual
	blt.s	FCDone
	bra.s	FCDone

FCsignEqual
	move.w	FloatType.exp(a0),d0
	cmp.w	FloatType.exp(a1),d0
	blt.s	FCDone
	bgt.s	FCDone

FCexpEqual
	move.l	FloatType.man(a0),d0
	cmp.l	FloatType.man(a1),d0
        bra.s   FCDone

CMPV2   movea.l pFloat1(a6),a0
	move.l	4(a0),-(a7)
	move.l	(a0),-(a7)
        movea.l pFloat2(a6),a0
	move.l	4(a0),-(a7)
	move.l	(a0),-(a7)
        move.l  #sysFloatEm_d_cmp,d2                    ;do a double prec compare
	trap	#15
	dc.w	sysTrapFlpEmDispatch
	lea.l	16(a7),a7
        tst.b   d0
        beq.s   FCDone                                  ;equal cond codes set
        cmp.b   #2,d0                                   ;less than?
        beq.s   FCLess
        ;if not equal or less, then assume greater
        move.w  sr,d0
        and.w   #$ff00,d0                               ;clear all status bits
        bra.s   FCDone                  
FCLess  move.w  sr,d0
        and.w   #$ff00,d0
        or.w    #9,d0                                   ;set the Neg and Carry bits
        move.w  d0,sr                                   ;move back to status reg (There must be a better way than this)        
FCDone
endproc


;
; Convert from ASCII to Floating point
;
;    Call FPIAsciiToFloat(&fpn(a5),&buf(a5))
;
proc FPIAsciiToFloat(ATOFOut.l,ATOFIn.l)
beginproc
        move.l  d2,-(a7)
        cmp.b   #2,romVersion(a5)
        bge.s   ATOFV2
        systrap FplAToF(ATOFOut(a6).l,ATOFIn(a6).l)	;convert ascii to float
        bra.s   ATOFx
ATOFV2  moveq.l #sysFloatAToF,d2                        ;put function request in d2
        systrap FlpDispatch(ATOFOut(a6).l,ATOFIn(a6).l)	;convert ascii to float
ATOFx   move.l  (a7)+,d2
endproc

;
; Convert from Float to ASCII
;
;    Call FPIFloatToAscii(&buf(a5),&fpn(a5))
;
proc FPIFloatToAscii(FTOAOut.l,FTOAIn.l)
beginproc
        move.l  d2,-(a7)
	move.l	FTOAOut(a6),-(a7)
	movea.l	FTOAIn(a6),a0
        cmp.b   #2,romVersion(a5)
        bge.s   FTOAV2
	move.b	FloatType.sign(a0),-(a7)
	move.w	FloatType.exp(a0),-(a7)
	move.l	FloatType.man(a0),-(a7)
	trap 	#15
	dc.w	sysTrapFplFToA
        bra.s   FTOAx
FTOAV2	move.l	4(a0),-(a7)
	move.l	(a0),-(a7)
        moveq.l #sysFloatFToA,d2
	trap 	#15
	dc.w	sysTrapFlpDispatch
FTOAx	lea.l	12(a7),a7
        move.l  (a7)+,d2
endproc
        
;
; Convert from long to float
;
;    Call FPILongToFloat(&fpn(a5),value(a5).l)
;
proc FPILongToFloat(LTOFOut.l,LTOFIn.l)
beginproc
        move.l  d2,-(a7)
        cmp.b   #2,romVersion(a5)
        bge.s   LTOFV2
	systrap	FplLongToFloat(LTOFOut(a6).l,LTOFIn(a6).l)
        bra.s   LTOFx
LTOFV2  moveq.l #sysFloatEm_d_itod,d2           ;long to FlpDouble
        systrap FlpEmDispatch(LTOFOut(a6).l,LTOFIn(a6).l)
LTOFx   move.l  (a7)+,d2
endproc


;
; Convert from float to long
;
;    Call FPIFloatToLong(&fpn(a5))
;      return with long in d0
;
proc FPIFloatToLong(FTOLIn.l)
beginproc
        move.l  d2,-(a7)
        movea.l FTOLIn(a6),a0
        cmp.b   #2,romVersion(a5)
        bge.s   FTOLV2
	move.b	FloatType.sign(a0),-(a7)
	move.w	FloatType.exp(a0),-(a7)
	move.l	FloatType.man(a0),-(a7)
	trap	#15
	dc.w	sysTrapFplFloatToLong
        bra.s   FTOLx
FTOLV2	move.l	4(a0),-(a7)
	move.l	(a0),-(a7)
        moveq.l #sysFloatEm_d_dtoi,d2
	trap	#15
	dc.w	sysTrapFlpEmDispatch
FTOLx	addq.l	#8,a7
        move.l  (a7)+,d2
endproc


;
; Convert from float to unsigned long
;
;    Call FPIFloatToULong(&fpn(a5))
;      return with long in d0
;
proc FPIFloatToULong(FTOULIn.l)
beginproc
        move.l  d2,-(a7)
        movea.l FTOULIn(a6),a0
        cmp.b   #2,romVersion(a5)
        bge.s   FTOULV2
	move.b	FloatType.sign(a0),-(a7)
	move.w	FloatType.exp(a0),-(a7)
	move.l	FloatType.man(a0),-(a7)
	trap	#15
	dc.w	sysTrapFplFloatToULong
        bra.s   FTOULx
FTOULV2	move.l	4(a0),-(a7)
	move.l	(a0),-(a7)
        moveq.l #sysFloatEm_d_dtou,d2
	trap	#15
	dc.w	sysTrapFlpEmDispatch
FTOULx	addq.l	#8,a7
        move.l  (a7)+,d2
endproc


;
; Add two floats 
;
;    Call FPIAdd(&result(a5),&fpn1(a5),&fpn2(a5))
;
proc FPIAdd(AddResult.l,AddOperand1.l,AddOperand2.l)
beginproc
        move.l  d2,-(a7)
        movea.l AddOperand1(a6),a0
        cmp.b   #2,romVersion(a5)
        bge.s   ADDV2
	move.b	FloatType.sign(a0),-(a7)
	move.w	FloatType.exp(a0),-(a7)
	move.l	FloatType.man(a0),-(a7)
        movea.l AddOperand2(a6),a0
	move.b	FloatType.sign(a0),-(a7)
	move.w	FloatType.exp(a0),-(a7)
	move.l	FloatType.man(a0),-(a7)
	move.l	AddResult(a6),-(a7)
	trap	#15
	dc.w	sysTrapFplAdd
        bra.s   ADDx
ADDV2	move.l	4(a0),-(a7)
	move.l	(a0),-(a7)
        movea.l AddOperand2(a6),a0
	move.l	4(a0),-(a7)
	move.l	(a0),-(a7)
	move.l	AddResult(a6),-(a7)
        moveq.l #sysFloatEm_d_add,d2                    ;do a double prec add
	trap	#15
	dc.w	sysTrapFlpEmDispatch
ADDx	lea.l	20(a7),a7
        move.l  (a7)+,d2
endproc


;
; Subtract two floats 
;
;    Call FPISub(&result(a5),&fpn1(a5),&fpn2(a5))
;
proc FPISub(SubResult.l,SubOperand1.l,SubOperand2.l)
beginproc
        move.l  d2,-(a7)
        movea.l SubOperand2(a6),a0
        cmp.b   #2,romVersion(a5)
        bge.s   SUBV2
	move.b	FloatType.sign(a0),-(a7)
	move.w	FloatType.exp(a0),-(a7)
	move.l	FloatType.man(a0),-(a7)
        movea.l SubOperand1(a6),a0
	move.b	FloatType.sign(a0),-(a7)
	move.w	FloatType.exp(a0),-(a7)
	move.l	FloatType.man(a0),-(a7)
	move.l	SubResult(a6),-(a7)
	trap	#15
	dc.w	sysTrapFplSub
        bra.s   SUBx
SUBV2	move.l	4(a0),-(a7)
	move.l	(a0),-(a7)
        movea.l SubOperand1(a6),a0
	move.l	4(a0),-(a7)
	move.l	(a0),-(a7)
	move.l	SubResult(a6),-(a7)
        moveq.l #sysFloatEm_d_sub,d2
	trap	#15
	dc.w	sysTrapFlpEmDispatch
SUBx	lea.l	20(a7),a7
        move.l  (a7)+,d2
endproc


;
; Multiply two floats 
;
;    Call FPIMul(&result(a5),&fpn1(a5),&fpn2(a5))
;
proc FPIMul(MulResult.l,MulOperand1.l,MulOperand2.l)
beginproc
        move.l  d2,-(a7)
        movea.l MulOperand1(a6),a0
        cmp.b   #2,romVersion(a5)
        bge.s   MULV2
	move.b	FloatType.sign(a0),-(a7)
	move.w	FloatType.exp(a0),-(a7)
	move.l	FloatType.man(a0),-(a7)
        movea.l MulOperand2(a6),a0
	move.b	FloatType.sign(a0),-(a7)
	move.w	FloatType.exp(a0),-(a7)
	move.l	FloatType.man(a0),-(a7)
	move.l	MulResult(a6),-(a7)
	trap	#15
	dc.w	sysTrapFplMul
        bra.s   MULx
MULV2	move.l	4(a0),-(a7)
	move.l	(a0),-(a7)
        movea.l MulOperand2(a6),a0
	move.l	4(a0),-(a7)
	move.l	(a0),-(a7)
	move.l	MulResult(a6),-(a7)
        moveq.l #sysFloatEm_d_mul,d2
	trap	#15
	dc.w	sysTrapFlpEmDispatch
MULx	lea.l	20(a7),a7
        move.l  (a7)+,d2
endproc

;
; Divide two floats 
;
;    Call FPIDiv(&result(a5),&fpn1(a5),&fpn2(a5))
;
proc FPIDiv(DivResult.l,DivOperand1.l,DivOperand2.l)
beginproc
        move.l  d2,-(a7)
        movea.l DivOperand2(a6),a0
        cmp.b   #2,romVersion(a5)
        bge.s   DIVV2
	move.b	FloatType.sign(a0),-(a7)
	move.w	FloatType.exp(a0),-(a7)
	move.l	FloatType.man(a0),-(a7)
        movea.l DivOperand1(a6),a0
	move.b	FloatType.sign(a0),-(a7)
	move.w	FloatType.exp(a0),-(a7)
	move.l	FloatType.man(a0),-(a7)
	move.l	DivResult(a6),-(a7)
	trap	#15
	dc.w	sysTrapFplDiv
        bra.s   DIVx
DIVV2	move.l	4(a0),-(a7)
	move.l	(a0),-(a7)
        movea.l DivOperand1(a6),a0
	move.l	4(a0),-(a7)
	move.l	(a0),-(a7)
	move.l	DivResult(a6),-(a7)
        moveq.l #sysFloatEm_d_div,d2 
	trap	#15
	dc.w	sysTrapFlpEmDispatch
DIVx	lea.l	20(a7),a7
        move.l  (a7)+,d2
endproc



;
; Negate float
;
;    Call FPINeg(&fpn(a5))
;
proc FPINeg(NegResult.l)
beginproc
        move.l  d2,-(a7)
        movea.l NegResult(a6),a0
        cmp.b   #2,romVersion(a5)
        bge.s   NEGV2
	move.b	#$ff,-(a7)	 		        ;this is 			
	move.w	#$ffe1,-(a7)	 		        ; -1
	move.l	#$80000000,-(a7) 		        ;  in floating point
	move.b	FloatType.sign(a0),-(a7)
	move.w	FloatType.exp(a0),-(a7)
	move.l	FloatType.man(a0),-(a7)
	move.l	NegResult(a6),-(a7)
	trap	#15					
	dc.w	sysTrapFplMul			        ;multiply by -1
	lea.l	20(a7),a7
        bra.s   NEGx
NEGV2	move.l	4(a0),-(a7)
	move.l	(a0),-(a7)
        move.l  NegResult(a6),-(a7)
        moveq.l #sysFloatEm_d_neg,d2                    ;do a double prec negate
	trap	#15					
	dc.w	sysTrapFlpEmDispatch		        ;negate
	lea.l	12(a7),a7
NEGx    move.l  (a7)+,d2
endproc


;********************************************************************************
;*                      D A T A B A S E   R O U T I N E S                       * 
;********************************************************************************
;-------------------------------------------------
;* Database format:                              *
;*                                               *
;*  Application info segment:                    *
;*                                               *
;*    $8270.w <- Special flag to indicate version*
;*    CurrentBase.w                              *
;*    DegreeFlag.w                               *
;*    KeyPage.w                                  *
;*    RoundingFlag.w                             *
;*    UnsignedResults.b                          *
;*    Display[n] NULL                            *
;*                                               *
;*  Database records:                            *
;*                                               *
;*  The following occurs once for each KEYTAB    *
;*                                               *
;*    Key.b           ;KEYxx                     *
;*    KeySym[n] NULL                             * 
;*    KeyText[n] NULL                            * 
;*                                               *
;*  The following occurs once for each SYMTAB    *
;*                                               *
;*    SymName[n] NULL                            *
;*    SymPgm[n] NULL                             * 
;*    SymFlags.b                                 *
;*                                               *
;-------------------------------------------------

proc OpenDatabase()
beginproc
        systrap DmOpenDatabaseByTypeCreator(#DBType.l,#AppType.l,#dmModeReadWrite.w) ;open database
        move.l  a0,hDB(a5)
ODBx
endproc

proc CreateDatabase()
local appInfoP.l
local dbID.l
local cardNo.w
local dbAttrs.w
beginproc
        clr.l   hDB(a5)
        systrap DmCreateDatabase(#0.w,&DBName(a5),#AppType.l,#DBType.l,#0.b)
        tst.b   d0
        beq.s   CDBCreateOK
        systrap FrmAlert(#CreateDBError.w)                ;tell user
        bra     CDBx
CDBCreateOK
        systrap DmOpenDatabaseByTypeCreator(#DBType.l,#AppType.l,#dmModeReadWrite.w)
        move.l  a0,hDB(a5)
        systrap DmOpenDatabaseInfo(hDB(a5).l,&dbID(a6),&0,&0,&cardNo(a6),&0)
        tst.b   d0
        bne     CDBx
        systrap DmDatabaseInfo(cardNo(a6).w,dbID(a6).l,&0,&dbAttrs(a6),&0,&0,&0,&0,&0,&0,&0,&0,&0)
        tst.b   d0
        bne.s   CDBx
        or.w    #dmHdrAttrBackup,dbAttrs(a6)            ;ensure database is backed up
        systrap DmSetDatabaseInfo(cardNo(a6).w, dbID(a6).l,&0,&dbAttrs(a6),&0,&0,&0,&0,&0,&0,&0,&0,&0)
CDBx
endproc

proc CloseDatabase()
beginproc
        tst.l   hDB(a5)
        beq.s   CDx
        systrap DmCloseDatabase(hDB(a5).l)              ;close the database
        clr.l   hDB(a5)                                 ;just in case
CDx
endproc

proc WriteRecord(pidx.l,pRecord.l,lRecord.w)
beginproc
        systrap DmNewRecord(hDB(a5).l, pidx(a6).l, lRecord(a6).l)
        cmp.l   #0,a0
        beq.s   WRx
        systrap MemHandleLock(a0.l)
        move.l  a0,-(a7)
        systrap DmWrite(a0.l,#0.l, pRecord(a6).l, lRecord(a6).l)
        systrap MemPtrUnlock()
        clr.b   d0
WRx
endproc

proc ReplaceRecord(pidx.l,pRecord.l,lRecord.l)
beginproc
        systrap DmNumRecords(hDB(a5).l)
        movea.l pidx(a6),a0
        move.w  (a0),d1         ;get record number
        cmp.w   d1,d0
        ble.s   RRNoRem     
        systrap DmRemoveRecord(hDB(a5).l,(a0).w)
RRNoRem
        call    WriteRecord(pidx(a6).l,pRecord(a6).l,lRecord(a6).l)
endproc

proc GetRecord(recidx.w)
beginproc
        systrap DmQueryRecord(hDB(a5).l,recidx(a6).w)     ;get handle to record
        cmp.l   #0,a0
        beq.s   GRx
        systrap MemHandleLock(a0.l)
        clr.b   d0
GRx        
endproc

proc SetAppInfo(pHeader.l,lHeader.l)
local appInfoID.l
local appInfoP.l
local SAIdbID.l
local SAIcardNo.w
beginproc
        tst.l   hDB(a5)                                 ;need a valid handle to do this
        beq     SAIx
        systrap DmOpenDatabaseInfo(hDB(a5).l,&SAIdbID(a6),&0,&0,&SAIcardNo(a6),&0)
        tst.b   d0
        bne     SAIx
        systrap DmDatabaseInfo(SAIcardNo(a6).w,SAIdbID(a6).l,&0,&0,&0,&0,&0,&0,&0,&appInfoID(a6),&0,&0,&0)
        tst.b   d0
        bne     SAIx
        systrap DmNewHandle(hDB(a5).l,lHeader(a6).l)    ;get mem for app info
        cmp.l   #0,a0
        beq     SAIx
        systrap MemHandleToLocalID(a0.l)
        move.l  d0,appInfoID(a6)                        ;save local id
        systrap DmSetDatabaseInfo(SAIcardNo(a6).w, SAIdbID(a6).l,&0,&0,&0,&0,&0,&0,&0,&appInfoID(a6),&0,&0,&0)
        tst.b   d0
        bne.s   SAIx
        systrap MemLocalIDToLockedPtr(appInfoID(a6).l,SAIcardNo(a6).w)
        move.l  a0,appInfoP(a6)                         ;save pointer to app info
        systrap DmWrite(appInfoP(a6).l,#0.l,pHeader(a6).l,lHeader(a6).l)
        systrap MemPtrUnlock(appInfoP(a6).l)
SAIx 
endproc


proc GetAppInfo()
local GIdbID.l
local GIappInfoID.l
local GIcardNo.w
beginproc
        clr.w   GIcardNo(a6)
        systrap DmOpenDatabaseInfo(hDB(a5).l,&GIdbID(a6),&0,&0,&GIcardNo(a6),&0)
        tst.b   d0
        bne.s   GAIx
        clr.l   GIappInfoID(a6)
        systrap DmDatabaseInfo(GIcardNo(a6).w,GIdbID(a6).l,&0,&0,&0,&0,&0,&0,&0,&GIappInfoID(a6),&0,&0,&0)
        movea.l GIappInfoID(a6),a0
        cmpa.l  #0,a0
        beq.s   GAIx
        systrap MemLocalIDToLockedPtr(GIappInfoID(a6).l,GIcardNo(a6).w)
GAIx
endproc




;----------------------------------------------------------------------------------------
        include "pgmrcalc.res"  ;pilrc generated resources

        end