This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Title: The grammar specification is inconsistent with the implementation of Python parser.
Type: compile error Stage: resolved
Components: Documentation Versions: Python 3.6
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: docs@python Nosy List: docs@python, georg.brandl, rhettinger, xxm
Priority: normal Keywords:

Created on 2020-11-07 11:03 by xxm, last changed 2022-04-11 14:59 by admin. This issue is now closed.

Messages (3)
msg380502 - (view) Author: Xinmeng Xia (xxm) Date: 2020-11-07 11:03
In full grammar specification of Python 3.6 official documentation (Python 3.6 official documentation: ), we can find a very clear definition on the grammar about the usage of 'break'. According to the definition, we can find the following derivation, which indicates the keyword 'break' can appear in the block of if statement without being nested into a loop block:

# Start symbols for the grammar:
#       single_input is a single interactive statement;

single_input: NEWLINE | simple_stmt | compound_stmt NEWLINE

compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | with_stmt | funcdef | classdef | decorated | async_stmt

if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]

suite: simple_stmt | NEWLINE INDENT stmt+ DEDENT

simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE

small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | nonlocal_stmt | assert_stmt)

flow_stmt: break_stmt | continue_stmt | return_stmt | raise_stmt | yield_stmt

break_stmt: 'break'

However, the implementation of the Python parser requires the 'break' can only be embedded into a loop statement.
See the following example:

Example A(without loop):
>>> compile("if True:break",'','exec')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "", line 1
SyntaxError: 'break' outside loop

Example B(with a loop):
>>> compile("while True:\n\tif True:break",'','exec')
<code object <module> at 0x7f5f4de90b70, file "", line 1>

Similar problems exist between if-statement and keywords: 'continue', 'yield', 'return', 'nonlocal' in Python 3.6 and later versions.
msg380504 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2020-11-07 11:34
This grammar specification doesn't contain a full specification of code that won't raise SyntaxError. There are several conditions that aren't checked by the generated parser, but at a later stage in the compilation process.

While probably possible to express in general, this would make the grammar much more complex.  For this example, it would require different definitions of `suite`, `stmt`, `simple_stmt`, `compound_stmt` and so on, to track where control-flow statements are allowed.  Other definitions need to track `nonlocal` and you'd get a combinatorial explosion of productions.

You could propose a PR to add a note somewhere on that page (but on the master branch, not 3.6 which is unmaintained).
msg380522 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2020-11-07 20:08
I concur with Georg.   

In writing compilers, it is often convenient to allow the grammar to be permissive and save the enforcement of additional syntax restrictions for the downstream semantic analysis phase.

For example, the C language grammar specifies the "break" statement in much the same way as Python does:

Thank you for the suggestion, but I'm going to mark this as declined.
Date User Action Args
2022-04-11 14:59:37adminsetgithub: 86450
2020-11-07 20:08:59rhettingersetstatus: open -> closed

nosy: + rhettinger
messages: + msg380522

resolution: not a bug
stage: resolved
2020-11-07 11:34:41georg.brandlsetnosy: + georg.brandl
messages: + msg380504
2020-11-07 11:03:31xxmcreate