Skip to content

Latest commit

 

History

History
131 lines (99 loc) · 4.66 KB

Calc.md

File metadata and controls

131 lines (99 loc) · 4.66 KB

Calculadora Infija :: Construcción Semi-Automática

Debo mencionar que mal interprete la consgina del trabajo practico: asumiendo que el objetvio era crear una calculadora, teniendo en cuenta los conceptos de scanner para el input, que verificase los caracteres validos; y el parser que estos esten en correcto orden, ver 12-old_autoCalc.

Diseño Léxico

No se realizan modificaciones respecto a la versión anterior.

  • EOL
  • NUMBER
  • VAR
  • ADD
  • MUL
  • EQ
  • LET
  • L_BRACKET
  • R_BRACKET

Los mismos se hayan en scanner.h bajo el enum token_t. Fragmento:

typedef enum Token{

    EPSILON,
    //\n
    EOL,
    //[0-9]+
    NUMBER,
    //[a-zA-Z]
    VAR,
    //[ + ]
    ADD,
    //[ * ]
    MUL,
    //[=]
    EQ,
    //[ ( ]
    L_BRACKET,
    //[ ) ]
    R_BRACKET,
    // [let||LET]
    LET,
    //[ . ]
    UNDEFINED
}token_t;

Reglas

En esta iteración se introduce el scanner realizado automaticámente por Flex.

Dónde se definieron las siguientes reglas

%%
[ \t]
[0-9]+                                          { yylval.num = atoi(yytext); return NUMBER; }
[+]                                             { return ADD; }
[*]                                             { return MUL; }
[=]                                             { return EQ; }
[(]                                             { return L_BRACKET; }
[)]                                             { return R_BRACKET; }
("let")|("LET")|("Let")                         { return LET; }
[a-zA-Z]+                                       { yylval.index = add_variable(yytext); return VAR;}
[\n]                                            { return EOL; }
.                                               { yyerror(*yytext);} 
%%

Diseño Sintáctico

En cuanto a la codificación, se optó por la propuesta sugerida en el libro de MUCHNIK. Donde cada transición del automáta esta representada por una funcion, para este caso un formato static void PAS(), donde se espía al próximo token y luego se realiza, de requerirse un terminal, match(TERMINAL) y las transiciones correspondientes.

Esta técnica utilizada es la de Análisis Sintáctico Descendente Recursivo (ASDR), la cual se implementa por rutinas que se van invocando de forma recursiva, contruyendo así el analisis sintactico. Cada función se llama Procedimiento de Análisis Sintáctico (PAS)

Además, me inspire en el manual de BISON para los nombres y diseño de las transiciones.

Si bien, esto se puede simplificar, para una mayor visibilidad encontramos el siguiente automáta:

    <Lines>         ->              |    <Line> <Lines>
    <Line>          ->  EOL         |   <Calc> EOL
    <Calc>          ->  expr        |   <Assignment>
    <Expr>          ->  <Terms>
    <Terms>         ->  <Term>      | <Term> ADD <Terms>
    <Term>          ->  <Factors>
    <Factors>       ->  <Factor>    | <Factor> MUL <Factors>
    <Factor>        ->  NUM         |      VAR       |      L_BRACKET <Expr> R_BRACKET
    <Assignment>    ->  LET VAR EQ <Calc>

Véase el suigiente framento de parcer.c

Donde a cada transición le corresponde una función.

        // <LINES>
        static void lines();

        // <LINE>
        static void line();

        // <CALC>
        static int calc();

        // <EXPR>
        static int expr();
        
        // <ASSIGMENT>
        static int assignment();

        // <TERMS>
        static int terms();

        // <TERM>
        static int term();

        // <FACTORS>
        static int factors();

        // NUMBER || VAR || ( EXPR )
        static int factor();

Para poder obtener cada resultado se produce una reducción, lo que podemos asociar con el concepto visto en Paradigmas de la Programación, folding, donde cada ciertos PAS reducen a un entero, por ello static int PAS()

Nótese como la precesedencia de operadores esta implícita en los PAS, donde primero se TERMS evalúa TERMS ADD TERM y luego FACTORS evalúa FACTORS MUL FACTOR.

Para la resolución de variables opté por contstruir un módulo de memoria memory.h, el cual se encarga de gestionar una "tabla" de símbolos a través de operaciones básicas como create,read y update. Por defecto, las variables no inicializadas se les otorga el valor 0 en el momento de su creación.

Las mismas se inicializan ingresando: LET <var> = <calc>, donde <var> representa una variable reconocida por el scanner y <calc> una operación aritmética.