Read Record Files with TLC
Tutorial Overview
Objective: Understand the structure of record files and learn how to parse them with TLC directives.
Open the Example:
openExample('simulinkcoder/AdviceAboutTLCTutorialsExample') cd('tlctutorial/guide')
In this tutorial you interpret a simple file of structured records with a series of TLC
scripts. You will learn how records are structured, and how TLC %assign
and %<>
token expansion directives are used to process them. In addition, the
tutorial illustrates loops using %foreach
, and scoping using
%with
.
The tutorial includes these steps, which you should follow sequentially:
Structure of Record Files — Some background and a simple example
Interpret Records — Presenting contents of the record file
Anatomy of a TLC Script — Deconstructing the presentation
Modify
read-guide.tlc
— Experiment with TLCPass and Use a Parameter— Pass parameters from the command line to TLC files
Review
Structure of Record Files
The code generator compiles models into a structured form called a record file, referred
to as
. Such compiled model files are
similar in syntax and organization to source model files, in that they contain a series of
hierarchically nested records of the formmodel
.rtw
recordName {itemName itemValue}
Item names are alphabetic. Item values can be strings or numbers. Numeric values can be scalars, vectors, or matrices. Curly braces set off the contents of each record, which may contain one or more items, delimited by space, tab, or return characters.
In a
file, the top-level (first)
record’s name is model
.rtwCompiledModel
. Each block is represented by a subrecord
within it, identified by the block’s name. TLC can parse well-formed record files, as this
exercise illustrates.
The following listing is a valid record file that TLC can parse, although not one for which it can generate code. Comments are indicated by a pound sign (#):
# # File: guide.rtw Illustrative record file, which can't be used by Simulink # Note: string values MUST be in quotes Top { # Outermost Record, called Top Date "21-Aug-2008" # Name/Value pair named Top.Date Employee { # Nested record within the Top record FirstName "Arthur" # Alpha field Top.Employee.FirstName LastName "Dent" # Alpha field Top.Employee.LastName Overhead 1.78 # Numeric field Top.Employee.Overhead PayRate 11.50 # Numeric field Top.Employee.PayRate GrossRate 0.0 # Numeric Field Top.Employee.GrossRate } # End of Employee record NumProject 3 # Indicates length of following list Project { # First list item, called Top.Project[0] Name "Tea" # Alpha field Name, Top.Project[0].Name Difficulty 3 # Numeric field Top.Project[0].Difficulty } # End of first list item Project { # Second list item, called Top.Project[1] Name "Gillian" # Alpha field Name, Top.Project[1].Name Difficulty 8 # Numeric field Top.Project[1].Difficulty } # End of second list item Project { # Third list item, called Top.Project[2] Name "Zaphod" # Alpha field Name, Top.Project[2].Name Difficulty 10 # Numeric field Top.Project[2].Difficulty } # End of third list item } # End of Top record and of file
As long as programmers know the names of records and fields, and their expected contents, they can compose TLC statements to read, parse, and manipulate record file data.
Interpret Records
Here is the output from a TLC program script that reads guide.rtw
,
interprets its records, manipulates field data, and formats descriptions, which are directed
to the MATLAB® Command Window:
Using TLC you can: * Directly access a field's value, e.g. %<Top.Date> -- evaluates to: "21-Aug-2008" * Assign contents of a field to a variable, e.g. "%assign worker = Top.Employee.FirstName" worker expands to Top.Employee.FirstName = "Arthur" * Concatenate string values, e.g. "%assign worker = worker + " " + Top.Employee.LastName" worker expands to worker + " " + Top.Employee.LastName = "Arthur Dent" * Perform arithmetic operations, e.g. "%assign wageCost = Top.Employee.PayRate * Top.Employee.Overhead" wageCost expands to Top.Employee.PayRate * Top.Employee.Overhead <- 11.5 * 1.78 = 20.47 * Put variables into a field, e.g. Top.Employee.GrossRate starts at 0.0 "%assign Top.Employee.GrossRate = wageCost" Top.Employee.GrossRate expands to wageCost = 20.47 * Index lists of values, e.g. "%assign projects = Top.Project[0].Name + ", " + Top.Project[1].Name..." "+ ", " + Top.Project[2].Name" projects expands to Top.Project[0].Name + ", " + Top.Project[1].Name + ", " + Top.Project[2].Name = Tea, Gillian, Zaphod * Traverse and manipulate list data via loops, e.g. - At top of Loop, Project = Tea; Difficulty = 3 - Bottom of Loop, i = 0; diffSum = 3.0 - At top of Loop, Project = Gillian; Difficulty = 8 - Bottom of Loop, i = 1; diffSum = 11.0 - At top of Loop, Project = Zaphod; Difficulty = 10 - Bottom of Loop, i = 2; diffSum = 21.0 Average Project Difficulty expands to diffSum / Top.NumProject = 21.0 / 3 = 7.0
This output from guide.rtw
was produced by invoking TLC from the
MATLAB Command Window, executing a script called read-guide.tlc
.
Do this yourself now, by following these steps:
In MATLAB, change folder (
cd
) to your copy oftlctutorial/guide
within your working folder.To produce the output just listed, process
guide.rtw
with the TLC scriptread-guide.tlc
by typing the following command:tlc -v -r guide.rtw read-guide.tlc
Note command usage:
The
-r
switch (for read) identifies the input data file, in this caseguide.rtw
.The TLC script handling the data file is specified by the last token typed.
The
-v
switch (for verbose) directs output to the command window, unless the TLC file handles this itself.
Anatomy of a TLC Script
You now dissect the script you just ran. Each “paragraph” of output from
guide.tlc
is discussed in sequence in the following brief
sections:
Coding Conventions — Before you begin
File Header — Header info and a formatting directive
Token Expansion— Evaluating field and variable identifiers
General Assignment — Using the
%assign
directiveString Processing Plus — Methods of assembling strings
Arithmetic Operations — Computations on fields and variables
Modify Records — Changing, copying, appending to records
Index Lists — Referencing list elements with subscripts
Loop Over Lists — Details on loop construction and behavior
Coding Conventions
These are some basic TLC syntax and coding conventions:
%% Comment
| TLC comment, which is not output |
/* comment */
| Comment, to be output |
%keyword
| TLC directive (keyword), start with
“% ” |
%<expr> | TLC token operator |
. (period) | Scoping operator, for example, Top.Lev2.Lev3 |
... (at end-of-line) | Statement continuation (line break is not output) |
\ (at end-of-line) | Statement continuation (line break is output) |
localvarIdentifier
| Local variables start in lowercase |
GlobalvarIdentifier
| Global variables start in uppercase |
RecordIdentifier
| Record identifiers start in uppercase |
EXISTS()
| TLC built-in functions are named in uppercase Note: TLC identifiers are case-sensitive. |
For further information, see TLC Coding Conventions.
File Header
The file read-guide.tlc
begins with:
%% File: read-guide.tlc (This line is a TLC Comment, and will not print) %% %% To execute this file, type: tlc -v -r guide.rtw read-guide.tlc %% Set format for displaying real values (default is "EXPONENTIAL") %realformat "CONCISE"
Lines 1 through 4 — Text on a line following the characters
%%
is treated as a comment (ignored, not interpreted or output).Line 5 — As explained in the text of the fourth line, is the TLC directive (keyword)
%realformat
, which controls how subsequent floating-point numbers are formatted when displayed in output. Here we want to minimize the digits displayed.
Token Expansion
The first section of output is produced by the script lines:
Using TLC you can: * Directly access a field's value, e.g. %assign td = "%" + "<Top.Date>" %<td> -- evaluates to: "%<Top.Date>"
Lines 1 and 2 — (and lines that contain no TLC directives or tokens) are simply echoed to the output stream, including leading and trailing spaces.
Line 3 — Creates a variable named
td
and assigns the string value%<Top.Date>
to it. The%assign
directive creates new and modifies existing variables. Its general syntax is:The optional double colon prefix specifies that the variable being assigned to is a global variable. In its absence, TLC creates or modifies a local variable in the current scope.%assign ::variable = expression
Line 4 — Displays
The preceding line enables TLC to print%<Top.Date> -- evaluates to:
%<Top.Date>
without expanding it. It constructs the string by pasting together two literals.As discussed in String Processing Plus, the plus operator concatenates strings as and adds numbers, vectors, matrices, and records.%assign td = "%" + "<Top.Date>"
Line 5 — Evaluates (expands) the record
Top.Date
. More precisely, it evaluates the fieldDate
which exists in scopeTop
. The syntax%<expr>
causes expressionexpr
(which can be a record, a variable, or a function) to be evaluated. This operation is sometimes referred to as an eval.
Note
You cannot nest the %<expr>
operator (that is,
%<foo%<bar>>
is not allowed).
Note
When you use the %<expr>
operator within quotation marks,
for example, "%<Top.Date>"
, TLC expands the expression and then
encloses the result in quotation marks. However, placing %assign
within quotation marks, for example, "%assign foo = 3"
, simply echoes
the statement enclosed in quotation marks to the output stream.
No assignment results (the value of foo
remains unchanged or undefined).
General Assignment
The second section of output is produced by the script lines:
* Assign contents of a field to a variable, e.g. %assign worker = Top.Employee.FirstName "%assign worker = Top.Employee.FirstName" worker expands to Top.Employee.FirstName = %<worker>
Line 1 — Echoed to output.
Line 2 — An assignment of field
FirstName
in theTop.Employee
record scope to a new local variable calledworker
.Line 3 — Repeats the previous statement, producing output by enclosing it in quotation marks.
Line 4 — Explains the following assignment and illustrates the token expansion. The token
%<worker>
expands toArthur
.
String Processing Plus
The next section of the script illustrates string concatenation, one of the uses of
the “+
” operator:
* Concatenate string values, e.g. %assign worker = worker + " " + Top.Employee.LastName "%assign worker = worker + " " + Top.Employee.LastName" worker expands to worker + " " + Top.Employee.LastName = "%<worker>"
Line 1 — Echoed to output.
Line 2 — Performs the concatenation.
Line 3 — Echoes line 2 to the output.
Line 4 — Describes the operation, in which a variable is concatenated to a field separated by a space character. An alternative way to do this, without using the
+
operator, isThe alternative method uses evals of fields and is equally efficient.%assign worker = "%<Top.Employee.FirstName> %<Top.Employee.LastName>"
The +
operator, which is associative, also works for numeric types,
vectors, matrices, and records:
Numeric Types — Add two expressions together; both operands must be numeric. For example:
Output:* Numeric Type example, e.g. Top.Employee.PayRate = %<Top.Employee.PayRate> Top.Employee.Overhead = %<Top.Employee.Overhead> %assign td = Top.Employee.PayRate + Top.Employee.GrossRate td = Top.Employee.PayRate + Top.Employee.Overhead td evaluates to %<td>
* Numeric Type example, e.g. Top.Employee.PayRate = 11.5 Top.Employee.Overhead = 1.78 td = Top.Employee.PayRate + Top.Employee.Overhead td evaluates to 13.28
Vectors — If the first argument is a vector and the second is a scalar value, TLC appends the scalar value to the vector. For example:
Output:* Vector example, e.g. %assign v1 = [0, 1, 2, 3] v1 is %<v1> %assign tp1d = Top.Project[1].Difficulty Top.Project[1].Difficulty is %<tp1d> %assign v2 = v1 + tp1d v2 = v1 + Top.Project[1].Difficulty v2 evaluates to: %<v2>
* Vector example, e.g. v1 is [0, 1, 2, 3] Top.Project[1].Difficulty is 8 v2 = v1 + Top.Project[1].Difficulty v2 evaluates to: [0, 1, 2, 3, 8]
Matrices — If the first argument is a matrix and the second is a vector of the same column-width as the matrix, TLC appends the vector as another row to the matrix. For example:
Output:* Matrices example, e.g. %assign mx1 = [[4, 5, 6, 7]; [8, 9, 10, 11]] mx1 is %<mx1> v1 is %<v1> %assign mx = mx1 + v1 mx = mx1 + v1 mx evaluates to %<mx>
* Matrices example, e.g. mx1 is [ [4, 5, 6, 7]; [8, 9, 10, 11] ] v1 is [0, 1, 2, 3] mx = mx1 + v1 mx evaluates to [ [4, 5, 6, 7]; [8, 9, 10, 11]; [0, 1, 2, 3] ]
Records — If the first argument is a record, TLC adds the second argument as a parameter identifier (with its current value). For example:
Output:* Record example, e.g. %assign StartDate = "August 28, 2008" StartDate is %<StartDate> %assign tsd = Top + StartDate Top + StartDate Top.StartDate evaluates to %<Top.StartDate>
* Record example, e.g. StartDate is August 28, 2008 Top + StartDate Top.StartDate evaluates to August 28, 2008
Arithmetic Operations
TLC provides a full complement of arithmetic operators for numeric data. In the next portion of our TLC script, two numeric fields are multiplied:
* Perform arithmetic operations, e.g. %assign wageCost = Top.Employee.PayRate * Top.Employee.Overhead "%assign wageCost = Top.Employee.PayRate * Top.Employee.Overhead" wageCost expands to Top.Employee.PayRate * Top.Employee.Overhead ... <- %<Top.Employee.PayRate> * %<Top.Employee.Overhead> = %<wageCost>
Line 1 — Echoed to output.
Line 2 —
%assign
statement that computes the value, which TLC stores in local variablewageCost
.Line 3 — Echoes the operation in line 2.
Lines 4 and 5 — Compose a single statement. The ellipsis (typed as three consecutive periods, for example,
...
) signals that a statement is continued on the following line, but if the statement has output, TLC does not insert a line break. To continue a statement and insert a line break, replace the ellipsis with a backslash (\
).
Modify Records
Once read into memory, you can modify and manipulate records just like variables you
create by assignment. The next segment of read-guide.tlc
replaces the
value of record field Top.Employee.GrossRate
:
* Put variables into a field, e.g. %assign Top.Employee.GrossRate = wageCost "%assign Top.Employee.GrossRate = wageCost" Top.Employee.GrossRate expands to wageCost = %<Top.Employee.GrossRate>
Such changes to records are nonpersistent (because record files are inputs to TLC; other file types, such as C source code, are outputs), but can be useful.
You can use several TLC directives besides %assign
to modify
records:
%createrecord | Creates new top-level records, and might also specify subrecords within them, including name/value pairs. |
%addtorecord | Adds fields to an existing record. The new fields can be name/value pairs or aliases to existing records. |
%mergerecord | Combines one or more records. The first record contains itself plus copies of the other records' contents specified by the command, in sequence. |
%copyrecord | Creates a new record as %createrecord does, except the
components of the record come from the existing record you specify. |
%undef var | Removes (deletes) var (a variable or a record) from scope.
If var is a field in a record, TLC removes the field from the
record. If var is a record array (list), TLC removes the first
element of the array; the remaining elements remain accessible. You can remove
only records you create with %createrecord or
%copyrecord . |
See Target Language Compiler Directives for details on these directives.
Index Lists
Record files can contain lists, or sequences of records having the same identifier.
Our example contains a list of three records identified as Project
within the Top
scope. List references are indexed, numbered from 0, in
the order in which they appear in the record file. Here is TLC code that compiles data
from the Name
field of the Project
list:
* Index lists of values, e.g. %assign projects = Top.Project[0].Name + ", " + Top.Project[1].Name... + ", " + Top.Project[2].Name "%assign projects = Top.Project[0].Name + ", " + Top.Project[1].Name..." "+ ", " + Top.Project[2].Name" projects expands to Top.Project[0].Name + ", " + Top.Project[1].Name + ", " + Top.Project[2].Name = %<projects>
The Scope.Record[n].Field
syntax is similar to that used in C to
reference elements in an array of structures.
While explicit indexing, such as the above, is perfectly acceptable, it is often preferable to use a loop construct when traversing entire lists, as shown in Loop Over Lists.
Loop Over Lists
By convention, the section of a record file that a list occupies is preceded by a
record that indicates how many list elements are present. In
files, such parameters are
declared as model
.rtwNum
, where
Ident
is the identifier used for records
in the list that follows. In Ident
guide.rtw
, the Project
list looks like this:
NumProject 3 # Indicates length of following list Project { # First list item, called Top.Project[0] Name "Tea" # Alpha field Name, Top.Project[0].Name Difficulty 3 # Numeric field Top.Project[0].Difficulty } # End of first list item Project { # Second list item, called Top.Project[1] Name "Gillian" # Alpha field Name, Top.Project[1].Name Difficulty 8 # Numeric field Top.Project[1].Difficulty } # End of second list item Project { # Third list item, called Top.Project[2] Name "Zaphod" # Alpha field Name, Top.Project[2].Name Difficulty 10 # Numeric field Top.Project[2].Difficulty } # End of third list item
Thus, the value of NumProject
describes how many
Project
records occur.
Note
model.rtw
files might also contain records that start with
Num
but are not list-size parameters. TLC does not require that
list size parameters start with Num
. Therefore you need to be
cautious when interpreting Num
record
identifiers. The built-in TLC function Ident
SIZE()
can determine the
number of records in a specified scope, hence the length of a list.
The last segment of read-guide.tlc
uses a
%foreach
loop, controlled by the NumProject
parameter, to iterate the Project
list and manipulate its values.
* Traverse and manipulate list data via loops, e.g. %assign diffSum = 0.0 %foreach i = Top.NumProject - At top of Loop, Project = %<Top.Project[i].Name>; Difficulty =... %<Top.Project[i].Difficulty> %assign diffSum = diffSum + Top.Project[i].Difficulty - Bottom of Loop, i = %<i>; diffSum = %<diffSum> %endforeach %assign avgDiff = diffSum / Top.NumProject Average Project Difficulty expands to diffSum / Top.NumProject = %<diffSum> ... / %<Top.NumProject> = %<avgDiff>
As you may recall, the TLC output looks like this:
* Traverse and manipulate list data via loops, e.g. - At top of Loop, Project = Tea; Difficulty = 3 - Bottom of Loop, i = 0; diffSum = 3.0 - At top of Loop, Project = Gillian; Difficulty = 8 - Bottom of Loop, i = 1; diffSum = 11.0 - At top of Loop, Project = Zaphod; Difficulty = 10 - Bottom of Loop, i = 2; diffSum = 21.0 Average Project Difficulty expands to diffSum / Top.NumProjects = 21.0 / 3 = 7.0
diffSum
, a
%foreach
loop is entered, with variable i
declared
as the loop counter, iterating up to NumProject
. The scope of the loop
is all statements encountered until the corresponding
%endforeach
is reached (%foreach
loops may be
nested).Note
Loop iterations implicitly start at zero and range to one less than the index that specifies the upper bound. The loop index is local to the loop body.
Modify read-guide.tlc
Now that you have studied read-guide.tlc
, it is time to modify it.
This exercise introduces two important TLC facilities, file control and
scoping control. You implement both within the
read-guide.tlc
script.
File Control Basics
TLC scripts almost invariably produce output in the form of streams of characters.
Output is normally directed to one or more buffers and files, collectively called
streams. So far, you have directed output from
read-guide.tlc
to the MATLAB Command Window because you included the -v
switch on the
command line. Prove this by omitting -v
when you run
read-guide.tlc
. Type
tlc -r guide.rtw read-guide.tlc
Nothing appears to happen. In fact, the script was executed, but output was directed to a null device (sometimes called the “bit bucket”).
There is one active output file, even if it is null. To specify, open, and close files, use the following TLC directives:
%openfile streamid ="filename" , "mode" %closefile streamid %selectfile streamid
If you do not give a file name, subsequent output flows to the memory buffer named by
streamid
. If you do not specify a mode, TLC opens the file for
writing and deletes any existing content (subject to
system-level file protection mechanisms). Valid mode identifiers are a
(append) and w
(write, the default). Enclose these characters in
quotes.
The %openfile
directive creates a file/buffer (in
w
mode), or opens an existing one (in a
mode).
Note the required equals sign for file specification. Multiple streams can be open for
writing, but only one can be active at one time. To switch output streams, use the
%selectfile
directive. You do not need to close files until you are
done with them.
The default output stream, which you can respecify with the stream ID
NULL_FILE
, is null
. Another built-in stream is
STDOUT
. When activated using %selectfile
,
STDOUT
directs output to the MATLAB Command Window.
Note
The streams NULL_FILE
and STDOUT
are
always open. Specifying them with
%openfile
generates errors. Use %selectfile
to
activate them.
The directive %closefile
closes the current output file or buffer.
Until an %openfile
or a %selectfile
directive is
encountered, output goes to the previously opened stream (or, if
none exists, to null). Use %selectfile
to
designate an open stream for reading or writing. In practice, many TLC scripts write
pieces of output data to separate buffers, which are then selected in a sequence and their
contents spooled to one or more files.
Implement Output File Control
In your tlctutorial/guide
folder, find the file
read-guide-file-src.tlc
. The supplied version of this file contains
comments and three lines of text added. Edit this file to implement output file control,
as follows:
Open
read-guide-file-src.tlc
in your text editor.Save the file as
read-guide-file.tlc
.Note five comment lines that begin with
%% ->
.Under each of these comments, insert a TLC directive as indicated.
Save the edited file as
read-guide-file.tlc
.Execute
read-guide-file.tlc
with the following command:tlc -r guide.rtw read-guide-file.tlc
If you succeeded, TLC creates the file
guidetext.txt
which contains the expected output, and the MATLAB Command Window displays*** Output being directed to file: guidetext.txt *** We're almost done . . . *** Processing completed.
If you did not see these messages, or if a text file was not produced, review the
material and try again. If problems persist, inspect
read-guide-file.tlc
in the guide/solutions
subfolder to see how you should specify file control.
Scope Basics
Structure of Record Files explains the hierarchical organization of records.
Each record exists within a scope defined by the records in which it is nested. The
example file, guide.rtw
, contains the following scopes:
Top Top.Employee Top.Project[0] Top.Project[1] Top.Project[2]
To refer to a field or a record, specify its scoping, even if
no other context that contains the identifier exists. For
example, in guide.rtw
, the field FirstName
exists
only in the scope Top.Employee
. You must refer to it as
Top.Employee.FirstName
whenever accessing it.
When models present scopes that are deeply nested, this can lead to extremely long identifiers that are tedious and error prone to type. For example:
CompiledModel.BlockOutputs.BlockOutput.ReusedBlockOutput
This identifier has a scope that is long and has similar item names that you could easily enter incorrectly.
The %with/%endwith
directive eases the burden of coding TLC scripts
and clarifies their flow of control. The syntax is
%with RecordName [TLC statements] %endwith
Every %with
is eventually followed by an
%endwith
, and these pairs might be nested (but not overlapping). If
RecordName
is below the top level, you need not include the top-level
scope in its description. For example, to make the current scope of
guide.rtw
Top.Employee
, you can specify
%with Employee [TLC statements] %endwith
Naturally, %with Top.Employee
is also valid syntax. Once bracketed
by %with/%endwith
, record identifiers in TLC statements do not require
you to specify their outer scope. However, note the following conditions :
You can access records outside of the current
%with
scope, but you must qualify them fully (for example, using record name and fields).Whenever you make assignments to records inside a
%with
directive, you must qualify them fully.
Change Scope Using %with
In the last segment of this exercise, you modify the TLC script by adding a
%with/%endwith
directive. You also need to edit record identifier
names (but not those of local variables) to account for the changes of scope resulting
from the %with
directives.
Open the TLC script
read-guide-scope-src.tlc
in the text editor.Save the file as
read-guide-scope.tlc
.Note comment lines that commence with
%% ->
.Under each of these comments, insert a TLC directive or modify statements already present, as indicated.
Save the edited file as
read-guide-scope.tlc
.Execute
read-guide-scope.tlc
with the following command:tlc -v -r guide.rtw read-guide-scope.tlc
The output should be exactly the same as from read-guide.tlc
,
except possibly for white space that you might have introduced by indenting sections of
code inside %with/%endwith
or by eliminating blank lines.
Fully specifying a scope inside a %with
context is not an error, it
is simply unnecessary. However, failing to fully specify its scope when assigning it to a
record (for example, %assign GrossRate = wageCost
) is invalid.
If errors result from running the script, review the discussion of scoping above and
edit read-guide-scope.tlc
to eliminate them. As a last resort, inspect
read-guide-scope.tlc
in the /solutions
subfolder
to see how you should have handled scoping in this exercise.
For additional information, see Scopes in the model.rtw File and Variable Scoping.
Pass and Use a Parameter
You can use the TLC commands and built-in functions to pass parameters from the command
line to the TLC file being executed. The most general command switch is
-a
, which assigns arbitrary variables. For example:
tlc -r input.rtw -avar=1 -afoo="abc" vars.tlc
The result of passing this pair of strings via -a
is the same as
declaring and initializing local variables in the file being executed (here,
vars.tlc
). For example:
%assign var = 1 %assign foo = "abc"
You do not need to declare such variables in the TLC file, and they are available for
use when set with -a
. However, errors result if the code assigns
undeclared variables that you do not specify with the -a
switch when
invoking the file. Also note that (in contrast to the -r
switch) a space
should not separate -a
from the parameter you are declaring.
In the final section of this tutorial, you use the built-in function
GET_COMMAND_SWITCH()
to print the name of the record file being used in
the TLC script, and provide a parameter to control whether or not the code is suppressed. By
default the code is executed, but is suppressed if the command line contains
-alist=0
:
Open the TLC script
read-guide-param-src.tlc
in your text editor.Save the file as
read-guide-param.tlc
.To enable your program to access the input filename from the command line, do the following:
Below the line
%selectfile STDOUT
, add the line:%assign inputfile = GET_COMMAND_SWITCH ("r")
The
%assign
directive declares and sets variables. In this instance, it holds a string filename identifier.GET_COMMAND_SWITCH()
returns whatever string argument follows a specified TLC command switch. You must use UPPERCASE for built-in function names.Change the line “
*** WORKING WITH RECORDFILE
” to read as follows:*** WORKING WITH RECORDFILE %<inputfile>
To control whether or not a section of TLC code is executed, do the following:
Below the line “
%assign inputfile = GET_COMMAND_SWITCH ("r")
”, add:The program checks whether a list parameter has been declared, via the intrinsic (built-in) function%if (!EXISTS(list)) %assign list = 1 %endif
EXISTS()
. If no list variable exists, the program assigns one. This defineslist
and by default its value isTRUE
.Enclose lines of code within an
%if
block.%if (list) * Assign contents of a field to a variable, e.g. %assign worker = FirstName "%assign worker = FirstName" worker expands to FirstName = %<worker> %endif
Now the code to assign
worker
is sent to the output only whenlist
isTRUE
.Save
read-guide-param.tlc
.
Execute
read-guide-param.tlc
and examine the output, using the commandtlc -r guide.rtw read-guide-param.tlc
This yields
*** WORKING WITH RECORDFILE [guide.rtw] * Assign contents of a field to a variable, e.g. "%assign worker = FirstName" worker expands to FirstName = Arthur ***END
Execute
read-guide-param.tlc
with the command:tlc -r guide.rtw -alist=0 read-guide-param.tlc
With the
-alist=0
switch, the output displays only the information outside of theif
statement.*** WORKING WITH RECORDFILE [guide.rtw] ***END
Review
The preceding exercises examined the structure of record files, and expanded on how to use TLC directives. The following TLC directives are commonly used in TLC scripts (see Target Language Compiler Directives for detailed descriptions):
%addincludepath | Enable TLC to find included files. |
%addtorecord | Add fields to existing record. New fields can be name/value pairs or aliases to existing records. |
%assign | Create or modify variables. |
%copyrecord | Create new record and, if applicable, specify subrecords within them, including name/value pairs. The components of the record come from the existing record specified. |
%createrecord | Create new top-level records and, if applicable, specify subrecords within them, including name/value pairs. |
%foreach/%endforeach | Iterate loop variable from 0 to upper limit. |
%if/%endif | Control whether code is executed, as in C. |
%include | Insert one file into another, as in C. |
%mergerecord | Combine one or more records. The first record contains itself plus copies of the other records contents specified by the command, in sequence. |
%selectfile | Direct outputs to a stream or file. |
%undef var | Remove (delete) var (a variable or a record) from scope. If
var is a field in a record, TLC removes the field from the
record. If var is a record array (list), TLC removes the first
element of the array; the remaining elements remain accessible. Only records created
via %createrecord or %copyrecord can be
removed. |
%with/%endwith | Add scope to simplify referencing blocks. |