SCL Control Structures


This document describes control structures in the shape edit command language (SCL), including loops, conditionals and procedures, and related subjects such as labels for dependency graph nodes, label scope, and modification operations.

 Many of the extensions require that SCL be run in its lazy evaluation mode. To do this execute the following line:

        set demand_eval true;


Table of Contents


Notation

Elements of the SCL grammar are used below and are signified by enclosure in single angle brackets (e.g., ''<expr>'' for an expression). The following standard elements are defined in the SCL grammar:

 

    <expr>
    <statement>
    <val_stmt>
    <control_stmt>
    <true>
    <false>
<expr_stmt> is used below to indicate:
         <expr>;


i.e., an expression followed by a semi-colon.
Other grammar meta-notation is used below for convenience and defined where it is used.

 

Labels

The label operator '':'' is used to establish a label for a node of a dependency graph. The label then may be used to stand for the value of the node and may be referenced in SCL statements where that value is appropriate.

 A label identifier followed by '':'' may appear at the start of any <val_stmt> (i.e., either a <expr_stmt> or <control_stmt>). In this case we refer to the label as being on the statement and the label as being defined by the colon syntax. Note that <expr_stmt> and <control_stmt> both return values.

 Here's an example:

    Axis : arcEndCenterEnd( pt(0,1),
                            Origin,
                            pt(1,0) );

    SrfA : circTubeConstantWidth( Axis, .2 );


The above statements define the labels ''Axis'' and
''SrfA''.  The label ''Origin'' is predefined.
Labels are also used by loop constructs and procedure definitions.

 For example, the loop construct:

    forCollect ( I; 1; I < 10; I + 1 )
        my_proc( I, 3, 4 );


uses ''I'' as the label for its induction (index) variable, whereas
the procedure definition:
    procedure my_proc( A, B, C )
        C * (A+B);


uses ''A'', ''B'', and ''C'' as the labels
of its formal arguments. 

Note that '':''s are not used in the declaration of the label
for the induction variable of a loop or the declaration of the labels
for the formal arguments of a procedure.
Labels have scopes. Once a label is defined in a particular scope, it may be used in subsequent expressions in that scope to stand for the value associated with the labeled statement, index variable, or formal argument. Sequences, loops, and procedure definitions are currently the only SCL statements that define scopes. If an SCL statement is outside the scope of any sequence, loop, or procedure definition, then we say that the statement is at the top level scope.

 

Label Scope

The scope of a label is that part of the model over which the label is defined. The scope of a label defined at the top level starts on the statement following the labeled statement and persists as long as the model is extent.

 The following statements establish inner scopes for labels: sequences, loops (the induction variable), and procedure definitions (the formal arguments).

 The scope of a label on a statement in a sequence of statements starts at the statement after the labeled statement, and extends to the last statement in the sequence.

 A ''for'' or ''forCollect'' statement establishes a scope for its index label. The scope extends to the test and update expressions, but not to the initialization expression. The scope of the index label extends also to the statement comprising the body of the ''for'' or ''forCollect''.

 The formal arguments of a procedure definition establish labels whose scope is the statement that comprises the procedure body.

 

Scope Rules:

Sequences

Sequences are compound statements. The sequence statements are:
    seq { <val_stmt> <val_stmt> <val_stmt> ... }

    seqCollect { <val_stmt> <val_stmt> <val_stmt> ... }


In both cases, the <val_stmt>s within the sequence are
evaluated and propagated in the order given.  The value of
''seq'' is the value of the last statement in the statement
list.  The value of ''seqCollect'' is a group consisting of
the values of each statement in order.
The ''seq'' statement can be written using curly braces alone, that is:
    { <val_stmt> <val_stmt> <val_stmt> ... }


Example:
    Prof1 :
    {
        Pt1    : ptIntersect2Lines( LeftTanLine, LLine );
        Pt2    : ptIntersect2Lines( LLine, BLine );
        Pt3    : ptIntersect2Lines( BLine, RLine );
        Pt4    : ptIntersect2Lines( RLine, RightTanLine );
        profile( Pt1, Pt2, Pt3, Pt4 );
    }


Typical uses of ''{'' and ''}'' are for specifying
the bodies of procedures, loops, and conditional clauses.
To use sequences you must first execute the line:
        set demand_eval true;



Conditionals

Conditional expressions imply conditional execution of statements. The format is:
    if ( <expr> ) <val_stmt> else <val_stmt>


If the test expression <expr> evaluates to
<true>, or is non-zero, then the first statement is
executed.  Otherwise the second statement is executed.  The value of
the ''if'' is the value of whichever statement is
executed.
Example:
    if ( Val > 0.4 ) 1.0;
    else
    {
        if ( Val > -1.8 ) TaperVal;
        else 1.0;
    }


Note that an ''if'' clause not followed by an
''else'' clause is currently invalid (and flagged as a syntax
error).  The reason for this is that the underlying functional model
of the dependency graph requires a conditional node to produce a value
(whether the test is true or not).
To use conditionals you must first execute the line:
        set demand_eval true;



Loops

Currently there are two forms of loops:
    for ( <label>; <init>; <test>; <update> ) <val_stmt>

    forCollect ( <label>; <init>; <test>; <update> ) <val_stmt>


<label> constitutes a definition of a label for a
model_obj containing a number (float or integer) which is local to the
loop evaluation (note that no colon is necessary in this definition).
This label will be used as the index variable of the loop and will
not be available for reference outside of the loop.  The label
scope is that of the <test> and <update>
expressions, as well as the <val_stmt> body.  The
<label> is undefined in the <init>
expression.
<init> is an <expr> which must evaluate to a number (float or integer). This value will be used to initialize the value of the <label> index object. Note: <init> may not reference <label>.

 <test> is an <expr> that gives termination criteria for the loop. The''for'' or ''forCollect'' will continue to loop as long as <test> evaluates to <true> or is non-zero. Typically, <test> is some relational expression that involves <label>.

 <update> is an <expr> which must evaluate to a number (float or integer). This value will be used to update the value of <label> after each iteration. The expression will typically reference <label>.

 The value of a ''for'' loop is the value of it's <val_stmt> the last time it was executed.

 The value of a''forCollect'' loop is a group consisting of the values returned by the <val_stmt> body each time it was executed (in the order of execution).

 Here's an example:

    FirstGroove : ...;
    GrooveList : forCollect( I; 1; I <= NumGrooves; I + 1 )
        objtransform( FirstGroove, tx( I * OffWidth ) );


Note that loops can nest and the index <label> of the
outer loop may be used by the inner loop:
    forCollect ( I; 0; I < N; I+1 )
        forCollect ( J; 0; J < I; J+1 )
            <val_stmt>


Note: A ''for'' loop is meaningful only if it:
a) is within the scope of a ''startWith'' statement and,
b) has modification statements within the scope of its body.
Otherwise there is no way to export the value or effect of inner
iterations of a ''for'' loop's statement body.  (This is
because side-effect functions are not well integrated into the
dependency graph and modification operators in c_shape_edit currently
can only be used within the scope of a ''startWith''
statement.)
To use loops you must first execute the line:
        set demand_eval true;



Procedures

A user defined procedure is defined as follows:
    procedure <identifier>( <label>, <label>, ... ) <val_stmt>


Where <identifier> is the name of the procedure and the
<label>s are the names of the formal arguments to the
procedure (note that no colons are used in declaring the names of the
formal arguments).
To call a user defined procedure, use the same syntax as any procedure (i.e. constructor) call:
        <identifier>( <arg>, <arg>, ... );


The value of the procedure call is the value of
<val_stmt>, the procedure body, evaluated with the
actual arguments bound to the formal arguments of the procedure.  The
scope of the formal arguments is the statement body.
Note: The current implementation does not support recursive use of user defined procedures.

 To use user defined procedures you must first execute the line:

        set demand_eval true;



Modification Operations

Typically, a series of modifications to an object is created by a sequence of statements that each reconstructs the object with incremental changes. This can be very inefficient.

 The ''startWith'' statement is used to help alleviate this problem, while stopping short of implementing full fledged modification operations in SCL (which is difficult because of the functional nature of the language model). The format of the statement is as follows:

 

        startWith ( <expr> ) <val_stmt>


A ''startWith'' statement first copies its
<expr> and then applies all the modifications in
its <val_stmt> body to the copy.  The value of the
''startWith'' statement is the modified copy of
<expr>.
A modification statement is a special form of <val_stmt> that is valid only withing the scope of a ''startWith''. Modification statements have a rather bizarre syntax:
        <access_list> = <val_stmt>


Note that a typical access expression has the syntax:
        <object> <access_list>


So modification expressions are not preceded by an object
designation (see  Accessors  for more
details about access expressions.)
An example will probably make all this somewhat more clear. Here's one from $scle/propeller.scl:
    RIdx : numRows( BladeSrf.ctlMesh ) - 1;

    # Modify some of the control points of Edge1.
    NewEdge1 : startWith( Edge1 )
    for ( I; 0; I <= 2; I+1 )
    {
        .ctlMesh[I][RIdx] =
            linProjInterp( Edge3.ctlMesh[I][0],
                           Edge1.ctlMesh[I][RIdx-1],
                           Edge3.ctlMesh[I][1] );
    }


In the example above  ''.ctlmesh[I][RIdx] = ...'' is a
modification of a point in the control mesh of the copied
version of Edge1.  Outside the scope of the
''startWith'' the copy can be referenced as NewEdge1
Note: the reason why the object designation is left off in the syntax of modification statements, is to dissallow references to the object being modified while it is being modified. Allowing such references would lead to general modification operations; something we're trying to avoid in SCL. 

Miscellaneous

Statement Block

Statements can be grouped by using ''<<'' and ''>>'', the result is a compound statement block:
    << <statement> <statement> <statement> ... >>


The value of the block is the value of the last statement in the
statement list.  The semantics of sequence
are not implied and no label scope is
created by these blocks.

Statement blocks can be used only at the top level and following the
''commentOutCode'' keyword at any other level.

CommentOutCode

A statement can be ''commented out'' by proceeding it with the keyword ''commentOutCode'':
    commentOutCode <statement>


A typical use of this mechanism is to comment out formal variable
assignments at the beginning of a user defined procedure definition.
This is handy for debugging the procedure, by first setting up an
environment where the formal arguments are defined, and then executing
the procedure definition one line at a time from within an editor.
Here's an example:
    ##########################################################
    # fooProc - Takes 3 arguments and does something with them.
    #
    procedure fooProc( Test1, Test2, A, B )
    {
        commentOutCode
        <<
            # Try it out with some arguments.
            Test1 : 1;
            Test2 : 2;
            A : 3.14159;
            B : 2.71828;
        >>

        if ( Test1 < Test2 )
            A * B;
        else
            A - B;
    }


Set Statement

The set statement allows controlling modes of the shape_edit interpreter.

Turning off the Parser Echo

The parser will echo the value of a statement by default. This behavior can be quite annoying if the statement creates a sizable object (like a surface or a shell). The parser echo can be turned off by executing the following line:

 

    set parse_echo false;


The parser echo can be turned back on by:
    set parse_echo true;


Alternatively, the parser echo can be turned off for a single line by
terminating that line with ''$;''.

Evaluation Mode

Two modes of dependency propagation are implemented: "enthusiastic" evaluation, currently the default, where a change to one model graph node causes the constructors of everything downstream to be refired once in order; and "lazy" (on-demand) evaluation, where everything downstream from a change is marked out-of-date, but no constructor firing is done until values are required. As stated above, most control structures require you to you first execute the line:
        set demand_eval true;

Change Propagation

If you want to temporarily disable change propagation entirely, use:
        set propagate_changes false;

and then to re-enable change propagation,
        set propagate_changes true;


To monitor the changes being made,
        set trace_changes true;

Command Timing

If you want to time the evaluation of commands, use:
        set time_command true;


Upon completion of each command, it prints the total elapsed time, the
time spent in the system, and the time spent executing the command.
Times are reported in seconds.

C_Shape_Edit User's Manual Home Page 
Alpha_1 User's Manual.
Copyright © 1998, University of Utah
a1-web@gr.cs.utah.edu