PYT - The expressions described in the Python language reference yield only boolean values

Peter J. Holzer hjp-python at hjp.at
Sat Feb 26 09:42:16 EST 2022


On 2022-02-19 23:28:28 +0100, vanyp wrote:
> *I am trying to learn Python from the grammar given in the Python language
> reference and I am surprised.*
> 
> *Lets start here:*
> 
> *"*
> *6.3.4. Calls*
> 
> A call calls a callable object (e.g., a function
> <https://docs.python.org/3/glossary.html#term-function>) with a possibly
> empty series of arguments
> <https://docs.python.org/3/glossary.html#term-argument>:
> 
> *call *::= |primary <https://docs.python.org/3/reference/expressions.html#grammar-token-python-grammar-primary>|"("
> [|argument_list <https://docs.python.org/3/reference/expressions.html#grammar-token-python-grammar-argument_list>|[","]
> | |comprehension <https://docs.python.org/3/reference/expressions.html#grammar-token-python-grammar-comprehension>|]

With all those links this is very hard to read. Please try to format
your mails in a way that makes them easy to follow.

[...][

> *The first or_test is strange, I assume it should be replaced by expression.*

Nope.

> *But even so I think that the only ways out of the recursion are the or_test
> or the lambda_expr.*
> 
> *And by the grammar, those evaluate to booleans as follows:*

No. A grammar specifies how to parse the text, it doesn't say anything
about the types of these expressions (especially not in a dynamically
typed language like python). 

> *Where did I, or the language reference, go wrong?*

First, you neglected the difference between parsing an expression and
evaluating it.

Secondly, you didn't see the way out. 

For example, let's parse the expression

«f(1+2, 3)»

Can this be a call?

To confirm this, is has to match 

    call                 ::=  primary "(" [argument_list [","] | comprehension] ")"

which looks plausible, so let's dive in:

    primary ::=  atom | attributeref | subscription | slicing | call

    atom      ::=  identifier | literal | enclosure

    identifier   ::=  xid_start xid_continue*

«f» is an identier which is an atom which is a primary.

Good so far. Now for the argument-list:

    argument_list        ::=  positional_arguments ["," starred_and_keywords] ...

    positional_arguments ::=  positional_item ("," positional_item)*

We have two comma-separated items, good so far. Check «1+2» first

    positional_item      ::=  assignment_expression | "*" expression

    assignment_expression ::=  [identifier ":="] expression

    expression             ::=  conditional_expression | lambda_expr

    conditional_expression ::=  or_test ["if" or_test "else" expression]

    or_test  ::=  and_test | or_test "or" and_test

    and_test ::=  not_test | and_test "and" not_test

    not_test ::=  comparison | "not" not_test

    comparison    ::=  or_expr (comp_operator or_expr)*

    or_expr  ::=  xor_expr | or_expr "|" xor_expr

    xor_expr ::=  and_expr | xor_expr "^" and_expr

    and_expr ::=  shift_expr | and_expr "&" shift_expr

    shift_expr ::=  a_expr | shift_expr ("<<" | ">>") a_expr

    a_expr ::=  m_expr | a_expr "+" m_expr | a_expr "-" m_expr

Oof. That was a deep recursion, but we finally found a «+». 
So 1 must be an a_expr and 2 an m_expr. Actually recursing once more reveals
that both can be m_expr:

    m_expr ::=  u_expr | m_expr "*" u_expr | m_expr "@" m_expr | ...

    u_expr ::=  power | "-" u_expr | "+" u_expr | "~" u_expr

    power ::=  (await_expr | primary) ["**" u_expr]

    primary ::=  atom | attributeref | subscription | slicing | call

    atom      ::=  identifier | literal | enclosure

    literal ::=  stringliteral | bytesliteral | integer | floatnumber | imagnumber

Ok, they are both integer. 

Then we do basically the same for the second argument and we arrive at
the parse tree:

[warning: fixed width font required]

                                    call
                                      |
   -----------------------------------+--------------------------
  /        /                          |                           \
  |        |                    argument_list                      |
  |        |                    positional_arguments               |
  |        |                   /          |         \              |
  |        |       positional_item        | positional_item        |
  |        |       assignment_expression  | assignment_expression  |
  |        |       expression             | expression             |
  |        |       conditional_expression | conditional_expression |
  |        |       or_test                | or_test                |
  |        |       and_test               | and_test               |
  |        |       not_test               | not_test               |
  |        |       comparison             | comparison             |
  |        |       or_expr                | or_expr                |
  |        |       xor_expr               | xor_expr               |
  |        |       and_expr               | and_expr               |
  |        |       shift_expr             | shift_expr             |
  |        |       a_expr                 | a_expr                 |
  |        |      /  |   \                |                        |
  |        | m_expr  | m_expr             | m_expr                 |
  |        | u_expr  | u_expr             | u_expr                 |
  |        | power   | power              | power                  |
  |        | primary | primary            | primary                |
primary    | atom    | atom               | atom                   |
atom       | literal | literal            | literal                |
identifier | integer | integer            | integer                |
f          ( 1       + 2                  , 3                      )

(Of course, most real parsers start at the bottom and build up, but I
think for humans the top-down approach is more convenient.)
        hp


-- 
   _  | Peter J. Holzer    | Story must make more sense than reality.
|_|_) |                    |
| |   | hjp at hjp.at         |    -- Charles Stross, "Creative writing
__/   | http://www.hjp.at/ |       challenge!"
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <https://mail.python.org/pipermail/python-list/attachments/20220226/139577ef/attachment.sig>


More information about the Python-list mailing list