File: statements.adoc

package info (click to toggle)
nickle 2.107
  • links: PTS
  • area: main
  • in suites: forky, sid
  • size: 3,756 kB
  • sloc: ansic: 27,954; yacc: 1,874; lex: 954; sh: 204; makefile: 13; lisp: 1
file content (239 lines) | stat: -rw-r--r-- 6,705 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
= Statements in Nickle

== Simple statements

_expr_ `;` +
`;` `/* null statement */` +
`{` _statement_ ... `}`

The simplest statement is merely an expression terminated by a semicolon; the expression is evaluated.
A semicolon by itself is allowed but does nothing.
One or more statements may be grouped inside curly braces to form one compound statement; each is executed in order.
Any statements may compose the statement list, including control statements and other curly-bracketed lists. 

== Conditionals

`if (` _expr_ `)` _statement_
`else` _statement_

`if` is used to execute a section of code only under some condition:
If `expr` is true, `statement` is executed; otherwise control skips
over it.  For example:

----
if ( x == 0 )
        printf ( "x is zero.\n" );
----

In this case, the message will be printed only if `x` is zero. 

`else` allows for a choice if the condition fails.  It executes its
`statement` if the most recent `if` or `twixt` (see below) did not.
For example,

----
if ( x == 0 )
        printf ( "x is zero.\n" );
else
        printf ( "x is not zero.\n" );
----

More than one option may be presented by nesting further 'if's in
'else' statements like this:

----
if ( x == 0 )
        printf ( "x is zero.\n" );
else if ( x  0 )
        printf ( "x is negative.\n" );
else
        printf ( "x is positive.\n" );
----

== Twixt

`twixt (` _expr_ `;` _expr_ `)` _statement_

Ensures that the the first `expr` will always have been evaluated
whenever control flow passes into any part of `statement` and ensures
that the second `expr` will be evaluated anytime control flow passes
out of `statement`. _That order is guaranteed_.  If a `long_jmp`
target is inside `statement`, the first `expr` will be executed before
control passes to the target.  If `statement` throws an exception or
`long_jmp`s out of the `twixt`, the second `expr` will be evaluated.
Thus, `twixt` is useful in locked operations where the statement
should only be executed under a lock and that lock must be released
afterwards.

----
twixt ( get_lock ( ); release_lock ( ) )
        locked_operation ( );
----

== Switch

`switch (` _expr_ `) { case` _expr_ `:` _statement-list_ ... `default:` _statement-list_ `}`

Control jumps to the first `case` whose `expr` evaluates to the same
value as the `expr` at the top.  Unlike in C, these values do not have
to be integers, or even constant.  The optional case `default` matches
any value.  If nothing is matched and there is no `default`, control
skips the `switch` entirely.  This example prints out a number to the
screen, replacing it by a letter as though it were a poker card:

----
switch ( x ) {
        case 1:
                printf ( "A\n" );       /* ace */
                break;
        case 11:
                printf ( "J\n" );       /* jack */
                break;
        case 12:
                printf ( "Q\n" );       /* queen */
                break;
        case 13:
                printf ( "K\n" );       /* king */
                break;
        default:
                printf ( "%d\n", x );   /* numeric */
                break;
}
----

Notice the `break`s in the example.  Once control jumps to the
matching case, it continues normally: Upon exhausting that
`statement-list`, _it does not jump out of the `_switch_`_; it
continues through the subsequent statement lists.  Here is an example
of this 'falling through':

----
int x = 3;

switch ( sign ( x ) ) {
        case -1:
                printf ( "x is negative.\n" );
        case 1:
                printf ( "x is positive.\n" );
        default:
                printf ( "x is zero.\n" );
}
----

This prints: 

----
x is positive.
x is zero.
----

Falling through may be desirable if several cases are treated
similarly; however, it should be used sparingly and probably commented
so it is clear you are doing it on purpose.  This is a difficult error
to catch.

== Union switch
`union switch (` _union_ `) { case` _name_ `:` _statement-list_ ... `default:` _statement-list_ `}`

`union switch` is similar to `switch`.  It matches the `case` based on
what name currently applies to the union's value.  As always,
`default` matches everything.  The following example chooses the best
way to print the union:

----
union {
        int a;
        string b;
} u;

u.b = "hello";

union switch ( u ) {
        case a:
                printf ( "%d\n", u.a );
                break;
        case b:
                printf ( "%s\n", u.b );
                break;
}
----

In this case, it prints 'hello'. 

An additional name may follow that of a case; the union's value will be available inside the case by that name.
The switch above could have been written: 

----
union switch ( u ) {
        case a num:
                printf ( "%d\n", num );
                break;
        case b str:
                printf ( "%s\n", str );
                break;
}
----

== Loops

`while (` _expr_ `)` _statement_ +
`do` _statement_ `while (` _expr_ `)` +
`for (` _expr_ `;` _expr_ `;` _expr_ `)` _statement_

`while` executes `statement` repeatedly as long as `expr` is true.
Control continues outside the loop when `expression` becomes false.
For example: 

----
int x = 0;
while ( x  10 ) {
        printf ( "%d\n", x );
        ++x;
}
----

This prints the numbers from zero to nine. 

`do-while` is like `while`, but tests the condition after each iteration rather than before.
Thus, it is garaunteed to execute at least once.
It is often used in input while testing for end-of-file: 

----
file f = File::open ( "test", "r" );

do {
        printf ( "%s\n", File::fgets ( f ) );
} while ( ! end ( f ) );

close ( f );
----

`for` begins by evaluating the first `expr`, which often initializes a
counter variable; since declarations are expressions in Nickle, they
may be used here and the counter will be local to the loop.  Then it
executes `statement` as long as the second `expr` is true, like
`while`.  After each iteration, the third `expr` is evaluated, which
usually increments or decrements the counter variable.  The `while`
example above can also be written as the following `for` loop:

----
for ( int x = 0; x  10; ++x )
        printf ( "%d\n", x );
----

== Flow control

`continue` +
`break` +
`return` _expr_

`continue` restarts the nearest surrounding `do-while`, `while`, or
`for` loop by jumping directly to the conditional test.  The iterative
statement of a `for` loop will be evaluated first.

`break` leaves the nearest surrounding `do-while`, `while`, `for`, or
`switch` statement by jumping to its end.  The iterative statement of
a `for` loop will not be evaluated.

`return` returns from the nearest surrounding function with value
`expr`.