11
votes

Mise en œuvre des boucles d'hélice dans un interprète

Je veux construire une interprète d'un esprit d'hérité (putain de nom) dans mon langage de programmation fraîchement créé pour prouver qu'elle est complétude-complétude.

Maintenant, tout est clair jusqu'à présent ( <> + - ,. ) - sauf une chose: les boucles ( [] ). Je suppose que vous connaissez la syntaxe BF (extrêmement dure) d'ici:

  • Comment puis-je implémenter les boucles BF dans mon interprète?

    Comment le pseudocode pourrait-il ressembler? Que dois-je faire lorsque l'interprète atteint une boucle de départ ( [) ou une extrémité de boucle (] )?

    Vérification si la boucle devrait continuer ou arrêter n'est pas le problème ( Cellule actuelle == 0 ), mais:

    • Quand et où dois-je vérifier?
    • Comment savoir où se trouve la boucle?
    • Comment gérer les boucles imbriquées?

      Alors que les boucles peuvent être nichées, je suppose que je ne peux pas utiliser une variable contenant la position de départ de la boucle actuelle.

      J'ai vu de très petits interprètes BF mis en œuvre dans diverses langues, je me demande comment ils ont réussi à faire fonctionner les boucles mais ne peut pas le comprendre.


1 commentaires

Dupliquer: Stackoverflow.com/questions/1055758/...


5 Réponses :


9
votes

Lorsque vous atteignez [, vous testez le pointeur de données.

Si c'est faux, vous pouvez numériser pour le prochain correspondre ] , comptant le nombre [ que vous voyez et en vous assurant de marquer les éteints comme vous voyez chaque ] .

Si c'est vrai, vous devez suivre sa position afin que vous puissiez revenir dessus plus tard. Je suggère d'utiliser une pile. Appuyez sur la position actuelle du programme sur la pile, puis lorsque vous atteignez ] , testez le pointeur de données. Si c'est vrai, allez à la position du programme le plus haut sur la pile. Si c'est faux, évitez la position de la pile et continuez.

Lorsque vous nidez dans les boucles intérieures, la pile enregistrera bien le contexte de chaque boucle.

voir pile (wikipedia) . Ceci est analogue à la manière dont les programmes d'assemblage traitent des appels de fonction.


1 commentaires

J'avais déjà construit dans une pile dans ma langue de programmation, donc c'est génial: d merci pour la réponse



2
votes

Comment puis-je implémenter les boucles BF dans mon interprète?

C'est le point - cela dépend entièrement de votre langue. Pour le cas d'un langage de programmation basé sur une pile (ou d'une langue pouvant utiliser une pile), @RJH a donné une bonne solution. D'autres langues utiliseraient différentes solutions, telles que la récursivité (c'est-à-dire une utilisation implicite d'une pile).


0 commentaires

1
votes

Du sommet de ma tête, cela pourrait être des erreurs dedans, mais quelque chose comme ça devrait fonctionner: xxx

appeler interpréter avec le code source cerfique * CK. Le pointeur P est à la position de la mémoire actuelle. Faire un appel récursif lorsque vous remarquez A [. Retour de cet appel récursif lorsque vous rencontrez un].


1 commentaires

Hm .. Seulement s'il ne rencontre jamais de "]", car si c'est le cas, il retournera l'emplacement de ce caractère. Mais obtenir un segfault du tout, même si cela est dû à une entrée non valide, n'est pas très agréable, non :) Encore une fois, illus d'une illustration approximative d'une solution, pas parfaitement sans faille.



0
votes

Je préfère utiliser une table de saut (ainsi que la conversion de BF brut en «bytecode»). Optimiser les interprètes BF sont clairement la voie à suivre!


0 commentaires

6
votes

Voici mon "optimisation" de la version d'interprète, qui compilait les sauts de boucle.

def interpret2(code):
    data = [0] * 5000   # data memory
    cp = 0              # code pointer
    dp = 0              # data pointer
    # pre-compile a jump table
    stack = []
    jump = [None] * len(code)
    for i,o in enumerate(code):
        if o=='[':
            stack.append(i)
        elif o==']':
            jump[i] = stack.pop()
            jump[jump[i]] = i
    # execute
    while cp < len(code):
        cmd = code[cp]
        if   cmd == '>': dp += 1
        elif cmd == '<': dp -= 1
        elif cmd == '+': data[dp] += 1 
        elif cmd == '-': data[dp] -= 1 
        elif cmd == '.': stdout.write(chr(data[dp]))
        elif cmd == ',': data[dp] = ord(stdin.read(1))
        elif cmd == '[' and not data[dp]: # skip loop if ==0
            cp = jump[cp]
        elif cmd == ']' and data[dp]:     # loop back if !=0
            cp = jump[cp]
        cp += 1


0 commentaires