Funktioner, Procedurer och Parametrar I delar vi upp underprogram i två grupper : Funktioner: lämnar alltid ett värde som resultat Funktionsnamnet får ett värde i funktionen genom: funktionsnamn := expr; Anropet av funktionen gör att vi erhåller ett värde som alltid måste användas: t.ex. IF funcanrop = värde THEN variabel := funcanrop; Writeln(funcAnrop); Procedurer: lämnar inte något värde som resultat. (Bara bieffekter!) men kan fungera som en funktion som lämnar fler värden som resultat. Anropas genom ProcNamn(< lista av aktuella parametrar >); Parametrarna kan vara av två typer: Värdeparametrar som endast kan föra in värden till proceduren eller Referensparametrar som både kan föra in och ut värden till proceduren. Gäller även funktioner men man brukar aldrig använda referensparametrar i funktioner DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 1 / 21 DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 2 / 21 Funktioner, Procedurer och Parametrar funktionsspecifikation Funktioner, Procedurer och Parametrar procedurspecifikation FUNCTION funcnamn(par1, par2: typ1; ): uttyp; CONST TYPE VAR <satser>; funcnamn := expr ; <satser>; PROCEDURE procnamn(par1, par2: typ1; ); CONST TYPE VAR <satser>; OBS funcnamn := expr; kan finnas på fler ställen i funktionen!! DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 3 / 21 DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 4 / 21
Ex: PROCEDURE newsection(ch : Char; n: Integer); IF n = 0 THEN WriteLn ELSE Write(ch); newsection(ch, n-1); Om vi vill skapa ett underprogram som tar två värden och byter plats på dem: från till y x 3 5 y x 5 3 så kan vi inte använda en funktion utan måste vi använda en procedur! DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 5 / 21 DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 6 / 21 PROCEDURE swap(a, b: Integer); VAR tmp: Integer; tmp := a; a := b; b := tmp; Det fungerar inte eftersom a och b kommer att vara kopior av de aktuella parametrarna! Parametrar av detta slag kallas värdeparametrar. Man kan förhindra att värden kopieras genom att före en parameter skriva VAR. Detta gör att den anropande parameterns adress kopieras in i stället för dess värde. Parametrar av detta slag kallas referensparametrar. Programmet arbetar då med variabeln själv och inte en kopia. PROCEDURE swap(var a, b: Integer); VAR tmp:integer; tmp:=a; a:=b; b:= tmp; Nu fungerar det! Om man vill skriva ut tre tal i (fallande) storleksordning: DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 7 / 21 DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 8 / 21
Parametrar och globala variabler PROGRAM sortthree; VAR tal1, tal2, tal3: Integer; PROCEDURE swap(var a, b: Integer); VAR tmp:integer; tmp := a; a := b; b := tmp; PROCEDURE sort(var a, b, c: Integer); IF a < b THEN swap(a, b); IF a < c THEN swap(a, c); IF b < c THEN swap(b, c); Write( Ge tre tal: ); ReadLn(tal1, tal2, tal3); sort(tal1, tal2, tal3); WriteLn(tal1, tal2, tal3); END. Om en variabel inte finns deklarerad i den egna omgivningen så går man till närmaste yttre omgivning och letar. Detta betyder att om man glömmer att deklarera en variabel så riskerar man att påverka variabler i andra programdelar! Detta kallar vi bieffekter! Variabler som är deklarerade utanför det egna underprogrammet kallas globala variabler och de som är deklarerade i det egna underprogrammet kallas lokala (även parametrar) Ett exempel på användning av globala variabler och dess konsekvenser: DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 9 / 21 DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 10 / 21 PROGRAM tzt (input, output); PROCEDURE iterate; VAR i: Integer; PROCEDURE newsection (ch: char); newsection( * ); Writeln(i : 3, kub(i) : 10); IF i = 0 THEN WriteLn i := i - 1; ELSE IF i > 1 THEN iterate i := i - 1; END procedure iterate; Write(ch); newsection(ch) huvudprogram END i := 10; END procedure newsection; iterate; END. huvudprogram FUNCTION kub (x: Integer): Integer; kub := x * sqr(x) END function kub; Om man arbetar med globala storheter så är risken för fel stor!!! Ändra inte globala storheter. Måste de ändras så skicka dem som parametrar! I de listhanterare som definierades på tidigare föreläsningar kan vissa funktioner bytas mot procedurer för att få en mer naturlig användning, vilka? Alla de som bara påverkar listans inre struktur t.ex i den för enkellänkade sorterade listor create insert(l, e) delete(l, k) retrieve(l, k) empty(l) member(l, k) L i s t a D.v.s. insert och delete bör vara procedurer! DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 11 / 21 DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 12 / 21
PROCEDURE delete(l: listptr; key: keytype); VAR tmp : elementptr; PROCEDURE deleteelement(e: elementptr); IF e^.next <> NIL THEN IF equal(e^.next^.entry^.key, key) THEN tmp := e^.next; e^.next := tmp^.next; Dispose(tmp^.entry); Dispose(tmp) END ELSE IF lessthan(e^.next^.entry^.key, key) THEN deleteelement(e^.next) END deleteelement; delete IF NOT empty(l) THEN IF equal (L^.firstElement^.entry^.key, key) THEN tmp := L^.firstElement; L^.firstElement := tmp^.next; Dispose(tmp^.entry); Dispose(tmp) END ELSE deleteelement(l^.firstelement) END delete; DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 13 / 21 DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 14 / 21 Separatkompilering PROCEDURE insert(l: listptr; e: itemptr); VAR tmpptr: elementptr; PROCEDURE insertelement(var e: elementptr); IF e = nil THEN e := tmpptr ELSE IF NOT lessthan(e^.entry^.key, tmpptr^.entry^.key) THEN tmpptr^.next := e; e := tmpptr END ELSE insertelement(e^.next) END insertelement; insert NEW(tmpPtr); tmpptr^.next := nil; tmpptr^.entry := e; insertelement(l^.firstelement); IF tmpptr^.next = L^.firstElement THEN L^.firstElement := tmpptr END insert; För att kunna använda förut definierade programdelar finns i de flesta versioner möjlighet att inkludera separat kompilerade filer eller att textuellt inkludera moduler i det egna programmet. OBS! att detta inte är möjligt i standard! DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 15 / 21 DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 16 / 21
Exempel Kalkylatorn Vi kan dela upp detta program i tre delar: calc.p där själva huvudprogrammet ligger. commmand.p där alla funktioner och procedurer för att t.ex. hämta de kommandon vi ger till kalkylatorn finns. stack.p här finns alla funktioner och procedurer som vi behöver för en stack. Vi tittar lite närmare på command.p: module command interface; export command = (commandsequencepointer, commandsequencetype, commandpointer, commandtype, createcommandsequence, getcommand, putcommand, clearcommandsequence, emptycommandsequence); type commandpointer = ^commandtype; commandtype = record entry : char; next : commandpointer end; commandsequencepointer = ^commandsequencetype; commandsequencetype = record first, last : commandpointer end; DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 17 / 21 DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 18 / 21 function createcommandsequence: commandsequencepointer; function getcommand (cmd: commandsequencepointer): char; function putcommand (cmd: commandsequencepointer; acommand: char): commandsequencepointer; function clearcommandsequence (cmd: commandsequencepointer): commandsequencepointer; function emptycommandsequence (cmd: commandsequencepointer): boolean; end. module command implementation; import StandardInput; standardoutput; DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 19 / 21 DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 20 / 21
Den första satsen module command interface; talar om att allt det som finns fram till första end. är sådant som behövs för att det som står i nästa sats: export command = (commandsequencepointer, commandsequencetype, commandpointer, commandtype, createcommandsequence, getcommand, putcommand, clearcommandsequence, emptycommandsequence); skall kunna synas så att andra programdelar kan utnyttja det. Resten av filen, efter första end., innehåller de kompletta funktions- och procedurdeklarationerna. I implementationsdelen, som den andra delen kallas, kan man ha allt som går att ha i ett pascalprogram (men inte ett helt program). Det som definieras i denna del syns inte utåt. kompilera exempelvis med gpc -o kalk stack.p command.p calc.p och kör med kalk eller möjligen./kalk DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 20 / 21 DA2001 (Föreläsning 16) Datalogi 1 Hösten 2010 21 / 21