Escuela Técnica Superior de Ingeniería

 

Grado en Ingeniería Informática

Procesadores de Lenguajes

Curso 2022/2023

 

Práctica 7
Analizadores sintácticos ascendentes

 

OBJETIVOS

 

  • Describir la implementación de un analizador sintáctico ascendente
  • Describir la implementación del analizador sintáctico del lenguaje de programación Tinto

 

CÓDIGO A UTILIZAR

 

El código de esta práctica contiene 11 ficheros de los cuales 6 ficheros corresponden al analizador léxico del lenguaje Tinto descrito en la práctica 3. Los ficheros añadidos corresponden al analizador sintáctico ascendente del lenguaje Tinto.

 

GRAMÁTICA DE TINTO EN NOTACIÓN BNF

 

Gramática SLR de Tinto:

  • CompilationUnit ::=  ImportClauseList  TintoDecl

  • ImportClauseList ::=  ImportClauseList  ImportClause

  • ImportClauseList ::=  lambda

  • ImportClause ::= import  identifier  semicolon

  • TintoDecl ::= LibraryDecl

  • TintoDecl ::= NativeDecl

  • LibraryDecl ::=  library  identifier  lbrace  FunctionList  rbrace

  • FunctionList ::=  FunctionList  FunctionDecl

  • FunctionList ::=  lambda

  • FunctionDecl ::=  Access  FunctionType   identifier   ArgumentDecl  FunctionBody

  • NativeDecl ::=  native  identifier  lbrace  NativeFunctionList  rbrace

  • NativeFunctionList ::=  NativeFunctionList  NativeFunctionDecl

  • NativeFunctionList ::=  lambda

  • NativeFunctionDecl ::=  Access  FunctionType   identifier   ArgumentDecl  semicolon

  • Access ::=  public

  • Access ::= private

  • FunctionType  :  Type

  • FunctionType  :  void

  • Type : int 

  • Type  :  char 

  • Type  :  boolean

  • ArgumentDecl  :  lparen  rparen 

  • ArgumentDecl  :  lparen  ArgumentList  rparen 

  • ArgumentList  :  Argument  

  • ArgumentList  :  ArgumentList  comma  Argument

  • Argument  :  Type  identifier

  • FunctionBody  : lbrace StatementList rbrace

  • StatementList  :  StatementList  Statement

  • StatementList  :  lambda

 

  • Statement  :  Decl

  • Statement  :  IdStm

  • Statement  :  IfStm

  • Statement  :  WhileStm

  • Statement  :  ReturnStm

  • Statement  :  NoStm

  • Statement  :  BlockStm

  • Decl  :  Type  IdList  semicolon

  • IdList  :   identifier  

  • IdList  :   identifier   assign   Expr

  • IdList  :  IdList   comma  identifier  

  • IdList  :  IdList   comma  identifier   assign   Expr

  • IfStm  :  if   lparen   Expr  rparen   Statement 

  • IfStm  :  if   lparen   Expr  rparen   Statement  else  Statement

  • WhileStm  :  while   lparen  Expr   rparen   Statement

  • ReturnStm  :  return  Expr  semicolon

  • ReturnStm  :  return  semicolon

  • NoStm  :  semicolon

  • IdStm  :  identifier   assign   Expr  semicolon

  • IdStm  :  identifier  FunctionCall   semicolon

  • IdStm  :  identifier  dot   identifier  FunctionCall  semicolon

  • BlockStm  :  lbrace  StatementList  rbrace

 

  • Expr  :  AndExpr

  • Expr  :  Expr   or  AndExpr 

  • AndExpr  :  RelExpr

  • AndExpr  :  AndExpr  and  RelExpr 

  • RelExpr  :  SumExpr 

  • RelExpr  :   SumExpr  eq  SumExpr

  • RelExpr  :   SumExpr  ne  SumExpr

  • RelExpr  :   SumExpr  gt  SumExpr

  • RelExpr  :   SumExpr  ge  SumExpr

  • RelExpr  :   SumExpr  lt  SumExpr

  • RelExpr  :   SumExpr  le  SumExpr

  • SumExpr  :  not  ProdExpr 

  • SumExpr  :  minus  ProdExpr 

  • SumExpr  :  plus  ProdExpr 

  • SumExpr  :  ProdExpr 

  • SumExpr  :  SumExpr  minus  ProdExpr

  • SumExpr  :  SumExpr  plus  ProdExpr

  • ProdExpr  :  Factor

  • ProdExpr  :  ProdExpr  prod  Factor

  • ProdExpr  :  ProdExpr  div   Factor

  • ProdExpr  :  ProdExpr  mod  Factor

  • Factor  :  Literal 

  • Factor  :  Reference  

  • Factor  :  lparen   Expr   rparen

  • Literal  :  integer_literal 

  • Literal  :  char_literal 

  • Literal  :  true 

  • Literal  :  false

  • Reference  :  identifier 

  • Reference  :  identifier  FunctionCall 

  • Reference  :  identifier  dot   identifier  FunctionCall

  • FunctionCall  :  lparen  rparen

  • FunctionCall  :  lparen  ExprList  rparen

  • ExprList  :  Expr 

  • ExprList  :  ExprList  comma  Expr

 

 

IMPLEMENTACIÓN DEL ANALIZADOR

 

La implementación realizada consta de cinco clases. Tres de ellas desarrollan una implementación genérica de los analizadores ascendentes basados en tablas de desplazamiento/reducción. Las otras dos clases desarrollan el analizador de tinto apoyándose en la implementación genérica.

Las clases utilizadas en la implementación genérica son las siguientes:

  • tinto.ActionElement: Esta clase permite describir el contenido de una celda de la tabla de acciones. Estas celdas pueden ser acciones de desplazamiento, de reducción, de aceptación de la entrada o de error. Los errores se representan en la tabla mediante referencias nulas. Por tanto, la clase se utiliza para representar acciones de desplazamiento, de reducción y de aceptación. La clase contiene dos campos: type, que indica el tipo de acción (por medio de una de las tres constantes definidas en la clase: ACCEPT, SHIFT o REDUCE), y value, que contiene el valor asociado a la acción (estado a apilar en el caso de desplazamiento e índice de la regla a reducir en caso de reducción). Los valores de estos campos se fijan en el constructor y se obtienen de los métodos getType() y getValue().

  • tinto.SintaxException: Esta clase describe un error sintáctico. Los errores sintácticos se producen cuando el algoritmo de desplazamiento/reducción lee una acción nula. El error contiene información sobre la fila y columna del token en el que se produce el error, la categoría del token encontrado y la lista de los tokens esperados.

  • tinto.SLRParser: Esta clase desarrolla el algoritmo de desplazamiento/reducción de manera genérica. Los campos de la clase son los siguientes:

    • lexer:  contiene el analizador léxico que proporciona los tokens a analizar.

    • nextToken: contiene el último token leído del analizador léxico;

    • stack: contiene la pila de estados usada por el algoritmo de desplazamiento/reducción. Los estados se representan en la pila por objetos Integer;

    • actionTable: almacena la tabla de acciones en forma de matriz de objetos ActionElement. La matriz tiene tantas filas como estados y tantas columnas como categorías léxicas. Este campo es protected para que las extensiones de la clase puedan dar contenido a la tabla;

    • gotoTable: almacena la tabla de IrA en forma de matriz de enteros. La matriz tiene tantas filas como estados y tantas columnas como símbolos no terminales. Eeste campo es protected para que las extensiones de la clase puedan dar contenido a la tabla;

    • rule: contiene la información sobre las reglas de la gramática en forma de matriz de enteros. La matriz tiene tantas filas como reglas y dos columnas. La primera columna contiene el símbolo no terminal de la parte izquierda de la regla. La segunda columna conmtiene el número de símbolos en la parte derecha de la regla. Este campo es protected para que las extensiones de la clase puedan dar contenido a las reglas.

    Los métodos de la clase son los siguientes:

    • parse(Lexer): desarrolla el funcionamiento del analizador de desplazamiento/reducción. La llamada a este método permite introducir la referencia al analizador léxico. El contenido del método consiste en inicializar la pila con el estado 0 y realizar iteraciones del algoritmo de desplazamiento/reducción hasta encontrar un error o una acción de aceptar.

    • step(): realiza una iteración del algoritmo de desplazamiento/reducción, es decir, lee el estado de la cima de la pila, considera el siguiente token y busca la celda correspondiente en la tabla de acción. Si la celda es nula lanza un error sintáctico. Si la celda es una acción de desplazamiento ejecuta el método shiftAction() y devuelve false (para que el bucle de análisis continúe su ejecución). Si la celda contiene una acción de reducción ejecuta el método reduceAction() y devuelve false (para que el bucle de análisis continúe su ejecución). Si la celda contiene una acción de aceptar devuelve true para que finalice el bucle de análisis.

    • shiftAction(): realiza una acción de desplazamiento, es decir, lee el siguiente token del analizador léxico y apila el estado correspondiente.

    • reduceAction(): realiza una acción de reducción, es decir: busca la regla a reducir; desapila tantos estados como símbolos tenga la regla; estudia el estado de la cima de la pila; busca en la tabla IrA la celda correspondiente al estado de la cima y al símbolo no terminal de la regla; y apila el valor de la celda de la tabla IrA.

La implementación del analizador ascendente de Tinto se desarrolla en dos clases:

  • tinto.SymbolConstants: es una interfaz que define los códigos de los símbolos no terminales de la gramática. Esta interfaz, al igual que TokenConstants, permite importar todos estos códigos a cualquier clase con solo implementar la interfaz.

  • tinto.TintoParser: desarrolla el analizador ascendente del lenguaje Tinto. La gramática SLR utilizada es ésta. El autómata reconocedor de prefijos viables asociado a la gramática es éste. Para generar la tabla SLR se utilizan los conjuntos siguientes de cada símbolo, que son éstos. La clase se limita a dar contenido a los campos actionTable, gotoTable y rule de la superclase SLRParser.