Je suis en train de mettre en œuvre actuellement un évaluateur d'expression (expressions de ligne simples, comme des formules) basées sur les éléments suivants:
Mon évaluateur fonctionne bien, mais je manque toujours un if()
et je me demande comment procéder.
Avec l'évaluation postfixée et la pile postfixée de ma cour de pile, si j'ajoute if()
comme une autre fonction avec une pièce vraie et false, une seule if(true, msgbox("ok"), msgbox("not ok"))
montrera les deux messages pendant que je voudrais montrer seulement un. En effet, lorsque j'ai besoin d'évaluer une fonction, tous ses arguments ont déjà été évalués et placés sur la pile.
Pourriez-vous me donner un moyen de mettre en œuvre if()
de manière paresseuse?
Je pense que de traiter ceux-ci comme une sorte de macro, mais au début de l'évaluation de la condition. Peut-être que j'ai besoin d'utiliser un autre type de structure qu'une file d'attente pour garder séparément la condition et les expressions vraies/fausses? Pour l'instant, l'expression est analysée avant l'évaluation, mais je prévois également de stocker la représentation intermédiaire comme une sorte d'expression précompilée pour l'évaluation future.
éditer: Après un certain problème, je pense que je pourrais construire une représentation d'arbres de mon expression (an AST au lieu d'un flux de jeton linéaire), à partir de laquelle je pourrait facilement ignorer une une ou une autre branche de mon if()
.
Il y a deux options ici.
1) Ne pas implémenter if
en fonction de la fonction. Faites-en une fonction de langue avec une sémantique spéciale. Facile à faire, mais moins "pur" si vous voulez que tout soit une fonction.
2) Mettre en œuvre la sémantique "Appel par nom", qui est beaucoup plus compliquée, mais permet à Compiler Magic de prendre soin du problème d'évaluation paresseux tout en conservant if
en fonction d'un élément linguistique. Ça va comme ça:
if
est une fonction qui prend deux paramètres, qui sont toutes deux déclarées comme "par nom". Lorsque le compilateur voit que cela passe quelque chose à un paramètre de nom, il modifie le code à générer. Au lieu d'évaluer l'expression et de transmettre la valeur, il crée une fermeture qui évalue l'expression et passe à la place. Et lorsque vous invoquez un paramètre de noms à l'intérieur de la fonction, le compilateur génère un code pour évaluer la fermeture.
Plutôt que la fonction ayant la signature:
object if(bool, object, object)
Donnez-lui la signature:
object if(bool, object function(), object function())
Ensuite, votre fonction if
appellera la fonction appropriée en fonction de la condition, n'ayant évaluant que l'une d'elles.
C'est assez facile si vous compilez tout ce qui est paresseux. Vous devez avoir un moyen de voir si une valeur est déjà évaluée, ou si elle a besoin de plus d'évacuation.
Ensuite, vous pouvez faire ce qui suit: S'il s'agit d'une variable littérale ou variable (avez-vous ceux-ci ?, I.e. noms des fonctions?), Poussez-la sur la pile. S'il s'agit d'une application d'une fonction, compilez-la séparément et appuyez sur le point d'entrée sur la pile.
L'exécution d'un programme est, puis, simplement en boucle jusqu'à ce que le sommet de la pile soit évalué et non une fonction. S'il n'est pas évalué ou une fonction, appelez le code en haut de la pile.