Labels

B

BartC

glen herrmannsfeldt said:
So you are writing a program that will generate C code?

Yes. Not the first time, but in the past, the C output was unstructured so
there were no {,} blocks. Both forms have their own sets of problems to
overcome, of which label syntax was a very minor one. (The bigger ones
usually involve the type system.)
if(x==y) lab: printf("hi!");

vs.

if(x==y) lab:; printf("hi!");

It is probably better not to do that at all, and, for machine
generate code, always generate the { and } in those cases.

I tend to that anyway, as I think having to keep treating one statement
differently from two or more is a nuisance, and is error-prone when code is
modified.
 
K

Keith Thompson

Robert Wessel said:
Not that it's a big point, but (in C) a label is syntactically an
optional prefix for a statement. The label is part of the statement;
there is no real notion of a label being "followed" by a statement.

Yes and no.

This:

lab: x = 42;

is actually two statements, one containing the other.

lab: x = 42;

is a labeled-statement, and

x = 42;

is an expression-statement.

The relevant grammar production is:

labeled-statement:
identifier : statement

Yes, the label is part of a statement, but it's also followed by a
statement.
 
J

James Kuyper

On 11/06/2013 07:11 PM, Robert Wessel wrote:
....
Not that it's a big point, but (in C) a label is syntactically an
optional prefix for a statement. The label is part of the statement;
there is no real notion of a label being "followed" by a statement.

The C grammar says otherwise:

statement:
labeled-statement
compound-statement
expression-statement
selection-statement
iteration-statement
jump-statement

labeled-statement:
identifier : statement
case constant-expression : statement
default : statement

Grammar productions that corresponded to your description would look
something like this:

statement-core:
compound-core
expression-core
selection-core
iteration-core
jump-core

statement-prefix:
identifier :
case constant-expression :
default :

statement:
statement-prefixopt statement-core


Where "opt" would be subscripted, and would indicate that the
statement-prefix is optional. Note: in the actual C grammar,
labeled-statement is recursive, so it allows, for instance, the following:

label1: case 2: x = 2*y+1;

The alternative syntax I've given above to describe your concept of how
labels work would only allow one prefix for any given statement. If
that's not actually a feature of your concept, that's easily fixed.
 
S

Stephen Sprunk

The C grammar says otherwise:

statement:
labeled-statement
...

labeled-statement:
identifier : statement
...

Potentially infinite mutual recursion? I'm not sure if that's a
"feature" or a "bug".

S
 
J

James Kuyper

Potentially infinite mutual recursion? I'm not sure if that's a
"feature" or a "bug".

It's a very common feature of the C grammar. In this case, it means that
it that the C syntax allows any given statement to have an arbitrarily
long sequence of labels, case labels and default labels.
 
B

BartC

Not that it's a big point, but (in C) a label is syntactically an
optional prefix for a statement. The label is part of the statement;
there is no real notion of a label being "followed" by a statement.

In this example:

{... a: b: c: d: f: g: h: }

this would be a syntax error (I now know). The labels need to apply to a
statement. By adding a semicolon:

{... a: b: c: d: f: g: h:; }

that satisfies the condition for h:, but it also does so for a: thru g:.
Either the empty ";" statement can have any number of label prefixes, or h:;
now forms a new statement on top of ";", which now satisfies the condition
for g:, and so on.

This is apparently what C does (combine a label and a statement into a new
composite statement), which sounds a complicated way of doing things,
although it has no real affect on programming other than the minor issue of
sometimes having to add in dummy empty statements.

When I program this stuff, labels are just treated as statements in their
own right, for parsing purposes anyway. (At least C *has* labels; some
potential target languages have done away with 'goto' completely.)
 
G

Geoff

this would be a syntax error (I now know). The labels need to apply to a
statement. By adding a semicolon:

{... a: b: c: d: f: g: h:; }

that satisfies the condition for h:, but it also does so for a: thru g:.
Either the empty ";" statement can have any number of label prefixes, or h:;
now forms a new statement on top of ";", which now satisfies the condition
for g:, and so on.

A statement can have any number of labels. When you write {... ; } you
have written a block statement consisting of one statement. Your block
above has exactly ONE statement.
This is apparently what C does (combine a label and a statement into a new
composite statement), which sounds a complicated way of doing things,
although it has no real affect on programming other than the minor issue of
sometimes having to add in dummy empty statements.

No. C is very simple in doing what it does. It takes each line and
begins evaluating the tokens. when it finds blah: it says, ok, that's
a label, what else do I have? Then it finds ; and says OK, that's the
end of that statement, I have an empty statement with one label.

In the case of multiple labels, it takes note of each label and
provides for it until it reaches the end of the statement. (;)

Upon execution, any code jumping to any one of your labels above would
execute the empty statement and continue to the next.

This is exactly like using multiple case statements:


case a:
case b:
{
//do an empty statement
;
}
 
K

Keith Thompson

BartC said:
In this example:

{... a: b: c: d: f: g: h: }

this would be a syntax error (I now know). The labels need to apply to a
statement. By adding a semicolon:

{... a: b: c: d: f: g: h:; }

that satisfies the condition for h:, but it also does so for a: thru g:.
Either the empty ";" statement can have any number of label prefixes, or h:;
now forms a new statement on top of ";", which now satisfies the condition
for g:, and so on.

Each of these:

;
h:;
g: h: ;
f: g: h: ;
...
a: b: c: d: f: g: h:;
{ a: b: c: d: f: g: h:; }

is a statement. The first is a null-statement (which, oddly, is
considered to be a form of expression-statement). The last is a
compound-statement. The others are all labeled-statements.
This is apparently what C does (combine a label and a statement into a new
composite statement), which sounds a complicated way of doing things,
although it has no real affect on programming other than the minor issue of
sometimes having to add in dummy empty statements.

It's actually a reasonably simple way of defining it. Syntactic
constructs in C are defined recursively in terms of other syntactic
constructs (statements can contain statements and expression,
expression can contain expressions and statements, and so on),
until you get down to single tokens -- which are themselves defined
similarly until you get down to single characters. There are
decades of work on parsing input based on recursive grammars.
And it allows programmers to write arbitrarily complex code (which
admittedly not always an entirely good thing).

If what you mean is that it would have been simpler to define a label
as a kind of statement, rather than as part of a particular kind
of statement, I suppose that's true -- but dummy empty statements
aren't the only issue. Consider this:

if (condition)
label: statement;

If a label were a statement by itself, then `statement;` would be
executed unconditionally, since `label:` would be the only thing
controlled by the `if`.

The majority of the time, you *want* a label to apply to some
particular statement (that's executed when you branch to the label).
And for the cases where you don't want that, as you've seen, it's
easy enough to add a null statement (a semicolon).
When I program this stuff, labels are just treated as statements in their
own right, for parsing purposes anyway. (At least C *has* labels; some
potential target languages have done away with 'goto' completely.)

If that works for you, that's fine -- but I suspect you'd encounter
fewer problems if you treat labels the same way the C grammar
treats them.

As for gotoless target languages, the Böhm-Jacopini theorem implies that
gotos are never strictly necessary.
<http://en.wikipedia.org/wiki/Structured_program_theorem>
 
T

Tim Rentsch

James Kuyper said:
On 11/05/2013 11:47 PM, glen herrmannsfeldt wrote:
....

It certainly would have been possible to do that. However, it
would have saved a grand total of 1 character in an extremely
uncommon corner case.

Not that uncommon, and not always a corner case - a fairly
routine occurrence in switch() statements.
 
T

Tim Rentsch

[...]
Drafts of the 1990, 1999, and 2011 versions of the standard can
be found at:

C90: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n869/
(gzipped PDF, PostScript, and plain text)
C99: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf
(includes the standard with all three Technical Corrigenda
merged into it)
C11: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
(last draft, shortly before the official standard)

The first of these (n869) is not about C90 but a preliminary
draft of C99 (dated January 18, 1999).

A (preliminary?) version of ANSI C (basically the same as C90
except for different section numbering) is available at

http://flash-gordon.me.uk/ansi.c.txt
 
K

Keith Thompson

Tim Rentsch said:
The first of these (n869) is not about C90 but a preliminary
draft of C99 (dated January 18, 1999).

A (preliminary?) version of ANSI C (basically the same as C90
except for different section numbering) is available at

http://flash-gordon.me.uk/ansi.c.txt

Oops, you're right, thank you.

N869 is somewhat useful because (as far as I know) it's the
last released plain-text draft of any version of the C standard.
N1256 was released only in PDF, but it's a significantly better
reflection of the actual standard.
 
B

BartC

Tim Rentsch said:
That's true, but in C neither are if()'s, for()'s, while()'s,
do...while()'s, or switch()'s.

In C, you need at least if-statements (with goto) for control flow within a
function.
 
B

Ben Bacarisse

BartC said:
In C, you need at least if-statements (with goto) for control flow
within a function.

Conditional expressions plus recursion is all you need. The result will
be a mess, of course, but that's not really the point.
 
B

BartC

Ben Bacarisse said:
Conditional expressions plus recursion is all you need. The result will
be a mess, of course, but that's not really the point.

Well, I did say *within* functions!

Code using for, while, switch etc is also trivially convertible to if+goto
form; I'd imagine using only recursive function calls is a little more
difficult.

Also using a flat if-and-goto code structure is an actual, viable way to
generate C code using an automatic tool (because I've done exactly that, and
benchmark programs, when passed through an optimising compiler, seemed to
run just as fast as properly structured versions.) So it works in practice
not just in theory.
 
B

Ben Bacarisse

BartC said:
Well, I did say *within* functions!

And I meant within functions too. If f calls f() is there, in your
mind, some point at which it is clear that the control flow is not "in
f"? (I say "clear" simply because I don't want to argue about obscure
definitions. You can declare that the control flow leaves and re-enters
the function, but it's not clear that that is the One True Way to look
at a function call.)

<snip>
 
S

Stephen Sprunk

Also using a flat if-and-goto code structure is an actual, viable way
to generate C code using an automatic tool (because I've done exactly
that, and benchmark programs, when passed through an optimising
compiler, seemed to run just as fast as properly structured
versions.) So it works in practice not just in theory.

The compiler is eventually going to turn it into an if/goto structure
anyway, so you're probably just making its job easier by doing that
yourself. Anything more complex is purely for human consumption.

S
 
K

Keith Thompson

Stephen Sprunk said:
The compiler is eventually going to turn it into an if/goto structure
anyway, so you're probably just making its job easier by doing that
yourself. Anything more complex is purely for human consumption.

It depends on the compiler.

An Ada compiler that I worked on more years ago than I care to admit
generated an intermediate form that corresponded to high-level
constructs like loops and if/else statements; the optimizer
operated on that level. Source code using gotos could actually
inhibit optimization.
 
G

glen herrmannsfeldt

(snip, someone wrote)
It depends on the compiler.
An Ada compiler that I worked on more years ago than I care to admit
generated an intermediate form that corresponded to high-level
constructs like loops and if/else statements; the optimizer
operated on that level. Source code using gotos could actually
inhibit optimization.

The IBM Fortran H (Fortran IV) compiler with OPT=2 can recognize loops
made with IF and GOTO. One option will print out a source listing with
the appropriate indent based on nesting level.

It may or may not be in IF/GOTO form internally, but in any case the
optimizer knows the nesting and loop structure.

-- glen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,772
Messages
2,569,593
Members
45,111
Latest member
KetoBurn
Top