OperatorPrecedenceParseImpl.Mesa
Last Edited by: Spreitzer, July 8, 1985 8:28:48 pm PDT
DIRECTORY OperatorPrecedenceParse;
OperatorPrecedenceParseImpl: CEDAR PROGRAM
EXPORTS OperatorPrecedenceParse =
BEGIN OPEN OperatorPrecedenceParse;
CantReduce: PUBLIC SIGNAL [ops: TokenList, args: ArgList] RETURNS [use: REF ANY] = CODE;
CantFix: PUBLIC SIGNAL [token: Token] RETURNS [fix: Token] = CODE;
DoesntFix: PUBLIC ERROR [token: Token, expectingArg, willGetArg: BOOLEAN] = CODE;
TerminateErr: PUBLIC ERROR [argStack: ArgList, opStack: TokenList] = CODE;
LastReduceErr: PUBLIC ERROR [args: ArgList, ops: TokenList] = CODE;
InvalidToken: PUBLIC ERROR [token: Token] = CODE;
endClass: TokenClass ← NEW [TokenClassRep ← [leftPrec: 1, rightPrec: 0]];
beginClass: TokenClass ← NEW [TokenClassRep ← [leftPrec: 0, rightPrec: 1, Reduce: ReduceEnd]];
argClass: PUBLIC TokenClass ← NEW [TokenClassRep ← [leftPrec: 0, rightPrec: 0]];
end: PUBLIC Token ← [class: endClass];
begin: Token ← [class: beginClass];
Parse: PUBLIC PROC [context: REF ANY, GetToken: TokenProc] RETURNS [ans: Arg] =
BEGIN
Reduce: PROC =
BEGIN
GrabArg: PROC = {
sr ← Union[sr, argStack.first.sr];
args ← CONS[argStack.first, args];
argStack ← argStack.rest};
GrabOp: PROC = {
sr ← Union[sr, opStack.first.sr];
ops ← CONS[opStack.first, ops];
opStack ← opStack.rest};
args: ArgList ← NIL;
ops: TokenList ← NIL;
new: REF ANY;
sr: SourceRange ← nullSR;
WHILE TRUE DO
IF opStack.first.class.rightPrec > 0 THEN GrabArg[];
GrabOp[];
IF opStack = NIL THEN EXIT;
IF opStack.first.class.rightPrec # ops.first.class.leftPrec THEN EXIT;
ENDLOOP;
IF ops.first.class.leftPrec > 0 THEN GrabArg[];
IF ops.first.class.Reduce # NIL THEN new ← ops.first.class.Reduce[sr, context, ops, args] ELSE new ← SIGNAL CantReduce[ops, args];
argStack ← CONS[[sr, new], argStack];
END;
argStack: ArgList ← NIL;
opStack: TokenList ← LIST[begin];
expectingArg: BOOLEANTRUE;
useOld: BOOLEANFALSE;
old: Token;
WHILE opStack # NIL DO
next: Token;
IF useOld THEN {next ← old; useOld ← FALSE} ELSE next ← GetToken[context, expectingArg];
IF next.class = NIL THEN ERROR InvalidToken[next];
IF next.class.rightPrec = 1 THEN ERROR InvalidToken[next];
IF next.class.leftPrec = 1 AND next # end THEN ERROR InvalidToken[next];
IF expectingArg # (next.class.leftPrec = 0) THEN
BEGIN
old ← next;
IF next.class.leftFix.class = NIL THEN next ← SIGNAL CantFix[next] ELSE next ← next.class.leftFix;
IF expectingArg # (next.class.leftPrec = 0) THEN ERROR DoesntFix[next, expectingArg, old.class.leftPrec = 0];
IF (next.class.rightPrec > 0) # (old.class.leftPrec = 0) THEN ERROR DoesntFix[next, expectingArg, old.class.leftPrec = 0];
useOld ← TRUE;
END;
IF next.class.leftPrec > 0 THEN
BEGIN
WHILE opStack.first.class.rightPrec > next.class.leftPrec DO Reduce[] ENDLOOP;
END;
IF next.class.leftPrec = 0 AND next.class.rightPrec = 0 THEN argStack ← CONS[[next.sr, next.asArg], argStack] ELSE opStack ← CONS[next, opStack];
expectingArg ← next.class.rightPrec > 0;
IF (next.class.leftPrec > 0) AND NOT expectingArg THEN Reduce[];
ENDLOOP;
IF argStack = NIL THEN ERROR TerminateErr[argStack, opStack];
IF argStack.rest # NIL THEN ERROR TerminateErr[argStack, opStack];
ans ← argStack.first;
END;
Union: PROC [a, b: SourceRange] RETURNS [c: SourceRange] =
BEGIN
IF a = nullSR THEN RETURN [b];
IF b = nullSR THEN RETURN [a];
c.first ← MIN[a.first, b.first];
c.last ← MAX[a.last, b.last];
END;
ReduceEnd: Reducer =
BEGIN
IF args = NIL THEN ERROR LastReduceErr[args, ops];
IF args.rest # NIL THEN ERROR LastReduceErr[args, ops];
IF ops = NIL THEN ERROR;
IF ops.rest = NIL THEN ERROR LastReduceErr[args, ops];
IF ops.rest.rest # NIL THEN ERROR LastReduceErr[args, ops];
reduced ← args.first.arg;
END;
END.