Target Language Compiler Directives
You control how code is generated from models largely through writing or modifying scripts
that apply TLC directives and built-in functions. Use the following sections as your primary
reference to the syntax and format of target language constructs, as well as the MATLAB®
tlc
command itself.
A target language directive must be the first non-blank character on a line and begins
with the %
character. Lines beginning with %%
are TLC
comments, and are not passed to the output stream. Lines beginning with
/*
are C comments, and are passed to the output
stream.
Syntax
A target language file consists of a series of statements of either form:
[text | %<expression>]*
The literal text is passed to the output stream unmodified, and expressions enclosed in
%< >
are evaluated before being written to output (stripped of%< >
).%keyword [argument1, argument2, ...]
The
%keyword
represents one of the directives of Target Language Compiler, and[argument1, argument2, ...]
represents expressions that define required parameters. For example, the statement%assign sysNumber = sysIdx + 1
uses the
%assign
directive to define or change the value of thesysNumber
parameter.
Directives
The rest of this section shows the complete set of Target Language Compiler directives, and describes each directive in detail.
%% text
Single-line comment where text
is the comment.
/% text%/
Single (or multiline) comment where text
is the comment.
%matlab
Calls a MATLAB function that does not return a result. For example, %matlab
disp(2.718)
.
%<expr>
Target language expressions that are evaluated. For example, if you have a TLC
variable that was created via %assign varName = "foo"
, then
%<varName>
would expand to foo
. Expressions
can also be function calls, as in %<FcnName(param1,param2)>
. On
directive lines, TLC expressions need not be placed within the
%<>
syntax. Doing so causes a double evaluation. For example,
%if %<x> == 3
is processed by creating a hidden variable for
the evaluated value of the variable x. The %if
statement then evaluates
this hidden variable and compares it against 3. The efficient way to do this operation is
to write %if x == 3
. In MATLAB notation, this would equate to writing if eval('x') == 3
as opposed to if x = 3
. The exception to this is during an
%assign
for format control, as in
%assign str = "value is: %<var>"
Note: Nested evaluation expressions (e.g.,
%<foo(%<expr>)>
) are not supported.
There is not a speed penalty for evaluations inside strings, such as
%assign x = "%<expr>"
Avoid evaluations outside strings, such as the following example.
%assign x = %<expr>
%if expr
%elseif expr
%else
%endif
expr
expr
Conditional inclusion, where the constant expression
must evaluate to an integer. For
example, the following code checks whether a parameter, expr
k
, has the
numeric value 0.0 by executing a TLC library function to check for equality.
%if ISEQUAL(k, 0.0) <text and directives to be processed if k is 0.0> %endif
In this and other directives, you do not have to expand variables or expressions using
the %<expr>
notation unless expr
appears
within a string. For example,
%if ISEQUAL(idx, "my_idx%<i>")
, where idx
and i
are both strings.
As in other languages, logical evaluations do short-circuit (are halted when the result is known).
%switch expr
%case expr
%break
%default
%break
%endswitch
expr
expr
The %switch
directive is similar to the C language
switch
statement. The expression expr
should be of
a type that can be compared for equality using the == operator
. If
the %break
is not included after a %case
statement, then it will fall through to the next statement.
%with
%endwith
%with recordName
is a scoping operator. Use it to bring the named
record into the current scope, to remain until the matching %endwith
is
encountered (%with
directives can be nested as desired).
Note that on the left side of %assign
statements contained within a
%with
/ %endwith
block, references to fields of
records must be fully qualified (see Assign Values to Fields of Records), as in the following example.
%with CompiledModel %assign oldName = name %assign CompiledModel.name = "newname" %endwith
%setcommandswitch string
string
Changes the value of a command-line switch as specified by the argument string. Only the following switches are supported:
v, m, p, O, d, r, I, a
The following example sets the verbosity level to 1.
%setcommandswitch "-v1"
See also Command-Line Arguments.
%assert expr
expr
Tests a value of a Boolean expression. If the expression evaluates to false, TLC
issues an error message, a stack trace and exit; otherwise, the execution continues
normally. To enable the evaluation of assertions outside the code generator environment,
use the command-line option -da
. When building from within the code
generator, this flag is ignored, as it is superseded by the Enable TLC
assertion check box in the Advanced parameters section
of the Code Generation pane. To control assertion handling from the MATLAB Command Window, use
set_param(model, 'TLCAssertion', 'on|off')
to set this flag on or off. Default is Off. To see the current setting, use
get_param(model, 'TLCAssertion')
%error
%warning
%trace
%exit
Flow control directives:
%error
tokens
The
are expanded and displayed.tokens
%warning
tokens
The
are expanded and displayed.tokens
%trace
tokens
The
are expanded and displayed only when the verbose output command-line optiontokens
-v
or-v1
is specified.%exit
tokens
The
are expanded, displayed, and TLC exits.tokens
When reporting errors, use the following command if the error is produced by an incorrect configuration that the user needs to fix in the model.
%exit Error Message
If you are adding assert code (that is, code that should never be reached), use
%setcommandswitch "-v1" %% force TLC stack trace %exit Assert message
%assign
Creates identifiers (variables). The general form is
%assign [::]variable = expression
The ::
specifies that the variable being created is a global
variable; otherwise, it is a local variable in the current scope (i.e., a local variable
in the function).
If you need to format the variable, say, within a string based upon other TLC variables, then you should perform a double evaluation, as in
%assign nameInfo = "The name of this is %<Name>"
or alternately
%assign nameInfo = "The name of this is " + Name
To assign a value to a field of a record, you must use a qualified variable expression. See Assign Values to Fields of Records.
%createrecord
Creates records in memory. This command accepts a list of one or more record
specifications (e.g., { foo 27 }
). Each record specification contains a
list of zero or more name-value pairs (e.g., foo 27
) that become the
members of the record being created. The values themselves can be record specifications,
as the following illustrates.
%createrecord NEW_RECORD { foo 1 ; SUB_RECORD {foo 2} } %assign x = NEW_RECORD.foo /* x = 1 */ %assign y = NEW_RECORD.SUB_RECORD.foo /* y = 2 */
If more than one record specification follows a given record name, the set of record specifications constitutes an array of records.
%createrecord RECORD_ARRAY { foo 1 } ... { foo 2 } ... { bar 3 } %assign x = RECORD_ARRAY[1].foo /* x = 2 */ %assign y = RECORD_ARRAY[2].bar /* y = 3 */
Note that you can create and index arrays of subrecords by specifying
%createrecord
with identically named subrecords, as follows:
%createrecord RECORD_ARRAY { SUB_RECORD { foo 1 } ... SUB_RECORD { foo 2 } ... SUB_RECORD { foo 3 } } %assign x = RECORD_ARRAY.SUB_RECORD[1].foo /* x = 2 */ %assign y = RECORD_ARRAY.SUB_RECORD[2].foo /* y = 3 */
If the scope resolution operator (::
) is the first token after the
%createrecord
token, the record is created in the global
scope.
Note
You should not create a record array by using %createrecord
within a loop.
%addtorecord
Adds fields to an existing record. The new fields can be name-value pairs or aliases to already existing records.
%addtorecord OLD_RECORD foo 1
If the new field being added is a record, then %addtorecord
makes
an alias to that record instead of a deep copy. To make a deep copy, use
%copyrecord
.
%createrecord NEW_RECORD { foo 1 } %addtorecord OLD_RECORD NEW_RECORD_ALIAS NEW_RECORD
%mergerecord
Adds (or merges) one or more records into another. The first record will contain the results of the merge of the first record plus the contents of the other records specified by the command. The contents of the second (and subsequent) records are deep copied into the first (i.e., they are not references).
%mergerecord OLD_RECORD NEW_RECORD
If duplicate fields exist in the records being merged, the original record’s fields are not overwritten.
%copyrecord
Makes a deep copy of an existing record. It creates a new record in a similar fashion
to %createrecord
except the components of the record are deep copied
from the existing record. Aliases are replaced by copies.
%copyrecord NEW_RECORD OLD_RECORD
%realformat
Specifies how to format real variables. To format in exponential notation with 16 digits of precision, use
%realformat "EXPONENTIAL"
To format without loss of precision and minimal number of characters, use
%realformat "CONCISE"
When inlining S-functions, the format is set to concise
. You can
switch to exponential
, but should switch it back to
concise
when done.
%language
This must appear before the first GENERATE
or
GENERATE_TYPE
function call. This specifies the name of the
language as a string, which is being generated as in %language "C"
.
Generally, this is added to your system target file.
The only valid value is C
which enables support for
C
and C++
code generation as specified by the
configuration parameter TargetLang
(see Language for more information).
%implements
Placed within the .tlc
file for a specific record type, when mapped
via %generatefile
. The syntax is %implements "Type"
"Language"
. When inlining an S-function in C or C++, this should be the first
noncomment line in the file, as in
%implements "s_function_name" "C"
The next noncomment lines will be %function
directives specifying
the functionality of the S-function.
See the %language
and GENERATE
function
descriptions for further information.
%generatefile
Provides a mapping between a record Type
and functions contained in
a file. Each record can have functions of the same name but different contents mapped to
it (i.e., polymorphism). Generally, this is used to map a Block
record
Type
to the .tlc
file that implements the
functionality of the block, as in
%generatefile "Sin" "sin_wave.tlc"
%filescope
Limits the scope of variables to the file in which they are defined. A
%filescope
directive anywhere in a file declares that variables in
the file are visible only within that file. Note that this limitation also applies to
files inserted, via the %include
directive, into the file containing
the %filescope
directive.
You should not use the %filescope
directive within functions or
GENERATE
functions.
%filescope
is useful in conserving memory. Variables whose scope is
limited by %filescope
go out of scope when execution of the file
containing them completes. This frees memory allocated to such variables. By contrast,
global variables persist in memory throughout execution of the program.
%include
Use %include "file.tlc"
to insert the specified target file at the
current point.
The %include
directives behave as if they were in a global context.
For example,
%addincludepath "./sub1" %addincludepath "./sub2"
in a .tlc
file enables either subfolder to be referenced
implicitly:
%include "file_in_sub1.tlc" %include "file_in_sub2.tlc"
Use forward slashes for folder names, as they work on both UNIX® and PC systems. However, if you do use back slashes in PC folder names, be
sure to escape them, e.g., "C:\\mytlc"
. Alternatively, you can express
a PC folder name as a literal using the L format specifier, as in
L"C:\mytlc"
.
%addincludepath
Use %addincludepath "folder"
to add additional paths to be
searched. Multiple %addincludepath
directives can appear. The compiler
evaluates multiple %addincludepath
directives from the bottom
up.
Using %addincludepath
directives establishes a global context. For
example,
%addincludepath "./sub1" %addincludepath "./sub2"
in a .tlc
file enables either subfolder to be referenced
implicitly:
%include "file_in_sub1.tlc" %include "file_in_sub2.tlc"
Use forward slashes for folder names, as they work on both UNIX and PC systems. However, if you do use back slashes in PC folder names, be
sure to escape them, e.g., "C:\\mytlc"
. Alternatively, you can express
a PC folder name as a literal using the L format specifier, as in
L"C:\mytlc"
.
%roll
%endroll
Multiple inclusion plus intrinsic loop rolling based upon a specified threshold. This directive can be used by most Simulink® blocks that have the concept of an overall block width that is usually the width of the signal passing through the block.
This example of the %roll
directive is for a gain operation,
y=u*k
:
%function Outputs(block, system) Output /* %<Type> Block: %<Name> */ %assign rollVars = ["U", "Y", "P"] %roll sigIdx = RollRegions, lcv = RollThreshold, block,... "Roller", rollVars %assign y = LibBlockOutputSignal(0, "", lcv, sigIdx) %assign u = LibBlockInputSignal(0, "", lcv, sigIdx) %assign k = LibBlockParameter(Gain, "", lcv, sigIdx) %<y> = %<u> * %<k>; %endroll %endfunction
The %roll
directive is similar to %foreach
,
except that it iterates the identifier (sigIdx
in this example) over
roll regions. Roll regions are computed by looking at the input signals and generating
regions where the inputs are contiguous. For blocks, the variable
RollRegions
is automatically computed and placed in the
Block
record. An example of a roll regions vector is [0:19,
20:39]
, where there are two contiguous ranges of signals passing through the
block. The first is 0:19
and the second is 20:39
.
Each roll region is either placed in a loop body (e.g., the C language
for
statement) or inlined, depending upon whether or not the length
of the region is less than the roll threshold.
Each time through the %roll
loop, sigIdx
is an
integer for the start of the current roll region or an offset relative to the overall
block width when the current roll region is less than the roll threshold. The TLC global
variable RollThreshold
is the general model-wide value used to decide
when to place a given roll region in a loop. When the decision is made to place a given
region in a loop, the loop control variable is a valid identifier (e.g.,
"i
"); otherwise it is ""
.
The block
parameter is the current block that is being rolled. The
"Roller"
parameter specifies the name for internal
GENERATE_TYPE
calls made by %roll
. The default
%roll
handler is "Roller"
, which is responsible
for setting up the default block loop rolling structures (e.g., a C for
loop).
The rollVars
(roll variables) are passed to
"Roller"
functions to create roll structures. The defined loop
variables relative to a block are
"U"
The inputs to the block. It assumes you use
LibBlockInputSignal(portIdx, "", lcv, sigIdx)
to access each input, whereportIdx
starts at 0 for the first input port."u
i
"Similar to
"U"
, except only for specific input,
. Thei
"u"
must be lowercase or it will be interpreted as"U"
above."Y"
The outputs of the block. It assumes you use
LibBlockOutputSignal(portIdx, "", lcv, sigIdx)
to access each output, whereportIdx
starts at 0 for the first output port."y
i
"Similar to
"Y"
, except only for specific output,
. Thei
"y"
must be lowercase or it will be interpreted as"Y"
above."P"
The parameters of the block. It assumes you use
LibBlockParameter
(name, "", lcv, sigIdx)
to access them."<param>/
name
"Similar to
"P"
, except specific for a specific
.name
rwork
The
RWork
vectors of the block. It assumes you useLibBlockRWork
(name, "", lcv, sigIdx)
to access them."<rwork>/
name
"Similar to
RWork
, except for a specific
.name
dwork
The
DWork
vectors of the block. It assumes you useLibBlockDWork
(name, "", lcv, sigIdx)
to access them."<dwork>/
name
"Similar to
DWork
, except for a specific
.name
iwork
The
IWork
vectors of the block. It assumes you useLibBlockIWork
(name, "", lcv, sigIdx)
to access them."<iwork>/
name
"Similar to
IWork
, except for a specific
.name
pwork
The
PWork
vectors of the block. It assumes you useLibBlockPWork
(name, "", lcv, sigIdx)
to access them."<pwork>/
name
"Similar to
PWork
, except for a specific
.name
"Mode"
The mode vector. It assumes you use
LibBlockMode
("",lcv,sigIdx)
to access it."PZC"
Previous zero-crossing state. It assumes you use
LibPrevZCState
("",lcv, sigIdx)
to access it.
To roll your own vector based upon the block’s roll regions,
you need to walk a pointer to your vector. Assuming your vector is pointed to by the first
PWork
, called name
,
datatype *buf = (datatype*)%<LibBlockPWork(name,"","",0) %roll sigIdx = RollRegions, lcv = RollThreshold, block, ... "Roller", rollVars *buf++ = whatever; %endroll
Note: In the above example, sigIdx
and lcv
are local to the body of the loop.
%breakpoint
Sets a breakpoint for the TLC debugger. See %breakpoint Directive.
%function
%return
%endfunction
A function that returns a value is defined as
%function name(optional-arguments) %return value %endfunction
A void function does not produce output and is not required to return a value. It is defined as
%function name(optional-arguments) void %endfunction
A function that produces outputs to the current stream and is not required to return a value is defined as
%function name(optional-arguments) Output %endfunction
For block target files, you can add to your inlined .tlc
file the
following functions that are called by the model-wide target files during code generation.
%function
BlockInstanceSetup
(block,system) void
Called for each instance of the block within the model.
%function
BlockTypeSetup
(block,system) void
Called once for each block type that exists in the model.
%function
Enable
(block,system) Output
Use this if the block is placed within an enabled subsystem and has to take specific actions when the subsystem is enabled. Place within a subsystem enable routine.
%function
Disable
(block,system) Output
Use this if the block is placed within a disabled subsystem and has to take specific actions when the subsystem is disabled. Place within a subsystem disable routine.
%function
Start
(block,system) Output
Include this function if your block has startup initialization code that needs to be placed within
MdlStart
.%function
InitializeConditions
(block,system) Output
Use this function if your block has state that needs to be initialized at the start of execution and when an enabled subsystem resets states. Place in
MdlStart
and/or subsystem initialization routines.%function
Outputs
(block,system) Output
The primary function of your block. Place in
MdlOutputs
.%function
Update
(block,system) Output
Use this function if your block has actions to be performed once per simulation loop, such as updating discrete states. Place in
MdlUpdate
.%function
Derivatives
(block,system) Output
Use this function if your block has derivatives.
%function
ZeroCrossings
(block,system) Output
Use this function if your block does zero-crossing detection and has actions to be performed in
MdlZeroCrossings
.%function
Terminate
(block,system) Output
Use this function if your block has actions that need to be in
MdlTerminate
.
%foreach
%endforeach
Multiple inclusion that iterates from 0
to the
upperLimit-1
constant integer expression. Each time through the loop,
the loopIdentifier
, (e.g., x
) is assigned the
current iteration value.
%foreach loopIdentifier = upperLimit %break -- use this to exit the loop %continue -- use this to skip the following code and continue to the next iteration %endforeach
Note: The upperLimit
expression is
cast to a TLC integer value. The loopIdentifier
is local to the loop
body.
%for
Multiple inclusion directive with syntax
%for ident1 = const-exp1, const-exp2, ident2 = const-exp3 %body %break %continue %endbody %endfor
The first portion of the %for
directive is identical to the
%foreach
statement. The %break
and
%continue
directives act the same as they do in the
%foreach
directive. const-exp2
is a Boolean
expression that indicates whether the loop should be rolled (see %roll
above).
If const-exp2
evaluates to TRUE
,
ident2
is assigned the value of const-exp3
.
Otherwise, ident2
is assigned an empty string.
Note:
ident1
and ident2
above are local to the loop
body.
%openfile
%selectfile
%closefile
These are used to manage the files that are created. The syntax is
%openfile streamId="filename.ext" mode {open for writing} %selectfile streamId {select an open file} %closefile streamId {close an open file}
Note that the "filename.ext
" is optional. If a filename is not
specified, a variable (string buffer) named streamId
is created
containing the output. The mode argument is optional. If specified, it can be
"a"
for appending or "w"
for writing.
Note that the special string streamIdNULL_FILE
specifies
no output. The special string
streamIdSTDOUT
specifies output to the terminal.
To create a buffer of text, use
%openfile buffer text to be placed in the 'buffer' variable. %closefile buffer
Now buffer
contains the expanded text specified between the
%openfile
and %closefile
directives.
%generate
%generate blk fn
is equivalent to
GENERATE
(
.blk
,fn
)
%generate blk fn type
is equivalent to
GENERATE
(
.blk
,fn
,type
)
%undef
%undef
removes the variable
var
from scope. If
var
is a field in a record,
var
%undef
removes that field from the record. If
is a record array,
var
%undef
removes the entire record array.
Comments
You can place comments anywhere within a target file. To include comments, use the
/%...%/
or %%
directives. For example:
/% Abstract: Return the field with [width], if field is wide %/
or
%endfunction %% Outputs function
Use the %%
construct for line-based comments. Characters from
%%
to the end of the line become a comment.
Non-directive lines, that is, lines that do not have %
as their first
non-blank character, are copied into the output buffer verbatim. For example,
/* Initialize sysNumber */ int sysNumber = 3;
copies both lines to the output buffer.
To include comments on lines that do not begin with the %
character,
you can use the /%...%/
or %%
comment directives. In
these cases, the comments are not copied to the output buffer.
Note
If a non-directive line appears within a function, it is not copied to the output
buffer unless the function is an output function or you specifically select an output file
using the %selectfile
directive. For more information about functions,
see Target Language Functions.
Line Continuation
You can use the C language
\
character or the MATLAB sequence
...
to continue a line. If a directive is too long to fit conveniently on
one line, this allows you to split the directive onto multiple lines. For example:
%roll sigIdx = RollRegions, lcv = RollThreshold, block,\ "Roller", rollVars
or
%roll sigIdx = RollRegions, lcv = RollThreshold, block,... "Roller", rollVars
Note
Use \
to suppress line feeds to the output and the ellipsis
...
to indicate line continuation. Note that \
and
the ellipsis ...
cannot be used inside strings.
Target Language Value Types
This table shows the types of values you can use within the context of expressions in your target language files. Expressions in the Target Language Compiler must use these types.
Value Type String | Example | Description |
---|---|---|
1==1 | Result of a comparison or other Boolean operator. The result will be
| |
3.0+5.0i | 64-bit double-precision complex number ( | |
3.0F+5.0Fi | 32-bit single-precision complex number ( | |
%openfile x | String buffer opened with | |
"File" | %openfile x = "out.c" | File opened with |
%function foo ... | User-defined function and | |
3+5i | 32-bit integer imaginary number ( | |
"Identifier" | abc | Identifier values can appear only within the
|
Matrix (3,2) [ [ 1, 2]; [3 , 4]; [ 5, 6] ] | Matrices are simply lists of vectors. The individual elements of the
matrix do not need to be the same type, and can be
any supported type except vectors or matrices. The
| |
15 | Integer number ( | |
[1:5] | Range of integers between 1 and 5, inclusive. | |
"Real" | 3.14159 | Floating-point number ( |
3.14159F | 32-bit single-precision floating-point number ( | |
Block { ... } | Block record. | |
FILE_EXISTS | Special built-in function, such as
| |
"Hello, World" | ASCII character strings. In all contexts,
two strings in a row are concatenated to form the final value, as in
| |
<sub1> | Subsystem identifier. Within the context of an expansion, be careful to
escape the delimiters on a subsystem identifier, as in | |
15U | 32-bit unsigned integer ( | |
3U+5Ui | 32-bit complex unsigned integer ( | |
[1, 2] or BR Vector(2) [1, 2] | Vectors are lists of values. The individual elements of a vector do not need to be the same type, and can be of any supported type except vectors or matrices. |
Target Language Expressions
You can include an expression of the form
%<
in a target file. The
Target Language Compiler replaces
expression
>%<
with a calculated
replacement value based upon the type of the variables within the
expression
>%<>
operator. Integer constant expressions are folded and replaced with the resultant value; string constants are concatenated (e.g., two strings in a row
"a"
"b"
, are replaced with "ab"
).
%<expression> /* Evaluates the expression. * Operators include most standard C * operations on scalars. Array indexing * is required for certain parameters that * are block-scoped within the .rtw file.*/
Within the context of an expression, each identifier must evaluate to an identifier or
function argument currently in scope. You can use the %< >
directive on a line to perform text substitution. To include the >
character within a
replacement, you must escape it with a \
character. For example:
%<x \> 1 ? "ABC" : "123">
Operators that need the >
character to be escaped are the
following:
Operator | Description | Example |
---|---|---|
> | greater than | y = %<x \> 2>; |
>= | greater than or equal to | y = %<x \>= 3>; |
>> | right shift | y = %<x \>\> 4>; |
The table Target Language Expressions lists the operators that are allowed in expressions. In this table, expressions are listed in order from highest to lowest precedence. The horizontal lines distinguish the order of operations.
As in C expressions, conditional operators are short-circuited. If the expression includes a function call with effects, the effects are noticed as if the entire expression was not fully evaluated. For example:
%if EXISTS(foo) && foo == 3
If the first term of the expression evaluates to a Boolean false (i.e.,
foo
does not exist), the second term (foo == 3
) is
not evaluated.
In the upcoming table, note that numeric
is one of the
following:
Boolean
Number
Unsigned
Real
Real32
Complex
Complex32
Gaussian
UnsignedGaussian
Also, note that integral
is one of the following:
Number
Unsigned
Boolean
See TLC Data Promotions for information on the promotions that result when the Target Language Compiler operates on mixed types of expressions.
Target Language Expressions
Note
Relational operators ( <, =<, >, >=, !=, ==
) can be
used with nonfinite values.
You do not have to place expressions in the %< >
eval
format when they appear on directive lines. Doing so causes a
double evaluation.
TLC Data Promotions
When the Target Language Compiler operates on mixed types of expressions, it promotes the results to the common types indicated in the following table.
The table uses the following abbreviations:
| Boolean |
| Number |
| Unsigned |
| Real32 |
| Real |
| Gaussian |
| UnsignedGaussian |
| Complex32 |
| Complex |
The top row (in bold) and first column (in bold) show the types of expression used in the operation. The intersection of the row and column shows the resulting type of expressions.
For example, if the operation involves a Boolean expression (B
) and
an unsigned expression (U
), the result will be an unsigned expression
(U
).
Data Types Resulting from Expressions of Mixed Type
B | N | U | F | D | G | UG | C32 | C | |
---|---|---|---|---|---|---|---|---|---|
B | B | N | U | F | D | G | UG | C32 | C |
N | N | N | U | F | D | G | UG | C32 | C |
U | U | U | U | F | D | UG | UG | C32 | C |
F | F | F | F | F | D | C32 | C32 | C32 | C |
D | D | D | D | D | D | C | C | C | C |
G | G | G | UG | C32 | C | G | UG | C32 | C |
UG | UG | UG | UG | C32 | C | UG | UG | C32 | C |
C32 | C32 | C32 | C32 | C32 | C | C32 | C32 | C32 | C |
C | C | C | C | C | C | C | C | C | C |
Formatting
By default, the Target Language Compiler outputs floating-point numbers in exponential notation with 16 digits of precision. To override the default, use the directive
If
is
string
"EXPONENTIAL"
, the standard exponential notation with 16 digits of
precision is used. If
is
string
"CONCISE"
, the compiler uses internal heuristics to output the values
in a more readable form while maintaining accuracy. The %realformat
directive sets the default format for Real
number output to the selected
style for the remainder of processing or until it encounters another
%realformat
directive.
Conditional Inclusion
The conditional inclusion directives are
%if constant-expression %else %elseif constant-expression %endif %switch constant-expression %case constant-expression %break %default %endswitch
%if
The constant-expression
must evaluate to an integer expression. It
controls the inclusion of the following lines until it encounters an
%else
, %elseif
, or %endif
directive. If the constant-expression
evaluates to
0
, the lines following the directive are not included. If the
constant-expression
evaluates to an integer value other than
0
, the lines following the %if
directive are
included until the %endif
, %elseif
, or
%else
directive.
When the compiler encounters an %elseif
directive, and
no prior %if
or
%elseif
directive has evaluated to nonzero, the compiler evaluates
the expression. If the value is 0, the lines following the %elseif
directive are not included. If the value is nonzero, the lines following the
%elseif
directive are included until the subsequent
%else
, %elseif
, or %endif
directive.
The %else
directive begins the inclusion of source text if the
previous %elseif
statements or the original %if
statement evaluates to 0
; otherwise, it prevents the inclusion of
subsequent lines up to and including the following %endif
.
The constant-expression
can contain
any expression specified in Target Language Expressions.
%switch
The %switch
statement evaluates the constant expression and compares
it to expressions appearing on %case
selectors. If a match is found,
the body of the %case
is included; otherwise the
%default
is included.
%case ... %default
bodies flow together, as in C, and
%break
must be used to exit the switch statement.
%break
exits the nearest enclosing %switch
,
%foreach
, or %for
loop in which it appears. For
example,
%switch(type) %case x /* Matches variable x. */ /* Note: Any valid TLC type is allowed. */ %case "Sin" /* Matches Sin or falls through from case x. */ %break /* Exits the switch. */ %case "gain" /* Matches gain. */ %break %default /* Does not match x, "Sin," or "gain." */ %endswitch
In general, this is a more readable form for the %if/%elseif/%else
construction.
Multiple Inclusion
%foreach
The syntax of the %foreach
multiple inclusion directive is
The constant-expression
must evaluate to an integer expression,
which then determines the number of times to execute the foreach
loop.
The identifier
increments from 0
to one less than
the specified number. Within the foreach
loop, you can use
x
, where x
is the identifier, to access the
identifier variable. %break
and %continue
are
optional directives that you can include in the %foreach
directive:
Use
%break
to exit the nearest enclosing%for
,%foreach
, or%switch
statement.Use
%continue
to begin the next iteration of a loop.
%for
Note
The %for
directive is functional, but it is not recommended.
Instead, use %roll
, which provides the same capability in a more open
way. The code generator does not use the %for
construct.
The syntax of the %for
multiple inclusion directive is
The first portion of the %for
directive is identical to the
%foreach
statement in that it causes a loop to execute from
0
to N-1
times over the body of the loop. In the
normal case, it includes only the lines between %body
and
%endbody
, and the lines between the %for
and
%body
, and ignores the lines between %endbody
and
%endfor
.
The %break
and %continue
directives act the same
as they do in the %foreach
directive.
const-exp2
is a Boolean expression that indicates whether the loop
should be rolled. If const-exp2
is true, ident2
receives the value of const-exp3
; otherwise it receives the null
string. When the loop is rolled, the lines between the %for
and the
%endfor
are included in the output exactly one time.
ident2
specifies the identifier to be used for testing whether the
loop was rolled within the body. For example,
%for Index = <NumNonVirtualSubsystems>3, rollvar="i" { int i; for (i=0; i< %<NumNonVirtualSubsystems>; i++) { %body x[%<rollvar>] = system_name[%<rollvar>]; %endbody } } %endfor
If the number of nonvirtual subsystems (NumNonVirtualSubsystems
) is
greater than or equal to 3, the loop is rolled, causing the code within the loop to be
generated exactly once. In this case, Index = 0
.
If the loop is not rolled, the text before and after the body of the loop is ignored
and the body is generated NumNonVirtualSubsystems
times.
This mechanism gives each individual loop control over whether or not it should be rolled.
%roll
The syntax of the
%roll
multiple inclusion directive is
%roll ident1 = roll-vector-exp, ident2 = threshold-exp, ... block-exp [, type-string [,exp-list] ] %break %continue %endroll
This statement uses the roll-vector-exp
to expand the body of the
%roll
statement multiple times as in the %foreach
statement. If a range is provided in the roll-vector-exp
and that range
is larger than the threshold-exp
expression, the loop will roll. When a
loop rolls, the body of the loop is expanded once and the identifier
(ident2
) provided for the threshold expression is set to the name of
the loop control variable. If no range is larger than the
specified rolling threshold, this statement is identical to the
%foreach
statement. For example,
%roll Idx = [ 1 2 3:5, 6, 7:10 ], lcv = 10, ablock %endroll
In this case, the body of the %roll
statement expands 10 times, as
in the %foreach
statement, because there are
no regions greater than or equal to 10.
Idx
counts from 1 to 10, and lcv
is set to the
null string, ""
.
When the Target Language Compiler determines that a given block will roll, it performs
a GENERATE_TYPE
function call to output the various pieces of the loop
(other than the body). The default type used is Roller
; you can
override this type with a string that you specify. Extra arguments passed to the
%roll
statement are provided as arguments to these special-purpose
functions. The called function is one of these four functions:
RollHeader(block, ...)
. This function is called once on the first section of this roll vector that will
actually roll. It should return a string that is assigned to the lcv
within the body of the %roll
statement.
LoopHeader(block, StartIdx, Niterations, Nrolled, ...)
. This function is called once for each section that will roll prior to the body of
the %roll
statement.
LoopTrailer(block, Startidx, Niterations, Nrolled, ...)
. This function is called once for each section that will roll after the body of the
%roll
statement.
RollTrailer(block, ...)
. This function is called once at the end of the %roll
statement if
any of the ranges caused loop rolling.
These functions should output language-specific declarations, loop code, and so on as required to generate code for the loop.
An example of a Roller.tlc
file is
%implements Roller "C" %function RollHeader(block) Output { int i; %return ("i") %endfunction %function LoopHeader(block,StartIdx,Niterations,Nrolled) Output for (i = %<StartIdx>; i < %<Niterations+StartIdx>; i++) { %endfunction %function LoopTrailer(block,StartIdx,Niterations,Nrolled) Output } %endfunction %function RollTrailer(block) Output } %endfunction
Note
The Target Language Compiler function library provided with the code generator has
the capability to extract references to the block I/O and other code generator vectors
that vastly simplify the body of the %roll
statement. These
functions include LibBlockInputSignal
,
LibBlockOutputSignal
, LibBlockParameter
,
LibBlockRWork
, LibBlockIWork
,
LibBlockPWork
, LibDeclareRollVars
,
LibBlockMatrixParameter
,
LibBlockParameterAddr
,
LibBlockContinuousState
, and
LibBlockDiscreteState
. (See the function reference pages in
Input Signal Functions, Output Signal Functions, Parameter Functions, and Block State and Work Vector Functions.) This library also includes a
default implementation of Roller.tlc
as a “flat”
roller.
Extending the former example to a loop that rolls,
%language "C" %assign ablock = BLOCK { Name "Hi" } %roll Idx = [ 1:20, 21, 22, 23:25, 26:46], lcv = 10, ablock Block[%< lcv == "" ? Idx : lcv>] *= 3.0; %endroll
This Target Language Compiler code produces this output:
{ int i; for (i = 1; i < 21; i++) { Block[i] *= 3.0; } Block[21] *= 3.0; Block[22] *= 3.0; Block[23] *= 3.0; Block[24] *= 3.0; Block[25] *= 3.0; for (i = 26; i < 47; i++) { Block[i] *= 3.0; } }
Object-Oriented Facility for Generating Target Code
The Target Language Compiler provides a simple object-oriented facility. The language directives are
This facility was designed specifically for customizing the code for Simulink blocks, but can be used for other purposes as well.
%language
The %language
directive specifies the target language being generated. It is required as a consistency check to
verify the implementation files found for the language being generated. The
%language
directive must appear prior to the first
GENERATE
or GENERATE_TYPE
built-in function
call. %language
specifies the language as a string. For example:
%language "C"
Simulink blocks have a Type
parameter. This parameter is a string
that specifies the type of the block, for example "Sin"
or
"Gain"
. The object-oriented facility uses this type to search the
path for a file that implements the block. By default the name of the file is the
Type
of the block with .tlc
appended, so for
example, if the Type
is "Sin"
the Compiler would
search for "Sin.tlc"
along the path. You can override this default
filename using the %generatefile
directive to specify the filename that
you want to use to replace the default filename. For example,
%generatefile "Sin" "sin_wave.tlc"
The files that implement the block-specific code must contain an
%implements
directive indicating both the type and the language being
implemented. The Target Language Compiler will produce an error if the
%implements
directive does not match as expected. For example,
%implements "Sin" "Pascal"
causes an error if the initial language choice was C.
You can use a single file to implement more than one target language by specifying the desired languages in a vector. For example,
%implements "Sin" "C"
Finally, you can implement several types using the wildcard (*
) for
the type field:
%implements * "C"
Note
The use of the wildcard (*
) is not recommended because it relaxes
error checking for the %implements
directive.
GENERATE and GENERATE_TYPE Functions
The Target Language Compiler has two built-in functions that dispatch object-oriented
calls, GENERATE
and GENERATE_TYPE
. You can call a function appearing in an
implementation file (from outside the specified file) only by using the
GENERATE
and GENERATE_TYPE
special
functions.
GENERATE. The GENERATE
function takes two or more input arguments. The
first argument must be a valid scope and the second a string containing the name of the
function to call. The GENERATE
function passes the first block
argument and any additional arguments specified to the
function being called. The return argument is the value, if
any, returned from the function being called. Note that
the compiler automatically “scopes” or adds the first argument to the list
of scopes searched as if it appears on a %with
directive line. (See
Variable Scoping.) This scope is removed when the function returns.
GENERATE_TYPE. The GENERATE_TYPE
function takes three or more input arguments.
It handles the first two arguments identically to the GENERATE
function call. The third argument is the type; the type specified in the Simulink block is ignored. This facility is used to handle S-function code
generation by the build process. That is, the block type is
S-function
, but the Target Language Compiler generates it as the
specific S-function specified by GENERATE_TYPE
. For example,
GENERATE_TYPE(block, "Output", "dp_read")
specifies that S-function block
is of type
dp_read
.
The block
argument and any
additional arguments are passed to the function being called. Like the
GENERATE
built-in function, the compiler automatically scopes the
first argument before the GENERATE_TYPE
function is entered and
then removes the scope on return.
Within the file containing %implements
, function calls are looked
up first within the file and then in the global scope. This makes it possible to have
hidden helper functions used exclusively by the current object.
Note
It is not an error for the GENERATE
and
GENERATE_TYPE
directives to find
no matching functions. This is to prevent requiring
empty specifications for all aspects of block code
generation. Use the GENERATE_FUNCTION_EXISTS
or
GENERATE_TYPE_FUNCTION_EXISTS
directives to determine whether
the specified function actually exists.
Output File Control
The structure of the output file control construct is
%openfile
The %openfile
directive opens a file or buffer for writing; the required string variable becomes a variable of type
file
. For example,
%openfile x /% Opens and selects x for writing. %/ %openfile out = "out.h" /% Opens "out.h" for writing. %/
%selectfile
The %selectfile
directive selects the file specified by the
variable as the current output stream. Output goes to that file until another file is
selected using %selectfile
. For example,
%selectfile x /% Select file x for output. %/
%closefile
The %closefile
directive closes the specified file or buffer. If the closed entity is the currently selected output stream,
%closefile
invokes %selectfile
to reselect the
previously selected output stream.
There are two possible cases that %closefile
must handle:
If the stream is a file, the associated variable is removed as if by
%undef
.If the stream is a buffer, the associated variable receives the text that has been output to the stream. For example,
%assign x = "" /% Creates an empty string. %/ %openfile x "hello, world" %closefile x /% x = "hello, world\n"%/
If desired, you can append to an output file or string by using the optional mode, a
, as in
%openfile "foo.c", "a" %% Opens foo.c for appending.
Input File Control
The input file control directives are
%include
The %include
directive searches the path for the target file
specified by string
and includes the contents of the file inline at the point where the %include
statement
appears.
%addincludepath
The %addincludepath
directive adds an additional include path to be searched when the Target Language Compiler references
%include
or block target files. The syntax is
%addincludepath string
The string
can be an absolute path or an explicit relative path.
For example, to specify an absolute path, use
%addincludepath "C:\\folder1\\folder2" (PC) %addincludepath "/folder1/folder2" (UNIX)
To specify a relative path, the path must explicitly start with .
. For example,
%addincludepath ".\\folder2" (PC) %addincludepath "./folder2" (UNIX)
Note that for PC, the backslashes must be escaped (doubled).
When an explicit relative path is specified, the folder that is added to the Target
Language Compiler search path is created by concatenating the location of the target file
that contains the %addincludepath
directive and the explicit relative
path.
The Target Language Compiler searches the folders in the following order for target or include files:
The current folder.
Include paths specified in
%addincludepath
directives. The compiler evaluates multiple%addincludepath
directives from the bottom up.Include paths specified at the command line via
-I
. The compiler evaluates multiple-I
options from right to left.
Typically, %addincludepath
directives should be specified in your
system target file. Multiple %addincludepath
directives will add
multiple paths to the Target Language Compiler search path.
Note
The compiler does not search the MATLAB path, and will not find a file that is available only on that path. The compiler searches only the locations described above.
Asserts, Errors, Warnings, and Debug Messages
The related assert, error, warning, and debug message directives are
These directives produce error, warning, or trace messages whenever a target file detects an error condition, or tracing is desired. The tokens following the directive on a line become part of the generated error or warning message.
The Target Language Compiler places messages generated by %trace
onto
stderr
if and only if you specify the verbose mode switch
(-v
) to the Target Language Compiler. See Command-Line Arguments for additional information about switches.
The %assert
directive evaluates the expression and produces a stack
trace if the expression evaluates to a Boolean false
.
Note
In order for %assert
directives to be evaluated, Enable
TLC assertion must be selected in the Advanced parameters
section of the Code Generation pane. The default action is for %assert
directives not to
be evaluated.
The %exit
directive reports an error and stops further
compilation.
Built-In Functions and Values
The following table lists the built-in functions and values that are added to the list
of parameters that appear in the
file. These Target Language Compiler functions and values are
defined in uppercase so that they are visually distinct from other parameters in the
model
.rtw
file, and, by convention, from
user-defined parameters.model
.rtw
TLC Built-In Functions and Values
Built-In Function Name | Expansion |
---|---|
The first expression must be a string that corresponds to one of the type names in the table Target Language Value Types, and the second expression will be cast to that type. A typical use might be to cast a variable to a real format as in CAST("Real", variable-name) An
example of this is in working with parameter values for S-functions. To use them
within C or C++ code, you need to typecast them to | |
| Returns |
If the | |
Performs an evaluation in MATLAB. For example, %assign result = FEVAL("sin",3.14159) The
%matlab disp(2.718) Note: If the MATLAB function returns more than one value, TLC receives the first value only. | |
Returns an array of strings containing the record field names associated
with the record. Because it returns a sorted list of strings, the function is
| |
| |
The first expression is a | |
The function accepts the folder or file names and returns the full file
specification. Using this function improves the efficiency of the TLC code when
compared to FEVAL function calls to MATLAB function | |
Returns the contents of the specified field name, if the field name is associated with the record. The function uses hash lookup, and therefore executes in constant time. | |
Executes function calls mapped to a specific record type (i.e., block
record functions). For example, use this to execute the functions in the
| |
For the specified record type, does a | |
Returns a potentially multiline string that can be used to declare the
value(s) of For
example,
yields this C code:
| |
Determines whether a given block function exists. The first expression is
the same as the first argument to | |
Similar to | |
Same as | |
Returns the values of command-line switches. Only the following switches are supported: v, m, p, O, d, dr, r, I, a | |
| |
Returns the imaginary part of a complex number. | |
| |
| |
| |
| |
| |
| |
Minimum integer value on host machine. | |
Maximum integer value on host machine. | |
Returns | |
Where the data types of both expressions are numeric: returns
Where the data type of either expression is nonnumeric
(e.g., string or record): returns | |
Returns | |
Returns | |
Returns | |
Returns | |
Returns | |
| Returns a Boolean value indicating whether its argument is a reference to a Simulink parameter or not. This function supports parameter sharing with Simulink; using it can save memory and time during code generation. For example, %if !ISSLPRMREF(param.Value) assign param.Value = CAST("Real", param.Value) %endif |
| Returns |
A predefined file for no output that you
can use as an argument to | |
The number of target files used thus far in expansion. | |
Returns the number of lines that have been written to the currently
selected file or buffer. Does not work for | |
Returns the real part of a complex number. | |
| Returns the substrings in |
| Returns a new string that replaces instances of the substring
|
Removes the specified field from the contents of the record. Returns
| |
Returns the number of times the current roll regions are looping or
| |
Sets the contents of the field name associated with the record. Returns
| |
Calculates the size of the first expression and generates a two-element
row vector. If the second operand is specified, it is used as an integer index
into this row vector; otherwise the entire row vector is returned.
[1,<number of blocks>] | |
Formats the data in variable | |
A predefined file for | |
Expands the expression into a string; the characters
| |
Accepts a vector of UTF-16 values and returns a UTF-8 encoded string that the function constructs by treating each value as a single code point (UTF-16 surrogate pairs are not supported). Use this function primarily for S-function string parameters. | |
| Returns |
| Accepts the string |
| Accepts the string |
Returns a substring of the string expr where the substring
begins at index position startIdx and ends at index position
endIdx-1 . The arguments startIdx and
endIdx must be nonnegative integers. The first character of the
string expr is at index position 0. If endIdx
is less than startIdx , the function returns an empty
string. | |
Looks for specially formatted strings of the form
%<sysname("<sub>/Gain")> returns ["sub","Gain"] In
| |
Returns a vector containing the names of the target files included thus
far in the expansion. Absolute paths are used. See also
| |
Boolean constant that equals a negative evaluated Boolean expression. | |
Boolean constant that equals a positive evaluated Boolean expression. | |
Date and time of compilation. | |
Version and date of the Target Language Compiler. | |
Evaluates | |
| |
| |
| |
Maximum unsigned integer value on host machine. | |
Accepts a string and returns 1 if the string contains only white-space
characters ( | |
The first expression is a roll vector and the second expression is a roll
threshold. This function returns |
FEVAL Function
The FEVAL
built-in function calls MATLAB file functions and MEX-functions. The structure is
%assign result = FEVAL( matlab-function-name, rhs1, rhs2, ... rhs3, ... );
Note
Only a single left-side argument is allowed when you use
FEVAL
.If your MATLAB function evaluation leads to an error, the TLC compiler does not terminate but continues with the execution. The FEVAL directive returns an empty value to the TLC.
For string operations, it is recommended to use string TLC directives instead of FEVAL functions.
This table shows the conversions that are made when you use
FEVAL
.
MATLAB Conversions
TLC Type | MATLAB Type |
---|---|
"Boolean" | Boolean (scalar or matrix) |
"Number" | Double (scalar or matrix) |
"Real" | Double (scalar or matrix) |
"Real32" | Double (scalar or matrix) |
"Unsigned" | Double (scalar or matrix) |
"String" | String |
"Vector" | If the vector is homogeneous, it is converted to a MATLAB vector. If the vector is heterogeneous, it is converted to a MATLAB cell array. |
"Gaussian" | Complex (scalar or matrix) |
"UnsignedGaussian" | Complex (scalar or matrix) |
"Complex" | Complex (scalar or matrix) |
"Complex32" | Complex (scalar or matrix) |
"Identifier" | String |
"Subsystem" | String |
"Range" | Expanded vector of Doubles |
"Idrange" | Expanded vector of Doubles |
"Matrix" | If the matrix is homogeneous, it is converted to a MATLAB matrix. If the matrix is heterogeneous, it is converted to a MATLAB cell array. (Cell arrays can be nested.) |
"Scope" or "Record" | Structure with elements |
Scope or Record alias | String containing fully qualified alias name |
Scope or Record array | Cell array of structures |
Other type not listed above | Conversion not supported |
When values are returned from MATLAB, they are converted as shown in this table. Note that conversion of matrices with more than two dimensions is not supported, nor is conversion or downcast of 64-bit integer values.
More Conversions
MATLAB Type | TLC Type |
---|---|
String
| String |
Vector of Strings | Vector of Strings |
Boolean (scalar or matrix) | Boolean (scalar or matrix) |
INT8,INT16,INT32 | Number (scalar or matrix) |
INT64 | Not supported |
UINT64 | Not supported |
Complex INT8,INT16,INT32 | Gaussian (scalar or matrix) |
UINT8,UINT16,UINT32 | Unsigned (scalar or matrix) |
Complex UINT8,UINT16,UINT32 | UnsignedGaussian (scalar or matrix) |
Single precision | Real32 (scalar or matrix) |
Complex single precision | Complex32 (scalar or matrix) |
Double precision | Real (scalar or matrix) |
Complex double precision | Complex (scalar or matrix) |
Sparse matrix | Expanded to matrix of Doubles |
Cell array of structures | Record array |
Cell array of non-structures | Vector or matrix of types converted from the types of the elements |
Cell array of structures and non-structures | Conversion not supported |
Structure | Record |
Object | Conversion not supported |
Other value types are not currently supported.
As an example, this statement uses the FEVAL
built-in function to
call MATLAB to take the sine of the input argument.
%assign result = FEVAL( "sin", 3.14159 )
Variables (identifiers) can take on the following constant values. Note the suffix on the value.
Constant Form | TLC Type |
---|---|
1.0 | "Real" |
1.0[F/f] | "Real32" |
1 | "Number" |
1[U|u] | "Unsigned" |
1.0i | "Complex" |
1[Ui|ui] | "UnsignedGaussian" |
1i | "Gaussian" |
1.0[Fi|fi] | "Complex32" |
Note
The suffix controls the Target Language Compiler type obtained from the constant.
This table shows Target Language Compiler constants and their equivalent MATLAB values.
TLC Constants | Equivalent MATLAB Value |
---|---|
rtInf , Inf ,
inf | +inf |
rtMinusInf | -inf |
rtNan , NaN ,
nan | nan |
rtInfi , Infi ,
infi | inf*i |
rtMinusInfi | -inf*i |
rtNaNi , NaNi ,
nani | nan*i |
TLC Reserved Constants
For double-precision values, the following are defined for infinite and not-a-number IEEE® values:
rtInf, inf, rtMinusInf, -inf, rtNaN, nan
For single-precision values, these constants apply:
rtInfF, InfF, rtMinusInfF, rtNaNF, NaNF
Their corresponding versions when complex are:
rtInfi, infi, rtMinusInfi, -infi, rtNaNi (for doubles) rtInfFi, InfFi, rtMinusInfFi, rtNaNFi, NaNFi (for singles)
For integer values, the following are defined:
INT8MIN, INT8MAX, INT16MIN, INT16MAX, INT32MIN, INT32MAX, UINT8MAX, UINT16MAX, UINT32MAX, INTMAX, INTMIN, UINTMAX
Identifier Definition
To define or change identifiers (TLC variables), use the directive
%assign [::]expression = constant-expression
This directive introduces new identifiers (variables) or changes the values of existing
ones. The left side can be a qualified reference to a variable using the
.
and []
operators, or it can be a single element of
a vector or matrix. In the case of the matrix, only the single element is changed by the
assignment.
The %assign
directive inserts new identifiers into the local function
scope, file function scope, generate file scope, or into the global scope. Identifiers
introduced into the function scope are not available within functions being called, and are
removed upon return from the function. Identifiers inserted into the global scope are
persistent. You can change existing identifiers by completely respecifying them. The
constant expressions can include legal identifiers from the .rtw
files.
You can use %undef
to delete identifiers in the same way that you use it
to remove macros.
Within the scope of a function, variable assignments create new local variables unless
you use the ::
scope resolution operator. In this example, the assignment
creates a variable foo
, local to the function, that will disappear when
the function exits.
%function ... ... %assign foo = 3 ... %endfunction
Note that foo
is created even if a global foo
already exists.
To create or change values in the global scope, you must use the scope resolution
operator (::
) to disambiguate, as in
%function ... %assign foo = 3 %assign ::foo = foo ... %endfunction
The scope resolution operator forces the compiler to assign the value of the local
variable foo
, 3, to the global variable foo
.
Note
It is an error to change a value from the code generator file without qualifying it with the scope. This example does not generate an error:
%assign CompiledModel.name = "newname" %% No error
This example generates an error:
%with CompiledModel %assign name = "newname" %% Error %endwith
Creating Records
Use the %createrecord
directive to build new records in the current
scope. For example, if you want to create a new record called Rec
that
contains two items (e.g., Name "Name"
and Type "t"
),
use
%createrecord Rec { Name "Name"; Type "t" }
Adding Records
Use the %addtorecord
directive to add new records to existing
records. For example, if you have a record called Rec1
that contains a
record called Rec2
, and you want to add an additional
Rec2
to it, use
%addtorecord Rec1 Rec2 { Name "Name1"; Type "t1" }
This figure shows the result of adding the record to the existing one.
If you want to access the new record, you can use
%assign myname = Rec1.Rec2[1].Name
In this same example, if you want to add two records to the existing record, use
%addtorecord Rec1 Rec2 { Name "Name1"; Type "t1" } %addtorecord Rec1 Rec2 { Name "Name2"; Type "t2" }
This produces
Adding Parameters to an Existing Record
You can use the %assign
directive to add a new parameter to an
existing record. For example,
%addtorecord Block[Idx] N 500 /% Adds N with value 500 to Block %/ %assign myn = Block[Idx].N /% Gets the value 500 %/
adds a new parameter, N
, at the end of an existing block with the
name and current value of an existing variable, as shown in this figure. It returns the
block value.
Variable Scoping
This section discusses how the Target Language Compiler resolves references to variables (including records).
Scope, in this document, has two related meanings. First, scope is an attribute of a variable that defines its visibility and persistence. For example, a variable defined within the body of a function is visible only within that function, and it persists only as long as that function is executing. Such a variable has function (or local) scope. Each TLC variable has one (and only one) of the scopes described in Scopes.
The term scope also refers to a collection, or pool, of variables that have the same scope. At a given point in the execution of a TLC program, several scopes can exist. For example, during execution of a function, a function scope (the pool of variables local to the function) exists. In all cases, a global scope (the pool of global variables) also exists.
To resolve variable references, TLC maintains a search list of current scopes and searches them in a well-defined sequence. The search sequence is described in How TLC Resolves Variable References.
Dynamic scoping refers to the process by which TLC creates and deallocates variables and the scopes in which they exist. For example, variables in a function scope exist only while the defining function executes.
Scopes
The following sections describe the possible scopes that a TLC variable can have.
Global Scope. By default, TLC variables have global scope. Global variables are visible to, and can be referenced by, code anywhere in a TLC program. Global variables persist throughout the execution of the TLC program. Global variables are said to belong to the global pool.
Note that the CompiledModel
record of the
file has global scope.
Therefore, you can access this structure from your TLC functions or files.model
.rtw
You can use the scope resolution operator (::
) to explicitly
reference or create global variables from within a function. See The Scope Resolution Operator for examples.
Note that you can use the %undef
directive to free memory used by
global variables.
File Scope. Variables with file scope are visible only within the file in which they are
created. To limit the scope of variables in this way, use the
%filescope
directive anywhere in the defining file.
In the following code fragment, the variables fs1
and
fs2
have file scope. Note that the %filescope
directive does not have to be positioned before the statements that create the
variables.
%assign fs1 = 1 %filescope %assign fs2 = 3
Variables whose scope is limited by %filescope
go out of scope
when execution of the file containing them completes. This lets you free memory
allocated to such variables.
Function (Local) Scope. Variables defined within the body of a function have function scope. That is, they
are visible within and local to the defining function. For example, in the following
code fragment, the variable localv
is local to the function
foo
. The variable x
is global.
%assign x = 3 %function foo(arg) %assign localv = 1 %return x + localv %endfunction
A local variable can have the same name as a global variable. To refer, within a
function, to identically named local and global variables, you must use the scope
resolution operator (::
) to disambiguate the variable references. See
The Scope Resolution Operator for examples.
Note
Functions themselves (as opposed to the variables defined within functions) have global scope. There is one exception: functions defined in generate scope are local to that scope. See Generate Scope.
%with Scope. The %with
directive adds a new scope, referred to as a
%with scope
, to the current list of scopes. This directive
makes it easier to refer to block-scoped variables.
The structure of the %with
directive is
For example, the directive
%with CompiledModel.System[sysidx] ... %endwith
adds the CompiledModel.System[sysidx]
scope to the search list.
This scope is searched before anything else. You can then refer to the system name
simply by
Name
instead of
CompiledModel.System[sysidx].Name
Generate Scope. Generate scope is a special scope used by certain built-in
functions that are designed to support code generation. These functions dispatch
function calls that are mapped to a specific record type. This capability supports a
type of polymorphism in which different record types are associated with functions
(analogous to methods) of the same name. Typically, this feature is used to map
Block
records to functions that implement the functionality of
different block types.
Functions that employ generate scope include GENERATE
,
GENERATE_TYPE
, GENERATE_FUNCTION_EXISTS
, and
GENERATE_TYPE_FUNCTION_EXISTS
. See GENERATE and GENERATE_TYPE Functions. This section discusses generate scope
using the GENERATE
built-in function as an example.
The syntax of the GENERATE
function is
GENERATE(blk,fn)
The first argument (blk
) to GENERATE
is a
valid record name. The second argument (fn
) is the name of a function
to be dispatched. When a function is dispatched through a GENERATE
call, TLC automatically adds blk
to the list of scopes that is
searched when variable references are resolved. Thus the record (blk
)
is visible to the dispatched function as if an implicit %with <blk>...
%endwith
directive existed in the dispatched function.
In this context, the record named blk
is said to be in generate
scope.
Three TLC files, illustrating the use of generate scope, are listed below. The file
polymorph.tlc
creates two records representing two hypothetical
block types, MyBlock
and YourBlock
. Each record
type has an associated function named aFunc
. The block-specific
implementations of aFunc
are contained in the files
MyBlock.tlc
and YourBlock.tlc
.
Using GENERATE
calls, polymorph.tlc
dispatches to a function for each block type. Notice that the aFunc
implementations can refer to the fields of MyBlock
and
YourBlock
, because these records are in generate scope.
The following listing shows
polymorph.tlc
:%% polymorph.tlc %language "C" %%create records used as scopes within dispatched functions %createrecord MyRecord { Type "MyBlock"; data 123 } %createrecord YourRecord { Type "YourBlock"; theStuff 666 } %% dispatch the functions thru the GENERATE call. %% dispatch to MyBlock implementation %<GENERATE(MyRecord, "aFunc")> %% dispatch to YourBlock implementation %<GENERATE(YourRecord, "aFunc")> %% end of polymorph.tlc
The following listing shows
MyBlock.tlc
:%%MyBlock.tlc %implements "MyBlock" "C" %% aFunc is invoked thru a GENERATE call in polymorph.tlc. %% MyRecord is in generate scope in this function. %% Therefore, fields of MyRecord can be referenced without %% qualification %function aFunc(r) Output %selectfile STDOUT The value of MyRecord.data is: %<data> %closefile STDOUT %endfunction %%end of MyBlock.tlc
The following listing shows
YourBlock.tlc
:%%YourBlock.tlc %implements "YourBlock" "C" %% aFunc is invoked thru a GENERATE call in polymorph.tlc. %% YourRecord is in generate scope in this function. %% Therefore, fields of YourRecord can be referenced without %% qualification %function aFunc(r) Output %selectfile STDOUT The value of YourRecord.theStuff is: %<theStuff> %closefile STDOUT %endfunction %%end of YourBlock.tlc
The invocation and output of polymorph.tlc
, as displayed in the
MATLAB Command Window, are shown below:
tlc -v polymorph.tlc The value of MyRecord.data is: 123 The value of YourRecord.theStuff is: 666
Note
Functions defined in generate scope are local to that scope. This is an exception
to the general rule that functions have global scope. In the above example, for
instance, neither of the aFunc
implementations has global
scope.
The Scope Resolution Operator
The scope resolution operator (::
) is used to indicate that the
global scope should be searched when a TLC function looks up a variable reference. The
scope resolution operator is often used to change the value of global variables (or even
create global variables) from within functions.
By using the scope resolution operator, you can resolve ambiguities that arise when a
function references identically named local and global variables. In the following
example, a global variable foo
is created. In addition, the function
myfunc
creates and initializes a local variable named
foo
. The function myfunc
explicitly references
the global variable foo
by using the scope resolution operator.
%assign foo = 3 %% this variable has global scope . . . %function myfunc(arg) %assign foo = 3 %% this variable has local scope %assign ::foo = arg %% this changes the global variable foo %endfunction
You can also use the scope resolution operator within a function to create global variables. The following function creates and initializes a global variable:
%function sideffect(arg) %assign ::theglobal = arg %% this creates a global variable %endfunction
How TLC Resolves Variable References
This section discusses how the Target Language Compiler searches the existing scopes to resolve variable references.
Global Scope. In the simplest case, the Target Language Compiler resolves a variable reference by
searching the global pool (including the CompiledModel
structure).
%with Scope. You can modify the search list and search sequence by using the
%with
directive. For example, when you add the following construct,
%with CompiledModel.System[sysidx] ... %endwith
the System[sysidx]
scope is added to the search list. This scope
is searched first, as shown by this picture.
This technique makes it simpler to access embedded definitions. Using the
%with
construct (as in the previous example), you can refer to the
system name simply by
Name
instead of
CompiledModel.System[sysidx].Name
Function Scope. A function has its own scope. That scope is added to the previously described search list, as shown in this diagram.
For example, in the following code fragment,
% with CompiledModel.System[sysidx] ... %assign a=foo(x,y) ... %endwith ... %function foo(a,b) ... assign myvar=Name ... %endfunction ... %<foo(1,2)>
If Name
is not defined in foo
, the assignment
uses the value of Name
from the previous scope,
CompiledModel.System[SysIdx].Name
.
In a nested function, only the innermost function scope is searched, together with
the enclosing %with
and global scopes, as shown in the following
diagram:
File Scope. File scopes are searched before the global scope, as shown in the following diagram.
The rule for nested file scopes is similar to that for nested function scopes. In the case of nested file scopes, only the innermost nested file scope is searched.
Target Language Functions
The target language function construct is
%function identifier ( optional-arguments ) [Output | void] %return %endfunction
Functions in the target language are recursive and have their own local variable space.
Target language functions do not produce output unless they are output functions or
explicitly use the %openfile
, %selectfile
, and
%closefile
directives.
A function optionally returns a value with the %return
directive. The
returned value can be a type defined in the table at Target Language Value Types.
In this example, a function, name
, returns x
if
x
and y
are equal, or returns z
if x
and y
are not equal:
%function name(x,y,z) void %if x == y %return x %else %return z %endif %endfunction
Function calls can appear in contexts where variables are allowed.
The %with
statements that are in effect
when a function is called are available to the function. Calls to other functions do not
include the local scope of the function, but do include %with
statements
appearing within the function.
Assignments to variables within a function create new local variables and cannot change
the value of global variables unless you use the scope resolution operator
(::
).
By default, a function returns a value and does not produce output. You can override this
behavior by specifying the Output
and void
modifiers on the function declaration line, as in
%function foo() Output ... %endfunction
In this case, the function continues to produce output to the currently open file, and
is not required to return a value. You can use the void
modifier to
indicate that the function does not return a value and should not produce output, as
in
%function foo() void ... %endfunction
Variable Scoping Within Functions
Within a function, the left-hand member of an %assign
statement
defaults to creating a local variable. A new entry is created in the function’s block
within the scope chain; it does not affect the other
entries. An example appears in Function Scope.
You can override this default behavior by using %assign
with the
scope resolution operator (::
).
When you introduce new scopes within a function, using %with
, these
new scopes are used during nested function calls, but the local scope for the function is
not searched.
If a %with
is included within a function, its associated scope is
carried with nested function calls, as shown in the next figure.
%return
The %return
statement closes all
%with
statements appearing within the current function. In this
example, the %with
statement is automatically closed when the
%return
statement is encountered, removing the scope from the list of
searched scopes:
%function foo(s) %with s %return(name) %endwith %endfunction
The %return
statement does not require a value. You can use
%return
to return from a function without a return value.