perm filename EEXPAR.2[EAL,HE]1 blob
sn#676486 filedate 1982-09-27 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00004 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 {$NOMAIN Editor: Expression parser routine }
C00005 00003 (* aux routines for parsing expressions(cont): eGetArgs *)
C00019 00004 (* function to parse expressions: eExprParse *)
C00036 ENDMK
C⊗;
{$NOMAIN Editor: Expression parser routine }
%include eparse.hdr;
{ Externally defined routines from elsewhere: }
(* From ALLOC *)
function newNode: nodep; external;
procedure relNode(n: nodep); external;
(* From PAUX1 *)
function getDtype(n: nodep): datatypes; external;
function checkArg(n: nodep; d: datatypes): nodep; external;
function copyExpr(n: nodep; lcp: boolean): nodep; external;
function defNode(d: datatypes): nodep; external;
(* From PAUX2 *)
function getdim(n: nodep; var d: nodep): nodep; external;
(* From EAUX1A *)
function eMakeUVar(vartype: datatypes; vid: identp): varidefp; external;
function eVarLookup(id: identp): varidefp; external;
(* From ETOKEN *)
procedure eGetToken; external;
procedure eGetDelim(char: ascii); external;
procedure eDimCheck(n,d: nodep); external;
(* From PP *)
procedure ppLine; external;
procedure ppOutNow; external;
procedure ppChar(ch: ascii); external;
procedure pp5(ch: c5str; length: integer); external;
procedure pp10(ch: cstring; length: integer); external;
procedure pp10L(ch: cstring; length: integer); external;
procedure pp20(ch: c20str; length: integer); external;
procedure pp20L(ch: c20str; length: integer); external;
procedure ppInt(i: integer); external;
procedure ppReal(r: real); external;
procedure ppStrng(length: integer; s: strngp); external;
procedure ppDtype(d: datatypes); external;
procedure ppDelChar; external;
(* aux routines for parsing expressions(cont): eGetArgs *)
function eExprParse: nodep; external; {also FORWARD}
procedure eGetArgs(opn: nodep); external;
procedure eGetArgs;
var arg,n,np,nhdr,d: nodep; nargs,i: integer; dch: ascii; dat: datatypes;
absp,aref,func,qp,closep,b,bp: boolean; paramlist,v: varidefp;
procedure check1(d: datatypes);
begin
opn↑.arg1 := checkArg(opn↑.arg1,d); (* check datatype is right *)
end;
procedure check2(d1,d2: datatypes);
begin
with opn↑ do
begin
arg1 := checkArg(arg1,d1); (* check datatype is right for first arg *)
arg2 := checkArg(arg2,d2); (* and also check second *)
end;
end;
procedure check3(d1,d2,d3: datatypes);
begin
with opn↑ do
begin
arg1 := checkArg(arg1,d1); (* check datatype is right for first arg *)
arg2 := checkArg(arg2,d2); (* and also check second *)
arg3 := checkArg(arg3,d3); (* and also check third *)
end;
end;
begin
with opn↑ do
begin
if not ((op=arefop) or (op=callop)) then arg1 := nil;
arg2 := nil;
arg3 := nil
end;
if (opn↑.op = grinchop) then (* grinch is special *)
begin
i := cursor;
b := false;
repeat
with cursorStack[i] do
if stmntp then b := (movetype <= st↑.stype) and (st↑.stype <= centertype);
i := i - 1;
until (i = 1) or b;
if b then
opn↑.arg1 := copyExpr(cursorStack[i+1].st↑.cf,true) (* copy control frame *)
else
begin
pp20L(' Grinch can only occ',20); pp20('ur in a motion state',20);
pp5('ment.',5); ppLine;
opn↑.op := badop;
opn↑.arg1 := newNode;
opn↑.arg2 := defNode(transtype);
with opn↑.arg1↑ do
begin
ntype := exprnode;
op := grinchop;
arg1 := opn↑.arg2;
arg2 := nil;
arg3 := nil;
end
end
end
else if (opn↑.op <> inscalarop) then (* expecting some args *)
begin
i := 0;
nhdr := nil;
d := nil;
nargs := 1;
absp := false;
aref := false;
func := false;
qp := false;
closep := true;
b := true;
paramlist := nil;
case opn↑.op of
atan2op,
tmakeop,
fmakeop,
vsaxwrop,
dacop: nargs := 2;
vmakeop,
constrop: nargs := 3;
queryop: begin
qp := true;
nargs := 99; (* variable number of args *)
end;
absop: absp := true;
arefop: begin
aref := true;
n := opn↑.arg1↑.vari↑.a; (* check it's defined *)
if n = nil then nargs := 1 else nargs := n↑.numdims;
end;
callop: begin
func := true;
nargs := 0;
n := opn↑.arg1↑.vari↑.p; (* see if procedure is defined *)
if n <> nil then
begin
paramlist := n↑.paramlist;
if paramlist = nil then closep := false;
end;
end;
otherwise {do nothing};
end;
if not absp then
begin
eGetToken; (* looking for opening '(' or '[' *)
if aref then dch := '[' else dch := '(';
with eCurToken do
if (ttype <> delimtype) or (ch <> dch) then (* not there - complain *)
begin
eBackup := true;
if opn↑.op = timeop then
begin
b := false; (* don't bother looking for args *)
closep := false; (* so we know not to expect a closing ')' *)
opn↑.arg1 := defNode(svaltype); (* use zero *)
i := 1;
end
else if qp or not closep then (* query doesn't need to take any args *)
begin
b := false; (* don't bother looking for args *)
closep := false; (* so we know not to expect a closing ')' *)
end
else
begin
pp10(' Need a " ',9); ppChar(dch); pp10('" here. ',7); ppLine;
end;
end;
end;
while b do
begin (* get the next argument *)
if paramlist = nil then arg := eExprParse (* implies (not func) *)
else if paramlist↑.tbits <> 5 then arg := eExprParse
else
with eCurToken do
begin (* looking for array passed by reference *)
eGetToken;
bp := ttype = identtype;
if bp then
begin (* is it a defined variable and an array? *)
v := eVarLookup(id);
if v <> nil then bp := (v↑.vtype <> pconstype) and odd(v↑.tbits)
else bp := false;
end;
if bp then
begin
arg := newNode;
arg↑.ntype := leafnode;
arg↑.ltype := varitype;
arg↑.vari := v;
arg↑.vid := v↑.name;
end
else (* no good *)
begin
pp20L(' Need an array varia',20); pp10('ble here ',8); ppLine;
arg := nil;
end;
end;
if arg <> nil then (* got one *)
begin
i := i + 1;
if func or aref or qp then (* add to arg list *)
begin
np := newNode;
np↑.ntype := listnode;
if func and (paramlist <> nil) then
with paramlist↑ do
begin (* check parameter for correct data type *)
np↑.lval := checkArg(arg,vtype);
if dtype <> nil then d := dtype↑.dim (* use dimension if it exists *)
else (* otherwise use default *)
if (vtype = transtype) or (vtype = frametype) then
d := distancedim↑.dim
else if vtype = rottype then d := angledim↑.dim
else d := nodim↑.dim;
eDimCheck(arg,d);
d := nil;
paramlist := next;
if paramlist = nil then nargs := i;
end
else if aref then
begin
np↑.lval := checkArg(arg,svaltype);
eDimCheck(arg,nodim↑.dim);
end
else np↑.lval := arg;
if nhdr = nil then nhdr := np else n↑.next := np;
n := np;
n↑.next := nil;
end
else
begin
with opn↑ do
case i of
1: arg1 := arg;
2: arg2 := arg;
3: arg3 := arg;
end;
end;
eGetToken; (* looking for separating ',' *)
with eCurToken do
if (ttype <> delimtype) or (ch <> ',') then b := false (* that's it *)
end
else b := false;
end;
if absp then (* looking for closing '|' *)
begin
with eCurToken do
if (ttype <> reswdtype) or (rtype <> optype) or (op <> absop) then
begin (* not there - complain *)
eBackup := true;
pp10(' Need a " ',9); ppChar(chr(174B)); pp10('" here. ',7); ppLine;
end;
if opn↑.arg1 = nil then opn↑.arg1 := defNode(svaltype);
dat := getdtype(opn↑.arg1); (* now figure out what sort of || we've got *)
if dat = svaltype then opn↑.op := sabsop
else if dat = vectype then opn↑.op := vmagnop
else opn↑.op := tmagnop;
end
else if closep then
begin
if aref then dch := ']' else dch := ')';
eBackup := true; (* looking for closing ')' or ']' *)
eGetDelim(dch);
end
else eBackup := true;
if func or aref then (* store arg list in arg 2 *)
begin
while (i < nargs) or (paramlist <> nil) do
begin (* make sure we return the right size arg list *)
i := i + 1;
np := newNode;
np↑.ntype := listnode;
if func and (paramlist <> nil) then
begin
np↑.lval := defNode(paramlist↑.vtype);
paramlist := paramlist↑.next;
if paramlist = nil then nargs := i;
end
else np↑.lval := defNode(svaltype);
if nhdr = nil then nhdr := np else n↑.next := np;
n := np;
n↑.next := nil;
end;
opn↑.arg2 := nhdr;
end
else if qp then opn↑.arg2 := nhdr (* store arg list in arg 2 *)
else
with opn↑ do
case op of (* check args are of proper type & dimension *)
sqrtop: check1(svaltype);
logop,
expop,
asinop,
acosop,
adcop: begin
check1(svaltype);
eDimCheck(arg1,nodim↑.dim);
end;
timeop: begin
check1(svaltype);
eDimCheck(arg1,timedim↑.dim);
end;
sinop,
cosop,
tanop: begin
check1(svaltype);
eDimCheck(arg1,angledim↑.dim);
end;
dacop,
atan2op: begin
check2(svaltype,svaltype);
eDimCheck(arg1,nodim↑.dim);
eDimCheck(arg2,nodim↑.dim);
end;
vmakeop: begin
check3(svaltype,svaltype,svaltype);
eDimCheck(arg2,getdim(arg1,d));
eDimCheck(arg3,d);
end;
unitvop: check1(vectype);
vsaxwrop: begin
check2(vectype,svaltype);
eDimCheck(arg2,angledim↑.dim);
end;
tposop,
torientop,
tinvrtop: check1(transtype);
taxisop: check1(rottype);
fmakeop,
tmakeop: begin
check2(rottype,vectype);
eDimCheck(arg1,angledim↑.dim);
if op = fmakeop then eDimCheck(arg2,distancedim↑.dim);
end;
deproachop: begin
check1(frametype);
eDimCheck(arg1,distancedim↑.dim);
end;
constrop: begin
check3(vectype,vectype,vectype);
eDimCheck(arg1,distancedim↑.dim);
eDimCheck(arg2,distancedim↑.dim);
eDimCheck(arg3,distancedim↑.dim);
end;
otherwise {do nothing};
end;
if aref then (* if array, check it's defined *)
if opn↑.arg1↑.vari↑.a = nil then nargs := i; (* it's not, assume all ok *)
if (not qp) and (i <> nargs) then
begin
pp10L(' Need ',6); ppInt(nargs); pp20(' arguments here. ',16); ppLine;
end;
if d <> nil then relNode(d); (* done with dimension node *)
end;
end;
(* function to parse expressions: eExprParse *)
function eExprParse; (* : nodep *)
var expstack, opstack: nodep; precstack: array [0..10] of integer;
opsp,i,j: integer; n,np: nodep; vp: varidefp; opseen,done,badp: boolean;
st: statementp;
function badexpr: nodep;
var n: nodep;
begin
n := newNode;
badexpr := n;
with n↑ do
begin ntype:= exprnode; op:= badop; arg1:= nil; arg2:= newNode; arg3:= nil end;
n := n↑.arg2;
with n↑ do begin ntype := leafnode; ltype := transtype; t := niltrans end;
if not badp then
begin
pp20L(' Bad expression ',15); ppLine;
badp := true;
end;
end;
function gettype(n: nodep): datatypes;
var d: datatypes;
begin
d := getdtype(n);
if (d = rottype) or (d = frametype) then d := transtype;
gettype := d;
end;
procedure pushexp(n: nodep);
begin
n↑.next := expstack;
expstack := n;
end;
procedure cpushexp(n: nodep);
begin
if opseen then pushexp(n) (* all okay *)
else
begin (* yow! - we just saw an operand - complain *)
pp20L(' Bad expression - co',20); pp20('nsecutive operands ',18); ppline;
end;
opseen := false; (* expecting an operator *)
end;
function popexp: nodep;
var n: nodep;
begin
if expstack <> nil then
begin
n := expstack;
expstack := expstack↑.next;
n↑.next := nil;
popexp := n;
end
else
begin (* this probably can't happen, but... *)
pp20L(' Gack! - parse opera',20); pp20('nd expression stack ',20);
pp10('underflow ',9); ppLine;
popexp := badexpr;
end;
end;
procedure pushop;
begin
if opsp <= 9 then
begin
n↑.next := opstack;
opstack := n;
opsp := opsp + 1;
precstack[opsp] := i;
end
else
begin
pp20L(' Gack! - parse opera',20); pp20('tor expression stack',20);
pp10(' overflow ',9); ppLine;
end;
opseen := true; (* expecting an operand *)
end;
procedure popop;
var n,n1,d: nodep; d1,d2: datatypes;
begin (* popop *)
d := nil;
n := opstack;
opstack := n↑.next;
opsp := opsp - 1;
with n↑ do
begin (* get its operand(s) *)
next := nil;
arg3 := nil;
if (op = negop) or (op = notop) then arg2 := nil
else
begin
arg2 := popexp;
if expstack = nil then
begin (* whoops - wasn't any arg 2 *)
expstack := arg2;
arg2 := badexpr;
end;
end;
arg1 := popexp;
if op <= modop then
begin
arg1 := checkArg(arg1,svaltype); (* check datatypes of args *)
if op <> notop then arg2 := checkArg(arg2,svaltype);
if (op <= sneop) or (op >= maxop) then (* relation, max, min & mod *)
begin
if (op <> intop) and (op <> idivop) then (* don't care about these *)
eDimCheck(arg2,getdim(arg1,d)); (* does arg2 match dimension of arg1 *)
end
else if op <= sexpop then (* check dimensions too *)
begin (* args better be dimensionless *)
eDimCheck(arg1,nodim↑.dim);
if op <> notop then eDimCheck(arg2,nodim↑.dim);
end
end
else if op = vdotop then
begin
arg1 := checkArg(arg1,vectype);
arg2 := checkArg(arg2,vectype);
end
else if op = wrtop then
begin
arg1 := checkArg(arg1,vectype);
arg2 := checkArg(arg2,transtype);
end
else if op = ftofop then
begin
arg1 := checkArg(arg1,transtype);
arg2 := checkArg(arg2,transtype);
eDimCheck(arg2,getdim(arg1,d)); (* does arg2 match dimension of arg1 *)
end
else if op >= addop then (* need to determine proper op for given args *)
case op of
negop: begin (* see if snegop or vnegop *)
d1 := getdtype(arg1);
if d1 = svaltype then op := snegop
else if d1 = vectype then op := vnegop
else begin n1 := badexpr; n1↑.arg1 := n; n := n1 end;
end;
addop: begin
eDimCheck(arg2,getdim(arg1,d)); (* does arg2 match dimension of arg1 *)
d1 := gettype(arg1);
d2 := gettype(arg2);
if d1 = undeftype then begin d1 := d2; arg1↑.vari↑.vtype := d1 end;
if d2 = undeftype then
begin
if d1 = transtype then d2 := vectype else d2 := d1;
arg2↑.vari↑.vtype := d2
end;
if (d1 = svaltype) and (d2 = svaltype) then op := saddop
else if (d1 = vectype) and (d2 = vectype) then op := vaddop
else if (d1 = transtype) and (d2 = vectype) then op := tvaddop
else begin op := saddop; n1 := badexpr; n1↑.arg1 := n; n := n1 end;
end;
subop: begin
eDimCheck(arg2,getdim(arg1,d)); (* does arg2 match dimension of arg1 *)
d1 := gettype(arg1);
d2 := gettype(arg2);
if d1 = undeftype then begin d1 := d2; arg1↑.vari↑.vtype := d1 end;
if d2 = undeftype then
begin
if d1 = transtype then d2 := vectype else d2 := d1;
arg2↑.vari↑.vtype := d2
end;
if (d1 = svaltype) and (d2 = svaltype) then op := ssubop
else if (d1 = vectype) and (d2 = vectype) then op := vsubop
else if (d1 = transtype) and (d2 = vectype) then op := tvsubop
else begin op := ssubop; n1 := badexpr; n1↑.arg1 := n; n := n1 end;
end;
mulop: begin
d1 := gettype(arg1);
d2 := gettype(arg2);
if d1 = undeftype then begin d1 := d2; arg1↑.vari↑.vtype := d1 end;
if d2 = undeftype then begin d2 := d1; arg2↑.vari↑.vtype := d2 end;
if (d1 = svaltype) and (d2 = svaltype) then op := smulop
else if (d1 = svaltype) and (d2 = vectype) then op := svmulop
else if (d1 = vectype) and (d2 = svaltype) then op := vsmulop
else if (d1 = vectype) and (d2 = vectype) then op := crossvop
else if (d1 = transtype) and (d2 = vectype) then op := tvmulop
else if (d1 = transtype) and (d2 = transtype) then op := ttmulop
else begin op := smulop; n1 := badexpr; n1↑.arg1 := n; n := n1 end;
if (op = ttmulop) or (op = tvmulop) then
eDimCheck(arg2,getdim(arg1,d)); (* does arg2 match dimension of arg1 *)
end;
divop: begin
d1 := gettype(arg1);
d2 := gettype(arg2);
if d1 = undeftype then
begin d1 := svaltype; arg1↑.vari↑.vtype := d1 end;
if d2 = undeftype then
begin d2 := svaltype; arg2↑.vari↑.vtype := d2 end;
if (d1 = svaltype) and (d2 = svaltype) then op := sdivop
else if (d1 = vectype) and (d2 = svaltype) then op := vsdivop
else begin op := sdivop; n1 := badexpr; n1↑.arg1 := n; n := n1 end;
end;
otherwise {do nothing};
end;
pushexp(n); (* save it as operand for next operator *)
if d <> nil then relNode(d);
end;
end (* popop *);
function opprecedence(op: exprtypes): integer;
var i: integer;
begin
i := 0;
case op of
eqvop: i := 1;
orop,
xorop: i := 2;
andop: i := 3;
sltop,
sleop,
seqop,
sgeop,
sgtop,
sneop: i := 4;
addop,
subop: i := 5;
wrtop: i := 6;
mulop,
divop,
maxop,
minop,
idivop,
modop,
vdotop: i := 7;
sexpop,
ftofop: i := 8;
negop,
notop: i := 9;
otherwise {do nothing};
end;
opprecedence := i;
end;
begin (* eExprParse *)
expstack := nil;
opstack := nil;
opsp := 0;
precstack[0] := -1;
done := false;
opseen := true; (* expecting an operand *)
badp := false; (* haven't complained about expression yet *)
repeat
eGetToken;
with eCurToken do
begin
case ttype of (* see what we've got *)
labeldeftype:
begin done := true; eBackup := true end;
delimtype:
if ch = '(' then
begin
cpushexp(eExprParse); (* get the parenthesized expression *)
eGetDelim(')'); (* get the closing ')' *)
end
else begin done := true; eBackup := true end;
reswdtype:
if rtype <> optype then begin done := true; eBackup := true end
else if not opseen and (op = absop) then
begin done := true; eBackup := true end
else if not (opseen and (op = addop)) then (* we want to ignore unary + *)
begin
if opseen and (op = subop) then op := negop;
n := newNode;
n↑.ntype := exprnode;
n↑.op := op;
i := opprecedence(op);
if i = 0 then (* really an operand *)
begin
eGetArgs(n); (* get any arguments op needs *)
cpushexp(n); (* save operand for its operator *)
end
else if opseen and ((op <> negop) and (op <> notop)) then
begin (* yow! - we just saw an operator - complain *)
pp20L(' Bad expression - co',20); pp20('nsecutive operators ',19); ppLine;
end
else if i > precstack[opsp] then (* higher precedence so push on stack *)
pushop
else (* lower precedence *)
begin
while (i <= precstack[opsp]) and (i < 9) do popop; (* 9 = prec(not,neg) *)
pushop;
end;
end;
constype: cpushexp(cons);
identtype:
begin
vp := eVarLookup(id);
if vp = nil then
begin (* undefined variable *)
vp := eMakeUVar(undeftype,id); (* define it somewhat *)
eGetToken; (* see if it's supposed to be a procedure or array *)
eBackup := true; (* we're just peeking *)
if newVarOk then pp10L(' Undeclare',10);
if (ttype = delimtype) and ((ch = '(') or (ch = '[')) then
if ch = '[' then
begin
vp↑.tbits := 1; (* array *)
vp↑.a := nil;
if newVarOk then pp20('d array variable ',16);
end
else
begin
vp↑.tbits := 2; (* procedure *)
vp↑.p := nil;
if newVarOk then pp20('d procedure ',11);
end
else if newVarOk then pp10('d variable',10);
if newVarOk then
begin pp20(' - will try to defin',20); pp5('e it.',5); ppLine end;
end;
if vp↑.vtype = pconstype then (* constant *)
begin
np := newNode; (* need to make a pointer to it *)
with np↑ do
begin
ntype := leafnode;
ltype := pconstype;
cname := vp;
pcval := vp↑.c;
end;
cpushexp(np);
end
else if odd(vp↑.tbits) or (vp↑.tbits = 2) then
begin (* array reference or procedure call *)
n := newNode;
with n↑ do
begin
ntype := exprnode;
if odd(vp↑.tbits) then op := arefop else op := callop;
arg1 := newNode;
end;
with n↑.arg1↑ do
begin
ntype := leafnode;
ltype := varitype;
vari := vp;
vid := vp↑.name;
end;
eGetArgs(n); (* get subscripts/parameters *)
cpushexp(n);
end
else (* variable *)
begin
n := newNode;
with n↑ do
begin
ntype := leafnode;
ltype := varitype;
vari := vp;
vid := vp↑.name;
end;
cpushexp(n);
end;
end;
otherwise {do nothing};
end {case};
end {with};
until done;
while opsp > 0 do popop; (* bind the rest of the operators *)
if expstack <> nil then eExprParse := popexp (* return what's left on stack *)
else eExprParse := nil;
while expstack <> nil do relNode(popexp); (* probably don't need, but... *)
end;