Informaticasite van het Lauwers College te Buitenpost                 © R.J. van der Beek
 

Hoofdstuk 6 Programmeren in Pascal

6.4. Theorie, structuurdiagrammen

  6.4.1. Een programma

Het hart van de computer is de processor, ook wel CPU of CVE genoemd.
In hoofdstuk 4 hebben we gezien dat de processor instructies achter elkaar uitvoert.
Die instructies zijn opgeslagen in het RAM-geheugen van de computer.
Zo'n reeks computerinstructies noem je een computerprogramma.
Een algoritme is een getailleerde beschrijving van hoe je een probleem moet oplossen, stap voor stap.
En als je de stappen zo beschrijft dat een computer ze kan uitvoeren dan is het een programma.

Een processor kent maar een beperkt aantal instructies, dat is de zogenaamde instructieset.
Elke instructie wordt met een nummer aangegeven, dat is de zogenaamde opcode.
Verder wordt die instructie meestal toegepast op een getal, dat is de zogenaamde operand.
Die twee (of meer) getallen vormen samen de opdracht.
Zo kunnen de opdrachten m.b.v. getallen worden aangegeven, en als je zó een programma schrijft dan noem je dat machinetaal.
De eerste programma's voor de eerste computers werden in machinetaal geschreven, daarom wordt dat ook wel de eerste generatie programmeertaal genoemd.
De eerste computer, de MARK1 uit 1943, werd bijvoorbeeld zo geprogrammeerd.



Maar het is ontzettend moeilijk om een ingewikkeld programma in machinetaal, dus alleen met getallen, te schrijven. Ook omdat een ingewikkeld programma uit miljoenen machinetaal-instructies bestaat.
Verder werkt zo'n programma misschien wel op de ene computer, maar niet op een andere. Want elke processor-fabrikant heeft zijn eigen instructieset voor zijn processoren, en ook het besturingssysteem speelt daarbij een rol.

Omdat het programmeren in machinetaal, met alleen getallen, ontzettend moeilijk is, werd al snel geprobeerd dat wat te vereenvoudigen.
Daarom werd voor elke instructie een instructie-woord bedacht, zodat je woorden kon gebruiken in plaats van getallen.
Dat was dus de tweede generatie programmeertaal, en dat werd assembleertaal genoemd (in het engels: assembler).
En om er voor te zorgen dat je niet zoveel hoefde te typen werd elk instructie-woord afgekort, en die afkortingen worden mnemonics genoemd.
Als een programma in assembleertaal was geschreven kon het niet direkt door de processor worden uitgevoerd, elk instructie-woord moest eerst worden vervangen door de bijbehorende machinetaal-code, dus door een getal.
Maar er was een programma gemaakt, dat voor die "vertaling" zorgde, en dat werd een compiler genoemd.

Ook het programmeren in assembler is ontzettend moeilijk, want er zijn net zoveel assembler-instructies voor een programma nodig als machinetaal-instructies. En dat zijn er miljoenen voor een ingewikkeld programma.

Daarom zijn er zogenaamde "hogere programmeertalen" uitgevonden.
Dat zijn programmeertalen, waarbij je opdrachten in "gewone taal" kunt geven (vrijwel altijd in het engels).
Je kunt dan niet elk woord gebruiken, dat je wilt. Er zijn een aantal opdrachtwoorden die je mag gebruiken, en welke dat zijn hangt van de programmeertaal af.
De computer moet het dan nog wel omzetten in machinetaal, en zo'n vertaalprogramma heet ook voor deze programmeertalen een compiler.
Het verschil met een compiler voor assembler is, dat nu niet elke opdracht in één machinetaalinstructie wordt omgezet. Maar voor elke opdracht heb je meerdere machinetaalinstructies nodig, soms heb je voor de vertaling van één opdracht wel 100 machinetaalinstructies nodig.
Maar de compiler regelt dat allemaal.
Voorbeelden van hogere programmeertalen zijn Pascal, Basic, Fortran, C.
Dat zijn derde generatie programmeertalen.

Je hebt ook nog vierde generatie programmeertalen, dat zijn bijvoorbeeld Java, Delphi, Visual Basic, Visual C++.
Die talen zijn object-geöriënteerd, en wat daarmee bedoeld wordt lees je wel als we met Visual Basic aan de slag gaan.

  6.4.2. Pascal compileren

Pascal is een derde generatie programmeertaal, het is in 1970 ontstaan.
In 1995 werd de programmeertaal zo veranderd, dat het een vierde generatie programmeertaal werd. Het werd toen Delphi genoemd, dat is dus de opvolger van Pascal.
Voor het schrijven van een computerprogramma zijn verschillende onderdelen nodig.
Ten eerste heb je een onderdeel nodig waarmee je de programmacode in kunt typen, dat noem je een editor.
Verder is er een compiler nodig, die zorgt er voor dat de broncode in machinetaal wordt vertaald.
Verder is het handig om een debugger te hebben: een onderdeel dat meehelpt met het opsporen van fouten.
Wanneer een text-editor, compiler en debugger in één programma zijn samengevoegd dan noem je dat een IDE, dat is de afkorting van Integrated Development Environment.
De eerste echt populaire IDE was Turbo Pascal. Ook Delphi, de opvolger ervan, wordt veel gebruikt. Ook Irie Pascal, dat wij gebruiken, is een IDE.

Een machinetaal-programma heeft vrijwel altijd de extensie EXE, soms is de extensie COM
Als je een Pascal-programma hebt ingetypt (dat noem je dan de broncode) en je slaat het op onder de naam TEST, dan krijgt het automatisch de extensie PAS. Dus de broncode wordt opgeslagen onder de naam TEST.PAS.
Als je het dan compileert wordt het machinetaal-programma opgeslagen onder de naam TEST.EXE.

Als je bijvoorbeeld de volgende code in Pascal hebt:
som := b + c;
dan wordt het door de compiler in drie machinetaal-instructies omgezet:

MIEP-instructie
(zie hoofdstuk 4.2)
assemblermachinetaal
(decimaal)
machinetaal
(hexadecimaal)
Copieer hok 90 in ALD A,(90)03 9003 5A
Tel hok 91 bij A opADD A,(91)06 9106 5B
Copieer A in hok 92LD (92),A02 9202 5C

  6.4.3. Syntax en semantiek

Als je een pascal-programma maakt, dan moet je je aan bepaalde regels houden.
Je mag niet elk woord gebruiken, je mag alleen bepaalde codewoorden gebruiken.
Elk codewoord heeft een nauwkeurig bepaalde betekenis, het is niet zoals bij "gewone" taal dat een woord soms verschillende betekenissen heeft.
In standaard-pascal zijn er maar 35 codewoorden, die je mag gebruiken.
Dat zijn de volgende (de verschillende typen variabelen staan er niet bij, en ook niet de functies zoals sin, cos, sqrt, enz):

anddowntoiforthen
arrayelseinpackedto
beginend label procedure type
casefile mod program until
constfor nil record var
divfunction not repeat while
dogoto of set with

Een programmeertaal heeft altijd specifieke regels, die met de grammaticaregels in een normale taal te vergelijken zijn. Dit wordt de syntax van de taal genoemd. Dat zijn niet alleen regels voor het gebruik van de codewoorden, maar ook van de leestekens.
In Pascal moet bijvoorbeeld elke opdracht worden gevolgd door een punt-komma.
De syntaxregels worden vaak beschreven met behulp van syntax-diagrammen of in BNF-notatie, zie hoofdstuk 3 en hier onder.
Als je een syntaxfout maakt herkent het programma dat onmiddelijk, en die fout wordt tijdens het compileren gemeld.

Als je in IriePascal op Help klikt kun je informatie over de syntax krijgen.
Daarbij wordt bijvoorbeeld uitgelegd hoe je variabelen moet declareren, dat gaat m.b.v. BNF op de volgende manier:

variable-declaration-group = 'var' variable-declaration { ';' variable-declaration }
identifier = letter { letter | digit }
identifier-list = identifier { ',' identifier }
type-denoter = type-identifier | new-type
type-identifier = identifier
variable-declaration = identifier-list ':' type-denoter
binary-digit = '0' | '1'
binary-digit-sequence = binary-digit { binary-digit }
digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'
letter = 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' |
              'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' |
              'u' | 'v' | 'w' | 'x' | 'y' | 'z' | '_'

De betekenis van de codewoorden noem je de semantiek.
Je kunt ook semantische fouten of logische fouten maken.
Vaak werkt het programma dan wel, maar niet zoals het bedoeld is.
Als je tien keer de naam R.J. van der Beek wilt laten afdrukken, dan kan dat m.b.v. de opdracht:
for i:=1 to 10 do
writeln("R.J. van der Beek");


Als je in plaats daarvan de opdracht als volgt invoert:
for i:=1 to 10 do ;
writeln("R.J. van der Beek");
dan volgt er geen foutmelding, maar de naam wordt maar één keer afgedrukt.
Dat komt door de punt-komma achter for i:=1 to 10 do, die hoort daar niet.
De for-opdracht wordt door die punt-komma afgesloten. De computer doet tien keer wat er achter de for-opdracht staat, tot aan de punt-komma. Maar de punt-komma staat vlak achter de for-opdracht, dus de computer doet tien keer niets!

  6.4.4. Variabelen en declaraties

Je kunt in pascal-programma's ook variabelen gebruiken.
Dat zijn letters of woorden, die getallen of woorden of andere dingen voorstellen.
Als je een variabele gebruikt dan moet je dat wel aan het programma duidelijk maken. En je moet er dan bij vertellen van welk type de variabele is, een geheel getal, een kommagetal of een woord of misschien nog iets anders.
Dat noem je het declareren van de variabele.

Dat doe je altijd in de kop van het programma, meestal op de tweede regel.
Die regel begint met het woordje var
Voorbeeld:
var a, b, som, i : integer;
       q, wortel: real;
       t, naam: string;

Er zijn meer typen dan integer, real en string.
Hier volgt een lijstje van de meest gebruikte:

typesoortaantal bytesmaximum/minimum
integergeheel getal4±231
shortintgeheel getal2±215
bytegeheel getal1255 / 0
wordgeheel getal4232 / 0
real (of double)kommagetal8circa ±10308
singlekommagetal4circa ±10154
stringwoord255 
string[20]woord20 
char1 teken1 
booleanwaar/niet waar1    
array [0..max] of integerrij getallen    
array [0..max] of stringrij woorden    

  6.4.5. Keuzestructuur

Binnen algoritmen is het vaak nodig te kiezen.
In het nederlands kun je zeggen:
als .......... dan ............. en anders ............

In Pascal is de code daarvoor als volgt:

if (voorwaarde) then
begin
..............
end
else
begin
..............
end;

De opdrachten, die uitgevoerd moeten worden als de voorwaarde waar is, staan tussen begin en end.
De opdrachten daartussen worden samen een samengestelde opdracht genoemd (engels: compound statement).
En ook de opdrachten, die uitgevoerd moeten worden als de voorwaarde niet waar is (die staan achter else), staan tussen begin en end.

Het else-gedeelte mag ook worden weggelaten, de code is dan als volgt:

if (voorwaarde) then
begin
..............
end;

Dat betekent het volgende: Als aan de voorwaarde voldaan is, voer dan de (samengestelde) opdracht na then uit, en ga anders door met de volgende opdracht.

Je kunt voorwaarden ook combineren m.b.v. de woorden AND en OR en NOT.
... AND ... is waar aan de eerste voorwaarde en tegelijk ook aan de tweede voorwaarde wordt voldaan.
... OR ... is waar als aan minstens één van de twee voorwaarden wordt voldaan.
NOT ... is waar als niet aan de voorwaarde wordt voldaan.

Als er meer keuzes zijn dan kun je beter gebruik maken van CASE .. OF
Als een varabele getal verschillende waarden kan hebben, en afhankelijk van die waarde moeten verschillende dingen gebeuren, dan kun je dat als volgt programmeren:

CASE getal OF
      1 .. 3         : Writeln ('de waarde is kleiner dan 4');
      5, 6           : Write ('de waarde is 5 of 6');
      7 .. 10       : Write ('de waarde zit tussen 7 en 10');
      ELSE           Write ('de waarde is groter dan 10')
end;

  6.4.6. Herhalingen

Er zijn drie manieren om opdrachten in een programma te herhalen:
  1. Bepaald aantal herhalingen.
    Dit pas je toe als je van tevoren precies weet hoe vaak het herhaald moet worden.
    Als je iets tien keer wilt herhalen, dan kan dat met behulp van de opdracht:
    for i=1 to 10 do
    begin
    ..............
    end;

    Daarbij is i een variabele.
    En i neemt de waarden 1, 2, 3 t/m 10 aan. De variabele i wordt daarom ook wel de teller genoemd, hij houdt bij tot hoever de herhaling gevorderd is.
    Wat er precies herhaald wordt moet tussen begin en end staan.

    Eigenlijk kun je net zo goed de opdracht als volgt schrijven:
    for i=0 to 9 do

    Dan neemt i de waarden 0, 1, 2 t/m 9 aan, maar dan wordt het ook 10 keer herhaald.

    Je mag ook een andere variabelenaam gebruiken, dus bijvoorbeeld:
    for k=1 to 10 do

    Je kunt ook naar beneden laten tellen, bijvoorbeeld:
    for k=10 to 1 downto

    Dan neemt k de waarden 10, 9, 8 t/m 1 aan, maar dan wordt het ook 10 keer herhaald.
  2. Onbepaald aantal herhalingen met test vooraf
    In het nederlands kun je zeggen:
    herhaal zolang (voorwaarde) .............

    In Pascal is de code daarvoor als volgt:

    while (voorwaarde) do
    begin
    ..............
    end;

  3. Onbepaald aantal herhalingen met test achteraf
    In het nederlands kun je zeggen:
    herhaal ............. totdat (voorwaarde)

    In Pascal is de code daarvoor als volgt:

    repeat
    ..............
    until (voorwaarde);

  6.4.7. Commentaar

Bij het schrijven van een pascal-programma worden meestal commentaarregels toegevoegd.
Die dienen alleen als toelichting bij het programma, als het programma wordt uitgevoerd dan worden die regels overgeslagen.
Ze dienen ook voor de programmeur zelf. Als die een programma gemaakt heeft, en een jaar later wil hij iets aan het programma wijzigen, dan weet hij soms zelf niet meer hoe het programma in elkaar zit.
De commentaarregels helpen hem dan op weg.
Als tekst tussen accolades staat dan wordt het in Pascal als commentaar opgevat.

Opgaven.
Maak nu opgave 16 van hoofdstuk 6 (Pascal)

  6.4.8. Stapsgewijze verfijning; structuurdiagrammen; procedures

Bij het uitwerken van een ingewikkeld probleem kun je het beste de stappen, die moeten gebeuren, eerst globaal beschrijven. Dus eerst schrijf je in grote lijnen de volgorde, waarin de dingen moeten gebeuren, op in gewone nederlandse woorden.
Als je het dan op de volgende manier noteert, dan noemen we dat een structuurdiagram.
De "gewone" opdrachten noteer je in een rechthoek:



Daarna ga je de onderdelen verfijnen. We verfijnen het probleem door het steeds op te splitsen in deelproblemen. Die deelproblemen verdelen we ook weer in stappen, en we gaan daarmee door tot we de kleinste deelproblemen zonder moeite kunnen programmeren.
We noemen dit stapsgewijze verfijning, en je bent dan bezig met top-down-programmeren.

Daarbij is het vaak zo, dat de opdrachten afhangen van een bepaalde voorwaarde. Dan noteer je het als volgt:



Verder komen er vaak herhalingen in voor, die noteer je op de volgende manier:



Voorbeeld:
We maken een programma, waarmee een aantal namen van leerlingen en hun cijfer voor een repetitie, kan worden ingevoerd.
Daarna kan een naam worden ingevoerd, en dan wordt in de lijst gezocht of die naam er in voorkomt. En als die naam er in voorkomt wordt het bijbehorende cijfer getoond. Als de naam niet voorkomt dan wordt dat gemeld.

In grote lijnen moet dus het volgende gebeuren:
(in een structuurdiagram zetten we de verschillende stappen, die achtereenvolgens moeten worden genomen, in een rechthoek)



Nu gaan we het eerste deelprobleem (namen met cijfers invoeren) verfijnen.
We weten niet hoeveel namen er zullen worden ingevoerd, we gaan ervan uit dat er telkens een naam en daarna een cijfer wordt ingevoerd. En als er op een gegeven moment, in plaats van het invoeren van een naam, direkt op enter wordt gedrukt (de naam is dan dus de lege string) nemen we aan dat er gestopt wordt met het invoeren van namen.
Dan moet dus het volgende gebeuren, in een structuurdiagram genoteerd:



Het tweede deelprobleem (zoeknaam invoeren) hoeven we niet te verfijnen, dat bestaat maar uit één opdracht.

Het derde deelprobleem (lijst doorzoeken) moeten we wel verfijnen.
Steeds moet de volgende naam van de lijst worden vergeleken met de zoeknaam.
Als die twee gelijk zijn is de naam gevonden.
Als alle namen geweest zijn, en de naam is niet gevonden, dan zit hij er niet bij.
Dan moet dus het volgende gebeuren, in een structuurdiagram genoteerd:



Het vierde deelprobleem (resultaat afdrukken) moeten we ook nog verfijnen.
Als de naam gevonden is, dan moet de naam met het cijfer worden afgedrukt, en anders moet worden afgedrukt dat de naam niet in de lijst voorkomt.
In een structuurdiagram ziet dat er als volgt uit:



Nu gaan we het struktuurdiagram omzetten in een programma.
Van elke deelprobleem, dat we hebben verfijnd in een nieuw struktuurdiagram, maken we een procedure.
(Een procedure is een programma in een programma, zie hoofdstuk 3)
We voegen de header toe, en de declaraties. En dan krijgen we het volgende programma: (in het commentaar tussen de accolades worden nog een aantal dingen verduidelijkt)

program lijst;

var nummer, aantal: integer;
   lijstnamen: array [1..100] of string;
   lijstcijfers: array [1..100] of integer;
   gevonden: boolean;
   zoeknaam: string;

procedure invoeren;
var naam: string;
   i: integer;
begin
   {de teller krijgt eerst de waarde 1}
   i:=1;
   {de variabele naam moet een (willekeurige) waarde krijgen
   want als naam gelijk is aan de lege string zal de  
   while-lus direkt stoppen}
   naam:="test";
   while naam<>"" do
   begin
      write("Geef naam nummer ",i:2,"        ");
      readln(naam);
      lijstnamen[i]:=naam;
      {als er geen naam is ingevoerd hoeft er ook 
       geen cijfer te worden gevraagd}
      if naam<>"" then
      begin
         write("Geef cijfer nummer ",i:2,"        ");
         readln(lijstcijfers[i]);
      end;
      {voor het vervolg de letter met 1 ophogen}
      i:=i+1;
   end;
   {als er gestopt wordt is het aantal namen gelijk aan i-1}
   aantal:=i-1;
end;

procedure lijst_doorzoeken;
var  i: integer;
begin
   i:=1;
   {als er wordt begonnen is de naam nog niet gevonden}
   gevonden:=false;
   while ((i<=aantal) and (gevonden=false)) do
   begin
      if (zoeknaam= lijstnamen[i]) then
      begin
         {het nummer van de gevonden naam moet worden onthouden}
         nummer:=i;
         gevonden:=true;
      end
      else
      begin
         {voor de volgende moet de teller worden opgehoogd}
         i:=i+1;
      end;
   end;
end;

procedure afdrukken;
begin
   if gevonden=true then
   begin
      writeln("De naam was: ",lijstnamen[nummer]);
      writeln("Het cijfer was: ",lijstcijfers[nummer]:2);
   end
   else
   begin
      writeln("De naam ",zoeknaam,"komt niet in de lijst voor");
   end;
end;

begin
   clrscr;
   invoeren;
   {de volgende opdrachten zorgen voor drie lege regels}
   writeln;writeln;writeln;
   write("Geef de naam die je op wilt zoeken ");
   readln(zoeknaam);
   lijst_doorzoeken;
   afdrukken;
end.

en als we het programma dan uitvoeren kan het volgende verschijnen: