Conditional keywords

Frank Heckenbach frank at
Mon Mar 17 05:40:50 CET 2003

Grant Jacobs wrote:

> At 10:29 AM +0100 16/3/03, Frank Heckenbach wrote:
> >I've done this now and analyzed all problematic keywords.
> >Fortunately, most of them could be completely resolved this way. In
> >addition, some of them can even be used as "keywords" (directives)
> >and identifiers in parallel, in particular `forward' (which the
> >Pascal standards require) and `near' and `far' (which BP seems to
> >do, though its documentation says otherwise).
> >
> >There are only two exceptions:
> >
> >- `Operator' can't be used as a type, untyped constant or exported
> >   interface (unless it's disabled as a keyword explicitly or by
> >   dialect options). This is because of the following conflict:
> >
> >     type
> >       Foo = record end;
> >       Operator = (a, b);  { enum type }
> >
> >   vs.
> >
> >     type
> >       Foo = record end;
> >
> >     operator = (a, b: Foo) c: Foo;
> >
> >   This is not a complete ambiguity, but requires 6 tokens look-ahead
> >   to decide whether `operator' is a keyword. That's way too much
> >   (IMHO), so since the operator `=' should be definable, we have to
> >   make the restriction as stated.
> Just out of interest: the use of the word 'operator' in the code I 
> was porting was within a type definition, e.g.
>     half_exprs      = record
>                          negate    : boolean;
>                          operator  : operators;
>                          case value_type : value_types of
>                             int_value     : ( int  : integer );
>                             string_value  : ( str  : strings )
>                       end;
> Is it easy to reduce the conflict to just when operator is defined as 
> a "plain" type (as in your example) rather than within a record?

It would not be easy because it would make the lexing dependent on
syntactic context again (which I just tried to get rid of as much as
possible because it made the grammar quite fragile).

However, that's not the problematic case at all. Only `operator' as
a "top-level" type is problematic, i.e. when it's followed by `='.
Since there is no `:' operator that could be overloaded, this record
example will just work.

Actually, there's one case where "top-level" types are not followed
by `=', viz schemata. This could be a conflict with keywords that
can be followed by `(', in particular `attribute':

    Foo = Integer; attribute (aligned);


    Foo = Integer;
    Attribute (Aligned: Integer) = Integer;

This is no conflict only because we don't allow type attributes at
all currently. But we might want to -- GCC does it, and it was
suggested as a solution for the `Integer (16)' problem. When we do
this, this conflict will arise.

One solution would be to omit the `;' before attribute:

    Foo = Integer attribute (aligned);

This seems to be conflict-free, and might even work in variable
declarations etc.:

    Foo: Integer attribute (aligned); attribute (static);

where the first attribute would be of the type, and the second one
of the variable.

> A possible further reduction, although a bit ugly, would be that if 
> the user wants to use "operator = ..." as a type, they must place it 
> as the first type definition, e.g.
> type
>    Operator = (a, b);
>    Foo = record end;
> These two would cover many, but not all cases.

This would be possible, but quite a bit more difficult -- either
making the lexing context-dependent (see above) or using a difficult
grammar rule (that includes the `operator' token) for the first type
in a block.

> As an aside, it makes me think that the const, type and var section 
> probably could have been designed to have an "end" keyword to avoid 
> this sort of thing (when Pascal was first designed, that is); this 
> isn't a suggestion, just a idle thought.
> Something like:
>      const-begin
>        <const declarations>
>      const-end
>      type-begin
>        <type declarations>
>      type-end
> This way later development of new things like operator = ... wouldn't 
> impact on the declaration sections, as they'd have one unique 
> end-point "for all time".

I agree. Or use something else than `;' to separate the items so the
next `;' (outside of records etc.) means the end. That's a case
where I prefer the `uses' syntax (with `,') over EP's `import' (with
`;' in between).

But given that this can't be changed, maybe the designers of the
`operator' syntax should have thought of it. (Maybe `function
operator'?) But that's too late now as well ...

CBFalconer wrote:

> They do, at least in standard Pascal.  Parsing is something like:
>   WHILE NOT (nextsym IN [typesy, varsy, procsy, funcsy, beginsy])
>     DO BEGIN
>     (* parse a constant *)
>     END;

But that's exactly the difference. They don't have their end-points
defined by themselves, but only by the context. While this doesn't
create a conflict by itself (i.e., within the standard Pascals), it
does make the syntax more fragile WRT extensions.

And it does not necessarily only apply to non-standard extensions;
the OOE (which is a standard draft after all) might have the
mentioned problem with `import' and `constructor'/`destructor' (I'd
have to check in detail). I.e., you either have to do more than one
token look-ahead or make `constructor' and `destructor' strictly
reserved words which breaks valid EP programs that use them as

Grant Jacobs wrote:

> (I hope understand the 'operator = ...' construct correctly, as I've
> never used it. In Frank's example it appears to occur in the 
> function/procedure declaration section and thus would extend the list 
> in the loop guard above.)

Yes, that's the problem.

> All of this is sort-of off topic... but fun :-)  Excuse my degression...

Yeah, it's fun ... until you actually try to implement it. ;-)


Frank Heckenbach, frank at,, 7977168E
GPC To-Do list, latest features, fixed bugs:
GPC download signing key: 51FF C1F0 1A77 C6C2 4482  4DDC 117A 9773 7F88 1707

More information about the Gpc mailing list