Statement: LabeledStatement BlockStatement ExpressionStatement DeclarationStatement IfStatement DebugStatement VersionStatement WhileStatement DoWhileStatement ForStatement SwitchStatement CaseStatement DefaultStatement ContinueStatement BreakStatement ReturnStatement GotoStatement WithStatement SynchronizeStatement TryStatement ThrowStatement VolatileStatement AsmStatement
LabelledStatement: Identifier ':' StatementAny statement can be labelled, including empty statements, and so can serve as the target of a goto statement. Labelled statements can also serve as the target of a break or continue statement.
Labels are in a name space independent of declarations, variables, types, etc. Even so, labels cannot have the same name as local declarations. The label name space is the body of the function they appear in. Label name spaces do not nest, i.e. a label inside a block statement is accessible from outside that block.
BlockStatement: { } { StatementList } StatementList: Statement Statement StatementListA block statement introduces a new scope for local symbols. A local symbol's name, however, must be unique within the function.
void func1(int x) { int x; // illegal, x is multiply defined in function scope } void func2() { int x; { int x; // illegal, x is multiply defined in function scope } } void func3() { { int x; } { int x; // illegal, x is multiply defined in function scope } } void func4() { { int x; } { x++; // illegal, x is undefined } }The idea is to avoid bugs in complex functions caused by scoped declarations inadvertantly hiding previous ones. Local names should all be unique within a function.
ExpressionStatement: Expression ;Expressions that have no affect, like (x + x), are illegal in expression statements.
DeclarationStatement: Type IdentifierList ; IdentifierList: Variable Variable , IdentifierList Variable: Identifier Identifier = AssignmentExpressionIf no AssignmentExpression is there to initialize the variable, it is initialized to the default value for its type.
IfStatement: if ( Expression ) Statement if ( Expression ) Statement else StatementExpression is evaluated and must have a type that can be converted to a boolean. If it's true the if statement is transferred to, else the else statement is transferred to.
The 'dangling else' parsing problem is solved by associating the else with the nearest if statement.
WhileStatement: while ( Expression ) StatementExpression is evaluated and must have a type that can be converted to a boolean. If it's true the statement is executed. After the statement is executed, the Expression is evaluated again, and if true the statement is executed again. This continues until the Expression evaluates to false.
A break statement will exit the loop. A continue statement will transfer directly to evaluationg Expression again.
DoStatement: do Statement while ( Expression )Statement is executed. Then Expression is evaluated and must have a type that can be converted to a boolean. If it's true the loop is iterated again. This continues until the Expression evaluates to false.
A break statement will exit the loop. A continue statement will transfer directly to evaluationg Expression again.
ForStatement: for (Initialize; Test; Increment) Statement Initialize: empty Expression Declaration Test: empty Expression Increment: empty ExpressionInitializer is executed. Test is evaluated and must have a type that can be converted to a boolean. If it's true the statement is executed. After the statement is executed, the Increment is executed. Then Test is evaluated again, and if true the statement is executed again. This continues until the Test evaluates to false.
A break statement will exit the loop. A continue statement will transfer directly to the Increment.
If Initializer declares a variable, that variable's scope extends through the end of Statement. For example:
for (int i = 0; i < 10; i++) foo(i);is equivalent to:
{ int i; for (i = 0; i < 10; i++) foo(i); }Function bodies cannot be empty:
for (int i = 0; i < 10; i++) ; // illegalUse instead:
for (int i = 0; i < 10; i++) { }The Initializer may be omitted. Test may also be omitted, and if so, it is treated as if it evaluated to true.
SwitchStatement: switch ( Expression ) BlockStatement CaseStatement: case Expression : Statement DefaultStatement: default: StatementExpression is evaluated. The result type T must be of integral type or char[] or wchar[]. The result is compared against each of the case expressions. If there is a match, the corresponding case statement is transferred to.
If none of the case expressions match, and there is a default statement, the default statement is transferred to.
If none of the case expressions match, and there is not a default statement, a SwitchException is thrown. The reason for this is to catch the common programming error of adding a new value to an enum, but failing to account for the extra value in switch statements.
The case expressions must all evaluate to a constant value or array, and be implicitly convertible to the type T of the switch Expression.
Case expressions must all evaluate to distinct values. There may not be two or more default statements.
Case statements and default statements associated with the switch can be nested within block statements; they do not have to be in the outermost block. For example, this is allowed:
switch (i) { case 1: { case 2: } break; }Like in C and C++, case statements 'fall through' to subsequent case values. A break statement will exit the switch BlockStatement. For example:
switch (i) { case 1: x = 3; case 2: x = 4; break; case 3: x = 5; break; }will set x to 4 if i is 1.
Note: Unlike C and C++, strings can be used in switch expressions. For example:
char[] name; ... switch (name) { case "fred": case "sally": ... }For applications like command line switch processing, this can lead to much more straightforward code, being clearer and less error prone. Both ascii and wchar strings are allowed.
Implementation Note: The compiler's code generator may assume that the case statements are sorted by frequency of use, with the most frequent appearing first and the least frequent last. Although this is irrelevant as far as program correctness is concerned, it is of performance interest.
ContinueStatement: continue; continue Identifier ;continue executes the next iteration of its innermost enclosing while, for, or do loop. The increment clause is executed.
If continue is followed by Identifier, the Identifier must be the label of an enclosing while, for, or do loop, and the next iteration of that loop is executed. It is an error if there is no such statement.
Any intervening finally clauses are executed, and any intervening synchronization objects are released.
Note: If a finally clause executes a return, throw, or goto out of the finally clause, the continue target is never reached.
BreakStatement: break; break Identifier ;break exits the innermost enclosing while, for, do, or switch statement, resuming execution at the statement following it.
If break is followed by Identifier, the Identifier must be the label of an enclosing while, for, do or switch statement, and that statement is exited. It is an error if there is no such statement.
Any intervening finally clauses are executed, and any intervening synchronization objects are released.
Note: If a finally clause executes a return, throw, or goto out of the finally clause, the break target is never reached.
ReturnStatement: return; return Expression ;Expression is required if the function specifies a return type that is not void. The Expression is implicitly converted to the function return type.
At least one return statement is required if the function specifies a return type that is not void.
Expression is illegal if the function specifies a void return type.
Before the function actually returns, any enclosing finally clauses are executed, and any enclosing synchronization objects are released.
The function will not return if any enclosing finally clause does a return, goto or throw that exits the finally clause.
If there is an out postcondition (see design by contract), that postcondition is executed after the Expression is evaluated and before the function actually returns.
GotoStatement: goto Identifier ;Any intervening finally clauses are executed, along with releasing any intervening synchronization mutexes.
It is illegal for a goto to be used to skip initializations.
WithStatement: with ( Expression ) BlockStatement with ( TemplateInstance ) BlockStatementwhere Expression evaluates to an Object reference. Within the with body the referenced Object is searched first for identifier symbols. The with statement
with (expression) { ... ident; }is semantically equivalent to:
{ Object tmp; tmp = expression; ... tmp.ident; }Note that expression only gets evaluated once. The with statement does not change what this or super refer to.
SynchronizeStatement: synchronized Statement synchronized ( Expression ) Statementsynchronized allows only one thread at a time to execute Statement.
synchronized (Expression), where Expression evaluates to an Object reference, allows only one thread at a time to use that Object to execute the Statement.
The synchronization gets released even if Statement terminates with an exception, goto, or return.
Example:
synchronized { ... }This implements a standard critical section.
TryStatement: try BlockStatement Catches try BlockStatement Catches finally BlockStatement try BlockStatement finally BlockStatement Catches: LastCatch Catch Catch Catches LastCatch: catch BlockStatement Catch: catch ( Parameter ) BlockStatementParameter declares a variable v of type T, where T is Object or derived from Object. v is initialized by the throw expression if T is of the same type or a base class of the throw expression. The catch clause will be executed if the exception object is of type T or derived from T.
If just type T is given and no variable v, then the catch clause is still executed.
It is an error if any Catch Parameter type T1 hides a subsequent Catch with type T2, i.e. it is an error if T1 is the same type as or a base class of T2.
LastCatch catches all exceptions.
ThrowStatement: throw Expression ;Expression is evaluated and must be an Object reference. The Object reference is thrown as an exception.
VolatileStatement: volatile StatementStatement is evaluated, and no common subexpressions or memory references cached in registers are propagated either into it or out of it. This is useful for accessing memory that can change asynchronously, such as memory mapped I/O or memory accessed by multiple threads.
A volatile statement does not guarantee atomicity. For that, use synchronized statements.
AsmStatement: asm { } asm { AsmInstructionList } AsmInstructionList: AsmInstruction ; AsmInstruction ; AsmInstructionListAn asm statement enables the direct use of assembly language instructions. This makes it easy to obtain direct access to special CPU features without resorting to an external assembler. The D compiler will take care of the function calling conventions, stack setup, etc.
The format of the instructions is, of course, highly dependent on the native instruction set of the target CPU, and so is implementation defined. But, the format will follow the following conventions:
For example, for the Intel Pentium:
int x = 3; asm { mov EAX,x; // load x and put it in register EAX }Inline assembler can be used to access hardware directly:
int gethardware() { asm { mov EAX, dword ptr 0x1234; } }For some D implementations, such as a translator from D to C, an inline assembler makes no sense, and need not be implemented. The version statement can be used to account for this:
version (InlineAsm) { asm { ... } } else { ... some workaround ... }