Skip to content

Interpreter for Mini J, a simplified subset inspired by the J language. Includes the ANTLR grammar, a Python-based evaluation engine, basic error handling, and several test cases.

Notifications You must be signed in to change notification settings

lauraapolzan/MiniJ-interpreter

Repository files navigation

Pràctica LP: Mini J

Gramàtica de l'Intèrpret Mini J

La gramàtica de l’intèrpret Mini J està dissenyada per reconèixer i executar expressions inspirades en el llenguatge J, conegut per la seva sintaxi vectorial i funcional. Aquest intèrpret permet treballar amb assignacions, operadors unaris i binaris, composicions de funcions i adverbis. A continuació es descriuen les regles principals de la gramàtica.

Arrel del Programa La regla inicial és root, que representa un programa com una seqüència d’instruccions (statement) fins arribar al final de fitxer (EOF):

root : statement* EOF ;

Statement

Un statement pot ser:

  • ID '=:' funcio: una assignació de funció.
  • ID '=:' expressio : una assignació de variable
  • expressio : una expressió directament
statement
    : ID '=:' funcio        #assignacioFuncio
    | ID '=:' expressio     #assignacioVariable
    | expressio             #expressions
    ;

Funció

Les funcions es poden declarar de tres formes diferents. Per aquest motiu, vaig considerar una bona idea separar-les en tres regles diferents:

  • Operador simple: una funció es pot declarar com un operador unari o un identificador (ID). Aquesta regla cobreix ambdues opcions.
  • Operació identitat: aquestes funcions tenen el símbol d'identitat (]) a la dreta, seguit d’un operador binari. A l'esquerra es pot posar una expressió normal.
  • Composició: aquestes funcions es caracteritzen per utilitzar el símbol de composició (@:). Tant a la dreta com a l'esquerra hi pot haver una altra funció.
funcio
    : operadorU                            #opSimple 
    | expressio operadorB ']'              #opIdentitat
    | funcio '@:' funcio                   #composicio
    ;

Expressió

La regla expressio és una de les més importants de la gramàtica, ja que defineix les diferents formes en què es poden construir expressions en Mini J. Aquesta regla captura totes les estructures bàsiques que poden aparèixer en un programa, i per aquest motiu ha estat dissenyada amb cinc formes diferenciades:

  • Agrupació: Aquesta forma permet encapsular una expressió dins de parèntesis (( expressio )). Serveix per controlar la precedència, especialment en expressions complexes.
  • Operació binària: Aquest cas contempla les operacions amb dos operands i un operador binari entre ells (expressio operadorB expressio). Es defineix amb associativitat a la dreta (<assoc=right>) per tal d’ajustar-se a les convencions del llenguatge.
  • Operació unària: Les operacions unàries són aquelles en què l’operador apareix a l’esquerra de l’expressió (operadorU expressio). En aquesta part de la gramàtica també es tenen en compte les crides a funcions, ja que tenen la mateixa forma sintàctica. D’aquesta manera, es simplifica la gramàtica i s’unifica el tractament d’operadors i funcions definides per l’usuari.
  • Llista: Aquesta forma permet declarar literalment una llista de nombres (llista), que és una estructura fonamental dins del llenguatge.
  • Identificador: Finalment, també es pot fer referència a un ID, que pot ser una variable o una funció definida prèviament.
expressio
    : '(' expressio ')'                             #agrupacio
    | <assoc=right> expressio operadorB expressio   #operacioBinaria
    | operadorU expressio                           #operacioUnaria
    | llista                                        #esLlista
    | ID                                            #identificador
    ;

Implementació del Intèrpret de Mini J

Aquest apartat descriu el codi que constitueix l'intèrpret de Mini J, destacant les seves funcionalitats principals i la seva estructura general.

L’intèrpret de Mini J ha estat implementat en Python i es basa en la gramàtica definida prèviament amb ANTLR. El seu objectiu és analitzar i executar instruccions escrites en aquest llenguatge, que imita certs aspectes del llenguatge J però amb una sintaxi simplificada. El cor de l’intèrpret és la classe EvalVisitor, que s’encarrega de recórrer i avaluar l’arbre de sintaxi generat per ANTLR a partir del codi font.

Arquitectura General

El funcionament intern es basa en un esquema típic de Visitor Pattern, on per cada tipus de node de l’arbre sintàctic hi ha un mètode que sap com interpretar-lo. Això permet modularitzar clarament el comportament de cada construcció del llenguatge (expressions, assignacions, crides a funció, etc.).

Per tal de gestionar els valors durant l’avaluació de les expressions, l’intèrpret utilitza una pila (self.pila). Aquesta estructura actua com una memòria temporal: a mesura que es processen les expressions, els resultats parcials es van apilant, i els operadors consumeixen aquests valors per produir nous resultats que tornen a apilar-se.

Gestió de Variables i Funcions

A més de la pila, es mantenen dos diccionaris:

  • variables, on es guarden els valors associats a noms definits pel programa.
  • funcions, on es guarden les definicions de funcions declarades amb la sintaxi específica de Mini J.

Quan una expressió conté un identificador, l’intèrpret primer comprova si aquest identificador correspon a una variable o a una funció. En el cas d’una variable, se n'obté el valor emmagatzemat; si es tracta d’una funció, se n’executa el cos. El cos de les funcions no s’avalua en el moment de la definició, sinó que es desa tal com s’ha parsejat i només es visita quan la funció és cridada.

Flux d’Execució

El mètode principal (main) carrega el fitxer d’entrada amb extensió .j, i el llegeix línia a línia. Cada línia es processa individualment: primer es genera l’arbre de sintaxi amb ANTLR i després s’avalua amb l’ajuda del visitador. Els comentaris i línies buides són ignorats, i els errors sintàctics i d’execució es detecten i informen de manera clara per facilitar el depurat.

Errors sintàctics

Per detectar i gestionar errors sintàctics durant l'execució dels programes Mini J, s'ha implementat una classe personalitzada anomenada SyntaxErrorListener, que hereta d'ErrorListener d'ANTLR. Aquesta classe sobreescriu el mètode syntaxError i llança una excepció quan es detecta un error durant el procés de parseig.

Aquesta aproximació permet interceptar qualsevol problema en la fase de reconeixement del codi, com per exemple l'ús incorrecte d'un operador, una expressió mal formada o símbols no reconeguts.

Quan es troba un error de sintaxi, l'intèrpret mostra un missatge descriptiu indicant la línia i el tipus d'error, evitant que l'execució continuï de manera incorrecta. Això garanteix que només s'executin les línies sintàcticament vàlides, millorant la robustesa de l'intèrpret.

Jocs de proves

Per verificar que l'intèrpret funciona correctament, s'han preparat diversos jocs de proves.
Cada joc de proves segueix la mateixa estructura: dins del fitxer .j, s'han escrit les expressions a executar i, al costat de cadascuna, s'ha afegit un comentari (NB.) que indica el resultat esperat.

NB. RESULTAT: 1 2 3 4

El contingut de les proves és el seguent:

  • prova1: En aquest joc de proves s'ha verificat que tots els exemples que es troben a l'enunciat de la pràctica funcionin.

  • prova2: Aquest joc de prova comprova que les operacions bàsques i combinades funcionen correctament. Es posa a prova l’intèrpret amb sumes, restes, multiplicacions, comparacions i operadors especials com #, {, ,, així com expressions més complexes amb adverbis i funcions com i. o +:. L’objectiu és validar que l’avaluació i els resultats són correctes en tots els casos.

  • prova3: Aquest joc comprova que la definició i ús de variables i funcions dins de l’intèrpret funcionen correctament. Es posen a prova funcions compostes, reutilització de noms, accés a valors per índex i càlculs més complexos com factorials o filtres per múltiples. S’avalua que la pila es gestioni bé i que la composició de funcions retorni el resultat esperat.

  • prova4: Aquest joc de prova té com a objectiu verificar que l’intèrpret identifica i gestiona correctament diferents tipus d’errors. S’han escrit expressions que contenen errors sintàctics intencionats, com crides a funcions no definides, divisions per zero o operacions amb llistes de longitud incompatible. Això permet assegurar que el sistema detecta aquests casos i mostra missatges d’error clars i útils.

Execució dels jocs de proves

He executat les proves de la manera següent:

 python3 g.py provaX.j > sortidaX.out

About

Interpreter for Mini J, a simplified subset inspired by the J language. Includes the ANTLR grammar, a Python-based evaluation engine, basic error handling, and several test cases.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published