From a80663a4ceeadaa813e17918123eff837e91fc51 Mon Sep 17 00:00:00 2001 From: Poor Yorick Date: Fri, 2 Jan 2015 07:56:48 -0700 Subject: better verbiage, add more commands. --- tcl.html.markdown | 159 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 100 insertions(+), 59 deletions(-) (limited to 'tcl.html.markdown') diff --git a/tcl.html.markdown b/tcl.html.markdown index ddf53fe9..5402ce04 100755 --- a/tcl.html.markdown +++ b/tcl.html.markdown @@ -49,8 +49,10 @@ programming in the best way. Even Lisp is more syntactically heavy than Tcl. # Every line is a command. The first word is the name of the command, and # subsequent words are arguments to the command. Words are delimited by -# whitespace. Since every word is a string, no escaping is necessary in the -# simple case. +# whitespace. Since every word is a string, in the simple case no special +# markup such as quotes, braces, or backslash, is necessary. Even when quotes +# are used, they are not a string constructor, but just another escaping +# character. set greeting1 Sal set greeting2 ut @@ -58,27 +60,34 @@ set greeting3 ations #semicolon also delimits commands - set greeting1 Sal; set greeting2 ut; set greeting3 ations # Dollar sign introduces variable substitution +set greeting $greeting1$greeting2$greeting3 -set greeting $greeting1$greeting2 +# Bracket introduces command substitution. The result of the command is +# substituted in place of the bracketed script. When the "set" command is +# given only the name of a variable, it returns the value of that variable. +set greeting $greeting1$greeting2[set greeting3] -# Bracket introduces command substitution -set greeting $greeting[set greeting3] +# Command substitution should really be called script substitution, because an +# entire script, not just a command, can be placed between the brackets. The +# "incr" command increments the value of a variable and returns its value. +set greeting $greeting[ + incr i + incr i + incr i +] # backslash suppresses the special meaning of characters - set amount \$16.42 # backslash adds special meaning to certain characters - puts lots\nof\n\n\n\n\n\nnewlines @@ -89,55 +98,48 @@ set somevar { brace remains uninterpreted } + # In a word enclosed in double quotes, whitespace characters lose their special # meaning - set name Neo set greeting "Hello, $name" #variable names can be any string - set {first name} New # The brace form of variable substitution handles more complex variable names - set greeting "Hello, ${first name}" # The "set" command can always be used instead of variable substitution - set greeting "Hello, [set {first name}]" # To promote the words within a word to individual words of the current # command, use the expansion operator, "{*}". - set {*}{name Neo} # is equivalent to - set name Neo # An array is a special variable that is a container for other variables. - set person(name) Neo set person(gender) male - set greeting "Hello, $person(name)" -# A namespace holds commands and variables +# A namespace holds commands and variables namespace eval people { namespace eval person1 { set name Neo } } -#The full name of a variable includes its enclosing namespace(s), delimited by two colons: +#The full name of a variable includes its enclosing namespace(s), delimited by two colons: set greeting "Hello $people::person::name" @@ -146,20 +148,19 @@ set greeting "Hello $people::person::name" ## 3. A Few Notes ################################################################################ -# From this point on, there is no new syntax. Everything else there is to -# learn about Tcl is about the behaviour of individual commands, and what -# meaning they assign to their arguments. +# All other functionality is implemented via commands. From this point on, +# there is no new syntax. Everything else there is to learn about Tcl is about +# the behaviour of individual commands, and what meaning they assign to their +# arguments. -# All other functionality is implemented via commands. To end up with an -# interpreter that can do nothing, delete the global namespace. It's not very -# useful to do such a thing, but it illustrates the nature of Tcl. - +# To end up with an interpreter that can do nothing, delete the global +# namespace. It's not very useful to do such a thing, but it illustrates the +# nature of Tcl. namespace delete :: # Because of name resolution behaviour, its safer to use the "variable" command to declare or to assign a value to a namespace. - namespace eval people { namespace eval person1 { variable name Neo @@ -168,7 +169,6 @@ namespace eval people { # The full name of a variable can always be used, if desired. - set people::person1::name Neo @@ -178,7 +178,6 @@ set people::person1::name Neo ################################################################################ # Math can be done with the "expr" command. - set a 3 set b 4 set c [expr {$a + $b}] @@ -189,56 +188,52 @@ set c [expr {$a + $b}] # The "expr" command understands variable and command substitution - set c [expr {$a + [set b]}] # The "expr" command provides a set of mathematical functions - set c [expr {pow($a,$b)}] # Mathematical operators are available as commands in the ::tcl::mathop # namespace - ::tcl::mathop::+ 5 3 # Commands can be imported from other namespaces - namespace import ::tcl::mathop::+ set result [+ 5 3] # New commands can be created via the "proc" command. - proc greet name { return "Hello, $name!" } +#multiple parameters can be specified +proc greet {greeting name} { + return "$greeting, $name!" +} + # As noted earlier, braces do not construct a code block. Every value, even # the third argument of the "proc" command, is a string. The previous command -# could be defined without using braces at all: +# rewritten to not use braces at all: +proc greet greeting\ name return\ \"Hello,\ \$name! -proc greet name return\ \"Hello,\ \$name! # When the last parameter is the literal value, "args", it collects all extra # arguments when the command is invoked - proc fold {cmd args} { set res 0 foreach arg $args { set res [cmd $res $arg] } } - fold ::tcl::mathop::* 5 3 3 ;# -> 45 - # Conditional execution is implemented as a command - if {3 > 4} { puts {This will never happen} } elseif {4 > 4} { @@ -250,7 +245,6 @@ if {3 > 4} { # Loops are implemented as commands. The first, second, and third # arguments of the "for" command are treated as mathematical expressions - for {set i 0} {$i < 10} {incr i} { set res [expr {$res + $i}] } @@ -258,7 +252,6 @@ for {set i 0} {$i < 10} {incr i} { # The first argument of the "while" command is also treated as a mathematical # expression - set i 0 while {$i < 10} { incr i 2 @@ -266,14 +259,14 @@ while {$i < 10} { # A list is a specially-formatted string. In the simple case, whitespace is sufficient to delimit values - set amounts 10\ 33\ 18 set amount [lindex $amounts 1] -# Braces and backslash can be used to format more complex values in a list. -# There are three items in the following - +# Braces and backslash can be used to format more complex values in a list. A +# list looks exactly like a script, except that the newline character and the +# semicolon character lose their special meanings. This feature makes Tcl +# homoiconic. There are three items in the following list. set values { one\ two @@ -286,8 +279,7 @@ set values { # Since a list is a string, string operations could be performed on it, at the -# risk of corrupting the list. - +# risk of corrupting the formatting of the list. set values {one two three four} set values [string map {two \{} $values] ;# $values is no-longer a \ properly-formatted listwell-formed list @@ -295,12 +287,10 @@ set values [string map {two \{} $values] ;# $values is no-longer a \ # The sure-fire way to get a properly-formmated list is to use "list" commands set values [list one \{ three four] - lappend values { } ;# add a single space as an item in the list # Use "eval" to evaluate a value as a script - eval { set name Neo set greeting "Hello, $name" @@ -309,20 +299,17 @@ eval { # A list can always be passed to "eval" as a script composed of a single # command. - eval {set name Neo} eval [list set greeting "Hello, $name"] # Therefore, when using "eval", use [list] to build up a desired command - set command {set name} lappend command {Archibald Sorbisol} eval $command -# A common mistake is not to use list functions - +# A common mistake is not to use list functions when building up a command set command {set name} append command { Archibald Sorbisol} eval $command ;# There is an error here, because there are too many arguments \ @@ -330,7 +317,6 @@ eval $command ;# There is an error here, because there are too many arguments \ # This mistake can easily occur with the "subst" command. - set replacement {Archibald Sorbisol} set command {set name $replacement} set command [subst $command] @@ -340,7 +326,6 @@ eval $command ;# The same error as before: to many arguments to "set" in \ # The proper way is to format the substituted value using use the "list" # command. - set replacement [list {Archibald Sorbisol}] set command {set name $replacement} set command [subst $command] @@ -348,24 +333,80 @@ eval $command # It is extremely common to see the "list" command being used to properly -# format values that are substituted into Tcl script templates. There is an -# example of this in the following replacement "while" implementation. +# format values that are substituted into Tcl script templates. There are +# several examples of this, below. -#get rid of the built-in "while" command. +# The "apply" command evaluates a string as a command. +set cmd {{greeting name} { + return "$greeting, $name!" +}} +apply $cmd Whaddup Neo + + +# The "uplevel" command evaluates a script in some enclosing scope. +proc greet {} { + uplevel {puts "$greeting, $name"} +} + +proc set_double {varname value} { + if {[string is double $value]} { + uplevel [list variable $varname $value] + } else { + error [list {not a double} $value] + } +} + +# The "upvar" command links a variable in the current scope to a variable in +# some enclosing scope +proc set_double {varname value} { + if {[string is double $value]} { + upvar 1 $varname var + set var $value + } else { + error [list {not a double} $value] + } +} + + +#get rid of the built-in "while" command. rename ::while {} # Define a new while command with the "proc" command. More sophisticated error # handling is left as an exercise. - proc while {condition script} { if {[uplevel 1 [list expr $condition]]} { uplevel 1 $script tailcall [namespace which while] $condition $script } } + + +# The "coroutine" command creates a separate call stack, along with a command +# to enter that call stack. The "yield" command suspends execution in that +# stack. +proc countdown {} { + #send something back to the initial "coroutine" command + yield + + set count 3 + while {$count > 1} { + yield [incr count -1] + } + return 0 +} +coroutine countdown1 countdown +coroutine countdown2 countdown +puts [countdown 1] ;# -> 2 +puts [countdown 2] ;# -> 2 +puts [countdown 1] ;# -> 1 +puts [countdown 1] ;# -> 0 +puts [coundown 1] ;# -> invalid command name "countdown1" +puts [countdown 2] ;# -> 1 + + ``` ## Reference -- cgit v1.2.3