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) | assembler | machinetaal (decimaal) | machinetaal (hexadecimaal)
|
Copieer hok 90 in A | LD A,(90) | 03 90 | 03 5A |
Tel hok 91 bij A op | ADD A,(91) | 06 91 | 06 5B |
Copieer A in hok 92 | LD (92),A | 02 92 | 02 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):
and | downto | if | or | then |
array | else | in | packed | to |
begin | end | label | procedure | type |
case | file | mod | program | until |
const | for | nil | record | var |
div | function | not | repeat | while |
do | goto | 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:
type | soort | aantal bytes | maximum/minimum |
integer | geheel getal | 4 | ±231 |
shortint | geheel getal | 2 | ±215 |
byte | geheel getal | 1 | 255 / 0 |
word | geheel getal | 4 | 232 / 0 |
real (of double) | kommagetal | 8 | circa ±10308 |
single | kommagetal | 4 | circa ±10154 |
string | woord | 255 | |
string[20] | woord | 20 | |
char | 1 teken | 1 | |
boolean | waar/niet waar | 1 | |
array [0..max] of integer | rij getallen | | |
array [0..max] of string | rij 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:
- 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.
- 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;
- 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:
|