Differences

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

Link to this comparison view

cpl:labs:02 [2015/12/06 19:49]
laura.vasilescu [Conflicte si ambiguitati]
cpl:labs:02 [2016/10/05 23:18] (current)
bogdan.nitulescu [Secțiunea de declarații Bison]
Line 14: Line 14:
   * LALR(1) - Look Ahead Left to Right with a one-token lookahead   * LALR(1) - Look Ahead Left to Right with a one-token lookahead
   * GLR - Generalized Left to Right    * GLR - Generalized Left to Right 
-Majoritatea parserelor folosesc LALR(1), care are mai putine capabilitati,​ insa este semnificativ mai rapid si mai usor de folosit decat GLR. Si noivom genera tot parsere LALR.+Majoritatea parserelor folosesc LALR(1), care are mai putine capabilitati,​ insa este semnificativ mai rapid si mai usor de folosit decat GLR. Si noi vom genera tot parsere LALR.
  
 ''​Bison''​ este varianta GNU a ''​yacc''​ (Yet Another Compiler-Compiler). ''​Bison''​ este varianta GNU a ''​yacc''​ (Yet Another Compiler-Compiler).
Line 72: Line 72:
   * simbolul de start al gramaticii (opțional)   * simbolul de start al gramaticii (opțional)
 <code C> <code C>
-%start <​tip> ​nume1 nume2    ​+%start <​tip> ​nume  ​
 </​code>​ </​code>​
  
Line 98: Line 98:
 %type <​int_value>​ exp %type <​int_value>​ exp
 </​code>​ </​code>​
-Dacă este suficient să întroarcem ​valori de tip int, și nu definim un union de tipuri, atunci ''<​token_type>''​ este omis în declararea tokenilor.+Dacă este suficient să întoarcem ​valori de tip int, și nu definim un union de tipuri, atunci ''<​token_type>''​ este omis în declararea tokenilor.
  
   * Precedența %left. Aceasta va fi detaliată intr-un subcapitol ulterior.   * Precedența %left. Aceasta va fi detaliată intr-un subcapitol ulterior.
-O listă completă cu simbolii ​''​bison''​ găsiți [[http://​www.gnu.org/​software/​bison/​manual/​html_node/​Table-of-Symbols.html|aici]] ​+O listă completă cu simbolurile ​''​bison''​ găsiți [[http://​www.gnu.org/​software/​bison/​manual/​html_node/​Table-of-Symbols.html|aici]] ​
   ​   ​
 ==== Secțiunea de reguli gramaticale ==== ==== Secțiunea de reguli gramaticale ====
Line 134: Line 134:
 {C statements} {C statements}
 </​code> ​ </​code> ​
-<​note>​Bison nu verifica ​corectitudinea codului C din acțiuni ci doar îl copiaza în fișierul .c al parserului, unde va fi verificat de compilatorul de C. Așadar erorile de C vor fi raportate abia la compilarea parserului.</​note>​+<​note>​Bison nu verifică ​corectitudinea codului C din acțiuni ci doar îl copiaza în fișierul .c al parserului, unde va fi verificat de compilatorul de C. Așadar erorile de C vor fi raportate abia la compilarea parserului.</​note>​
 Acțiunea poate fi plasată la sfârșitul unei alternative sau chiar în interiorul acesteia. Acțiunea poate fi plasată la sfârșitul unei alternative sau chiar în interiorul acesteia.
   * ''​$$''​ reprezinta rezultatul, adica valoarea ce va fi atribuită neterminaului de la stânga regulii, cel la care se va reduce regula.   * ''​$$''​ reprezinta rezultatul, adica valoarea ce va fi atribuită neterminaului de la stânga regulii, cel la care se va reduce regula.
   * ''​$n''​ este al n-lea termen din regula sintactica.   * ''​$n''​ este al n-lea termen din regula sintactica.
-Acțiunile definite în mijlocul unei reguli se folosesc numai în anumite situații, pot folosi doar simbolii anteriori ​acesteia (fiindcă se execută înainte ca simbolii ​următori regulii să fie parsați) și sunt o sursă de conflicte. Vom reveni asupra acestora în laboratorul ​urmator.+Acțiunile definite în mijlocul unei reguli se folosesc numai în anumite situații, pot folosi doar simboluri anterioare ​acesteia (fiindcă se execută înainte ca simbolurile ​următoare regulii să fie parsați) și sunt o sursă de conflicte. Vom reveni asupra acestora în laboratorul ​următor.
 ==== Secțiunea de cod C ==== ==== Secțiunea de cod C ====
 Secțiunea de cod C trebuie să conțină: Secțiunea de cod C trebuie să conțină:
Line 146: Line 146:
 </​code>​ </​code>​
   * definiția funcției ''​main''​ care conține un apel către ''​yyparse()''​   * definiția funcției ''​main''​ care conține un apel către ''​yyparse()''​
-===== Flex si bison/yacc =====+===== Flex și bison/yacc =====
  
-Vom vedea acum cum comunica ​analizorul lexical (flex) cu analizorul sintactic (bison). +Vom vedea acum cum comunică ​analizorul lexical (flex) cu analizorul sintactic (bison). 
-''​Bison'' ​genereaza ​un parser, din ''​nume_gram.y'', ​in fisierul ​''​nume_gram.tab.c'' ​si un fiser header ''​nume_gram.tab.h''​. ​In fisierul ​header fiecare token are asociat un numar. ​Fisierul ​de intrare pentru lex (.l) include ​fisierul ​header (cu extensia ''​.tab.h''​) ​si foloseste ​numerele atribuite tokenilor ​in acest fisier.+''​Bison'' ​generează ​un parser, din ''​nume_gram.y'', ​în fișierul ​''​nume_gram.tab.c'' ​și un fișier ​header ''​nume_gram.tab.h''​. ​În fișierul ​header fiecare token are asociat un numar. ​Fișierul ​de intrare pentru lex (.l) include ​fișierul ​header (cu extensia ''​.tab.h''​) ​și folosește ​numerele atribuite tokenilor ​în acest fisier.
 {{ :​cpl:​labs:​flex_bison.png?​600 |}} {{ :​cpl:​labs:​flex_bison.png?​600 |}}
  
-Intrarea pentru ''​bison''​ este un sir de tokeni furnizat de flex prin functia ​yylex(). ​+Intrarea pentru ''​bison''​ este un șir de tokeni furnizat de flex prin funcția ​yylex(). ​
  
 Numerele asociate tokenilor: Numerele asociate tokenilor:
-  * Numarul ​unui token literal este valoarea sa ASCII +  * Numărul ​unui token literal este valoarea sa ASCII 
 <code C> <code C>
 [-+]               ​return *yytext; [-+]               ​return *yytext;
 </​code> ​ </​code> ​
-va returna valoarea ASCII a caracterului ‘-’ (45), respective ​valoarea ASCII a caracterului ‘+’ (43) +va returna valoarea ASCII a caracterului ‘-’ (45), respectiv ​valoarea ASCII a caracterului ‘+’ (43) 
-  * Ceilalti ​tokeni primesc numere ​incepand ​cu 257+  * Ceilalți ​tokeni primesc numere ​începând ​cu 257
  
 <​note>​Token-ul ''​error''​ este rezervat pentru tratarea erorilor</​note>​ <​note>​Token-ul ''​error''​ este rezervat pentru tratarea erorilor</​note>​
    
  
-Sa presupunem ​ca avem o gramatica ​care defineste ​token-ul INTEGER ​si acesta a primit valoarea 258 in fisierul ​header nume_gram.tab.h. +Să presupunem ​că avem o gramatică ​care definește ​token-ul INTEGER ​și acesta a primit valoarea 258 în fișierul ​header nume_gram.tab.h. 
-Fiecare ​aparitie ​instructiunii ​“return INTEGER” din fisierul ​.l va fi inlocuitain acest caz cu “return 258”. +Fiecare ​apariție ​instrucțiunii ​“return INTEGER” din fișierul ​.l va fi înlocuităîn acest caz cu “return 258”. 
-Pentru a obtine ​tokenii, bison apeleaza functia ​yylex. Altfel spus, fisierul ​cu extensia .tab.h atribuie ​fiecarui ​token/​terminal un identificator unic de tip int. Cum acest header este inclus ​in fisierul *.l, numele tokenilor sunt inlocuite ​cu identificatorul unic.+Pentru a obține ​tokenii, bison apelează funcția ​yylex. Altfel spus, fișierul ​cu extensia .tab.h atribuie ​fiecărui ​token/​terminal un identificator unic de tip int. Cum acest header este inclus ​în fisierul *.l, numele tokenilor sunt înlocuite ​cu identificatorul unic.
  
-Daca un token are asociata ​o valoare, aceasta poate fi transmisa catre parser prin variabila ''​yylval''​. +Dacă un token are asociată ​o valoare, aceasta poate fi transmisă către ​parser prin variabila ''​yylval''​. 
-(in cazul nostru un int) +(în cazul nostru un int) 
  
-<​note>​Atentie: Nu faceti ​confuzie ​intre id-ul token-ului dat de bison (identificator unic) si valoarea pe care o trimite din yylex.+<​note>​Atenție: Nu faceți ​confuzie ​între ​id-ul token-ului dat de bison (identificator unic) și valoarea pe care o trimite din yylex.
 </​note>​ </​note>​
  
-====== Conflicte ​si ambiguitati ​======+====== Conflicte ​și ambiguități ​======
  
 **Conflictele** sunt rezultatul unei gramatici ambigue. Conflictele pot fi fie shift/​reduce,​ fie reduce/​reduce **Conflictele** sunt rezultatul unei gramatici ambigue. Conflictele pot fi fie shift/​reduce,​ fie reduce/​reduce
-  * Intr-un conflict shift/​reduce ​actiunea implicita ​este cea de shift. +  * Într-un conflict shift/​reduce ​acțiunea implicită ​este cea de shift. 
-  * Intr-un conflict reduce/​reduce ​actiunea implicita ​este de a reduce folosind prima regula aplicabila ​a gramaticii. +  * Într-un conflict reduce/​reduce ​acțiunea implicită ​este de a reduce folosind prima regulă aplicabilă ​a gramaticii. 
-Exemplu de conflict shift/​reduce datorat ​ambiguitatii ​''​dangling else'':​+Exemplu de conflict shift/​reduce datorat ​ambiguității ​''​dangling else'':​
  
-Cand token-ul ''​else''​ este citit si devine token-ul lookahead, ceea ce a fost deja citit se potriveste ​pe prima regula si ar putea fi redus. Dar, este de asemenea legal sa shiftam else-ul, pentru ca sirul de tokeni de la intrare s-ar putea potrivi pe a doua regula.  +Când token-ul ''​else''​ este citit și devine token-ul lookahead, ceea ce a fost deja citit se potrivește ​pe prima regulă și ar putea fi redus. Dar, este de asemenea legal să shiftam else-ul, pentru ca șirul ​de tokeni de la intrare s-ar putea potrivi pe a doua regulă.  
-Deoarece parser-ul ​prefera ​sa shifteze, else-ul va fi atasat ​if-ului cel mai imbricat. ​+Deoarece parser-ul ​preferă ​sa shifteze, else-ul va fi atașat ​if-ului cel mai imbricat. ​
  
-Daca parser-ul ar alege sa reduca, atunci ​cand poate, ​si nu sa shifteze, else-ul va fi atasat ​if-ului exterior(primul).+Dacă parser-ul ar alege să reducă, atunci ​când poate, ​și nu să shifteze, else-ul va fi atașat ​if-ului exterior(primul).
  
 <code C> <code C>
Line 194: Line 194:
 </​code>​ </​code>​
  
-Cu aceasta gramaticasecventa ​de intrare ''​if (exp1) if (exp2) stmt1 else stmt2''​ poate fi parsata in 2 moduri diferite:+Cu această gramaticăsecvența ​de intrare ''​if (exp1) if (exp2) stmt1 else stmt2''​ poate fi parsată în 2 moduri diferite:
 <code C> <code C>
 Cazul 1: if (e1) { if (e2) s1 else s2 } Cazul 1: if (e1) { if (e2) s1 else s2 }
Line 201: Line 201:
 </​code>​ </​code>​
  
-Acesta este un asa zis conflict shift/​reduce legitim. ​Exista ​cazuri ​in care gramatica ​genereaza ​astfel de conflicte pentru că a fost scrisa ambiguu, ​desi se putea scrie si intr-o forma neambiguaIn aceste cazuri se recomanda ​rescriere regulilor cu conflicte.+Acesta este un asa zis conflict shift/​reduce legitim. ​Există ​cazuri ​în care gramatica ​generează ​astfel de conflicte pentru că a fost scrisa ambiguu, ​deși se putea scrie și într-o formă neambiguăÎn aceste cazuri se recomandă ​rescriere regulilor cu conflicte.
 <code C> <code C>
-expr : expr ’+’ expr+expr 
 +: expr ’+’ expr
 | expr ’*’ expr | expr ’*’ expr
 | ’-’ expr | ’-’ expr
Line 210: Line 211:
 ; ;
 </​code>​ </​code>​
-Gramatica expresiilor ​genereaza ​conflicte ​cand uitam sa implementam ​asociativitatea ​si precedenta ​tokenilor. +Gramatica expresiilor ​generează ​conflicte ​când uitam să implementăm ​asociativitatea ​și precedența ​tokenilor. 
-Sunt 2 moduri de a specifica ​precedenta si asociativitatea pentru o gramatica: implicit ​si explicit. ​Cand specificam ​implicit trebuie ​sa introducem un simbol neterminal pentru fiecare nivel de precedenta. ​Iata mai jos solutia implicita:+Sunt 2 moduri de a specifica ​precedența și asociativitatea pentru o gramatică: implicit ​și explicit. ​Când specificăm ​implicit trebuie ​să introducem un simbol neterminal pentru fiecare nivel de precedenta. ​Iată mai jos soluția implicită:
 <code C> <code C>
-expr: expr '​+'​ factor +expr 
-  | factor ​+: expr '​+'​ factor 
 +| factor ​
 ; ;
  
-factor: factor '​*'​ term +factor 
-  | term+: factor '​*'​ term 
 +| term
 ; ;
  
-term:     ​'​-'​ term    +term 
-  | ID +: '​-'​ term    
-  | NUMBER +| ID 
-  ;+| NUMBER
 ; ;
 </​code>​ </​code>​
  
  
-Gramatica devine mai stufoasa, dar neambigua. Metoda ​explicita ​presupune folosirea ​explicita ​a regulilor de precedenta ​suportate de Bison.+Gramatica devine mai stufoasă, dar neambiguă. Metoda ​explicită ​presupune folosirea ​explicită ​a regulilor de precedență ​suportate de Bison.
  
-**Asociativitatea** ​si **precedenta** pot fi specificate ​in urmatorul ​mod:+**Asociativitatea** ​și **precedența** pot fi specificate ​în următorul ​mod:
   * Pentru asociativitate se pot folosi: ''​%left'',​ ''​%right'',​ ''​%nonassoc''​   * Pentru asociativitate se pot folosi: ''​%left'',​ ''​%right'',​ ''​%nonassoc''​
-  * Precedenta ​operatorilor binari: +  * Precedența ​operatorilor binari: 
-    * Se specifica ​asociativitatea folosind ''​%left''​ +    * Se specifică ​asociativitatea folosind ''​%left''​ 
-    * Operatorii din acelasi ​grup au aceeasi precedenta, iar intre grupuri, ​precedenta creste in jos. +    * Operatorii din același ​grup au aceeași precedență, iar între ​grupuri, ​precedența crește în jos. 
-  * Pentru a stabili ​precedenta ​operatorilor unari se foloseste ''​%prec''​. Acesta ​schimba precedenta ​unei reguli la precedenta ​tokenului ​urmator.+  * Pentru a stabili ​precedența ​operatorilor unari se foloseste ''​%prec''​. Acesta ​schimbă precedența ​unei reguli la precedența ​tokenului ​următor.
 <code C> <code C>
 %left ’+’ ’-’ %left ’+’ ’-’
 %left ’*’ ’/’ %left ’*’ ’/’
 ... ...
-expr : expr ’+’ expr+expr 
 +: expr ’+’ expr
 | expr ’*’ expr | expr ’*’ expr
 | ’-’ expr %prec ’*’ | ’-’ expr %prec ’*’
Line 248: Line 252:
 </​code>​ </​code>​
  
-**Exercitiu**: Incercati sa rezolvati ​conflictul shift/​reduce pentru ''​dangling else''​ folosind reguli de precedenta.+**Exercițiu**: Încercați să rezolvați ​conflictul shift/​reduce pentru ''​dangling else''​ folosind reguli de precedență.
   ​   ​
  
-====== ​Instructiuni ​compilare ​si executie ​folosind flex si bison ======+====== ​Instrucțiuni ​compilare ​și execuție ​folosind flex și bison ======
  
 <code bash> <code bash>
Line 260: Line 264:
  
 </​code>​ </​code>​
-====== Exerciții de laborator (10p) ======+====== Exerciții de laborator (13p) ======
  
 În rezolvarea laboratorului folosiți arhiva de sarcini {{ :​cpl:​labs:​lab02_simple_ops.zip | lab02_simple_ops.zip }} În rezolvarea laboratorului folosiți arhiva de sarcini {{ :​cpl:​labs:​lab02_simple_ops.zip | lab02_simple_ops.zip }}
Line 271: Line 275:
 ===== Exercițiul 2 - variables (5p) ===== ===== Exercițiul 2 - variables (5p) =====
  
-Extindeți exercițul anterior astfel încât calculatorul să accepte instrucțiuni de atribuire și variabile și să poată evalua expresii care conțin variabile cărora le-a fost atribuită o valoare. Pentru a implementa această extensie, veți avea nevoie de o **tabelă de simboli** cu ajutorul căreia să țineți minte variabilele cărora li s-a atribuit o valoare și din care să citiți valoarea curentă a unei variabile în cazul în care variabila este operand al unei expresii. Tabela de simboli o puteți implementa folosind ''​std::​map''​. ​+Extindeți exercițiul anterior astfel încât calculatorul să accepte instrucțiuni de atribuire și variabile și să poată evalua expresii care conțin variabile cărora le-a fost atribuită o valoare. Pentru a implementa această extensie, veți avea nevoie de o **tabelă de simboli** cu ajutorul căreia să țineți minte variabilele cărora li s-a atribuit o valoare și din care să citiți valoarea curentă a unei variabile în cazul în care variabila este operand al unei expresii. Tabela de simboli o puteți implementa folosind ''​std::​map<char *, int>''​. ​
  
 +===== Exercițiul 3 (bonus - 3p) =====
  
 +Extindeți exercițiul anterior astfel încât calculatorul să accepte parantezarea expresiilor și operatorul unar minus (-), având în vedere prioritatea operatorilor.
cpl/labs/02.1449424165.txt.gz · Last modified: 2015/12/06 19:49 by laura.vasilescu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0