web-dev-qa-db-fra.com

Comment mettre en œuvre une évaluation paresseuse de si ()

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:

  • l'expression entrée est tokenized pour séparer les booléens littéraux, les entiers, les décimales, les chaînes, les fonctions, les identifiants (variables) (variables)
  • J'ai mis en place l'algorithme de coureurs de courage (légèrement modifié pour gérer les fonctions avec un nombre variable d'arguments) pour vous débarrasser de la parenthèse et commander les opérateurs avec une préséance décente dans un ordre postfixed
  • ma chandelle de shunting produit simplement une file d'attente (simulée) de jetons (au moyen d'une matrice, mon langage Powerbuilder Classic peut définir des objets, mais avoir uniquement des tableaux dynamiques comme stockage natif - pas la liste de la véritable, pas de dictionnaire) que j'évalue séquentiellement avec un Machine de pile simple

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().

10
Seki

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.

9
Mason Wheeler

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.

3
Hand-E-Food

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.

1
Ingo