[Edit]
TL;DR: You may consider what constitutes the block statement associated with branching, class definitions, and similar by considering what characters semantically and grammatically bind to what tokens. The `simple_stmt' and `stmt' do not have a rule for a leading ':' character so any sentence beginning with a ':' is invalid. The actual block statement, the alternative to a single `simple_stmt' within the `suite' rule, begins with the `NEWLINE' and `INDENT' rule leaving the ':' character to bind with the other related statements.
[/Edit]
To get technically technical, let's look instead at suite, where blocks are actually defined:
O_o
You've confused yourself by looking at the official grammar because they didn't separate, as I did on your behalf, the statement rule versus block rule.
I'll show you again by making the same split with the copy of the official grammar you posted.
Code:
compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
while_stmt: 'while' test ':' suite ['else' ':' suite]
for_stmt: 'for' exprlist 'in' testlist ':' suite ['else' ':' suite]
try_stmt: ('try' ':' suite
((except_clause ':' suite)+
['else' ':' suite]
['finally' ':' suite] |
'finally' ':' suite))
with_stmt: 'with' with_item (',' with_item)* ':' suite
with_item: test ['as' expr]
except_clause: 'except' [test [('as' | ',') test]]
BLOCK: NEWLINE INDENT stmt+ DEDENT
suite: simple_stmt | BLOCK
The `suite' rule doesn't just represent a block. The `suite' rule represents a statement or a block.
The "or" is the source or your confusion.
Remove the "or" to yeild "suite: BLOCK" and consider the following:
Code:
# The example is invalid.
if True: print("Hello, World!")
# if(true) printf("Hello, World!");
Code:
# The example is valid.
if True:
print("Hello, World!")
# if(true){printf("Hello, World!");}
Remove the "or" to yeild "suite: simple_stmt" and consider the following:
Code:
# The example is valid.
if True: print("Hello, World!")
# if(true) printf("Hello, World!");
Code:
# The example is invalid.
if True:
print("Hello, World!")
# if(true){printf("Hello, World!");}
Once again, the ':' character binds as part of the relevant statement not the block.
If the ':' character did bind as you suggest to the block, you could change the grammar:
Code:
compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated
if_stmt: 'if' test suite ('elif' test suite)* ['else' suite]
while_stmt: 'while' test suite ['else' suite]
for_stmt: 'for' exprlist 'in' testlist suite ['else' suite]
try_stmt: ('try' suite
((except_clause suite)+
['else' suite]
['finally' suite] |
'finally' suite))
with_stmt: 'with' with_item (',' with_item)* suite
with_item: test ['as' expr]
except_clause: 'except' [test [('as' | ',') test]]
suite: simple_stmt | ':' NEWLINE INDENT stmt+ DEDENT
Actually, let's go ahead and do the same split for convenience:
Code:
compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated
if_stmt: 'if' test suite ('elif' test suite)* ['else' suite]
while_stmt: 'while' test suite ['else' suite]
for_stmt: 'for' exprlist 'in' testlist suite ['else' suite]
try_stmt: ('try' suite
((except_clause suite)+
['else' suite]
['finally' suite] |
'finally' suite))
with_stmt: 'with' with_item (',' with_item)* suite
with_item: test ['as' expr]
except_clause: 'except' [test [('as' | ',') test]]
BLOCK: ':' NEWLINE INDENT stmt+ DEDENT
suite: simple_stmt | BLOCK
Remove the "or" from the augmented grammar to yeild "suite: BLOCK" and consider the following:
Code:
# The example is invalid.
if True print("Hello, World!")
# if(true) printf("Hello, World!");
Code:
# The example is valid.
if True:
print("Hello, World!")
# if(true){printf("Hello, World!");}
Remove the "or" from the augmented grammar to yeild "suite: simple_stmt" and consider the following:
Code:
# The example is valid.
if True print("Hello, World!")
# if(true) printf("Hello, World!");
Code:
# The example is invalid.
if True:
print("Hello, World!")
# if(true){printf("Hello, World!");}
You may not be able to see it with the examples I've shown, but we have introduced a semantic ambiguity.
Let's consider a non-literal condition with the augmented grammar to illustrate an instance of the ambiguity:
Code:
if var1 - DoSomething() + var2 and print("Hello, World!")
These example are both valid code from among the possible interpretations:
Code:
if var1: -DoSomething() + var2 and print("Hello, World!")
Code:
if var1 - DoSomething(): +var2 and print("Hello, World!")
Along with funcdef and classdef, all suite is preceded by the : delimiter.
Try looking at the examples in terms of finding what is missing:
Code:
if var == 5
print("Hello, World!")
Code:
if (var == 5
{
print("Hello, World!")
}
In both cases, the block--the `suite' rule--itself is a valid sentence.
Soma