0100 977f 0151 ... TURBO2,1.DOK
.PL72
.MT1
.MB3
.FM1
.FO                                                              
.HE                                       TURBO-Pascal  Seite #
.PN38
.PO8


10. Feldtypen (ARRAY)

Ein Feld (ARRAY) ist ein strukturierter Typ, der aus einer festen 
Anzahl  von  Komponenten besteht.  Die Komponenten sind alle  vom 
gleichen Typ.  Diesen bezeichnet man als Komponententyp oder  Ba-
sistyp.  Jede dieser Komponenten kann man exakt durch Indizierung 
des  Feldes erreichen.  Indizes sind INTEGER-Ausdruecke,  die  in 
eckigen Klammern geschrieben,  an den Bezeichner des Feldes ange-
haengt werden. Ihr Typ heisst Indextyp.


10.1 Feld-Definition

Die  Definition  eines Feldes besteht aus dem  reservierten  Wort 
array,  dem  ein  in eckigen Klammern  eingeschlossener  Indextyp 
folgt.  Nach  diesem steht das reservierte Wort of und ein Kompo-
nententyp.

Beipiele:
     type
          Day      = (Mon,Die,Mit,Don,Fre,Sam,Son);
     Var
          WorkHour : array[1..8]  of Integer;
          Week     : array[1..52] of Day;

     type
          Players  = (Player1,Player2,Player3,Player4);
          Hand     = (One,Two,Pair,TwoPair,Three,Straight,Flush,
                    FullHouse,Four,StraightFlush,RSF);
          LegalBid = 1..200;
          Bid      = array[Players];
     Var  
          Player   : array[Players] of Hand;
          Pot      : Bid;

Die Zuweisung zu einer Feld-Komponente erfolgt durch Angabe eines 
in  eckigen Klammern eingeschlossenen Indexes hinter dem  Variab-
lenbezeichner.

Beispiele:
     Player[Player3] := FullHouse;
     Pot[Player3]    := 100;
     Player[Player4] := Flush;
     Pot[Player4]    := 50;

Es  ist  erlaubt,  einer  Variablen  x  den  Wert  einer  anderen 
Variablen Y zuzuweisen, wenn beide den gleichen Typ haben. Analog 
ist es moeglich ganze Felder zu kopieren:
               Index1 := Index2.
Die Compiler-Direktive R steuert auch die Erzeugung eines  Codes, 
der  zur Laufzeit des Programmes die Index-Ausdruecke prueft,  ob 
sie innerhalb des erlaubten Bereiches liegen.  Standard ist dabei 
{$R-},  d.h.  es muss im Programm {$R+} gesetzt werden,  wenn die 
Index-Ausdruecke geprueft werden sollen.
.pa

10.2 Mehrdimensionale Felder

Der  Komponententyp  eines Feldes kann  ein jeder Datentyp  sein, 
d.h.  der  Komponententyp kann auch ein Feld  sein.  Eine  solche 
Konstruktion heisst mehrdimensionales Feld.

Beispiele:
     type
          card = (Two,Three,Four,Five,Six,Seven,Eight,Nine,Ten,
                  Knight,Queen,King,Ace);
          Suit = (Hearts,Spade,Clubs,Diamonds);
          AllCards = array[Suit] of array[1..13] of Card;
     var   
          Deck : AllCards;

Ein  mehrdimensionales  Feld  kann  auch  durch  mehrdimensionale 
Indices definiert werden:
     
     type
          AlCards = array[Sui,1..13] of Card;

Aus  diesem  Grunde kann man auch folgende kuerzere  Schreibweise 
fuer die Auswahl eines Feldes anwenden:

     Deck[Hearts,10]   equivalent mit    Deck[Hearts][10]

Es ist natuerlich auch moeglich mehrdimensionale Felder in Termen 
vorher definierter Feldtypen zu definieren.

Beispiele:
     type
          Pupils = string[10];
          Class  = array[1..30]  of Pupils;
          Scool  = array[1..100] of Class;
     var
          J,P,Vacant    : Integer;
          ClassA,ClassB : Class;
          NewTownScool  : Scool;

Mit diesen Definitionen gelten folgende Zuweisungen:

          ClassA              := 'Peter';
          NewTownScool[5][21] := 'Peter Brown';
          NewTownScool[8,J]   := NewTownScool[7,J];
          ClassA[Vacant]      := ClassB[P];

10.3 Zeichenfelder (Caracter Arrays)

Zeichenfelder  sind  Felder mit einem Index und  Komponenten  vom 
Standard-Skalar-Typ Char.  Zeichenfelder koennen auch als  String 
mit fester Laenge aufgefasst werden. 
In  TURBO-Pascal duerfen Zeichenfelder auch in STRING-Ausdruecken 
auftreten.  In diesen Faellen werden jeweils in einen String  von 
der Laenge des Zeichenfeldes umgewandelt.  Damit koennen Zeichen-
felder  in  gleicher Weise wie String miteinander verglichen  und 
manipuliert werden.  Auch Stringkonstanten duerfen Zeichenfeldern 
zugewiesen  werden,  wenn sie die gleiche Laenge  haben.  STRING-
Variable und -Werte, die aus STRING-Ausdruecken berechnet werden, 
koennen Zeichenfeldern nicht zugewiesen werden.


10.4 Standard-Felder

TURBO-Pascal stellt zwei Standard-Felder vom Typ Byte zur Verfue-
gung:  MEM und PORT.  Mit ihnen erhaelt man den Zugriff zum Spei-
cher und zu den Datenports.  Ihre Besprechung erfolgt in Anhang A 
und B.

11. Datensatztypen

Ein Datensatz ist eine Struktur,  die aus einer festen Anzahl von 
Komponenten, den Datenfeldern, besteht. Die einzelnen Datenfelder 
koennen  von  unterschiedlichem Typ sein und jedes Datenfeld  hat 
einen  eigenen  Datenfeldbezeichner,  der dem Zugriff  zu  diesem 
Datenfeld dient.


11.1 Datensatz-Definition

Die  Definition eines Datensatztyps besteht aus dem  reservierten 
Wort  record,  dem eine Datenfeldliste folgt.  Diese  Liste  wird 
durch  das  reservierte Wort end abgeschlossen.  Sie besteht  aus 
Datensatzabschnitten,  die  voneinander durch Semikolon  getrennt 
sind.  Jeder  Datensatzabschnitt besteht aus einem oder  mehreren 
Datenfeldbezeichnern,  die durch Komma voneinander getrennt sind. 
Der  letzte wird durch einen  Doppelpunkt  abgeschlossen.  Diesem 
folgt  ein Typbezeichner.  Jeder Datensatzabschnitt  spezifiziert 
demnach den Typ und die Bezeichner fuer einen oder mehrere Daten-
felder. 

Beispiele: 
     type
          Date = record
                    Day   : 1..31;
                    Month : (Jan,Feb,Mrz,Apr,Mai,Jun,Jul,Aug,
                             Sep,Okt,Nov,Dez);
                    Year  : 1900..1999;
                 end;
     var 
          Birth   : Date;
          WorkDay : array[1..5] of date;

In diesem Beispiel sind Day,  Month und Year Datenfeldbezeichner. 
Ein  Datenfeldbezeichner  muss  nur eindeutig  in  dem  Datensatz 
selbst  sein,  indem  er definiert wurde.  Den Zugriff  zu  einem 
Datenfeld  erhaelt  man durch den Datenfeldbezeichner,  dem  man, 
getrennt durch einen Punkt,  den Variablenbezeichner fuer  diesen 
Datensatz voranstellt.

Beispiele:
     Birth.Month        := Jun;
     Birth.Year         := 1950;
     WorkDay[Current]   := WorkDay[Current-1];

Man  beachte,  dass  wie bei den Feltypen auch ganze  Datensaetze 
einander  zugewiesen werden koennen,  wenn sie vom  gleichen  Typ 
sind.
Da  der  Typ der Datensatzkomponenten nicht  eingeschraenkt  ist, 
kann er selbstverstaendlich auch ein Datensatztyp sein. Damit ist 
es moeglich, einen Datensatz von Datensaetzen zu bilden:

     type
          Name = record
                    FamilyName     : string[32];
                    ChristianName  : array[1..3] of string[16];
                 end;
          Rate = record
                    NormalRate,OverTime,NightTime,Weekend:Integer;
                 end;
          Date = record
                    Day   : 1..31;
                    Month :  (Jan,Feb,Mrz,Apr,Mai,Jun,Jul,Aug,
                             Sep,Okt,Nov,Dez);
                    Year  : 1900..1999;
                 end;
          Person = record
                    Id   : Name;
                    Time : Date;
                   end;
          Wages  = record
                    Individual : Person;
                    Cost       : Rate;
                   end;
     var
          Salary,Fee  : Wages;

Mit diesen Definitionen sind folgende Zuweisungen erlaubt:
     
     Salary                          :=  Fee;
     Salary.Cost.OverTime            :=  950;
     Salary.Individual.Time          :=  Fee.Individual.Time;
     Salary.Individual.Id.FamilyName := 'Smith';



11.2 WITH-Anweisung

Die Verwendung von Datensaetzen in der obigen Weise ergibt  meis-
tens  ziemlich weitschweifige Anweisungen.  Die Schreibweise  der 
Ergibtanweisungen wuerde einfacher sein, wenn die Datensatzfelder 
einfache  Variablen waeren.  Genau dies ermoeglicht die  WITH-An-
weisung:  Sie "eroeffnet" einen Datensatz so, dass die Datenfeld-
bezeichner  wie  einfache  Variablenbezeichner  verwendet  werden 
koennen.
Eine  WITH-Anweisung besteht aus dem reservierten Wort with,  dem 
eine Liste von Datensatzvariablen folgt,  die durch Komma vonein-
ander getrennt sind.  Anschliessend folgt das reservierte Wort do 
und eine Anweisung.
In  einer  WITH-Anweisung  wird ein Datenfeld  nur  durch  seinen 
Datenfeldbezeichner gekennzeichnet, d.h. ohne Datensatzvariablen-
bezeichner.

     with Date do
          begin
               Day   := 23;
               Month := Feb;
               Year  := 1982;
          end;

Datensaetze koennen in einer WITH-Anweisung geschachtelt  werden, 
d.h.  Datensaetze  von  Datensaetzen koennen wie folgt  eroeffnet 
werden:

     with Salary do with Individual do with Id do ...

oder kuerzer:

     with Salary,Individual,Id do
          begin
               FamilyName    := 'Smith';
               ChristianName := 'Jones';
          end;

Die maximale Tiefe dieser Schachtelung der WITH-Folgen,  d.h. die 
maximale  Anzahl  der Datensaetze,  die man in  einem  Block  zur 
gleichen Zeit eroeffnen kann, haengt von der Implementierung ab. 
Eine ausfuehrliche Besprechung erfolgt im Anhang A und B.
.pa


11.3 Definition von Datensatz-Varianten.

Die  Syntax eines Datensatztypes erlaubt auch die Definition  von 
Datensatzteil-Varianten,  d.h. von alternativen Datensatzstruktu-
ren,  die aus Datensatzteilen bestehen, deren Datenfeldanzahl und 
Datenfeldtypen  unterschiedlich  sind und deren Struktur  jeweils 
vom Wert eines Kennzeichnungsfeldes abhaengen.
Ein Varianten-Datensatzteil besteht aus einem  Kennzeichnungsfeld 
eines vorher definierten Typs,  dem Marken folgen,  die den moeg-
lichen  Werten des Kennzeichnungsfeldes entsprechen.  Jede  Marke 
fuehrt  eine  Datenfeldliste  an,  die den Typ der  dieser  Marke 
zugeordneten Datensatzteil-Variante definiert.
Als Beispiel gelte obige Typdefinition fuer Name und Date, sowie

     type      Origin = (Citizen,Alien);

Dann  ist es mit der folgenden Datensatztyp-Definition  moeglich, 
fuer  das Datenfeld CitizenChip zwei verschiedene  Strukturen  zu 
definieren,  die nur von seinem Wert:  Citizen oder Alien abhaen-
gen:
     type
       Name = record
               FamilyName       : string[32];
               ChristianNames   : array[1..3] of strings[16];
               HourRates        : array[1..4] of Integer;
              end;
       Person  = record
                    PersonName       : Name;
                    BirthDate        : Date;
                    case CitizenShip : Origin of
                         Citizen: (BirthPlace :Name);
                         Alien  : (CountryOfOrigin : Name;
                                   DateOfEntry     : Date;
                                   PermittedUntil  : Date;
                                   PortOfEntry     : Name);
                 end;

Bei  dieser Definition von Datensatzvarianten ist das  Kennzeich-
nungsfeld  ein  explizites Datenfeld,  das man wie  jedes  andere 
Datenfeld  auswaehlen und mit Werten versehen kann.  Es sind des-
halb auch die folgenden Anweisungen exakt gueltig:

     var  Passenger : Person;

     Passenger.CitizenShip  := Citizen;
     with Passenger,Person,Name do
          if CitizenShip = Alien then writeln(FamilyName); 

Der  feste Teil eines Datensatzes,  d.h.  der Teil,  der  gleiche 
Datenfelder enthaelt,  muss stets vor dem variablen Teil  liegen. 
Im  obigen  Beispiel  sind PersonName und  BirthDate  die  festen 
Felder.  Ein  Datensatz darf nur einen variablen Teil  haben.  Im 
variablen Teil muessen die Klammern geschrieben werden, auch wenn 
sie nichts enthalten. 
Die Nutzung eines Kennzeichnungsfeldes liegt in der Verantwortung 
des Programmierers und nicht bei TURBO-Pascal.  Aus diesem Grunde 
kann  man sich auf das Feld DateOfEntry im Typ Person auch bezie-
hen, wenn das Kennzeichnungsfeld CitizenChip nicht den Wert Alien 
hat.  Tatsaechlich kann man das Kennzeichnungsfeld ueberall  weg-
lassen, indem man den Typbezeichner streicht. Solche Datensatzde-
finitionen sind bekannt als freie Vereinigungen (free unions). Im 
Gegensatz  dazu heissen diejenigen mit Kennzeichnungsfeld gekenn-
zeichnete  Vereinigungen (discriminated unions).  Die  Verwendung 
freier  Vereinigungen sind selten und sollten nur von  erfahrenen 
Programmierern praktiziert werden.
.pa


12. Mengentypen

Eine Menge ist eine Sammlung verwandter Objekte, die man sich als 
eine Gesamtheit vorstellen kann. Jedes Objekt einer solchen Menge 
heisst  Mitglied oder Element der Menge.  Beispiele  fuer  Mengen 
sind:
     1) Alle ganzen Zahlen von 0 bis 100.
     2) Alle Buchstaben des Alphabets.
     3) Alle Konstanten des Alphabets.
Zwei Mengen sind dann und nur dann gleich, wenn ihre Elemente die 
gleichen  sind.  Es gibt in dieser Definition keinen  Ordnungsbe-
griff, sodass folgende Mengen gleich sind:
   [1,3,5]     [5,3,1]     [3,5,1].
Wenn  alle Elemente einer Menge auch Elemente einer anderen Menge 
sind,  sagt man,  dass diese Menge in der anderen Menge enthalten 
ist. Sie wird auch als Teilmenge der anderen Menge bezeichnet. Im 
obigen Beispiel ist 3) in 2) enthalten.
Es gibt drei Operationen, die den Zahlenoperationen entlehnt sind 
und auf Mengen angewandt werden koennen: die Vereinigung (+), der 
Durchschnitt (*) und das relative Komplement (-):

     Die   Vereinigung  (oder  Summe)  zweier  Mengen  A  und  B, 
     geschrieben A+B,  ist die Menge aller Elemente, die entweder 
     in A oder in B enthalten sind. Die Vereinigung von [1,3,5,7] 
     und [2,3,4] ist [1,2,3,4,5,7].

     Der  Durchschnitt  (oder  Produkt) zweier Mengen  A  und  B, 
     geschrieben A*B, ist die Menge aller Elemente, die sowohl in 
     A  als  auch  in B  enthalten  sind.  Der  Druchschnitt  von 
     [1,3,4,5,7] und [2,3,4] ist [3,4].

     Das   relative  Komplement  (oder  die  Differenz)   von   B 
     bezueglich A, geschrieben A-B, ist die Menge aller Elemente, 
     die  in A aber nicht in B enthalten sind.  Die Differenz von 
     [1,3,4,5,7] und [2,3,4] ist [1,5,7].

12.1 Mengentyp-Definition

Obgleich  es  in der Mathematik keine Einschraenkungen  fuer  die 
Elemente  einer  Menge gibt,  gestattet Pascal  nur  eine  einge-
schraenkte Form der Definition von Mengen:
Die Elemente einer Menge muessen alle vom gleichen Typ sein,  dem 
Basistyp.  Der  Basistyp muss ein einfacher Typ  sein,  d.h.  ein 
beliebiger Skalartyp ausser REAL.  Die Definition eines Mengentyp 
besteht aus einem Mengentypbezeichner, dem ein Gleichheitszeichen 
und die reservierten Worte set of und ein einfacher Typ folgen.

Beispiele:
     DaysOfMonth     =   set of 0..31;
     WorkWeek        =   set of Mon..Fre;       
     Letter          =   set of 'A'..'Z';
     Additiv Colors  =   set of [Red,Green,Blue];
     Characters      =   set of Char;

In TURBO-Pascal betraegt die maximale Anzahl von Elementen  einer 
Menge  256     und die Ordnungswerte des Basistyp muessen im  Be-
reich 0..255 liegen.
.pa


12.2 Mengenausdruecke

Mengenwerte  koennen  aus anderen Mengenwerten  durch  Mengenaus-
druecke berechnet werden. Mengenausdruecke bestehen aus:
          Mengenkonstruktionen,
          Mengenoperatoren,
          Mengenkonstanten und
          Mengenvariablen. 



12.2.1 Mengenkonstruktionen

Eine  Mengenkonstruktion besteht aus einer oder mehreren  Elemen-
tenspezifikationen,  die  durch Komma voneinander getrennt und in 
eckige Klammern eingeschlossen sind.  Eine Elementenspezifikation 
ist ein Ausdruck vom gleichen Typ wie der Basistyp der Menge. Sie 
kann  auch ein Bereich sein,  der durch zwei  solcher  Ausdruecke 
dargestellt wird, getrennt durch zwei aufeinanderfolgende Punkte.

Beispiele:
     ['T','U','R','B','O']
     ['X','Y']
     [X..Y]
     [1..5]
     ['A'..'Z','a'..'z','0'..'9']
     [1,3..10,12]
     []   

Das  letzte Beispiel stellt die leere Menge dar.  Da  sie  keinen 
Ausdruck enthaelt, der ihren Basistyp festlegt, ist sie mit allen 
Mengentypen   kompatibel.    Die  Menge  [1..5]  ist  der   Menge 
[1,2,3,4,5]  equivalent.  Wenn  X>Y,  dann bezeichnet [X..Y]  die 
leere Menge.


12.2.2 Mengenoperationen

Die  Mengenoperationen  werden entsprechend  ihrer  Rangfolge  in 
folgende drei Klassen eingeteilt:

     1)  *    Mengendurchschnitt.

     2)  +    Mengenvereinigung,
         -    Mengendifferenz.

     3)  =    Test auf Gleichheit,
         <>   Test auf Ungleichheit,
         >=   Wahr,  wenn der zweite Operand im ersten  enthalten 
              ist,
         <=   Wahr,  wenn der erste Operand im zweiten  enthalten 
              ist,
         in   Test auf Mitgliedschaft in einer Menge.  Der zweite 
              Operand ist ein Mengentyp und der erste ein Mengen-
              ausdruck  vom  gleichen  Typ wie der  Basistyp  der 
              Menge.  Das Ergebnis ist wahr,  wenn der erste Ope-
              rand ein Element des zweiten Operanden ist, andern-
              falls ist es falsch.

Es gibt keinen Operator fuer ein exaktes Nichtenthaltensein. Aber 
man kann dies in der Form  A*B = [] programmieren.
.pa


Mengenausdruecke sind oft brauchbar,  um komplizierte Tests  ein-
facher zu programmieren. Dafuer einige Beispiele:

fuer:     (CH='T') or (CH='U') or (CH='R') or (CH='B') or (CH='O')

besser:   CH in ['T','U','R','B','O']


fuer:     (CH>'0') and (CH<'9')

besser:   CH in ['0'..'9']



12.2.3 Mengenzuweisungen

Mengenvariablen wird das Ergebnis von Mengenausdruecken durch das 
Ergibtzeichen ':=' zugewiesen.

Beispiele:
     type
          ASCII = set of 0..127;
     var
          NoPrint,Print,AllChars : ASCII;
     begin
          AllChars := [0..127];
          NoPrint  := [0..31,127];
          Print    := AllChars - NoPrint;
     end;


.pa


13. Typisierte Konstante

Typisierte Konstante sind eine TURBO Spezialitaet. Eine typisier-
te  Konstante  kann man exakt wie eine Variable vom gleichen  Typ 
verwenden. Sie koennen deshalb als initialisierte Variable einge-
setzt werden. Denn ihr Wert ist von Anfang an definiert, waehrend 
eine Variable solange undefiniert ist,  bis ihr ein Wert zugewie-
sen wurde.
Man  sollte  natuelich  darauf  achten,   das  einer  typisierten 
Konstante  keine Werte zugewiesen werden,  denn ihr  Wert  sollte 
eben wirklich konstant sein.
Die Verwendung typisierter Konstanten hilft Speicherplatz sparen, 
wenn sie haeufig im Programm verwendet werden. Denn sie werden im 
Programmcode nur einmal gespeichert,  im Gegensatz zu den untypi-
sierten Konstanten, die im Code jedesmal gespeichert werden, wenn 
sie im Text vorkommen.
Typisierte   Konstanten   werden  wie   untypisierte   Konstanten 
definiert (siehe 5.2.2), sie enthalten nur zusaetzlich auch ihren 
Typ. 
Die  Definition  einer  typisierten Konstanten  besteht  aus  dem 
Konstantenbezeichner,  einem  Doppelpunkt,  einem  Typbezeichner, 
einem Gleichheitszeichen und dem wirklichen Konstantenwert.


13.1 Unstrukturierte typisierte Konstante

Eine unstrukturierte typisierte Konstante ist eine Konstante, die 
durch einen Skalartyp definiert wird. 

Beispiele:
     NumbersOfCars : Integer = 1267;
     Interest : Real = 12.67;
     Heading : string[7] = 'Section';
     Xon : Char = ^Q;

Im Gegensatz zu den untypisierten Konstanten kann eine typisierte 
Konstante anstelle  einer Variablen als Parameter in  einer  Pro-
zedur  oder Funktion verwendet werden.  Eine typisierte Konstante 
ist  tatsaechlich eine Variable mit einem  konstanten  Wert.  Sie 
kann  deshalb  nicht  in der Definition anderer  Konstanten  oder 
Typen  verwendet werden.  Deshalb ist im folgenden  Beispiel  die 
Verwendung der typisierten Konstanten Min und Max nicht erlaubt:

     const
          Min : integer = 0;
          Max : integer = 50; 
     type 
          Range : array[Min..Max] of integer;   {Falsch !}


13.2 Strukturierte typisierte Konstante

Strukturierte Konstante sind
                    Feldkonstante,
                    Datensatzkonstante und 
                    Mengenkonstante.
Sie werden häufig verwendet,  um initialisierte Tabellen und Men-
gen fuer Tests,  Konvertierungen,  Abbildungsfunktionen usw.  be-
reitzustellen.  Die  folgenden Abschnitte definieren jeden Typ im 
Einzelnen.
.pa

13.2.1 Feldkonstante

Die  Definition einer typisierten Feldkonstanten besteht aus  dem 
Konstantenbezeichner,  einem Doppelpunkt, dem Typbezeichner eines 
vorher definierten Feldtyps,  dem Gleichheitszeichen und dem kon-
stanten Wert.  Letzterer besteht aus einer Liste von  Konstanten, 
die durch Komma getrennt und in Klammern eingeschlossen sind.

Beispiele:
     type
          Status         =    (Activ,Passiv,Wartend);
          StringRep      =    array[Status] of string[7];
     const
          Stat:StringRep =    ('aktiv','passiv','wartend');

Das  Beispiel  definiert die Feldkonstante  Stat,  die  verwendet 
werden kann,  um Werte vom Skalartyp Status in ihre entsprechende 
Stringdarstellung zu konvertieren:
     Stat[Aktiv]    = 'aktiv'
     Stat[Passiv]   = 'passiv'
     Stat[Wartend]  = 'wartend'

Der  Komponententyp  einer  Feldkonstanten kann  jeder  Typ  sein 
ausser  einem Feld- oder Pointertyp.  Charakterfeldtypen  koennen   
sowohl  als einzelne Char als auch als Strings definiert  werden. 
Aus diesem Grunde ist es guenstiger statt:

     const
          Digits : array[0..9] of 
               Char=('0','1','2','3','4','5','6','7','8','9');
besser:
     
     const
          Digits : array[0..9] of Char='0123456789';

zu schreiben.


13.2.2 Mehrdimensionale Feldkonstante

Eine  typisierte mehrdimensionale Feldkonstante wird analog defi-
niert,  indem  man jede Dimension in separate Klammernpaare  ein-
schliesst, die durch Komma voneinander getrennt sind. Die inners-
te  Konstant entspricht der am weitesten rechts  stehenden  Dimen-
sion:

Beipiele:
     type
          Cube = array[0..1,0..1,0..1] od integer;
     const
          Maze : Cube = (((0,1),(2,3)),((4,5),(6,7)));
     begin
          writeln(Maze[0,0,0],' =0');
          writeln(Maze[0,0,1],' =1');
          writeln(Maze[0,1,0],' =2');
          writeln(Maze[0,1,1],' =3');
          writeln(Maze[1,0,0],' =4');
          writeln(Maze[1,0,1],' =5');
          writeln(Maze[1,1,0],' =6');   
          writeln(Maze[1,1,1],' =7');   
     end;

.pa

13.2.3 Datensatzkonstante

Die Definition einer typisierten Datensatzkonstanten besteht  aus 
dem  Konstantenbezeichner,  einem Doppelpunkt,  dem Typbezeichner 
eines vorherdefinierten Datensatztyps,  einem  Gleichheitszeichen 
und  dem Konstantenwert.  Letzterer ist eine Liste,  die aus  den 
Datenfeldkonstanten,  getrennt  durch Komma und eingeschlossen in 
runde Klammern, besteht. 

Beipiele:
     type
          Point     = record
                         X,Y,Z : integer;
                      end;
          OS        = (CPM80,CPM86,MSDOS,UNIX);
          UI        = (CCP,SomethingElse,MenuMaster);
          Computer  = record
                         OperatingSystems : array[1..4] of OS;
                         UserInterfacs : UI;
                      end;    
     const
          Origo     : Point   = (X:0; Y:0; Z:0);
          SuperComp : Computer=
                         (OperatingSystems:(CPM80,CPM86,MSDOS,UNIX);
                          UserInterface:MenuMaster);
          Planel : array[1..3] of Point =
                         ((X:1;  Y:4;  Z:5),
                          (X:10, Y:-78,Z:45),
                          (X:100,Y:10, Z:-75));    

Die Feldkonstanten muessen in der gleichen Reihenfolge  definiert 
werden,  wie  sie in der Datensatzdefinition auftreten.  Wenn ein 
Datensatz  Felder  vom File- oder  Pointertyp  enthaelt,  koennen 
typisierte  Konstanten fuer diesen Datensatztyp  nicht  definiert 
werden. Wenn eine Datensatzkonstante eine Variante enthaelt, dann 
ist der Programmierer selbst dafuer verantwortlich,  dass nur die 
Datenfelder der gueltigen Variante spezifiziert werden.  Wenn die 
Variante ein Kennzeichnungsfeld enthaelt, dann muss auch ihr Wert 
spezifiziert werden.



13.2.4 Mengenkonstanten

Eine  typisierte Mengenkonstante besteht aus einer oder  mehreren 
Elementenspezifikationen, die durch Komma getrennt und in eckigen 
Klammern  eingeschlossen sind.  Eine Elementenspezifikation  darf 
eine  Konstante  oder  ein Bereichsausdruck sein,  der  aus  zwei 
Konstanten, getrennt durch zwei Punkte, besteht.

Beipiele:
     type
          Up  = set of 'A'..'Z';
          Low = set of 'a'..'z';
     const
          UpperCase : Up  = ['A'..'Z'];
          Vocals    : Low = ['a','e','i','o','u'];
          Delimiter : set of Char = 
                         [' '..'/',':'..'?','['..'`','{'..'~'];

.pa


14. Filetypen

Computerprogramme produzieren häufig so grosse Datenmengen,  dass 
man  sie nicht bis zu einer spaeteren Verwendung im gleichen oder 
anderen Programmen im Speicher belassen kann.  Aus diesem  Grunde 
speichert man solche Datenmengen auf externen Datentraegern,  wie 
Magnetbandkassetten  oder  Disketten.  Die Einheit einer  solchen 
Datenmenge heisst File oder Datei. 
Ein  File besteht aus einer Folge von Komponenten gleichen  Typs. 
Die  Anzahl der Komponenten im File (die Filegroesse) wird  nicht 
in der Filedefinition festgelegt.  Stattdessen wird in Pascal der       
Zugriff  zu  den  einzelnen Komponenten ueber  einen  Filepointer 
organisiert.  Jedesmal,  wenn  eine Komponente des Files  gelesen 
oder  geschrieben wird,  rueckt der Filepointer  eine  Komponente 
weiter, d.h. er weist auf die naechste Komponente. Da alle Kompo-
nenten eines File die gleiche Laenge haben, weil sie vom gleichen 
Typ sind, kann die Position einer bestimmten Komponente berechnet 
werden  d.h.  man kann ueber den Filepointer zu jeder  Komponente 
des File zugreifen. Damit sind die Voraussetzungen gegeben, einen 
wahlfreien Zugriff zu den Komponenten des File aufzubauen.


14.1 Filetyp-Definition

Ein Filetyp wird durch die reservierten Worte file of,  denen der 
Typbezeichner der Komponenten folgt, definiert. Eine Filevariable 
wird definiert durch einen Filevariablenbezeichner, einem Doppel-
punkt  und  einen  Filetyp.  Dabei gibt es  zwei  Moeglichkeiten, 
jenachdem, ob der Filetyp mit einem Filetypbezeichner explizit im 
Typdefinitionsteil definiert wurde oder nicht:

     1) type   Komponente =  record
                              x,y,z : integer;
                             end;
               Filetyp    =  file of Komponente;
        var    FileVar    :  Filetyp;
oder
     2) type   Komponente =  record
                              x,y,z : integer;
                             end;
        var    FileVar    : file of Komponente  

Beispiele: 
     type
       ProductName = string[80];
       Product     = record
                      Name      : ProductName;
                      ItmNumber : Real;
                      InStock   : Real;
                      MinStock  : Real;
                      Supplier  : Integer;
                     end;
     FProduct      = file of Product;

     var
       ProductFiles   :   FProduct;  
       ProductNames   :   file of ProductName;

Der Komponententyp eines Files kann irgend ein Typ  sein,  jedoch 
kein Filetyp!, d.h. in obigem Beispiel ist 
     var ProdFile : file of FProduct
nicht erlaubt.
.pa

Man beachte auch, dass zwar       var P1File : FProduct;          
und                                   P2File : FProduct;
den gleichen Filetyp haben, aber nicht:
                                  var PM1File : file of Product;
und                                   PM2File : file of Product;
Weiterhin merke man sich: Filevariable duerfen weder in Ergibtan-
weisungen noch in Ausdruecken auftreten.


14.2 Fileoperationen

In den folgenden Abschnitten werden die in TURBO-Pascal vorhande-
nen Fileprozeduren beschrieben. Dabei werden folgende Kurzzeichen 
fuer die Parameter verwendet:

     str       Stringausdruck,  der einen gueltigen Filenamen  in 
               der bekannten Form 
                    '[A:]Dateinam.Typ'
               darstellen muss.
     filvar    Filevariable.
     var       Eine  Variable  oder mehrere  Variable,  die  dann 
               durch  Komma getrennt sein muessen,  und die  alle 
               den  gleichen  Komponententyp wie das  File  haben 
               muessen.
     num       Integerkonstante.


14.2.1 Assign

Syntax:        Assign(filvar,str)

Durch diese Prozedur wird der in str enthaltene physische Filena-
men  der  Filevariablen filvar zugewiesen.  Danach beziehen  sich 
alle auf filvar ausgeuebte Operationen auf das genannte physische 
Diskettenfile.  Wurde  der Filevariablen bereits  ein  physischer 
Filenamen zugewiesen,  und mit der Filevariablen gearbeitet, darf 
ein erneutes ASSIGN auf sie nicht angewendet werden.



14.2.2 Rewrite

Syntax:        Rewrite(filvar)

Mit  dieser Prozedur wird auf der Diskette ein neues File mit dem 
filvar zugewiesenen physischen Filenamen aufgebaut. Der Filepoin-
ter wird dabei auf den Anfang des File,  d.h.  auf die Komponente 
mit der Nummer 0, gesetzt. Existiert auf der Diskette bereits der 
gleiche physische Filenamen,  dann wird das zugehoerige File  ge-
loescht!  Ein  mit REWRITE erzeugtes File ist anfangs immer  leer 
und enthaelt kein Element.



14.2.3 Reset

Syntax:        Reset(filvar)

Das  filvar zugewiesene File wird fuer die Verarbeitung vorberei-
tet und der Filepointer auf den Anfang des File,  d.h. die Kompo-
nente mit der Nummer 0,  gesetzt.  Das zugewiesene File muss  be-
reits existieren, sonst entsteht in I/O-Fehler.

.pa

14.2.4 Read

Syntax:        Read(filvar,var)

Durch  diese  Prozedur werden die Variablen var nacheinander  mit 
dem  Inhalt  der Komponenten des filvar  zugeordneten  Files  ge-
fuellt. Begonnen wird mit der Komponente, auf die der Filepointer 
zeigt.  Nach  jeder  Zuweisung wird der Pointer auf die  naechste 
Komponente eingestellt.


14.2.5 Write

Syntax:        Write(filvar,var)

Durch diese Prozedur werden nacheinander der Inhalt der Variablen 
var in die Komponenten des filvar zugewiesenen Files geschrieben. 
Begonnen wird mit der Komponente,  auf die der Filepointer zeigt. 
Nach  jedem  Schreibvorgang  wird der Pointer  auf  die  naechste 
Komponente eingestellt.


14.2.6 Seek

Syntax:        Seek(filvar,num)

Der  Filepointer des filvar zugeordneten Files wird  durch  diese 
Prozedur auf die Komponente mit der Nummer num-1 eingestellt (die 
1.Komponente  hat  die  Nummer 0!).  Um ein  File  zu  erweitern, 
braucht  man  nur den Filepointer auf die Komponente  hinter  der 
letzten Komponente des File einzustellen.


14.2.7 Flush

Syntax:        Flush(filvar)

Diese  Prozedur wird eigentlich nur in Multi-User-Systemen benoe-
tigt,  in denen mehrere Nutzer zum gleichen Diskettenfile zugrei-
fen  koennen.  Flush  schreibt sofort den Update-Puffer  auf  die 
Diskette  zurueck und sichert damit nach  Updatefunktionen,  dass 
die  naechste  Leseoperation wirklich als  ein  physisches  Lesen 
ausgefuehrt  wird.  Flush  darf  niemals  auf  ein  geschlossenes 
(CLOSE) File angewendet werden.


14.2.8 Close

Syntax:        Close(filvar)

Diese  Prozedur  schliesst das filvar zugeordnete physische  File 
und schreibt den aktuellen Filestatus in das Diskettenvezeichnis. 
In Multi-User-Systemen sollte man oefter diese Prozedur anwenden, 
auch wenn nur gelesen wurde.


14.2.9 Erase

Syntax:        Erase(filvar)

Diese Prozedur loescht das filvar zugeordnete File im  Disketten-
verzeichnis.  Wenn das File bereits eroeffnet wurde,  d.h.  RESET 
oder REWRITE ausgefuehrt wurde,  sollte man stets CLOSE vor ERASE 
aufrufen.
.pa

14.2.10 Rename

Syntax:        Rename(filvar,st)

Das filvar zugewiesene File erhaelt den in str enthaltenen  neuen 
Filenamen.  Der neue Name wird in das Diskettenverzeichnis einge-
tragen  und  die weiteren Operationen von filvar werden dann  mit 
diesem File unter dem neuen Namen ausgefuehrt.
Man sollte RENAME niemals auf ein bereits eroeffnetes File anwen-
den.  Ebenso  sollte der Programmierer sichern,  dass das mit str 
benannte  File nicht bereits auf der  Diskette  existiert.  Sonst 
entstehen doppelte Namen in der Direktory. 

Die  folgende Funktion gibt den Wert True zurueck,  falls der  im 
Parameter  spezifizierte Filenamen bereits in der Direktory exis-
tiert, andernfalls ist der Wert False:

     function Exist(Filename:Boolean):Boolean;
     var
          File:file;
     begin
          Assign(File,FileName);
          {$I-};
          Reset(File);
          {$I+};
          if Ioresult <> 0 then Exist := False;
                           else Exist := True;
     end;




14.3 Standardfilefunktionen

TURBO-Pascal enthaelt die folgenden Standardfilefunktionen:


14.3.1 EOF

Syntax:        Eof(filvar)

Diese  Boolesche-Funktion gibt den Wert True  zurueck,  wenn  der 
Filepointer  das Fileende erreicht hat,  d.h.  hinter die  letzte 
Komponente  des filvar zugewiesenen Files weist.  Andernfalls ist 
der zurueckgegebene Wert False.


14.3.2 FilePos

Syntax:        FilePos(filvar)

Diese  Integer-Funktion gibt den Wert der aktuellen Position  des 
Filepointer zurueck. Die erste Komponente hat den Wert 0.


14.3.3 FileSize

Syntax:        FileSize(filvar)

Diese  Integer-Funktion  gibt  den Wert der  Groesse  des  filvar 
zugeordneten Files zurueck,  d.h.  die Anzahl der Komponenten des 
Files.  Wenn FileSize(filvar) gleich Null ist,  dann ist das File 
leer.

.pa



14.4 Filenutzung

Bevor ein File benutzt werden kann,  muss ASSIGN aufgerufen  wer-
den,  um  der Filevariablen ein physisches File  zuzuordnen.  Vor 
einer I/O-Operation sollte das File durch Aufruf von REWRITE oder 
RESET eroeffnet werden. Damit zeigt der Filepointer auf die erste 
Komponente des File,  d.h. es ist FilePos(filvar)=0. Nach REWRITE 
ist  stets FileSize(filvar)=0.  Ein Diskettenfile kann nur  durch 
Anfuegen  von weiteren Komponenten hinter die letzte  existierend 
Komponente  des File erweitert werden.  Den Filepointer kann  man 
dafuer an das  Fileende positionieren durch:

          Seek(filvar,FileSize(filvar));

Nach  Beendigung  aller Input/Output-Operationen  sollte  man  in 
einem  Programm stets die eroeffneten Files durch CLOSE  schlies-
sen.  Vergisst man dies, kann das zu Datenverlust fuehren, da das 
Diskettenverzeichnis  dann eventuell nicht dem letzten Stand  des 
Filestatus entspricht.

Das  folgende Programm baut ein File mit dem  Namen  PRODUCTS.DTA 
auf  und  schreibt 100 Saetze vom Typ Product auf das  File.  Das 
File  ist  fuer einen wahlfreien Zugriff  vorbereitet  (d.h.  die 
Saetze koennen von jeder Stelle des File gelesen oder geschrieben 
werden).

     program InitProductFile;
     const
       MaxNumberOfProducts = 100;
     type
       ProductName         = string[20];
       Product             = record
                               Name         : ProductName;
                               ItemNumber   : Integer;
                               InStock      : Real;
                               Supplier     : Integer;
                             end;
     var
       ProductFile         : file of Product;
       ProductRec          : Product;
       I                   : Integer;
     begin
       Assign(ProductFile,'F:PRODUCT.DTA');
       Rewrite(ProductFile);   {eroeffnet File und loescht alle Daten}
       with ProductRec do
         begin
           Name := ' '; InStock := 0; Supplier := 0;
           for I := 1 to MaxNumberOfProducts do
           begin
             ItemNumber := I;
             Write(ProductFile,ProductRec);
           end;
         end;
         Close(ProductFile);
       end.
.pa



Das  folgende Programm demonstriert die Verwendung von SEEK  fuer 
den  wahlfreien  Zugriff.  Mit diesem Programm kann  man  in  dem    
soeben  aufgebauten  File PRODUCT.DTA den Inhalt in  die  bereits 
existierenden  Datensaetze (Komponenten) bringen oder den  Inhalt 
spaeter aendern.





     program UpdateProductFile;
     const
       MaxNumberOfProducts = 100;
     type
       ProductName         = string[20];
       Product             = record
                               Name         : ProductName;
                               ItemNumber   : Integer;
                               InStock      : Real;
                               Supplier     : Integer;
                             end;
     var
       ProductFile         : file of Product;
       ProductRec          : Product;
       I,Pnr               : Integer;
     begin
       Assign(ProductFile,'F:PRODUCT.DTA');
       Reset(ProductFile);
       ClrScr;
       Write('Enter product number (0 = stop):'); Readln(Pnr);
       while Pnr in [1..MaxNumberOfProducts] do
       begin
         Seek(ProductFile,Pnr-1); Read(ProductFile,ProductRec);
         with ProductRec do
         begin
           Write('Enter name of product(',name:20,') ');
           Readln(Name);
           Write('Enter number in stock (',InStock:20:0,') ');
           Readln(InStock);
           Write('Enter supplier number (',Supplier:20,') ');
           Readln(Supplier);
           ItemNumber := Pnr;
         end;
         Seek(ProductFile,Pnr-1);
         Write(ProductFile,ProductRec);
         ClrScr; Writeln;
         Write('Enter product number (0 = stop):'); Readln(Pnr);
       end;
       Close(ProductFile);
     end.

.pa