2015-05-22 5 views

risposta

3

Semplificare il comune Lisp go in altre lingue goto è, beh, troppo semplificazione.

In Common Lisp, go è possibile scaricare lo stack. Per esempio:

(tagbody 
    (mapC#'(lambda (el1 el2) 
       (format t "el1: ~a, el2: ~a~%" el1 el2) 
       (when (or (null el1) (null el2)) 
       (go stop))) 
      list1 
      list2) 
    stop) 

Se stai attuazione Common Lisp in termini di C, quindi un non-svolgimento go può essere un normale goto, ma svolgersi go richiede setjmp/longjmp o equivalente funzionalità, con una corretta pila svolgimento , seguito da un normale goto se necessario, vale a dire nel caso in cui il modulo Lisp con tag non sia l'istruzione o l'espressione C dopo setjmp.

Probabilmente vorrete usare la gestione delle eccezioni del sistema operativo, se potete permettervi di estenderlo. Potrebbe essere più vantaggioso se in un secondo momento si desidera integrare le funzionalità di altri linguaggi, ad esempio le eccezioni C++, e la piattaforma potrebbe già disporre di una serie di gestori, eseguendo automaticamente i moduli di pulizia unwind-protect fino a un determinato stack frame.

Se si desidera mantenere portatile con il minimo sforzo, è possibile gestire uno stack thread-local di setjmp contesti in cui si longjmp alla più recente contesto con informazioni sufficienti per tenere longjmp ing fino al giusto contesto, in esecuzione unwind-protect pulita -up forme in tutto. In questo modo, è possibile continuare a utilizzare le funzionalità di gestione delle eccezioni della piattaforma, ma solo per impostare i telegrammi di srotolamento da/a chiamate esterne.

3

Dal punto di vista dell'attuazione, se siete interpretare un programma Lisp-like, si potrebbe fare qualcosa di un po 'come questo:

  • Entrando un tagbody, iniziano una tabella di destinazioni. (Una mappa di coppie simbolo → indirizzo)
  • Iterate ogni forma ai tagbody
  • if (symbolp this-element), quindi memorizzare l'indirizzo (un puntatore a quella forma) nella tabella
  • altrimenti, (eval this-element) come al solito
  • Incontrando un modulo go, cercare il simbolo di destinazione e (in modo distruttivo) modificare il puntatore "istruzione corrente" del programma su quel valore. Quindi, salta alla tua routine per recuperare l'istruzione successiva.
  • Quando si esce da tagbody, è sufficiente scartare la tabella di destinazione.

Le tabelle di destinazione (in definitiva) devono essere uno stack (indicato nella documentazione Lisp precedente come "elenco push-down" o PDL), poiché si effettuerà una ricerca verso l'alto attraverso l'ambito dinamico per trovare il tag in questione. Tieni presente, in Common Lisp, i tag go sono uno spazio dei nomi separato da variabili, funzioni, classi e così via.

@jlahd è corretto, è effettivamente identico a un (intervallo limitato) goto in C, ma se si sta interpretando il codice, si sovrascriverà effettivamente il puntatore "contatore del programma" con il valore memorizzato.