8
votes

Mise en œuvre d'un interprète fileté direct dans une langue fonctionnelle comme OCAML

en C / C ++ Vous pouvez implémenter un interprète fileté direct avec une gamme de pointeurs de fonction. Le tableau représente votre programme - une gamme d'opérations. Chacune des fonctions d'opération doit être terminée dans un appel à la fonction suivante de la matrice, quelque chose comme: xxx

le bytecodearray est une gamme de pointeurs de fonction. Si nous avions un tableau de ces opérations OP_PLUS, la longueur de la matrice déterminerait comment nous allions incrémenter le contenu des données. (Bien sûr, vous devriez ajouter une sorte d'opération de terminaison en tant que dernière opération de la matrice).

Comment créerait-il de la mise en œuvre de quelque chose comme celui-ci dans OCAML? J'essaie peut-être de traduire ce code trop littéralement: j'utilisais un tableau OCAML de fonctions comme dans le C ++. Le problème avec c'est que je continue de finir avec quelque chose comme: xxx

où op_array est un tableau défini dans la portée ci-dessus, puis redéfinissez-le plus tard pour être rempli avec un tas OP_PLUS fonctionne ... Toutefois, la fonction op_plus utilise la définition précédente de OP_ARRAY. C'est un problème de poulet et d'œuf.


2 commentaires

Si vous mettez en place un interprète fileté direct de cette manière, vous obtiendrez un débordement de la pile très bientôt :-) Il n'ya aucun moyen de mettre en place un interprète fileté direct dans la norme C, c'est pourquoi GNU a inventé les étiquettes calculées comme étiquettes de compilateur.


@Lothar "Overflow de pile" -> pas dans la version OCAML. L'appel à f dans la question est compilé comme un appel de queue. J'ai presque remarqué dessus et puis j'ai décidé que ce n'était pas le sujet de la question.


3 Réponses :


4
votes

Vous ne devez pas redéfinir op_array code>, vous devez le remplir avec des instructions en la modifiant en place afin que ce soit le même op_array code> que vos fonctions se rapportent déjà. Malheureusement, vous ne pouvez pas modifier la taille d'un tableau de manière dynamique dans OCAML.

Je vois deux solutions: p>

1) Si vous n'avez pas besoin de modifier la séquence des "instructions", de les définir Dans une récursion mutuelle avec le tableau op_array code>. OCAML permet des fonctions et des valeurs mutuellement récursives qui commencent par l'application d'un constructeur à définir. Quelque chose comme: p> xxx pré>

2) ou utilisez une indirection supplémentaire: faire op_array code> une référence à un tableau d'instructions et référez-vous dans les fonctions à ( ! op_array). (PC + 1). Plus tard, après avoir défini toutes les instructions, vous pouvez faire op_array code> point sur un tableau de la bonne taille, rempli des instructions que vous souhaitez. P>

let op_array = ref [| |] ;;
let op_plus pc data = ... ;;
op_array := [| ... |] ;;


1 commentaires

Pour des matrices redimensionnables, on peut utiliser extlib.dynarray ou res << un href = "http://hg.ocaml.info/release/res/raw-file/release-3.2.0/readme.txt" rel = "Nofollow NoreFerrer "> hg.ocaml.info/release/res/raw-file/release-3.2.0/readme.txt >



2
votes

Une option de plus (si la taille est connue à l'avance) - remplissez initialement la matrice avec des instructions de vide: xxx


3 commentaires

L'approche que j'ai fini par prendre depuis la taille de la matrice est le nombre d'instructions du programme et la taille est connue à l'avance. Je peux également remplir de manière programmative la matrice en progression de l'analyse qui constitue un avantage de cette approche.


En fait, bien que cela ait travaillé dans la RÉP, il ne fonctionne pas lorsque j'essaie de compiler avec OCAMLC, j'obtiens: Erreur: Type de cette expression ('_A ->' _B -> '_c), contient des variables de type qui ne peut pas être généralisé à partir de cette ligne: laissez op_array = array.create code_size (amusement _ _ -> affirmer faux) ;;


A dû le changer à: laissez op_array = array.create code_size_size (amusement (x: int) (Y: int) -> printf.printf "fait. \ N") ;; Intéressant que l'autre a fonctionné dans la RÉPEP.



5
votes

Une autre alternative utiliserait des CPS et éviterait complètement la matrice de fonction explicite. L'optimisation des appels quotidiennes s'applique toujours dans ce cas.

Je ne sais pas comment générez-vous le code, mais ne prête pas non plus une hypothèse déraisonnable qu'à un moment donné, vous avez un tableau d'instructions VM que vous souhaitez préparer à l'exécution. Chaque instruction est toujours représentée en fonction, mais au lieu de compteur de programme, il reçoit une fonction de continuation. P>

Voici l'exemple le plus simple: P>

for i = 500_000_000 downto 0 do () done


2 commentaires

Intéressant. Comment cela fonctionnerait-il avec une sorte de saut conditionnel ou «si» opcode?


Voir la mise à jour. La transformation de la CPS et les interprètes basés sur la CPS ont été largement étudiés, vous pouvez trouver de meilleures solutions que mon approche naïve, mais cela fonctionne toujours.