Files
Digital-Research-Source-Code/MPM OPERATING SYSTEMS/MPM-86/MPM-86 2.0 SOURCES/10/EXPR.PLM
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

516 lines
14 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

$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: <over>: variable, <over>=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;