Table of Contents

Tema de casă 1 - Analiza sintactică

În cadrul acestei teme de casă veţi implementa partea de analiză lexicală şi sintactică a unui compilator pentru limbajul LCPL descris mai jos.

Pentru orice nelămuriri cu privire la această temă, puteţi posta un mesaj pe lista de discuţii, de preferinţă având subiectul mesajului de forma [Tema1] …..

Informaţii organizatorice

Enunţ

Va trebui să realizaţi în limbajul C++, folosind Flex și Bison, porţiunea responsabilă cu analiza lexicală şi sintactică a codului sursă pentru un compilator al limbajului LCPL. Programul vostru va trebui să primească la intrare codul sursă LCPL şi să furnizeze la ieşire informaţii (un AST) pentru analiza semantică.

Documentaţia principală în cadrul acestei teme va fi manualul limbajului LCPL. Rezultatul programului realizat de voi va fi folosit de restul compilatorului în temele următoare.

Analiza lexicală

În cadrul analizei lexicale, va trebui să urmăriţi următoarele puncte:

Analiza sintactică

În cadrul analizei sintactice, va trebui să urmăriţi următoarele puncte:

Formatul datelor

În urma compilării temei, va trebui să rezulte un fişier executabil bin/lcpl-parser, ce va conţine funcţia main() asociată programului. Programul va citi de la linia de comandă numele unui fişier LCPL, pe care îl va procesa, şi numele unui fişier în care se va scrie AST-ul. Pentru a formata corespunzător AST-ul, vă punem la dispoziţie o serie de clase ce descriu un AST; acestea vor fi serializate în format JSON, folosind biblioteca rapidjson, ce se găseşte în arhivă. Secţiunea următoare prezintă conţinutul arhivei cu codul pe care va trebui să-l extindeţi/folosiţi.

Exemplu:

class Main inherits IO
    main :
        [out "Hello world!"];
    end;
end;

La ieşire nu vă interesează atât de mult formatul, pentru că aveţi în arhivă codul care generează acest text:

{
  "NodeType": "Program",
  "NodeID": 0,
  "LineNumber": 1,
  "Classes": [
    {
      "NodeType": "Class",
      "NodeID": 1,
      "LineNumber": 1,
      "Name": "Main",
      "Parent": "IO",
      "Features": [
        {
          "NodeType": "Method",
          "NodeID": 2,
          "LineNumber": 2,
          "Name": "main",
          "ReturnType": "Void",
          "Body": {
            "NodeType": "Block",
            "NodeID": 3,
            "LineNumber": 3,
            "Expressions": [
              {
                "NodeType": "Dispatch",
                "NodeID": 4,
                "LineNumber": 3,
                "Name": "out",
                "Arguments": [
                  {
                      "NodeType": "StringConstant",
                      "NodeID": 5,
                      "LineNumber": 3,
                      "Value": "Hello world!"
                  }
                ]
              }
            ]
          }
        }
      ]
    }
  ]
}

Prezentarea arhivei

Pentru a rezolva această temă va trebui să porniţi de la această arhivă.

Structura arhivei este următoarea:

Fişierele sursă prezente în arhivă sunt următoarele

Puteți modifica orice fișier din aceasă arhivă, va trebui să descrieți în fișierul README aceste modificări. Nu vă este impusă o structură anume a programului atâta vreme cât programul vostru face corect analiza sintactică.

Vectori

Extindeți limbajul LCPL prin adăugarea unui tip de date vector. Acest tip de date va fi folosit conform sintaxei din exemplele următoare.

 String[] myArray;
 init sort String[] anArray -> String[];
 myArray = new String[8];
 myArray[3] = "Hello";
 String myValue = myArray[3];

Nu este necesar să implementați vectori de tip Int, însă va trebui să puteți avea vectori din orice tip derivat din Object, nu doar String.

Exemplu de utilizare

Pentru definirea unui obiect de tip stivă cu ajutorul vectorilor se poate folosi următorul program LCPL extins:

 class StringStack 
   var
     String[] st;
     Int index;
   end;
     init Int size -> StringStack :
         st = new String[size];
         self;
     end;
     # adăugarea în stivă
     push String o :
          st[index] = o;
          index = index + 1;
     end;
     # extragerea din stivă
     pop -> String :
         index = index - 1;
         st[index];
     end;
 end;

Clasa Main folosită la testare:

 class Main inherits IO
 var
     StringStack stack = [(new StringStack).init 8];
 end;
     main : 
         [stack.push "Hello"];
         [stack.push "smile"];
         [out [stack.pop][1,5]]; # "mile"
     end;
 end;

Implementare

In LCPL, vectorii nu fac parte din limbajul de bază, ci sunt doar o extensie de sintaxă (Syntax Sugar).

Implementarea NU trebuie să introducă noi tipuri de noduri în AST, ci trebuie să se folosească doar de clasele și nodurile existente. Practic va trebui să simulați vectorii folosind o altă structură de date.

Cum limbajul LCPL nu suportă implicit operații pe obiecte de tip vector, va trebui să vă definiți o clasă ajutătoare pentru a simula aceste funcționalități; puteţi apoi ca în timpul parsării să adugaţi codul acestei clase la fişierul LCPL primit la intrare. Clasa trebuie implementată folosind doar facilităţile oferite de limbajul LCPL de bază.

Sugerăm ca acest cod LCPL suplimentar scris de voi să fie plasat în arhivă într-un fișier numit src/Vector.lcpl.

Nu uitați să introduceţi în AST noduri de tip CAST necesare pentru compatibilitatea tipurilor.

Testarea şi notarea

Testarea temei de casă va folosi o serie de teste ce vor fi disponibile pe vmchecker. Modul în care este distribuit punctajul pentru această temă este următorul:

La punctajele de mai sus se adaugă 25 puncte dacă operațiile pe vectori sunt implementate complet și parserul trece toate testele.

Change Log

FAQ

Q: Clasele din AST sunt documentate undeva? De unde încep?

A: De la clasa “Program”. Conține o listă de “Class”, care conține o listă de “Feature”, ce pot fi “Attribute” sau “Method” … și așa mai departe.

Pentru a înțelege mai bine ierarhia nodurilor din arbore și care sunt structurile de date corespunzătoare, puteți încărca fișierele *.ast.ref din arhiva de teste într-un viewer de JSON.

Q: Cum tratăm erorile sintactice?

A: Mesajul de eroare generat de Bison este suficient.

Q: Dacă există diferențe între teste și textul temei, care e rezultatul corect?

A: În general, dacă descoperiți diferențe între teste și manual, comportamentul din teste e cel bun. Dacă le raportați, noi vom corecta manualul și actualiza change log-ul.

Download