Tcl_ParseCommand(3)
π Tcl_ParseCommand β the Tcl Library Procedures glow-up π
okay bestie, gather round, because we're about to get intimate with the Tcl parser. this is the Tcl_ParseCommand(3) page, and she is long, so buckle up. part 1 of 2, no skimming allowed. π«Ά
β¨ NAME β¨
Tcl_ParseCommand, Tcl_ParseExpr, Tcl_ParseBraces, Tcl_ParseQuotedString, Tcl_ParseVarName, Tcl_ParseVar, Tcl_FreeParse, Tcl_EvalTokensStandard β parse Tcl scripts and expressions π
πΈ SYNOPSIS πΈ
like, the receipts, exactly as they are:
#include <tcl.h>
int
Tcl_ParseCommand(interp, start, numBytes, nested, parsePtr)
int
Tcl_ParseExpr(interp, start, numBytes, parsePtr)
int
Tcl_ParseBraces(interp, start, numBytes, parsePtr, append, termPtr)
int
Tcl_ParseQuotedString(interp, start, numBytes, parsePtr, append, termPtr)
int
Tcl_ParseVarName(interp, start, numBytes, parsePtr, append)
const char *
Tcl_ParseVar(interp, start, termPtr)
Tcl_FreeParse(usedParsePtr)
int
Tcl_EvalTokensStandard(interp, tokenPtr, numTokens)
π ARGUMENTS π
here's the cast, every single one, no cuts:
Tcl_Interp *interp(out) β for every procedure exceptTcl_FreeParseandTcl_EvalTokensStandard, this is only used for error reporting. if it'sNULL, then no error messages get left behind after errors. but forTcl_EvalTokensStandard, it actually determines the context for evaluating the script and it's used for error reporting too β so it must not beNULL. periodt. πconst char *start(in) β pointer to the first character in the string we're parsing. the main character energy, fr. πTcl_Size numBytes(in) β how many bytes are in the string to parse, not counting any terminating null character. and if it's less than 0, then the script is literally all the characters followingstartup to the first null character. iykyk. β¨int nested(in) β non-zero means the script is part of a command substitution, so an unquoted close bracket should be treated as a command terminator. if it's zero, close brackets have no special meaning whatsoever. just vibes. π¦int append(in) β non-zero means*parsePtralready holds valid tokens and the new tokens should be appended to the ones already there. zero means*parsePtris uninitialized and anything in it gets ignored. this argument is normally0. πΈTcl_Parse *parsePtr(out) β points to the structure we fill in with info about the parsed command, expression, variable name, etc. any previous info in this structure is ignored, unlessappendis non-zero in a call toTcl_ParseBraces,Tcl_ParseQuotedString, orTcl_ParseVarName. π«Άconst char **termPtr(out) β if it's notNULL, this points to a location whereTcl_ParseBraces,Tcl_ParseQuotedString, andTcl_ParseVarwill stash a pointer to the character just after the terminating character (that's the close-brace, the last character of the variable name, or the close-quote respectively) β but only if the parse succeeded. π₯Tcl_Parse *usedParsePtr(in) β points to a structure that was filled in by a previous call toTcl_ParseCommand,Tcl_ParseExpr,Tcl_ParseVarName, etc. recycling, we love to see it. β»οΈ
π DESCRIPTION π
so these procedures parse Tcl commands, or little pieces of Tcl commands like expressions or references to variables. each procedure takes a pointer to a script (or a portion of one) and fills in the structure pointed to by parsePtr with a collection of tokens describing the info that was parsed. normally they return TCL_OK. but if an error happens, they return TCL_ERROR, leave an error message in interp's result (if interp is not NULL), and leave nothing in parsePtr. π
π Tcl_ParseCommand π
Tcl_ParseCommand parses Tcl scripts. give it a pointer to a script and it parses the first command from the script. if the command parsed successfully, Tcl_ParseCommand returns TCL_OK and fills in the structure pointed to by parsePtr with info about the structure of the command (more on that below, keep reading bestie). if an error occurred while parsing the command, then TCL_ERROR is returned, an error message is left in interp's result, and no information is left at *parsePtr. π
π Tcl_ParseExpr π
Tcl_ParseExpr parses Tcl expressions. give it a pointer to a script containing an expression and it parses the expression. if the expression parsed successfully, Tcl_ParseExpr returns TCL_OK and fills in the structure pointed to by parsePtr with info about the structure of the expression (again, below). if an error occurred while parsing the command, then TCL_ERROR is returned, an error message is left in interp's result, and no information is left at *parsePtr. π
π Tcl_ParseBraces π
Tcl_ParseBraces parses a string or command argument enclosed in braces, like {hello} or {string \t with \t tabs}, starting from the beginning of its start argument. the first character of start must be {. if the braced string parsed successfully, Tcl_ParseBraces returns TCL_OK, fills in the structure pointed to by parsePtr with info about the structure of the string (you know the drill), and stores a pointer to the character just after the terminating } in the location given by *termPtr. if an error occurs while parsing the string, then TCL_ERROR is returned, an error message is left in interp's result, and no information is left at *parsePtr or *termPtr. π¦
β¨ Tcl_ParseQuotedString β¨
Tcl_ParseQuotedString parses a double-quoted string like "sum is [expr {$a+$b}]" from the beginning of the start argument. the first character of start must be ". if the double-quoted string parsed successfully, Tcl_ParseQuotedString returns TCL_OK, fills in the structure pointed to by parsePtr with info about the structure of the string (yes, also below), and stores a pointer to the character just after the terminating " in the location given by *termPtr. if an error occurs while parsing the string, then TCL_ERROR is returned, an error message is left in interp's result, and no information is left at *parsePtr or *termPtr. π€
πΈ Tcl_ParseVarName πΈ
Tcl_ParseVarName parses a Tcl variable reference like $abc or $x([expr {$index + 1}]) from the beginning of its start argument. the first character of start must be $. if a variable name parsed successfully, Tcl_ParseVarName returns TCL_OK and fills in the structure pointed to by parsePtr with info about the structure of the variable name (yes bestie, below). if an error occurs while parsing the command, then TCL_ERROR is returned, an error message is left in interp's result (if interp is not NULL), and no information is left at *parsePtr. π«
π Tcl_ParseVar π
Tcl_ParseVar parses a Tcl variable reference like $abc or $x([expr {$index + 1}]) from the beginning of its start argument. the first character of start must be $. if the variable name parsed successfully, Tcl_ParseVar returns a pointer to the string value of the variable. if an error occurs while parsing, then NULL is returned and an error message is left in interp's result. π«Ά
π§ memory management moment π§
the info left at *parsePtr by Tcl_ParseCommand, Tcl_ParseExpr, Tcl_ParseBraces, Tcl_ParseQuotedString, and Tcl_ParseVarName may include dynamically allocated memory. if these five parsing procedures return TCL_OK, then the caller must invoke Tcl_FreeParse to release the storage at *parsePtr. these procedures ignore any existing information in *parsePtr (unless append is non-zero), so if you're making repeated calls to any of them, then Tcl_FreeParse must be invoked once after each call. like, don't leak, bestie, it's not cute. π¨
π₯ Tcl_EvalTokensStandard π₯
Tcl_EvalTokensStandard evaluates a sequence of parse tokens from a Tcl_Parse structure. the tokens typically consist of all the tokens in a word, or all the tokens that make up the index for a reference to an array variable. Tcl_EvalTokensStandard performs the substitutions requested by the tokens and concatenates the resulting values. the return value from Tcl_EvalTokensStandard is a Tcl completion code with one of the values TCL_OK, TCL_ERROR, TCL_RETURN, TCL_BREAK, or TCL_CONTINUE, or possibly some other integer value originating in an extension. on top of that, a result value or error message is left in interp's result; it can be retrieved using Tcl_GetObjResult. slay. π
π TCL_PARSE STRUCTURE π
okay so Tcl_ParseCommand, Tcl_ParseExpr, Tcl_ParseBraces, Tcl_ParseQuotedString, and Tcl_ParseVarName return parse information in two data structures: Tcl_Parse and Tcl_Token. the duo. the iconic pair. π
typedef struct {
const char *commentStart;
Tcl_Size commentSize;
const char *commandStart;
Tcl_Size commandSize;
Tcl_Size numWords;
Tcl_Token *tokenPtr;
Tcl_Size numTokens;
...
} Tcl_Parse;
typedef struct {
int type;
const char *start;
Tcl_Size size;
Tcl_Size numComponents;
} Tcl_Token;
the first five fields of a Tcl_Parse structure are filled in only by Tcl_ParseCommand. these fields are not used by the other parsing procedures. so like, don't come for them, they're spoken for. π
okay pausing here because this page is genuinely a two-parter and part 2 is where the rest of theTcl_Parse/Tcl_Tokendeets live π
...and your type field is gonna be exactly one of these, bestie. Each one has its own whole personality, so let's get into it β¨
TCL_TOKEN_WORDβ the main character π Usually this bad boy describes one single word of a command, but plot twist: it can also describe a quoted or braced string sitting inside an expression. What it's really describing is a component of the script that exists because you concatenated a whole sequence of subcomponents together β and every one of those subcomponents gets its own subtoken. The token kicks off at the first non-blank character of the component (so yeah, that could be a double-quote or an open brace π) and it swallows every character in the component right up to β but not including β the space, semicolon, close bracket, close quote, or close brace that terminates the component. AndnumComponents? That's counting the total number of sub-tokens making up the word, and yes that includes the sub-tokens ofTCL_TOKEN_VARIABLEandTCL_TOKEN_BStokens too. no skipping π«ΆTCL_TOKEN_SIMPLE_WORDβ literally the same meaning asTCL_TOKEN_WORD, except the word is guaranteed to consist of a singleTCL_TOKEN_TEXTsub-token. SonumComponentsis always1. always. iconic consistency β¨TCL_TOKEN_EXPAND_WORDβ again, same meaning asTCL_TOKEN_WORD, except the command parser clocked that this word began with the expansion prefix{*}, which means that after substitution, the list value of this word should be expanded to form multiple arguments in command evaluation. and ngl, this token type can only be created byTcl_ParseCommand. it's exclusive, it's rare, it's her πTCL_TOKEN_TEXTβ describes a range of literal text that's part of a word.numComponentsis always0. simple, clean, no drama πΈTCL_TOKEN_BSβ describes a backslash sequence, like\nor\0xA3.numComponentsis always0. πTCL_TOKEN_COMMANDβ describes a command whose result has to get substituted into the word. The token includes the square brackets that surround the command.numComponentsis always0β and hear me out, the nested command is not parsed, okay? if you want to see its tokens you have to callTcl_ParseCommandrecursively yourself. do the work bestie πTCL_TOKEN_VARIABLEβ describes a variable substitution, and that means the$, the variable name, and the array index (if there is one) all the way up through the close parenthesis that terminates the index. This token is followed by one or more additional tokens describing the variable name and array index. So: ifnumComponentsis1, the variable is a scalar, and the next token is aTCL_TOKEN_TEXTtoken giving the variable name. IfnumComponentsis greater than1, it's an array β the first sub-token is aTCL_TOKEN_TEXTtoken giving the array name, and the remaining sub-tokens areTCL_TOKEN_TEXT,TCL_TOKEN_BS,TCL_TOKEN_COMMAND, andTCL_TOKEN_VARIABLEtokens that must be concatenated to produce the array index. AndnumComponentsincludes nested sub-tokens that are part ofTCL_TOKEN_VARIABLEtokens in the array index. yeah. it nests. it's giving inception πTCL_TOKEN_SUB_EXPRβ describes one subexpression of an expression (or, if you're feeling fancy, an entire expression). A subexpression may consist of a value β like an integer literal, a variable substitution, or a parenthesized subexpression β and it may also consist of an operator plus its operands. The token starts with the first non-blank character of the subexpression, up to but not including the space, brace, close-paren, or bracket that terminates the subexpression. This token is followed by one or more additional tokens describing the subexpression. Here's the tea: if the first sub-token after theTCL_TOKEN_SUB_EXPRtoken is aTCL_TOKEN_OPERATORtoken, then the subexpression is an operator and its token operands β and if that operator has no operands, the subexpression consists of just theTCL_TOKEN_OPERATORtoken, periodt. Each operand is described by aTCL_TOKEN_SUB_EXPRtoken. Otherwise, the subexpression is a value described by one ofTCL_TOKEN_WORD,TCL_TOKEN_TEXT,TCL_TOKEN_BS,TCL_TOKEN_COMMAND,TCL_TOKEN_VARIABLE, andTCL_TOKEN_SUB_EXPR.numComponentscounts the total number of sub-tokens that make up the subexpression, and yes, that includes the sub-tokens for any nestedTCL_TOKEN_SUB_EXPRtokens π₯TCL_TOKEN_OPERATORβ describes one operator of an expression, like&&orhypot. ATCL_TOKEN_OPERATORtoken is always preceded by aTCL_TOKEN_SUB_EXPRtoken that describes the operator and its operands, and you can use thatTCL_TOKEN_SUB_EXPRtoken'snumComponentsfield to figure out how many operands there are. A binary operator like*is followed by twoTCL_TOKEN_SUB_EXPRtokens describing its operands. A unary operator like-is followed by a singleTCL_TOKEN_SUB_EXPRtoken for its operand. If the operator is a math function likelog10, theTCL_TOKEN_OPERATORtoken gives its name and the followingTCL_TOKEN_SUB_EXPRtokens describe its operands β and if there are no operands (as withrand), noTCL_TOKEN_SUB_EXPRtokens follow at all. And there's exactly one trinary operator,?, which shows up in if-then-else subexpressions likex?y:zβ in that case the?TCL_TOKEN_OPERATORtoken is followed by threeTCL_TOKEN_SUB_EXPRtokens for the operandsx,y, andz. ThenumComponentsfield for aTCL_TOKEN_OPERATORtoken is always0β
okay now the "after it returns" section, this is where it all comes together besties π
After Tcl_ParseCommand returns, the very first token pointed to by the tokenPtr field of the Tcl_Parse structure always has type TCL_TOKEN_WORD or TCL_TOKEN_SIMPLE_WORD or TCL_TOKEN_EXPAND_WORD. It's followed by the sub-tokens that must be concatenated to produce the value of that word. Then the next token is the TCL_TOKEN_WORD or TCL_TOKEN_SIMPLE_WORD of TCL_TOKEN_EXPAND_WORD token for the second word, followed by sub-tokens for that word, and so on and so on until all numWords have been accounted for. every single one. no stragglers π
After Tcl_ParseExpr returns, the first token pointed to by the tokenPtr field of the Tcl_Parse structure always has type TCL_TOKEN_SUB_EXPR. It's followed by the sub-tokens that must be evaluated to produce the value of the expression. And heads up: only the token information in the Tcl_Parse structure gets modified here β the commentStart, commentSize, commandStart, and commandSize fields are not modified by Tcl_ParseExpr. hands off π«Ά
After Tcl_ParseBraces returns, the array of tokens pointed to by the tokenPtr field of the Tcl_Parse structure will contain a single TCL_TOKEN_TEXT token if the braced string does not contain any backslash-newlines. If the string does contain backslash-newlines, the array of tokens will contain one or more TCL_TOKEN_TEXT or TCL_TOKEN_BS sub-tokens that must be concatenated to produce the value of the string. And if the braced string was just {} (that is, the string was empty), the single TCL_TOKEN_TEXT token will have a size field containing zero β which is lowkey a serve, because it ensures that at least one token appears to describe the braced string. Again: only the token information in the Tcl_Parse structure is modified; the commentStart, commentSize, commandStart, and commandSize fields are not modified by Tcl_ParseBraces π
After Tcl_ParseQuotedString returns, the array of tokens pointed to by the tokenPtr field of the Tcl_Parse structure depends on the contents of the quoted string. It'll consist of one or more TCL_TOKEN_TEXT, TCL_TOKEN_BS, TCL_TOKEN_COMMAND, and TCL_TOKEN_VARIABLE sub-tokens. The array always contains at least one token β for example, if the argument start is empty, the array returned consists of a single TCL_TOKEN_TEXT token with a zero size field. And yes, same deal: only the token information in the Tcl_Parse structure is modified, and the commentStart, commentSize, commandStart, and commandSize fields are not modified πΈ
After Tcl_ParseVarName returns, the first token pointed to by the tokenPtr field of the Tcl_Parse structure always has type TCL_TOKEN_VARIABLE. It's followed by the sub-tokens that make up the variable name as described above. The total length of the variable name is contained in the size field of the first token. And as in Tcl_ParseExpr, only the token information in the Tcl_Parse structure is modified by Tcl_ParseVarName β the commentStart, commentSize, commandStart, and commandSize fields are not modified π
All of the character pointers in the Tcl_Parse and Tcl_Token structures refer to characters in the start argument passed to Tcl_ParseCommand, Tcl_ParseExpr, Tcl_ParseBraces, Tcl_ParseQuotedString, and Tcl_ParseVarName. one source of truth, we love to see it β
okay real talk, important one: there are additional fields in theTcl_Parsestructure after thenumTokensfield, but those are for the private use ofTcl_ParseCommand,Tcl_ParseExpr,Tcl_ParseBraces,Tcl_ParseQuotedString, andTcl_ParseVarName. They should not be referenced by code outside of these procedures. like. do not touch. it's not yours bestie π
π KEYWORDS π
- backslash substitution
- braces
- command
- expression
- parse
- token
- variable substitution
and that's the whole page babes, you ate it π
β¨ this one's from the Tcl 8.3 era, filed under Tcl_ParseCommand(3) β go forth and parse responsibly, mwah π«Άππ¦
π¦ where this page comes from
- alpine 3.23: tcl9-doc 9.0.3-r0 Β· TCL
- alpine 3.24: tcl9-doc 9.0.3-r2 Β· TCL
- fedora 43: tcl-doc 1:9.0.2-1.fc43 Β· TCL AND GPL-3.0-or-later WITH Bison-exception-2.2 AND BSD-3-Clause
- fedora 44: tcl-doc 1:9.0.2-1.fc44 Β· TCL AND GPL-3.0-or-later WITH Bison-exception-2.2 AND BSD-3-Clause
- nixos 26.05: tcl 9.0.3
- nixpkgs unstable: tcl 9.1.0
- Copyright (c) 1997 Sun Microsystems, Inc
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms