$title ('EXPRESSION MODULE') expres: do; /* modified 4/8/81 R. Silberstein modified 4/24/81 R. Silberstein modified 8/19/81 R. Silberstein */ /* This is the module to evaluate expressions and instruction operands. The entry subroutines are: EXPRESSION (resultfield) byte OPERAND byte The expression subroutine evaluates a numeric or memory expression. The "operand" routine evalates a single instruction operand. Both routines return FALSE if an error is found,otherwise true. */ $include (:f1:macro.lit) $include (:f1:expr.x86) $include (:f1:ermod.ext) $include (:f1:exglob.ext) $INCLUDE (:F1:SUBR2.EXT) $eject /************** global variables: ************/ dcl maxlev lit '5', /* max no of nested parenthesis */ parlevel byte, /* current no of parenthesis level */ stck(600) byte, /* local stack within module */ savestack addr, /* save of initial entry stack */ expresserr byte, /* error flag */ noforward byte, /* true if undefined symbols to be neglected */ bracketlegal byte, /* true if bracket expression is legal */ udefflag byte; /* true if an udefined element found */ $eject $include (:f1:bnf.tex) $eject /************ michellaneous subroutines: ***********/ exprexit: proc (dummy); dcl dummy byte; stackptr=savestack; end exprexit; errorexit: proc; /* return if wrong syntax */ dcl dummy byte at (.udefflag); expresserr=false; call exprexit(dummy); end errorexit; clearoperand: proc(p); dcl p address,oper based p operandstruc; CALL FILL (0, .OPER.BASEINDEX - .OPER + 1, P); OPER.BASEINDEX = NOOVERRIDEBIT; end clearoperand; /* routine to test if current token is member of a given set of special characters. Entry parameters: base = exitvalue if token is 1. member of set numbel = no of elements in set pt = pointer to list of elements Exit value: routine= 0ffh if token not member of list routine= base+i if token is element i, token is skipped */ specmember: proc (base,numbel,pt) byte; dcl (base,numbel,i) byte,pt address,list based pt (1) byte; i=0ffh; do while (i:=i+1) < numbel; if specialtoken(list(i)) then$do call scan; return base+i; end$if; end$while; return 0ffh; end specmember; /* Routine to test if current token is member of a given set of operators. Entry/exit : see "specmember" header */ opmember: proc(base,numbel,pt) byte; dcl (base,numbel,i,byteval) byte,pt address,list based pt (1) byte; if token.type = operator then$do i=0ffh; do while (i:=i+1) < numbel; byteval=token.value; if byteval=list(i) then$do call scan; return base+i; end$if; end$while; end$if; return 0ffh; end opmember; /* test if both operands are numbers, if not, error */ numbtest: proc (ptl,ptr); dcl (ptl,ptr) address,(left based ptl,rigth based ptr) operandstruc; if (left.stype <> number) or (rigth.stype <> number) then call errorexit; end numbtest; /* find resulting symbol type as result of an addition or a subtraction, test if illegal types */ typefind: proc (ptl,ptr); dcl (ptl,ptr) address,stype byte, (left based ptl,rigth based ptr) operandstruc; dcl err lit '07fh', crosstab(9) byte data(number,variable,lab,variable,err,err, lab,err,err); typeno: proc(typ) byte; dcl typ byte; if typ=number then return 0; if typ=variable then return 1; if typ=lab then return 2; call errorexit; /* illegal member of expression */ end typeno; stype=crosstab(typeno(left.stype)*3+typeno(rigth.stype)); if stype=err then call errorexit; left.length=left.length+rigth.length; left.stype=stype; end typefind; /* take care of segment specification in front of variables syntax: : variable, =ES/SS/DS/CS */ segover: proc(pt) byte; dcl pt address,segreg based pt byte; if (token.type=reg) and (token.descr=dwrd) then$do if nextch=':' then$do segreg=token.value; segreg=(shl(segreg,segtypecount) and segtypebit) or segmbit; call scan; /* skip segment register */ call scan; /* skip : */ return 0; end$if; end$if; return 0ffh; end segover; /* create a number operator */ createnumber: proc(p,n); dcl p address,n addr,oper based p operandstruc; call clearoperand(.oper); oper.stype=number; oper.offset=n; end createnumber; /* get current identificator, perform symboltable lookup set undefined-symbol-flag if symbol not defined, treat undefined symbols as numbers */ finditem: proc (pt); dcl pt address,left based pt operandstruc,symbptr address,i byte; if token.type <> ident then$do call clearoperand(.left); left.stype=token.type; left.sflag=token.descr; left.offset=token.value; else$do if findsymbol(acclen,.accum(0),.symbptr) then$do call getattributes(symbptr,.left); i=left.stype; if (i=neglected) or (i=doubledefined) or (i=udefsymb) then$do udefflag=true; left.stype=number; expresserr=false; call errmsg(udefsymbol); end$if; else$do /* symbol undefined - test if it is to be "neglected" */ expresserr=false; if noforward then$do if not newsymbol(acclen,.accum,.symbptr) then$do call errorexit; end$if; left.stype=neglected; call enterattributes(symbptr,.left); end$if; call errmsg(udefsymbol); udefflag=true; end$if; end$if; call scan; end finditem; /* recognize the different symboltypes for the II (identicator) subroutine */ symtyp: proc(pt) byte; dcl pt address, left based pt operandstruc,i byte; if specialtoken('$') then return 0; if specialtoken('.') then return 1; if token.type=string then$do if (acclen > 0) and (acclen < 3 ) then return 2; return 4; /* error */ end$if; call finditem(.left); i=left.stype; if (i=pseudo) or (i=operator) or (i=spec) then return 4; /* error */ return 3; end symtyp; $eject /********** subroutines for each "NON-TERMINAL" **********/ /********** in "BNF" syntax **********/ II: proc (pt) reentrant; dcl pt address,left based pt operandstruc, doublebyt addr at (.accum(0)),saveb byte; do case symtyp(.left); do; /* $ */ left.stype=lab; left.sflag=wrd; left.offset=cip; if csegspec then$do /* pick up current segment specification */ left.sflag=shl(csegtype,segtypecount) or segmbit or wrd; left.segment=csegvalue; end$if; call scan; /* skip $ */ end; do; /* . number */ call scan; /* skip . */ call finditem(.left); if left.stype <> number then call errorexit; left.stype=variable; left.segment=curdseg; left.sflag=shl(rds,segtypecount) and segtypebit; if dspec then left.sflag=left.sflag or segmbit; end; do; /* string */ if acclen=1 then$do call createnumber(.left,accum(0)); else$do saveb=accum(0); accum(0)=accum(1); accum(1)=saveb; call createnumber(.left,doublebyt); end$if; call scan; /* skip string */ end; do; end; /* number,label,variable,register */ call errorexit; end$case; end II; BB: proc (pt) reentrant; dcl pt address,left based pt operandstruc; if specialtoken('(') then$do if (parlevel:=parlevel+1) > maxlev-1 then call errorexit; call scan; call EE(.left); if not specialtoken(')') then call errorexit; parlevel=parlevel-1; call scan; return; end$if; if specialtoken(leftbracket) then$do if not bracketlegal then call errorexit; bracketlegal=false; call scan; /* skip leftbracket */ call clearoperand(.left); left.stype=number; if not bracketexpr(.left) then call errorexit; return; end$if; call II(.left); end BB; FF: proc (pt) reentrant; dcl pt address,left based pt operandstruc,rigth operandstruc, opertyp byte,val addr; if (opertyp:=opmember(0,5,.(oseg,ooffset,otype,olength,olast))) <> 0ffh then$do call BB(.left); do case opertyp; do; /* SEG */ if (left.sflag and segmbit) = 0 then call errorexit; call createnumber(.left,left.segment); end; do; /* OFFSET */ call createnumber(.left,left.offset); end; do; /* TYPE */ call createnumber(.left,left.sflag and typebit); end; do; /* LENGTH */ call createnumber(.left,left.length); end; do; /* LAST */ if (val:=left.length) = 0 then val=1; call createnumber(.left,val-1); end; end$case; else$do call BB(.left); do while opmember(0,1,.(optr)) <> 0ffh; call BB(.rigth); left.stype=rigth.stype; left.segment=rigth.segment; left.offset=rigth.offset; left.baseindex=rigth.baseindex; left.sflag=(left.sflag and typebit) or (rigth.sflag and (not typebit)); end$while; end$if; end FF; SS: proc (pt) reentrant; dcl pt address,left based pt operandstruc,segreg byte; if segover(.segreg) <> 0ffh then$do call FF(.left); left.sflag=(left.sflag and (not segtypebit)) or segreg; left.baseindex=left.baseindex and (not nooverridebit); else$do call FF(.left); end$if; end SS; MM: proc (pt) reentrant; dcl pt address,left based pt operandstruc,opertyp byte; if (opertyp:=specmember(0,2,.('+-'))) <> 0ffh then$do call MM(.left); call numbtest(.left,.left); if opertyp=1 then$do left.offset=-left.offset; end$if; else$do call SS(.left); end$if; end MM; TT: proc (pt) reentrant; dcl pt address,left based pt operandstruc,rigth operandstruc, opertyp byte,(leftval,rigthval) addr; call MM(.left); do while (opertyp:=specmember(0,2,.('*/')) and opmember(2,3,.(omod,oshl,oshr))) <> 0ffh; call MM(.rigth); call numbtest(.left,.rigth); leftval=left.offset; rigthval=rigth.offset; do case opertyp; leftval=leftval*rigthval; leftval=leftval/rigthval; leftval=leftval mod rigthval; if rigthval>0 and rigthval<16 then leftval=shl(leftval,rigthval); if rigthval>0 and rigthval<16 then leftval=shr(leftval,rigthval); end$case; left.offset=leftval; end$while; end TT; PP: proc (pt) reentrant; dcl pt address,left based pt operandstruc,rigth operandstruc, opertyp byte; call TT(.left); do while (opertyp:=specmember(0,2,.('+-'))) <> 0ffh; call TT(.rigth); call typefind(.left,.rigth); if opertyp=0 then$do left.offset=left.offset+rigth.offset; else$do left.offset=left.offset-rigth.offset; end$if; end$while; end PP; RR: proc (pt) reentrant; dcl pt address,left based pt operandstruc,rigth operandstruc, opertyp byte,(leftval,rigthval) addr; call PP(.left); if (opertyp:=opmember(0,6,.(oeq,olt,ole,ogt,oge,one))) <> 0ffh then$do call PP(.rigth); call numbtest(.left,.rigth); leftval=left.offset; rigthval=rigth.offset; do case opertyp; leftval = (leftval = rigthval); leftval = (leftval < rigthval); leftval = (leftval <= rigthval); leftval = (leftval > rigthval); leftval = (leftval >= rigthval); leftval = (leftval <> rigthval); end$case; IF LEFTVAL = 0FFH THEN LEFTVAL = 0FFFFH; left.offset=leftval; end$if; end RR; NN: proc (pt) reentrant; dcl pt address,left based pt operandstruc; if opmember(0,1,.(onot)) <> 0ffh then$do call NN(.left); call numbtest(.left,.left); left.offset=not left.offset; else$do call RR(.left); end$if; end NN; AA: proc (pt) reentrant; dcl pt address,left based pt operandstruc,rigth operandstruc; call NN(.left); do while opmember(0,1,.(oand)) <> 0ffh; call NN(.rigth); call numbtest(.left,.rigth); left.offset=left.offset and rigth.offset; end$while; end AA; EE: proc (pt) reentrant; dcl pt address,left based pt operandstruc,right operandstruc, opertype byte; call AA(.left); do while (opertype:=opmember(0,2,.(oor,oxor))) <> 0ffh; call AA(.right); call numbtest(.left,.right); if opertype=0 then$do left.offset=left.offset or right.offset; else$do left.offset=left.offset xor right.offset; end$if; end$while; end EE; $eject /*************** MAIN SUBROUTINES ***************/ realexpress: proc(pt); dcl pt address,oper based pt operandstruc, dummy byte at(.udefflag); savestack=stackptr; /* use local stack for reentrant routines */ stackptr=.stck(length(stck)); call EE(.oper); call exprexit(dummy); end realexpress; express: proc(pt) byte; dcl pt address,oper based pt operandstruc; expresserr=true; udefflag=false; parlevel=0; call realexpress(.oper); if udefflag then$do oper.stype=number; oper.sflag=byt; oper.offset=0; end$if; return expresserr; end express; /* normal expression */ expression: proc (pt) byte public; dcl pt address; noforward=false; bracketlegal=false; return express(pt); end expression; /* special expression - mark all undefined symbols as "neglected" */ noforwardexpr: proc(pt) byte public; dcl pt address; noforward=true; bracketlegal=false; return express(pt); end noforwardexpr; OPERND: PROC BYTE; dcl exitvalue byte,pt address,oper based pt operandstruc; pt=.operands(nooper); exitvalue=true; bracketlegal=true; exitvalue=express(pt); if specialtoken(leftbracket) then$do if bracketlegal then$do call scan; exitvalue=exitvalue and bracketexpr(pt); else$do exitvalue=false; end$if; end$if; return exitvalue; END OPERND; OPERAND: PROC BYTE PUBLIC; NOFORWARD = FALSE; RETURN OPERND; END OPERAND; NOFORWARDOPER: PROC BYTE PUBLIC; NOFORWARD = TRUE; RETURN OPERND; END NOFORWARDOPER; end$module expres;