LEDA logo LEDA

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

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


< >