ayuda!! infijo a postfijo con 1 o mas digitos.

Iniciado por isaaclm, 31 Mayo 2017, 20:22 PM

0 Miembros y 1 Visitante están viendo este tema.

isaaclm

hola amigos, buen dia. alguien me podria ayudar a modificar un codigo de infijo a postfijo con pilas. son 2 cosas que necesito hacer:
1.-ejemplo  : Entrada : (100+5.75) + 100 -> salida : 100 5.75 + 100 +.
el problema es que solo acepta caracteres de 1 solo digito.

2.- la segunda modificacion es evaluar la raiz cuadra representado por el caracter '$' con un prioridad maxima. ejemplo Entrada : $(10*10) -30 ->salida 1 :  10 10 * $ 30 -  salida2 : -20 que es el resultado de la evalucacion.

de antemano les agradeceria su ayuda.

el codigo es el siguiente:

Código (java) [Seleccionar]

class InToPost // infix to postfix conversion
{
    private StackX theStack;
    private String input;
    private String output = "";
    //--------------------------------------------------------------
    public InToPost(String in) // constructor
    {
        input = in;
        int stackSize = input.length();
        theStack = new StackX(stackSize);
    }
    //--------------------------------------------------------------
    public String doTrans() // lo traduce a postfijo
    {
        for(int j=0; j<input.length(); j++)
        {
            char ch = input.charAt(j);
            theStack.displayStack("For "+ch+" "); // *diagnostico*
            switch(ch)
            {
                case '+': // es + o -
                case '-':
                gotOper(ch, 1); // apila operadores
                break; // (precedence 1)
                case '*': // it's * or /
                case '/':
                gotOper(ch, 2); // apila operadores
                break; // (precedence 2)
               
                case '$':
                gotOper(ch, 3); // apila operador raiz cuadrada
                break; // (precedence 3)
               
                case '(': // parentesis izquierdo
                theStack.push(ch); // apilarlo
                break;
                case ')': // parentesis derecho
                gotParen(ch); // apila
                break;
                default: // debe ser un operando
                    output = output + ch; // escribiendo ala salida
                    break;
            } // fin del switch
        } // fin del for
        while( !theStack.isEmpty() ) // apila los restantes operadoeres
        {
            theStack.displayStack("While "); // *diagnostico*
            output = output + theStack.pop(); // escribe la salida
        }
        theStack.displayStack("End "); // *diagnostico*
        return output; // retorna el postfijo
    } // fin de doTrans()
    //--------------------------------------------------------------
    public void gotOper(char opThis, int prec1)
    { // Obtuvo el operador de la entrada
        while( !theStack.isEmpty() )
        {
            char opTop = theStack.pop();
            if( opTop == '(' ) // if es un '('
            {
                theStack.push(opTop); // restaura '('
                break;
            }
            else // es un operador
            {
                int prec2; // precedencia de nuevo operador
                if(opTop=='+' || opTop=='-') //encuentra nuevo operador de precedencia
                prec2 = 1;
                else
                prec2 = 2;
                if(prec2 < prec1) // if precedencia de nuevo operador es menor
                { // que precedencia del viejo operador
                    theStack.push(opTop); // guarda el nuevo operador
                    break;
                }
                else // precedencia de nuevo operador no es menor
                    output = output + opTop; // que prec del viejo operador
            } // fin del else (es un operador)
        } // fin while
        theStack.push(opThis); // apila nuevo operador
    } // fin gotOp()
    //--------------------------------------------------------------
    public void gotParen(char ch)
    { // obtuvo parentesis derecho de la entrada
        while( !theStack.isEmpty() )
        {
            char chx = theStack.pop();
            if( chx == '(' ) // si es extraido '('
            break; // esta listo
            else // si es extraido el operador
            output = output + chx; // output it
        } // fin while
    } // fin popOps()
    //--------------------------------------------------------------
} // fin de la clase InToPost


clase evaluacion postfija
Código (java) [Seleccionar]

class ParsePost
{
    private StackX theStack;
    private String input;
    //--------------------------------------------------------------
    public ParsePost(String s)
    { input = s; }
    //--------------------------------------------------------------
    public int doParse()
    {
        theStack = new StackX(20); // crea una nueva pila
        char ch;
        int j;
        int num1, num2, interAns;
        for(j=0; j<input.length(); j++) // for para cada caracter (char),
        {
            ch = input.charAt(j); // lee la entrada
            theStack.displayStack(""+ch+" "); // *diagnostico*
            if(ch >= '0' && ch <= '9') // if es un numero
            theStack.push((char) (ch-'0')); // lo  apila
            else // es operador
            {
                num2 = theStack.pop(); // extrae operandos
                num1 = theStack.pop();
                switch(ch) // hace la evaluacion aritmetica
                {
                    case '+':
                    interAns = num1 + num2;
                    break;
                    case '-':
                    interAns = num1 - num2;
                    break;
                    case '*':
                    interAns = num1 * num2;
                    break;
                    case '/':
                    interAns = num1 / num2;
                    break;
                    case '$':
                   
                    default:
                        interAns = 0;
                } // end switch
                theStack.push((char) interAns); // apila el resultado
            } // fin del  else
        } // fin del for
        interAns = theStack.pop(); // devuelve respuesta
        return interAns;
    } // fin doParse()
} // fin de la clase ParsePost


este es el codigo de la clase pila

Código (java) [Seleccionar]

class StackX
{
    private int maxSize;
    private char[] stackArray;
    private int top;
    //--------------------------------------------------------------
    public StackX(int s) // constructor
    {
        maxSize = s;
        stackArray = new char[maxSize];
        top = -1;
    }
    //--------------------------------------------------------------
    public void push(char j) // pone un elemento en el tope de la pila
    { stackArray[++top] = j; }
    //--------------------------------------------------------------
    public char pop() // toma un elemento del tope de la pila
    { return stackArray[top--]; }
    //--------------------------------------------------------------
    public char peek() // obtiene el tope de la pila
    { return stackArray[top]; }
    //--------------------------------------------------------------
    public boolean isEmpty() // verdadero si la pila westa vacia
    { return (top == -1); }
    //-------------------------------------------------------------
    public int size() // regresa el tamano
    { return top+1; }
    //--------------------------------------------------------------
    public char peekN(int n) // regresa el elemento al indice n
    { return stackArray[n]; }
    //--------------------------------------------------------------
    public void displayStack(String s)
    {
        System.out.print(s);
        System.out.print("Stack (bottom-->tope): ");
        for(int j=0; j<size(); j++)
        {
            System.out.print( peekN(j) );
            System.out.print(' ');
        }
        System.out.println("");
    }
    //--------------------------------------------------------------
} // fin de la clase StackX


y por ultimo la clase principal la cual testea el programa.

Código (java) [Seleccionar]

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

class InfixApp {
    public static void main(String[] args) throws IOException {
        String input, output;
        int eval;

        while(true) {
            System.out.print("introduce el infijo: ");
            System.out.flush();
            input = getString(); // lee un string de kbd
            if( input.equals("") ) // sale del programa si es [Enter]
                break;
            // crea la traduccion
            InToPost theTrans = new InToPost(input);
            output = theTrans.doTrans(); // hace la traduccion
            System.out.println("Postfix is " + output + '\n');
            ParsePost aParser = new ParsePost(output);
            eval = aParser.doParse(); // hace la evaluacion
            System.out.println("Evaluates to " + eval);
        } // fin del while
    } // fin del  main()
    //--------------------------------------------------------------
    public static String getString() throws IOException
    {
        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(isr);
        String s = br.readLine();
        return s;
    }
    //--------------------------------------------------------------
} // fin de la clase InfixApp








Serapis

#1
Cita de: isaaclm en 31 Mayo 2017, 20:22 PM
modificar un codigo de infijo a postfijo con pilas. son 2 cosas que necesito hacer:
1.-ejemplo  : Entrada : (100+5.75) + 100 -> salida : 100 5.75 + 100 +.
el problema es que solo acepta caracteres de 1 solo digito.
El primer fallo, es que pretendes operar con 1 dígito... eso esta bien en la fase de análisis léxico, para determinar correctamente los identificadores.
Pero en una etapa superior (cuando tratas la semántica), ya debe existir una separación clara, y aunque para un sencillo problema quizás pueda no parecer adecuado tener una tabla de símbolos, lo cierto es que resuelve el problema. simplemente para casos sencillos la tabla de símbolos puede ser un simple array.

En resumen (  :silbar: :silbar: :silbar: :silbar: ) :
- 1º Añade una etapa a modo de analizador léxico, donde reconoces y separas convenientemente cada identificador, y donde
- 2º Añadas luego el identificador a un array. Como hablamos de que es un problema sencillo, y que por ello nos basta con un usar un array, no es descabellado en estos casos, proveer un array estático, lo suficientemente grande, como albergar la expresión más compleja que pueda esperarse tratar... quizás un tamaño de 64 sea suficiente, tú decides ese tamaño.
- 0º Para simplificar el analizador léxico, es adecuado anotar (crear el minilenguaje admitido) las diferentes producciones que pueden darse... es bastante sencillo, si usas BNF o alguna modificación particular.
Básicamente describe que es un número, (que SIEMPRE empieza por un dígito y que está formado por 1 o más digitos y el número acaba cuando aparece un carácter distinto de dígito, dígito, operador, identificador, char, etc...
numero = digito | digito || numero     <--- las dos barras juntas '||' indica concatenación
digito = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9"    <---- la barra '|' indica opcion.
operador = " + "|" - "|" * "|" / "|" $ "  
 

En este ejemplo: digito es cualquiera de los números (caracteres) en el rango 0-9
y número es un digito, o un digito + un número (esto expresa recusividad, ya que número puede expresarse nuevamente con cualquiera de las dos opciones previas, esto es un digito, o un digito + otro número, etc...).

Y operador es cualquiera de los caracteres indicados (inclusído tu 'raíz cuadrada'). fíjate la obligación de estar separado por espacios, es decir un operador son 3 caracteres, el que se reconoce + un espacio acada lado. Así tu analizador léxico, puede indicar error cuando no tenga un espacio a cada lado. El número no exige espacio, gracias a la última producción que falta por definir... expresión, y se define como:


expresion = numero || operador || numero | numero || operador || expresion
id = char | char || id  <---- identificador
char = "a"|"b"|"c"|"d"|"e"|"f"|"g"|"h"| ... |"y"|"z"|
 <---- carácter, ojo, veáse que son minúsculas, por tanto debiera generarse error en el analizador léxico, si aparece mayúsculas, ya que no se ha definido su uso en para generar los identificadores...

formula =  id || " = " || expresion <---- una producción sería la fórmula entera (la expresión entera, más la asignación a un identificador).

A veces la 'formula' es fácil confundirlo con las producciones, debido al '=', en realidad para las producciones suele usarse el símbolo: ":=" o también "::=", yo los he usado indistintamente " = ", para explicar una producción (cualquier combinación del 'lenguaje' como una formula (una combinación específica del lenguaje que hemos llamado 'formula', espero que se sepa distinguir cuando hablo de una cosa y cuando de otra.

Claramente se ve, que a una 'formula' se le asigna una expresión y es reconocida por un identificador.
Por su parte una expresión consiste de una lista de números separados por un operador. Igual que número tiene 2 opciones de ser definido, se podría decir que una expresión es simple si consta de solo dos números y un operador, y una expresión es compleja si consta de una lista de números (mayor de 2), donde siempre empieza con un número y a cada número excepto al último le sigue un operador.

Tu analizador léxico puede optar por indicar fallo cuando falta espacios a ambos lados del operador, o dada la simplicidad de la expresión, puedes modificarlo y añadirlo tú mismo por código (autocorreción).

Nota como id (un identificador) es uno o más caracteres y que una 'formula' requiere el identificador y luego el símbolo "=", también con espacios a ambos lados.

Nota que hay otra forma de expresar opciones (de una producción). Y es, usar varias líneas en vez de reunirlas en solo una, para los dígitos, los operadores y los caracteres es bastante claro el modelo de una sola línea, pero para otras, a veces queda más entendible si se usa como varias líneas, donde en cada línea se pone una sola de las opciones posibles. Un ejemplo para número (que valdría igualmente para expresión)

Producción multilínea para número y expresion (es idéntico al anterior)
numero = digito <--- ejemplo: 5
numero = digito || numero   <---- ejemplo: 53456

expresion = numero || operador || numero <---- ejemplo: x = 5 + 3
expresion = numero || operador || expresion
<---- ejemplo: y = 7 + ( 3 - 1 ) <---no hemos definido los paréntesis (en el ejemplo) como operadores, pero los he puesto para diferenciar la parte 'expresión' de esta producción.

Otro ejemplo: valor = 9 - 2 + 16
Estos ejemplos en cambio actualmente darían error:
valor = 44
suma = valor + 12 - 7
...porque no hemos definido lo siguiente para formula:

formula = id | id ||" = "|| expresion <--- --->ejemplos:
valor = 5
h = valor
total = h * cantidad
total = (total + 21)
preciolatas = 12
preciounitario = 32
total = total + (preciolatas * preciounitario)

Este otro ejemplo daría error léxico:
Valor = 5   <---- identificador no admite mayúsculas, tal como está actualmente descrito identificador.
valor = 5H  <---- número solo lleva dígitos, no se ha previsto diferencia de números decimales, hexadecimales, octales, binarios,etc...
valor10 = 23  <--- identificador secompone solo de caracteres en el rango a-z, no puede llevar números (ni menos empezar por él), tal como está actualmente definido identificador.


Hasta aquí el analizador léxico. Éste si debe operar con caracteres hasta ir formando los números (no dígitos), que deben ser añadidos a la tabla de símbolos (un array para algo sencillo basta).

Si quieres profundizar en el asunto, vuelve a leer todo lo previo las veces que haga falta, si solo quieres 'aprobar el examen', te bastaba con leer este párrafo que sigue (y aplicalro bien, obviamente)  :laugh: :laugh: :laugh: :laugh:
Luego en la siguiente fase de análisis se puede operar ya con los tokens que contiene la tabla de símbolos. Pero ahora ya, no opera con 'chars' si no con 'strings'... sólo así, puedes hacer: valor = 534 + 723

Te recuerdo, que una de las ventajas de la notación postfija es que no exige el uso de paréntesis. y por si al final has profundizado, y le has leído varias veces, te aclaro que puede simplificarse mucho, cuando uno acaba por entender que una expresión (como la descrita, básicamente matemática) es una lista, ya que se alternan números y operadores... ..y ahí lo dejo.

Te he dejado como ejercicio optimizar: expresion, formula, numero ...una de ellas es redundante, pero es ideal para ayudar a entenderlo, y una vez entendido puede ser suprimido.

Cita de: isaaclm en 31 Mayo 2017, 20:22 PM
2.- la segunda modificacion es evaluar la raiz cuadra representado por el caracter '$' con un prioridad maxima. ejemplo Entrada : $(10*10) -30 ->salida 1 :  10 10 * $ 30 -  salida2 : -20 que es el resultado de la evalucacion.
Como puedes ver, en ese mismo problema, usando la notación de postfijo (polaca inversa), no requiere el uso de paréntesis, ya que el orden en que se usan los operadores no da lugar a dudas.

Ayuda mucho construir un árbol de análisis sintáctico, no es obligado, pero sí para acabar de entenderlo bien.

p.d.: Nota: Se deja como ejercicio, dónde colocarías (que producción debería llevar los paréntesis y cómo sería esa producción), los paréntesis. En los operadores no se incluye paréntesis... para indicar prioridad/precedencia. Aunque la notación postfija, no requiere de paréntesis, si el analizador léxico.