|  | # Limbajul extensibil LEDA

"A cunoaste o limba nu este totul. Mai trebuie sa ai si ceva de spus."

Acest capitol contine: surse de inspiratie in proiectarea unui nou limbaj de programare, descrierea sintactica a limbajului LEDA utilizind EBNF, semantica instructiunilor de baza ale limbajului, modul in care se definesc extendorii in LEDA si exemple de programe sursa scrise in LEDA.

## Surse de inspiratie in proiectarea unui limbaj de programare

Inainte de a concepe un nou limbaj de programare trebuie avute in vedere urmatoarele aspecte:

- e intr-adevar necesara construirea unui alt limbaj sau se poate completa unul deja existent printr-un mecanism de extindere?
- limbajul este destinat unui domeniu concret sau se gindeste a fi utilizat intr-o paleta larga de domenii?
- limbajul nou proiectat aduce noi facilitati in comparatie cu limbajele existente?

Obiectivul unui proiectant de limbaj este, prin urmare, acela de a crea un limbaj facil pentru utilizator, cit mai puternic, clar din punctul de vedere al redactarii, simplu de inteles, posedind avansate mecanisme de detectie a erorilor. Vor trebui, asadar, folosite structuri si notatii apropiate de limbajul utilizatorului, indiferent daca limbajul de programare e specializat sau nu. Astfel vom asista la o minimizare a efortului de programare si la o invatare mult mai rapida a acestui limbaj.

Surse de idei:

1. Numeroase aspecte practice ale limbajelor de programare deriva din limbajul natural, astfel incit regulile gramaticii atasate limbajului sint similare celor din vorbirea curenta. Aceste constructii conduc in mod evident la intelegere rapida a programelor, atit de catre specialisti, cit si de catre novici. Totodata, limbajul natural ofera informatii despre alfabetul necesar, despre separatori ( spatiul, virgula, punctul ), despre sintaxa etc. Totusi, deseori limbajul natural duce la ambiguitati, nedorite intr-un limbaj de programare. Ca exemplu de limbaje de programare construite dupa limbajul natural putem enumera COBOL, dBASE, LOGO, BASIC si altele.
2. Matematica a fost o sursa importanta de concepte, conventii si notatii. Un bun suport matematic va da limbajului concizie si o larga sfera de aplicabilitate. Drept exemple mentionam FORTRAN, Joy, C, LISP etc.
3. Limbajele de programare deja existente pot constitui modele demne de urmat in proiectarea si implementarea unui nou limbaj. Se cunoaste importanta influienta a limbajului Algol asupra altor limbaje de programare. Aceeasi observatie e valabila si pentru Pascal.
4. Un cuvint de spus il are experienta proprie care stabileste ce tipuri de date, operatori, instructiuni sint obligatorii, ce facilitati sint prioritare, ce aspecte pozitive si lacune au alte limbaje de programare.

Limbajele de programare trebuie sa posede anumite caracteristici astfel incit sa fie acceptate de potentialii utilizatori. Ele vor folosi, pe cit posibil, cuvinte rezervate al caror inteles e larg cunoscut, fara a genera dubii. Sintaxa trebuie sa aiba constructii convenabile, clare si sa reflecte semantica, in sensul ca sintaxa va urmari sabloanele gindirii umane, programatorul prevazind comportamentul unei instructiuni doar stiindu-i numele. Limbajele trebuiesc a fi facil de utilizat, concise, cu reguli usor de retinut.

Urmarind paradigmele programarii structurate, limbajele vor oferi mecanisme de abstractizare, de ascundere a informatiilor, de modularitate. In plus, se vor evita aparitia erorilor si pierderea de timp pentru corectare. Erorile se vor evidentia intr-un mod precis ( localizare, tip, mesaje explicative ) si se vor propune metode de corectare.

Un alt aspect este acela al portabilitatii si independentei de periferice. E bine ca metodele de procesare a intrarilor si iesirilor ( atit la nivel inalt, cit si la nivel apropiat de hardware ) sa fie scoase in afara limbajului de programare, asa cum se intimpla la limbajele C si C++.

In concluzie, proiectantul unui limbaj de programare trebuie sa aiba in vedere aspecte multiple pentru a inventa un limbaj de programare ( extensibil ) cu adevarat eficient si folositor.

## Trasaturi ale limbajului LEDA

LEDA este:

- un limbaj de nivel inalt,
- simplu, posedind ca tipuri de date simple sau tablouri doar tipurile de baza intreg ( `int` ), boolean ( `bool` ) si caracter ( `char` ), iar ca instructiuni initiale: asignarea, while, if, primitive de intrare/iesire ( `read` si `write` ),
- dotat cu un mecanism de extindere care permite definirea de noi instructiuni,
- iconic ( instructiunile si extinderile sint reprezentate prin simboluri grafice, intuitive ),
- un limbaj care nu ofera suport pentru definirea si apelul de proceduri/functii, nici pentru tipuri dinamice de date.

## Descrierea sintactica si semantica a limbajului LEDA

Sintaxa limbajului:

`

1. letter ::= A | B | ... | Z | a | b | ... | z
2. digit ::= 0 | 1 | ... | 9
3. punct ::= + | - | * | / | % | \ | # | $ | . | , | : | ; | _ | = | < | > | ! | ? | ' | " | ( | ) | [ | ] | { | } | &
4. text ::= { letter | digit | punct | space }
5. a_op ::= + | - | / | %
6. b_op2 ::= and | or
7. b_op1 ::= not
8. space ::= _
9. r_op ::= < | > | =
10. b_cst ::= false | true
11. c_cst ::= 'letter' | 'digit' | 'punct' | 'space'
12. ident ::= letter { letter | digit }
13. u_number ::= { digit }
14. number ::= + u_number | - u_number | u_number
15. i_exp ::= number | i_exp a_op i_exp | i_var | ( i_exp )
16. b_exp ::= b_cst | b_exp b_op2 b_exp | b_op1 b_exp | ( b_exp ) | b_var
17. c_exp ::= c_cst | c_var | ( c_exp )
18. r_exp ::= b_exp | i_exp r_op i_exp | c_exp r_op c_exp
19. var ::= i_var | c_var | b_var
20. i_var ::= i_vars | i_varc
21. b_var ::= b_vars | b_varc
22. c_var ::= c_vars | c_varc
23. i_vars ::= ident
24. i_varc ::= ident { [ i_exp ] }
25. b_vars ::= ident
26. b_varc ::= ident { [ i_exp ] }
27. c_vars ::= ident
28. c_varc ::= ident { [ i_exp ] }
29. stat ::= { assign | if | while | read | write | note }
30. assign ::= i_var := i_exp | b_var := b_exp | c_var := c_exp
31. if ::= if r_exp then stat else stat fi | if r_exp then stat fi
32. while ::= while r_exp do stat od
33. read ::= read var
34. write ::= write var
35. note ::= note text
36. decl ::= { ident : type }
37. type ::= simple | compose
38. simple ::= int | char | bool
39. compose ::= array[ u_number ] of type
40. use_ext ::= { ident }
41. prog ::= prog ident use_ext use_ext decl decl body prog_body end
42. def_ext ::= extension ident syntax syntax use_ext use_ext decl decl ext_body stat end
43. syntax ::= { text | $ ident : def_token }
44. def_token ::= def_var | def_exp | def_stat
45. def_var ::= var type
46. def_exp ::= exp type
47. def_stat ::= stat
48. ext_call ::= text
49. prog_body := { stat | ext_call }
50. ext_body ::= pascal text | { stat | ext_call } | operator { stat | ext_call }
51. leda ::= { def_ext } prog

`

Remarci

- Regulile (1), (2), (3) si (8) definesc alfabetul utilizat de limbajul extensibil LEDA, in fapt intregul cod ASCII.
- Regula (4) defineste textul 'in clar' scris de catre programator drept comentarii sau atunci cind concepe o noua extindere.
- Regulile (5), respectiv (6) si (7), definesc operatiile aritmetice uzuale ( intre operanzi intregi ) si operatiile binare si unare booleene ( and, or si not ).
- Operatorii relationali sint definiti de regula (9).
- Urmeaza constantele logice - regula (10), constantele caracter - regula (11).
- Regula (12) furnizeaza modul de definire a unui identificator ( nume de variabila )
- Regulile (13) si (14) definesc constantele intregi.
- Regula (15) defineste expresia intreaga, pentru ca (16) si (17) sa le defineasca pe cele de tip logic, respectiv de tip caracter. Regula (18) se refera la definirea expresiilor relationale.
- Regulile (19) pina la (28) vor defini variabilele utilizate de limbajul LEDA.
- Regula (29) defineste lista de instructiuni de baza ale limbajului, urmatoarele 6 reguli fiind in fapt definitiile sintactice pentru instructiunile de asignare, test, ciclare, intrare/iesire, remarci.
- Regula (36) defineste declararea variabilelor, (37) pina la (39) vor defini tipurile de date LEDA.
- Regula (40) defineste numele de extindere.
- Regula (41) defineste corpul programelor LEDA.
- Revenind la extinderi, regulile de la (42) pina la (47) furnizeaza modul de definire de catre utilizator a extinderilor.
- Regulile (48), (49), (50) furnizeaza modul de definire a corpului unui program sau extinderi.
- Ultima regula, a (51)-a, va defini forma completa a unui program scris in limbajul LEDA.

Fiecare instructiune si fiecare definitie de extindere au asociate, in mod bijectiv, cite un icon, deoarece LEDA se doreste a fi un limbaj vizual.

In ceea ce priveste semantica, instructiunile de baza incluse in LEDA se comporta exact ca si cele din limbajul Pascal. La fel, specificatiile tehnice ale limbajului sint similare cu cele ale Pascal-ului.

## Exemple de programe LEDA

1. Definirea unei instructiuni de ciclare

       extension for
       syntax    for $cnt : var int := $low : exp int to $high : exp int do
                          $st : stat
                 rof
       body      note simuleaza for-ul cu ajutorul lui while
                 cnt := low
                 while cnt < high + 1 do
                    st
                    cnt := cnt + 1
                 od
       end
       prog      exemplul1
       use_ext   for
       decl      sum    : int
                 i      : int
                 vector : array[30] of int
       body      note sumeaza elementele unui vector avind 30 de componente
                 note folosind extensia definita mai sus
                 sum := 0
                 read vector
                 for i := 1 to 30 do
                    sum := sum + vector[i]
                 rof
                 write sum
       end

   Din acest exemplu putem observa urmatoarele aspecte:

   1. `extension`, `syntax`, `body` inlocuiesc meta-terminalii _SBL_, _SSY_, respectiv _SSE_ prezentati in capitolul precedent;
   2. instructiunea `for` nou definita poate fi considerata ca apartine nivelului 1 al limbajului, ea definindu-se prin intermediul elementelor nivelului 0 ( baza ).
2. Definirea unei instructiuni de ciclare pe baza unei extensii

       extension for2
       syntax    for2 $cnt1 : var int ( $exp1 : exp int ),
                      $cnt2 : exp int ( $exp2 : exp int ) do
                    $st : stat
                 rof2
       use_ext   for
       body      note simuleaza noul ciclu cu doua for-uri imbricate
                 for cnt1 := 1 to exp1 do
                   for cnt2 := 1 to exp2 do
                     st
                   rof
                 rof
       end
       prog      exemplul2
       use_ext   for2
       decl      minim  : int
                 i      : int
                 j      : int
                 matr   : array[50] of array[100] of int
       body      note calculeaza minimul unei matrici de dimensiuni 50 x 100
                 read matr
                 minim := matr[1][1]
                 for2 i ( 50 ), j ( 100 ) do
                    if minim > matr[i][j] then
                      minim := matr[i][j]
                    fi
                 rof2
                 write minim
       end

   O serie de observatii:

   1. `for2` apartine multimii elementelor de nivel secund fiind definit cu ajutorul unui element al nivelului 1 ( `for` );
   2. in urma preprocesarii nivel-nivel, `for2` va fi exprimat doar prin intructiuni de baza astfel:

          extension for2
          syntax    for2 $cnt1 : var int ( $exp1 : exp int ),
                         $cnt2 : exp int ( $exp2 : exp int ) do
                       $st : stat
                    rof2
          body      note for2 va fi simulat de instructiunile de baza
                    cnt1 := 1
                    while cnt1 < exp1 + 1 do
                       cnt2 := 1
                       while cnt2 < exp2 + 1 do
                          st
                          cnt2 := cnt2 + 1
                       od
                       cnt1 := cnt1 + 1
                    od
          end

3. Definirea unei pseudo-operator de inmultire a doua matrici

       extension matprod
       syntax    $rez : var array[100] of array[100] of int :=
                 $a : var array[100] of array[100] of int +
                 $b : var array[100] of array[100] of int
       use_ext   for2 for
       decl      i : int
                 j : int
                 k : int
       body      note inmulteste matricile folosind for2 si for
                 for2 i ( 100 ), j ( 100 ) do
                   rez[i][j] := 0
                   for k := 1 to 100 do
                     rez[i][j] := rez[i][j] + a[i][k] * b[k][j]
                   rof
                 rof2
       end
       prog      exemplul3
       use_ext   matprod
       decl      a   : array[100] of array[100] of int
                 b   : array[100] of array[100] of int
                 c   : array[100] of array[100] of int
       body      note calculeaza produsul a doua matrici patratice
                 read a
                 read b
                 c := a + b
                 write c
       end

   Observatii:

   1. `matprod` apartine multimii elementelor nivelului 3 fiind definit prin intermediul unui element al nivelului 1 ( `for` ), prin intermediul unui element de nivel 2 ( `for2` ) si cu ajutorul elementelor bazei;
   2. sintaxa de definire a extinderilor permite scrierea noilor instructiuni sub orice forma ( usor de inteles de catre utilizator )