|  | # Exemple de extinderi

"In fiecare zi se invata ceva nou."

SOLON

In prezentul capitol vom ilustra mecanismele de definire, fixare si utilizare a extinderilor la nivel formal, apoi citeva exemple practice de extinderi.

### Metodologia de definire a extinderilor

Pentru definirea extinderilor ( de date, de operatii, de instructiuni si de dirijari ), se folosesc mijloace metalingvistice ( terminali metalingvistici ) care se vor combina cu elementele lingvistice deja existente.

Declararea extinderilor are, in principiu, aceeasi forma ca si definirea clasica a oricarui element intr-un limbaj de programare comun, dar ea se bazeaza pe folosirea unor metaterminali speciali.

Fiecare compartiment de definire a unui element ( de reamintit ca trebuiesc mentionate: pragmatica, sintaxa, semantica, contextul utilizarii si exemplele de utilizare ale noului element introdus in limbaj ) este compus din sub-elemente de definire care la rindul lor formeaza un metalimbaj. Astfel, vom avea un metalimbaj de definire a pragmaticii, un metalimbaj de definire a sintaxei si asa mai departe.

#### Definirea unui nou tip de data

Vom introduce tipul de data matrice de tip real pe care il vom defini prin intermediul elementelor deja existente in limbajul de programare pe care dorim sa-l extindem. Astfel, presupunem deja definite: tipul real, neterminalii <ident>, constantele intregi, delimitatorii metalingvistici _DBL_ ( Data Begin Layout ), _DCO_ ( Data COntext ), _DSY_ ( Data SYntax ), _DSE_ ( Data SEmantics ), _DEX_ ( Data EXample ), _DEL_ ( Data End Layout ), _AS_.

    _DBL_ <real_mat>
    _DCO_ _AS_ <type-complex>
    _DSY_ <ident> : MATRIX[ <line>, <col> ]
    _DSE_ <ident> : ARRAY[ 1..<line>, 1..<col> ] OF REAL
    _DEX_ mult_mat: MATRIX[30,10]
    _DEL_

In acest prim caz, se observa ca s-a extins limbajul PASCAL, prin definirea unui nou tip de data: matrice cu elemente reale.

#### Definirea operatiilor

Fiecare tip are asociata o multime de operatori. Utilizind tipul de data matrice definit mai sus, vom ilustra aici definirea operatiei de sumare a doua matrici reale. Presupunem cunoscute: operatia de adunare a doi reali, instructiunile de asignare, de ciclare, functiile care furnizeaza numarul de linii, respectiv coloane ale unei matrici, metaterminalii _OBL_ ( Operation Begin Layout ), _OCO_ ( Operation COntext ), _OSY_ ( Operation SYntax ), _OSE_ ( Operation SEmantics ), _OEX_ ( Operation EXample ), _OEL_ ( Operation End Layout ).

Consideram ca matricile sint declarate si au aceleasi dimensiuni.

Vom suprascrie ( defini ) operatorul + pentru a suporta sumarea de matrici.

    _OBL_ <add_mat>
    _OCO_ _AS_ <add>
    _OSY_ <ident1> + <ident2>
    _OSE_ var lin : INTEGER;
            	{ numarul de linii ale matricii }
          var col : INTEGER;
      		{ numarul de coloane ale matricii }
          result : matrix[lin][col];
    		{ matricea rezultat }
          var i, j : INTEGER;
    	        { variabile de ciclu }
          lin := matlines( <ident1> );
          col := matcols( <ident2> );
          For i := 1 to lin Do
    	For j := 1 to col Do
              result[i][j]=<ident1>[i][j] + <ident2>[i][j];
          return ( result );
    _OEX_ a + b
    _OEL_

#### Definirea instructiunilor

Vom defini o instructiune grafica de desenare a unui triunghi, cunoscindu-se coordonatele virfurilor. In limbaj sint deja implementate instructiunile `PutPixel`, `LineTo`. Nu lipsesc delimitatorii metalingvistici: _SBL_ ( Statement Begin Layout ), _SCO_ ( Statement COntext ), _SSY_ ( Statement SYntax ), _SSE_ ( Statement SEmantics ), _SX_ ( Statement eXample ), _SEL_ ( Statement End Layout ).

Vom construi o instructiune grafica pentru desenarea unui triunghi cunoscindu-se coordonatele virfurilor.

    _SBL_ <triangle>
    _SCO_ _AS_ <statement>
    _SSY_ TRIANGLE (<x1>, <y1>) (<x2>, <y2>) (<x3>, <y3>)
    _SSE_ PutPixel (<x1>,  <y1>);
          LineTo (<x1>,  <y1>);
          LineTo (<x2>,  <y2>);
          LineTo (<x3>,  <y3>);
    _SX_  TRIANGLE (30,50) (100,205) (80,74)
    _SEL_

#### Definirea dirijarilor

Limbajul extensibil va dispune de urmatoarele constructii implementate: <statement>, <for>, expresiille aritmetice, variabile de ciclu de tip intreg, metaterminalii _CBL_ ( Control Begin Layout ), _CCO_ ( Control COntext ), _CSY_ ( Control SYntax ), _CSE_ ( Control SEmantics ), _CEX_ ( Control EXample ), _CEL_ ( Control End Layout ).

Putem defini un nou ciclu, pe baza ciclului `For` deja existent in limbaj.

    _CBL_ <double-for>
    _CCO_ _AS_ <statement>
    _CSY_ For2 <cycle_var1> : <expr1>, <cycle_var2> : <expr2> Do
            <statement>
          EndFor2
    _CSE_ For <cycle_var1> = 1 TO  <expr1> Do
            For <cycle_var2> = 1 TO  <expr2> Do
              <statement>
            EndFor
          EndFor
    _CEX_ sum = 0
          For2 i : 30, j : 50 Do
            sum = sum + matrix[i][j]
          EndFor2
    _CEL_

Observatie: Dupa cum s-a vazut mai sus, definirea unui element implica imbogatirea limbajului cu noi constructii ( apar astfel noi terminali si neterminali, plus noi reguli ale gramaticii asociate limbajului respectiv ).

## Exemple reale

### Extinderea limbajului C pentru a accepta interogari SQL

Sub ORACLE in implementarea SQL-PLUS, utilizind pre-compilatorul PRO-C:
``

    #define <stdio.h>
    #define <strings.h>
    #define <SQL.h>

    main()
    {
        ....
        EXEC SQL BEGIN DECLARE SECTION; /* inceputul sectiunii de declaratii SQL*/
        VARCHAR uid[20];
        VARCHAR pwd[20];
        VARCHAR lid[1];
        VARCHAR e_id[1];
        VARCHAR nmar[4];
        VARCHAR nouv[500][5];
        VARCHAR ldesign[120];
        EXEC SQL END DECLARE SECTION;
        printf("\nLogin:");              /* inceput interogare */
        gets(uid.arr);
        uid.len=strlen(uid.arr);
        uid.arr[uid.len]='\0';
        printf("\nPassword:");
        gets(pwd.arr);
        pwd.len=strlen(pwd.arr);
        pwd.arr[pwd.len]='\0';
        EXEC SQL WHENEVER SQLERROR GOTO err;
        EXEC SQL CONNECT :uid IDENTIFIED BY :pwd;
        printf("\nConnection to ORACLE...done\n");
        EXEC SQL WHENEVER NOT FOUND CONTINUE;
        /* exemplu de cursor explicit */
        EXEC SQL DECLARE CURSOR FOR   \
             SELECT L_DESIGN FROM LOT \
             WHERE L_ID=:lid;
        EXEC SQL OPEN c1;
        EXEC SQL FETCH c1 INTO :ldesign;
        EXEC SQL CLOSE c1;
        /* exemplu de cursor implicit */
        EXEC SQL SELECT DISTINCT substr(M.OAED_ID,1,5) \
             INTO :nouv FROM OAED M                    \
             WHERE M.LOC_ID LIKE :edif_id || :nmar ||  \
             '%' AND M.OAED_ID LIKE :lid || '%' ;
        ....
    err:
         printf("\nIncorrect login!\n");
         return 1;
         ....
    }

### O extindere a limbajului PASCAL pentru manipularea bazelor de date relationale prin SQL

Relatiile sint in mod natural definite ca facind parte dintr-un record in PASCAL, utilizind o extindere de tip: RELATION care e o implementare a unei tabele SQL:

`

           TYPE DATE=string[8];          { ZZ-LL-AA }
           TYPE TStud=RECORD             { cimpurile bazei de date }
                         name:string[60];
                         number:integer;
                         points:integer;
                         born_date:DATE;
                       END;
            TYPE RStud=RELATION OF TStud;
            VAR stud:RStud;
            ....

`

### Exemplu de extinderi macro-textuale pentru adaugarea unui nou tip de data

- definire
  `

               DEFINE MACRO COMPLEX_MATRIX (M,N)
                      WHERE MACROARGS M,N
               TO BE ARRAY[1..M,1..N,1..2] OF REAL
               END MACRO

  `
- utilizare
  `

      VAR X:COMPLEX_MATRIX(3,4);

  `

Dupa expandare, in codul sursa va apare:

`

    VAR X:ARRAY[1..3,1..4,1..2] OF REAL; /*macro COMPLEX_MATRIX*/

`

### Exemplu de extindere macro-sintactica, intr-un dialect BASIC

Definirea unei noi dirijari ( control ): ``

         SMACRO for s1(VARIABLE:INTEGER) = s2(EXPRESSION:INTEGER)
                CASE 1: while s3(EXPRESSION:LOGICAL)
                CASE 2: by s4(EXPRESSION:INTEGER) OPTIONALLY
                CASE 3: to s5(EXPRESSION:INTEGER)
                do s6(STATEMENT)
         LET BE
                LABEL l1,l2
                l1 LET s1=s2
                l2 IF (1 :: s3) THEN
                         s6 : GO TO l1
                      (3 :: s1<=s5) THEN
                         s6
                         LET s1=s1 + (2 :: s4) (NOT 2 :: 1)
                         GO TO l2
                    END IF
         END SMACRO

Apelarea macro-ului: ``

         for i=1 while i<=6 do INPUT a(i)

determina generarea textului BASIC:
`

         REM label_??? sint generate de preprocesorul extensibil
         label_1 LET i=1
         label_2 IF i<=6 THEN
                    INPUT a(i) : GO TO label_1
                 END IF

`
iar apelul
`

         for i=1 to 10 do PRINT i*i

`
duce la:
`

         label_3 LET i=1
         label_4 IF i<=10 THEN
                   PRINT i*i
                   LET i=i+1
                 END IF

`

### Definirea de noi operatori

- definirea operatorului de calculare a maximului valorilor a doua expresii:
  `

           Max (A,B:single_type) = ( if A > B then A else B )

  `
  care poate fi in C scrisa ca o declaratie preprocesor:
  `

          #define Max(A,B) (A) > (B) ? (A) : (B)

  `
- definirea unui operator de incrementare:
  `

           Let ++ be a left associative unary operator as
               succ(_:ANY_TYPE) with precedence > '+'

  `