Question

Quelqu'un pourrait-il s'il vous plaît me donner quelques conseils / idées sur la façon de faire face aux situations où il est nécessaire d'avoir un coup d'œil à d'autres déclarations pour être en mesure de faire des actions sémantiques correctes relatives au moment actuel? Par exemple, il est un phénomène bien connu quand quelqu'un écrit un interprète / compilateur un langage de programmation qui ne supporte pas les « déclarations avant ». Ayons un exemple:

foo(123);//<-- our parser targets here. we estimate we have a function 
         //    invocation, but we have no idea about foo declaration/prototype,
         //     so we can't be sure that "foo" takes one integer argument.   


void foo(int i){
//...
}

Il est assez clair que nous devons avoir au moins deux passes. Tout d'abord, nous analysons toutes les déclarations de fonction et d'obtenir toutes les informations nécessaires telles que: le montant des arguments de la fonction prend, leurs types et alors nous sommes en mesure de traiter les appels de fonction et résoudre les difficultés ci-dessus. Si nous allons cette façon, nous devons faire tous ces laissez-passer en utilisant des AST mécanismes / visiteurs Cheminement. Dans ce cas, nous avons affaire à AST traversantes / application visiteurs et nous devons dire « au revoir » à toute la beauté des constructions de Phoenix intégré directement dans nos parseurs.

Comment réagiriez-vous cela?

Était-ce utile?

La solution

[2 réponse, sur la sémantique] Cet exemple particulier se trouve être simple. Ce que vous pouvez faire est appels de fonction d'enregistrement faites à des fonctions encore non déclarés, et les types d'arguments réels. Lorsque vous rencontrez une déclaration de fonction plus tard, vous vérifier s'il y a des précédents appels de fonction qui sont (mieux) adaptés à cette nouvelle fonction. Vous détecterez évidemment des erreurs seulement à la fin de l'analyse syntaxique, becuase la dernière ligne pourrait introduire une fonction manquante. Mais après cette ligne, tout appel de fonction qui n'a pas été adaptée à tout est une erreur.

Maintenant, le problème est que cela fonctionne pour la sémantique simples. Si vous regardez des langues plus complexes - par exemple avec C ++ - fonction comme templates - il ne devient plus possible de faire ces recherches dans une table simple. Vous auriez besoin tabes spécialisés qui correspondent structurellement vos constructions linguistiques. Un AST est tout simplement pas la meilleure structure pour ceux-ci, et encore moins l'AST partielle lors de l'analyse.

Autres conseils

Si vous voulez faire deux passes, au lieu de vérifier sémantique à la fin de la première passe, vous pouvez avoir des fonctions te appelées par vos actions savoir qui passent ils sont. Donc, si vous aviez des actions

[functionCall(name, args)]
[functionDef(name, args, body)]

Ils seraient définis quelque chose comme ça (pas la syntaxe correcte de l'esprit, mais vous obtenez le point)

functionCall(string name, vector<string> args)
{
  if (!first_pass) {
    // check args for validity
    // whatever else you need to do
  }
} 

functionDef(string name, vector<string> args, ... body)
{
  if (first_pass)
    // Add function decleration to symbol table
  else
    // define function
}

Je pense que vous faites des suppositions sans fondement. Par exemple, « il est assez clair que nous devons avoir au moins deux passes ». Non, ce n'est pas. Si la syntaxe est telle que foo(123) ne peut être analysé comme function-name "(" expression ")", puis une passe suffit.

Par conséquent, je vous conseille de concevoir votre syntaxe pour l'analyse sans ambiguïté. Eviter les constructions qui ne peuvent pas être analysés isolément,, par exemple éviter dependendencies sur les déclarations elesewhere.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top