| 
  Universidad de Costa Rica  | 
 | 
| ![[<=]](../../../img/back.gif)  ![[home]](../../../img/home.gif)  | ![[<>]](../../../img/index.gif)  | ![[\/]](../../../img/bottom.gif)  ![[=>]](../../../img/next.gif)  | 
El programa de la Figura 1 es una calculadora que evalúa expresiones complejas, con paréntesis. Tiene la limitación de que trabaja con números de un solo dígito.
     
Modifique este programa para que pueda procesar expresiones con 
números de varios dígitos. Limite su trabajo a los 
métodos "aparea()", "num()" y 
"Evaluar()". Use la clase "Token.h" de 
la
Figura 2 y complete el método 
"yylex()" para obtener un programa que pueda leer de 
la línea de comandos valores numéricos que contengan 
separadores para miles y millones. También use funciones de 
utiliería como
"atof()" para obtener el valor numérico de una 
hilera. Su programa debe procesar correctamente estos ejemplos:
 C:\DIR\SubDir> CLC.exe ( 1,234,567.00 + 3 )
==> 1,234,570.00C:\DIR\SubDir> CLC.exe ( 1.234.567,00 + 3 )
==> 1,234,570.00C:\DIR\SubDir> CLC.exe ( 1_234_567.00 + 3 )
==> 1,234,570.00     
El caracter "_" nunca se usa como marcador de 
decimles. Como no siempre es posible saber si la coma o el punto 
son el marcador de decimales, su programa debe permitir indicar 
cuál se usa incluyendo un punto o una coma al principio:
 C:\DIR\SubDir> CLC.exe , ( 1,234 + 3 )
==> 4,234 C:\DIR\SubDir> CLC.exe . ( 1,234 + 3 )
==> 1,237C:\DIR\SubDir> CLC.exe ( 1,234.567,00 + 3 )
==> ?? error (,.,)C:\DIR\SubDir> CLC.exe ( 1.234,567.00 + 3 )
==> ?? error (.,.)
| 
// Token.h    (C) 2010 adolfo@di-mare.com
/** \file  Token.h
    \brief Ejemplo de una analizador léxico yylex() implementado a mano
    para la gramática de la calculadora. En la práctica es
    necesario reprogramar \c yylex() para que reconozca un conjunto
    de tokens y lexemas diferente.
*/
#ifndef Token_h
#define Token_h
#include <string>
#include <cstdlib> // strlen(), etc.
using std::string;
#include <iostream>
#include <cctype>
#include <climits>         // CHAR_MAX
/// Contiene la pareja <code> <Token, Lexema> </code> que retorna \c yylex().
class Token {
private:
    int    m_codigo; ///< \c Token::Codigo. Valor numérico que representa al token.
    string m_lexema; ///< Lexema asociado al código.
    int  m_fl;       ///< \c first_line.   Línea que contiene la primera letra del token.
    int  m_fc;       ///< \c first_column. Columna en la que aparece la primera letra del token.
    int  m_ll;       ///< \c last_line.    Línea que contiene la última letra del token.
    int  m_lc;       ///< \c last_column.  Columna en la que aparece la última letra del token.
public:
    enum Codigo {
        NUM = 256+99+1-32,  // podría ser otro, mientras no "choque"
                            // con otros valores para tokens
        ERROR  = 666, FIN  = 999
    };
    Token()       { *this = 0; } ///< Constructor.
    Token(char c) { *this = c; } ///< Constructor para una letra.
    Token(int  c) { *this = c; } ///< Constructor sinónimo de <code> Token(char c) </code>.
    Token(const Token& o) { *this = o; } ///< Constructor de copia.
    const string& lexema() const { return m_lexema;  } ///< Retorna el lexema del token.
    const int     num()    const { return m_codigo;  }  ///< Código numérico del token.
    const int     token () const { return num(); }      ///< Sinónimo de \c num().
    const char*   Nombre() const { return Nombre(m_codigo); } ///< Nombre del token.
    static const char* Nombre(int);
    void   operator=( int c ); /// Asignación a partir de un entero o de una letra.
    Token& operator=( const Token& );
    void   set( int c, const Astring& lexema, int, int, int, int);
    void   loc( int &, int &, int &, int &) const;
}; // Token
/// Analizador léxico simple usado para tokenizar las letras de una hilera.
class Anlizador_Lexico {
private:
    const char * m_str; ///< Hilera grandota que contiene todas las letras.
    int m_idx; ///< Indica la siguiente posición en \c m_str a reconocer.
    int m_len; ///< Longitud de \c m_str.
public:
    /// Constructor por defecto.
    Anlizador_Lexico() : m_str(""),m_idx(0),m_len(0) { }
    ~Anlizador_Lexico() { } ///< Destructor.
    /// Constructor para usar \c str.
    Anlizador_Lexico( const char* str ) : { set(str); }
    /// Prepara a \* this para que use \c str.
    void set( const char* str ) : { m_str = str; m_idx = 0; m_len=strlen(m_str); }
    /// Retorna el siguiente token del analizador léxico.
    int yylex( Token & tk ); //<== Esto es lo que falta de implementar !!!
};
/// Deja el lexema como la hilera nula a menos que \c "c" sea un caracter válido.
inline void Token::operator=( int c ) {
    m_codigo =  c;
    if ( (0 < c) && (c <= CHAR_MAX) ) {
        m_lexema = c;
    } else {
        m_lexema = "";
    }
    m_fl = m_fc = m_ll = m_lc = 1;
}
inline void Token::set( int c, const Astring& lexema,
                        int fl=1, int fc=1, int ll=1, int lc=1 ) {
    m_codigo = c;
    m_lexema = lexema;
    m_fl = fl;
    m_fc = fc;
    m_ll = ll;
    m_lc = lc;
}
/// Retorna la posición del token.
/// - \c fl==first_line.   Línea que contiene la primera letra del token.
/// - \c fc==first_column. Columna en la que aparece la primera letra del token.
/// - \c ll==last_line.    Línea que contiene la última letra del token.
/// - \c lc==last_column.  Columna en la que aparece la última letra del token.
inline void Token::loc( int &fl, int &fc, int &ll, int &lc) const {
    fl = m_fl;
    fc = m_fc;
    ll = m_ll;
    lc = m_lc;
}
/// Copia.
inline Token& Token::operator=( const Token& o ) {
    m_codigo = o.m_codigo;
    m_lexema = o.m_lexema;
    m_fl = o._fl;
    m_fc = o._fc;
    m_ll = o._ll;
    m_lc = o._lc;
    return *this;
}
/// ¿ l == r ?
inline operator == (const Token& l, const Token& r) {
    return l.token() == r.token() && l.lexema() == r.lexema();
}
/// ¿ l != r ?
inline operator != (const Token& l, const Token& r) {
    return ! (l == r);
}
/// Retorna el nombre del token cuyo valor numérico es \c num.
const char* Token::Nombre(int num) {
    if      (num == '+')             return "+";
    else if (num == '-')             return "-";
    else if (num == '*')             return "*";
    else if (num == '/')             return "/";
    else if (num == Token::NUM)      return "NUM";
    else if (num == Token::FIN)      return "FIN";
    else                             return "ERROR";
} // Token::Nombre()
#endif // Token_h
// EOF: Token.h
 | 
Entregue su tarea por correo electrónico, como lo hizo anteriormente.
| 
 | 
![[mailto:]](../../../img/mailbox.gif) Adolfo Di Mare <adolfo@di-mare.com>.
  Adolfo Di Mare <adolfo@di-mare.com>.
| ![[home]](../../../img/home.gif)  |   | ![[/\]](../../../img/top.gif)  |