2012-05-08 14 views
5

Dire che ho definito proc f1 proc f2 e proc f3. Ora voglio creare un interprete TCL, procurarmi il codice di proc f1 proc f2 e proc f3 in quell'interprete e limitare tutti i comandi tranne che f1, f2 e f3 sono all'interno di quell'interprete. Come posso farlo?Creare un interprete TCL che supporti solo i comandi che fornisco

EDIT:

Se un comando diverso che f1, f2 ed f3 sono chiamati entro l'interprete ho creato un messaggio di errore deve essere rilasciato e l'esecuzione del codice di provenienza nell'interprete (si presuppone che questo un altro codice che è reperibile nello stesso interprete, dopo aver acquisito il codice con i proc f1, f2 e f3) deve essere interrotto.

risposta

9

Non è possibile piuttosto farlo, ma è possibile fare qualcosa che è abbastanza simile per la maggior parte degli scopi.

Quello che dovresti fare è creare i comandi f1, f2 e f3 in un interprete normalmente, quindi creare un subinterprete che non ha comandi Tcl e alias i comandi che vuoi mostrare in quel sottotitolo interprete ai comandi nel genitore.

# First define f1-f3 in whatever way you want 

# Now make the context; we'll use a safe interpreter for good measure... 
set slave [interp create -safe] 

# Scrub namespaces, then global vars, then commands 
foreach ns [$slave eval namespace children ::] { 
    $slave eval namespace delete $ns 
} 
foreach v [$slave eval info vars] { 
    $slave eval unset $v 
} 
foreach cmd [$slave eval info commands] { 
    # Note: we're hiding, not completely removing 
    $slave hide $cmd 
} 

# Make the aliases for the things we want 
foreach cmd {f1 f2 f3} { 
    $slave alias $cmd $cmd 
} 

# And evaluate the untrusted script in it 
catch {$slave invokehidden source $theScript} 

# Finally, kill the untrusted interpreter 
interp delete $slave 
+2

Si potrebbe anche voler definire un comando 'sconosciuto' in modo da poter gestire meglio i comandi non definiti, ma questo è facoltativo. –

+0

Grazie mille. Penso che questo sia quello che volevo. – Narek

2

Ecco una soluzione semplice: leggere l'input riga per riga. Se il primo token è f1, f2, o f3, quindi eseguire il comando, colpito controllo + C o digitare exit per uscire dal ciclo:

proc f1 {args} { puts "f1:$args" } 
proc f2 {args} { puts "f2:$args" } 
proc f3 {args} { puts "f3:$args" } 

while 1 { 
    puts -nonewline ">" 
    flush stdout 
    gets stdin line 
    set firstToken [lindex $line 0] 
    if {[lsearch {f1 f2 f3 exit} $firstToken] != -1} { 
     eval $line 
    } 
} 

Ci sono diversi problemi con questa soluzione:

  1. Eval è considerato pericoloso
  2. Non capacità di editing molto, si potrebbe desiderare di ottenere l'immaginazione e utilizzare il pacchetto tclreadline

Nonostante questi inconvenienti, la soluzione è molto semplice da implementare.