Language Change Specification for Precedence of Unary Operators

LCS Number: LCS-2016-13
Version: 5
Date: v4 8-Feb-2017 v5 2-Mar-2017
Status:  
Author: Peter Flake
Email:  
Source Doc: Unary Precedence
Summary: Remove ambiguity of precedence of unary operators in formal syntax

Voting Results: Cast your votes here

* Yes:

  1. Peter Flake - 2016-12-20
  2. Jim Lewis - 2017-02-07 ver 3
  3. Brent Hayhoe - 2017-02-02
  4. Lieven Lemiengre - 2017-02-02
  5. Rob Gaddi - 2017-03-02 ver 5
  6. Thomas Preusser - 2017-02-08 - ver 3
  7. Patrick Lehmann - 2017-03-02 ver 5

* No:

* Abstain:

Details of Language Change:

Key:

  • Existing LRM text is shown in BLACK font
  • Additional LRM text is shown in RED
  • Deleted LRM text is shown in RED with strike-through

LRM 9 Expressions

page 117

9.1 General

An expression is a formula that defines the computation of a value.

expression ::=
   condition_operator primary
   | logical_expression 
logical_expression ::=
   relation { and relation }
   | relation { or relation }
   | relation { xor relation }
   | relation [ nand relation ]
   | relation [ nor relation ]
   | relation { xnor relation } 
relation ::=
   shift_expression [ relational_operator shift_expression ]
   shift_expression ::=
   simple_expression [ shift_operator simple_expression ] 
simple_expression ::=
   [ sign ] term { adding_operator term } 
term ::=
   factor { multiplying_operator factor } 
 
factor ::=
   primary [ ** primary ]
   | abs primary
   | not primary
   | logical_operator primary 

factor ::=
   unary_expression [ ** unary_expression ] 

unary_expression ::=
     primary
   | abs primary
   | not primary
   | unary_logical_operator primary
primary ::=
   name
   | literal
   | aggregate
   | function_call
   | qualified_expression
   | type_conversion
   | allocator
   | ( expression ) 

Each primary has a value and a type. The only names allowed as primaries are attributes that yield values and names denoting objects or values. In the case of names denoting objects other than objects of file types or protected types, the value of the primary is the value of the object. In the case of names denoting either file objects or objects of protected types, the value of the primary is the entity denoted by the name. The type of an expression depends only upon the types of its operands and on the operators applied; for an overloaded operand or operator, the determination of the operand type, or the identification of the overloaded operator, depends on the context (see 12.5). For each predefined operator, the operand and result types are given in the following subclause.

NOTE 1—The syntax for an expression involving logical operators allows a sequence of binary and, or, xor, or xnor operators (whether predefined or user-defined), since the corresponding predefined operations are associative. For the binary operators nand and nor (whether predefined or user-defined), however, such a sequence is not allowed, since the corresponding predefined operations are not associative.

NOTE 2—The syntax for an expression involving a unary condition operator or unary logical operator in combination with any other operator requires that the unary operator and its operand be a parenthesized expression. For example, the expressions “(and A) and B” and “A and (and B)” are legal, whereas the expression “and A and B” and “A and and B” are not. Similarly, “and (and A)” is legal, whereas “and and A” is not. An expression consisting only of a unary condition oprator or unary logical operator and its operand need not be parenthesized.

NOTE 2 3—PSL extends the grammar of VHDL expressions to allow PSL expressions, PSL built-in function calls, and PSL union expressions as subexpressions. Such extended expressions can only appear in a VHDL description within PSL declarations and PSL directives, or in a verification unit.

9.2 Operators

9.2.1 General

The operators that may be used in expressions are defined as follows. Each operator belongs to a class of operators, all of which have the same precedence level; the classes of operators are listed in order of increasing precedence.

condition_operator ::= ??

logical_operator ::= and | or | nand | nor | xor | xnor

relational_operator ::= = | /= | < | <= | > | >= | ?= | ?/= | ?< | ?<= | ?> | ?>=

shift_operator ::= sll | srl | sla | sra | rol | ror

adding_operator ::= + | – | &

sign ::= + | –

multiplying_operator ::= * | / | mod | rem

binary _miscellaneous_operator ::= **

unary miscellaneous_operator ::= ** | abs | not | _unary _logical_operator

Operators of higher precedence are associated with their operands before operators of lower precedence. Where the language allows a sequence of operators, operators with the same precedence level are associated with their operands in textual order, from left to right. The precedence of an operator is fixed and cannot be changed by the user, but parentheses can be used to control the association of operators and operands. In general, operands in an expression are evaluated before being associated with operators. For certain operations, however, the right-hand operand is evaluated if and only if the left-hand operand has a certain value. These operations are called short-circuit operations. The binary logical operations and, or, nand, and nor defined for operands of types BIT and BOOLEAN are all short-circuit operations; furthermore, these are the only short-circuit operations.

Every predefined operator and every predefined MINIMUM and MAXIMUM operation is a pure function (see 4.2.1). No predefined operators have named formal parameters; therefore, named association (see 6.5.7.1) cannot be used when invoking a predefined operator.

NOTE 1—The predefined operators for the standard types are declared in package STANDARD as shown in 16.3.

NOTE 2—The operator not is classified as a miscellaneous operator for the purposes of defining precedence, but is otherwise classified as a logical operator.

9.2.2 General

[Delete note at end of section on page 120]

NOTE—All of the binary logical operators belong to the class of operators with the lowest precedence. The unary logical operators belong to the class of operators with the highest precedence.

LRM Annex C

page 486


factor ::=
   primary [ ** primary ]
   | abs primary
   | not primary
   | logical_operator primary 

factor ::=
   unary_expression [ ** unary_expression ] 

page 500 (top)


unary_expression ::=
     primary
   | abs primary
   | not primary
   | unary_logical_operator primary

Comments

In section 9.2.2 - Logical operators is the following: NOTE—All of the binary logical operators belong to the class of operators with the lowest precedence. The unary logical operators belong to the class of operators with the highest precedence.

Perhaps this note needs to be copied (or possibly moved), to section 9.2.1 to define the precedence of unary operators rather than defining new 'unary_expression'. Would seem to me to be simpler way to accomplish the goal of defining unary operator precedence.

-- Kevin Jennings - 2016-12-08

The EBNF rule for "unary_expression" should refer to //unary_//logical_operator. The EBNF rule "miscellaneous_operator" should also use "logical_operator" with "unary_" in italic font.

-- Patrick Lehmann - 2016-12-31

It's not clear what the intent is for the proposed introduction of unary_expression in 9.1. Its effect is that expressions of the form abs x ‍** y become legal while in 1076-2008 this would have to be written as (abs x) ‍** y. In my perspective the parenthesized form is clear with regards to associativity while the form that becomes legal with the proposed change is not (I am referring to the expression text; of course it's clear when referring to the LRM). A rationale for the proposed change would be welcome.

Regarding the proposed change to 9.2.1, the prefix unary should be in tialics. The change works because there is no syntactic reference to the production miscellaneous_operators, otherwise the grammar would become ambiguous. However, I second Kevin in his proposal to add a NOTE 3 that repeats the NOTE from 9.2.2.

-- Ernst Christen - 2017-01-26

I agree: NOTE 2 should be removed because it is not true even in the current LRM:

  • “and A and B” as well as “A and and B” are legal in VHDL 2008.
  • “and (and A)” as well as “and and A” are not possible because after the first reduction, the result will not be an one-dimensional array of type bit or std_logic_vector any more.

EDIT: The BNF should not be changed. I concur with Ernst here. See Patrick's comment below.

-- Martin Zabel - 2017-02-03

By dividing the EBNF rules into two rules for factor and unary_expression, you are introducing, as intended, a new level of precedence. You also need to create a new rule/row in 9.2.1 because each line/rule represents one level of precedence. So you need to divide miscellaneous_operator into two lines to reflect the new precedence levels.

-- Patrick Lehmann - 2017-02-03

I think the note in 9.2.2 needs to be deleted. The lowest precedence is now ??. Like Ernst I too like parentheses, however, only the ** operator requires them. All of the other binary operators do not. Hence, I think the change makes things more consistent. I agree on the usage of unary in itallics in the two places Patrick noted.

WRT precedence of miscellaneous operators (**, abs, not, unary logic operators) the precedence between operators did change, however, the precedence of the group of operators did not change. The precedence between operators was none (parentheses required) and is now left to right. This is still consistent with the LRM text as it allows left to right precedence where the EBNF allows it.

-- Jim Lewis - 2017-02-08

Updated to revision 3 to address comments above

-- Jim Lewis - 2017-02-08

@JimLewis:

JL: WRT precedence of miscellaneous operators (**, abs, not, unary logic operators) the precedence between operators did change, however, the precedence of the group of operators did not change. The precedence between operators was none (parentheses required) and is now left to right. This is still consistent with the LRM text as it allows left to right precedence where the EBNF allows it.

MZ: I don't understand this. Within each group, all operators have the same precedence, as also stated in clause 9.2.1 paragraph 1. But within an expression, operators with the same precedence level are associated from left to right, as stated in clause 9.2.1 paragraph 3 (below BNF).

Example 1:

a AND b OR c is the same as (a AND b) OR c.

Example 2:

a OR b AND c is the same as (a OR b) AND c even if OR is listed after AND in the group logical_operator.

Example 3:

abs a ** abs b is not possible in VHDL-2008, but will be possible with this LCS. The expression equals to (abs a) ** (abs b). Thus ** has a higher precedence and must be listed in it's own group.

-- Martin Zabel - 2017-02-08

@MZ. WRT Example 3: you state: abs a ** abs b is equivalent to: (abs a) ** (abs b)

I agree.

One correct view of this is: "abs" has higher precedence than "**" because "abs" is done first.

Another correct view of this is: "abs" and "**" have equal precedence, and then left to right evaluation results in the same parenthesized expression.

Hence, the current table correctly expresses one of the two possible precedence rules.

For Examples 1 and 2, you have to read the "weasel words": "Where the language allows a sequence of operators". The EBNF does not allow mixing "and" with "or". Interestingly, the EBNF is the sole source of that information. If you try to mix "and" and "or" without parentheses you will get a syntax error.

Honestly, I like parentheses, however, it does not make sense to require parentheses for "**" and not for "and".

-- Jim Lewis - 2017-02-08

@Jim: Now I understand the "weasel words." Of course, example 1 and 2 have syntax errors.

Regarding example 3: You cannot evaluate it from left to right, this would be ((abs a) **) abs b which is non-sense. (Or I don't understand your view.)

The only problem with the BNF rule for miscellaneous_operator was, that clause 9.2.8 refers to it. What about this change for clause 9.2.1 to split it into two groups:

binary_miscellaneous_operator ::= **

unary_miscellaneous_operator ::= abs | not | unary _logical_operator

-- Martin Zabel - 2017-02-10

In example 3, left to right it evaluates to: ((abs a) * abs b). The expression "abs b" is left operand to * and it is evaluated per the text "In general, operands in an expression are evaluated before being associated with operators".

Hence, both are indeed correct.

-- Jim Lewis - 2017-02-24

Topic revision: r28 - 2017-04-02 - 16:30:38 - PatrickLehmann
 
Copyright © 2008-2025 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback