VB6: Ayuda con evaluación de expresiones matemáticas

Publicado por elcalez, Octubre 07, 2008, 15:22:45

Tema anterior - Siguiente tema

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

elcalez

Buenas Argentos. Recurro a uds. porque estoy investigando y no llego a ningún punto.

Estoy haciendo un programita para liquidar sueldos y jornales en VB6, y me trabo en la parte de las fórmulas. Lo que deseo es que el usuario pueda poner, por ejemplo:

SI(ANTIGUEDAD>3;ANTIGUEDAD*IMPORTE*2%;ANTIGUEDAD*IMPORTE*1%)

En donde lo que se resuelve es si la antiguedad es mayor a 3 años, haga ANTIGUEDAD por un IMPORTE que ingresa el usuario cuando carga el concepto x 2%, en cambio si es menor a 3, lo mismo por 1%.

Este ejemplo lo puedo hacer (ej con una function en donde le pase las variables) pero sería para ese ejemplo puntual, y así como tengo una variable permitida como IMPORTE, hay otras (como MAYOR para el sueldo más alto del semestre, CANTIDAD para cantidad de "algo", etc). Por eso lo que quiero es que el usuario pueda poner la fórmula que quiera, con lo cual las Function serían interminables, y si analizo caracter por caracter pasaría lo mismo: las distintas variantes se vuelven infinitas. Para expresiones sencillas como:

ANTIGUEDAD*IMPORTE

pude usar del SCRIPTCONTROL, eval y asunto terminado. Por más que sea ANTIGUEDAD*IMPORTE o ANTIGUEDAD*IMPORTE-20+CANTIDAD, o cualquier otro cálculo simple, cambio las variables por el número, lo transformo en un string, lo evalúo con eval y a la lona.

El tema es cuando el cálculo es complejo, cuando hay un SI, o un SUMA para sumar varios conceptos, o fórmulas anidadas, en fin, cuando la expresión es "compleja" por llamarlo de alguna manera, no se que hacer.

Busqué por internet (ahí conseguí lo del SCRIPTCONTROL) pero no encontré una soga. No pido que me resuelvan el problema, sino que me tiren ideas para destrabar el problema y poder seguir con el proyecto. No se si hay alguna dll de Excel para añadir, que se yo. Hace días que le doy vuelta al asunto y es por eso que acudo a la ayuda.

Muchas gracias y saludos.

hardrocker

No entiendo bien, será porque estoy esuchando música... a ver.
Lo que vos querés hacer es que el usuario ingrese por ejemplo la formula en una textbox y que el programa reconozca cada elemento de ella y realice los cálculos?
O sea, lo que querés hacer es parametrizarlo bien para que reconozca todas las operaciones aún anidadas?
-·=»‡«=·- M€ÐÏØ€VØ-·=»‡«=·-

elcalez

Cita de: hardrocker en Octubre 07, 2008, 22:58:34
No entiendo bien, será porque estoy esuchando música... a ver.
Lo que vos querés hacer es que el usuario ingrese por ejemplo la formula en una textbox y que el programa reconozca cada elemento de ella y realice los cálculos?
O sea, lo que querés hacer es parametrizarlo bien para que reconozca todas las operaciones aún anidadas?


Exacto! Parecido a lo que hace Excel (en donde ponés "=SI(A1>A2;3;2)" y calcula) pero obviamente no tiene que ser tan complejo como lo que hace excel.

Es un bardo, ya lo se. De última, tengo 2 caminos: o me pongo a escribir código a lo pavote para que analice la cadena o simplifico los cálculos posibles y chau. Siempre me gusta complicarme la vida!  :jaja:

hardrocker

Si, es que es mucho lío.
Sino vas a tener que pensarla demasiaaaado bien como para que sea muy parametrizable y ahorrarte código... implementar algun patrón de diseño quizá, pero si es una aplicación "simple" no vale la pena realmente.
Si se me ocurre algo lo posteo, pasa que ahora ando con mis problemas con Crstal reports :P
-·=»‡«=·- M€ÐÏØ€VØ-·=»‡«=·-

elcalez

Cita de: hardrocker en Octubre 08, 2008, 19:50:07
Si, es que es mucho lío.
Sino vas a tener que pensarla demasiaaaado bien como para que sea muy parametrizable y ahorrarte código... implementar algun patrón de diseño quizá, pero si es una aplicación "simple" no vale la pena realmente.
Si se me ocurre algo lo posteo, pasa que ahora ando con mis problemas con Crstal reports :P

Jaja. Ok Hard, gracias. Si, es algo que tenía en los planes: hacer como una especie de "asistente" para fórmulas complejas para que venga todo más tranqui.

Bueno, eso pedía, alguna idea, no código: como diría Perón (?) la caña para pescar y no el pescado.

Saludos!

Predicador

Hola,
En vez de usar script control, podes usar directamente Excel para evaluar las expresiones, eso si, tenes que agregar la referencia en VB y es probable que sea necesario que Excel este instalado en la maquina que corra el software.
Un ejemplito:
Public Function evaluame()
   Dim excel_app As Object
   Set excel_app = CreateObject("Excel.Application")

   Debug.Print excel_app.Evaluate("if(1=1,1,0)")
   
   excel_app.Quit
   Set excel_app = Nothing
End Function

Si queres otra alternativa, ya deberias hacer un mini analizador de expresiones, no son complicados de hacer, solo definir una gramatica, crear un analizador lexico e integrar todo para que haga el parsing de las operaciones. Para tu grupo reducido de operaciones no deberia tomar mas de 100 0 150 lineas.
Baii
En la mayoría de las comunidades online el 90% de los usuarios son mirones que nunca contribuyen, el 9% contribuyen un poco y el 1% son los responsables de casi toda la acción. Nielsen

elcalez

Cita de: Predicador en Octubre 09, 2008, 04:42:24
Hola,
En vez de usar script control, podes usar directamente Excel para evaluar las expresiones, eso si, tenes que agregar la referencia en VB y es probable que sea necesario que Excel este instalado en la maquina que corra el software.
Un ejemplito:
Public Function evaluame()
   Dim excel_app As Object
   Set excel_app = CreateObject("Excel.Application")

   Debug.Print excel_app.Evaluate("if(1=1,1,0)")
   
   excel_app.Quit
   Set excel_app = Nothing
End Function

Si queres otra alternativa, ya deberias hacer un mini analizador de expresiones, no son complicados de hacer, solo definir una gramatica, crear un analizador lexico e integrar todo para que haga el parsing de las operaciones. Para tu grupo reducido de operaciones no deberia tomar mas de 100 0 150 lineas.
Baii

Gracias Predicador, no había leído la respuesta. Muy bueno lo de Excel pero me desmoralizó el hecho de que quizá tenga que tener instalado Excel.
Voy a sentarme a hacer lo que proponés en el segundo párrafo. Te pido un favor: me das un ejemplo "estúpido"? Una punta del ovillo para empezar el razonamiento, no te pido código ni ejemplos del mismo, sino una idea. A ver si masomenos te entendí: Definir la gramática entiendo por definir las "palabras reservadas" de mis expresiones, es correcto? (Ej. "SI", "MAYOR", "ANTIGUEDAD", etc). "Analizador léxico" sería repasar caracter por caracter lo que escribió el usuario? Y parsing no tengo la menor idea de que significaría  :-[

Gracias!

Predicador

Hola, directamente te doy todo el codigo que esta presente en la pagina de soporte de microsoft.
http://support.microsoft.com/kb/86688
Si queres podes eliminar varias cosas ya que hay muchas funciones extras que nunca vas a usar, leelo bien, entendelo y luego extendelo a que tambien funcione con IF (o SI en castellano).
Tene en cuenta que la gramatica del IF (el menos el IF de excel)  es:
IF(<expresion>; <evaluar si true>; <evaluar si false>)
por ende lo podes tomar casi como un caso particular de funcion.
Baii
En la mayoría de las comunidades online el 90% de los usuarios son mirones que nunca contribuyen, el 9% contribuyen un poco y el 1% son los responsables de casi toda la acción. Nielsen

elcalez

Uf, parece ser muy interesante! Ya me lo estoy copiando y analizando.

Gracias Predicador!

Predicador

Uff! tenia unos minutos libres en la oficina y termine de definir la gramatica y modificar el codigo para que sporte IFs... los cambios son sencillos, solo agregue que IF sea reconocifo como palabra resevada y luego la parte donde interpreta el IF...
en la funcion e_pers:
   ' *************** Gramatica del IF
   ' Agregado por Predicad0r
   ElseIf e_tok = "if" Then
      Call e_nxt
      Call e_match("(")
      tr = e_prs(1)
      Call e_match(";")
     
      If tr Then
                 n = e_prs(1)
                 Call e_match(";")
                 Call e_nxt
      Else
                 Call e_nxt
                 Call e_match(";")
                 n = e_prs(1)
      End If
      Call e_match(")")
   ' *************** fin IF

la puse inmediatmente antes del  ElseIf e_tok = "id" Then
y en e_next() agreue un  Case "if" asi detecta a IP como keyword
Para probar esto....
Sub ev()
  Dim n As Double
  Dim st As String
  st = "if(1+1<2;1;3+1) + 1"
  If e_eval(st, n) Then
    Debug.Print n
  End If
End Sub

y Devuleve 5 como deberia :)
Exitos!
En la mayoría de las comunidades online el 90% de los usuarios son mirones que nunca contribuyen, el 9% contribuyen un poco y el 1% son los responsables de casi toda la acción. Nielsen

elcalez

#10
Increíble lo suyo amigo! Me prestás la cabeza un rato? Todavía estoy interpretando el código  :P

A ver si te seguí: en e_next habría que agregar el if?

         Select Case LCase$(e_spelling)
            Case "and"
            Case "if"
            Case "eqv"
            Case "imp"
            Case "mod"
            Case "not"
            Case "or"
            Case "xor"
            Case Else: is_keyword = 0
         End Select



Bueno, mientras preguntaba lo probé y EFECTIVAMENTE FUNCA!  :palmas:

Sigo leyendo/interpretando el código con el extra del IF. Por lo que veo es bastante adaptable a lo que quiero.

MUCHIISIMAS GRACIAS!  :up:

PD: Recomiendo el código. Es interesante.


AGREGO PARA EVITAR DOBLE POST:

Acerca del código, tengo algunas dudas:

1) La p de e_prs es solo para ver el orden en que hace los cálculos no? Es decir, primero que resuelva la multiplicación y división, después + y -, etc. Es decir, que si no me interesa "xor", "eqv" y "imp" en los elseif finales de e_prs, puedo alterar el valor de los elseif? Quedaría (para los que me interesan):
        ElseIf p <= 5 And e_tok = "*" Then Call e_nxt: n = n * e_prs(6)
        ElseIf p <= 5 And e_tok = "/" Then Call e_nxt: n = n / e_prs(6)
        ElseIf p <= 4 And e_tok = "+" Then Call e_nxt: n = n + e_prs(5)
        ElseIf p <= 4 And e_tok = "-" Then Call e_nxt: n = n - e_prs(5)
        ElseIf p <= 3 And e_tok = "=" Then Call e_nxt: n = n = e_prs(4)
        ElseIf p <= 3 And e_tok = "<" Then Call e_nxt: n = n < e_prs(4)
        ElseIf p <= 3 And e_tok = ">" Then Call e_nxt: n = n > e_prs(4)
        ElseIf p <= 3 And e_tok = "<>" Then Call e_nxt: n = n <> e_prs(4)
        ElseIf p <= 3 And e_tok = "<=" Then Call e_nxt: n = n <= e_prs(4)
        ElseIf p <= 3 And e_tok = ">=" Then Call e_nxt: n = n >= e_prs(4)
        ElseIf p <= 2 And e_tok = "and" Then Call e_nxt: n = n And e_prs(3)
        ElseIf p <= 1 And e_tok = "or" Then Call e_nxt: n = n Or e_prs(2)

Esto es correcto?

2) ¿Que tipo de variable es "is_id%" cuando arma la cadena en
Case 'a' to 'z', '_'
en la sub e_next? Y de paso, para que evalúa el "_"? No entendí para que el "_".

Bueno, perdón por el abuso. Creo que con eso estoy. Nuevamente gracias.

Predicador

#11
Exactamente donde lo pusiste, igual pongo el codigo completo por si a alguien mas le sirve:
Dim e_input As String     ' Expression input string.
Dim e_tok As String       ' Current token kind.
Dim e_spelling As String  ' Current token spelling.
Dim e_error As Integer    ' Tells if syntax error occurred.

' e_eval
'   Evaluate a string containing an infix numeric expression.
'   If successful, return true and place result in <value>.
'   This is the top-level function in the expression evaluator.
Function e_eval(ByVal s As String, value As Double) As Integer
   ' Initialize.
   e_error = 0
   e_input = s
   Call e_nxt

   ' Evaluate.
   value = e_prs(1)

   ' Check for unrecognized input.
   If e_tok <> "" And Not e_error Then
      MsgBox "syntax error, token = '" + e_spelling + "'"
   e_error = -1
   End If

   e_eval = Not e_error
End Function

' e_prs
'   Parse an expression, allowing operators of a specified
'   precedence or higher. The lowest precedence is 1.
'   This function gets tokens with e_nxt and recursively
'   applies operator precedence rules.
Function e_prs(p As Integer) As Double
   Dim n As Double    ' Return value.
   Dim fun As String  ' Function name.

   ' Parse expression that begins with a token (precedence 12).
   If e_tok = "num" Then
      ' number.
      n = Val(e_spelling)
      Call e_nxt
   ElseIf e_tok = "-" Then
      ' unary minus.
      Call e_nxt
      n = -e_prs(11)    ' Operand precedence 11.
   ElseIf e_tok = "not" Then
      ' logical NOT.
      Call e_nxt
      n = Not e_prs(6)  ' Operand precedence 6.
   ElseIf e_tok = "(" Then
      ' parentheses.
      Call e_nxt
      n = e_prs(1)
      Call e_match(")")
   
   ' *************** Gramatica del IF
   ' *************** Agregado por Predicador
   ElseIf e_tok = "if" Then
      Call e_nxt
      Call e_match("(")
      tr = e_prs(1)
      Call e_match(";")
     
      If tr Then
                 n = e_prs(1)
                 Call e_match(";")
                 z = e_prs(1)
      Else
                 z = e_prs(1)
                 Call e_match(";")
                 n = e_prs(1)
      End If
      Call e_match(")")
   ' *************** fin IF
     
   ElseIf e_tok = "id" Then
      ' Function call.
      fun = e_spelling
      Call e_nxt
      Call e_match("(")
      n = e_prs(1)
      Call e_match(")")
      n = e_function(fun, n)
   Else
      If Not e_error Then
         MsgBox "syntax error, token = '" + e_spelling + "'"
         e_error = -1
      End If
   End If

   ' Parse binary operators.
Do While Not e_error
  If 0 Then  ' To allow ElseIf .
  ElseIf p <= 11 And e_tok = "^" Then Call e_nxt: n = n ^ e_prs(12)
  ElseIf p <= 10 And e_tok = "*" Then Call e_nxt: n = n * e_prs(11)
  ElseIf p <= 10 And e_tok = "/" Then Call e_nxt: n = n / e_prs(11)
  ElseIf p <= 9 And e_tok = "\" Then Call e_nxt: n = n \ e_prs(10)
  ElseIf p <= 8 And e_tok = "mod" Then Call e_nxt: n = n Mod e_prs(9)
  ElseIf p <= 7 And e_tok = "+" Then Call e_nxt: n = n + e_prs(8)
  ElseIf p <= 7 And e_tok = "-" Then Call e_nxt: n = n - e_prs(8)
  ElseIf p <= 6 And e_tok = "=" Then Call e_nxt: n = n = e_prs(7)
  ElseIf p <= 6 And e_tok = "<" Then Call e_nxt: n = n < e_prs(7)
  ElseIf p <= 6 And e_tok = ">" Then Call e_nxt: n = n > e_prs(7)
  ElseIf p <= 6 And e_tok = "<>" Then Call e_nxt: n = n <> e_prs(7)
  ElseIf p <= 6 And e_tok = "<=" Then Call e_nxt: n = n <= e_prs(7)
  ElseIf p <= 6 And e_tok = ">=" Then Call e_nxt: n = n >= e_prs(7)
  ElseIf p <= 5 And e_tok = "and" Then Call e_nxt: n = n And e_prs(6)
  ElseIf p <= 4 And e_tok = "or" Then Call e_nxt: n = n Or e_prs(5)
  ElseIf p <= 3 And e_tok = "xor" Then Call e_nxt: n = n Xor e_prs(4)
  ElseIf p <= 2 And e_tok = "eqv" Then Call e_nxt: n = n Eqv e_prs(3)
  ElseIf p <= 1 And e_tok = "imp" Then Call e_nxt: n = n Imp e_prs(2)
  Else
       Exit Do
  End If
Loop

   e_prs = n
End Function

' e_function.
'   Evaluate a function. This is a helper function to simplify
'   e_prs.
Function e_function(fun As String, arg As Double) As Double
   Dim n As Double

   Select Case LCase$(fun)
   Case "abs": n = Abs(arg)
   Case "atn": n = Atn(arg)
   Case "cos": n = Cos(arg)
   Case "exp": n = Exp(arg)
   Case "fix": n = Fix(arg)
   Case "int": n = Int(arg)
   Case "log": n = Log(arg)
   Case "rnd": n = Rnd(arg)
   Case "sgn": n = Sgn(arg)
   Case "sin": n = Sin(arg)
   Case "sqr": n = Sqr(arg)
   Case "tan": n = Tan(arg)
   Case Else
      If Not e_error Then
         MsgBox "undefined function '" + fun + "'"
         e_error = -1
      End If
   End Select

   e_function = n
End Function

' e_nxt
'   Get the next token into e_tok and e_spelling and remove the
'   token from e_input.
'   This function groups the input into "words" like numbers,
'   operators and function names.
Sub e_nxt()
   Dim is_keyword As Integer
   Dim c As String  ' Current input character.

   e_tok = ""
   e_spelling = ""

   ' Skip whitespace.
   Do
      c = Left$(e_input, 1)
      e_input = Mid$(e_input, 2)
   Loop While c = " " Or c = Chr$(9) Or c = Chr$(13) Or c = Chr$(10)

   Select Case LCase$(c)

   ' Number constant. Modify this to support hexadecimal, etc.
   Case "0" To "9", "."
      e_tok = "num"
      Do
         e_spelling = e_spelling + c
         c = Left$(e_input, 1)
         e_input = Mid$(e_input, 2)
      Loop While (c >= "0" And c <= "9") Or c = "."
      e_input = c + e_input

   ' Identifier or keyword.
   Case "a" To "z", "_"
      e_tok = "id"
      Do
         e_spelling = e_spelling + c
         c = LCase$(Left$(e_input, 1))
         e_input = Mid$(e_input, 2)
         is_id% = (c >= "a" And c <= "z")
         is_id% = is_id% Or c = "_" Or (c >= "0" And c <= "9")
      Loop While is_id%
      e_input = c + e_input

      ' Check for keyword.
      is_keyword = -1
      Select Case LCase$(e_spelling)
         Case "and"
         Case "eqv"
         Case "imp"
         Case "mod"
         Case "not"
         Case "or"
         Case "xor"
         Case "if" ' **** Agregado por Predicador
         Case Else: is_keyword = 0
      End Select
      If is_keyword Then
         e_tok = LCase$(e_spelling)
      End If

   ' Check for <=, >=, <>.
   Case "<", ">"
      e_tok = c
      c = Left$(e_input, 1)
      If c = "=" Or c = ">" Then
         e_tok = e_tok + c
         e_input = Mid$(e_input, 2)
      End If

   ' Single character token.
   Case Else
      e_tok = c
   End Select

    If e_spelling = "" Then
       e_spelling = e_tok
   End If
End Sub

' e_match
'   Check the current token and skip past it.
'   This function helps with syntax checking.
Sub e_match(token As String)
   If Not e_error And e_tok <> token Then
      MsgBox "expected " + token + ", got '" + e_spelling + "'"
      e_error = -1
   End If
   Call e_nxt
End Sub

Sub test()
  Dim n As Double
  Dim st As String
  st = "if(1+1<2;1;3+1) + 1"
  If e_eval(st, n) Then
    Debug.Print n
  End If
End Sub

para probarlo solo llamar a test
Las partes que agrege estan indicadas (igual son solo dos partecitas), una agrega el IF como keyword y el otro complementa la gramatica de las expresiones para soportar IF.
Baii

EDIT: Modifique la parte de la gramatica del IF ya que tenia problemas con las subexpresiones del tipo "if(2 <= 1;1+1+1;0-0+1)"
EDIT 2: tiene un problema, aun asi la condicion sea verdadera, evalua la condicion falsa de todos modos, por ende algo del tipo IF(1=1;1;1/0) va a dar error. Te dejo como tarea que arregles eso (o sea, que se saltee la expresion que no es necesario evaluar)
En la mayoría de las comunidades online el 90% de los usuarios son mirones que nunca contribuyen, el 9% contribuyen un poco y el 1% son los responsables de casi toda la acción. Nielsen

Predicador

Cita de: elcalez en Octubre 14, 2008, 05:13:54
Acerca del código, tengo algunas dudas:

1) La p de e_prs es solo para ver el orden en que hace los cálculos no? Es decir, primero que resuelva la multiplicación y división, después + y -, etc. Es decir, que si no me interesa "xor", "eqv" y "imp" en los elseif finales de e_prs, puedo alterar el valor de los elseif? Quedaría (para los que me interesan):
        ElseIf p <= 5 And e_tok = "*" Then Call e_nxt: n = n * e_prs(6)
        ElseIf p <= 5 And e_tok = "/" Then Call e_nxt: n = n / e_prs(6)
        ElseIf p <= 4 And e_tok = "+" Then Call e_nxt: n = n + e_prs(5)
        ElseIf p <= 4 And e_tok = "-" Then Call e_nxt: n = n - e_prs(5)
        ElseIf p <= 3 And e_tok = "=" Then Call e_nxt: n = n = e_prs(4)
        ElseIf p <= 3 And e_tok = "<" Then Call e_nxt: n = n < e_prs(4)
        ElseIf p <= 3 And e_tok = ">" Then Call e_nxt: n = n > e_prs(4)
        ElseIf p <= 3 And e_tok = "<>" Then Call e_nxt: n = n <> e_prs(4)
        ElseIf p <= 3 And e_tok = "<=" Then Call e_nxt: n = n <= e_prs(4)
        ElseIf p <= 3 And e_tok = ">=" Then Call e_nxt: n = n >= e_prs(4)
        ElseIf p <= 2 And e_tok = "and" Then Call e_nxt: n = n And e_prs(3)
        ElseIf p <= 1 And e_tok = "or" Then Call e_nxt: n = n Or e_prs(2)

Esto es correcto?
Correcto, la p marca el nivel de precedencia, esto es para que 1+2<4 se evalue como (1+2)<3

Cita de: elcalez en Octubre 14, 2008, 05:13:54
2) ¿Que tipo de variable es "is_id%" cuando arma la cadena en
Case 'a' to 'z', '_'
en la sub e_next? Y de paso, para que evalúa el "_"? No entendí para que el "_".
eso se usa para las funciones, evalua que el nombre de una funcion [o identificador] (definidas en el codigo) puede compenzar por a..z y _ y luego debe seguir con uno o mas numeros/letras.
Esto te facilita si queres utilizar variables dentro de la gramatica, solo habria que extenderla apenas un poco mas como para que evalue esos identificadores.
Baii
En la mayoría de las comunidades online el 90% de los usuarios son mirones que nunca contribuyen, el 9% contribuyen un poco y el 1% son los responsables de casi toda la acción. Nielsen

elcalez

#13
Estuve tratando de que evalúe una condición y en caso de ser verdadera que obvie la otra, pero entra y sale tantas veces de e_prs que estoy mareao sin una gota de alcohol  :P

El error de la división lo capturé (juro que antes de ver tu mensaje!) así:

       ElseIf p <= 10 And e_tok = "/" Then
           Call e_nxt
           If e_prs(11) <> 0 Then
               n = n / e_prs(11)
           Else
               MsgBox "Error. Se intenta dividir por 0!"
               e_error = -1
           End If


Quizá se pueda hacer con menos líneas, quizá en el if se podría reemplazar una variable ya asignada como e_prs(11) para no entrar 2 veces en esta función, pero bue, es hasta donde me dió la cabeza en este momento. Igual te digo que me encanta como quedó. Pero te voy a repetir una pregunta que te hice y que con el asunto del "_" quedó medio oculta o si me la respondiste no entendí:
si pongo "Option Explicit" me aparece que "is_id%" no está declarada. Quería saber que tipo de variable es. Está en la parte de la asignación de letras:

is_id% = (c >= "a" And c <= "z")
is_id% = is_id% Or c = "_" Or (c >= "0" And c <= "9")
Loop While is_id%
e_input = c + e_input


Bueno, esa pregunta de vicioso nomás. Por enésima vez, gracias: me sirvió un montón el código, son un par de líneas nomás y está muy bueno.

Saludos!

PD: Lo de "_" digamos que entendí que estaba para utilizarlo en una función que tenga "_", pero en el código puntual no se utiliza no? Es decir, las funciones que ponen en el ejemplo (abs, eqv, and, or, etc etc) no hay ninguna con "_".


Predicador

Perdon, te habia entendido mal el tema del is_id, variable la cual tiene mas pinta de ser Booleana que la mismisima hija de George Boole :P
Es ceirto, no hay funcion algun con _ ahora mismo, pero puede haberlo, mas que nada lo que expresa es los nombres validos de funciones que podrias llegar a definir.
Baii
En la mayoría de las comunidades online el 90% de los usuarios son mirones que nunca contribuyen, el 9% contribuyen un poco y el 1% son los responsables de casi toda la acción. Nielsen

elcalez

Cita de: Predicador en Octubre 14, 2008, 14:05:11
Perdon, te habia entendido mal el tema del is_id, variable la cual tiene mas pinta de ser Booleana que la mismisima hija de George Boole :P

Jaja, es bien Bul la guacha! Había probado en definirla como Booleana pero me tiraba error porque no se sacaba los "%".
PERFECTO. No jodo más. Muy interesante el código (lo digo por milésima vez, pero no encontré mucho en google y con el link que pasaste más las mejoras, ojalá que les sirva a algunos).

Salud y saludos!

Predicador

Cita de: elcalez
El error de la división lo capturé (juro que antes de ver tu mensaje!) así:
No me referia a la division por cero per se (ya que si hay una division por cero el mismo visual basic la detecta), sino al hecho que en el IF sea la condicion falsa o verdadera, se evaluan ambas expresiones en el IF. Lo que deberias modificar es que se evalue solo la expresion corresponiente.
Lo que implica:
   ' *************** Gramatica del IF
   ' Agregado por Predicad0r
   ElseIf e_tok = "if" Then
      Call e_nxt
      Call e_match("(")
      tr = e_prs(1)
      Call e_match(";")
     
      If tr Then  ' IF true
                 n = e_prs(1)
                 Call e_match(";")
                 'z = e_prs(1)   ' en vez de evaluar la segunda condicion innecesariamente
                 Call e_skip(")") ' la salteamos hasta que cierra el parentesis
                 
      Else  ' IF flase Se evalua la segunda expresion
                 'z = e_prs(1)   ' en vez de evaluar innecesariamente
                 Call e_skip(";") ' salteamos hasta la posicion de la segunda expresion
                 Call e_match(";")
                 n = e_prs(1)
      End If
      Call e_match(")")
   ' *************** fin IF

donde:
' Saltea caracteres hasta que encuntra until_ch
' controla que los parentesis esten balanceados por si until_ch es un parentesis
' By Predicador
Sub e_skip(until_ch As String)
   parentesis = 0
   e_tok = Left$(e_input, 1)
   Do While ((e_tok <> until_ch) Or (parentesis > 0)) And e_input <> ""
      If e_tok = "(" Then parentesis = parentesis + 1
      If e_tok = ")" Then parentesis = parentesis - 1
      e_input = Mid$(e_input, 2)
      e_tok = Left$(e_input, 1)
   Loop
   e_input = Mid$(e_input, 2)
End Sub

Baii
En la mayoría de las comunidades online el 90% de los usuarios son mirones que nunca contribuyen, el 9% contribuyen un poco y el 1% son los responsables de casi toda la acción. Nielsen

elcalez

Quedó bárbaro. No sabía como salir del if de tr (hacer el corte cuando evalúa una y otra condición), te entendí lo que planteaste (que si la primer condición es verdadera, no evalúe la segunda) pero como te dije, entraba tantas veces en la function e_prs que me perdí. No se me ocurrió poner otra función, pero evidentemente es la mejor solución. Lo de la división por cero, tampoco se me ocurrió capturar el error del VB y lo hice directamente con un mensaje personalizado.
El código realmente superó mis espectativas. Que vocación que tenés Predicador, realmente admirable (no digo sana envidia porque la envidia nunca es sana)  :up:

Gracias!