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':
type Foo = Integer; attribute (aligned);
vs.
type 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:
type Foo = Integer attribute (aligned);
This seems to be conflict-free, and might even work in variable declarations etc.:
var 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 identifiers.
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