Skip to content

Latest commit

 

History

History
333 lines (266 loc) · 11.4 KB

pascal_5.md

File metadata and controls

333 lines (266 loc) · 11.4 KB

Hier volgt alweer deel 5 van mijn PASCAL cursus. Ik hoop dat mensen het leuk vinden dat ik dit doe, anders kan ik beter ophouden. PASCAL 5 ========

���� Alweer deel 5 van deze cursus! Wat gaat de tijd toch ���� snel(NvdR: snif). Deze keer een kleine cursus, omdat het ���� over een gemakkelijk onderwerp handelt. Deze cursus ���� behandelt namelijk het maken van eigen types.

Bij het declareren van een variabele konden we tot nog toe alleen maar kiezen uit de standaard type's (integer, real, boolean, etc.). In PASCAL is het echter ook mogelijk om je eigen type's te maken en wel als volgt:

TYPE OpsomType = {Item1,Item2,Item3}; SubrangeType = 1..10; ArrayType = ARRAY[1..10] OF AnderType;

Je kunt dus een opsommingstype maken bijvoorbeeld:

DagenVanDeWeek = {Maandag,Dindag,Woensdag,Donderdag,Vrijdag, Zaterdag,Zondag}

Of een subrangetype (van elk ander type). Bijvoorbeeld:

DagenVanDeMaand = 1..31 (* integers dus *)

Of een ARRAY type. Bijvoorbeeld:

WekenVanEenJaar = ARRAY[1..52] OF DagenVanDeWeek

Vervolgens kun je de types gebruiken, maar let wel goed op met toekenningen e.d. Neem bijvoorbeeld het volgende:

VAR Dag : DagenVanDeWeek;

Dan mag

Dag := Maandag;

Maar niet

Write("Geef dag : "); Readln(Dag);

De type's verschillen immers. Bij Readln lees je een integer, real of string, maar niet een DagenVanDeWeek.

Wat ook niet kan is

Dag := Maandag; Writeln("Het is vandaag ",Dag);

En wel om dezelde reden als bij Readln. Wat wel kan is

Dag := Maandag; CASE Dag OF Maandag : Write("Maandag"); Dinsdag : write("Dinsdag"); . . .

Experimenteer maar eens een beetje met het cre�ren van eigen type's en je zult zien dat dit heel handig kan zijn.

Een functie die een beetje met deze type declaratie te maken heeft is de IN functie. Deze werkt als volgt:

IF Dag IN {Maandag,Dinsdag,Woensdag,Donderdag,Vrijdag} THEN writeln("Dit is een werkdag");

Je kunt dus met IN kijken of de waarde van een variabele in een gegeven verzameling zit. Die verzameling moet je wel eerst opsommen, maar dat is een kleine prijs om te betalen tegenover (in dit geval) 5 IF statements.

Zo, dit was kort maar krachtig(NvdR: tja).

Jeroen "Ik beloof beterschap" Smael �� En de Pascal cursus gaat verder... PASCAL 6 ========

���� Tja, vorige keer was ik er niet helemaal met mijn koppie ���� bij, want ik heb een deel van wat ik moest vertellen ���� vergeten(NvdR: de eikel!). Ik heb verteld dat je eigen ���� types kunt maken, maar ��n van de belangrijkste types ben ik vergeten. Ik ben namelijk het RECORD en de string vergeten. Hierbij dan ook mijn excuses en de aanvullende informatie.

          TYPE

Over de string kan ik heel snel zijn. De string is een "PACKED ARRAY[1..?] of char". Een PACKED ARRAY is een array waarvan de lengte intern wordt bijgehouden. Iets wat bij een string noodzakelijk is...

PROGRAM StringVoorbeeld;

TYPE
  Woord = PACKED ARRAY[1..10] OF char;

VAR
  A : Woord;
  B : Woord;

BEGIN          (* StringVoorbeeld *)
  A:='hallo';
  B:=A;
  Writeln(A);
  Writeln(B);
END.           (* StringVoorbeeld *)

Het bovenstaande programma lijkt goed (A:=B mag bij arrays, zolang de arrays van het zelfde type en even groot zijn), maar er zal twee keer het woord 'hallo' verschijnen, met daarachter 5 ongewilde karakters (mocht het zo zijn dat het programma niet al een foutmelding geeft bij de opdracht A:='hallo', omdat dat niet voldoet aan de voorwaarde van dezelfde grootte). Bij een PACKED ARRAY zoekt de computer zelf uit hoe groot het ARRAY is en lost alle genoemde problemen dus op. Bij een aantal compilers is het mogelijk om een type te gebruiken dat "string" heet. Genoemd type wordt gebruikt bij TYPE met "woord = string[10]" of bij VAR met "A : string[10]".

Dat ik RECORD's vergeten ben is veel erger, omdat daar nou juist de meeste leuke dingen mee gedaan kunnen worden. Een klein voorbeeldje:

PROGRAM RecordVoorbeeld;

TYPE
  datum = RECORD
            dag   : 1..31;
            maand : 1..12;
            jaar  : 0..5000;
          END;
  persoonsgegevens = RECORD
                       naam : string[30];    (* ik maak
                                                gebruik van
                                                het string
                                                type *)
                       geboortedatum : datum;
                     END;

VAR
  persoon : persoonsgegevens;

BEGIN          (* RecordVoorbeeld *)
  persoon.naam:='Jeroen Smael';
  persoon.geboortedatum.dag:=27;
  persoon.geboortedatum.maand:=10;
  persoon.geboortedatum.jaar:=1970;
END.           (* RecordVoorbeeld *)

Op deze manier kun je dus hele "gegevensbomen" aanleggen. Bij de persoonsgegevens kun je ook nog het adres, de geboortestad, etc., etc. toevoegen. Alles wat je maar wilt. Zoals je ziet moet je wel, om bij de velden te komen een punt gebruiken. Deze punt is vergelijkbaar met de \ van DOS (het scheidings- teken van subdirectory's). Tevens zie je dat ik pas jarig ben geweest, maar dat terzijde(NvdR: inderdaad, dat boeit ons, ja).

Met genoemde velden zijn verder natuurlijk wel alle bewerkingen mogelijk, zo zou de opdracht: "persoon.geboortejaar:=persoon.geboortejaar+1" een geldige opdracht zijn.

Een hele bruikbare "opdracht" bij records is de CASE opdracht. Deze maakt het mogelijk om ��n of meerdere veldnamen weg te laten. Met gebruikmaking van de CASE opdracht zou het vorige (hoofd)programma er als volgt hebben uitgezien:

BEGIN          (* RecordVoorbeeld *)
  CASE Persoon OF
    naam:='Jeroen Smael';
    geboortedatum.dag:=27;
    geboortedatum.maand:=10;
    geboortedatum.jaar:=1970;
  END;
END.           (* RecordVoorbeeld *)

Hetzelfde (de CASE) kunnen we natuurlijk ook toepassen bij de geboortedatum en dan ziet het (hoofd)programma er als volgt uit:

BEGIN          (* RecordVoorbeeld *)
  CASE Persoon OF
    naam:='Jeroen Smael';
    CASE geboortedatum OF
      dag:=27;
      maand:=10;
      jaar:=1970;
    END;
  END;
END.           (* RecordVoorbeeld *)

Zoals te zien spaart dit een heleboel tikken. Let er natuurlijk wel op dat de CASE afgesloten wordt door een END (anders krijg je een compiler fout).

         Files

Het zou uiteraard ook leuk zijn als we met PASCAL toegang zouden hebben tot de diskette. Gelukkig hebben de makers daaraan gedacht en kan dat. Voor de beeldvorming zal ik uitleggen hoe PASCAL een file "ziet".

Een file is in PASCAL een lange keten gegevens. De gegevens zitten (en zullen ten eeuwige dagen blijven zitten) in de volgorde waarin ze zijn weggeschreven. Bij het werken met een file schuift er een "window" over de file, waardoor altijd maar ��n gegeven per keer "zichtbaar" is. Het genoemde window heeft trouwens de onprettige eigenschap dat het alleen maar vooruit kan schuiven. Ophalen en wegschrijven van waardes gebeurt via het window. Het window is te bereiken met "File^" (waar File de naam van de filevariabele is). Ik zal nu wat opdrachten bespreken die mogelijk zijn met files, waarna nog een voorbeeld programma volgt. Opdrachten zijn:

RESET(File) Opent een file zodat er in gelezen kan worden (zet het window aan het begin van de file). REWRITE(File) Opent de file en maakt hem geschikt om in te schrijven (file is nu leeg, ook al was hij dat niet!!). GET(File) Schuift het window een plaats op (de nieuwe waarde kan met "Waarde:=File^" opgevraagd worden). PUT(File) Zet de waarde van het window in de file en schuift het window een plaats op (de window waarde kan veranderd worden met "File^:=Waarde"). READ(File,Waarde) Leest uit de file en plaats de gelezen waarde in "Waarde" (geen geklooi meer met het window, hier gebeurt dat allemaal automatisch). READLN(File,Waarde) Idem als READ, maar leest tevens tot het einde van de regel (wordt gebruikt bij tekstfiles). WRITE(File,Waarde) Schrijft de waarde van "Waarde" in de file en schuift het window door (ook hier geen geklooi meer met het window). WRITELN(File,Waarde) Idem als WRITE, maar plaatst tevens een EOLN (End OF LiNe) teken in de file (wederom bij tekstfiles). EOF(File) Geeft de waarde TRUE als het einde van de file bereikt is (EOF = End Of File). EOLN(File) Geeft de waarde TRUE als het einde van de regel bereikt is (EOLN = End Of LiNe).

Offici�el zijn genoemde opdrachten alle opdrachten voor files, maar de meeste compilers hebben nog twee extra opdrachten, en dat zijn:

ASSIGN(File,"FileNaam") Dit koppelt de "File" aan de "FileNaam". M.a.w. Als ik iets in de file schrijf, dan komt dit op de schijf in de file "FileNaam" te staan. Volgens de regels van PASCAL is dit niet nodig, omdat de fysieke file (de file op schijf) dezelfde naam krijgt als de variabele "File" heeft. Veel compilers hebben echter een ASSIGN opdracht nodig, anders gebeurt er niets (vaak niet eens een foutmelding en al helemaal geen file). CLOSE(File) Dit moge wel duidelijk zijn. Hier wordt de file gesloten. Deze opdracht zorgt ervoor dat de file ook voor DOS gesloten wordt, zodat er niet een ge-opende file achter- blijft als het programma stopt. Deze opdracht moet dus alleen op het einde van het programma staan. Ook deze opdracht is geen standaard, maar moet ook bij de meeste compilers worden toegevoegd voor een goede werking.

Zo, en dan nu een voorbeeldje:

PROGRAM FileVoorbeeld;

TYPE
  FileType = FILE OF integer;      (* FILE OF AnyType is
                                      mogelijk *)

VAR
  FileVar : FileType;
  Teller  : integer;

BEGIN          (* FileVoorbeeld *)
  ASSIGN(FileVar,"testfile.dat");  (* voor de zekerheid *)
  REWRITE(FileVar);                (* ik wil er iets
                                      inschrijven *)
  FOR Teller:=1 TO 5000 DO
    Write(FileVar,Teller);         (* dat doe ik hier *)
  FOR Teller:=5000 DOWNTO 1 DO
    Write(FileVar,Teller);         (* en hier ook *)
  RESET(FileVar);                  (* nu wil ik lezen uit
                                      de file *)
  WHILE NOT EOF(FileVar) DO
  BEGIN
    Read(FileVar,Teller);          (* hier noem ik
                                      expliciet de file *)
    Write(Teller);                 (* hier niet, dus gaat
                                      de output naar het
                                      standaard uitvoerap-
                                      paraat en dat is het
                                      beeldscherm *)
  END;
  CLOSE(FileVar);                  (* voor de zekerheid *)
END.           (* FileVoorbeeld *)

Dit voorbeeld zou een heleboel duidelijk moeten maken. Alles wat je nu nog moet doen is verder experimenteren. Probeer eens een tekstfile te lezen en/of schrijven, dan kun je zien wat EOLN precies doet. De opdrachten GET en PUT worden weinig gebruikt, maar je kunt eens kijken hoe ze precies werken (goed voor de beeldvorming).

Zo, dat was het dan alweer voor deze keer. Groetjes van,

           Jeroen 'ik ben nog lang niet aan mijn EOF' Smael

                                                  C YA @!!