52
PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI 266 CAPITOLUL 8 LIMBAJUL PASCAL 8.1. ELEMENTELE DE BAZA ALE LIMBAJULUI PASCAL Limbajele de programare reprezintǎ unul din principalele mijloace de comunicare om- maşinǎ, evoluţia lor fiind nemijlocit legatǎ de cea a calculatoarelor electronice, a cǎror erǎ începe în 1944. Primele calculatoare puteau fi programate numai în limbaj maşinǎ. La începutul anilor ’50, se înregistreazǎ trecerea la programarea simbolicǎ, prin apariţia limbajelor de asamblare caracterizate prin folosirea codurilor mnemonice pentru instrucţiuni şi a adresǎrii simbolice a operanzilor. Dupǎ apariţia primului limbaj de nivel înalt, limbajul FORTRAN (1954), se observǎ o proliferare acceleratǎ a limbajelor de programare, astfel prin 1969, se pot identifica 120 de limbaje de programare cu o largǎ utilizare, iar în primii ani ai deceniului opt, un sondaj efectuat în S.U.A. identifica, la nivelul unui singur domeniu de activitate (sistemele informatice ale armatei americane) utilizarea a peste 450 de limbaje de programare sau dialecte ale unor limbaje. 8.1.1. Apariţia, evoluţia şi caracteristicile generale ale limbajului Apariţia limbajului Pascal este un rezultat al conceptelor dezvoltate ca urmare a crizei programǎrii ce caracteriză domeniul programǎrii calculatoarelor la sfârşitul anilor ’60. În aceastǎ perioadǎ, rǎspândirea pe plan mondial a prelucrǎrii automate a datelor a cunoscut o extindere remarcabilǎ, trecându-se la abordarea şi rezolvarea unor probleme din ce în ce mai complexe. Programele mari asociate acestor probleme s-au complicat în aşa mǎsurǎ încât au devenit foarte greu accesibile, chiar şi pentru autorii lor. Întelegerea, depanarea şi dezvoltarea unor astfel de programe prezintǎ dificultǎţi majore. Limitǎrile limbajelor de programare cu largǎ utilizare în epocǎ (FORTRAN, COBOL etc.), dublatǎ de inexistenţa unor principii clare, care sǎ impunǎ o disciplinǎ a programǎrii, au favorizat în mare mǎsurǎ programarea empiricǎ. Ca rǎspuns la cerinţa de elaborare a unei metodologii generale de dezvoltare sistematicǎ a programelor s-a cristalizat metoda proiectǎrii şi programǎrii structurate. Un program structurat este constituit din unitǎţi funcţionale bine conturate, ierarhizate conform naturii intrinseci a problemei. În interiorul unor astfel de unitǎţi, structura se manifestǎ atât la nivelul acţiunilor (instructiunilor), cât şi al datelor. Programarea structuratǎ este o metodǎ independentǎ de limbajul de programare, acţionând la nivelul stilului de lucru. În 1968, profesorul elveţian Niklaus Wirth realizează acest limbaj. Numele limbajului a fost ales ca un omagiu adus marelui matematician, fizician, filosof şi scriitor francez Blaise Pascal (1623-1662), primul care, în 1642, a inventat o maşinǎ de calcul. Dupǎ o fazǎ de dezvoltare extensivǎ, un prim compilator devine operaţional în 1970, limbajul fiind publicat în 1971. Interesul trezit de apariţia sa a condus la necesitatea unor consolidǎri ale limbajului, finalizate prin publicarea în 1973 a unui raport revizuit, în care se realizeazǎ o definire a formei de referinţǎ numitǎ Pascal Standard, redactatǎ ulterior conform normelor ISO şi devenitǎ bazǎ comunǎ pentru diverse implementǎri. Limbajul Pascal include conceptele programǎrii structurate în ambele laturi ale efortului de abstractizare presupus de realizarea unui program - organizarea datelor şi conceperea acţiunilor. Printre principalele caracteristici ale lui pot fi menţionate: • Include o serie de instrucţiuni care reprezintǎ chiar structurile de control impuse de tehnica progrămǎrii structurate (IF-THEN-ELSE, CASE, REPEAT, WHILE, FOR). • Are facilitǎţi puternice şi deosebit de flexibile pentru reprezentarea datelor. Noţiunea de tip de date a fost extinsǎ dincolo de cercul restrâns al datelor întregi, reale, şiruri de caractere şi tablouri (masive). S-au introdus structuri de date complexe, ca articolul (înregistrarea), mulţimea, fisierul şi posibilitǎţi de a descrie altele noi, combinându-le pe cele existente. La acestea se adaugǎ facilitatea de a defini şi manipula structuri dinamice (liste liniare, arbori etc.). În anumite implementǎri ale

CAPITOLUL 8 PCLP LPas.pdf

Embed Size (px)

Citation preview

Page 1: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

266

CAPITOLUL 8

LIMBAJUL PASCAL

8.1. ELEMENTELE DE BAZA ALE LIMBAJULUI PASCAL Limbajele de programare reprezintǎ unul din principalele mijloace de comunicare om-

maşinǎ, evoluţia lor fiind nemijlocit legatǎ de cea a calculatoarelor electronice, a cǎror erǎ începe în 1944. Primele calculatoare puteau fi programate numai în limbaj maşinǎ. La începutul anilor ’50, se înregistreazǎ trecerea la programarea simbolicǎ, prin apariţia limbajelor de asamblare caracterizate prin folosirea codurilor mnemonice pentru instrucţiuni şi a adresǎrii simbolice a operanzilor. Dupǎ apariţia primului limbaj de nivel înalt, limbajul FORTRAN (1954), se observǎ o proliferare acceleratǎ a limbajelor de programare, astfel prin 1969, se pot identifica 120 de limbaje de programare cu o largǎ utilizare, iar în primii ani ai deceniului opt, un sondaj efectuat în S.U.A. identifica, la nivelul unui singur domeniu de activitate (sistemele informatice ale armatei americane) utilizarea a peste 450 de limbaje de programare sau dialecte ale unor limbaje.

8.1.1. Apariţia, evoluţia şi caracteristicile generale ale limbajului

Apariţia limbajului Pascal este un rezultat al conceptelor dezvoltate ca urmare a crizei

programǎrii ce caracteriză domeniul programǎrii calculatoarelor la sfârşitul anilor ’60. În aceastǎ perioadǎ, rǎspândirea pe plan mondial a prelucrǎrii automate a datelor a cunoscut o extindere remarcabilǎ, trecându-se la abordarea şi rezolvarea unor probleme din ce în ce mai complexe. Programele mari asociate acestor probleme s-au complicat în aşa mǎsurǎ încât au devenit foarte greu accesibile, chiar şi pentru autorii lor. Întelegerea, depanarea şi dezvoltarea unor astfel de programe prezintǎ dificultǎţi majore. Limitǎrile limbajelor de programare cu largǎ utilizare în epocǎ (FORTRAN, COBOL etc.), dublatǎ de inexistenţa unor principii clare, care sǎ impunǎ o disciplinǎ a programǎrii, au favorizat în mare mǎsurǎ programarea empiricǎ. Ca rǎspuns la cerinţa de elaborare a unei metodologii generale de dezvoltare sistematicǎ a programelor s-a cristalizat metoda proiectǎrii şi programǎrii structurate.

Un program structurat este constituit din unitǎţi funcţionale bine conturate, ierarhizate conform naturii intrinseci a problemei. În interiorul unor astfel de unitǎţi, structura se manifestǎ atât la nivelul acţiunilor (instructiunilor), cât şi al datelor.

Programarea structuratǎ este o metodǎ independentǎ de limbajul de programare, acţionând la nivelul stilului de lucru. În 1968, profesorul elveţian Niklaus Wirth realizează acest limbaj. Numele limbajului a fost ales ca un omagiu adus marelui matematician, fizician, filosof şi scriitor francez Blaise Pascal (1623-1662), primul care, în 1642, a inventat o maşinǎ de calcul. Dupǎ o fazǎ de dezvoltare extensivǎ, un prim compilator devine operaţional în 1970, limbajul fiind publicat în 1971. Interesul trezit de apariţia sa a condus la necesitatea unor consolidǎri ale limbajului, finalizate prin publicarea în 1973 a unui raport revizuit, în care se realizeazǎ o definire a formei de referinţǎ numitǎ Pascal Standard, redactatǎ ulterior conform normelor ISO şi devenitǎ bazǎ comunǎ pentru diverse implementǎri.

Limbajul Pascal include conceptele programǎrii structurate în ambele laturi ale efortului de abstractizare presupus de realizarea unui program - organizarea datelor şi conceperea acţiunilor.

Printre principalele caracteristici ale lui pot fi menţionate: • Include o serie de instrucţiuni care reprezintǎ chiar structurile de control impuse de tehnica

progrămǎrii structurate (IF-THEN-ELSE, CASE, REPEAT, WHILE, FOR). • Are facilitǎţi puternice şi deosebit de flexibile pentru reprezentarea datelor. Noţiunea de tip

de date a fost extinsǎ dincolo de cercul restrâns al datelor întregi, reale, şiruri de caractere şi tablouri (masive). S-au introdus structuri de date complexe, ca articolul (înregistrarea), mulţimea, fisierul şi posibilitǎţi de a descrie altele noi, combinându-le pe cele existente. La acestea se adaugǎ facilitatea de a defini şi manipula structuri dinamice (liste liniare, arbori etc.). În anumite implementǎri ale

Page 2: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

267

limbajului a fost introdus tipul obiect, care permite reunirea în aceeasi construcţie a datelor şi metodelor care le prelucreazǎ (proceduri şi funcţii), creând cadrul trecerii la programarea orientatǎ obiect (POO).

• Oferǎ posibilitǎţi de modularizare a programelor, prin structurarea lor în module cǎrora le pot fi asociate construcţii ale limbajului (proceduri şi funcţii).

• Fundamenteazǎ construcţiile pe conceptul de bloc, care permite, pe de o parte, definirea de date proprii (variabile locale) şi, pe de altǎ parte, accesul la datele din blocurile de pe nivelurile superioare (variabile globale).

• Posedǎ o bibliotecǎ bogatǎ de funcţii şi proceduri standard, cu elemente specifice diverselor implementǎri ale limbajului şi permite, totodatǎ, construirea de biblioteci ale utilizatorului.

Aceste caracteristici au fǎcut ca, deşi conceput iniţial pentru a servi ca suport de studiu al programǎrii structurate, limbajul sǎ fie folosit intens şi de cǎtre programatorii profesionişti. Ca efect, s-a ajuns rapid la o creştere spectaculoasǎ a productivitǎtii muncii de programare, ducând la rǎspândirea utilizǎrii limbajului.

Limbajul Pascal beneficiazǎ de implementǎri pe toate tipurile de sisteme de calcul. Multe dintre aceste implementǎri marcheazǎ şi dezvoltǎri ale limbajului însuşi, adicǎ în raport cu care Pascal Standard apare ca un subset. Dintre variantele utilizate de informaticienii români pot fi mentionate implementarea pe calculatoarele din generaţia a treia din familia FELIX, din 1978; Pascal Oregon pentru minicalculatoarele din familiile Independent şi Coral; implementǎrile realizate de firma Borland International pentru microcalculatoarele IBM PC şi compatibile.

Firma Borland a realizat, începând cu 1983, medii integrate de dezvoltare (IDE - Integrated Development Environment) cu denumirile generice Turbo Pascal, Borland Pascal şi Delphi. Turbo Pascal, ajuns la versiunea 7.0, a marcat introducerea progresivǎ a unor noi facilitǎţi, dintre care cele mai semnificative sunt:

· realizarea segmentǎrii programelor folosind tehnica overlay, începând cu versiunea 5.0 (1988);

· introducerea conceptelor POO, începând cu versiunea 5.5 (1989); · folosirea mouse-ului, ferestrelor de editare multiple, asamblorului integrat şi sistemului

Turbo Vision, pentru dezvoltarea de aplicaţii orientate obiect, în versiunea 6.0 (1990). Versiunile din categoria Turbo Pascal sunt destinate utilizǎrii sub DOS. Pentru dezvoltarea de

aplicaţii Windows a fost lansatǎ implementarea Borland Pascal 7.0 pentru Windows, cu posibilitǎţi superioare de utilizare a POO. Ultima realizare a firmei Borland o reprezintǎ Delphi, care implementeazǎ facilitǎţi de POO şi programare vizualǎ. Dacǎ în cazul implementǎrilor pe 16 biţi apare limitarea importantǎ a dimensiunii segmentelor de date şi de cod la 64 KB (spaţiul maxim de adrese care poate fi gestionat cu un cuvânt de 16 biţi), trecerea la cod pe 32 de biţi face ca limitǎrile sǎ fie impuse numai de sistemul de operare.

8.1.2. Construcţiile limbajului

Acceptând terminologia folositǎ în definirea limbajelor formale, limbajului Pascal îi poate fi

asociatǎ o gramaticǎ formatǎ din urmǎtoarele clase de elemente: - alfabetul terminal (AT), format din entitǎţile elementare ale limbajului, (cele mai mici

unitǎţi cu semnificaţie proprie). Prin comparaţie cu limbajul natural, aceste unitǎţi formeazǎ mulţimea cuvintelor sau lexicul limbajului Pascal (simboluri speciale, cuvinte rezervate, identificatori, etichete, literali numerici, literali nenumerici);

- alfabetul neterminal (AN), format din mulţimea constructiilor sintactice realizate prin agregare succesivǎ pornind de la elementele alfabetului terminal;

- simbolul de start sau axioma gramaticii (aoÎAN), care este construcţia sintacticǎ de cel mai înalt nivel;

- mulţimea producţiilor (P), formatǎ din regulile de sintaxǎ ce se aplicǎ în realizarea construcţiilor limbajului.

Page 3: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

Construcţiile sintactice ale limbajului Pascal sunt formate, din unitǎţi lexicale şi separatori, unde separatorul este un spaţiu sau un comentariu. Douǎ unitǎţi lexicale trebuie sǎ fie separate prin unul sau mai mulţi separatori, dacǎ fiecare dintre ele este un cuvânt rezervat, un identificator, o etichetǎ sau un numǎr. Separatorii nu pot fi parte a unitǎţilor lexicale, cu excepţia includerii în şiruri de caractere.

Principalele construcţii sintactice ale limbajului Pascal sunt: - expresiile, care sunt construcţii formate din operanzi (date numerice, logice, de tip

caracter etc.) şi operatori (aritmetici, relaţionali, logici etc.) şi a cǎror evaluare produce o valoare de un anumit tip;

- declaraţiile, care sunt construcţii pentru definirea şi descrierea datelor (constante şi/sau variabile, date scalare şi/sau structuri de date etc.);

- instrucţiunile, pentru descrierea acţiunilor realizate asupra datelor; - subprogramele de tip funcţie şi procedurǎ, care, pe baza unor date de intrare, furnizeazǎ

unu sau mai multe rezultate de ieşire; - programul, reprezentând construcţia sintacticǎ de nivel superior, care poate face obiectul

prelucrǎrii şi execuţiei pe un sistem de calcul. În termenii folosiţi anterior, construcţiile sintactice enumerate aparţin alfabetului neterminal,

iar, dintre ele, programul reprezintǎ axioma gramaticii limbajului Pascal. Regulile de sintaxǎ ce formeazǎ mulţimea producţiilor pot fi specificate în mai multe moduri,

dintre care se remarcǎ: notaţia formalǎ BNF (Backus Normal Form) şi diagramele de sintaxǎ. În notaţia BNF, regulile sintactice (metadefiniţiile) au forma: <parte-stânga> ::= parte-dreapta unde: <parte-stânga> : desemneazǎ metavariabila (variabila neterminalǎ) ce se defineşte; ::= : metasimbol având sensul de "este prin definiţie"; parte-dreapta : definiţia metavariabilei. În cadrul definiţiei (parte-dreapta) se întâlnesc urmǎtoarele elemente: <metavariabila>: categorie sintacticǎ folositǎ în definirea altei categorii sintactice; metaconstanta : element al alfabetului terminal; | : separǎ alternativele în definiţie; [ ] : indicǎ o construcţie opţionalǎ; { } : indicǎ posibilitatea repetǎrii construcţiei. Alternativele se constituie prin juxtapunerea de metavariabile şi/sau metaconstante. O diagramǎ de sintaxǎ este un graf orientat având o singurǎ intrare şi o singurǎ ieşire. Orice

drum posibil în graf, începând cu intrarea şi terminând cu ieşirea, defineşte o construcţie sintacticǎ corectǎ. Ca noduri ale grafului se folosesc urmǎtoarele figuri geometrice, pentru care se precizeazǎ şi condiţiile de utilizare în prezentarea limbajului Pascal:

încadreazǎ simboluri speciale;

încadreazǎ cuvinte rezervate;

încadreazǎ elementele limbajului care se definesc prin alte diagrame de sintaxǎ. În sens restrâns, diagramele de sintaxǎ şi meta-definiţiile ar trebui asociate numai

construcţiilor sintactice propriu-zise (neterminale). Utilizatorul este implicat în alcǎtuirea unora din clasele de componenţe ale lexicului, se vor folosi, şi în cazul acestora, diagrame de sintaxǎ şi/sau metadefiniţii.

Pentru a ilustra comparativ cele douǎ moduri de reprezentare a regulilor sintactice, se prezintǎ în continuare metadefiniţiile şi diagramele de sintaxǎ pentru literǎ, cifrǎ (zecimalǎ) şi cifrǎ hexazecimalǎ.

268

Construcţiile sintactice enumerate aparţin alfabetului neterminal, iar dintre ele programul reprezintǎ axioma gramaticii limbajului Pascal.

Page 4: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

269

Lexicul limbajului Pascal se construieşte pe baza unui set de caractere format din urmǎtoarele submulţimi de caractere ASCII:

- litere mari şi mici ale alfabetului englez; (8.1.)

- cifrele sistemului zecimal; (8.2.)

- cifrele sistemului hexazecimal; (8.3.) - caracterul spaţiu (#32) şi toate caracterele de control (#0..#31); - o serie de caractere speciale. Dupǎ modul lor de construire, componentele lexicului pot fi grupate în:

- entitǎţi lexicale prestabilite, în care se înscriu simbolurile speciale şi cuvintele rezervate; - entitǎţi realizate de utilizator, în care se înscriu identificatorii, etichetele, numerele şi

constantele de tip şir. Entitǎţile prestabilite se folosesc conform destinaţiei impuse de definitorul limbajului, pentru

utilizator fiind suficientǎ specificarea mulţimii acestora (de exemplu, prin enumerare) şi a modului de utilizare.

Sunt simboluri speciale în Pascal urmǎtoarele caractere ASCII: + - * / = < > [ ] . , ( ) ; : ^ ' _ @ { } & $ # etc. şi urmǎtoarele perechi de caractere: <= >= := .. (* *) (. .) <>.

Unele dintre simbolurile speciale servesc ca operatori în expresii. Cuvintele rezervate ale limbajului Pascal sunt prezentate în tabelul 8.1. Scrierea cuvintelor

rezervate cu majuscule este numai o convenţie de prezentare, în programe fiind permisǎ folosirea atât a literelor mari cât şi a celor mici, cu aceeaşi semnificaţie. Pentru celelalte categorii de elemente ale lexicului este necesarǎ aplicarea unor reguli de construire, abordate în continuare.

Tabelul 8.1. Lista cuvintelor rezervate

ABSOLUTE AND ARRAY BEGIN CASE CONST DIV DO

DOWNTO ELSE END EXTERNAL FILE FOR FORWARD FUNCTION

GOTO IF IMPLEMENTATION IN INLINE INTERFACE INTERRUPT LABEL

MOD NIL NOT OF OR PACKED PROCEDUREPROGRAM

SHR RECORD REPEAT SET SHL STRING THEN TO

TYPE UNIT UNTIL USES VAR WHILE WITH XOR

Identificatorii sunt folosiţi în Pascal pentru a desemna date, proceduri, funcţii etc. (8.4.).

(8.4.) În notaţia BNF, regula de construire a unui identificator este urmǎtoarea: <identificator>::=<literǎ>|_{<literǎ>|<cifrǎ>|_} Un identificator trebuie sǎ înceapǎ cu o literǎ sau cu caracterul _ (liniuţa de subliniere)

urmatǎ, eventual, de litere, cifre zecimale şi liniuţe de subliniere. Un identificator poate avea orice lungime, dar numai primele 63 de caractere sunt semnificative.

Page 5: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

Identificatorii pot fi scrişi atât cu litere mari, cât şi cu litere mici. Caracterul liniuţă de subliniere (#95) folosit în construirea identificatorilor este, formal, tratat ca literǎ.

Etichetele sunt secvenţe de cifre zecimale din intervalul 0 la 9999 (8.6.), care asociate unor instructiuni permit transferul cǎtre acestea prin instrucţiuni de salt necondiţionat (GOTO). Ca extensie faţǎ de varianta standard, în Turbo Pascal este permisǎ folosirea unor identificatori cu rol de etichetǎ. În condiţiile programǎrii structurate folosirea instrucţiunii GOTO (şi a etichetelor) este foarte redusǎ şi se realizeazǎ în condiţii restrictive, cu respectarea riguroasǎ a cerinţelor de construire a structurilor fundamentale de control.

Numerele denumite în prezentarea unor limbaje de programare şi literali numerici, sunt constante de tip întreg şi real (8.5.- 8.11.).

(8.5) (8.6)

(8.7) (8.8)

(8.9) (8.10)

(8.11)

Numerele întregi se pot scrie în baza 10 sau în baza 16, precedate, eventual, de semn. Cifre le hexazecimale au ca prefix caracterul $.

Numerele reale se pot scrie în forma uzualǎ din matematicǎ, cu parte întreagǎ şi fracţionarǎ, separate prin caracterul "." şi, eventual, precedate de semn, sau în forma ştiinţificǎ (cu exponent), adicǎ urmate de E sau e şi de un întreg reprezentând o putere a lui 10. Numerele cu parte fracţionarǎ sau exponent corespund constantelor (literalilor) reale, iar celelalte numere zecimale, precum şi numerele hexazecimale, corespund constantelor (literalilor) întregi. Şirurile de caractere (literali nenumerici) sunt - în sens restrâns - secvenţe de zero sau mai multe caractere ASCII afişabile, incluse între apostrofuri (8.12 – 8.13).

(8.12) (8.13)

Şirul format din zero caractere, deci cu nimic între apostrofuri, se numeste şir nul. Pentru a include un apostrof în cadrul şirului se folosesc douǎ apostrofuri consecutive. Lungimea unui şir (L) va fi datǎ de numǎrul efectiv de caractere incluse între apostrofuri.

Structura generalǎ a programelor Pascal.

270

Pentru evidenţierea relaţiilor între diverse construcţii sintactice, în cele ce urmeazǎ se face o abordare descendentǎ, pornind de la axioma gramaticii limbajului. În forma sa cea mai generalǎ, structura unui program Pascal poate fi descrisǎ prin diagramele de sintaxǎ 8.14 şi 8.15:

Page 6: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

271

(8.14)

(8.15) Antetul programului, atunci când este prezent, are rol pur informativ. Totodatǎ, posibilitatea

definirii unor eventuali parametri este menţionatǎ numai pentru asigurarea similitudinii cu Pascal Standard, fǎrǎ a avea nici o semnificaţie în Turbo Pascal. Clauza USES, cu caracter opţional, permite specificarea unitǎţilor (UNIT-urilor) folosite în programul respectiv.

Principala componentǎ a unui program este blocul, care reprezintǎ corpul acestuia. Blocul (diagramele 8.16 – 8.27) este format din declaraţii (instrucţiuni neexecutabile) şi instrucţiuni (instrucţiuni executabile).

(8.16) (8.18)

(8.17) (8.19)

(8.20) (8.21)

(8.22) (8.23)

(8.24) (8.25)

(8.26) (8.27)

Partea de declaratii a blocului este subîmpǎrţitǎ în: - partea de declarare a etichetelor (LABEL), în care se declarǎ etichetele folosite în partea de

instrucţiuni a blocului; - partea de declarare a tipurilor (TYPE), care conţine definirea unor tipuri de date pe baza

altor tipuri definite anterior, standard sau ale utilizatorului; - partea de declarare a constantelor (CONST), care cuprinde declararea constantelor

simbolice (identificatori asociaţi unor constante) şi a constantelor cu tip (variabile iniţializate în momentul compilǎrii);

- partea de declarare a variabilelor (VAR), care conţine definirea tuturor variabilelor specifice blocului respectiv;

- partea de declarare a procedurilor şi/sau funcţiilor. Procedurile şi funcţiile sunt subprograme interne sau externe. Constructiv, indiferent de tipul

sǎu, un subprogram este format din un antet şi un corp (8.23 şi 8.24). Antetul unui subprogram de tip PROCEDURE precizeazǎ numele (identificatorul) acestuia şi

lista parametrilor formali, care în momentul apelǎrii vor fi puşi în corespondenţǎ cu parametrii actuali, asigurând schimbul de informaţii în contextul de apelare. Parametrii sunt de intrare şi/sau de

Page 7: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

ieşire, ceea ce înseamnǎ cǎ un subprogram PROCEDURE returneazǎ zero, unu sau mai multe rezultate. Un subprogram de tip FUNCTION returneazǎ (cel puţin) un rezultat asociat cu numele funcţiei, iar în antetul sǎu se va include şi o declaraţie de tip corespunzând acestui rezultat (8.26). Corpul procedurilor interne conţine drept principalǎ componentǎ blocul, care are aceeaşi structurǎ ca în cazul programului. Partea de instrucţiuni (8.27) este formatǎ din instrucţiunile executabile prin care se codificǎ algoritmul problemei. Termenul instrucţiune desemneazǎ generic tipurile de instrucţiuni pe care le posedǎ limbajul. Însǎşi construcţia BEGIN...END reprezintǎ o instrucţiune compusǎ (care poate sǎ fie vidǎ).

Analizând diagramele de sintaxǎ rezultă urmǎtoarele aspecte practice: • partea de declaraţii poate sǎ lipseascǎ (rezultǎ cǎ în partea de instrucţiuni nu se referǎ date

declarate în program); • partea de declaraţii, atunci când este prezentǎ, o precede obligatoriu pe cea de instrucţiuni; • ordinea diverselor componenete ale pǎrţii de declaraţii este oarecare, cu condiţia ca orice

referire a unui obiect sǎ fie precedatǎ de definirea sa; • procedurile (funcţiile) interne sunt opţionale, iar când sunt prezente se definesc anterior

pǎrţii de instrucţiuni care le referǎ; • pot fi realizate subprograme imbricate, adicǎ definirea de proceduri/funcţii în cadrul altor

proceduri/funcţii. Schema bloc a unui program Pascal, construitǎ pe baza diagramelor de sintaxǎ definite

anterior cuprinde antetul, zona de declaraţii şi corpul programului propriu-zis. Programul se prezintǎ ca o succesiune de linii, fiecare de maximum 127 de caractere. Declaraţiile si instructiunile programului se separǎ între ele prin simbolul “;”. Se recomandǎ ca fiecare linie sǎ conţinǎ o singurǎ declaraţie sau instrucţiune, dar este permisǎ

scrierea mai multor asemenea construcţii pe aceeasi linie sau continuarea lor pe mai multe linii. Comentariul este o succesiune de caractere inclusǎ între acolade { } sau între perechile de

caractere speciale (* şi *) folosite ca delimitatori. Delimitatorii folosiţi pentru comentarii pot servi şi la introducerea unor directive de compilare, ce conţin dupǎ delimitatorul stânga caracterul $, urmat de codul unei directive.

8.2. TIPURI STATICE DE DATE ŞI EXPRESII

Limbajul Pascal oferǎ posibilitǎti deosebit de elastice în declararea şi utilizarea tipurilor de

date. El acceptǎ tipuri de date simple şi structurate, statice şi dinamice. În plus, pe lângǎ tipurile standard, programatorii pot sǎ-şi defineascǎ propriile tipuri de date. Prin tip de date se înţelege mulţimea valorilor pe care le poate lua data împreunǎ cu mulţimea operatiilor care se aplicǎ asupra acestora. O clasificare a tipurilor statice de date în Turbo Pascal este prezentatǎ în figura 8.1.

Figura 8.1. Tipuri statice de date

272

Tipurile ordinale (salare) reprezintǎ mulţimi finite şi ordonate de valori discrete. Unui element i se asociazǎ un numǎr de ordine în cadrul mulţimii, obţinut implicit sau prin funcţia ORD.

Page 8: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

273

Pot fi referite elementele succesor - predecesor ale unui element, prin funcţiile SUCC şi PRED. Valoarea unei date ordinale se reprezintǎ intern prin ordinul ei. Elementele pot fi puse în relaţie (<, <=, =, >, >=, <>), rezultatul fiind evaluat în funcţie de numǎrul de ordine.

Dupǎ modul de specificare a valorilor pe care le pot avea, datele de tip ordinal pot fi subîmpǎrţite în date de tip domeniu (subdomeniu) şi date de tip enumerativ (fig. 8.2). Pentru tipul domeniu (subdomeniu), mulţimea valorilor discrete se precizeazǎ printr-un interval închis (8.28).

Marginile intervalului trebuie sǎ îndeplineascǎ condiţia: ORD(limita_inferioarǎ)<=ORD(limita_superioarǎ).

Figura 8.2. Tipuri ordinale de date

(8.28) Tipurile standard întregi au domeniile implicite prezentate în tabelul 8.2. De exemplu, prin tipul standard INTEGER se desemneazǎ mulţimea numerelor întregi din intervalul -32768..32767. Tipul standard CHAR are domeniul implicit #0..#255 (mulţimea caracterelor setului extins ASCII). Utilizatorul poate sǎ-şi defineascǎ propriile tipuri, prin subdomenii incluse în cele predefinite (standard).

Tabelul 8.2.

Tipuri întregi de date

Pentru tipul enumerativ, multimea de valori discrete se precizeazǎ prin liste ordonate (8.29).

(8.29) Tipul standard BOOLEAN are lista de valori implicitǎ (FALSE,TRUE). Utilizatorul poate sǎ-şi defineascǎ propriile tipuri enumerative. Elementelor datelor de tip enumerativ li se asociazǎ numere de ordine, prima valoare din listǎ având ordinalitatea zero.

Page 9: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

Datele de tip real au valori în mulţimea R. În funcţie de lungimea internǎ, se disting mai multe tipuri reale care au precizii diferite (tabelul 8.3). Datele de tip real nu sunt ordinale (între oricare douǎ valori reale existǎ o infinitate de valori).

Datele de tip structurat sunt mulţimi (colecţii) de date de tipuri simple sau structurate, constituite dupǎ anumite reguli bine stabilite. Nici o datǎ structuratǎ nu poate ocupa în memorie mai mult de 65520 octeţi. Tipul datelor statice poate fi definit ca în diagrama 8.30 în care identificator_tip desemneazǎ un tip definit de utilizator. Tipurile definite conform diagramelor 8.30 şi 8.31 se regǎsesc în declararea variabilelor şi constantelor.

Tabelul 8.3.

Tipuri reale de date

(8.30)

(8.31)

8.2.1. Clasificarea tipurilor statice de date.Variabile şi constante

274

Page 10: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

275

Din punct de vedere al posibilitǎtii de modificare a valorii în faza de execuţie a programului, se disting:

date variabile, care îşi pot modifica valoarea pe parcursul execuţiei programului;

date constante, predefinite la momentul scrierii programului şi ale cǎror valori sunt generate în faza de compilare.

Toate variabilele cu care se lucreazǎ într-un program Pascal trebuie declarate în secţiunea VAR (unele şi în CONST) a pǎrţii de declaraţii a programului.

Într-o declaraţie (8.32) pot fi specificate mai multe variabile.

(8.32) Douǎ sau mai multe variabile pot fi definite la aceeaşi adresǎ de memorie, folosindu-se clauza ABSOLUTE (8.33). Variabilele se numesc echivalente (sau echivalate).

(8.33) Datele constante pot fi literali care se autoindentificǎ prin valoare, sau constante simbolice, referite prin identificatori, cǎrora li se asociazǎ declaraţii în secţiunea CONST a pǎrţii de declaraţii a programului (8.34 şi 8.35). Expresie_de_constante este evaluatǎ în momentul compilarii, având ca operanzi numai literali sau constante simbolice. Operatorii folosiţi în expresii sunt cei specifici tipului de datǎ pentru care se defineşte constanta. În expresiile de constante pot fi folosite şi urmǎtoarele funcţii: ABS, CHR, HI, LENGTH, LO, ODD, ORD, PRED, ROUND, SIZEOF, SUCC, SWAP, TRUNC.

(8.34)

(8.35) Limbajul Pascal defineşte ca fiind constante şi acele variabile iniţializate în momentul compilǎrii, numindu-se în limbaj, constante cu tip sau variabile initializate (8.36).

(8.36) În multe construcţii sintactice se cere respectarea unor clase de compatibilitǎţi de tip. Prin

noţiunea de variabile de acelaşi tip se va întelege: variabile de acelaşi tip utilizator; variabile simple de acelaşi tip standard; variabile definite în aceiaşi descriere.

Page 11: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

Tipurile întregi de date sunt: BYTE, WORD, SHORTINT, INTEGER, LONGINT. Ele se referǎ la întregi farǎ semn (BYTE, WORD) şi la întregi cu semn (SHORTINT, INTEGER, LONGINT). În operaţii, toate tipurile întregi sunt compatibile între ele. Operatorii aritmetici sunt:

+ adunare (sau operator unar); - scǎdere (sau operator unar); * înmulţire; DIV împǎrţire întreagǎ (se obţine câtul); MOD împǎrţire întreagǎ (se obţine restul). Datele de tip întreg pot fi puse în relaţie (<, <=, =, >, >=, <>), rezultatul logic fiind în

concordanţǎ cu ordinea lor (ca tip ordinal) sau cu valoarea lor în Z. Funcţiile specifice tipurilor ordinale (ORD, PRED, SUCC) se aplicǎ şi tipurilor întregi, cu menţiunea cǎ numǎrul de ordine a datei coincide cu valoarea sa din Z.

În Turbo Pascal existǎ douǎ constante predefinite, având identificatorii MaxInt (tip INTEGER) şi MaxLongint (tip LONGINT) care au valoarea egalǎ cu maximul din valorile domeniilor acestor tipuri (32767, respectiv 2147483647).

Tipul BOOLEAN este ordinal, enumerativ: (FALSE, TRUE). Asupra datelor booleene se pot aplica funcţiile specifice tipului ordinal (ORD, PRED, SUCC).

O datǎ de tip BOOLEAN se reprezintǎ în memorie pe un octet, în care se memoreazǎ valorile ordinelor elementelor: 0 (pentru FALSE), 1 (pentru TRUE).

Operatorii logici sunt: NOT (nu); AND (si); OR (sau); XOR (sau exclusiv). Tipul caracter (CHAR) este ordinal, subdomeniul #0..#255. Mulţimea valorilor tipului

caracter este formatǎ din caracterele setului extins ASCII (256 caractere). O datǎ de tip CHAR ocupǎ în memorie un octet, în care se memoreazǎ valori binare interne din intervalul 0..255. Literalii de tip CHAR pot fi scrişi în urmǎtoarele moduri (8.37):

a) Un caracter imprimabil cuprins între apostrofuri; b) Un întreg din domeniul 0..255, precedat de caracterul #; c) Un caracter imprimabil precedat de ^. Prin exprimarea literalilor CHAR sub forma ^x se

pot preciza uşor codurile de control al transmisiei şi imprimǎrii (caractere neimprimabile), din intervalul de valori #0..#31.

(8.37) Asupra datelor de tip caracter se poate realiza operaţia de concatenare (+), rezultatul fiind de

tip STRING. Acelaşi efect se poate obţine utilizând funcţia CONCAT. Asupra datelor de tip CHAR se pot aplica funcţiile specifice tipurilor ordinale: ORD, PRED, SUCC.

Datele de tip CHAR pot fi puse în relaţie (<, <=, =, >, >=, <>), rezultatul logic fiind în concordantǎ cu ordinalitatea lor, care se memoreazǎ intern. Funcţiile ORD şi CHR sunt inverse.

276

Tipul ordinal enumerativ se defineşte ca o listǎ ordonatǎ de identificatori ai utilizatorului (8.38). Valorilor din lista ordonatǎ care precizeazǎ tipul enumerativ li se asociazǎ numere de ordine în cadrul acesteia, începând de la zero. Un identificator precizat într-o listǎ nu poate fi prezent si într-o altǎ listǎ. Dacǎ numǎrul elementelor listei este mai mic sau egal cu 256, variabilele de tip enumerativ se reprezintǎ pe un octet. În caz contrar, ele se reprezintǎ pe un cuvânt. Intern este memorat numǎrul de ordine a valorii. Din aceastǎ cauzǎ, numǎrul elementelor listei enumerative

Page 12: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

277

este maxim 65536. Referirea unui element se face prin intermediul unui identificator de tip şi nu al unui identificator de variabilǎ. Asupra datelor de tip enumerativ se pot aplica funcţiile specifice tipurilor ordinale: ORD, PRED, SUCC.

(8.38) Datele de tip enumerativ pot fi puse în relaţie (<, <=, =, >, >=, <>), rezultatul logic fiind în

concordanţǎ cu ordinea valorii lor. Datele de tip enumerativ se folosesc în urmǎtoarele situaţii: • în operaţia de atribuire: unei variabile de tip enumerativ i se poate atribui o valoare definitǎ în lista tipului respectiv (şi numai în aceea); • în declararea dimensiunilor masivelor şi în expresiile indiceale pentru referirea elementelor

acestora; • ca variabile de control în instrucţiunea FOR. Tipul ordinal subdomeniu se mai numeşte tip interval şi se defineşte ca submulţime a unui

tip ordinal ("tip pǎrinte"), prin precizarea intervalului închis de valori. Toate caracteristicile tipului pǎrinte se regǎsesc în tipul subdomeniu, singura deosebire dintre ele referindu-se la mulţimea valorilor pe care le pot lua. Literalii, constantele, funcţiile şi operaţiile definite pentru datele de tip subdomeniu sunt similare celor specifice tipului pǎrinte. Funcţia ORD aplicatǎ unui element dintr-un subdomeniu returneazǎ numǎrul de ordine din domeniul pǎrinte. Datele de tip subdomeniu se memoreazǎ identic cu cele din tipul pǎrinte.

Tipurile reale sunt: REAL, SINGLE, DOUBLE, EXTENDED, COMP. Datele reale sunt memorate intern în virgulǎ mobilǎ. În ISO Standard Pascal este inclus doar tipul REAL, celelalte tipuri sunt cuprinse în convenţia IEEE (Institute for Electrical and Electronics Engineers). Tipul COMP desemneazǎ o datǎ realǎ particularǎ, având numai valori întregi. În operatii ea intrǎ ca o datǎ realǎ, cu partea zecimalǎ egalǎ cu zero. În operaţii, toate tipurile reale sunt compatibile între ele. Operatorii aritmetici sunt: + adunare (sau operator unar), - scǎdere (sau operator unar), * înmulţire şi / împǎrţire realǎ. Datele de tip real pot fi puse în relaţie (<, <=, =, >, >=, <>), rezultatul logic fiind în concordanţǎ cu valoarea lor în mulţimea R.

Tipul şir de caractere este implementat tipul structurat şir (STRING), care defineşte şiruri de caractere ASCII, de lungime variabilǎ (8.39). Lungimea maximǎ a şirurilor este 255 caractere, iar lungimea minimǎ este zero, pentru şirul null (vid).

(8.39)

Din analiza diagramei se observǎ cǎ în definirea literalilor de tip STRING se pot succede şiruri scrise în cele trei moduri corespunzătoare tipului caracter.

Tipul şir se declarǎ conform diagramei 8.40. Dacǎ la declarare nu se specificǎ lungimea maximǎ, se considerǎ, implicit, 255 caractere. Lungimea efectivǎ a şirului este numǎrul de caractere pe care îl are valoarea memoratǎ. Lungimea maximǎ a şirului este numǎrul de caractere specificat în descrierea datelor STRING. Lungimea fizicǎ a zonei ocupate de şir este egalǎ cu lungimea maximǎ plus unu, deoarece un octet este rezervat pentru memorarea lungimii efective.

Şirurile pot fi referite în totalitatea lor, prin numele variabilei STRING. Pot fi, de asemenea, referite caractere din şir, utilizând construcţia din diagrama 8.41, la care elementul referit este de tip

Page 13: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

CHAR. Se poate referi şi octetul care memoreazǎ lungimea, prin numǎrul de octet zero. Cu toate cǎ octetul zero memoreazǎ întregi din domeniul 0..255, el este tot de tip CHAR.

(8.40)

(8.41) Cu datele de tip STRING poate fi realizatǎ operaţia de concatenare (+). Acelaşi efect se obtine utilizând funcţia CONCAT. Datele de tip STRING pot fi puse în

relatie (<, <=, =, >, >=, <> ). Compararea se face caracter cu caracter, de la stânga la dreapta (lexicografic), terminându-se fie la întâlnirea primei perechi de caractere neegale, fie dupǎ un numǎr de comparǎri egal cu minimul dintre lungimile şirurilor.

Tipul masiv este structurat şi desemneazǎ o mulţime finitǎ de elemente omogene constituitǎ ca un tablou cu una, douǎ sau mai multe dimensiuni (8.42). Mulţimea are un singur identificator şi oferǎ posibilitatea referirii elementelor în acces direct prin poziţie, determinatǎ printr-un numǎr de expresii indiceale corespunzând dimensiunilor masivului.

(8.42) Tip_dimensiune este ordinal (mai puţin LONGINT) şi precizeazǎ, pe de o parte, numǎrul de

elemente de pe fiecare dimensiune, care se rezervǎ în momentul compilǎrii, iar pe de altǎ parte, tipul expresiei indiceale care se poate utiliza în referirea elementelor masivului.

Pot fi declarate oricâte dimensiuni pentru masiv, dar zona de memorie rezervatǎ pentru el nu trebuie sǎ depǎseascǎ 65520 octeţi. Masivele se memoreazǎ cu liniarizare în ordine lexicograficǎ (de exemplu, la matrice, în ordinea liniilor). Tip_element este orice tip de date, mai puţin tipul fişier.

Se pot declara constante de tip ARRAY (8.43 şi 8.44). Valorile iniţiale din constantele cu tip ARRAY se precizeazǎ în ordinea linializǎrii masivelor în memorie ("pe linii"), construindu-se entitǎţi cuprinse între paranteze pentru fiecare dimensiune, mai puţin ultima.

(8.43)

Referirea elementelor unui masiv se face prin variabile indexate (8.45 şi 8.46). Expresia indicealǎ trebuie sǎ aibǎ tipul dimensiunii respective, prezent la declararea masivului. Pe baza unei funcţii rang, specificǎ liniarizǎrii, compilatorul genereazǎ calculul adreselor elementelor referite. Este posibilǎ adresarea prin multiindice, echivalentǎ cu adresarea prin multiexpresii într-un indice.

278

Page 14: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

279

(8.44)

(8.45)

(8.46) Observaţie: Limbajul nu are incluse operaţii cu masive. Se pot realiza operaţii cu elemente ale

masivelor, operaţii care sunt caracteristice tipului acestor elemente. Tipul structurat mulţime (SET) desemneazǎ o mulţime - în sens matematic - de elemente de

acelaşi tip şi operaţii specifice de lucru pe mulţimi (intersecţie, reuniune, incluziune etc.). Mulţimea poate avea maxim 256 elemente dintr-un tip "pǎrinte" ordinal, care la rândul sǎu, nu poate avea mai mult de 256 elemente. Declararea tipului SET se face conform diagramelor 8.47 şi 8.48.

(8.47)

(8.48)

Literalii de tip SET se declarǎ conform diagramei 8.49, unde element este un literal (sau subdomeniu de literali) din tipul de bazǎ (8.50).

(8.49)

(8.50) Reprezentarea internǎ a datelor de tip SET are la bazǎ urmǎtorul mecanism: se rezervǎ un

numǎr de biţi (maxim 256) egal cu numǎrul de elemente ale tipului "pǎrinte". Biţii corespunzǎtori obiectelor din tipul pǎrinte, prezente în SET, sunt puşi pe valoarea unu, ceilalţi pe valoarea zero.

Page 15: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

Operaţiile şi relaţiile se aplicǎ mulţimilor compatibile între ele (care au acelaşi tip pǎrinte). Operatorii care se aplicǎ datelor de tip SET sunt:

* Intersecţia (rezultǎ o mulţime formatǎ din elementele comune celor douǎ mulţimi). Fizic se realizeazǎ funcţia SI între biţii valorilor interne ale celor douǎ variabile.

+ Reuniunea (rezultǎ o mulţime formatǎ din elementele celor douǎ mulţimi). Fizic se realizeazǎ funcţia SAU între biţii valorilor interne ale celor douǎ variabile.

- Diferenţa (A-B: rezultǎ o mulţime formatǎ din elemente care aparţin mulţimii A şi nu aparţin mulţimii B). Fizic se realizeazǎ funcţia A SI NOT(B) între biţii valorilor interne ale celor douǎ variabile.

Mulţimile pot fi puse în "relaţie", dupǎ urmǎtoarele reguli: A <= B: valoarea TRUE, dacǎ toate elementele mulţimii A sunt în mulţimea B - incluziune A

în B (AÎB); A >= B: valoarea TRUE, dacǎ toate elementele mulţimii B sunt în mulţimea A - incluziune B

în A (BÎA); A = B: valoarea TRUE dacǎ cele douǎ mulţimi sunt identice (A<=B şi A>=B) - egalitate; A <> B: valoarea TRUE dacǎ existǎ cel puţin un element care aparţine numai unei mulţimi -

neegalitate. Existǎ, de asemenea, operatorul IN, care se aplicǎ între un element e şi o mulţime A: e IN A.

Expresia are valoarea TRUE dacǎ elementul e se regǎseşte în mulţimea A - apartenenţǎ (eÎA). Atribuirea, operaţiile şi relaţiile pe mulţimi au la bazǎ testarea şi/sau poziţionarea biţilor din reprezentarea internǎ a datelor de tip SET.

Tipul articol (RECORD) desemneazǎ o structurǎ de date staticǎ, eterogenǎ, cu acces direct, între componentele cǎreia existǎ o relaţie de ordine ierarhicǎ. Articolul poate fi reprezentat sub formǎ de arbore, ale cǎrui noduri sunt asociate componentelor structurii. Componentele de pe ultimul nivel sunt scalare şi se numesc date elementare sau câmpuri. Datele de pe celelalte niveluri, numite de grup, se constituie prin agregarea datelor de pe nivelurile inferioare. Data de grup de cel mai înalt nivel (rǎdǎcina arborelui) corespunde articolului în ansamblu. Conceptual, datele de grup de pe diverse niveluri au aceleaşi proprietǎţi ca şi articolul, ceea ce permite ca aceastǎ structurǎ sǎ fie construitǎ recursiv, prin descompunerea în structuri cu aceleaşi proprietǎţi (figura 8.3).

Posibilitatea construirii recursive se remarcǎ în figura 8.3.b, unde data de grup DATA_NASTERII este formal echivalentǎ cu articolul DATA.

Figura 8.3. Exemple de structuri de articole

Tipul articol se declarǎ conform diagramei 8.51, iar variabilele de acest tip conform diagramei 8.52. Tip este orice tip de date PASCAL, mai puţin tipul fişier. În cazul componentelor care sunt la rândul lor structuri de date (RECORD, SET, STRING, ARRAY) apar aspecte specifice în rezervarea zonelor de memorie şi/sau în referirea lor. Tipul articol poate fi definit şi ca structurǎ vidǎ. Câmpurile care se succed imediat şi sunt de acelaşi tip pot fi declarate ca liste.

280

Page 16: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

281

(8.51)

(8.52)

Din punct de vedere practic, utilizarea tipului articol este strâns legatǎ de prelucrarea fişierelor binare. În lucrul cu variabilele de tip articol se recomandǎ declararea identificatorului de tip în secţiunea TYPE. În acest mod, identificatorul de tip articol poate fi folosit în definirea mai multor variabile, inclusiv a celor asociate fişierelor cu tip. În procesul de descriere a unui articol, arborele se parcurge în preordine (de la rǎdǎcinǎ spre extremitǎţi şi de la stânga la dreapta).

Variabilele de tip articol se reprezintǎ intern ca succesiuni de câmpuri elementare, cu reprezentarea internǎ şi lungimea fizicǎ specifice tipurilor lor. Datele STRING se memoreazǎ pe lungimea fizicǎ (octet de lungime plus lungime maximǎ), componentele SET se reprezintǎ pe maxim 32 octeţi (depinzând de numǎrul de elemente ale mulţimii) iar pentru componentele ARRAY se rezervǎ numǎrul de octeţi necesari fiecǎrui element al masivului. Lungimea zonei de memorie rezervatǎ pentru variabila de tip articol rezultǎ din însumarea lungimilor câmpurilor. Aceasta nu poate depǎşi 65520 octeţi (ca orice variabilǎ de tip structurat). Pentru structura unui articol îşi dovedeste utilitatea funcţia SizeOf, din unitatea SYSTEM, care asigurǎ determinarea lungimii zonei de memorie asociate unei variabile sau unui tip de date.

Din punct de vedere fizic, identificatorii câmpurilor din descrierea articolului reprezintǎ deplasǎri fatǎ de începutul acestuia. Adresa fizicǎ a unui câmp rezultǎ din însumarea adresei articolului cu deplasarea sa. Structura arborescentǎ a articolelor poate fi exprimatǎ sugestiv şi prin machete, care evidenţiazǎ componentele, natura, lungimea declaratǎ şi lungimea fizicǎ ale acestora.

Datele de tip articol pot fi referite în douǎ moduri: global sau pe componente. Referirea globalǎ este permisǎ numai în operaţia de atribuire, cu condiţia ca ambele variabile (sursǎ şi destinaţie) sǎ fie articole de acelaşi tip. În programele de lucru cu fişiere cu tip, variabilele articol sunt referite global, ca parametri în apelul procedurilor de I/E. Referirea pe componente (prin numele lor) este o reflectare a faptului cǎ articolul este o structurǎ cu acces direct. Referirea unor componente de tip articol din structura altui articol este posibilǎ numai în operaţia de atribuire, în condiţiile precizate anterior la referirea globalǎ. În cele ce urmeazǎ se are în vedere numai referirea componentelor de tip datǎ elementarǎ, situate pe ultimul nivel al structurii. Existǎ douǎ variante de referire a componentelor articolelor: referirea prin calificare şi referirea fǎrǎ calificare.

În referirea prin calificare asigurarea identificǎrii unice a câmpurilor se realizeazǎ prin asocierea numelui acestora cu numele articolului care le conţine (8.53). Construcţia rǎmâne la aceastǎ formǎ dacă structura are numai douǎ niveluri: articolul şi câmpurile elementare ale acestuia.

În articolele cu structurǎ recursivǎ se realizeazǎ calificarea progresivǎ cu articolele de pe nivelurile superioare, primul calificator fiind numele articolului rǎdǎcinǎ. În lanţul de calificǎri, numele articolului rǎdǎcinǎ este nume de variabilǎ, celelalte fiind nume de câmpuri ale articolului. Dacǎ anumite componente sunt structuri de date de alte tipuri (de exemplu, masive sau şiruri de caractere), în referirea elementelor lor se aplicǎ, pe lângǎ calificare, regulile specifice acestor structuri.

(8.53) Pentru referirea fǎrǎ calificare se foloseste instrucţiunea WITH, care are la bazǎ un procedeu

similar scoaterii factorului comun din matematicǎ. În cadrul ei, câmpurile unui articol pot fi referite

Page 17: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

numai prin identificatorii lor, fǎrǎ a fi descrisǎ explicit întreaga structurǎ arborescentǎ de care aparţin, referirea având efect în instrucţiunea care aparţine structurii WITH. Sintaxa instrucţiunii WITH este precizatǎ în diagrama 8.54. Pot fi folosite structuri WITH imbricate, cu condiţia evitǎrii ambiguitǎţilor: se includ în WITH toate nivelurile superioare de arborescenţǎ, începând cu identificatorul de variabilǎ al articolului şi continuând cu identificatorii de câmpuri de tip grup. Pe baza declarǎrilor din WITH, compilatorul "reface" adresarea fizicǎ a câmpurilor.

(8.54) Forma WITH r1, r2, ..., rm DO instrucţiune poate fi scrisǎ astfel:

WITH r1 DO WITH r2 DO ............... WITH rm DO instructiune; Referirea câmpurilor articolelor fǎrǎ calificare este preferabilǎ atunci când se realizeazǎ

operatii asupra mai multor câmpuri ale aceleiasi variabile articol. Ea poate fi aplicatǎ întregului program Pascal, dacǎ instructiunea WITH este plasatǎ la începutul pǎrtii executabile. Programatorul poate lucra, astfel, direct cu identificatorii câmpurilor, în întregul sǎu program, cu conditia ca identificatorii sǎ fie unici.

Limbajul PASCAL oferǎ posibilitatea lucrului cu articole care au structurǎ variabilǎ. Acestea au în componentǎ o parte fixǎ şi o parte variabilǎ. Partea variabilǎ este descrisǎ în funcţie de existenţa mai multor variante de structurǎ ale articolului. Tipul articol se declarǎ, în acest caz, conform diagramelor 8.55 şi 8.56 (care pot fi considerate generale pentru tipul articol). Descrierea pǎrţii variabile începe cu cuvântul CASE. Variantele de structurǎ se descriu prin "selecţie", pe baza valorilor unei caracteristici (selector) de tip ordinal sau pe baza valorilor unui tip ordinal.

Din studiul diagramelor 8.55 – 8.59 se desprind urmǎtoarele reguli practice: partea fixǎ, când existǎ, o precede pe cea variabilǎ; fiecare variantǎ de structurǎ se descrie între paranteze rotunde; partea variabilǎ poate avea, la rândul ei, o parte fixǎ şi o parte variabilǎ.

(8.55)

(8.56)

(8.57)

(8.58)

282

Page 18: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

283

(8.59) Câmpul selector poate fi declarat sau nu în descrierea CASE; când este declarat, se considerǎ

ca aparţinând pǎrtii fixe a articolului; când nu este declarat, selecţia variantelor de structurǎ se face dupǎ valori aparţinând mulţimii tipului ordinal specificat în CASE.

În practicǎ, câmpul selector se declarǎ în CASE când este ultimul din partea fixǎ a articolului (precede imediat partea variabilǎ). Constantele utilizate în selecţia pǎrţii variabile nu au nici o legǎturǎ cu conţinutul real al selectorului.

Din punct de vedere fizic, articolele au lungime fixǎ, egalǎ cu lungimea pǎrţii fixe (care include eventual şi lungimea câmpului selector) la care se adaugǎ lungimea maximǎ a pǎrţii variabile. Din punct de vedere fizic, existenta pǎrţii variabile într-un articol genereazǎ, la compilare, deplasǎri egale faţǎ de începutul articolului pentru toate variantele de descriere. Descrierea mai multor structuri de articole creeazǎ doar premisa prelucrǎrii diferenţiate a acestora. Este sarcina programatorului ca în partea executabilǎ a programului sǎ-şi gestioneze tipul articolului care trebuie prelucrat.

Constantele RECORD sunt cu tip şi se definesc în secţiunea CONST. În momentul compilǎrii se rezervǎ zone de memorie pentru acestea, iar câmpurile articolelor sunt iniţializate cu valorile precizate de utilizator. Declararea constantelor presupune definirea tipului articol (în secţiunea TYPE) conform diagramei 8.60.

Valoarea iniţialǎ trebuie sǎ fie de acelaşi tip cu câmpul cǎruia îi corespunde. Când articolul conţine la rândul sǎu alt articol, identificarea câmpului care se iniţializeazǎ se face pe niveluri, folosind perechi corespunzǎtoare de paranteze.

La initializarea câmpurilor unui articol cu parte variabilǎ, constanta de tip articol se asociazǎ unei singure structuri, deoarece zona de memorie rezervatǎ pentru articol este unicǎ.

(8.60) Expresii Asupra datelor pot fi aplicaţi operatori din diverse clase, rezultând construcţiile sintactice

numite expresii. Expresiile sunt alcǎtuite din operanzi şi operatori. Evaluarea expresiilor produce ca rezultat o valoare de un anumit tip. În metalimbajul BNF expresia poate fi definitǎ astfel:

<expresie>::=<operand>|<operator_unar><expresie>|<expresie><operator_binar><expresie> Prima variantǎ din definiţie corespunde celei mai simple forme de expresie, redusǎ la o

variabilǎ sau o constantǎ de un anumit tip. A doua şi a treia variantǎ, prin aplicare repetatǎ, conduc la recursivitate în construirea expresiilor.

Ordinea de aplicare a operatorilor din expresii poate fi, total sau parţial, impusǎ prin folosirea parantezelor. Acestea sunt evaluate cu prioritate, iar dacǎ sunt mai multe niveluri de paranteze, evaluarea se realizeazǎ din interior spre exterior. În absenţa parantezelor, respectiv în interiorul acestora, evaluarea se realizeazǎ în funcţie de ordinul de precedentǎ a operatorilor. Se disting cinci clase de precedentǎ, care (de la superior la inferior) sunt:

1 : operatorii unari + si -; 2 : operatorul unar NOT; 3 : *, DIV, /, MOD, AND, SHR, SHL; 4 : +, -, OR, XOR, intersecţie (*), reuniune (+), diferenţǎ (-) de mulţimi; 5 : <, <=, =, >, >=, <>, IN şi operatorii relaţionali între mulţimi. Pentru operatorii apartinând aceleiaşi clase de precedenţǎ, evaluarea se realizeazǎ de la stânga

la dreapta.

Page 19: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

Definirea expresiei, cu menţionarea explicitǎ a operatorilor, poate fi realizatǎ prin diagramele de sintaxǎ 8.61 – 8.64.

(8.61)

(8.62)

(8.63)

(8.64) În general, operatorii se aplicǎ operanzilor de acelaşi tip, cu rezultat în mulţimea tipului de

datǎ respectiv (aceste operaţii au fost prezentate la fiecare tip de date). Existǎ şi excepţii: - Expresiile aritmetice au operanzi numerici. În categoria acestora se includ datele de tip

întreg (BYTE, WORD, INTEGER, LONGINT, SHORTINT) şi cele de tip real (REAL, SINGLE, DOUBLE, EXTENDED, COMP). În general, toate tipurile numerice sunt compatibile între ele, cu unele excepţii prezentate în tabelul 8.4. Deoarece expresiile se evalueazǎ pe subexpresii definite de un operator, comutativitatea din matematicǎ nu este conservatǎ (în programare, expresia A+B+C nu este întotdeauna egalǎ cu A+C+B, depinzând de tipurile variabilelor). Operatorii *, /, +, -, pot fi aplicaţi şi în cazul când un operand este întreg iar celǎlalt real, rezultatul fiind de tip real.

Tabelul 8.4 Operatori arimetici

284

Page 20: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

285

În operaţiile de împǎrţire (/, DIV, MOD), împǎrţitorul nu poate fi zero. În evaluarea

expresiilor nu se sesizeazǎ eventuala depǎşire a domeniului de valori admise de tipul rezultatului, care, în acest caz, este imprevizibil pentru utilizator.

- Expresiile logice sunt cele care, în urma evaluǎrii, produc rezultat de tip BOOLEAN. În funcţie de operatorii utilizaţi, se disting expresii relaţionale şi expresii logice propriu-zise.

Expresiile relaţionale se construiesc cu operatorii < <= = > >= <> incluşi în clasa de precedentǎ cinci. Operanzii expresiilor (subexpresiilor) relaţionale trebuie sǎ fie compatibili.

Se considerǎ urmǎtoarele clase de compatibilitǎti: - operanzii numerici (tipurile întregi si reale); - operanzii STRING sau CHAR ; - operanzii de tip BOOLEAN ; - operanzii de tip enumerativ ; - operanzii de tip multimi compatibile (acelasi tip "pǎrinte").

Operatorii relaţionali pot fi aplicaţi şi operanzilor de tip mulţime, semnificaţia lor fiind: incluziune (<=), egalitate (=), neegalitate (<>), apartenenţǎ (IN). Rezultatul este de tip BOOLEAN (TRUE sau FALSE). Operatorii relaţionali aplicaţi mulţimilor au clasa de precedenţǎ cinci.

Expresiile logice propriu-zise au operanzi de tip logic şi se construiesc cu operatorii NOT (clasa de precedenţǎ doi), AND (clasa de precedenţǎ trei), OR si XOR (clasa de precedenţǎ patru). Rezultatul evaluǎrii este de tip BOOLEAN (TRUE sau FALSE).

În cazul în care în expresiile logice se folosesc ca operanzi expresii relaţionale, datoritǎ prioritǎţii mai mari a operatorilor logici faţǎ de cei relaţionali, este obligatoriu includerea subexpresiilor relaţionale între paranteze. Ca urmare, o expresie logicǎ de forma a>b OR c<=0 se va scrie corect astfel: (a>b) OR (c<=0), asigurându-se evaluarea prealabilǎ a subexpresiilor relaţionale şi apoi aplicarea operatorului OR.

Compilatorul foloseşte douǎ modele diferite de generare a codului maşinǎ pentru evaluarea expresiilor formate cu operatorii AND si OR. Evaluarea completǎ a expresiilor se recomandǎ în cazul în care unul sau mai mulţi operanzi sunt funcţii. Evaluarea parţialǎ a expresiilor este mai rapidǎ şi se bazeazǎ pe testarea primului operand. Dacǎ primul operand dintr-o subexpresie cu AND este FALSE, ceilalţi operanzi nu se mai evalueazǎ şi valoarea finalǎ a expresiei este FALSE. Dacǎ primul operand dintr-o subexpresie cu OR este TRUE, ceilalţi operanzi nu se mai evalueazǎ şi valoarea finalǎ a expresiei este TRUE.

- Expresii cu siruri de caractere. Operaţia care se realizeazǎ cu şiruri de caractere este concatenarea (+). Operanzii trebuie sǎ fie de tip STRING sau CHAR. Rezultatul este de tip STRING. Şirul rezultat va fi trunchiat la dreapta dacǎ are lungimea mai mare de 255 de caractere.

- Operaţii pentru prelucrare la nivel de bit. Limbajul prevede posibilitǎti de lucru la nivel de bit, prin operatorii prezentaţi în tabelul 8.5. Operanzii trebuie sǎ fie de tip întreg. Toate operaţiile se fac bit cu bit.

Tabelul 8.5. Operatorii utilizaţi în lucrul la nivel de bit

Page 21: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

Operatiile de deplasare au forma:

(8.65) Operand_1 reprezintǎ operandul care se deplaseazǎ, iar operand_2 precizeazǎ numǎrul de

poziţii binare cu care se produce deplasarea. În operaţia de deplasare participǎ toţi biţii operandului_1. Prin deplasare, atât spre dreapta cât şi spre stânga, se propagǎ zero. În reprezentarea aritmeticǎ (bitul de semn considerat ca bit de cifrǎ), deplasarea spre stânga corespunde înmulţirii cu o putere a lui doi, iar deplasarea spre dreapta corespunde împǎrţirii întregi la o putere a lui doi. O atenţie deosebitǎ trebuie acordatǎ ordinei de evaluare a expresiilor utilizate în prelucrarea la nivel de bit.

8.3. REALIZAREA STRUCTURILOR FUNDAMENTALE DE CONTROL

Limbajul Pascal este puternic orientat spre programarea structuratǎ. El este conceput astfel încât sǎ implementeze fidel conceptele proiectǎrii şi realizǎrii structurate şi modularizate a programelor.

8.3.1. Tipurile de instrucţiuni

Instrucţiunile specificǎ operaţiile (acţiunile) care se aplicǎ datelor în vederea obţinerii rezultatelor scontate prin algoritm. În programul obiect rezultat dupǎ compilare, ele se regǎsesc sub forma unor secvenţe de apeluri şi instrucţiuni cod maşinǎ. Aceeaşi instrucţiune sursǎ poate avea diverse configuraţii cod maşinǎ, depinzând de tipul operanzilor pe care îi referǎ. Instrucţiunile unui program Pascal se grupeazǎ într-un bloc BEGIN...END. Un program trebuie sǎ execute cel puţin o instrucţiune, chiar dacǎ, la limitǎ, aceasta este vidǎ. Rezultǎ deci, cǎ forma cea mai simplǎ a unui program Pascal este: BEGIN END.

Dupǎ modul de realizare a construcţiilor sintactice şi al numǎrului de acţiuni descrise, se disting instrucţiuni simple şi structurate. De asemenea, pot fi create blocuri de instrucţiuni executabile, denumite instrucţiuni compuse.

· O instrucţiune compusǎ este o secvenţǎ de instrucţiuni (simple, structurate sau compuse) delimitatǎ de cuvintele rezervate BEGIN şi END (8.66). Ea implementeazǎ natural structura secvenţialǎ din programarea structuratǎ. Mulţimea instrucţiunilor executabile ale unui program este o instrucţiune compusǎ. Orice instrucţiune (simplǎ sau structuratǎ) poate fi transformatǎ în instrucţiune compusǎ.

286 (8.66)

Page 22: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

287

· O instrucţiune este simplǎ dacǎ descrie o singurǎ acţiune, unic determinatǎ şi care nu provoacǎ condiţionǎri. Din categoria instrucţiunilor simple fac parte: atribuirea, saltul necondiţionat (GOTO), apelul procedurilor, instrucţiunea INLINE (care corespunde unei secvenţe de program scrisǎ în cod maşinǎ) şi instrucţiunea vidǎ.

· Instrucţiunile structurate sunt construcţii care conţin alte instrucţiuni (simple, compuse sau structurate) care vor fi executate alternativ sau repetitiv. Prin instrucţiunile structurate se codificǎ structurile fundamentale alternative sau repetitive din algoritm. Instrucţiunile sunt separate între ele prin caracterul “;” şi poate lipsi înaintea cuvântului rezervat END. În limbaj existǎ şi alte cuvinte rezervate cu rol de separator (ELSE, UNTIL). În concluzie, conceptului de instrucţiune îi poate fi asociatǎ diagrama de sintaxă 8.67.

8.3.2. Instrucţiunile simple ale limbajului

Prin instrucţiunile simple se realizeazǎ o parte a operaţiilor de bazǎ din algoritmi. · Instructiunea vidǎ descrie actiunea vidǎ. Ea este definitǎ prin lipsǎ în contextul unor construcţii Pascal, neavând o mnemonicǎ explicitǎ. Prin construcţia instrucţiune se subîntelege şi instrucţiunea vidǎ.

· Instrucţiunea de atribuire evalueazǎ o expresie şi atribuie valoarea acesteia unei variabile sau funcţii. Instrucţiunea are forma:

identificator:=expresie,

unde identificator referǎ o variabilǎ (simplǎ sau indexatǎ) sau o funcţie (8.68).

(8.67)

(8.68)

Forma cu identificator_functie se utilizeazǎ în cadrul subprogramelor de tip funcţie. Pentru simplificarea prezentǎrii, în continuare se va face referire numai la identificator_variabilǎ, regulile enuntate fiind identice şi pentru funcţii. Expresia din membrul drept al instrucţiunii este evaluatǎ independent de lungimea şi tipul variabilei din stânga. Dupǎ determinarea tipului valorii finale ale expresiei are loc atribuirea, acesta fiind momentul când se face eventuala "ajustare" la lungimea şi tipul variabilei din stânga. Între variabila din stânga atribuirii şi expresia din dreapta trebuie sǎ existe compatibilitǎţile prezentate în tabelul 8.6.

Tabelul 8.6.

Page 23: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

Compatibilităţi în operaţia de atribuire.

Limbajul Pascal acceptǎ un numǎr limitat de atribuiri neomogene: când variabila este de un

tip real şi expresia este de un tip întreg sau variabila este de tip şir şi expresia este de tip caracter. Alte combinaţii de tipuri neomogene genereazǎ erori în momentul compilǎrii (compilatorul verificǎ respectarea compatibilitǎţii în operaţiile de atribuire). În cazul în care expresia din dreapta atribuirii este o constantǎ simbolicǎ sau un literal, compilatorul verificǎ atât compatibilitatea de tip, cât şi încadrarea valorii în domeniul (lista) de valori admise de tipul variabilei receptoare, semnalând, eventual, erorile corespunzǎtoare.

Atribuirea numericǎ presupune ca variabila sǎ fie de tip numeric (întreg, real) şi expresia sǎ fie aritmeticǎ. În categoria atribuirilor numerice pot fi incluse şi cele în care variabila din stânga este de tip întreg, iar expresia din dreapta este formatǎ cu operatori de lucru la nivel de bit.

La atribuire de şiruri, când şirul rezultat din expresie are lungimea mai mare decât cea declaratǎ pentru variabila receptoare, acesta va fi trunchiat la dreapta. Octetul de lungime al variabilei receptoare primeşte valoarea şirului efectiv atribuit.

· Instrucţiunea de apel al unei proceduri (8.69) are forma: nume_procedurǎ [ (listǎ_parametri_actuali ) ];

(8.69) Parametrii din apel se numesc actuali şi se pun în corespondenţǎ cu parametrii corespunzǎtori

definiţi în antetul subprogramelor, care se numesc formali. 8.3.3. Realizarea structurilor alternative Structurile alternative se realizeazǎ prin instrucţiunile IF şi CASE. · În instrucţiunea condiţionalǎ IF, modul de continuare a execuţiei instrucţiunilor programului

depinde de rezultatul evaluǎrii unei expresii logice (condiţii). Instrucţiunea IF (8.70), are forma: IF condiţie THEN instrucţiune [ELSE instrucţiune]; unde condiţie este o expresie logicǎ, iar instrucţiune corespunde definiţiei.

(8.70)

288

În figura 8.4. se prezintǎ douǎ exemple de structuri alternative: c desemneazǎ o condiţie (expresie logicǎ), a cǎrei evaluare produce rezultatul TRUE (ramura DA în schema logicǎ) sau FALSE (ramura NU în schema logicǎ); s1 şi s2 desemneazǎ secvenţe de operaţii ce se transpun în limbaj prin construcţia instrucţiune, fiind posibilǎ, la limitǎ, situaţia de instrucţiune vidǎ; pentru

Page 24: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

289

lizibilitate, se recomandǎ scrierea cu indentare (cu deplasarea cu câteva pozitii spre dreapta) a secvenţelor s1 şi/sau s2.

Întrucât s1 şi s2 trebuie sǎ rǎspundǎ cerinţelor construcţiei instrucţiune, adicǎ sǎ fie o instrucţiune simplǎ, compusǎ sau structuratǎ, se vor constitui instrucţiuni compuse care sǎ înglobeze eventualele succesiuni de instrucţiuni ce corespund lui s1 şi/sau s2.

Structura pseudoalternativǎ IF-THEN poate fi descrisǎ şi ca o structurǎ alternativǎ simplǎ, cu instrucţiune vidǎ pe ramura FALSE:

IF c THEN s1 ELSE; O structurǎ IF-ELSE se poate descrie fie ca structurǎ pseudoalternativǎ IF-THEN, fie ca

structurǎ IF-THEN-ELSE cu instrucţiune vidǎ pe ramura THEN: IF NOT c THEN s1; IF c THEN ELSE s1;

Figura 8.4. Structura alternativă simplă (a) şi pseudoalternativă (b)

Se remarcǎ faptul cǎ instrucţiunea ce precede ELSE nu trebuie urmatǎ de caracterul ; . Prezenta lui ar genera interpretarea eronatǎ a întregii instrucţiuni IF. În cazul în care

secventele s1 şi/sau s2 conţin alte instrucţiuni IF, se ajunge la structuri alternative multiple. Pentru o imbricare clarǎ şi corectǎ, se recomandǎ ca pe ramurile care se dezvoltǎ sǎ se construiascǎ instrucţiuni compuse.

· Instrucţiunea CASE permite alegerea unei acţiuni dintr-un grup, în funcţie de valorile pe care le poate lua un selector (8.71).

(8.71) CASE selector OF listǎ_constante : instructiune

{;listǎ_constante : instructiune} [ELSE instructiune]

END; Selector este o expresie de tip ordinal, listǎ_constante conţine literali compatibili cu tipul

selectorului iar instrucţiune corespunde definiţiei din digrama 8.5. Instrucţiunea CASE selecteazǎ pentru execuţie instrucţiunea a cǎrei listǎ_constante conţine o

valoare egalǎ cu valoarea curentǎ a selectorului. Dacǎ nici o constantǎ nu îndeplineşte condiţia de egalitate, se executǎ instrucţiunea care urmeazǎ dupǎ ELSE (dacǎ aceasta existǎ) sau nu se executǎ nimic (dacǎ aceasta lipseşte).

Instrucţiunea permite realizarea structurii alternative generalizate (CASE-OF) a cǎrei formǎ de principiu se prezintǎ în figura 8.5.

Page 25: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

Figura 8.5. Structura CASE - OF

Constantele din listǎ sunt literali compatibili cu selectorul, a cǎror ordine este arbitrarǎ. Valorile acestora trebuie sǎ fie unice în cadrul aceleiaşi instructiuni CASE.

8.3.4. Realizarea structurilor repetitive Limbajul Pascal dispune de instrucţiuni care realizeazǎ natural structurile repetitive cu

condiţie anterioarǎ, posterioarǎ şi cu numǎrător. · Structurile repetitive condiţionate anterior se realizeazǎ cu instrucţiunea WHILE (8.72), care

are forma: WHILE condiţie DO instrucţiune;, unde condiţie este o expresie logicǎ, iar instrucţiune corespunde definiţiei.

(8.72) Instrucţiunea WHILE este repetitivǎ cu un numǎr necunoscut de paşi, al cǎrei corp poate sǎ nu

fie executat niciodatǎ, dacǎ expresia logicǎ are de la început valoarea FALSE. Programatorul trebuie sǎ asigure în corpul ciclǎrii modificarea, la un moment dat, a valorii expresiei logice, pentru a evita ciclarea infinitǎ.

La execuţia instrucţiunii WHILE (figura 8.6) se realizeazǎ urmǎtoarele operaţii: 1. se evalueazǎ expresia logicǎ; 2. dacǎ valoarea este TRUE se trece la pasul 3, altfel se trece la pasul 4; 3. se executǎ instrucţiunea şi se revine la pasul 1; 4. se trece la instrucţiunea s de dupǎ construcţia WHILE.

Figura 8.6. Structura WHILE - DO

· Structurile repetitive condiţionate posterior se realizeazǎ cu instrucţiunea REPEAT (8.73), care are forma:

(8.73) REPEAT instructiune

{;instructiune} UNTIL conditie;

unde condiţie şi instrucţiune au aceleaşi semnificaţii prezentate la instrucţiunea WHILE. Instrucţiunea REPEAT este repetitivǎ cu numǎr nedefinit de iteraţii, al cǎrei corp se executǎ

cel puţin o datǎ. La întâlnirea ei, funcţioneazǎ urmǎtorul algoritm (figura 8.7):

290

Page 26: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

291

Figura 8.7. Structura DO - UNTIL

1. se executǎ corpul de instructiuni S; 2. se evalueazǎ expresia logicǎ; 3. dacǎ valoarea este FALSE, se revine la pasul 1, altfel se trece la pasul 4; 4. se trece la instructiunea de dupǎ constructia REPEAT.

Programatorul trebuie sǎ asigure în corpul ciclǎrii modificarea valorii expresiei logice, pentru a evita ciclarea infinitǎ.

Dacǎ S este mulţime de instrucţiuni, nu este necesarǎ formarea unei instrucţiuni compuse deoarece instrucţiunea REPEAT are delimitatori expliciţi: cuvintele REPEAT şi UNTIL.

· Structurile repetitive cu numǎrǎtor se realizeazǎ cu instrucţiunea FOR (8.74) care are urmǎtoarele forme sintactice:

(8.74) FOR contor := vi TO vf DO instrucţiune; FOR contor := vi DOWNTO vf DO instrucţiune; unde contor este variabilǎ de tip ordinal pentru controlul ciclǎrii, vi şi vf sunt expresii

compatibile cu tipul contorului, semnificând valoarea initialǎ, respectiv valoarea finalǎ a acestuia, iar instrucţiune corespunde corpului ciclului.

Structurile asociate instructiunii FOR sunt prezentate în figura 8.8. Numǎrul de iteraţii se determinǎ astfel: n= ±[ORD(vf)-ORD(vi)]+1.

Figura 8.8. Structura DO - FOR

Semnul + se utilizeazǎ pentru forma instrucţiunii cu TO, iar semnul - pentru forma cu

DOWNTO. Dacǎ de la început n≤0, s nu se executǎ şi se trece la urmǎtoarea instrucţiune. La sfârşitul execuţiei instrucţiunii, variabila contor are o valoare nedefinitǎ. Nu se recomandǎ modificarea de cǎtre programator a valorii variabilei contor în corpul ciclǎrii. Ea poate apǎrea ca operand în expresii.

Dacǎ în corpul ciclǎrii, contorul este utilizat şi pentru referirea elementelor de masiv (rol de index), valorile iniţialǎ şi finalǎ trebuie sǎ se încadreze în mulţimea definitǎ în tipul ARRAY pentru

Page 27: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

292

respectivul indice. Dacǎ algoritmul necesitǎ ca pasul iteraţiei sǎ fie diferit de SUCC(v) sau PRED(v), structura repetitivǎ cu numǎrator se va transforma într-o structurǎ repetitivǎ cu numǎr necunoscut de iteraţii (WHILE sau REPEAT).

8.4. PROCEDURI ŞI FUNCŢll

Procedurile şi funcţiile sunt secvenţe de program subordonate (subprograme), care se execută sub controlul programului principal. Procedurile şi funcţiile prezintă aceeaşi structura în trei secţiuni (antet, secţiune de declaraţii, secţiune de instrucţiuni) ca şi programul. Oricum, spre deosebire de programe, procedurile şi funcţiile pot fi imbricate unele în altele, prezintă facilităţi sofisticate de transmitere a parametrilor şi se pot chiar autoapela. Procedurile sunt activate prin invocarea numelui lor în instrucţiuni de apelare, iar funcţiile sunt activate prin evaluarea unor expresii care conţin apeluri ale acestor funcţii ca operanzi, valoarea rezultată din evaluarea funcţiilor fiind asociată numelui acestora.

8.4.1. Proceduri

Declaraţia unei proceduri asociază unui bloc un identificator, care este numele procedurii. Structura generală a unei proceduri este următoarea:

PROCEDURE nume_proc[(lista_param_formali)]; [opţiune;] LABEL {declaraţii de etichete locale}; CONST {declaraţii de constante locale}; TYPE {declaraţii de tipuri locale}; VAR {declaraţii de variabile locale};

{declaraţii de subprograme FUNCTION şi PROCEDURE}; BEGIN

{instrucţiuni -corpul procedurii}; . END;

Antetul procedurii specifică numele procedurii, nume_proc, lista parametrilor formali, lista_param_formali şi, eventual, o opţiune.

Detalii asupra listei parametrilor formali sunt date în continuare. Pentru opţiune există următoarele posibilităţi:

FORWARD pentru declararea anticipată a procedurii ; INLINE pentru proceduri scrise în cod obiect; EXTERNAL pentru declararea procedurilor externe scrise în limbaj de asamblare; INTERRUPT pentru declararea procedurilor de întreruperi.

Activarea unei proceduri se poate realiza printr-o instrucţiune de apel de procedură, care specifică numele procedurii şi, dacă este cazul, lista parametrilor actuali:

nume_proc[(lista_param_actuali)]; unde nume_proc este numele utilizat la declararea procedurii, iar lista_param _actuali este lista parametrilor actuali.

8.4.2. Funcţii

Declaraţia unei funcţii defineşte un bloc, care calculează o valoare asociată numelui funcţiei. Funcţiile prezintă o structură similară cu cea a procedurilor:

FUNCTION nume func[(lista_param_formali)]: tip_func; [opţiune;] LABEL {declaraţii de etichete locale}; CONST {declaraţii de constante locale}; TYPE {declaraţii de tipuri locale}; VAR {declaraţii de variabile locale};

Page 28: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

293

{declaraţii de subprograme FUNCTION şi PROCEDURE}; BEGIN

{instrucţiuni- corpul funcţiei}; END.

Antetul funcţiei specifică identificatorul funcţiei, nume_func, lista parametrilor formali, lista_param_formali, dacă este cazul, şi tipul rezultatului funcţiei, tip_func. Pentru opţiune există aceleaşi variante ca şi în cazul procedurilor. Blocul unei funcţii trebuie să conţină cel puţin o instrucţiune de atribuire către identificatorul funcţiei (fie în secţiunea de instrucţiuni, fie într-o procedură sau funcţie definită în secţiunea de declaraţii). Dacă o asemenea instrucţiune nu există sau nu este executată, valoarea returnată de către funcţie este nedefinită.

O funcţie este activată prin invocarea ei ca operand într-o expresie.

8.4.3. Parametri

Parametrii specificaţi în listele de parametri ale declaraţiilor procedurilor şi funcţiilor se numesc parametri formali. Parametrii formali sunt identificatori de variabile locale, care pot fi referite în blocul subprogramului respectiv. Parametrii utilizaţi în locul parametrilor formali în listele de parametri ale apelurilor procedurilor sau funcţiilor se numesc parametri actuali. Parametrii actuali pot fi variabile, expresii sau valori.

Parametrii formali ai unui subprogram primesc ca valori actuale valorile corespunzătoare din lista de parametri actuali a apelului subprogramului respectiv şi, de aceea, trebuie să existe coincidentă de număr şi tip între parametrii formali şi, parametrii actuali corespunzători.

În funcţie de modul transmiterii parametrilor actuali către parametrii formali, aceştia din urmă sunt de două tipuri:

a) parametri valoare b) parametri variabilă (parametri referinţă).

Un parametru valoare se comportă ca o variabilă locală a subprogramului apelat, cu deosebirea că primeşte ca valoare iniţială valoarea parametrului actual corespunzător din lista de argumente a apelulul subprogramului în momentul apelării. Modificarea valorii unui parametru valoare nu are efect asupra valorii parametrului actual corespunzător din blocul apelant. Prin urmare, prin intermediul unui parametru valoare poate fi transmisă o valoare din blocul apelant către subprogram, nu însă şi în sens invers. Parametrul actual corespunzător unui parametru valoare poate fi o expresie, a cărei valoare însă nu trebuie să fie de tip fişier, sau să aparţină unui tip structurat care implică în definiţie un tip fişier .

Un parametru variabilă devine în momentul apelului, şi este pe parcursul execuţiei subprogramului, chiar variabilă care constituie parametrul actual corespunzător din blocul apelant, putând fi identificaţi în cele două blocuri prin nume diferite. Orice referire a parametrului formal de tip variabilă accesează însuşi parametrul actual, modificarea valorii parametrului variabilă reflectându-se imediat asupra parametrului actual. În consecinţă, un parametru variabilă este, utilizat în situaţia în care trebuie transmisă o valoare din subprogramul apelat către blocul apelant şi, de aceea, parametrul actual corespunzător trebuie să fie un identificator de variabilă de un tip compatibil, neputând fi o expresie.

Tipurile fişier pot fi transmise numai ca parametri variabilă. Specificarea faptului că un parametru formal este de tip variabilă se realizează prin precedarea acestui parametru în lista argumentelor formale ale subprogramului de către cuvântul rezervat VAR. La nivel intern, în cazul parametrilor variabilă nu se transmite valoarea parametrului actual către parametrul formal, ci se transmite adresa de memorie a celui dintâi.

Sintaxa scrierii listei de parametri formali din declaraţia unei proceduri sau funcţii este următoarea:

( [VAR] id _1, id_2 , ...: tip_1 [ ; [VAR]id_i, id_j , ..: tip_2 ; ...]) unde identificatorii corespunzători aceluiaşi tip (tip _i) sunt separaţi prin virgule, grupurile de

identificatori corespunzători unor tipuri diferite fiind separaţi prin " ; ".

Page 29: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

294

Cuvântul rezervat VAR trebuie să apară numai înaintea grupurilor de parametri variabilă. În program argumentul formal n al procedurii fact este parametru valoare, parametrul actual corespunzător din programul principal este o variabilă distinctă ( deşi are acelaşi nume), care la revenirea execuţiei în programul principal nu este afectată de eventuala modificare a variabilei n din procedură. Argumentul formal f este declarat ca parametru variabilă (fiind precedat de cuvântul rezervat VAR), pentru ca la revenirea execuţiei din procedura în programul principal, parametrul actual corespunzător f să conţină valoarea calculată a factorialului.

Sintaxa scrierii listei de parametri actuali pentru o procedură sau funcţie este următoarea: (id_1/const_1[,id_2/const_2,...]) unde parametrii actuali pot fi identificatori de variabile, constante simbolice (id _i), sau

constante (const_i). Parametrii actuali trebuie separaţi în lista de argumente prin virgule. Domeniul de valabilitate al declaraţiilor Declaraţia identificatorilor şi etichetelor este valabilă în interiorul blocului în care au fost

definite, incluzând toate blocurile subordonate. În particular, identificatorii sau etichetele definite în programul principal pot fi folosite în orice bloc al programului.

Un identificator sau o etichetă nu pot să fie invocate în textul sursă anterior declarării lor în blocul respectiv. De la această regulă face excepţie tipul de bază al unui tip POINTER, tipul de bază putând fi declarat ulterior tipului POINTER.

Declararea identificatorilor şi etichetelor trebuie să fie unică la nivelul exterior dintr-un bloc. Excepţie fac redeclarările din blocurile subordonate sau câmpurile tipurilor RECORD (pot exista identificatori într-un bloc având acelaşi nume cu cel al unor identificatori de câmpuri). Identificatorii şi etichetele pot fi redeclarate în blocurile subordonate blocului în care au fost declarate, noua declaraţie desemnând obiecte diferite faţă de cele declarate la nivelul superior şi fiind valabilă până la revenirea execuţiei în blocul apelant, în care ramâne valabilă declaraţia iniţială. Folosirea unui identificator în cadrul unui subprogram, fără a fi fost declarat în lista de parametri formali sau în secţiunea de declaraţii a subprogramului, implică considerarea acestui identificator ca fiind identificator al unui bloc ierarhic superior.

Utilizarea unui identificator declarat în lista de argumente formale a subprogramului, implică considerarea acestuia ca variabilă locală dacă este parametru valoare, sau ca variabilă a blocului apelant dacă este parametru variabilă. În sfârşit, folosirea unui identificator declarat în secţiunea de declaraţii a unui subprogram, implică considerarea acestuia ca obiect local al subprogramului, neputând fi "văzut" la un nivel superior.

Tipurile folosite în lista de parametrii formali, trebuie să fie tipuri diferite în programul apelat sau tipuri standard, recunoscute de limbaj.

O declaraţie este valabilă în blocul în care a fost declarată. Se pot folosi: - variabile globale - sunt variabile declarate în programul principal şi sunt recunoscute în

orice procedura sau funcţie; - variabile locale - sunt variabile declarate în blocul procedurii sau funcţiei şi sunt

recunoscute în blocurile subordonate (de nivel inferior). O variabilă decalarată în program, procedură sau funcţie, este considerată globală la nivel de

program şi locală la nivel de procedură sau funcţie. Este de preferat ca toate variabilele folosite de proceduri sau funcţii, sa fie declarate în lista

de parametrii formali fie în cadrul procedurii (ca variabile locale), pentru a nu se modifica variabilele globale în mod nedorit.

Declaraţii forward de procedură. O procedură sau funcţie poate apela o procedura sau funcţie deja declarată, declararea fiind

amplasată în program înainte de daclararea procedurii sau funcţiei ce o apelează. O declaraţie de procedură ce spacifică directiva FORWARD în loc de bloc, este o declaraţie

FORWARD de procedură. După această decalaraţie, o procedura poate fi definită oriunde, dar lista de parametrii

formali trebuie să fie sursă şi să se închidă blocul. Procedure Nume1 [(lista parametrilor formali)];forward;

Page 30: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

295

.............. Procdure Nume2 [(lista parametrilor formali)];

begin .............. Nume1(lista parametrilor actuali); .............. end;

Procedure Nume1; begin

............... Nume2(lista parametrilor actuali);

............... end; ...............

Procedure Nume1 (lista parametrilor formali);forward; Procedure Nume2 (lista parametrilor formali);

begin ............... Nume1(lista parametrilor actuali); ...............

end; Procedure Nume1;

begin ............... Nume2(lista parametrilor actuali); ...............

end; Proceduri şi funcţii recursive. În Turbo-Pascal este permis ca o procedură sau funcţie să se

apeleze pe sine. Aceasta tehnică se numeşte recursivitate. Folosirea acestei tehnici impune introducerea in program a directivelor de compilare {$S+},

prin care se genereaza un cod care verifica depasirea stivei. Directiva de compliare {$M stacksize, heapmin, heapmax}, stabileste dimensiunea stivei (stacksize, de inceput (heapmin, si de sfarsit (heapmax, a zonei de heap.

Valorile implicite sunt: {$M 6384,0,655360}. Recursivitatea directa. Un subprogram (funcţie sau procedură) este direct recursivă

dacă se apelează pe el insuşi Aceasta proprietate este realizabila in PASCAL , datorita faptului ca variabilele locale ale

subprogramului sunt create in momentul apelului si apoi distruse la sfarsitul executiei subprogramului

Daca un program se apeleaza pe el insusi , fiecare dintre variabilele sale locale sunt duplicate in atatea exemplare ,cate se alfa in curs de executie.

Recursivitatea permite tratarea intr-o maniera eleganta a majoritatii problemelor care nu se exprima intr-o forma iterativa evidenta

Recursivitatea implică activarea unei proceduri sau funcţii din propria secţiune de instrucţiuni (subprogramul se autoapelează). Oricum, în utilizarea recursivităţii trebuie avut în vedere faptul că orice apel al subprogramului implicat provoacă memorarea în stivă a adresei instrucţiunii care urmează după apel, precum şi a valorilor parametrilor valoare şi a adreselor parametrilor variabilă. La autoapelări repetate, spaţiul ocupat în stivă poate depăşi limitele admise. De aceea, orice subprogram recursiv trebuie să asigure controlul numărul de autoapelări, permiţând ieşirea din recursivitate.

Programul următor este destinat calculului funcţiei factorial, în vederea utilizării recursivităţii directe.

Page 31: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

296

program recursiv_fact; var n : integer; function fact(n: integer): real; begin

if n <= 1 then fact := 1.0 else fact := n*fact(n-1); end;

{ program principal } begin

write('n='); readln(n); writeln('factorial=',fact(n));

end. Recursivitatea indirectă (mutuală) implică apelarea reciprocă a două sau mai multe

subprograme şi poate fi realizată cu ajutorul directivei FORWARD, care permite apelarea unui subprogram înaintea definirii sale complete în textul sursă. Astfel, presupunând că două proceduri, A şi B, trebuie să se apeleze reciproc, trebuie declarată mai întîi procedura A cu directiva FORWARD, incluzând în textul sursă antetul acesteia urmat de cuvântul rezervat FORWARD, dar omiţând blocul, apoi trebuie inclusă definiţia completă a procedurii B (în care este conţinut apelul procedurii A) şi apoi trebuie să apară definiţia completă a procedurii A omiţând, de această dată, lista de parametri formali dar incluzând blocul (care conţine apelul procedurii B).

procedure A(m,n: integer); forward; . procedure B(x,y: real); begin …

A(2,5); … end; procedure A; begin

B(2.5,8.4); end. Între declaraţia FORWARD a unui subprogram şi definiţia sa ulterioară pot să apară mai

multe subprograme, care să apeleze sau nu subprogramul declarat FORWARD.

8.5. FIŞIERE

Prin fişier în general se înţelege o structură de date care constă dintr-o secvenţă de componente. Fiecare componentă din secvenţă are acelaşi tip. Numărul acestor componente nu este fixat. Aceasta este o caracteristicii prin care se distinge clar fişierul de tablou. La un moment dat însă, este accesibilă direct numai o singură componentă a secvenţei. Celelalte componente sunt accesibile progresând secvenţial în fişier. Progresarea în componentele unui fişier se realizează prin subprograme de citire şi de scriere. Datele fişierului sunt stocate de obicei pe un suport magnetic.

Datele se manevrează, pe purtători tehnici de informaţii, dar se prelucrează numai când sunt prezente în memoria internă, acestea trebuie organizate atât extern, cât şi intern. În organizarea externă a datelor se identifica două niveluri de abordare logic şi fizic. Fişierul reprezintă termenul generic care desemnează structurile de date externe. El reprezintă o mulţime (colecţie) de date omogene din punct de vedere al semnificaţiei şi al cerintelor de prelucrare. În purtatorul extern, fişierul are, pe lângă partea de date, şi informaţii de identificare.

Privit din punctul de vedere al prelucrării, un fişier este o colecţie ordonată de date, numite articole. Articolul este constituit dintr-o mulţime ordonată de valori ale unor caracteristici care aparţin, unei singure entităţi Componentele articolului destinate diverselor caracteristici sunt denumite câmpuri de date. Depinzând de natura, ordinul de mărime şi forma de reprezentare externă a valorilor asociate, fiecare câmp de date are o lungime, exprimată în octeti. Lungimea unui articol

Page 32: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

297

este dată de suma lungimilor câmpurilor care îl compun. După cum toate articolele dintr-un fişier au sau nu aceeaşi lungime, se face distincţie între fişierele cu articole de lungime fixă sau variabilă. Limbajul Pascal acceptă atât fişiere cu articole de lungime fixă (stabilită la momentul fiecărei prelucrări), cât şi de lungime variabilă (implementată prin separarea fizică a două înregistrari alăturate - de exemplu, prin caracterele CR/LF).

Principiile şi regulile după care se memorează articolele unui fişier pe purtatorul extern, cu asigurarea protecţiei şi regăsirii acestor, constituie metoda de organizare. În evoluţia organizării datelor externe s-au conturat mai multe metode (secvenţială, relativă, indexată), dintre care, în limbajul Pascal este inclusă metoda de organizare secventială. Tipul de acces reprezintă modalitatea de regăsire (localizare) a articolelor din fişier. Noţiunea de acces trebuie aplicată atât pentru operaţia de scriere, cât şi pentru cea de citire a datelor. Poziţia din/în care se face citirea/scrierea în cadrul fişierului este indicată de un pointer. Accesul la datele înregistrate pe un purtator tehnic poate fi secvenţial sau direct, în funcţie de modul în care se stabileşte pointerul.

Accesul secvenţial este posibil la toţi purtatorii tehnici de date şi presupune înscrierea înregistrărilor în ordinea furnizării lor şi regăsirea ulterioară în ordinea în care au fost înscrise în suport. O problemă importantă la consultarea (citirea) în acces secvenţial este controlul ajungerii la sfârşitul fişierului. Dupa citirea ultimei entităţi (articol, bloc, linie sau câmp), pointerul indică marcatorul (logic sau fizic) de sfârşit de fisier – EOF (End of File).

În accepţiunea limbajului Turbo Pascal, pot fi definite trei structuri de tip fişier: • fişier cu tip • fişier text • fişier fără tip,

Să notăm cu f o variabilă de tip fişier. Înainte ca variabila să fie ulilizată, ea trebuie asociată cu un fişier extern, prin apelul procedurii Assign. În general, fişierul extern este un fişier pe disc, dar variabila de fişier poate fi asociată şi cu un dispozitiv (de exemplu tastatura, ecran). Fişierul extern marchează informaţiile scrise în, fişier sau furnizează informaţiile depuse. După ce s-a stabilit asocierea cu un fişier extern, fişierul trebuie "deschis". Această deschidere pregăteşte fişierul pentru citire şi/sau scriere. Un fişier existent poate fi deschis cu ajutorul procedurii Reset. Un fişier nou poate fi deschis cu procedura Rewrite. Fişierele de tip text deschise cu Reset permit doar operaţii de citire; fişierele de tip text deschise cu procedura Rewrite sau Append permit numai operaţii de scriere. Fişierele cu tip sau fără tip permit atât citiri cât şi scrieri, indiferent dacă ele au fost deschise cu Rewrite sau cu Reset.

Fiecare fişier este o secvenţă liniară de componente, fiecare componentă având tipul de bază al variabilei fişier. Fiecare componentă a fişierului are asociat un număr, numit numărul componentei. Prima componenta a fişierului este considerată având numărul de componentă zero. Cea de a doua componenta are numărul 1 şi aşa până la n-1 ultima componentă.

În mod normal accesul la componentele fişierului este secvenţial. Aceasta înseamnă ca atunci când se citeşte o componentă cu ajutorul procedurii standard Read, sau când se scrie o componentă cu ajutorul rocedurii standard Write, poziţia curentă de fişier se deplasează la următoarea componentă, în sensul ordonării numerice. În afară de acest mod de acces, fişierele cu tip şi fişierele fără tip permit şi accesul direct (aleator) la componentele fişierului. Accesul direct se bazează pe procedura de căutare Seek, care mută poziţia curentă în; fişier pe o componentă specificată. După această poziţionare componenta astfel aleasă poate fi citită. Funcţiile standard File-Pos şi File-size permit determinarea poziţiei curente în fişier, respectiv a dimensiunii actuale a fişierului. Când prelucrarea componentelor unui fişier se termină, fişierul trebuie închis cu procedura standard Close. După ce fişierul a fost închis, se vor actualize datele fişierului extern asociat. După fiecare apel de procedură şi funcţie standard de intrare/ieşire se testează automat reuşita operaţiei de intrare/ieşire. În cazul în care apare o eroare, programul se termină şi se afişează un mesaj, de eroare în execuţie. Directiva de compilare $I permite ca această eroare să fie tratată în program. În stare decuplată {$I-}, programul nu se opreşte la o eroare de intrare/ieşire. Pentru a analiza cauza erorii, se apelează funcţia standard IoResult, care în caz de operaţie reuşită returnează valoarea zero, iar în

Page 33: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

caz de eşec returnează o valoare diferită de zero, care codifică natura erorii. Ştergerea fişierului extern asociat unui fişier închis poate fi realizată cu procedura Erase.

În procesul de citire a unui fişier, faptul că s-a ajuns la sfârşitul fişierului poate fi urmărit cu funcţia Eof. Această funcţie returnează valoarea logica true dacǎ s-a ajunsla sfirşitul fişierului, respectiv false în caz contrar. Logica apelurilor diferitelor subprograme şi funcţii standard de intrare/ieşire sint prezentate în figura 8.9.

Figura 8.9. Principalele proceduri utilizate la lucrul cu fişiere

Fişiere cu tip, reprezintă o secvenţă de componente, fiecare componentǎ având acelaşi tip,

numit tipul de bază al fişierului. Fişierele cu tip sunt constituite, logic, din articole de lungime fixă, cărora li se asociază

numere relative, începând de la zero. Fişierele cu tip se mai numesc fişiere cu prelucrare la nivel de articol. Operaţiile de acces la articolele fişierelor cu tip transferă date fără conversie. Unitatea de transfer este articolul, definit ca variabilă de acelaşi tip cu fişierul. Mecanismul fizic de "decupare" a articolelor în cadrul fişierului se bazează pe faptul că ele au lungime fixă (lart), definită în momentul prelucrării. Operaţia de I/E transferă atâţia octeţi câţi indică lart. Lungimea fisierului, exprimată în octeţi, este memorată în intrarea lui din director (sfârşitul de fişier este logic). Numărul de articole din fişier (Filesize(f)) este determinat de sistem prin împărţirea întreagă a lungimii acestuia la lart. Fişierele cu tip acceptă accesul secvenţial şi relativ la articole. Accesul secvenţial poate fi combinat cu cel relativ în cadrul aceluiaşi program. Poziţionarea directă pe articolul cu numărul relativ r se realizează cu procedura Seek(f,r). Funcţia Eof(f) are valoarea TRUE, dacă pointerul este plasat după ultimul articol. Valoarea curentă a pointerului (poziţia în cadrul fişierului exprimată în număr relativ) poate fi determinată prin funcţia Filepos(f). Dacă Eof(f) este TRUE, atunci Filepos(f)=Filesize(f).

Citirea articolelor se face cu procedura Read, iar scrierea cu procedura Write. Asupra fişierelor cu tip nu se pot aplica funcţiile Eoln, SeekEoln, SeekEof şi procedurile WriteLn, ReadLn. Procedurile de I/E pot transfera unul sau mai multe articole, în funcţie de numărul variabilelor specificate în lista argumentelor acestora.

Tipul fişier cu tip se declară conform diagramei 8.75, unde tip este orice tip de date Pascal, mai puţin tipul fişier. Variabilele asociate fişierelor cu tip se declara conform diagramei 8.76. Tipul precizează structura şi lungimea articolelor care fac obiectul operaţiilor de I/E.

298

Page 34: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

299

(8.75)

(8.76) O variabilă de acest tip poate fi declarată printr -o declaraţie de forma:

var nume_fişier : file of tip_de_bază; unde tip _de_bază este un tip arbitrar, exceptând tipul fişier (nu există fişier de fişiere).

Deseori tipul de bază este un tip înregistrare (record), astfel încât fiecare linie a unui fişier reprezintă o înregistrare cu toate câmpurile completate.

Fişiere de tip text, conţine caractere structurate pe linii, fiecare linie fiind terminată cu un caracter de sfârşit de linie (EOLN character). Lungimea liniilor este variabilă. Caracterul de sfârşit de linie este de regulă CR (ASCII #13), care poate să fie urmat şi de un caracter LF (ASCII #10). Un fişier text este terminat cu un caracter de sfârşit de fişier CTRL-Z.

Fişierele TEXT acceptă numai accesul secvenţial. Operaţia de citire se realizează cu procedurile Read şi ReadLn, iar scrierea cu procedurile Write si WriteLn. Deoarece datele memorate în fişiere TEXT au reprezentarea externă ASCII, nu toate tipurile de date pot face obiectul operaţiilor de citire/scriere. Nu pot fi citite/scrise date de tip SET sau enumerativ, date de tip ARRAY sau RECORD, ci numai elemente ale acestora. Există dispozitive fizice care acceptă numai fişiere TEXT, cum ar fi: tastatura, care emite numai coduri ASCII; monitorul şi imprimanta, care recepţionează numai coduri ASCII.

Tipul TEXT se declară conform diagramei 8.77, unde TEXT este cuvântul rezervat, iar variabilele asociate se declară conform diagramelor 8.78 şi 8.79.

(8.77)

(8.78)

(8.79)

Un fişier text este declarat prin tipul predefinit text, de exemplu: var f : text; Notăm că un fişier text nu este echivalent cu un fişier de tip file of char. Lungimea liniilor fiind variabilă, poziţia unei linii în cadrul fişierului nu este calculabilă. În

consecinţă, la fişiere text accesul nu poate fi decât secvenţial. Asocierea numelui fişierului la suportul extern este realizată cu procedura Assign. Deschiderea fişierului poate fi realizată prin trei subprograme standard. Un fişier nou se

deschide cu procedura Rewrite, un fişier existent poate fi deschis fie la începutul fişierului, fie la sfârşitul lui, în vederea adăugării liniilor noi. Deschiderea la început se realizează cu procedura Append.

Pentru fişiere text, formele speciale ale subprogramelor Read şi Write permit citirea şi scrierea nu numai a valorilor de tip caracter, ci şi a valorilor de tip întreg, real şi de tip şir de caractere. De exemplu, Read(f,i), unde i este o variabilă de tip intreg, va citi o secvenţă de cifre, care vor fi interpretate ca un întreg zecimal, şi care va fi depus în variabila i.

Detectarea caracterelor de sfârşit de linie poate fi realizată cu funcţia Eoln, care returnează valoarea true dacă s-a ajuns la sfârşitul liniei curente.

Page 35: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

Funcţia SeekEoln este similară cu Eoln; exceptând faptul că se sare peste blancuri şi tab-uri, după care se testează starea de sfârşit de linie.

Starea de sfârşit de fişier poate fi testată cu funcţia Eof, precum şi cu funcţia SeekEof; aceasta din urmă sare peste blancuri şi tab-uri, după care se returnează true dacă s-a ajuns la sfârşitul fişierului.

Procedura SetTextBuf permite ataşarea unui tampon de intrare/ieşire de lungime dată la un fişier text. Golirea tamponului unui fişier text deschis pentru scriere poate fi realizată cu procedura Flush.

Aşa cum s-a arătat la generalităţi despre fişiere, există două fişiere text standard: Input şi Output. Fişierul Input este destinat numai pentru operaţii de citire şi este asociat cu fişierul standard de intrare al sistemului de operare (de regulă claviatură). Fişierul Output este destinat numai pentru operaţii de scriere şi este asociat cu fişierul standard de ieşire al sistemului de operare (de regula ecranul). Aceste fişiere sunt deschise automat înainte de începutul execuţiei, ca şi cum ar fi prezente instrucţiunile.

Assign(Input,' '); Reset(Input); Assign(Output,' '); Rewrite(Output);

Aceste fişiere sunt închise automat după ce s-a terminat execuţia programului. Unele proceduri şi funcţii de intrare/ieşire permit ca numele fişierului să nu fie specificat în

lista de argumente. În acest caz se presupune că fişierul text implicit este sau Input, sau Output, în funcţie de natura subprogramului. De exemplu, Read(x) este echivalent cu Read (Input,x), iar Write(x) este echivalent cu Write(Output,x).

Un fişier deschis cu Reset suportă numai proceduri şi funcţii orientate spre citire. Analog, un fişier deschis cu Rewrite sau Append permite utilizarea acelor proceduri şi funcţii, care sunt orientate spre scriere.

Fişiere fără tip, sunt canale de intrare/ieşire de nivel inferior, utilizate în primul rând pentru accesul direct la orice fişier disc, indiferent de tipul şi de structurarea internă a fişierului.

Fişierele fără tip sunt construite, logic, din blocuri de lungime fixă, asupra cărora nu se face nici o ipoteză de structură. Se mai numesc fişiere cu prelucrare la nivel de bloc. Unitatea de transfer este blocul, a carui lungime este definită, implicit sau explicit, la deschiderea fişierului (parametrul RecSize). Transferul datelor între memoria internă şi suportul extern se realizează fără conversie.

Blocurilor, fiind de lungime fixă, (lbloc) li se asociază numere relative începând de la zero. Accesul la blocuri se poate face secvenţial sau direct. Poziţionarea directă pe un bloc cu număr relativ r se realizează cu procedura Seek(f,r). Funcţia Eof(f) are valoarea TRUE dăcă pointerul este plasat după ultimul bloc. Valoarea curenta a pointerului poate fi determinata prin funcţia Filepos(f), iar numărul de blocuri din fişier prin funcţia Filesize(f). Citirea blocurilor se face cu procedura BlockRead, iar scrierea cu procedura BlockWrite. Procedurile de I/E pot transfera unul sau mai multe blocuri, în funcţie de valoarea specificată prin parametrul Count.

Între fişierele cu tip şi cele fără tip există multe asemănări de prelucrare. Dintre aceste, cele mai importante se referă la faptul ca transferul este binar (fără conversie) şi ca entităţile transferate (articolul sau blocul) au lungime fixă. Deosebirea esenţială dintre cele două tipuri de fişiere constă în aceea că la fişierele cu tip, articolul are definită o structură, iar la cele fără tip, blocului nu i se asociază o structura.

Tipul fişier fără tip se declară conform diagramei 8.80, unde FILE este cuvânt rezervat, iar variabilele asociate se declară conform diagramei 8.81.

(8.80)

(8.81)

300

În operaţiile de intrare/ieşire, la fişierele fără tip informaţiile sunt transferate direct între fişier disc şi variabile, economisindu-se astfel spaţiul necesar zonei tampon. Un fişier fără tip este compatibil cu orice fişier (cu tip sau text).

Page 36: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

301

O variabilă de acest tip se declară cu tipul predefinit "file", şi nimic altceva, de exemplu var f:file;

Pentru fişiere fără tip, procedurile de deschidere Reset şi Rewrite permit folosirea unui parametru auxiliar. Acest parametru specifică lungimea unei componente a fişierului. Valoarea acestui parametru, din motive istorice, este 128. Se recomandă alegerea valorii 1, deoarece această valoare permite reflectarea corectă a dimensiunii exacte a fişierului (când această valoare este 1, nu sunt posibile componente fracţionate).

Exceptând procedurile Read şi Write, toate procedurile şi funcţiile standard utilizabile pentru fişierele cu tip sunt permise şi pentru fişierele fără tip. În locul procedurilor Read şi Write, pentru realizarea transferurilor rapide de date sunt folosite procedurile BlockRead şi BlockWrite.

Procedura BlockRead citeşte din işierul fără tip un număr precizat de componente, care se depun în memorie de la o adresă specificată. La revenire din procedură, o variabilă -care se poate specifica opţional –va conţine numărul componentelor citite efectiv. Dacă această variabilă nu este specificată, şi dacă nu s-a reuşit citirea tuturor componentelor, va apare o eroare de intrare/ieşire.

Procedura BlockWrite scrie în fişierul fără tip un număr precizat de componente, componentele fiind luate de la o adresă specificată. La revenire din procedura o variabilă opţională va conţine numărul componentelor scrise efectiv. Dacă această variabilă nu este specificată şi dacă nu s-a reuşit scrierea tuturor componentelor, atunci va apare o eroare de intrare/ieşire.

Este permis atât accesul secvenţial, cât şi cel direct, datorită faptului că toate componentele au aceeaşi lungime. Poziţionarea pe o componentă dorită se realizează cu procedura Seek. Numerotarea componentelor începe de la zero.

Numărul componentelor se determină cu funcţia FileSize, iar numărul componentei actuale se determină cu funcţia FilePos. Procedura Truncate permite trunchierea fişierului, pornind de la componenta actuală din fişier.

Observaţie: Să considerăm variabilele ftp, fft şi ftxt de tipul fişier cu tip, fişier fără tip, respectiv text. În

zona de memorie alocată acestor fişiere se găsesc informaţii referitoare la fişierul fizic. Aceste informaţii sunt organizate într-un articol de tip FileRec (pentru fişiere cu sau fără tip) respectiv TextRec (pentru fişiere text). Tipurile TextRec şi FileRec sunt definite în unit-ul DOS.

După asignarea şi deschiderea fişierelor există posibilitatea de a avea acces la aceste informaţii prin folosirea clauzei absolute.

Aceste informaţii pot fi obţinute datorită faptului că variabilele referitoare la fişiere şi cele referitoare la informaţii ocupă aceeaşi locaţie de memorie.

Caracteristici generale ale algoritmilor de prelucrare a fişierelor Pascal Organizarea datelor în fişiere pe suporţi externi de informaţii presupune proiectarea unor

algoritmi specifici operaţiilor de gestiune a acestora, denumiţi generic algoritmi de prelucrare a fişierelor de date. Datorită complexităţii aplicaţiilor care prelucrează fişiere este recomandată aplicarea metodei modularizării algoritmilor şi programelor. Modularizarea presupune ca, pe baza analizei problemei, să se descompună rezolvarea ei în părţi distincte, numite module, astfel încât fiecare dintre acestea să îndepliniească anumite funcţii. Descompunerea se poate realiza în mai multe faze (pe mai multe niveluri), prin metoda top-down. Criteriile de descompunere în module se refera la: omogenizarea funcţiilor; utilizarea diverselor structuri de date; separarea funcţiilor de intrare/iesire de funcţiile de prelucrare; utilizarea unor module deja existente; utilizarea eficientă a resurselor calculatorului. Modulele se implementează în program prin proceduri interne sau externe.

De cele mai multe ori o aplicaţie necesită existenţa mai multor fişiere active simultan, cu rol diferit (de intrare, de ieşire, de intrare/iesire). Indiferent de numarul fisierelor utilizate, în marea majoritate a algoritmilor, logica prelucrarii este coordonată, la un moment dat, de un singur fişier, obligatoriu de intrare, parcurs secvenţial, numit fişier conducător (sau director). Fişierul conducător are proprietatea ca articolele lui pot fi citite independent de prelucrarea altor fişiere. Accesul la datele memorate în fişierul conducător se realizează la nivel de articol. De aceea, algoritmii de prelucrare, indiferent de operaţia de gestiune, necesită utilizarea unei structuri repetitive pentru parcurgerea (parţială sau integrală) a fişierului.

Page 37: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

Algoritmii de prelucrare cu fişier conducător pot fi reprezentaţi printr-o schemă logică generalizată, concepută modularizat (figura 8.10).

Figura 8.10. Schema logică generală a unui algoritm de prelucrare cu fişier conducător

· Modulul ÎNCEPUT se realizează o singură dată, înaintea prelucrării primului articol al

fişierului conducător şi cuprinde următoarele grupe de operaţii: Operaţii iniţiale standard, obligatorii oricărui algoritm care includ: asignarea fişierelor logice

la fişiere fizice, deschiderea fişierelor şi pentru anumite variante, iniţializarea unei variabile boolene pentru sfârşit de fişier (SF) şi citirea primului articol.

Operaţii iniţiale specifice, facultative, existenţa lor depinzând de particularităţile problemei abordate care includ, în principal: iniţializări de variabile de total, afişări ale antetului, titlului şi/sau a capului de tabel pentru situaţii de ieşire etc.

· Modulul PRELUCRARE se execută repetitiv (în general, printr-o structură WHILE-DO) şi cuprinde, pe de o parte, totalitatea operaţiilor de prelucrare a articolului curent al fişierului conducător - operaţii specifice fiecărei probleme - şi, pe de alta parte, citirea unui articol din fişierul conducător. Ordinea celor două operaţii (citire şi prelucrare) depinde de varianta de algoritm aleasă.

· Modulul SFÂRSIT se execută o singură dată, după prelucrarea ultimului articol al fişierului conducător şi include următoarele grupe de operaţii: operaţii finale standard, corespunzând închiderii fişierelor implicate în prelucrare; operaţii finale specifice, care depind de natura problemei şi includ, de regulă: afişarea variabilelor de total, a statisticilor privind operaţiile de gestiune executate, închiderea situaţiilor de ieşire etc.

· Modalitatea de detectare/tratare a sfârşitului de fişier conduce la existenţa mai multor variante ale schemei generale de prelucrare cu fişier conducător, prin forme particulare ale condiţiei sfârsit_de_prelucrare. În funcţie de variantele alese, se pot construi scheme logice valabile pentru toate tipurile de fişiere sau numai pentru fişierele binare, scheme valabile pentru toate tipurile de fisiere

Detectarea sfârşitului de fişier independent de operaţia de citire, cu funcţia standard Eof, caz în care testarea sfârşitului de fişier trebuie să preceadă citirea unui articol. Dacă condiţia de sfârşit de prelucrare este testul asupra variabilei boolene SF, algoritmul va prevedea o citire iniţială în modulul ÎNCEPUT şi o citire curentă la sfârşitul modulului PRELUCRARE - varianta 1(figra 8.11).

Varianta se poate aplica fişierelor vide sau nevide. Când condiţia de sfârşit de prelucrare este chiar expresia (funcţia) Eof(f), algoritmul va include doar citirea curentă în debutul modului PRELUCRARE - variantele 2 si 3 (figura 8.12). Varianta 3 necesită existenţa cel puţin a unui articol (fişier conducător nevid), scheme logice valabile numai pentru fişierele binare.

302

Detectarea sfârşitului de fişier prin operaţia de citire, caz în care se generează eroare şi se întrerupe execuţia programului. Întreruperea programului se poate inhiba cu directive de compilare {$I-}, iar eroarea de intrare/ieşire se poate detecta cu funcţia standard IOResult. Algoritmul de

Page 38: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

303

prelucrare prevede o citire iniţială în modulul ÎNCEPUT şi citirea curentă în finalul modulului PRELUCRARE.

Figura 8.11. Schema logică varianta 1

Figura 8.12. Schema logică – variantele 2 şi 3

Testul de sfârşit al prelucrării poate fi constituit de însăşi funcţia IOResult - varianta 4 (figura 8.13.a) sau de variabila booleană SF, poziţionată la citirea marcatorului de sfârşit de fişier - varianta 5 (figura 8.13.b).

În ambele variante fişierul conducător este binar, vid sau nevid. În cazul în care fişierul este nevid (are cel puţin un articol), citirea iniţială poate să nu mai fie încadrată de directivele de compilare {$I-} si {$I+}.

Prelucrarea unui număr cunoscut de articole, prin determinarea în modulul ÎNCEPUT a numărului de articole din fişierul conducător, cu funcţia FileSize. Structura repetitivă de prelucrare devine o structură DO-FOR (varianta 6 – figura 8.14).

Fişierele utilizate într-o aplicaţie au rol diferit în procesul prelucrării, în funcţie de scopul lor: de intrare, de ieşire, de intrare/ieşire, temporare, de tip listă etc.

Aceste caracteristici conduc la algoritmi specifici fiecărei operaţii de gestiune în parte (creare/populare, consultare şi actualizare), fiind însă variante derivate din schema generală a unui algoritm de prelucrare cu fişier conducător.

Page 39: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

a. b.

Figura 8.13. Schema logică a. varianta 4; b. varianta 5.

Figura 8.14. Schena logică – varianta 6

8.6. TIPURI DINAMICE DE DATE

Datele de tip static au caracteristici care limiteazǎ rezolvarea unor clase de probleme. În

primul rând, spaţiul de memorie aferent unor astfel de date se defineşte şi se rezervǎ la dimensiune maximǎ, prestabilitǎ, ca spaţiu propriu care nu poate fi disponibilizat şi nici împǎrţit cu alte date, chiar dacǎ, în momentul diverselor execuţii ale programului, nu este în întregime utilizat (rezervare staticǎ sau la momentul compilǎrii). În al doilea rând, componentele structurilor statice ocupǎ locuri prestabilite în spaţiul rezervat, determinate de relaţia de ordonare specificǎ fiecǎrei structuri. În al treilea rând, limbajul defineşte operaţiile admise cu valorile componentelor, potrivit tipului de bazǎ al structurii, astfel încât numǎrul maxim şi ordinea componentelor structurii nu pot fi modificate. În aceste condiţii, structurile statice sunt dificil de utilizat în rezolvarea problemelor care prelucrazǎ mulţimi de date pentru care numǎrul şi ordinea componentelor se modificǎ frecvent în timpul execuţiei programului. Pentru astfel de situaţii, limbajul PASCAL oferǎ posibilitatea utilizǎrii datelor de tip dinamic, cǎrora li se pot aloca şi elibera zone de memorie pe parcursul execuţiei programului.

Lucrul cu adrese în Pascal

304

Page 40: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

305

Adresarea memoriei se realizeazǎ prin registre ale unitǎţii centrale, care au apacitatea de un cuvânt. La adresarea în modul real, pentru formarea unei adrese fizice din spaţiul de 1Mo este necesarǎ folosirea a douǎ registre: de segment (segment), care conţine adresa de început a segmentului, numitǎ şi adresa de bazǎ; de deplasare (offset), care precizeazǎ distanţa la care se aflǎ octetul adresat faţǎ de începutul segmentului. Astfel, orice adresǎ din memorie poate fi specificatǎ în formatul segment:offset sau, în alţi termeni, bazǎ:deplasare. Memoria este împǎrţitǎ în paragrafe de câte 16 octeţi, iar fiecare segment începe la graniţǎ de paragraf, adicǎ de la o adresǎ divizibilǎ cu 16. Într-un spaţiu de 1Mo sunt 216 paragrafe, adresa de început a unui segment, corespunzând unui numǎr de paragraf, poate fi reprezentatǎ ca o valoare pe 16 biţi. Adresele din segmentul curent se numesc apropiate (near), iar cele din afara acestuia sunt îndepǎrtate (far). Accesul la o adresǎ apropiatǎ presupune doar schimbarea conţinutului registrului de deplasare, în timp ce pentru o adresǎ îndepǎrtatǎ trebuie schimbatǎ atât valoarea registrului de segment, cât şi a celui de deplasare.

În unitatea System sunt definite functiile Seg(Var x):WORD, Ofs(VAR x):WORD care furnizeazǎ adresa de segment şi deplasarea variabilei, procedurii sau funcţiei x. În Pascal existǎ tipul de date pointer, memorat pe douǎ cuvinte, în care cuvântul superior (high) conţine partea de segment, iar cuvântul inferior (low) pe cea de deplasare asociate unei adrese. Pentru a se putea exemplifica modul de lucru cu adrese, se precizeazǎ faptul cǎ:

· tipul pointer se defineşte prin construcţia de forma ^tip; · adresarea indirectǎ a unei variabilei se defineşte prin construcţia identificator^; · referirea adresei unei variabile se defineşte prin construcţia @identificator. În sintaxa @identificator, identificator se referǎ la o variabilǎ, procedurǎ sau funcţie. Efectul

referirii @identificator este similar celui obţinut prin funcţia Addr definitǎ în unitatea System astfel: Addr(VAR x):pointer, unde x este variabilǎ, funcţie sau procedurǎ. Folosirea referirii identificator^ presupune existenţa unei adrese valide în variabila identificator.

Structura memoriei la execuţia unui program Dupǎ încǎrcarea programului executabil, memoria aferentǎ lui se structureazǎ în urmǎtoarele

regiuni (segmente): segmentul prefix program, regiunea de cod, segmentul de date, stiva şi zona heap. Pentru adresarea acestora, unitatea centralǎ de prelucrare foloseşte registre specializate, la unele dintre ele existând acces direct sau indirect.

• Segmentul prefix al programului (PSP) este o zonǎ de 256 de octeţi constituitǎ la încǎrcarea în memorie a fişierului de tip .EXE. Adresa de segment este memoratǎ în variabila publicǎ PrefixSeg, de tip WORD, definitǎ în unitatea System.

• Regiunea de cod este constituitǎ din mai multe segmente de cod: unul corespunzând programului principal, respectiv câte unul pentru fiecare unitate referitǎ în program. Registrul CS conţine adresa de start a instrucţiunilor programului, iar registrul IP (registru pointer al instrucţiunilor) precizeazǎ adresa urmǎtoarei instrucţiuni de executat. Programele Pascal nu au acces la registrul IP, dar valoarea curentǎ a registrului CS poate fi obţinutǎ cu funcţia CSeg.

• Segmentul de date este unic şi conţine constantele cu tip urmate de variabilele globale. Atunci când necesarul de memorie pentru datele interne depǎşeşte 64Ko, trebuie sǎ se recurgǎ la folosirea unor tehnici adecvate (memorarea datelor în heap sau pe medii externe, folosirea compactǎrii etc.).

• Segmentul de stivǎ, ca şi cel de date, poate avea maximum 64Ko, reducându-se la unul singur. Stiva este folositǎ în lucrul cu subprograme pentru memorarea parametrilor formali, variabilelor locale şi adreselor de revenire.

• Zona variabilelor dinamice, poate corespunde întregii memorii convenţionale a calculatorului, rǎmasǎ disponibilǎ dupǎ încǎrcarea programului. În heap se memoreazǎ variabilele dinamice, buffer-ele pentru structuri de reacoperire şi pentru lucrul în modul grafic. Adresa de început a zonei heap este datǎ de variabila publicǎ HeapOrg, iar adresa curentǎ este datǎ de variabila HeapPtr, ambele de tip pointer, definite în unitatea System. Alocarea variabilelor începe de la adrese mai mici cǎtre adrese mai mari, spaţiul maxim ce poate fi alocat unei variabile neputând depǎşi 64Ko (65520 octeţi), ca urmare a limitǎrilor impuse mecanismului de adresare a

Page 41: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

306

memoriei. Dupǎ modul lor de funcţionare, stiva şi heap-ul pot fi asimilate cu douǎ stive aşezate spate în spate. Programatorul poate controla repartizarea memoriei disponibile între stivǎ şi heap în faza de execuţie cu directiva de compilare {$M}, care are urmǎtoarea formǎ sintacticǎ: {$M StackSize,HeapMin,HeapMax}

StackSize trebuie sǎ fie un întreg din domeniul 1024 (1Ko) la 65520 (64 Ko), prin care se specificǎ mǎrimea segmentului de stivǎ. HeapMin şi HeapMax specificǎ dimensiunea minimǎ, respectiv maximǎ a heap-ului, teoretic cu valori între 0 si 640 Ko. Riguros, HeapMin poate avea valori de la 0 la 655360, iar HeapMax trebuie sǎ fie în domeniul de la HeapMin la 655360. Valorile implicite pentru aceşti parametri de alocare sunt {$M 16384,0,655360}.

Rezultǎ cǎ dimensiunea implicitǎ a stivei este de 16 Ko, iar zona de heap se extinde, teoretic, în tot spaţiul rǎmas liber în memoria convenţionalǎ. Practic, din dimensiunea de 640 Ko trebuie scǎzut, pe lângǎ spaţiul ocupat de programul însusi, cel corespunzǎtor componentelor sistemului de operare rezidente în memorie pe parcursul executiei.

Tipuri dinamice de date În Pascal se opereazǎ cu douǎ tipuri de date dinamice - referinţǎ şi pointer - primele fiind "cu

tip" iar celelalte "fǎrǎ tip". · Tipul referinţǎ are sintaxa: tip_referintǎ=^tip_de_bazǎ; Simbolul ^ are semnificaţia de "indirect". Datoritǎ asocierii cu un tip de bazǎ, variabilele

tip_referintǎ se mai numesc şi variabile cu referinţǎ legatǎ. La compilare, pentru astfel de variabile, se vor rezerva în segmentul de date douǎ cuvinte şi la referirea lor se vor genera instrucţiuni cod maşinǎ conform tipului de bazǎ, dar cu adresare indirectǎ. Înainte de referire, în variabilele de tip_referintǎ trebuie sǎ se încarce adresele variabilelor de tipul tip_de_bazǎ. Declararea unui tip referinţǎ permite referirea anterior declarǎrii tipului de bazǎ. Astfel, urmǎtoarea secvenţǎ de declarǎri este corectǎ: TYPE pointer_a=^vector; vector=ARRAY[1..20] OF REAL;

Construcţia sintacticǎ a referirii unei variabile dinamice depinde de caracteristicile tipului sǎu de bazǎ: este de forma identificator^ în cazul tipurilor nestructurate sau celor structurate care permit referirea globalǎ (STRING, RECORD şi SET); conţine prefixul identificator^, urmat de elementele specifice modului de referire a componentelor, în cazul tipurilor structurate care permit referirea pe componente (ARRAY, STRING şi RECORD).

· Tipul pointer este desemnat prin cuvântul rezervat pointer. Variabilele de tip pointer pot fi denumite variabile cu referintǎ liberǎ, deoarece pot fi folosite la memorarea adreselor pentru variabile de orice tip. Tehnica de lucru cu astfel de variabile este asemǎnǎtoare celei prezentate la tipul referinţǎ. Utilizarea efectivǎ presupune o asociere explicitǎ cu un anumit tip de bazǎ, dar soluţia folositǎ este diferitǎ. La tipul referinţǎ, asocierea se face prin declarare, iar în cazul tipului pointer asocierea se realizeazǎ la utilizare, prin diverse tehnici. O posibilitate este asiguratǎ de referinta typecasting (transfer de tip), care are forma generalǎ: tip(variabilǎ), unde tip este un tip standard sau declarat anterior de utilizator iar variabilǎ poate fi cu/fǎrǎ tip sau o referinţǎ prin pointer, de forma variabilǎ_pointer^.

Din punct de vedere fizic, variabilele de tip referintǎ_legatǎ şi pointer memoreazǎ adrese sub forma segment:offset. De aceea, în limbajul curent de specialitate, ambele tipuri se definesc prin termenul pointer. Urmǎtorul evemplu evalueazǎ expresia e:=a+b, folosind adresarea indirectǎ pentru toate variabilele (a şi e prin referintǎ_cu_tip iar b prin pointer):

VAR a,b,e:REAL; pa,pe:^REAL; pb:POINTER;

BEGIN pa:=addr(a); pb:=@b; pe:=@e;

Write(‘A=); ReadLn(pa^); Write(‘B=’); ReadLn(REAL(pb^)); pe^:=pa^+REAL(pb^); WriteLn(‘E= ‘,pe^:8:2))

END.

Page 42: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

307

Variabilele pointer (referinţǎ sau pointer) pot fi puse în relaţie cu operatorii = şi < >. Douǎ variabile vor fi egale dacǎ au componentele segment, respectiv offset egale. De remarcat faptul cǎ douǎ variabile de tip pointer care indicǎ aceeasi adresǎ pot fi neegale, deoarece le diferǎ componentele. Variabilele pointer pot fi folosite în atribuiri. Atât în relaţii cât şi în atribuiri sunt definite urmǎtoarele clase de compatibilitate: tipul referinţǎ este compatibil cu orice alt tip dinamic; douǎ variabile de tip referinţǎ sunt compatibile dacǎ sunt de acelaşi tip.

Observaţie: pa şi pb nu sunt de acelaşi tip dacǎ sunt declarate astfel: pa:^real; pb:^real. Ele sunt de acelaşi tip dacǎ sunt declarate astfel: pa,pb:^real.

Este definitǎ o constantǎ simbolicǎ (nil) cu semnificaţie de valoare nulǎ a tipului dinamic (valoarea nil nu puncteazǎ o zonǎ de memorie).

Utilizarea zonei heap Noţiunea de dinamic este strâns legatǎ de utilizarea zonei de memorie heap (deşi tipul

dinamic poate fi asociat variabilelor memorate în orice componentǎ a memoriei principale). În unitatea System sunt definite urmǎtoarele variabile de tip pointer, care pot fi folosite în

gestionarea zonei heap: HeapOrg, HeapPtr, HeapEnd, HeapError, FreeList. HeapOrg puncteazǎ pe adresa de început a zonei heap, iar HeapEnd dǎ adresa de sfârşit a

heap-ului. HeapPtr conţine urmǎtoarea adresa disponibilǎ din heap. Ea este variabila prin care se

gestioneazǎ fiecare nouǎ alocare, punctând pe prima adresǎ disponibilǎ din heap. Toate procedurile de alocare (New, GetMem, Mark) lucreazǎ cu aceastǎ variabilǎ. HeapError corespunde adresei rutinei de tratare a erorilor de alocare pentru variabile dinamice. FreeList serveşte la gestiunea blocurilor devenite libere în interiorul heap-ului, punctând pe primul bloc liber în heap, care puncteazǎ pe al doilea. Ultimul bloc liber puncteazǎ pe vârful heap-ului, adicǎ pe locatia datǎ de HeapPtr, asigurându-se astfel posibilitatea realocǎrii acestor spaţii. Dacǎ în interiorul heap-ului nu existǎ blocuri libere, atunci FreeList va fi egalǎ cu HeapPtr.

În unitatea System sunt definite o serie de proceduri şi funcţii care pot fi utilizate în lucrul cu variabilele dinamice. Procedurile GetMem(p,n), FreeMem(p,n), respectiv New(p) şi Dispose(p) se folosesc pentru a aloca /elibera un bloc a cǎrui adresǎ este datǎ de variabila pointer sau referintǎ, p.

Deoarece zona heap este limitatǎ, iar alocarea şi eliberarea dinamicǎ determinǎ alternanţa unor zone libere cu cele ocupate, este necesarǎ cunoasterea spaţiului disponibil şi a spaţiului contiguu maxim disponibil.

În acest scop pot fi folosite funcţiile (fǎrǎ argumente, cu rezultat de tip LONGINT) MemAvail (pentru spaţiul total disponibil) şi MaxAvail (pentru spaţiul contiguu maxim disponibil).

Iniţial, rezultatul furnizat de MemAvail corespunde dimensiunii totale a heap-ului, care poate fi obţinutǎ şi prin aplicarea formulei (Seg(HeapEnd^)-Seg(HeapOrg^))*16, întrucât adresele de început şi de sfârşit ale heap-ului sunt exprimate ca numere de paragraf. Aceastǎ dimensiune conicide iniţial cu cea furnizatǎ de funcţia MaxAvail, care precizeazǎ cel mai lung bloc de locaţii de memorie contigue disponibile în heap. Se poate determina dacǎ spaţiul disponibil este contiguu, pe baza expresiei relaţionale MemAvail = MaxAvail. Dimensiunea în octeţi ocupatǎ de o variabilǎ poate fi obţinutǎ cu funcţia SizeOf(VAR x):WORD, unde x este identificator de variabilǎ.

Se poate stabili dacǎ spaţiul disponibil este acoperitor pentru o variabilǎ de un anumit tip, scriind o relaţie de forma MaxAvail >= SizeOf (tip).

· Alocarea şi eliberarea zonelor pentru variabile referintǎ_legatǎ se face cu procedurile New, respectiv Dispose, definite în unitatea System astfel:

New(VAR p:pointer), Dispose(VAR p:pointer). Procedura New rezervǎ în heap o zonǎ de memorie de lungime egalǎ cu cea indicatǎ de tipul

de bazǎ şi încarcǎ în variabila p adresa acestei zone. Existǎ douǎ niveluri de rezervare: staticǎ (corespunzǎtoare lui px) şi dinamicǎ (datoratǎ procedurii New(px), care rezervǎ variabila în heap, în conformitate cu tipul de bazǎ). Din punct de vedere fizic, operaţia realizeazǎ memorarea în variabila p a valorii HeapPtr şi avansarea acesteia din urmǎ cu lungimea specificǎ tipului de bazǎ.

Dacǎ nu existǎ o zonǎ contiguǎ disponibilǎ de lungime mai mare sau egalǎ cu cea necesarǎ se genereazǎ eroare de execuţie. Procedura Dispose elibereazǎ zona alocatǎ variabilei. Urmǎtorea

Page 43: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

308

alocare se poate face pe spaţiul eliberat, dacǎ este acoperitor ca lungime. Fizic, se reface în HeapPtr valoarea de dinaintea alocǎrii prin New.

Prin posibilitatea de generare a unor succesiuni de valori de acelaşi tip, de la simpla alocare dinamicǎ de spaţiu pentru o singurǎ valoare a unei variabile se poate trece la realizarea unor structuri dinamice de date.

Acest lucru este posibil pe baza înlǎnţuirii succesiunilor de valori, ca urmare a includerii la fiecare element al structurii a douǎ pǎrţi:

o parte de informaţii, corespunzând valorii propriu-zise a elementului; o parte de legǎturǎ, care va conţine adresa urmǎtorului element.

· Alocarea şi eliberarea zonelor pentru variabile de tip pointer se realizeazǎ cu procedurile GetMem, respectiv FreeMem, definite în unitatea System astfel:

GetMem(VAR p:pointer; l:WORD), FreeMem(VAR p:pointer; l:WORD). Efectul acestora este asemǎnǎtor procedurilor New şi Dispose, cu precizarea cǎ este necesarǎ

specificarea lungimii, care nu poate fi dedusǎ implicit, neexistând un tip de bazǎ. Spaţiul alocat la un apel al procedurii GetMem corespunde dimensiunii articolului (6 octeti). · Ca alternative ale procedurilor New, GetMem, respectiv Dispose, FreeMem, pot fi folosite

procedurile Mark şi Release, definite în unitatea System astfel: Mark(VAR p:pointer), Release(VAR p:pointer). Procedura Mark memoreazǎ în variabila p valoarea din HeapPtr, iar procedura Release

depune în variabila HeapPtr conţinutul variabilei p. Folosirea în pereche a procedurilor Mark şi Release oferǎ posibilitatea ca dupǎ diverse alocǎri sǎ se restabileascǎ valoarea variabilei HeapPtr cu valoarea memoratǎ prin Mark.

Apelul Release(HeapOrg) aduce HeapPtr pe începutul zonei heap (elibereazǎ zona). În exemplul urmǎtor, se memoreazǎ în y adresa de la un moment dat a lui HeapPtr (fie ea a),

se modificǎ HeapPtr prin rezervarea a 12 octeţi (pentru x2, x3), se reface conţinutul lui HeapPtr cu adresa a, ceea ce înseamnǎ cǎ x3^ se rezervǎ la aceastǎ adresǎ (în locul variabilei x2^). VAR

x1,x2,x3.x4:^REAL; y:POINTER;

BEGIN New(x1); x1^:12; Mark(y); {Memorarea valorii HeapPtr in Y} New(x2); x2^:=10; New(x3); x3^:=34; Release(y); {Reincarcarea valorii din Y in Heapptr} New(x4); x4:=46; {Se va memora peste valoare 10 din x2}

O altă facilitate a limbajului consta în posibilitatea utilizării tipurilor care se autoreferă (sunt definite recursiv). Tipul reper "listă" reperează un tip "articol", în care câmpul "următor" la rândul lui este de asemenea de tip "lista". Aceasta facilitate poate fi folosită de exemplu la alcătuirea listelor înlănţuite. După crearea unei variabile dinamice a cărei adresă este depusă într-o variabilă de tip reper, ea poate fi accesată prin aşa zisa dereperare: numele variabilei de tip reper este urmat de semnul ^. Acest semn poate fi urmat şi de un alt calificator (de câmp, de tablou, etc.).

8.7. UNITĂŢI DE PROGRAME

Unitǎţile de program (UNIT-uri), stau la baza programarii modulare în Turbo- Pascal. Ele sunt folosite pentru a crea biblioteci ce pot fi incluse în diferite programe. Programele

mari se pot împarţi în module logice create şi testate separat. Unit-ul este o colecţie de constante predefinite, declaraţii de tip si variabile, funcţii şi

proceduri, care sunt stocate în forma compilatǎ şi este recunoscut dupǎ identificatorul de nume, care are extensia .TPU

Page 44: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

309

Incorporarea Unit-urilor în programul Turbo-Pascal, se realizează cu instrucţiunea USES, plasată în prima linie de program, dupǎ linia de titlu PROGRAM (dacǎ aceasta existǎ).

Formatul general al instructiunii USES este: USES Nume_unit1[,Nume_unit2,...]; unde: Nume_unit1, Nume_unit2,... - reprezintǎ numele Unit-urilor ce vor fi incorporate în

program. La întâlnirea acestei instrucţiuni, compilatorul pregateste incorporarea în program a unit-ului

specificat în USES, astfel: A - caută unit-urile specificate în fişierul Turbo.TPL. Dacǎ acesta este găsit, este încărcat în

memoria centrală şi astfel codurile obiect sunt incorporate în program; B - dacă unit-ul nu se găseşte în Turbo.TPL, compilatorul caută în catalogul de unităţi un

fişier cu numele unit-ului şi extensia .TPU. Dacă este găsit, se realizează paşii de la punctul A. C - dacă nu-l gaseşte, compilatorul caută un fişier sursǎ cu numele unit-ului şi extensia .PAS.

Daca îl găseşte , acesta va fi compilat şi-l va include în program; D - dacă un astfel de fişier nu exista, este semnalată eroarea. În Turbo-Pascal se pot folosi două categori de Unit-uri: - unit-uri STANDARD - puse la dispoziţie de mediul Turbo-Pascal; - unit-uri NESTANDARD - create de utilizatori. Unit-urile STANDARD sunt urmatoarele: - unit-ul SYSTEM, conţine toate funcţiile şi procedurile de bază din Turbo-Pascal. Acest

unit se încarcă automat. - unit-ul DOS, conţine proceduri şi funcţii echivalente cu funcţiile DOS cele mai

utilizate. - unit-ul OVERLAY, conţine proceduri şi funcţii care permit gestionarea segmentelor de

program pentru proiectarea programelor mari. - unit-ul CRT, conţine proceduri şi funcţii pentru folosirea ecranului în mod alfanumeric şi a tastaturii. - unit-ul GRAPH, conţine proceduri şi funcţii, pentru folosirea ecranului în mod grafic. - unit-ul PRINTER, conţine funcţiile de lucru cu imprimanta. - unit-urile GRAPH3,TURBO3, care permit folosirea programelor mari scrise în Turbo-

Pascal versiunea 3.0. Unităţile STANDARD sunt pastrate în fişierul bibliotecă Turbo.TPL Actualizarea acestui fişier se poate face cu programul utilitar TPUMOVER.EXE. Unit-urile NESTANDARD, sunt acele unit-uri create de utilizatori, în care sunt incluse

proceduri şi funcţii proprii utilizatorului. Crearea unui unit propriu, necesita următoarele etape: - editarea unit-ului; - compilare in memorie şi eliminarea erorilor de compilare;

- salvarea Unit-ului editat şi compilat în memorie sub un nume de fişier (care va fi numele unit-ului), cu extensia .PAS;

- compilarea fişierului pe disc, obţinându-se fişierul cu extensia .TPU Dupǎ creare, unit-ul poate fi incorporat în program, folosind instructiunea USES. Editarea Unit-ului Initial programatorul editeaza textul unui unit într-un fişier sursǎ nume_unit.PAS. Pentru a edita unit-ul, se deschide un fişier folosind opţiunea OPEN din meniul FILE (F10,

File, Open, sau ALT-F,O), şi se introduce numele viitorlui UNIT. Se deschide o fereastră de editare cu numele UNIT-ului, în care se va edita codul sursă într-o

anumită structurǎ. Structura unui unit consta din: - titlul Unit-ului (UNIT HEADING);

Page 45: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

310

- secţiunea INTERFACE - care conţine lista de declaraţii de constante, tipuri, variabile, proceduri şi funcţii; - secţiunea IMPLEMENTATION - care conţine codul sursă a procedurilor şi funcţiilor declarate în secţiunea INTERFACE;

- secţiunea INITIALIZATION - care conţine instrucţiuni pe care Turbo-Pascal-ul le execută la prima apelare a Unit-ului, respectiv la linia finală din programul principal.

Forma generala în limbajul Turbo-Pascal a unui Unit este: UNIT Nume_unit; INTERFACE uses {lista unit-urilor folosite} {declaratii globale } {lista de proceduri si functii globale} IMPLEMENTATION {declaraţii locale de etichete} {declaratii locale de constante} {declaraţii locale de tipuri} {declaraţii locale de variabile} {proceduri şi funcţii} [ begin {iniţializare} {instrucţiuni} ] {opţional} end. {sfârşit iniţializare şi unitate} Numele unităţii Nume_unit , este identificatorul unităţii utilizat în clauza USES. Numele acestor unităţi trebuie să difere între ele. Lista unit-urilor folosite, este lista numelor unităţilor utilizate de unitatea curentă. Ordinea

unităţilor este oarecare, exceptând cazul când o unitate apeleaza pe alta; atunci unitatea apelată trebuie să preceadă unitea apelantă.

Declaraţiile globale, conţin declaraţii de constante, tipuri şi variabile accesibile altor unităţi. Lista de funcţii şi proceduri, cuprinde antetele funcţiilor şi procedurilor accesibile altor

unităţi. Procedurile şi funcţiile conţin declaraţiile procedurilor şi funcţiilor locale sau globale şi corpul

acestora cu zona de instrucţiuni cuprinsă între Begin şi End. Secvenţa de iniţializare cuprinde instrucţiunile care trebuiesc executate înainte de declanşarea

execuţiei programului principal. Exemplu: Unit Mate; {O+F+} INTERFACE function fact(x:integer):longint; IMPLEMENTATION function fact(x:integer):longint; var f:longint; i:integer; begin f:=1; for i:=2 to x do f:=f+i; fact:=f; end end. Incorporarea acestui unit într-un program se realizează cu linia USES Mate; Program calcule; uses mate; var NFact:longint;

Page 46: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

311

- - - - - - begin - - - - - - NFact:=Nfact(10); - - - - - - end. Programul apelează funcţia Fact(10) care este definită în unitul Mate. Compilarea în memorie şi eliminarea erorilor la compilare. După terminarea editarii se verifică dacă opţiunea de compilare Compile din meniul

COMPILE, este setată pe MEMORY după care se efectuează complilarea (ALT+F9 sau ALT+F,C). Daca în timpul compilării apar erori, acestea se vor corecta şi se va relua compilarea. Rezultatul compilării unit-ului editat, este fişierul nume_unit.PAS. Salvarea Unit-ului compilat sub numele viitorului unit (nume folosit la OPEN) se realizează

cu opţiunea Save din meniul FILE (F2 sau ALT+F,S) Se obţine fişierul cu numele nume_unit.Pas Compilarea Unit-ului Se procedează la setarea opţiunii Compile pe Compile Disk (din meniul Compile ALT+F10,C

sau ALT+F9) Se obţine fişierul nume_unit.TPU, care reprezintă fişierul obiect al unit-ului. Când se efectuează modificări în partea de implementare, sau de iniţializare a unui unit,

unităţile care-l utilizează trebuiesc recompilate. Când se efectuează modificări în interfaţa unit-ului, trebuiesc recompilate toate unit-urile care

la rândul lor o utilizează. Acest lucru se efectuează automat cu Compile Built şi Make din meniul Compile. Comanda Make, compară data creării fişierului sursă (.PAS) şi obiect (.TPU) ale unităţilor

folosite şi le recompilează pe cele care au fost modificate dar nu au fost compilate din nou. Comanda Built, recompilează toate unităţile indiferent de data creării. Codul obiect generat pentru fiecare Unit, nu trebuie să depasească 64k, fiid limitat de

dimensiunea unui segment în care trebuie să se încadreze. Organizarea programelor mari. Fişiere incluse. Editorul Turbo Pascal poate trata programe a caror text nu depaseste 64K. Programele mai mari trebuiesc împărţite în mai multe fişiere, a căror grupare poate fi realizată

prin directive de includere. Un exemplu este dat în programul următor, dispus în două fişiere diferite. Fişierul inclus Proc.inc conţine textul:

Procedure ListareFisier; Var i : integer; Begin ....corp procedura .... End.

Fişierul principal Princ.pas conţine: {$I Proc.inc} Begin ListareFisier; End;

Directiva $I face ca Turbo Pascal să trateze conţinutul fişierului Proc.inc ca parte a programului, plasată chiar în poziţia directivei.

Forma generala a directivei de includere este : {$I nume_fisier_inclus} unde: nume_fisier_inclus este identificatorul unui fişier conţinând un text sursă Pascal. Dacǎ numele nu este însoţit de extensie, Turbo Pascal considerǎ implicit extensia .Pas.

Page 47: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

312

Stive şi cozi Listele, implementate dinamic, sunt foarte utile atunci când se lucrează cu multe informaţii,

pe care vectorii se dovedesc incapabili a le stoca, sau ineficienţi. Un caz particular de liste (simplu înlănţuite) îl constituie stivele şi cozile. Acestea

implementează două mecanisme diferite de intrare şi ieşire a elementelor din lista. La ambele feluri de liste, un nod al listei este o înregistrare ce conţine o informaţie (info), precum şi un pointer (indicator) către următorul element al listei (prec sau urm).

. Stiva este o structurǎ dinamicǎ de date reprezentatǎ de o listǎ simplu înlǎnţuitǎ în care mecanismul de intrare-ieşire a elementelor este de tip LIFO – Ultimul intrat este primul ieşit (last in – first out). Este de ajuns un pointer către primul element al stivei, pentru a realiza atât operaţia de adăugare a unui element (numită Push), cât şi cea de eliminare (Pop), deoarece ambele operaţii se realizează prin partea superioară a listei.

. Coada este o structurǎ dinamicǎ de date reprezentatǎ de o listǎ simplu înlǎnţuitǎ în care mecanismul de intrare-ieşire a elementelor este de tip FIFO – primul intrat este primul ieşit (first in – first out). În cazul cozii, avem nevoie de doi pointeri, unul către primul element al cozii (capul cozii), iar altul către ultimul său element (coada cozii), deoarece introducerea în listă se face prin spate, iar eliminarea prin faţă. (Există şi o variantă de coadă circulară, în care elementele sunt legate într-un cerc, iar cei doi pointeri, indicând capul şi coada cozii, sunt undeva pe acest cerc.).

Liste dublu înlǎnţuite În cazul listelor dublu înlănţuite avem, spre deosebire de stive şi cozi, următoarele noi

elemente: • există doi pointeri speciali: început şi sfârşit care pointează către două celule extreme ale

listei, dar care nu fac parte din listă; ei se numesc santinele, • există un pointer numit curent care indică întotdeauna elementul curent din listă; • fiecare element a listei este legat prin doi pointeri (prec şi urm) de elementele dinaintea şi

de după el din cadrul listei; • avem un câmp lungime, care va indica lungimea listei. Operaţiile ce se cer a se efectua cu o astfel de listă sunt:

• iniţializarea listei; • adăugarea unui element ta sfârşitul listei; • inserarea unui element înaintea elementului curent din listă; • ştergerea elementului curent din listă. • afişarea listei.

Când se adaugă sau se inserează un nou element în listă, acel element devine cel curent. Când elementul curent se şterge din listă, locul său este preluat de elementul care îl succeda, în cadrul listei. În momentul în care se introduce sau se eliminǎ un element din listă, dispar unele legături şi apar altele. Procese aproape inverse se realizează la eliminarea elementului curent din listă. Fireşte, acest lucru se poate realiza doar dacă lista nu este vidă. Pentru a elibera efectiv zona de memorie ocupată de elementul eliminat, se apelează procedura Dispose. Eliminarea elementului curent va presupune legarea elementului ce-l precede cu cel ce îl succede. Succesorul elementului eliminat devine element curent, iar lungimea listei scade cu o unitate.

Arbori binari. Arborescenţe în digrafuri Fie H=(V,E) un digraf (graf orientat). Se numeşte rădăcină a lui G un vârf V0ЄV astfel încât

oricare ar fi un vârf vЄV, există cel puţin un drum de la V0 la v. Dacă H=(V,E) este un digraf, prin graful suport al lui H vom înţelege graful obţinut din H, prin renunţarea la orientarea arcelor. H se numeşte arborescentă dacă are o rădăcină şi graful său suport este arbore.

În informatică, arborescentele sunt numite, prin abuz de limbaj, arbori, specificându-se rădăcina şi considerând implicită orientarea muchiilor corespunzător parcurgerii drumului unic de la rădăcină la fiecare vârf. Fiecare vârf are astfel nişte fii, adică vecinii imediat următori pe drumul de la rădăcină în jos (către frunze, adică noduri fără fii). Un arbore cu cel mult doi fii se, mai numeşte şi arbore binar. Se pote considera arborele ca fiind organizat pe mai multe niveluri. Primul nivel

Page 48: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

313

este cel al rădăcinii. Urmează nivelul fiilor acesteia şi tot aşa până la ultimul nivel, cel al ultimelor frunze.

Referirea unui arbore binar şi, implicit, definirea sa, pote fi făcută printr-un pointer către nodul său rădăcină. Fiecare nod din arbore este o înregistrare cu următoarele elemente:

• o informaţie info de tip întreg; • doi pointeri către cei doi fii (subarborii stâng şi drept) ai nodului: stg şi dr. În programul care urmează, vom construi astfel de arbori, care au în plus următoarea

proprietate: fiecare nod din arbore este mai mare sau egal cu nodurile din fiul stâng şi mai mic decât nodurile din fiul drept (din punct de vedere al câmpului info). Un astfel de arbore se numeşte arbore de căutare - sortare,

O căutare a unui element în astfel de arbori este într-adevăr uşor de realizat: dacă elementul căutat este identic cu informaţia din nod, atunci căutarea se încheie cu succes, dacă nu, atunci se pleacă pe una din cele două direcţii: dacă elementul căutat este mai mic, atunci se merge pe fiul stâng, altfel pe fiul drept. Dacă se încearcă o trecere dincolo de un nod terminal, deci la nil, atunci căutarea eşuează.

Un arbore binar poate fi parcurs în trei feluri: • în inordine se parcurge mai întâi, recursiv, în inordine, fiul stâng, apoi rădăcina, apoi fiul

drept; • în postordiner se parcurge fiul stâng, apoi cel drept, în final rădăcina; • în preordine se parcurge rădăcina, fiul stâng şi apoi fiul drept. Se observă că parcurgerea în inordine a unui astfel de arbore duce la afişarea în ordine

crescătoare a elementelor din nodurile arborelui, motiv pentru care astfel de arbori pot fi consideraţi şi de sortare.

Memorarea arborilor oarecare în arbori binari se realizează dacă legăm rădăcina 1 de nodul 2, iar apoi, nodul 2 poate fi legat de primul fiu al său (21) şi de următorul fiu al rădăcinii, deci 3, despre care se spune că este un frate a lui 2. Procedând astfel pentru toate nodurile din arbore, vom obţine un arbore binar, cu două legături: cea din stânga este către primul fiu, iar cea din dreapta către primul frate din dreapta al acestui fiu.

Arborii oarecare se vor memora sub forma unei structuri ce conţine o informaţie info (de tip Integer), un numǎr de fii (NrFii), precum şi un vector de pointeri (referinţe) cǎtre toţi fii nodului în cauzǎ (fiu: array[1..max] of arbore).

8.8 PROGRAMAREA ORIENTATĂ SPRE OBIECTE

O tendinţă naturală în evoluţia limbajelor de programare este de a pune în corespondenţă

obiectele acestei realităţi cu reprezentări cât mai fidele la nivelul limbajului. Limbajele orientate spre obiecte elimină neajunsurile menţionate prin includerea conceptelor

de încapsulare şi moştenire, pentru caracterizarea acestor limbaje care sugerează că reprezentarea obiectelor în limbaj se apropie tot mai mult de realitatea acestora.

Încapsularea realizeaza "fuziunea" dintre datele şi procedurile caracteristice unui obiect, într-o structură unică ce-l caracterizează static şi comportamental. Moştenirea permite captarea unor mecanisme naturare ca specializarea, abstractizarea, aproximarea şi evoluţia. Moştenirea poate fi folosită pentru organizarea mai bună a prelucrărilor.

Primul limbaj orientat spre obiecte, Simula, a fost dezvoltat la mijlocul anilor '60. Atât el, cât şi următorul sistem reprezentativ pentru programarea orientată spre obiecte, Smalltalk-80 nu au cunoscut o răspândire semnificativă până la mijlocul anilor '80. Odată cu ameliorarea suportului tehnologic, limbajele orientate spre obiecte au fost acceptate de tot mai mulţi programatori, aparând totodată şi alte limbaje orientate spre obiecte ca C++ sau Turbo Pascal 5.5, 6.0 şi7.0.

Programarea orientată spre obiecte este o tehnică de programare, iar un limbaj de programare orientat spre obiecte are mecanismele-suport necesare acestui stil de programare. Limbajul este înzestrat cu elementele care fac programarea orientată spre obiecte suficient de comodă.

Page 49: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

314

Unitatea grupează datele şi procedurile de prelucrare a lor, cu următoarele efecte: -ascunde utilizatorului unităţii amănuntele de implementare a listei (încapsulare); -furnizează o interfaţăa clară de acces la listă, doar prin procedurile şi funcţiile definite; -face iniţializarea listei.

Utilizând tehnica modularizării, sunt posibile următoarele soluţii: -modificarea unităţii de program lista, astfel încât să gestioneze un număr oarecare de liste, nu doar una singură; -utilizarea unei unităţi separate, cu acelaşi conţinut dar cu nume diferit, pentru gestionarea unei a doua liste,

Ambele soluţii sunt incomode, problema având o tratare greoaie dacă se utilizeaza tehnica modularizarii programelor.

Versiunile 5.5, 6.0 şi 7.0 ale limbajului Turbo Pascal, ca şi alte limbaje care suporta mecanismele programarii orientate spre obiecte, permit rezolvarea simplă şi elegantă a problemelor.

Definirea obiectelor Deşi programarea orientată spre obiecte este un stil de programare -fundamental deosebit de

cel tradiţional, construcţiile sintactice ale limbajului Turbo Pascal care o facilitează pot fi înţelese ca "extinderi" ale unora mai vechi. Astfel, asocierea dintre datele caracteristice unor subprobleme şi procedurile de prelucrare a lor nu este nouă, ea fiind întâlnită şi în cazul unităţilor de program. În cazul obiectelor, programatorul are posibilitatea să definească această asociere în forma unui tip, care se comportă aproape la fel ca celelalte tipuri ale limbajului, cum ar fi înregistrările: se pot declara variabile având tipul respectiv şi se pot realiza prelucrări cu ele. Acest nou tip poartă numele de object.

Obiectul conţine declaraţii atât pentru date, cât şi pentru proceduri şi funcţii, într-o formă similară definirii unei înregistrări. Procedurile şi funcţiile declarate într-un obiect se numesc metode. Obiectul cuprinde doar antetul metodelor, blocurile asociate lor urmând a fi specificate separat. Câmpurile de date sunt definite ca în înregistrări, prin selectorul şi tipul fiecăruia.

O metodă este identificată prin numele obiectului la care se referă, urmat de un punct şi de numele procedurii sau al funcţiei, după tiparul notaţiei unui câmp de înregistrare. În schimb, în blocul metodei, câmpurile de date sunt referite doar prin selector, ca şi cum acesta s-ar afla sub incidenţa unei instrucţiuni with referitoare la obiectul corespunzator.

Odată ce a fost definit un object, pot fi declarate instante ale sale. Acestea pot fi valorile unor variabile-obiect statice, declarate în maniera cunoscută (declaraţia var), sau ale unor variabile dinamice create prin aplicarea procedurilor predefinite new şi getmem unor variabile referinţe la obiectul declarat.

O astfel de modificare directă a câmpurilor unei instanţe nu este în concordanţă cu stilul programării cu obiecte, care recomandă folosirea exclusivă a metodelor. Apelul unei metode are forma uzuală a apelului oricarei proceduri sau funcţii, cu observaţia ca numele metodei este prefixat de numele variabilei căreia i se aplică.

Observaţie. Terminologia adoptată în Turbo Pascal diferă de cea a altor limbaje orientate spre obiecte. Astfel, în C + + , se utilizează denumirile clasa (pentru un tip obiect) şi obiect (pentru o instanţă). Turbo Pascal este mai conservator, denumirile adoptate fiind în concordanţă cu noţiunile mai vechi ale limbajului. Prin urmare, se vorbeşte despre un tip object în acelaşi mod în care ne referim la un tip înregistrare şi despre o variabilă obiect la fel ca despre o variabilă înregistrare.

Variabilele obiect pot fi iniţializate cu ajutorul declaraţiei const, similar altor variabile. Deoarece iniţializarea se referă doar la câmpurile obiectelor nu şi la metode, iniţializarea variabilelor obiect are aceeaşi formă cu iniţializarea variabilelor înregistrare: numele instanţei insoţit de tip şi de lista valorilor iniţiale ale câmpurilor, inclusă între paranteze rotunde. Valoarea iniţială a unui câmp este precedată de selectorul acestuia.

Unul din scopurile programării orientate spre obiecte este utilizarea obiectelor ca entităţi complete, de sine stătătoare: niciunul din câmpurile unui obiect nu trebuie să fie direct accesibil utilizatorului, orice operaţie asupra sa realizându-se prin intermediul metodelor. Metodele trebuie să

Page 50: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

315

alcătuiasca un set cât mai complet de operaţii relative la object. Metodele permit testarea şi actualizarea oricărui câmp al obiectului, eliminând necesitatea adresării directe la câmpurile acestuia.

Odată cu definirea metodelor, descrierea obiectului este încheiată şi poate fi utilizată ca atare în orice program. Deoarece utilizatorul nu este interesat în modul de realizare a metodelor, ci doar în comportarea lor, descrierea unui object se încadrează foarte bine într-o unitate de program, declaraţia obiectului fiind plasată în partea de interfaţă, iar definiţiile metodelor în partea de implementare.

Utilizatorul are la dispoziţie un set complet de metode pentru prelucrarea câmpurilor obiectului, accesul direct la aceste câmpuri nu este îngrădit, deoarece ele sunt declarate în partea de interfaţă, la fel ca metodele. Versiunea 6 a limbajului Turbo Pascal permite însă divizarea declaraţiei obiectului în două secţiuni: una publică, accesibilă din afara obiectului şi una privată, accesibilă doar în cadrul obiectului, inclusiv în declaraţiile metodelor sale. Se asigură astfel o protecţie a câmpurilor şi metodelor private. Prin aceasta, se elimină posibilitatea manevrării lor incorecte, prin acţiuni din afara obiectului, de îndată ce metodele care au acces la ele sunt puse la punct. Secţiunea privată este specificată prin cuvântul cheie private şi se află după secţiunea publică a obiectului.

Definiţia unui obiect începe cu declararea elementelor publice, urmată de secţiunea privată. Aceasta este indicată de cuvântul cheie private, urmat de declaraţiile corespunzătoare. Există

şi situaţii în care şi unele metode sunt dispuse în zona privată. Acestea devin inaccesibile din afara obiectului.

Includerea unor structuri de date în altele este un procedeu obişnuit de realizare a unor structuri complexe. O astfel de imbricare nu este permisă în cazul obiectelor. Există totuşi un mecanism prin care un object să moştenească componentele altui obiect, declaraţia primului trebuie să facă o referire la cel de-al doilea obiect.

Definirea metodei init într-un obiect face ca metoda init a strămoşului său să nu mai fie moştenită, fiind astfel redefinită. În schimb ea poate fi utilizată în noua metodă, evitând astfel duplicarea codului necesar câmpurilor care sunt prezente. Redefinirea unei metode poate schimba lista parametrilor acesteia.

Spre deosebire de metode, ale căror nume pot fi duplicate, selectorii câmpurilor nu pot fi redefiniţi în nici un obiect descendent.

Metode statice şi virtuale. Dacă dorim să îmbogăţim metodele obiectelor definite anterior cu una de modificare a unui

câmp, această metodă ar trebui adăugată obiectului, de ea beneficiind, prin moştenire şi obiectul. Mecanismul care permite realizarea unei legături dinamice este acela al metodelor virtuale. Sintactic, declararea unei metode virtuale se face prin adăugarea cuvântului rezervat virtual antetului metodei din declaraţia obiectului. Dacă o metodă a fost declarată virtuală într-un obiect, ea trebuie declarată virtuală în toţi descendenţii acestuia, antetul metodei rămânând nemodificat în toţi descendenţii (nu se pot modifică parametrii şi nu se poate schimba o funcţie cu o procedură sau invers).

Implementarea metodelor virtuale se bazează pe construcţia unor tabele de metode virtuale (virtual method table -VMT), care conţin adresele metodelor virtuale. Fiecare obiect care conţine o metodă virtuală are o astfel de tabelă realizată de o metodă specială a obiectului numită constructor. Constructorul execută şi alte operaţii, cum ar fi iniţializarea câmpurilor obiectului, alocarea unor variabile dinamice etc. El trebuie apelat înaintea oricărei metode virtuale; de obicei el este apelat înaintea oricarei alte metode a obiectului. Sintactic, constructorul diferă de celelalte metode prin prezenţa cuvântului rezervat constructor, în loc de function sau procedure.

Spre deosebire de alte metode, constructorii nu pot fi virtuali. Un obiect poate avea mai mulţi constructori, cu antete diferite. Constructorii pot fi moşteniţi.

Funcţia inversă celei a constructorului este realizată de o altă metodă specială, numită destructor. Sintactic, ea se deosebeşte de celelalte metode prin cuvântul rezervat destructor folosit în locul cuvintelor procedure sau function.

Page 51: CAPITOLUL 8  PCLP LPas.pdf

PROGRAMAREA CALCULATOARELOR ŞI LIMBAJE DE PROGRAMARE ÎN INDUSTRIA LEMNULUI

316

Destructorul este ultima metodă apelată a unui obiect. Uzual, destructorul nu are parametri. Mecanismul metodelor virtuale se bazează pe construirea şi utilizarea unei tabele de metode

virtuale (VMT -Virtual Methods Table) pentru fiecare object. Ea are următoarea alcătuire: -dimensiunea obiectului (1 cuvânt); -valoarea negativă a primului cuvânt; -adresa primei metode virtuale (2 cuvinte: segment + deplasare) -adresa celei de-a doua metode virtuale etc. Al doilea cuvânt al acestei structuri este prevăzut pentru validarea tabelei în cazul în care se

utilizează directiva de compilare ($R+ }. Ea constă în însumarea primelor două cuvinte, rezultatul fiind zero dacă tabela este iniţializată corect şi diferit de zero în caz contrar (eroare de execuţie 210). După cum s-a aratat, iniţializarea este făcută de constructorul obiectului (de unul din constructori, dacă sunt mai mulţi) care trebuie apelat înaintea oricărei metode virtuale.

Pe de altă parte, forma internă a unui object, asemănătoare cu cea a unei înregistrări, cuprinde câmpurile obiectului în ordinea declarării lor. Un câmp special este alocat pentru a păstra adresa, dacă obiectul are metode virtuale, constructori sau destructori. Acest câmp este moştenit odată cu metodele virtuale, constructorii şi destructorii obiectului. El este iniţializat la execuţia unui constructor.

La apelul unei metode virtuale, Turbo Pascal transmite automat prin stivă adresa variabilei-obiect prin care s-a facut apelul. De exemplu, la apelul s.afisare se transmite prin stiva adresa lui s. Aceasta este cunoscută sub denumirea de parametrul self şi este ultimul parametru încărcat în stivă la apelul metodei.

Compatibilitatea obiectelor.Variabilele obiect pot fi copiate prin instrucţiuni de atribuire şi pot fi folosite ca parametri variabile, la apelul subprogramelor. Astfel, dacă s1 şi s2 sunt variabile de tip student, pentru a copia valoarea uneia dintre variabile în cealaltă putem scrie

s1:= s2; sau s2: = s1; De asemenea, dacă procedura prelucrare are antetul: procedure prelucrare ( var s: student ); putem scrie instrucţiunea procedurală prelucrare ( s1 ) unde parametrul efectiv s1 este de tip student Ambele situaţii de utilizare a variabilelor object admit şi o excepţie: un object strămoş este

compatibil cu orice descendent al său, dar nu şi invers. Conform aceleiaşi reguli de compatibilitate, o variabilă referinţă către un tip obiect poate referi o instanţă de acel tip sau de un tip descendent.

Această regulă de compatibilitate a obiectelor stă la baza implementării polimorfismului: o aceeaşi procedură acceptă o gamă largă de tipuri object, chiar dacă la elaborarea ei aceste obiecte nu au fost avute în vedere. Singura condiţie este ca tipurile să fie descendente ale obiectului parametru formal al procedurii.

Avantajul obţinut în exploatarea programelor este deosebit. Rutinele cu parametri variabile objecte pot fi incluse într-o unitate, şi păstrate în forma compilată. Ele pot fi folosite în această formă în programe care definesc noi obiecte, compatibile ca tip cu cele ale rutinelor anterior elaborate, fără a fi necesară modificarea sau recompilarea acestora.

Obiecte care conţin referinţe. Dacă un object are un câmp referinţă, constructorul trebuie să realizeze nu numai iniţializarea VMT ci şi a câmpurilor de tip referinţă (cu NIL, sau prin alocarea memoriei pentru variabilele dinamice).

Referinţe la obiecte. În Turbo Pascal este permisă utilizarea variabilelor referinţă la obiecte. Variabilele dinamice referite se creează şi se distrug prin apelul procedurilor predefinite new

şi dispose. Acestea au fost extinse astfel încât prima să facă automat apelul constructorilor obiectului referit, după alocarea spaţiului necesar instanţei corespunzătoare, iar a doua să apeleze automat destructorul înainte de eliberarea spaţiului ocupat de instanţa referită.

Page 52: CAPITOLUL 8  PCLP LPas.pdf

CAPITOLUL 8. LIMBAJUL PASCAL

317

Turbo Pascal consideră că toate tipurile derivate sunt compatibile în privinţa operaţiei de atribuire, cu tipurile object de la care provin.

Acelaşi lucru este valabil pentru tipurile referinţă corespunzătoare. Dacă un parametru formal este de tip referinţă la un tip T, putem utiliza ca parametru efectiv o variabilă referinţă de orice tip derivat din T. Combinarea acestei reguli cu metodele virtuale oferă programatorului o formă foarte puternică de polimorfism.