Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2013-12

Very odd case parsing problem

14 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Mark Morgan Lloyd

I've been wrestling with something for a chunk of the early evening, which is reproducible in situ but not in a cut-down test program.

Using 2.6.2 on x86 Linux in objfpc mode, a case statement that looks like this fails to parse:

   try
     case parseCommand(selector) of
       help:        begin
                    end;
       help_:       begin
                    end;
       quit_:       if High(lexemeListArray) = 1 then begin
                    end
     else
     end // line 323
   finally
   end;

As it stands, compilation fails with

centralcontrol/distributionanddisplay.pas(323,5) Error: Constant and
CASE types do not match
centralcontrol/distributionanddisplay.pas(323,5) Error: Constant
Expression expected
centralcontrol/distributionanddisplay.pas(323,5) Error: duplicate case label
centralcontrol/distributionanddisplay.pas(323,5) Fatal: Syntax error,
":" expected but "END" found

I can fix that either by putting a semicolon before the else- which I believe is strictly incorrect- or by putting begin/end around that conditional, or by inserting a dummy statement before the else like

       quit_:       if High(lexemeListArray) = 1 then begin
                    end;
       nop:         begin end
     else

I suspect I might have seen this happen before, but it's not an easy one to grep for. Does this make sense to anybody, is it a known (and preferably fixed) issue, or should I be putting time into trying to match the behaviour in a cut-down test program?

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Saunders, Rich
to Mark Morgan Lloyd
Mark Morgan Lloyd wrote 8 lines
I can fix that either by putting a semicolon before the else- which I believe is strictly incorrect- or by putting begin/end around that conditional, or by inserting a dummy statement before the else like quit_: if High(lexemeListArray) = 1 then begin end; nop: begin end else

The problem is the compiler associates the else with the if..then and not with the case statement. All your fixes break the possible connection between the else and the if..then and that's why they work.

Your first fix (to just add a semicolon) would be my preferred one. I have lots of code that is written that way. I'm not sure why you think this is "strictly incorrect".

Cheers! Rich Saunders

Reply by email

leledumbo
to Mark Morgan Lloyd: I've been wrestling with something for a chunk of the early evening, which is…
I can fix that either by putting a semicolon before the else- which I

believe is strictly incorrect

Nope, that's correct. Take a look at the syntax diagram for case statement here:
http://www.freepascal.org/docs-html/ref/refsu50.html

As you can see, each "case" is terminated by ";". From the parser point of
view, your code is exactly parsed as:
try
  case parseCommand(selector) of
    help: begin
    end;
    help_: begin
    end;
    quit_: if High(lexemeListArray) = 1 then begin
    end else <there should be a statement here> <there should be a semicolon
here>
  end // line 323
finally
end;

So that else after begin-end pair of the if statement becomes the else of the if statement, not the case statement.

View this message in context: http://free-pascal-general.1045716.n5.nabble.com/Very-odd-case-parsing-problem-tp5717723p5717724.html Sent from the Free Pascal - General mailing list .

Reply by email

Mark Morgan Lloyd
to Saunders, Rich: The problem is the compiler associates the else with the if..then and not with the case…
Rich wrote 17 lines
On 2013-12-28 15:47, Mark Morgan Lloyd wrote: > I can fix that either by putting a semicolon before the else- which I > believe is strictly incorrect- or by putting begin/end around that > conditional, or by inserting a dummy statement before the else like > > quit_: if High(lexemeListArray) = 1 then begin > end; > nop: begin end > else The problem is the compiler associates the else with the if..then and not with the case statement. All your fixes break the possible connection between the else and the if..then and that's why they work. Your first fix (to just add a semicolon) would be my preferred one. I have lots of code that is written that way. I'm not sure why you think this is "strictly incorrect".

Drat- a dangling else in a case! I should have spotted that, but instead spent an hour or so
Mark Morgan Lloyd
markMLl .AT. telemetry.co .DOT. uk

[Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Mark Morgan Lloyd
to leledumbo: believe is strictly incorrect Nope, that's correct. Take a look at the syntax diagram for…
leledumbo wrote 9 lines
> I can fix that either by putting a semicolon before the else- which I believe is strictly incorrect Nope, that's correct. Take a look at the syntax diagram for case statement here: http://www.freepascal.org/docs-html/ref/refsu50.html As you can see, each "case" is terminated by ";". From the parser point of view, your code is exactly parsed as:

No, that shows a semicolon separating successive cases, not terminating each one. What's more statement can be a compound statement and that's similarly defined as using ; as a separator.

Bit of an old chestnut, and my recollection is that an extra semicolon would crash some versions of Turbo Pascal. I'm not sure where my copy of J&W is, so I can't go back to the BNF... but it wouldn't help since else was added to the case statement by Turbo Pascal which explicitly has

case expression of case-element { ; case-element } else

where a case-element ends with a statement which can be a compound-statement which again defines ; as a separator.

(Oh Lord this is all we need: a syntax war to round off the year.)

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Sven Barth
to Mark Morgan Lloyd

Am 29.12.2013 09:10 schrieb "Mark Morgan Lloyd" <

Show quoted text 9 lines
: leledumbo wrote: >> >> I can fix that either by putting a semicolon before the else- which I > > believe is strictly incorrect > > Nope, that's correct. Take a look at the syntax diagram for case

statement

> here: > http://www.freepascal.org/docs-html/ref/refsu50.html > > As you can see, each "case" is terminated by ";". From the parser point

of

> view, your code is exactly parsed as: No, that shows a semicolon separating successive cases, not terminating

each one. What's more statement can be a compound statement and that's similarly defined as using ; as a separator.

Bit of an old chestnut, and my recollection is that an extra semicolon

would crash some versions of Turbo Pascal. I'm not sure where my copy of J&W is, so I can't go back to the BNF... but it wouldn't help since else was added to the case statement by Turbo Pascal which explicitly has

case expression of case-element { ; case-element } else where a case-element ends with a statement which can be a

compound-statement which again defines ; as a separator.

(Oh Lord this is all we need: a syntax war to round off the year.)

In case you don't need Delphi compatibility you can use "otherwise" instead of "else" inside a case-statement. This keyword comes from the ISO dialects and is enabled in all modes.

Regards,
Sven

Reply by email

Martin Frb
to Mark Morgan Lloyd: Drat- a dangling else in a case! I should have spotted that, but instead spent an hour or…
Mark Morgan Lloyd wrote 7 lines
Saunders, Rich wrote: > On 2013-12-28 15:47, Mark Morgan Lloyd wrote: >> >> quit_: if High(lexemeListArray) = 1 then begin >> end; >> nop: begin end >> else

....

Drat- a dangling else in a case! I should have spotted that, but instead spent an hour or so picking at it.

1) If you use Lazarus then you can have case-labels highlighted (e.g add underline/border, blend foreground by mixing in another color, bold, ...) It is in the color config.

That will (in this case) not highlight the else, so you will know the else is part of the if.

2) I tried your code and it compiles (2.6.2 win32)

{$mode objfpc}{$H+}
procedure TForm1.FormCreate(Sender: TObject);
var
   a: (help, help_, quit_);
   b: Integer;
begin
    try
     case a of
       help:        begin
                    end;
       help_:       begin
                    end;
       quit_:       if b = 1 then begin
                    end
     else
     end // line 323
   finally
   end;
end;

Reply by email

Mark Morgan Lloyd
to Martin Frb
Martin Frb wrote 9 lines
> Drat- a dangling else in a case! I should have spotted that, but > instead spent an hour or so picking at it. 1) If you use Lazarus then you can have case-labels highlighted (e.g add underline/border, blend foreground by mixing in another color, bold, ...) It is in the color config. That will (in this case) not highlight the else, so you will know the else is part of the if.

Thanks, noted.

Show quoted text 23 lines
2) I tried your code and it compiles (2.6.2 win32) {$mode objfpc}{$H+} procedure TForm1.FormCreate(Sender: TObject); var a: (help, help_, quit_); b: Integer; begin try case a of help: begin end; help_: begin end; quit_: if b = 1 then begin end else end // line 323 finally end; end;

There were additional statements in between the else and the final end. Since the else associated with a case accepts multiple statements while the else associated with an if doesn't, the compiler was getting confused by what it thought was a spurious end statement. I'm sure I've been bitten by this one before, and recently enough for it to be embarrassing.

I find myself habitually putting in an explicit else part in each case statement, even if it's empty. That's a habit from Modula-2 days, I can't remember what the spec said but some (if not all) compilers insisted on it. In view of the potential for a dangling else, I'm not sure whether that's a good or a bad habit.

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email

Sven Barth
to Martin Frb: .... 1) If you use Lazarus then you can have case-labels highlighted (e.g add…
Martin Frb wrote 19 lines
On 29/12/2013 07:33, Mark Morgan Lloyd wrote: > Saunders, Rich wrote: >> On 2013-12-28 15:47, Mark Morgan Lloyd wrote: >>> >>> quit_: if High(lexemeListArray) = 1 then begin >>> end; >>> nop: begin end >>> else .... > Drat- a dangling else in a case! I should have spotted that, but > instead spent an hour or so picking at it. > 1) If you use Lazarus then you can have case-labels highlighted (e.g add underline/border, blend foreground by mixing in another color, bold, ...) It is in the color config. That will (in this case) not highlight the else, so you will know the else is part of the if.

Does Lazarus recognize "otherwise" as an alternative for "else" inside a "case"-statement as well?

Regards,
Sven

Reply by email

Sven Barth
to Martin Frb
Martin Frb wrote 9 lines
On 29/12/2013 17:08, Martin Frb wrote: > On 29/12/2013 16:37, Sven Barth wrote: >> >> Does Lazarus recognize "otherwise" as an alternative for "else" >> inside a "case"-statement as well? > > Not yet Now 1.3 does

Great! :)

Regards,
Sven

Reply by email

Mark Morgan Lloyd
to Sven Barth
Sven Barth wrote 12 lines
On 29.12.2013 18:20, Martin Frb wrote: > On 29/12/2013 17:08, Martin Frb wrote: >> On 29/12/2013 16:37, Sven Barth wrote: >>> >>> Does Lazarus recognize "otherwise" as an alternative for "else" >>> inside a "case"-statement as well? >> >> Not yet > > Now 1.3 does Great! :)

Ruefully agrees :-)

Mark Morgan Lloyd markMLl .AT. telemetry.co .DOT. uk [Opinions above are the author's, not those of his employers or colleagues]

Reply by email