https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126002
Bug ID: 126002
Summary: parenthesized sign condition fails to parse
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: cobol
Assignee: unassigned at gcc dot gnu.org
Reporter: peeterjoot at protonmail dot com
Target Milestone: ---
Created attachment 64865
--> https://gcc.gnu.org/bugzilla/attachment.cgi?id=64865&action=edit
sign conditions, two accepted examples, and one rejected.
## Summary
`gcobol` rejects a **sign condition** (`operand IS [NOT] {POSITIVE | NEGATIVE |
ZERO}`) when it is enclosed in parentheses.
## Environment
```
gcobol (GCC) 17.0.0 20260604 (experimental), target aarch64-linux-gnu
```
## Reproducer
`paren-sign-condition.cob` (this directory). Three conforming `IF`s; gcobol
accepts #1 and #2 but rejects #3:
```cobol
IF WS-N IS ZERO *> #1 sign, no parens -- ACCEPTED
IF (WS-N = 0) *> #2 relation, parens -- ACCEPTED
IF (WS-N IS ZERO) *> #3 sign, parens -- REJECTED
```
```
$ gcobol -c paren-sign-condition.cob -nomain -o /dev/null
paren-sign-condition.cob:28:24: error: syntax error, unexpected ZERO, expecting
class name or OMITTED
28 | IF (WS-N IS ZERO)
| ^~~~~
```
`POSITIVE` and `NEGATIVE` fail the same way. Unparenthesized (#1) parses fine,
so the defect is confined to the parenthesized-condition path. The diagnostic
names exactly the *class name* and *OMITTED* alternatives, which suggests the
sign-condition alternative is unreachable in that state.
It is also triggered indirectly when a logical operator forces parentheses
around a sign condition, e.g. `NOT (WS-N IS ZERO)` or
`PERFORM UNTIL (WS-I = 0 OR TBL(WS-I) IS POSITIVE)`.
In the grammar (`gcc/cobol/parse.y`, trunk `c9ee2c5ab6c`; line numbers
approximate) the pieces are all present, so the construct is grammatically
intended: the sign condition is `simple_cond: expr posneg` (~6610), a
parenthesized condition is `log_term: '(' log_expr ')'` (~6684), and `log_expr`
reaches `simple_cond` (~6694). The two alternatives the diagnostic *does* list
are `expr is CLASS_NAME` (~6580) and `expr is OMITTED` (~6594), the siblings of
the sign production. The likely cause is an LALR conflict between the
parenthesized condition (~6684) and a parenthesized arithmetic operand
`factor: '(' expr ')'` (~6876), resolved so that the sign continuation is lost
while the class/omitted continuations survive.
## Why it is a bug
A sign condition is a *simple condition*, and a simple condition may be
parenthesized freely. From the IBM Enterprise COBOL for z/OS 6.5 Language
Reference (SC27-8713-04):
- "Simple conditions" (p.274) lists the six simple conditions, including the
**sign** condition.
- "Conditional expressions" (p.274): *"Both simple and complex conditions can
be
enclosed within any number of paired parentheses; the parentheses do not
change whether the condition is simple or complex."*
- "Order of evaluation of conditions" (p.292) gives IBM's own
fully-parenthesized
evaluation form containing a parenthesized sign condition directly:
`... AND (D IS POSITIVE)`.
So `(WS-N IS ZERO)` should be conforming COBOL, at least for the IBM dialect,
but probably generally. gcobol accepting the unparenthesized
sign form and the parenthesized relation/class forms, while rejecting only the
parenthesized sign form, marks this as a grammar omission rather than a dialect
restriction.
## Workaround
This issue was observed running our COBOL "clang-format" like tool, which was
over parenthesizing -- I've added a GcobolCompat: option to that tool to work
around this. When that option is used, I attempt to drop parentheses that can
be implied by precedence (standard precedence is `NOT > AND > OR`),
e.g.`NOT (WS-N IS ZERO)` -> `NOT WS-N IS ZERO`.
That workaround is not always possible: when parentheses are required to
override
precedence (a sign condition inside `(a OR b) AND c`), the expression must be
restructured instead.