LEDA logo LEDA

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:

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:

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

    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 )

    < >