Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
lfa:2025:proiect:etapa2 [2025/11/24 21:57] ldaniel |
lfa:2025:proiect:etapa2 [2025/11/25 20:48] (current) ldaniel |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| Deadline etapa 1: 26 nov 2025 23:55 | Deadline etapa 1: 26 nov 2025 23:55 | ||
| - | Deadline etapa 2: 1 ian 2026 23:55 | + | Deadline etapa 2: 16 ian 2026 23:55 |
| Link etapa 1 [[lfa:2025:proiect:etapa1| Etapa 1]] | Link etapa 1 [[lfa:2025:proiect:etapa1| Etapa 1]] | ||
| + | |||
| + | Schelet de cod: {{:lfa:2025:proiect:lfa2025_skel_etapa2.zip|}} | ||
| Line 72: | Line 74: | ||
| Un parser foloseste output-ul produs de lexer pentru etapa de analiza sintactica a textului. | Un parser foloseste output-ul produs de lexer pentru etapa de analiza sintactica a textului. | ||
| - | Construim un parser pe baza unei gramatici care contine reguli ce descriu sintaxa valida a inputului. O astfel de gramatica va folosi lexemele generate de analiza lexicala in rolul de terminali. | + | Construim un parser pe baza unei gramatici care contine reguli ce descriu sintaxa valida a inputului. O astfel de gramatica va folosi categoriile lexicale generate de analiza lexicala in rolul de terminali. |
| === Sintaxa pentru gramatici === | === Sintaxa pentru gramatici === | ||
| - | In implementarea noastra, sintaxa folostia pentru descrierea gramaticilor in format text va fi urmatoarea: | + | In implementarea noastra, sintaxa folosita pentru descrierea gramaticilor in format text va fi urmatoarea: |
| <code> | <code> | ||
| s: a b | s: a b | ||
| - | s: A | + | s: b a |
| - | s: B | + | a: A |
| + | b: B | ||
| </code> | </code> | ||
| - | unde a si b sunt neterminali si A si B sunt terminali. Preferam sa notam neterminalii cu litere mici si terminalii cu litere mari deoarece terminalii nostri vor fi tokenii proveniti de la analiza lexicala. De asemenea, putem scrie simplificat cele trei reguli de mai sus astfel: | + | unde a si b sunt neterminali si A si B sunt terminali. Preferam sa notam neterminalii cu litere mici si terminalii cu litere mari deoarece terminalii nostri vor fi tokenii proveniti de la analiza lexicala. De asemenea, putem scrie simplificat primele 2 reguli astfel, folosind o alternativa: |
| <code> | <code> | ||
| - | s: a b|A|B | + | s: a b|b a |
| </code> | </code> | ||
| E important ca inainte si dupa simbolul pentru alternativa sa nu existe spatii, pentru citirea corecta a fisierului. In mod automat simbolul care introduce prima regula din gramatica este considerat simbolul de start, indiferent de denumirea lui. | E important ca inainte si dupa simbolul pentru alternativa sa nu existe spatii, pentru citirea corecta a fisierului. In mod automat simbolul care introduce prima regula din gramatica este considerat simbolul de start, indiferent de denumirea lui. | ||
| Line 90: | Line 93: | ||
| Gramaticile folosite de noi vor fi intotdeauna in Forma Normala Chomsky, pentru a putea aplica algoritmul care valideaza apartenenta unui cuvant la limbajul generat de gramatica. | Gramaticile folosite de noi vor fi intotdeauna in Forma Normala Chomsky, pentru a putea aplica algoritmul care valideaza apartenenta unui cuvant la limbajul generat de gramatica. | ||
| - | O gramatica este in FNC daca are doar reguli de tipul A: B C (un neterminal produce doi neterminali) sau A: a (un neterminal produce un singur terminal). | + | O gramatica este in FNC daca are doar reguli de tipul a: b c (un neterminal produce doi neterminali) sau a: A (un neterminal produce un singur terminal). |
| Line 100: | Line 103: | ||
| === Arbore de parsare === | === Arbore de parsare === | ||
| - | In plus fata de algoritmul CYK implementat la curs, care ne spune daca un text este acceptat de gramatica, ne dorim sa avem si sirul de reguli prin care am ajuns la acceptare, adica sa obtinem la final un arbore de parsare pentru textul nostru. In scheletul temei aveti implementata o clasa numita ParseTree, care reprezinta arborele de parsare. | + | In plus fata de algoritmul CYK implementat la curs, care ne spune daca un text este acceptat de gramatica, ne dorim sa avem si secventa de derivari care a produs cuvantul, sau echivalent: arborele de parsare pentru textul nostru. In scheletul temei aveti implementata o clasa numita ParseTree, care reprezinta arborele de parsare. |
| - | Arborele de parsare va fi afisat ca un arbore in care copiii au o indentare cu 2 spatii mai la dreapta decat parintele. Pentru regulile intermediare generate de normalizarea gramaticii (care trebuie sa inceapa cu **int_**) nu se va afisa numele regulii, ci direct copiii. Pentru regulile simple, de tipul neterminal produce un terminal (a: TOKEN) se va afisa doar categoria lexicala si lexemul corespunzator, fara numele regulii. Aceste lucruri sunt deja implementate in metoda str() a lui ParseTree. | + | Arborele de parsare va fi afisat ca un arbore in care copiii au o indentare cu 2 spatii mai la dreapta decat parintele. |
| - | Pentru a obtine un arbore de parsare ca rezultat, in implementarea algoritmului CYK va recomandam sa folositi o matrice de dictionare in care pentru fiecare neterminal sa aveti ca valoare un nod de ParseTree cu informatiile despre derivarile bottom-up care au dus la obtinerea acelui neterminal. La final, in caz de acceptare, arborele de parsare afisat va fi nodul de arbore aferent simbolului de start. | + | Atunci cand doreste sa foloseasca o gramatica independenta de context arbitrara pentru parsare, programatorul trebuie intai sa o converteasca (manual) in FNC. Pentru a usura vizualizarea arborilor de parsare, convenim sa denumim toti non-terminalii creati in procesul de conversie cu **int_**. Vom folosi aceasta conventie pentru a nu afisa regulile ce au in stanga un non-terminal de forma **int_**, ci direct copii. Astfel, arborii de parsare sunt mai usor de citit. Pentru regulile simple, de tipul neterminal produce un terminal (a: TOKEN) se va afisa doar categoria lexicala si lexemul corespunzator, fara numele regulii. Aceste lucruri sunt deja implementate in metoda str() a lui ParseTree. |
| + | |||
| + | Pentru a obtine un arbore de parsare ca rezultat, in implementarea algoritmului CYK va recomandam sa folositi o matrice de dictionare in care pentru fiecare neterminal sa aveti ca valoare un ParseTree cu informatiile despre derivarile bottom-up care au dus la obtinerea acelui neterminal. La final, in caz de acceptare, arborele de parsare afisat va fi arborele avand ca radacina simbolul de start. | ||
| === Cerinta: === | === Cerinta: === | ||
| Line 116: | Line 121: | ||
| 3. Completati specificatia pentru Lexerul de expresii lambda in fisierul "**lexer_spec.json**", adaugand regex-ul potrivit pentru fiecare Token. | 3. Completati specificatia pentru Lexerul de expresii lambda in fisierul "**lexer_spec.json**", adaugand regex-ul potrivit pentru fiecare Token. | ||
| - | 4. In clasa Parser completati metoda "parse", pentru a scrie un parser general care citeste o gramatica in FNC din fisierul primit ca parametru la initializare si returneaza arborele de parsare. | + | 4. In clasa Parser completati metoda "parse", care primeste un text de intrare si returneaza arborele de parsare. Folositi-va de campurile lexer si grammar ale parserului pentru analiza lexicala si apoi analiza sintactica a textului. Dupa analiza lexicala va trebui sa ignoratii tokenii SPACE inainte de a trece la analiza sintactica. |
| === Exemplu de parsare === | === Exemplu de parsare === | ||
| - | Pentru textul "int x = 1 + 2" analiza lexicala a produs tokenii [(TYPE, "int"), (ID, "x"), (EQUAL, "="), (NUMBER, "3"), (PLUS, "+"), (NUMBER, "2")] (tokenii de SPACE au fost ignorati). | + | Pentru textul "int x = 1 + 2" analiza lexicala a produs tokenii [(TYPE, "int"), (ID, "x"), (EQUAL, "="), (NUMBER, "3"), (PLUS, "+"), (NUMBER, "2")] (tokenii SPACE au fost ignorati). |
| - | Parserul e configurat cu urmatoarea gramatica (care in exemplu nu e in FNC, dar inainte de a fi interpretata de Parser a fost normalizata): | + | Parserul e configurat cu urmatoarea gramatica (care in exemplu nu e in FNC, dar inainte de a fi interpretata de Parser a fost convertita la FNC): |
| <code> | <code> | ||
| assign: TYPE ID EQUAL sum | assign: TYPE ID EQUAL sum | ||
| Line 169: | Line 174: | ||
| │ ├── __init__.py | │ ├── __init__.py | ||
| │ ├── DFA.py | │ ├── DFA.py | ||
| - | │ ├── Grammar.py | ||
| - | │ ├── Lexer.py | ||
| │ ├── NFA.py | │ ├── NFA.py | ||
| + | │ ├── Regex.py | ||
| + | │ ├── Lexer.py | ||
| │ ├── Parser.py | │ ├── Parser.py | ||
| + | │ ├── Grammar.py | ||
| │ ├── ParseTree.py | │ ├── ParseTree.py | ||
| | ... (alte surse pe care le folositi) | | ... (alte surse pe care le folositi) | ||