better verbiage, add more commands.

This commit is contained in:
Poor Yorick 2015-01-02 07:56:48 -07:00
parent 335d618b1a
commit a80663a4ce

View File

@ -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 # 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 # subsequent words are arguments to the command. Words are delimited by
# whitespace. Since every word is a string, no escaping is necessary in the # whitespace. Since every word is a string, in the simple case no special
# simple case. # 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 greeting1 Sal
set greeting2 ut set greeting2 ut
@ -58,27 +60,34 @@ set greeting3 ations
#semicolon also delimits commands #semicolon also delimits commands
set greeting1 Sal; set greeting2 ut; set greeting3 ations set greeting1 Sal; set greeting2 ut; set greeting3 ations
# Dollar sign introduces variable substitution # Dollar sign introduces variable substitution
set greeting $greeting1$greeting2$greeting3
set greeting $greeting1$greeting2
# Bracket introduces command substitution # 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]
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 # backslash suppresses the special meaning of characters
set amount \$16.42 set amount \$16.42
# backslash adds special meaning to certain characters # backslash adds special meaning to certain characters
puts lots\nof\n\n\n\n\n\nnewlines puts lots\nof\n\n\n\n\n\nnewlines
@ -89,55 +98,48 @@ set somevar {
brace remains uninterpreted brace remains uninterpreted
} }
# In a word enclosed in double quotes, whitespace characters lose their special # In a word enclosed in double quotes, whitespace characters lose their special
# meaning # meaning
set name Neo set name Neo
set greeting "Hello, $name" set greeting "Hello, $name"
#variable names can be any string #variable names can be any string
set {first name} New set {first name} New
# The brace form of variable substitution handles more complex variable names # The brace form of variable substitution handles more complex variable names
set greeting "Hello, ${first name}" set greeting "Hello, ${first name}"
# The "set" command can always be used instead of variable substitution # The "set" command can always be used instead of variable substitution
set greeting "Hello, [set {first name}]" set greeting "Hello, [set {first name}]"
# To promote the words within a word to individual words of the current # To promote the words within a word to individual words of the current
# command, use the expansion operator, "{*}". # command, use the expansion operator, "{*}".
set {*}{name Neo} set {*}{name Neo}
# is equivalent to # is equivalent to
set name Neo set name Neo
# An array is a special variable that is a container for other variables. # An array is a special variable that is a container for other variables.
set person(name) Neo set person(name) Neo
set person(gender) male set person(gender) male
set greeting "Hello, $person(name)" set greeting "Hello, $person(name)"
# A namespace holds commands and variables
# A namespace holds commands and variables
namespace eval people { namespace eval people {
namespace eval person1 { namespace eval person1 {
set name Neo 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" set greeting "Hello $people::person::name"
@ -146,20 +148,19 @@ set greeting "Hello $people::person::name"
## 3. A Few Notes ## 3. A Few Notes
################################################################################ ################################################################################
# From this point on, there is no new syntax. Everything else there is to # All other functionality is implemented via commands. From this point on,
# learn about Tcl is about the behaviour of individual commands, and what # there is no new syntax. Everything else there is to learn about Tcl is about
# meaning they assign to their arguments. # 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 # To end up with an interpreter that can do nothing, delete the global
# interpreter that can do nothing, delete the global namespace. It's not very # namespace. It's not very useful to do such a thing, but it illustrates the
# useful to do such a thing, but it illustrates the nature of Tcl. # nature of Tcl.
namespace delete :: namespace delete ::
# Because of name resolution behaviour, its safer to use the "variable" command to declare or to assign a value to a namespace. # 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 people {
namespace eval person1 { namespace eval person1 {
variable name Neo variable name Neo
@ -168,7 +169,6 @@ namespace eval people {
# The full name of a variable can always be used, if desired. # The full name of a variable can always be used, if desired.
set people::person1::name Neo set people::person1::name Neo
@ -178,7 +178,6 @@ set people::person1::name Neo
################################################################################ ################################################################################
# Math can be done with the "expr" command. # Math can be done with the "expr" command.
set a 3 set a 3
set b 4 set b 4
set c [expr {$a + $b}] set c [expr {$a + $b}]
@ -189,56 +188,52 @@ set c [expr {$a + $b}]
# The "expr" command understands variable and command substitution # The "expr" command understands variable and command substitution
set c [expr {$a + [set b]}] set c [expr {$a + [set b]}]
# The "expr" command provides a set of mathematical functions # The "expr" command provides a set of mathematical functions
set c [expr {pow($a,$b)}] set c [expr {pow($a,$b)}]
# Mathematical operators are available as commands in the ::tcl::mathop # Mathematical operators are available as commands in the ::tcl::mathop
# namespace # namespace
::tcl::mathop::+ 5 3 ::tcl::mathop::+ 5 3
# Commands can be imported from other namespaces # Commands can be imported from other namespaces
namespace import ::tcl::mathop::+ namespace import ::tcl::mathop::+
set result [+ 5 3] set result [+ 5 3]
# New commands can be created via the "proc" command. # New commands can be created via the "proc" command.
proc greet name { proc greet name {
return "Hello, $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 # 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 # 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 # When the last parameter is the literal value, "args", it collects all extra
# arguments when the command is invoked # arguments when the command is invoked
proc fold {cmd args} { proc fold {cmd args} {
set res 0 set res 0
foreach arg $args { foreach arg $args {
set res [cmd $res $arg] set res [cmd $res $arg]
} }
} }
fold ::tcl::mathop::* 5 3 3 ;# -> 45 fold ::tcl::mathop::* 5 3 3 ;# -> 45
# Conditional execution is implemented as a command # Conditional execution is implemented as a command
if {3 > 4} { if {3 > 4} {
puts {This will never happen} puts {This will never happen}
} elseif {4 > 4} { } elseif {4 > 4} {
@ -250,7 +245,6 @@ if {3 > 4} {
# Loops are implemented as commands. The first, second, and third # Loops are implemented as commands. The first, second, and third
# arguments of the "for" command are treated as mathematical expressions # arguments of the "for" command are treated as mathematical expressions
for {set i 0} {$i < 10} {incr i} { for {set i 0} {$i < 10} {incr i} {
set res [expr {$res + $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 # The first argument of the "while" command is also treated as a mathematical
# expression # expression
set i 0 set i 0
while {$i < 10} { while {$i < 10} {
incr i 2 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 # A list is a specially-formatted string. In the simple case, whitespace is sufficient to delimit values
set amounts 10\ 33\ 18 set amounts 10\ 33\ 18
set amount [lindex $amounts 1] set amount [lindex $amounts 1]
# Braces and backslash can be used to format more complex values in a list. # Braces and backslash can be used to format more complex values in a list. A
# There are three items in the following # 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 { set values {
one\ two one\ two
@ -286,8 +279,7 @@ set values {
# Since a list is a string, string operations could be performed on it, at the # 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 {one two three four}
set values [string map {two \{} $values] ;# $values is no-longer a \ set values [string map {two \{} $values] ;# $values is no-longer a \
properly-formatted listwell-formed list 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 # The sure-fire way to get a properly-formmated list is to use "list" commands
set values [list one \{ three four] set values [list one \{ three four]
lappend values { } ;# add a single space as an item in the list lappend values { } ;# add a single space as an item in the list
# Use "eval" to evaluate a value as a script # Use "eval" to evaluate a value as a script
eval { eval {
set name Neo set name Neo
set greeting "Hello, $name" set greeting "Hello, $name"
@ -309,20 +299,17 @@ eval {
# A list can always be passed to "eval" as a script composed of a single # A list can always be passed to "eval" as a script composed of a single
# command. # command.
eval {set name Neo} eval {set name Neo}
eval [list set greeting "Hello, $name"] eval [list set greeting "Hello, $name"]
# Therefore, when using "eval", use [list] to build up a desired command # Therefore, when using "eval", use [list] to build up a desired command
set command {set name} set command {set name}
lappend command {Archibald Sorbisol} lappend command {Archibald Sorbisol}
eval $command 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} set command {set name}
append command { Archibald Sorbisol} append command { Archibald Sorbisol}
eval $command ;# There is an error here, because there are too many arguments \ 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. # This mistake can easily occur with the "subst" command.
set replacement {Archibald Sorbisol} set replacement {Archibald Sorbisol}
set command {set name $replacement} set command {set name $replacement}
set command [subst $command] 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" # The proper way is to format the substituted value using use the "list"
# command. # command.
set replacement [list {Archibald Sorbisol}] set replacement [list {Archibald Sorbisol}]
set command {set name $replacement} set command {set name $replacement}
set command [subst $command] set command [subst $command]
@ -348,24 +333,80 @@ eval $command
# It is extremely common to see the "list" command being used to properly # 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 # format values that are substituted into Tcl script templates. There are
# example of this in the following replacement "while" implementation. # several examples of this, below.
# 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. #get rid of the built-in "while" command.
rename ::while {} rename ::while {}
# Define a new while command with the "proc" command. More sophisticated error # Define a new while command with the "proc" command. More sophisticated error
# handling is left as an exercise. # handling is left as an exercise.
proc while {condition script} { proc while {condition script} {
if {[uplevel 1 [list expr $condition]]} { if {[uplevel 1 [list expr $condition]]} {
uplevel 1 $script uplevel 1 $script
tailcall [namespace which while] $condition $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 ## Reference