Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
lfa:2022:proiect_etapa3 [2022/12/11 18:23]
mihai.calitescu
lfa:2022:proiect_etapa3 [2022/12/12 12:48] (current)
mihai.calitescu
Line 4: Line 4:
  
  
-Deadline etapa 3: ... ora 23:59+Deadline etapa 3: 8 ianuarie 2023 ora 23:00 (**deadline hard**)
  
 ====== Proiect ====== ====== Proiect ======
  
 Etapa 3 a proiectul consta in implementarea unui lexer in python sau scala. Etapa 3 a proiectul consta in implementarea unui lexer in python sau scala.
- 
-<note important>​Este recomandat sa va folositi de functionalitatile implementate la etapele precedente pentru rezolvarea etapei</​note>​ 
  
 ===== Ce este un lexer? ==== ===== Ce este un lexer? ====
Line 16: Line 14:
  
 ==== Care este input-ul unui lexer? ==== ==== Care este input-ul unui lexer? ====
-Lexer-ul primeste initial ​o specificatie ​de forma:+ 
 +Inputul unul lexer consta in doua componente:​ 
 +  ​- o **specificatie** 
 +  - un **text** care va fi analizat lexical, mai precis, impartit in lexeme. 
 + 
 +Specificatia are urmatoarea structura:
 <​code>​ <​code>​
 TOKEN1 : REGEX1; TOKEN1 : REGEX1;
Line 26: Line 29:
 ... ...
 </​code>​ </​code>​
-unde fiecare ''​TOKENi''​ este un nume dat unui token, iar ''​REGEXi''​ este un regex ce descrie ​lexemele ce pot fi clasificate ca acel token. Puteti imagina aceasta specificatie ca un //fisier de configurare//​care descrie modul in care va functiona lexerul pe diverse fisiere de text+unde fiecare ''​TOKENi''​ este un nume dat unui token, iar ''​REGEXi''​ este un regex ce descrie acel token. Puteti imagina aceasta specificatie ca un //fisier de configurare//​ care descrie modul in care va functiona lexerul pe diverse fisiere de text.
- +
-Inputul efectiv al unui lexer este un text care va fi impartit in lexeme folosind expresii regulate. In cursurile viitoare veti afla mai multe detalii despre cum functioneaza si cum sunt implementate lexerele.+
  
 ==== Care este output-ul unui lexer? ==== ==== Care este output-ul unui lexer? ====
 Lexer-ul are ca output o lista de forma : ''​[(lexema1,​ TOKEN_LEXEMA_1),​ (lexema2, TOKEN_LEXEMA_2),​ ...]'',​ unde ''​TOKEN_LEXEMA_N''​ este numele token-ului asociat lexemei n, pe baza specificatiei. Lexer-ul are ca output o lista de forma : ''​[(lexema1,​ TOKEN_LEXEMA_1),​ (lexema2, TOKEN_LEXEMA_2),​ ...]'',​ unde ''​TOKEN_LEXEMA_N''​ este numele token-ului asociat lexemei n, pe baza specificatiei.
 +
 +
 +==== Modalitati de implementare a unui lexer ====
 +
 +Exista mai multe modalitati prin care puteti implementa un lexer. Abordarea conventionala (si cea pe care o recomandam) consta in urmatoarele etape:
 +  - fiecare regex este convertit intr-un AFN, pastrand totodata informatia despre token-ul aferent si pozitia la care acesta apare in spec.
 +  - se construieste un AFN unic, introducand o stare initiala si epsilon-tranzitii de la aceasta catre toate starile initiale ale AFN-urilor de mai sus. Astfel, acest AFN va accepta oricare dintre tokenii descrisi in specificatie. Starea finala vizitata va indica token-ul gasit.
 +  - AFN-ul este convertit la un AFD (care optional poate fi minimizat). In acest automat:
 +     - cand vizitam un grup de stari ce contine (AFN-)stari finale, inseamna ca unul sau mai multe token-uri corespunzatoare au fost identificate.
 +     - cand vizitam un sink-state (daca acesta exista), inseamna ca subsirul curent nu este descris de nici un token. In acest caz trebuie sa intoarcem cel mai lung prefix acceptat si sa continuam lexarea cuvantului ramas
 +     - cand vizitam o stare non-finala si care nu e sink-state, continuam prin trecerea in urmatoarea stare a AFD-ului consumand un caracter din cuvant
  
 ==== Cand isi termina un lexer executia ? ==== ==== Cand isi termina un lexer executia ? ====
  
-Un lexer va incepe dintr-o stare initiala si va continua pana cand ajunge ​in sink state. Pe parcursul trecerii lui dintr-o stare in alta el va tine minte starile si cuvintele intermediare pe care le a acceptat.+Scopul unui lexer este identificarea **celui mai lung subsir** care satisface un regex din specificatia data. Daca un cel mai lung subsir satisface **doua sau mai multe regex-uri**, ​va fi raportat primul token aferent, ​in ordinea ​in care acestea sunt scrise in specificatie.
  
-Exemplupentru ​un lexer cu configuratia ''​TOKEN ​-a+''​ si un cuvant ''​aaab''​ vom accepta ​3 cuvinte intermediare inainte sa ajungem ​in sink state pe caracterul b: ''​a''​''​aa''​''​aaa''​+Pentru a identifica **cel mai lung subsir** folosind un AFD precum cel descris in sectiunea anterioara, trebuie sa observam faptul ca: 
 +  - vizitarea unui grup de stari ce contine o (AFN-)stare finala, **nu indica** in mod necesar faptul ca am gasit cel mai lung subsir acceptat. 
 +  - daca un grup de stari ce contine o (AFN-)stare finala ​fost vizitata **anterior**:​ 
 +    - vizitarea unui grup de stari ce nu contine stari finale, **nu indica** in mod necesar faptul ca am gasit cel mai lung subsir (automatul poate accepta in viitor) 
 +    - vizitarea ​sink-state-ului AFD-ului (daca acesta exista)indica faptul ca automatul nu va mai accepta in viitor. 
 +    - daca in AFD nu exista un sink stateatunci analiza lexicala trebuie sa continue pana la epuizarea inputului, pentru a decide asupra celui mai lung subsir.
  
-==== Acceptarea celui mai lung prefix ====+Odata ce subsirul cel mai lung a fost identificat:​ 
 +  - AFD-ul va fi //resetat// - adus in starea initiala pentru a relua analiza lexicala. 
 +  - analiza lexicala va continua de la pozitia unde subsirul cel mai lung s-a terminat, iar aceasta poate preceda cu **oricate pozitii**, pozitia curenta unde a ajuns analiza.
  
-In exemplul precedent avem 3 cuvinte intermediare acceptate, un lexer il va considera doar pe acela cel mai lung (''​aaa''​) si dupa va continue lexarea partii ramase din cuvant (''​b''​). ​+=== Exemplu ===
  
-==== Prioritatea unui token ====+Fie specificatia urmatoare:​ 
 +<​code>​ 
 +TOKEN1 -> abbc*; 
 +TOKEN2 -> ab+; 
 +TOKEN3 -> a*d; 
 +</​code>​
  
-Un lexer poate intalni urmatorul caz: sa accepte prin 2 tokenuri diferite acelasi cuvant de lungime maximaIn cazul asta vom considera tokenul cu prioritate mai mare (care apare inaintea celuilalt ​in configuratie)+si input-ul ''​abbd''​Analiza lexicala se va opri la caracterul ''​d'' ​(AFD-ul descris anterior va ajunge pe acest caracter ​in sink state). Subsirul ''​abb''​ este cel mai lung care satisface atat ''​TOKEN1''​ cat si ''​TOKEN2'',​ iar ''​TOKEN1''​ va fi raportat, intrucat il preceda pe ''​TOKEN2''​ In specificatie. Ulterior, lexerul va devansa cu un caracter pozitia curenta in input, si va identifica subsirul ''​d''​ ca fiind ''​TOKEN3''​. 
 + 
 +Pentru lamuriri ulterioare si mai multe exemple ce includ cel mai lung subsir, revizitati cursul aferent lexerelor.
  
-Exemplu: pentru configuratia:​ ''​(TOKEN1 -> abbc*, TOKEN2 -> ab+)''​ si cuvantul ''​abbd''​ lexerul se va opri la caracterul ''​d''​ in sink state si va fi acceptat inainte o data prin ''​TOKEN1 -> abb''​ si a doua oara prin ''​TOKEN2 -> abb''​. Astfel, lexerul va considera lexemul ''​(TOKEN1 -> abb)''​ deoarece primul token are prioritate mai mare decat al doilea (apare inaintea lui in configuratie) 
  
 ===== Structura specificatiei si incarcarea ei ===== ===== Structura specificatiei si incarcarea ei =====
 +
 +<note important>​Este recomandat sa folositi functionalitatile implementate la etapele precedente pentru rezolvarea etapei finale</​note>​
 +
  
 ==== Python ==== ==== Python ====
Line 119: Line 147:
  
   {   {
-      "​BEGIN":​ "​s*me|r*g*x"​ +      "​BEGIN":​ "​s*me|r*g*x"​, 
-      "​END":​ "​oth*r|r+g+x"​+      "​END":​ "​oth*r|r+g+x"​,
       ...       ...
   }   }