Hay dos casos diferentes a considerar, dependiendo de la sintaxis de su idioma. Si su idioma usa paréntesis para indicar la aplicación de funciones (por ejemplo f(2+1)
), entonces la precedencia es irrelevante. La función debe insertarse en la pila y desplegarse después (para el ejemplo anterior, el resultado es 2 1 + f
). Alternativamente, puede tratar la función como un valor y generarla de inmediato, y generar una operación de invocación de función después del paréntesis de cierre (que de lo contrario debería tratarse de la misma manera que cualquier otro paréntesis), por ejemplo f 2 1 + $
, dónde $
está la operación de invocación de función.
Sin embargo, si su lenguaje no utiliza paréntesis para indicar la invocación de la función, sino que coloca el argumento directamente después de la función sin ninguna puntuación especial (por ejemplo f 2 + 1
), como aparentemente es el caso del ejemplo de Wikipedia, entonces las cosas son un poco más complicadas. Tenga en cuenta que la expresión que acabo de dar ás como ejemplo es ambigua: ¿se aplica f a 2 y 1 agregado al resultado, o agregamos 2 y 1 juntos y luego llamamos f con el resultado?
De nuevo, hay dos enfoques. Simplemente puede empujar la función a la pila de operadores cuando la encuentre y asignarle cualquier precedencia que desee. Este es el enfoque más simple, y aparentemente es lo que ha hecho el ejemplo citado. Sin embargo, hay problemas prácticos. En primer lugar, ¿cómo identificas una función? Si tiene un conjunto finito, es fácil, pero si tiene funciones definidas por el usuario, esto significa que su analizador también necesita retroalimentar su entorno, lo que puede volverse desordenado rápidamente. ¿Y cómo manejas las funciones con múltiples argumentos?
Creo que para este estilo de sintaxis, el uso de funciones como valores que son más útiles para un operador de aplicación de funciones tiene mucho más sentido. Luego, simplemente puede inyectar el operador de la aplicación cada vez que lea un valor y lo último que leyó también fue un valor, por lo que no necesita ninguna forma especial de saber qué identificadores son funciones. También puede trabajar con expresiones que devuelven funciones (lo cual es difícil o imposible con el estilo de función como operación). Y esto significa que puede usar curry para manejar múltiples funciones de argumento, lo cual es una simplificación masiva sobre tratar de manejarlas directamente.
Lo único que debe decidir es cuál es la precedencia de la aplicación de funciones. La elección depende de usted, pero en todos los idiomas que he utilizado que funcionan de esta manera, ha sido el operador más vinculante en el lenguaje y ha sido correcto asociativo. (La única variación interesante es Haskell, que además de tener la versión fuertemente vinculante descrita, también tiene un sinónimo con el símbolo $
que es el operador más débilmente vinculante en el lenguaje, permitiendo expresiones como f 2 + 1
aplicar f a 2 y f $ 2 + 1
aplicar a todo el resto de la expresión)
sin( max( 2 3) / 3 * 3.1415)