MODULE AGRS; (* Modul AGRS - Attributed Graph Rewriting System Najnizi modul. Ovde su implementirani apstraktni tipovi podataka (ADT) koji cine graf izraza. *) CONST MaxStack= 6495; Fixed*= MAX(INTEGER); Unique*= 0; TYPE Term*= POINTER TO TermDesc; (* ADT Term - korenska klasa *) TermDesc*= RECORD indirection-: Term; END; SubTerm*= POINTER TO SubTermDesc; (* ADT SubTerm *) SubTermDesc*= RECORD(TermDesc) query-: Term; END; FieldTail= POINTER TO RECORD(TermDesc) END; Field*= POINTER TO RECORD(SubTermDesc) (* ADT Field *) tail: FieldTail; END; Name*= POINTER TO NameDesc; (* ADT Name *) NameDesc*= RECORD(TermDesc) age-: INTEGER; END; Equation= POINTER TO RECORD(TermDesc) param: Name; next: Equation; END; Tree*= POINTER TO TreeDesc; (* ADT Tree *) TreeDesc*= RECORD(TermDesc) attributes: Equation; constant: BOOLEAN; END; Atomic*= POINTER TO AtomicDesc; (* ADT Atomic *) AtomicDesc*= RECORD(TermDesc) END; OpenTree*= POINTER TO RECORD(TreeDesc) (* ADT OpenTree *) END; Class*= POINTER TO ClassDesc; (* ADT Class *) ClassDesc*= RECORD(TreeDesc) END; ClosedClass*= POINTER TO ClosedClassDesc; (* ADT ClosedClass *) ClosedClassDesc*= RECORD(ClassDesc) END; Block*= POINTER TO RECORD(TreeDesc) END; HandlerType*= PROCEDURE; SystemTerm*= POINTER TO RECORD(TermDesc) (* ADT SystemTerm *) handler: HandlerType; END; Disjunction*= POINTER TO RECORD(TermDesc) (* ADT Disjunction *) alternative-: Term; END; TermBackup= NameDesc; TermStack*= POINTER TO TermStackDesc; TermStackDesc= RECORD top-: Term; rest-: TermStack; END; VAR stack: POINTER TO ARRAY MaxStack OF TermBackup; continuation-,paramStack*: TermStack; sp, eldestAsked*: INTEGER; allConstant: BOOLEAN; otherwise*: Name; lastResult-, lastAtom-, Failure*, result*: Term; failName*: Name; Undefined-, Variable-: SystemTerm; LocalRestore, StackRestore, FunctionResult: SystemTerm; GuardTrap*, MatchTrap: SystemTerm; PROCEDURE Push*(t: Term); VAR newStack: TermStack; BEGIN IF t#NIL THEN NEW(newStack); newStack.top:= t; newStack.rest:= continuation; continuation:= newStack; END; END Push; PROCEDURE (t: Term) Init*(ind: Term); BEGIN t.indirection:= ind; END Init; PROCEDURE (t: Term) Reduce*; BEGIN t.indirection.Reduce; END Reduce; PROCEDURE (t: Term) Value*(): Term; VAR spOld,spNew: INTEGER; contOld: TermStack; BEGIN spOld:= sp; contOld:= continuation; Push(FunctionResult); t.Reduce; spNew:= sp; ASSERT((sp=spOld) & (continuation=contOld)); RETURN result END Value; PROCEDURE (t: Term) Evaluate*(query: Term): Term; VAR spOld,spNew: INTEGER; contOld,contNew: TermStack; BEGIN spOld:= sp; contOld:= continuation; Push(FunctionResult); Push(query); t.Reduce; spNew:= sp; contNew:= continuation; ASSERT((sp=spOld) & (continuation=contOld)); RETURN result END Evaluate; PROCEDURE (t: Term) Actual*(): Term; BEGIN RETURN t END Actual; PROCEDURE Continue*; VAR spOld,spNew: INTEGER; next: Term; newTop: TermStack; BEGIN spOld:= sp; next:= continuation.top; continuation:= continuation.rest; IF lastResult IS Atomic THEN NEW(newTop); newTop.top:= lastResult; newTop.rest:= paramStack; paramStack:= newTop; next.Reduce; paramStack:= paramStack.rest; ELSE next.Reduce; END; spNew:= sp; ASSERT(spNew=spOld, 255); END Continue; PROCEDURE Continued*(): BOOLEAN; BEGIN IF continuation.top=FunctionResult THEN continuation:= continuation.rest; RETURN FALSE ELSE Continue; RETURN TRUE END; END Continued; PROCEDURE ResultHandler*; BEGIN result:= lastResult; END ResultHandler; PROCEDURE Fail*; VAR spOld: INTEGER; BEGIN WHILE continuation.top#FunctionResult DO continuation:= continuation.rest; END; continuation:= continuation.rest; result:= Failure; END Fail; PROCEDURE (t: Name) Init*(contents: Term); BEGIN t.Init^(contents); t.age:= 0; END Init; PROCEDURE (t: Name) Actual*(): Term; BEGIN IF t.indirection IS SystemTerm THEN RETURN t ELSIF t.indirection IS Name THEN ASSERT(t.indirection#t); RETURN t.indirection.Actual() ELSE RETURN t.indirection END; END Actual; PROCEDURE (t: Name) Assign*(contents: Term); BEGIN (* ASSERT(contents#t); *) INC(sp); stack[sp].indirection:= t.indirection; stack[sp].age:= t.age; t.indirection:= contents; t.age:= sp; END Assign; PROCEDURE (t: Name) Restore*(); BEGIN ASSERT(sp>0); ASSERT(t.age=sp); t.indirection:= stack[sp].indirection; t.age:= stack[sp].age; DEC(sp); END Restore; PROCEDURE (t: Name) Reduce*; VAR saveLastName: Term; spOld,spNew: INTEGER; BEGIN spOld:= sp; saveLastName:= lastResult; lastResult:= t; t.indirection.Reduce; lastResult:= saveLastName; IF t.age=spStart THEN oldEdges.param.age:= -oldEdges.param.age; END; oldEdges:= oldEdges.next; END; WHILE t#NIL DO IF t.param.age<0 THEN t.param.age:= -t.param.age; ELSE oldEdges:= newEdges; NEW(newEdges); newEdges.param:= t.param; newEdges.indirection:= t.param.indirection; newEdges.next:= oldEdges; END; t:= t.next; END; base.attributes:= newEdges; base.constant:= FALSE; ELSE IF base IS Name THEN NEW(newTerm); newTerm.indirection:= base; newTerm.constant:= FALSE; newTerm.attributes:= NIL; oldEdges:= t; WHILE oldEdges#NIL DO NEW(newEdges); newEdges.param:= oldEdges.param; newEdges.indirection:= oldEdges.param.indirection; newEdges.next:= newTerm.attributes; newTerm.attributes:= newEdges; oldEdges:= oldEdges.next; END; base:= newTerm; END; END; END Enrich; PROCEDURE (t: Equation) ActualizeUsing(base: Equation); VAR follow: Equation; link: Name; spStart: INTEGER; BEGIN spStart:= sp; follow:= t; WHILE follow#NIL DO IF follow.indirection IS Name THEN link:= follow.indirection(Name); link.age:= -link.age-1; END; follow:= follow.next; END; WHILE base#NIL DO IF base.param.age<0 THEN base.param.Assign(base.indirection); END; base:= base.next; END; follow:= t; WHILE follow#NIL DO IF follow.indirection IS Name THEN link:= follow.indirection(Name); IF link.age<0 THEN link.age:= -link.age-1; ELSE follow.param.indirection:= link.indirection; follow.indirection:= link.indirection; link.indirection:= stack[link.age].indirection; link.age:= -stack[link.age].age-1; END; END; follow:= follow.next; END; sp:= spStart; END ActualizeUsing; PROCEDURE (t: Equation) Actual(): Term; VAR newEdge: Equation; newMeaning,actualRest: Term; BEGIN newMeaning:= t.indirection.Actual(); IF newMeaning=t.indirection THEN IF t.next#NIL THEN actualRest:= t.next.Actual(); IF actualRest#t.next THEN NEW(newEdge); newEdge.param:= t.param; newEdge.indirection:= newMeaning; newEdge.next:= actualRest(Equation); RETURN newEdge END; END; IF t.indirection IS Name THEN allConstant:= FALSE; END; RETURN t ELSE NEW(newEdge); newEdge.param:= t.param; newEdge.indirection:= newMeaning; IF t.next=NIL THEN newEdge.next:= NIL; ELSE actualRest:= t.next.Actual(); newEdge.next:= actualRest(Equation); END; RETURN newEdge END; END Actual; PROCEDURE (t: Tree) AddProperty*(param: Name; meaning: Term); VAR newEdge: Equation; BEGIN newEdge:= t.attributes; WHILE (newEdge#NIL) & (newEdge.param#param) DO newEdge:= newEdge.next; END; IF newEdge=NIL THEN NEW(newEdge); newEdge.param:= param; newEdge.next:= t.attributes; t.attributes:= newEdge; END; newEdge.indirection:= meaning; END AddProperty; PROCEDURE (t: Tree) RemoveProperty*(param: Name); VAR follow,oldEdge: Equation; BEGIN oldEdge:= t.attributes; WHILE (oldEdge#NIL) & (oldEdge.param#param) DO follow:= oldEdge; oldEdge:= oldEdge.next; END; IF oldEdge#NIL THEN IF oldEdge=t.attributes THEN t.attributes:= oldEdge.next; ELSE follow.next:= oldEdge.next; END; END; END RemoveProperty; PROCEDURE Attributed(VAR root: Term; prop: Name; value: Term); VAR newTerm: OpenTree; BEGIN NEW(newTerm); IF root IS Name THEN newTerm.indirection:= root; newTerm.constant:= FALSE; newTerm.attributes:= NIL; ELSIF root IS OpenTree THEN newTerm^:= root(OpenTree)^; ELSE RETURN END; newTerm.AddProperty(prop,value); root:= newTerm; END Attributed; PROCEDURE (t: Tree) Reduce*; VAR spOld,spNew: INTEGER; attr,follow,newEq: Equation; newTerm: OpenTree; BEGIN spOld:= sp; attr:= t.attributes; IF attr=NIL THEN t.Reduce^; ELSE attr.UnfoldActual(); t.indirection.Reduce; attr.Enrich(result); attr.Restore(); END; spNew:= sp; ASSERT(spOld=spNew); END Reduce; PROCEDURE (t: Tree) Actual*(): Term; VAR newTerm: Tree; newAttributes: Term; BEGIN IF t.constant OR (t.attributes=NIL) THEN t.constant:= TRUE; RETURN t END; allConstant:= TRUE; newAttributes:= t.attributes.Actual(); IF allConstant & (newAttributes=t.attributes) THEN t.constant:= TRUE; RETURN t ELSE NEW(newTerm); newTerm.indirection:= t.indirection; newTerm.attributes:= newAttributes(Equation); (* newTerm.constant:= TRUE; *) RETURN newTerm END; END Actual; PROCEDURE (t: Tree) Init*(ind: Term); BEGIN t.indirection:= ind; t.attributes:= NIL; t.constant:= FALSE; END Init; PROCEDURE (t: Tree) ProcessAttributes*(proc: PROCEDURE(attr: Name; VAR meaning: Term)); VAR follow: Equation; BEGIN follow:= t.attributes; WHILE follow#NIL DO proc(follow.param,follow.indirection); follow:= follow.next; END; END ProcessAttributes; PROCEDURE (t: Class) Reduce*; VAR spOld: INTEGER; attr: Equation; BEGIN spOld:= sp; attr:= t.attributes; IF attr=NIL THEN t.Reduce^; ELSE attr.Unfold(); Continue; attr.Restore(); END; ASSERT(spOld=sp); END Reduce; PROCEDURE (t: Class) Actual*(): Term; BEGIN RETURN t END Actual; PROCEDURE (t: ClosedClass) Reduce*; VAR query,root: Term; BEGIN query:= continuation.top; root:= query; WHILE ~(root IS Name) DO root:= root.indirection; END; WITH root: Name DO result:= t.attributes.Association(root); IF result=NIL THEN result:= t.attributes.Association(otherwise); IF result=NIL THEN Continue; RETURN END; END; root.Assign(Undefined); continuation:= continuation.rest; Push(result); query.Reduce(); root.Restore(); END; END Reduce; PROCEDURE (t: SystemTerm) Reduce*; BEGIN t.handler; END Reduce; PROCEDURE (t: SystemTerm) InitHandler*(h: HandlerType); BEGIN t.handler:= h; END InitHandler; PROCEDURE (t: Atomic) Reduce*; VAR saveLastAtom: Term; BEGIN saveLastAtom:= lastAtom; lastAtom:= t; t.indirection.Reduce; lastAtom:= saveLastAtom; END Reduce; PROCEDURE (t: Atomic) Compare*(reference: Term; VAR lessEq,grEq: BOOLEAN); BEGIN lessEq:= (t.indirection=reference.indirection); grEq:= lessEq; END Compare; PROCEDURE AtomicHandler*; VAR saveLastResult: Term; BEGIN eldestAsked:= Fixed; saveLastResult:= lastResult; lastResult:= lastAtom; Continue; lastResult:= saveLastResult; END AtomicHandler; PROCEDURE Equal*(t1,t2: Term): BOOLEAN; VAR lessEq,greaterEq: BOOLEAN; PROCEDURE AttrEqual(attr1,attr2: Equation): BOOLEAN; VAR oldSp: INTEGER; copy: Equation; BEGIN copy:= attr1; oldSp:= sp; copy.Unfold(); WHILE (attr1#attr2) & (attr2#NIL) & (attr2.param.age>oldSp) & Equal(attr2.indirection,attr2.param.indirection) DO attr1:= attr1.next; attr2:= attr2.next; END; copy.Restore(); RETURN attr1=attr2 END AttrEqual; BEGIN IF t1=t2 THEN RETURN TRUE END; IF t1.indirection#t2.indirection THEN RETURN FALSE END; WITH t1: Tree DO WITH t2: Tree DO IF t1.attributes#NIL THEN RETURN AttrEqual(t1.attributes,t2.attributes) END; ELSE RETURN FALSE END; ELSE WITH t1: Atomic DO t1.Compare(t2,lessEq,greaterEq); RETURN lessEq&greaterEq ELSE RETURN TRUE END; END; END Equal; PROCEDURE EnvironmentPath*(t: Name): SubTerm; VAR result,previous: SubTerm; position: INTEGER; BEGIN NEW(result); result.Init(t.indirection); position:= t.age; WHILE position#0 DO previous:= result; NEW(result); result.indirection:= stack[position].indirection; result.query:= previous; position:= stack[position].age; END; RETURN result END EnvironmentPath; PROCEDURE RestoreReversed(list: Equation); BEGIN IF list#NIL THEN RestoreReversed(list.next); list.param.Assign(continuation.top); continuation:= continuation.rest; END; END RestoreReversed; PROCEDURE RestoreLocals; VAR locals: Equation; BEGIN locals:= continuation.top(Equation); continuation:= continuation.rest; RestoreReversed(locals); Continue; WHILE locals#NIL DO locals.param.Restore(); locals:= locals.next; END; END RestoreLocals; PROCEDURE RestoreLocal; VAR local: Name; BEGIN local:= continuation.top(Name); continuation:= continuation.rest; local.Assign(continuation.top); continuation:= continuation.rest; Continue; local.Restore(); END RestoreLocal; PROCEDURE PushLocal*(t: Name); BEGIN Push(t.indirection); Push(t); Push(LocalRestore); END PushLocal; PROCEDURE (t: Block) Reduce*; VAR follow: Equation; newTerm: Name; BEGIN follow:= t.attributes; IF follow#NIL THEN REPEAT Push(follow.param.indirection); IF follow.indirection=Variable THEN NEW(newTerm); newTerm.Init(Variable); follow.param.Assign(newTerm); ELSE follow.param.Assign(follow.indirection.Actual()); END; follow:= follow.next; UNTIL follow=NIL; Push(t.attributes); Push(StackRestore); t.indirection.Reduce; IF result IS Tree THEN t.attributes.ActualizeUsing(result(Tree).attributes); END; t.attributes.Enrich(result); t.attributes.Restore; ELSE t.indirection.Reduce; END; END Reduce; PROCEDURE GuardHandler*; VAR follow: Equation; pattern: Term; newTerm: OpenTree; BEGIN pattern:= continuation.top; continuation:= continuation.rest; IF lastResult=pattern.indirection THEN IF pattern IS Tree THEN follow:= pattern(Tree).attributes; WHILE follow#NIL DO Push(follow.indirection); Push(follow.param.indirection); Push(MatchTrap); follow:= follow.next; END; END; Continue; ELSIF (lastResult IS Name) & (lastResult.indirection=Variable) THEN WITH lastResult: Name DO lastResult.Assign(pattern.Actual()); Continue; Attributed(result,lastResult,lastResult.indirection); lastResult.Restore(); END; ELSIF (pattern IS Atomic) & Equal(pattern,lastResult) THEN Continue; ELSE Fail; END; END GuardHandler; PROCEDURE MatchHandler; VAR lhs,pattern: Term; r: TermStack; BEGIN lhs:= continuation.top; r:= continuation; continuation:= continuation.rest; pattern:= continuation.top; IF pattern IS Name THEN continuation:= continuation.rest; pattern:= pattern.Value(); IF (pattern IS Name) & (pattern.indirection=Variable) THEN WITH pattern: Name DO pattern.Assign(lhs); Continue; pattern.Restore(); Attributed(result,pattern,lhs); END; RETURN ELSE Push(pattern); END; END; Push(GuardTrap); lhs.Reduce; END MatchHandler; PROCEDURE (t: Disjunction) Reduce*; VAR oldCont: TermStack; BEGIN oldCont:= continuation; t.indirection.Reduce; IF result=Failure THEN continuation:= oldCont; t.alternative.Reduce; END; END Reduce; PROCEDURE (t: Disjunction) InitAlternative*(alt: Term); BEGIN t.alternative:= alt; END InitAlternative; PROCEDURE Unify*(t1,t2: Term); BEGIN Push(t2); Push(t1); MatchHandler; END Unify; PROCEDURE MakeLocalBlock*(locals,body: Term): Term; VAR newTerm: Block; BEGIN IF locals=NIL THEN RETURN body END; NEW(newTerm); newTerm.Init(body); IF locals IS Tree THEN locals:= locals(Tree).attributes; END; newTerm.attributes:= locals(Equation); RETURN newTerm END MakeLocalBlock; PROCEDURE MakeAlternative*(pattern,ifMatch: Term): Term; VAR sub1,sub2: SubTerm; (* newDis: Disjunction; *) acc: Equation; PROCEDURE Locals(t: Equation); VAR newEq: Equation; BEGIN IF t#NIL THEN IF t.indirection IS Name THEN IF (acc=NIL) OR (acc.Association(t.indirection(Name))=NIL) THEN NEW(newEq); newEq.param:= t.indirection(Name); newEq.indirection:= Variable; newEq.next:= acc; acc:= newEq; END; ELSIF t.indirection IS Tree THEN Locals(t.indirection(Tree).attributes); END; Locals(t.next); END; END Locals; BEGIN WITH pattern: Tree DO NEW(sub1); NEW(sub2); sub1.query:= ifMatch; sub2.query:= pattern; sub2.indirection:= GuardTrap; sub1.indirection:= sub2; acc:= NIL; Locals(pattern.attributes); (* IF noMatch=NIL THEN *) RETURN MakeLocalBlock(acc,sub1) (* END; NEW(newDis); newDis.indirection:= MakeLocalBlock(acc,sub1); newDis.alternative:= noMatch; RETURN newDis *) ELSE RETURN ifMatch END; END MakeAlternative; BEGIN NEW(stack); sp:= 0; continuation:= NIL; NEW(FunctionResult); FunctionResult.Init(NIL); FunctionResult.InitHandler(ResultHandler); lastAtom:= NIL; NEW(lastResult); lastResult.Init(NIL); NEW(Variable); Variable.Init(NIL); Variable.InitHandler(Continue); NEW(Undefined); Undefined.Init(NIL); Undefined.InitHandler(Continue); NEW(LocalRestore); LocalRestore.Init(NIL); LocalRestore.InitHandler(RestoreLocal); NEW(StackRestore); StackRestore.Init(NIL); StackRestore.InitHandler(RestoreLocals); NEW(GuardTrap); GuardTrap.Init(NIL); GuardTrap.InitHandler(GuardHandler); NEW(MatchTrap); MatchTrap.Init(NIL); MatchTrap.InitHandler(MatchHandler); END AGRS.