Máquina para lenguajes procedimentales con alcance
Transcripción
Máquina para lenguajes procedimentales con alcance
Máquina para lenguajes procedimentales con alcance estático Cómo leer este documento: En este documento se definen funciones así: Foo: Tipo1 x … x TipoN Tipo Estas funciones las podemos definir de una de las siguientes dos formas: o Foo(x1, …, xn) = …. ,donde cada xi es de tipo Tipoi o usando la notación de objetos: x1.foo(x2,…, xn) =.. Las pilas ya sean de valores o de ambientes se definen con la notación usada en CAML: [] para la pila vacía x::xs para la pila con al menos un elemento x, que está en el tope de la pila. Suponemos la función top definida así: o Top([]) = indefinida o Top(x::xs) = x La máquina tiene los siguientes componentes: Pila de evaluación Código Pila de ambientes El Código tiene los siguientes componentes Cod: Arreglo de instrucciones PC : posición en el arreglo Instrucción actual = Cod[PC] Un ambiente tiene los siguientes componentes: <direcciónDeRetorno, idAmbiente, idAmbienteEstáticoPadre,Memoria> idAmbiente idAmbienteEstáticoPadre Memoria Dirección de retorno Una memoria, MEM, es un arreglo de valores. Tenemos las siguientes funciones. Su definición es intuitiva. Una función para obtener el valor guardado en una posición de la memoria: Get: arregloValores x int valor mem.get(pos) Una función para obtener la memoria que se obtendría al modificar una memoria dada asignando un valor en una posición. Set: arregloValores x int x valor arregloValores mem.set(pos,val) Dado un ambiente, fr, tenemos las siguientes funciones selectoras: fr.mem() fr.id() fr.staticLink() fr.return() Ahora más funciones sobre un ambiente: Para obtener el valor de que se encuentra en una posición de la memoria GetValue: Ambiente x int valor fr.GetValue ( d) = fr.mem().get(d) Para obtener el ambiente resultante de modificar la memoria asignando un valor en una posición dada. SetValue : Ambiente x int x valor Ambiente fr.setValue(pos,val) = <fr.return(),fr.id(),fr.parent(),fr.mem.set(pos,val)> La máquina tiene una pila de ambientes. Necesitamos poder manejar esta pila también como un arreglo. La base de la pila está en la posición cero del arreglo. Se tiene que si un ambiente, fr, que está en la posición pos de la pila de ambientes, entonces fr.id() = pos. Para obtener el n-ésimo ambiente: getNthFrame: ambientes x int ambiente getNthFrame(fs, i) Para modificar el n-ésimo ambiente: setNthFrame: ambientes x int x ambiente ambientes setNthFrame(fs,i,f) Para la pila de ambientes tenemos la siguiente función para recorrer el link estático n veces desde un marco dado. Esta función se define así: NthParent: Ambientes x int x int Ambiente NthParent(pilaAmbientes, id, n) = If (n == 0) then actual Else NthParent(pilaAmbientes, pilaAmbientes[id].StaticLink(), n-1) Fi El índice del N-ésimo padre se puede obtener así: NthParent(pilaAmbientes,actual,cuantas).id() Para obtener el valor que se encuentra en la posición d de la memoria del ambiente que se encuentra recorriendo s pasos el enlace estático: getValueFrames(frames, s, d) = NthParent(frames, frames.top().id(), s).getValue(d) Para modificar los ambientes modificando la posición d de la memoria del ambiente que se encuentra recorriendo s pasos el enlace estático asignándole el valor val: SetValueFrames : Ambientes x int x int x valor Ambientes SetValueFrames(frames,s,d,val) = let f = NthParent(frames, frames.top().id(), s) in setNthFrame(frames, f.pos(), f.setValue(d.val)) endLet Las funciones descritas arriba nos sirven para describir el comportamiento de la máquina. Tenemos las siguientes instrucciones sencillas sobre la pila <Pila, Ambientes, <C, PC, push v>> <C,PC+1,C[PC+1]>> <v::Pila, Ambientes, <Pila, fs, <C, PC, pushV s,d>> Ambientes, <C,PC+1,C[PC+1]>> <fs.getValueFrames(s,d)::Pila, <v::Pila, fs, <C, PC, Asgmem s,d>> <C,PC+1,C[PC+1]>> <Pila, fs.setValueFrames(s,d), <x:Pila, Ambientes, <C, PC, pop>> <C,PC+1,C[PC+1]>> <Pila, Ambientes, <y::x:Pila, Ambientes, <C, PC, plus>> <C,PC+1,C[PC+1]>> <y::x:Pila, Ambientes, <C, PC, sub>> <C,PC+1,C[PC+1]>> <(x+y)::Pila, Ambientes, <(x-y)::Pila, Ambientes, … Suponemos que antes de invocar un método se empilan los parámetros y la traducción de una función empieza con desempilar sus parámetros y guardarlos en las posiciones de memoria respectivas. Al comenzar la ejecución: <[], [], <C, PC, start(dir)>> <C,dir,C[dir]>> <[], [< _,0,_, [0,..,0]>], La configuración final: <[], [[< _,0,_, MEM], <C, PC, END>> Un llamado de una función: <Pila, a:as, <C, PC, call(s, dir)>> < Pila, <PC+1,a.id()+1,nthParent(a::as,a.id(),s).id(),[0,..,0]>::a::as, <C,dir,C[dir]> > La salida de una función: <Pila, a::b::as, <C, PC, return >> <Pila, b::as, <C,a.return(),C[a.return()]>> Un ejemplo de traducción: Program test; Int 0 START 1 ASGMEM 0,0 2 3 4 5 6 7 8 9 10 11 PUSHV 1,0 PUSHV 0,0 PUSHV 0,0 TIMES PLUS ASGMEM 0,1 PUSHV 0,1 RETURN /* Se sacan los parametros al principio de la función */ ASGMEM 0,1 ASGMEM 0,0 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 PUSHV 0,0 PUSHV 1,1 EQ JMPF 19 PUSHV 0,1 ASGMEM 0,2 JMP 28 PUSHV 0,0 PUSH 1 PLUS PUSHV 0,1 PUSHV 1,0 Call 2,1 PLUS Call 1,10 ASGMEM 0,2 Pushv 0,2 RETURN 30 31 32 33 34 35 ASGMEM 0,1 ASGMEM 0,0 Push 0 Push 0 Call 0,10 return 36 37 38 39 40 41 42 Push 1 Asgmem 0,0 Push 3 Push 2 Call 0,30 Asgmem 0,1 End x; Int plusX (int y) { Int a; a := x + y*y; return a; } Int foo (int x, int n) Int goo(int i, int accum) { int a; if (i = n) then A = accum Else A = goo(i+1, acum+plusX(x)) Return A; } { Return goo(0,0) } { X:= 1; R := } foo(3,2); Para el seguimiento solo denotaré el estado de la pila de los ambientes y el PC para no tener que escribir tanto <[],[], 0> = Start 36 <[],[<_,0,_,[0,0]>], 36> == push 1 <[1],[<_,0,_,[0,0]>], 37> == asgmem 0,0 <[],[<_,0,_,[1,0]>], 38> == push 3 <[3],[<_,0,_,[1,0]>], 39> == push 2 <[2,3],[<_,0,_,[1,0]>], 40> == call 0,30 <[2,3],[ <41,1,0,[0,0]>,<_,0,_,[1,0]>], 30> =asgnmem 0,1 <[3],[<41,1,0,[0,2]>,<_,0,_,[1,0]>], 31>==asgnmem 0,0 <[],[<41,1,0,[3,2]>,<_,0,_,[1,0]>], 32>== push 0 <[0],[ <41,1,0,[3,2]>,<_,0,_,[1,0]>], 33>== push 0 <[0,0],[ <41,1,0,[3,2]>,<_,0,_,[1,0]>], 34>== call 0,10 <[0,0],[ <35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 10>== asgmem 0,1 <[0],[ <35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 11>== asgmem 0,0 <[],[ <35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 12>== pushv 0,0 <[0],[ <35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 13>== pushv 1,1 <[2,0],[ <35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 14>== EQ <[false],[ <35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 15>== JMPF 19 <[],[ <35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 19>== pushv 0,0 <[0],[ <35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 20>== push 1 <[1,0],[ <35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 21>== plus <[1],[ <35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 22>== pushV 0,1 <[0,1],[ <35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 23>== pushV 1,0 <[3,0,1],[ <35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 24>== call 2, 1 <[3,0,1],[ <25,3,0,[0,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 1>== asgmem 0,0 <[0,1],[ <25,3,0,[3,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 2>== PUSHV 1,0 <[1,0,1],[ <25,3,0,[3,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 3>== PUSHV 0,0 <[3,1,0,1],[ <25,3,0,[3,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 4>== PUSHV 0,0 <[3,3,1,0,1],[ <25,3,0,[3,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 5>== tIMES <[9,1,0,1],[ <25,3,0,[3,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 6>== pluS <[10,0,1],[ <25,3,0,[3,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 7>== ASGMEM 0,1 <[0,1],[ <25,3,0,[3,10]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 8>== PUSHV 0,1 <[10,0,1],[ <25,3,0,[3,10]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 9>== RETURN <[10,0,1],[ <35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 25>== PLUS <[10,1],[ <35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 26>== call 1,10 <[10,1],[ <27,3,1,[0,0,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 10>== asgmem 0,1 <[1],[ <27,3,1,[0,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 11>== asgmem 0,0 <[],[ <27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 12>== pushv 0,0 <[1],[ <27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 13>== pushv 0,0 <[2,1],[ <27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 14>== EQ <[false],[ <27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 15>== JMPF 19 <[],[ <27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 19>== pushV 0,0 <[1],[ <27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 20>== push 1 <[1,1],[ <27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 21>== plus <[2],[ <27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 22>== pushV 0,1 <[10,2],[ <27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 23>== pushV 1,0 <[3,10,2],[ <27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 24>== call 2,1 <[3,10,2],[ <25,4,0,[0,0]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 1>==asgmem 0,0 <[10,2],[ <25,4,0,[3,0]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 2>== pushV 1,0 <[1,10,2],[ <25,4,0,[3,0]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 3>== pushV 0,0 <[3,1,10,2],[ <25,4,0,[3,0]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 4>== pushV 0,0 <[3,3,1,10,2],[ <25,4,0,[3,0]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 5>== timeS <[9,1,10,2],[ <25,4,0,[3,0]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 6>== PLUs <[10,10,2],[ <25,4,0,[3,0]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 7>==asgmem 0,1 <[10,2],[ <25,4,0,[3,10]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 8>== PUSHv 0,1 <[10,10,2],[ <25,4,0,[3,10]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 8>== reTURN <[10,10,2],[ <27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 25>==plus <[20,2],[ <27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 26>==CALL 1,10 <[20,2],[ <27,4,1,[0,0,0]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 10>== ASGMEM 0,1 <[2],[ <27,4,1,[0,20,0]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 11>== ASGMEM 0,0 <[],[ <27,4,1,[2,20,0]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 12>== PUSHv 0,0 <[2],[ <27,4,1,[2,20,0]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 13>== PUSHv 1,1 <[2,2],[ <27,4,1,[2,20,0]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 14>== EQ <[true],[ <27,4,1,[2,20,0]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 15>== JMPF 19 <[],[ <27,4,1,[2,20,0]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 16>== PUSHV 0,1 <[20],[ <27,4,1,[2,20,0]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 17>== ASGMEM 0,2 <[],[ <27,4,1,[2,20,20]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 18>== JMP 28 <[],[ <27,4,1,[2,20,20]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 28>== PUSHV 0,2 <[20],[ <27,4,1,[2,20,20]>,<27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 29>== RETURN <[20],[ <27,3,1,[1,10,0]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 27>== ASGMEM 0,2 <[],[ <27,3,1,[1,10,20]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 28>== PUSHV 0,2 <[20],[ <27,3,1,[1,10,20]>,<35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 29>== RETURN <[20],[ <35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 27>== ASGMEM 0,2 <[],[ <35,2,1,[0,0,20]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 28>== PUSHV 0,2 <[20],[ <35,2,1,[0,0,0]>,<41,1,0,[3,2]>,<_,0,_,[1,0]>], 29>== RETURN <[20],[ <41,1,0,[3,2]>,<_,0,_,[1,0]>], 35>== RETURN <[20],[ <_,0,_,[1,0]>], 41>== ASGMEM 0,1 <[],[ <_,0,_,[1,20]>], 42>== END Solución tarea: Suponga que en la pila podemos guardar parejas que denotan una dirección absoluta: (Ambiente, posición en el ambiente) Agregamos las siguientes instrucciones: DEREF : supone que tenemos una dirección en el tope de la pila. Cambiamos la dirección por el valor guardado en esa dirección. AsgDirVal: supone que tenemos una dirección en el tope de la pila y debajo un valor. Se le asigna a la dirección de memoria ese valor PushDir s,d: empila la dirección en memoria correspondiente al ambiente que se encuentra recorriendo s veces el enlace estático y la dirección d. Suponga las siguientes funciones: Para obtener el valor que se encuentra en la posición d de la memoria del n-ésimo ambiente: getValueFramesAbs(frames, n, d) = frames.getNthFrame(n).getValue(d) Para modificar los ambientes modificando la posición d de la memoria del n-ésimo ambiente asignándole el valor val: SetValueFrames : Ambientes x int x int x valor Ambientes SetValueFramesAbs(frames,n,d,val) = let f = frames.getNthFrame(n) in setNthFrame(frames,n, f.setValue(d.val)) endLet <Pila, fs, <C, PC, pushDir s,d>> <(fs.getNtParent(s).id(),d)::Pila, Ambientes, <C,PC+1,C[PC+1]>> <(f,d)::Pila, Ambientes, <C, PC, deRef>> <getValueframesAbs(ambientes, f, d)::Pila, Ambientes, <C,PC+1,C[PC+1]>> <(f,d)::v::Pila, Ambientes, <C, PC, AsgDirVal >> < Pila, setValueframesAbs(Ambientes,f,d,v), <C,PC+1,C[PC+1]>> Entonces si tenemos un procedimiento definido así: Prog test; Int A, B; Proc proo(REF int x; Val int y, VR int z) { Z := x+y; X:= z+X; Z := 0; } { A := 1; B:= 2; Proo(A,B, B) } 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 START 24 ASGMEM 0,2 ASGMEM 0,1 ASGMEM 0,0 pushV 0,2 deref asgmem 0,3 pushV 0,0 deref pushV 0,1 plus AsgMem 0,3 pushV 0,3 pushV 0,0 deREF plus pushV 0,0 ASGDIRVAL push 0 ASGMEM 0,3 pushV 0,3 pushV 0,2 ASGDIRVAL return push 1 asgmem 0,0 push 1 asgmem 1,1 pushDir 0,0 29 30 31 32 push 0,1 pushDir 0,1 call 0, 1 end