Deadline etapa 1: 21 nov 2024 23:55
Schelet etapa 1 {{:lfa:2023:lfa2024-skel-etapa1.zip|}}
====== Proiect ======
Proiectul este structurat in trei teme al caror obiectiv final reprezinta implementarea unui lexer in Python.
===== Ce este un lexer? ====
Un lexer este un program care, pe baza unei specificatii, imparte un sir de caractere in subsiruri, si identifica carei //categorii// apartine fiecare dintre subsiruri. Categoriile se numesc //tokens// iar subsirurile - //lexeme//. Acest proces, deseori implementat ca prima etapa din cadrul unui parser, se numeste **analiza lexicala**.
==== Care este input-ul unui lexer? ====
Specificatia unui lexer arata astfel:
TOKEN1 : REGEX1;
TOKEN2 : REGEX2;
TOKEN3 : REGEX3;
...
unde fiecarui ''TOKENi'' ii este asociat un ''REGEXi'' care descrie toate lexemele ce trebuie clasificate ca acel token. Specificatia de mai sus are caracterul unei //configuratii// care descrie modul in care orice sir de la input ar trebui analizat lexical de catre lexer.
Inputul efectiv al unui lexer este un text care va fi obiectul analizei lexicale.
==== Care este output-ul unui lexer? ====
Lexer-ul are ca output o lista de forma : ''[(lexema1, TOKEN_i1), (lexema2, TOKEN_i2), ...]'', unde ''TOKEN_iN'' este numele token-ului asociat lexemei N, pe baza specificatiei.
===== Etapa 1 =====
Procedura de implementare a unui lexer pe care o vom urma la acest curs va fi una **bottom-up**. Astfel, **etapa 1** a proiectului consta in conversia unui Automat Finit Nedeterminist (AFN) in Automat Finit Determinist (AFD) (folosind algoritmul __Subset Construction__ prezentat la curs) si minimizarea acestuia folosind, de asemenea, recomandat, algoritmul prezentat la curs.
Tema va fi implementata in Python, iar scheletul va ofera un punct de plecare pentru implementarea functionalitatilor necesare.
====Structura scheletului====
In scheletul temei veti gasi 2 clase: **NFA** si **DFA**.
=== Clasa DFA ===
Un AFD va fi descris de urmatoarele:
S - alfabetul limbajului, reprezentat ca un set de string-uri
K - multimea starilor automatului, reprezentata ca un set de __STATE__
q0 - starea initiala a automatului
d - functia de tranzitie, reprezentata ca un dictionar care asociaza unei perechi (stare, caracter_alfabet), o stare-succesor
F - multimea starilor finale ale automatului, reprezentata ca un set de __STATE__
Desi cea mai simpla modalitate de a ne referi la o stare este printr-un numar intreg, in anumite componente ale proiectului va fi mult mai convenabil sa lucram cu alte tipuri pentru identitatea unei stari (de exemplu, seturi de intregi sau tupluri). Parametrul ''STATE'' va permite aceasta flexibilitate. In etapa 1, puteti sa utilizati ce tip doriti pentru reprezentarea unei stari, spre exemplu folosind intregi ''0,1,2,3,...'', siruri de caractere ''s0,q1,sink,...'' sau alte tipuri de date (''frozenset'')
- In aceasta clasa veti avea de implementat **obligatoriu** functia ''accept'', care primeste un cuvant si simuland executia AFD-ului pe acel cuvant va intoarce ''True'' daca cuvantul este acceptat, iar ''False'' in caz contrar.
- functia ''minimize'' este **obligatoriu** de implementat pentru obtinerea puntajului maxim, dar nu este necesara pentru realizarea etapelor urmatoare.
- Functia ''remap_states'' **nu este** obligatoriu de implementat, din moment ce nu este apelata de checker, insa este recomandata. Aceasta va simplifica implementarea algoritmului subset construction. Ea are ca scop **transformarea** setului de stari, de la un tip (spre exemplu set cu elemente de tip //string//) la un altul (spre exemplu, set cu elemente de tip //integer//). Astfel de transformari vor fi necesare, in special in etapele ulterioare ale proiectului.
Spre exemplu, daca am avea automatul de mai jos:
{{:lfa:2023:remap_before.png?400|}}
/*
> (0) -a,b-> (1) ----a----> ((2))
\-b-> (3) <-a,b-/
/ \
\-a,b-/
*/
Am putea aplica functia ''x -> 'q' + str(x+2)'', care ar creea un AFD cu urmatoarele stari:
{{:lfa:2023:remap_after.png?400|}}
/*
> (q2) -a,b-> (q3) ----a----> ((q4))
\-b-> (q5) <-a,b-/
/ \
\-a,b-/
*/
===Clasa NFA===
Clasa functioneaza in aceeasi maniera cu cea a AFD-ului, cu o singura particularitate:
* Relatia $math[\Delta] va fi reprezentata tot folosind un dictionar ''d'' care va asocia unei perechi (stare, caracter_alfabet), un **set de stari** succesor (in loc de o stare unica, asa cum se intampla intr-un DFA).
Alte observatii:
- Functia ''epsilon_closure'' primeste o stare a automatului si intoarce un set de stari, care reprezinta starile la care se poate ajunge doar prin epsilon-tranzitii de la starea initiala (fara a consuma nici un caracter)
- Functia ''subset_construction'' va intoarce un AFD, construit din AFN-ul curent prin algoritmul __subset construction__. AFD-ul intors va avea ca tip al starilor ''frozenset[STATE]''. Folosim ''frozenset'' in loc de ''set'', pentru ca acesta din urma **nu este imutabil** (seturile pot fi modificate prin efecte laterale). Avem nevoie de un obiect **imutabil** pentru a putea calcula un hash (mereu acelasi), si implicit pentru a putea folosi astfel de obiecte drept chei intr-un dictionar (lucru imposibil daca obiectul-cheie este mutabil).
- Functia ''remap_states'' are acelasi format si scop ca functia de la AFD-uri
Functiile ''epsilon_closure'' si ''subset_construction'' **sunt obligatoriu** de implementat, insa functia ''remap_states'' **nu** este
.
===== Testare =====
Verificarea corectitudinii implementarii voastre se va face automat, printr-o serie de teste unitare. Testele vor verifica echivalenta intre AFD-urile create de operatiile ''subset_construction'' si ''minimize'' cu un AFD minimal dat ca referinta.
O alta verificare va urmari integritatea AFDului d.p.d.v. structural (starea initiala si starile finale sunt incluse in multima de stari, nu are tranzitii definite pe un caracter dintr-o anume stare, are tranzitii definite pe fiecare pereche (stare, caracter)
).
==== Python ====
Versiunea de python pe care o vom folosi pentru aceasta tema este ''python3.12''. Un ghid de instalare a acestei versiuni poate fi gasit [[https://aruljohn.com/blog/install-python/|aici]]
Este recomandat sa parcurgeti [[lfa:2023:lab_python_extras|documentul extra]] pentru descrierea unor feature-uri folosite in schelet si a unora utile in implementarea proiectului, mai ales topic-urile:
* [[lfa:2023:lab_python_extras#dictionaries_sets_and_hashable_objects | hashing]]
* [[lfa:2023:lab_python_extras#python_312_generics | genericitate in python 3.12]]
* [[lfa:2023:lab_python_extras#dataclasses | decoratorul dataclass]]
Pentru rularea testelor folositi comanda ''python3.12 -m unittest''.
Aceasta comanda va detecta automat testele definite in folder-ul ''test'' si le va rula pe rand, afisand la final testele care au esuat, daca exista
.
==== Structura arhivei ====
Veti incarca in assignment-ul de pe moodle o arhiva ''zip'' care va avea la baza folderul ''src'' din schelet si fisierul ''ID.txt'' ce contine user@stud.acs.pub.ro pe prima linie
.
└── src
├── __init__.py
├── DFA.py
├── NFA.py
... (alte surse pe care le folositi)
├── ID.txt