From 79b730dcaa8994cb6b58af1e25a5aa9e06f48471 Mon Sep 17 00:00:00 2001 From: Poor Yorick Date: Sun, 4 Jan 2015 23:00:23 -0700 Subject: add filename: learntcl.tcl --- tcl.html.markdown | 893 +++++++++++++++++++++++++++--------------------------- 1 file changed, 447 insertions(+), 446 deletions(-) diff --git a/tcl.html.markdown b/tcl.html.markdown index 44805b5c..f2d92fcd 100755 --- a/tcl.html.markdown +++ b/tcl.html.markdown @@ -1,446 +1,447 @@ ---- -language: Tcl -contributors: - - ["Poor Yorick", "http://pooryorick.com/"] ---- - -Tcl was created by [John Ousterhout](http://wiki.tcl.tk/John Ousterout) as a -reusable scripting language for chip design tools he was creating. In 1997 he -was awarded the [ACM Software System -Award](http://en.wikipedia.org/wiki/ACM_Software_System_Award) for Tcl. Tcl -can be used both as an embeddable scripting language and as a general -programming language. It can also be used as a portable C library, even in -cases where no scripting capability is needed, as it provides data structures -such as dynamic strings, lists, and hash tables. The C library also provides -portable functionality for loading dynamic libraries, string formatting and -code conversion, filesystem operations, network operations, and more. -Various features of Tcl stand out: - -* Convenient cross-platform networking API - -* Fully virtualized filesystem - -* Stackable I/O channels - -* Asynchronous to the core - -* Full coroutines - -* A threading model recognized as robust and easy to use - - -If Lisp is a list processor, then Tcl is a string processor. All values are -strings. A list is a string format. A procedure definition is a string -format. To achieve performance, Tcl internally caches structured -representations of these values. The list commands, for example, operate on -the internal cached representation, and Tcl takes care of updating the string -representation if it is ever actually needed in the script. The copy-on-write -design of Tcl allows script authors can pass around large data values without -actually incurring additional memory overhead. Procedures are automatically -byte-compiled unless they use the more dynamic commands such as "uplevel", -"upvar", and "trace". - -Tcl is a pleasure to program in. It will appeal to hacker types who find Lisp, -Forth, or Smalltalk interesting, as well as to engineers and scientists who -just want to get down to business with a tool that bends to their will. Its -discipline of exposing all programmatic functionality as commands, including -things like loops and mathematical operations that are usually baked into the -syntax of other languages, allows it to fade into the background of whatever -domain-specific functionality a project needs. It's syntax, which is even -lighter that that of Lisp, just gets out of the way. - - - - - -```tcl -#! /bin/env tclsh - -################################################################################ -## 1. Guidelines -################################################################################ - -# Tcl is not Bash or C! This needs to be said because standard shell quoting -# habits almost work in Tcl and it is common for people to pick up Tcl and try -# to get by with syntax they know from another language. It works at first, -# but soon leads to frustration with more complex scripts. - -# Braces are just a quoting mechanism, not a code block constructor or a list -# constructor. Tcl doesn't have either of those things. Braces are used, -# though, to escape special characters in procedure bodies and in strings that -# are formatted as lists. - - -################################################################################ -## 2. Syntax -################################################################################ - -# 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, 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 -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 - - -# 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] - - -# 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 - - -# A word enclosed in braces is not subject to any special interpretation or -# substitutions, except that a backslash before a brace is not counted when look#ing for the closing brace -set somevar { - This is a literal $ sign, and this \} escaped - 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 -namespace eval people { - namespace eval person1 { - set name Neo - } -} - - -#The full name of a variable includes its enclosing namespace(s), delimited by two colons: -set greeting "Hello $people::person::name" - - - -################################################################################ -## 3. A Few Notes -################################################################################ - -# 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. - - -# 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 - } -} - - -# The full name of a variable can always be used, if desired. -set people::person1::name Neo - - - -################################################################################ -## 4. Commands -################################################################################ - -# Math can be done with the "expr" command. -set a 3 -set b 4 -set c [expr {$a + $b}] - -# Since "expr" performs variable substitution on its own, brace the expression -# to prevent Tcl from performing variable substitution first. See -# "http://wiki.tcl.tk/Brace%20your%20#%20expr-essions" for details. - - -# 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 -# rewritten to not use braces at all: -proc greet greeting\ 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} { - puts {This will also never happen} -} else { - puts {This will always happen} -} - - -# 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}] -} - - -# The first argument of the "while" command is also treated as a mathematical -# expression -set i 0 -while {$i < 10} { - incr i 2 -} - - -# 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. 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 - - {three four} - - five\{six - -} - - -# Since a list is a string, string operations could be performed on it, at the -# 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 - - -# 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" -} - - -# 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 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 \ - to "set" in {set name Archibald Sorbisol} - - -# This mistake can easily occur with the "subst" command. -set replacement {Archibald Sorbisol} -set command {set name $replacement} -set command [subst $command] -eval $command ;# The same error as before: to many arguments to "set" in \ - {set name Archibald Sorbisol} - - -# 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] -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 are -# 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. -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 - -[Official Tcl Documentation](http://www.tcl.tk/man/tcl/) - -[Tcl Wiki](http://wiki.tcl.tk) - -[Tcl Subreddit](http://www.reddit.com/r/Tcl) +--- +language: Tcl +contributors: + - ["Poor Yorick", "http://pooryorick.com/"] +filename: learntcl.tcl +--- + +Tcl was created by [John Ousterhout](http://wiki.tcl.tk/John Ousterout) as a +reusable scripting language for chip design tools he was creating. In 1997 he +was awarded the [ACM Software System +Award](http://en.wikipedia.org/wiki/ACM_Software_System_Award) for Tcl. Tcl +can be used both as an embeddable scripting language and as a general +programming language. It can also be used as a portable C library, even in +cases where no scripting capability is needed, as it provides data structures +such as dynamic strings, lists, and hash tables. The C library also provides +portable functionality for loading dynamic libraries, string formatting and +code conversion, filesystem operations, network operations, and more. +Various features of Tcl stand out: + +* Convenient cross-platform networking API + +* Fully virtualized filesystem + +* Stackable I/O channels + +* Asynchronous to the core + +* Full coroutines + +* A threading model recognized as robust and easy to use + + +If Lisp is a list processor, then Tcl is a string processor. All values are +strings. A list is a string format. A procedure definition is a string +format. To achieve performance, Tcl internally caches structured +representations of these values. The list commands, for example, operate on +the internal cached representation, and Tcl takes care of updating the string +representation if it is ever actually needed in the script. The copy-on-write +design of Tcl allows script authors can pass around large data values without +actually incurring additional memory overhead. Procedures are automatically +byte-compiled unless they use the more dynamic commands such as "uplevel", +"upvar", and "trace". + +Tcl is a pleasure to program in. It will appeal to hacker types who find Lisp, +Forth, or Smalltalk interesting, as well as to engineers and scientists who +just want to get down to business with a tool that bends to their will. Its +discipline of exposing all programmatic functionality as commands, including +things like loops and mathematical operations that are usually baked into the +syntax of other languages, allows it to fade into the background of whatever +domain-specific functionality a project needs. It's syntax, which is even +lighter that that of Lisp, just gets out of the way. + + + + + +```tcl +#! /bin/env tclsh + +################################################################################ +## 1. Guidelines +################################################################################ + +# Tcl is not Bash or C! This needs to be said because standard shell quoting +# habits almost work in Tcl and it is common for people to pick up Tcl and try +# to get by with syntax they know from another language. It works at first, +# but soon leads to frustration with more complex scripts. + +# Braces are just a quoting mechanism, not a code block constructor or a list +# constructor. Tcl doesn't have either of those things. Braces are used, +# though, to escape special characters in procedure bodies and in strings that +# are formatted as lists. + + +################################################################################ +## 2. Syntax +################################################################################ + +# 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, 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 +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 + + +# 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] + + +# 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 + + +# A word enclosed in braces is not subject to any special interpretation or +# substitutions, except that a backslash before a brace is not counted when look#ing for the closing brace +set somevar { + This is a literal $ sign, and this \} escaped + 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 +namespace eval people { + namespace eval person1 { + set name Neo + } +} + + +#The full name of a variable includes its enclosing namespace(s), delimited by two colons: +set greeting "Hello $people::person::name" + + + +################################################################################ +## 3. A Few Notes +################################################################################ + +# 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. + + +# 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 + } +} + + +# The full name of a variable can always be used, if desired. +set people::person1::name Neo + + + +################################################################################ +## 4. Commands +################################################################################ + +# Math can be done with the "expr" command. +set a 3 +set b 4 +set c [expr {$a + $b}] + +# Since "expr" performs variable substitution on its own, brace the expression +# to prevent Tcl from performing variable substitution first. See +# "http://wiki.tcl.tk/Brace%20your%20#%20expr-essions" for details. + + +# 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 +# rewritten to not use braces at all: +proc greet greeting\ 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} { + puts {This will also never happen} +} else { + puts {This will always happen} +} + + +# 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}] +} + + +# The first argument of the "while" command is also treated as a mathematical +# expression +set i 0 +while {$i < 10} { + incr i 2 +} + + +# 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. 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 + + {three four} + + five\{six + +} + + +# Since a list is a string, string operations could be performed on it, at the +# 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 + + +# 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" +} + + +# 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 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 \ + to "set" in {set name Archibald Sorbisol} + + +# This mistake can easily occur with the "subst" command. +set replacement {Archibald Sorbisol} +set command {set name $replacement} +set command [subst $command] +eval $command ;# The same error as before: to many arguments to "set" in \ + {set name Archibald Sorbisol} + + +# 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] +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 are +# 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. +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 + +[Official Tcl Documentation](http://www.tcl.tk/man/tcl/) + +[Tcl Wiki](http://wiki.tcl.tk) + +[Tcl Subreddit](http://www.reddit.com/r/Tcl) -- cgit v1.2.3