Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #67454 > unrolled thread

Labels

Started byDavid Kleinecke <dkleinecke@gmail.com>
First post2015-08-15 09:46 -0700
Last post2015-08-15 19:00 -0700
Articles 20 on this page of 26 — 5 participants

Back to article view | Back to comp.lang.c


Contents

  Labels David Kleinecke <dkleinecke@gmail.com> - 2015-08-15 09:46 -0700
    Re: Labels James Kuyper <jameskuyper@verizon.net> - 2015-08-15 14:49 -0400
      Re: Labels David Kleinecke <dkleinecke@gmail.com> - 2015-08-15 18:48 -0700
    Re: Labels Bartc <bc@freeuk.com> - 2015-08-15 18:27 +0100
      Re: Labels Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-08-15 23:44 +0100
        Re: Labels James Kuyper <jameskuyper@verizon.net> - 2015-08-15 19:04 -0400
          Re: Labels Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-08-16 00:47 +0100
            Re: Labels James Kuyper <jameskuyper@verizon.net> - 2015-08-15 20:20 -0400
              Re: Labels Bartc <bc@freeuk.com> - 2015-08-16 01:56 +0100
                Re: Labels Keith Thompson <kst-u@mib.org> - 2015-08-15 19:47 -0700
                  Re: Labels James Kuyper <jameskuyper@verizon.net> - 2015-08-16 11:59 -0400
              Re: Labels Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-08-16 22:42 +0100
                Re: Labels James Kuyper <jameskuyper@verizon.net> - 2015-08-16 20:39 -0400
                  Re: Labels Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-08-17 03:16 +0100
          Re: Labels David Kleinecke <dkleinecke@gmail.com> - 2015-08-15 19:01 -0700
        Re: Labels Bartc <bc@freeuk.com> - 2015-08-16 01:11 +0100
          Re: Labels Keith Thompson <kst-u@mib.org> - 2015-08-15 19:13 -0700
            Re: Labels Bartc <bc@freeuk.com> - 2015-08-16 10:34 +0100
              Re: Labels Keith Thompson <kst-u@mib.org> - 2015-08-16 13:58 -0700
              Re: Labels David Kleinecke <dkleinecke@gmail.com> - 2015-08-16 20:42 -0700
                Re: Labels Keith Thompson <kst-u@mib.org> - 2015-08-16 21:24 -0700
                  Re: Labels David Kleinecke <dkleinecke@gmail.com> - 2015-08-17 18:01 -0700
                Re: Labels Bartc <bc@freeuk.com> - 2015-08-17 11:04 +0100
          Re: Labels David Kleinecke <dkleinecke@gmail.com> - 2015-08-15 19:04 -0700
          Re: Labels Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-08-16 23:55 +0100
      Re: Labels David Kleinecke <dkleinecke@gmail.com> - 2015-08-15 19:00 -0700

Page 1 of 2  [1] 2  Next page →


#67454 — Labels

FromDavid Kleinecke <dkleinecke@gmail.com>
Date2015-08-15 09:46 -0700
SubjectLabels
Message-ID<21f52d2c-4f30-4ae1-9f0a-c1c82527b884@googlegroups.com>
One of the curious little problems encountered in making a C compiler
is how to recognize labels. 

There is no problem in a two-pass compiler - but let me assume a one
pass compiler. Then I am reading along compiling statements and I
start a new statement and the first token in the statement is an
identifier. Is this token a label? 

The obvious way to tell is to read another token and check whether
the new token is a colon. If it is a colon then this is indeed a 
label. But if the new token is not a colon then I am two tokens deep
into an expression. This is not the expected situation. The expected
situation is that only the first token has been read. 

Now in reading an expression nothing happens until two tokens have
been read (except in the case where the first token is a semicolon).
The second token may well not belong to the expression as in 
   if (a) { ...}
but it takes that token to know the expression has ended. So I could
pass both the tokens in non-label case into to the expression
subroutine.  

But this seems clumsy. I think a better way to go is to admit I am
reading ahead one token. When I discover this is not a label
   ahead = true;
   ahead_token = non-colon; 
And then I call the expression subroutine with the usual argument -
the identifier - but ahead is now true. So the next_token call 
becomes
   if(ahead) {
      ahead = false;
      token = ahead_token;}
   else
      token - next_token();
or even
   token = ahead ? ahead = false, ahead_token : next_token ();

So far as I can tell this is the only place in the C syntax where
such a device is needed.

Better, I think, than ungetc. 

[toc] | [next] | [standalone]


#67458

FromJames Kuyper <jameskuyper@verizon.net>
Date2015-08-15 14:49 -0400
Message-ID<55CF89BD.5050703@verizon.net>
In reply to#67454
On 08/15/2015 12:46 PM, David Kleinecke wrote:
> One of the curious little problems encountered in making a C compiler
> is how to recognize labels. 
> 
> There is no problem in a two-pass compiler - but let me assume a one
> pass compiler. Then I am reading along compiling statements and I
> start a new statement and the first token in the statement is an
> identifier. Is this token a label? 
> 
> The obvious way to tell is to read another token and check whether
> the new token is a colon. If it is a colon then this is indeed a 
> label. But if the new token is not a colon then I am two tokens deep
> into an expression. This is not the expected situation. The expected
> situation is that only the first token has been read.

I'm not sure what you mean by that - but if "the expected situation" is
different from what's actually possible, then that argues for a change
to your expectations.

If you parse an identifier in a context where the start of a labeled
statement is permitted, than it must be either
a) a declaration making use of a previously defined typedef
b) an expression statement starting with the previously declared name of
an object or a function.
c) a labeled statement.

If the identifier has not been declared in this scope as either a
typedef, object, or function name, it must be a label name. Therefore,
if such an identifier is not followed by a ':', it's syntax error.

If the identifier has been declared in this scope as one of those
things, it could still also be a label. That's because label names have
their own name space (6.2.3). Therefore, it is indeed necessary to read
the ':' to identify it as a label name rather than a declaration or an
expression.

However, is that really a big problem? In precisely the same context, if
the first token is a '(', you can be sure that you're in the expression
of an expression-statement, but you have to read at least one additional
token to determine whether what you're looking at is a parenthesized
expression, or a cast-expression. It seems to me from my previous
efforts in this area that it's pretty normal to have ambiguities that
require the reading of two or more tokens before they are cleared up.

[toc] | [prev] | [next] | [standalone]


#67505

FromDavid Kleinecke <dkleinecke@gmail.com>
Date2015-08-15 18:48 -0700
Message-ID<464b6107-e788-4d4c-baca-31055452bb2f@googlegroups.com>
In reply to#67458
On Saturday, August 15, 2015 at 12:21:56 PM UTC-7, James Kuyper wrote:
> On 08/15/2015 12:46 PM, David Kleinecke wrote:
> > One of the curious little problems encountered in making a C compiler
> > is how to recognize labels. 
> > 
> > There is no problem in a two-pass compiler - but let me assume a one
> > pass compiler. Then I am reading along compiling statements and I
> > start a new statement and the first token in the statement is an
> > identifier. Is this token a label? 
> > 
> > The obvious way to tell is to read another token and check whether
> > the new token is a colon. If it is a colon then this is indeed a 
> > label. But if the new token is not a colon then I am two tokens deep
> > into an expression. This is not the expected situation. The expected
> > situation is that only the first token has been read.
> 
> I'm not sure what you mean by that - but if "the expected situation" is
> different from what's actually possible, then that argues for a change
> to your expectations.
> 
> If you parse an identifier in a context where the start of a labeled
> statement is permitted, than it must be either
> a) a declaration making use of a previously defined typedef
> b) an expression statement starting with the previously declared name of
> an object or a function.
> c) a labeled statement.
> 
> If the identifier has not been declared in this scope as either a
> typedef, object, or function name, it must be a label name. Therefore,
> if such an identifier is not followed by a ':', it's syntax error.
 
Sure, I know that but I want to keep syntax and semantics separate as
much as possible (typedef semantics cannot - I think - be avoided). As
I use the words checking whether an identifier has been declared as an
object/function name (or a typedef) is an appeal to semantics. 

> If the identifier has been declared in this scope as one of those
> things, it could still also be a label. That's because label names have
> their own name space (6.2.3). Therefore, it is indeed necessary to read
> the ':' to identify it as a label name rather than a declaration or an
> expression.
> 
> However, is that really a big problem? In precisely the same context, if
> the first token is a '(', you can be sure that you're in the expression
> of an expression-statement, but you have to read at least one additional
> token to determine whether what you're looking at is a parenthesized
> expression, or a cast-expression. It seems to me from my previous
> efforts in this area that it's pretty normal to have ambiguities that
> require the reading of two or more tokens before they are cleared up.

It may depend on one's compiler architecture - there don't seem to be
any other places in my compiler aritecture.

[toc] | [prev] | [next] | [standalone]


#67459

FromBartc <bc@freeuk.com>
Date2015-08-15 18:27 +0100
Message-ID<mqnsnd$2c5$1@dont-email.me>
In reply to#67454
On 15/08/2015 17:46, David Kleinecke wrote:
> One of the curious little problems encountered in making a C compiler
> is how to recognize labels.
>
> There is no problem in a two-pass compiler - but let me assume a one
> pass compiler.

Recognising labels isn't peculiar to C compilers, nor does it need 
multiple passes: parsers are usually done in a single pass.

> Then I am reading along compiling statements and I
> start a new statement and the first token in the statement is an
> identifier. Is this token a label?
...
> But this seems clumsy. I think a better way to go is to admit I am
> reading ahead one token.

That is not necessary. The way I wrote parsers (of the recursive descent 
sort, nothing unusual), when a syntactic element has been identified, 
the it is usually 'positioned' at the following symbol or token, ready 
for the next lot of parsing.

So if '(a+b),' has just been processed, you've recognised Expression, 
and the 'current' token will be whatever follows, Comma in this case.

In the case of reading a label, if Name has been seen, then you read the 
next token. If it's a colon, then you've identified a Label, and you 
read the following token (which determines what happens next).

If it isn't a colon, then return Name, and exit.

  When I discover this is not a label
>     ahead = true;
>     ahead_token = non-colon;
> And then I call the expression subroutine with the usual argument -
> the identifier - but ahead is now true. So the next_token call
> becomes
>     if(ahead) {
>        ahead = false;
>        token = ahead_token;}
>     else
>        token - next_token();
> or even
>     token = ahead ? ahead = false, ahead_token : next_token ();

You could also just write a Peek() function which tells you the next 
token without advancing the token pointer (which might well be 
implemented along the lines above, but it's easier to use).

> So far as I can tell this is the only place in the C syntax where
> such a device is needed.

Really? It's more like one of the few places it isn't needed!

Is 'A*B' an expression, or is it declaring a variable B of type 
pointer-to-A?

Is 'F(G)' a function call to G with argument G, or is it declaring a 
variable G of type F, or is it the start of function declaration, or the 
start of function definition?

I think you have your work cut out!

-- 
Bartc

[toc] | [prev] | [next] | [standalone]


#67484

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2015-08-15 23:44 +0100
Message-ID<874mk0goix.fsf@bsb.me.uk>
In reply to#67459
Bartc <bc@freeuk.com> writes:
<snip>
> Is 'A*B' an expression, or is it declaring a variable B of type
> pointer-to-A?
>
> Is 'F(G)' a function call to G with argument G, or is it declaring a
> variable G of type F, or is it the start of function declaration, or
> the start of function definition?
>
> I think you have your work cut out!

This makes it sound as if C is particularly hard to parse, but it isn't,
provided you know how to handle typedefs.  After reading a typedef, the
parser must mark the identifiers involved as referring to types.  This
can be as simple as a flag in the symbol table.  With that done, C can
be parsed using standard techniques to be found in any introductory text
on parsing.  New named types simply take on the same syntactic role as
type keywords like int.

If typedef names were your point, then it would have been better to be
more explicit (and give the solution?) rather than just saying "you've
got your work cut out".

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#67486

FromJames Kuyper <jameskuyper@verizon.net>
Date2015-08-15 19:04 -0400
Message-ID<55CFC58E.5090600@verizon.net>
In reply to#67484
On 08/15/2015 06:44 PM, Ben Bacarisse wrote:
> Bartc <bc@freeuk.com> writes:
> <snip>
>> Is 'A*B' an expression, or is it declaring a variable B of type
>> pointer-to-A?
>>
>> Is 'F(G)' a function call to G with argument G, or is it declaring a
>> variable G of type F, or is it the start of function declaration, or
>> the start of function definition?
>>
>> I think you have your work cut out!
> 
> This makes it sound as if C is particularly hard to parse, but it isn't,
> provided you know how to handle typedefs.  After reading a typedef, the
> parser must mark the identifiers involved as referring to types.

As earlier messages in this thread have shown, you can't always do that
immediately after parsing the identifier - the identifier could be a
statement label, and you have to read the next token after the
identifier to rule out that possibility. This doesn't strike me as a big
problem, but David Kleinecke finds it so.

None of the other kinds of identifiers can cause this problem:
definitions/declarations of the names of objects, functions, tags or
members of structs, unions, or enumerations, and typedefs all have at
least one of the tokens needed to identify them as such occurring before
the identifier.

[toc] | [prev] | [next] | [standalone]


#67492

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2015-08-16 00:47 +0100
Message-ID<87mvxsf713.fsf@bsb.me.uk>
In reply to#67486
James Kuyper <jameskuyper@verizon.net> writes:

> On 08/15/2015 06:44 PM, Ben Bacarisse wrote:
>> Bartc <bc@freeuk.com> writes:
>> <snip>
>>> Is 'A*B' an expression, or is it declaring a variable B of type
>>> pointer-to-A?
>>>
>>> Is 'F(G)' a function call to G with argument G, or is it declaring a
>>> variable G of type F, or is it the start of function declaration, or
>>> the start of function definition?
>>>
>>> I think you have your work cut out!
>> 
>> This makes it sound as if C is particularly hard to parse, but it isn't,
>> provided you know how to handle typedefs.  After reading a typedef, the
>> parser must mark the identifiers involved as referring to types.
>
> As earlier messages in this thread have shown, you can't always do that
> immediately after parsing the identifier - the identifier could be a
> statement label, and you have to read the next token after the
> identifier to rule out that possibility.

I'm taking about what the parse must do once it has parsed a full
typedef declarator.  I don't see any connection with the original issue
of labels.

> This doesn't strike me as a big
> problem, but David Kleinecke finds it so.

Yes, any introductory book on parsing will explain how to handle
look-ahead for languages like C.  They won't all explain the typedef
issue which is why I tried to explain it.

<snip>
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#67495

FromJames Kuyper <jameskuyper@verizon.net>
Date2015-08-15 20:20 -0400
Message-ID<55CFD75B.6020102@verizon.net>
In reply to#67492
On 08/15/2015 07:47 PM, Ben Bacarisse wrote:
> James Kuyper <jameskuyper@verizon.net> writes:
> 
>> On 08/15/2015 06:44 PM, Ben Bacarisse wrote:
>>> Bartc <bc@freeuk.com> writes:
>>> <snip>
>>>> Is 'A*B' an expression, or is it declaring a variable B of type
>>>> pointer-to-A?
>>>>
>>>> Is 'F(G)' a function call to G with argument G, or is it declaring a
>>>> variable G of type F, or is it the start of function declaration, or
>>>> the start of function definition?
>>>>
>>>> I think you have your work cut out!
>>>
>>> This makes it sound as if C is particularly hard to parse, but it isn't,
>>> provided you know how to handle typedefs.  After reading a typedef, the
>>> parser must mark the identifiers involved as referring to types.
>>
>> As earlier messages in this thread have shown, you can't always do that
>> immediately after parsing the identifier - the identifier could be a
>> statement label, and you have to read the next token after the
>> identifier to rule out that possibility.
> 
> I'm taking about what the parse must do once it has parsed a full
> typedef declarator.

So am I. I'm talking about a use of the typedef, not the declaration of
the typedef. After parsing the full typedef declarator, if you find an
identifier with the same name at the start of a new line, it could be
the first token of a declaration, or the first token of a labeled
statement, with a label that happens to be the same as the typedef name.
Therefore, you can't mark it as a type until you've read the next token
and determined that it's not ':'.

> ... I don't see any connection with the original issue
> of labels.

Until you read the following ':', you can't distinguish a label that has
the same name as a typedef from a typedef used as the first token of a
declaration. And that's one of the three reasons (the other two are
object names and function names) why the ':' must (in some cases) be
read before a statement label can be unambiguously identified as such.

>> This doesn't strike me as a big
>> problem, but David Kleinecke finds it so.
> 
> Yes, any introductory book on parsing will explain how to handle
> look-ahead for languages like C.  They won't all explain the typedef
> issue which is why I tried to explain it.

[toc] | [prev] | [next] | [standalone]


#67500

FromBartc <bc@freeuk.com>
Date2015-08-16 01:56 +0100
Message-ID<mqon12$20n$1@dont-email.me>
In reply to#67495
On 16/08/2015 01:20, James Kuyper wrote:
> On 08/15/2015 07:47 PM, Ben Bacarisse wrote:

>> ... I don't see any connection with the original issue
>> of labels.
>
> Until you read the following ':', you can't distinguish a label that has
> the same name as a typedef from a typedef used as the first token of a
> declaration. And that's one of the three reasons (the other two are
> object names and function names) why the ':' must (in some cases) be
> read before a statement label can be unambiguously identified as such.

You mean that a label can have the same name as a typedef within the 
same function scope?

Interesting. (And ... why?)

-- 
Bartc

[toc] | [prev] | [next] | [standalone]


#67518

FromKeith Thompson <kst-u@mib.org>
Date2015-08-15 19:47 -0700
Message-ID<lnbne87xuo.fsf@kst-u.example.com>
In reply to#67500
Bartc <bc@freeuk.com> writes:
> On 16/08/2015 01:20, James Kuyper wrote:
>> On 08/15/2015 07:47 PM, Ben Bacarisse wrote:
>
>>> ... I don't see any connection with the original issue
>>> of labels.
>>
>> Until you read the following ':', you can't distinguish a label that has
>> the same name as a typedef from a typedef used as the first token of a
>> declaration. And that's one of the three reasons (the other two are
>> object names and function names) why the ':' must (in some cases) be
>> read before a statement label can be unambiguously identified as such.
>
> You mean that a label can have the same name as a typedef within the 
> same function scope?

Yes.

> Interesting. (And ... why?)

An identifier is a label name if and only if appears either before the
":" in a labelled statement or it appears following a "goto" keyword, so
there's no ambiguity if a label name happens to match a non-label
identifier.  (Similarly, struct tags can only follow a "struct"
keyword.)

And since labels needn't be predeclared, it might be awkward to diagnose
conflicts if they weren't in their own namespace.  I haven't given that
a lot of though, so I'm not entirely sure about it.

Using the same identifier for a label and for something else is probably
a bad idea, but it's not forbidden, and I suspect that just makes the
compiler's job a little easier (something that would have been more
important when the language was designed).

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#67531

FromJames Kuyper <jameskuyper@verizon.net>
Date2015-08-16 11:59 -0400
Message-ID<55D0B37A.2070901@verizon.net>
In reply to#67518
On 08/15/2015 10:47 PM, Keith Thompson wrote:
> Bartc <bc@freeuk.com> writes:
...
>> You mean that a label can have the same name as a typedef within the 
>> same function scope?
> 
> Yes.

Pedantic details:
A label has function scope, and is the only kind of thing that can have
function scope; a typedef has either file scope or block scope depending
upon where it is declared. Two scopes are considered the "same scope" if
they end at the same place (6.2.1p5), even if they are different types
of scope. Therefore, a function scope can be the same scope as a block
scope, but only for the outermost block of a function. However, because
they are in different name spaces, the fact that a label and a typedef
could have the same scope never actually matters.

[toc] | [prev] | [next] | [standalone]


#67545

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2015-08-16 22:42 +0100
Message-ID<87614egbb1.fsf@bsb.me.uk>
In reply to#67495
James Kuyper <jameskuyper@verizon.net> writes:

> On 08/15/2015 07:47 PM, Ben Bacarisse wrote:
>> James Kuyper <jameskuyper@verizon.net> writes:
>> 
>>> On 08/15/2015 06:44 PM, Ben Bacarisse wrote:
>>>> Bartc <bc@freeuk.com> writes:
>>>> <snip>
>>>>> Is 'A*B' an expression, or is it declaring a variable B of type
>>>>> pointer-to-A?
>>>>>
>>>>> Is 'F(G)' a function call to G with argument G, or is it declaring a
>>>>> variable G of type F, or is it the start of function declaration, or
>>>>> the start of function definition?
>>>>>
>>>>> I think you have your work cut out!
>>>>
>>>> This makes it sound as if C is particularly hard to parse, but it isn't,
>>>> provided you know how to handle typedefs.  After reading a typedef, the
>>>> parser must mark the identifiers involved as referring to types.
>>>
>>> As earlier messages in this thread have shown, you can't always do that
>>> immediately after parsing the identifier - the identifier could be a
>>> statement label, and you have to read the next token after the
>>> identifier to rule out that possibility.
>> 
>> I'm taking about what the parse must do once it has parsed a full
>> typedef declarator.
>
> So am I. I'm talking about a use of the typedef, not the declaration of
> the typedef. After parsing the full typedef declarator, if you find an
> identifier with the same name at the start of a new line, it could be
> the first token of a declaration, or the first token of a labeled
> statement, with a label that happens to be the same as the typedef
> name.

[I think there may be confusion used by terms here.  I've left my reply
as it was typed and added a bit at the end to say what I think might be
causing the confusion.  That was the simplest way I could think of to
try to unravel what might, in fact, be total agreement.

I originally wrote:]

I'm a bit confused by the reference to a new line and your use of
declarator.  You need to mark the identifier right after seeing the
declarator (even before the declaration is over) in order to parse
subsequent declarators in the same declaration, for example,

  typedef int *ip, func(ip);

> Therefore, you can't mark it as a type until you've read the next token
> and determined that it's not ':'.

Having marked ip as a typedef name does not mean that you must ignore
the possibility that it might be used in other contexts (as a label
being one).  But I don't see how you can delay marking it as being a
typedef name -- and certainly not until you see it used without
following a ':'.

[Then it occurred to that you are using the word "mark" differently.  I
was referring to the trick of setting a flag in the symbol table to say
"this name has been the subject of a typedef declaration -- if you see
it where a type keyword makes sense, it is one".  I think you are
using it to mean "decide that an identifier is a typedef name".]

<snip>
-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#67555

FromJames Kuyper <jameskuyper@verizon.net>
Date2015-08-16 20:39 -0400
Message-ID<mqracn$cr5$1@dont-email.me>
In reply to#67545
On 08/16/2015 05:42 PM, Ben Bacarisse wrote:
> James Kuyper <jameskuyper@verizon.net> writes:
...
>> So am I. I'm talking about a use of the typedef, not the declaration of
>> the typedef. After parsing the full typedef declarator, if you find an
>> identifier with the same name at the start of a new line, it could be
>> the first token of a declaration, or the first token of a labeled
>> statement, with a label that happens to be the same as the typedef
>> name.
> 
> [I think there may be confusion used by terms here.  I've left my reply
> as it was typed and added a bit at the end to say what I think might be
> causing the confusion.  That was the simplest way I could think of to
> try to unravel what might, in fact, be total agreement.
> 
> I originally wrote:]
> 
> I'm a bit confused by the reference to a new line and your use of
> declarator.  You need to mark the identifier right after seeing the
> declarator (even before the declaration is over) in order to parse
> subsequent declarators in the same declaration, for example,
> 
>   typedef int *ip, func(ip);
>
>> Therefore, you can't mark it as a type until you've read the next token
>> and determined that it's not ':'.
> 
> Having marked ip as a typedef name does not mean that you must ignore
> the possibility that it might be used in other contexts (as a label
> being one).  But I don't see how you can delay marking it as being a
> typedef name -- and certainly not until you see it used without
> following a ':'.
> 
> [Then it occurred to that you are using the word "mark" differently.  I
> was referring to the trick of setting a flag in the symbol table to say
> "this name has been the subject of a typedef declaration -- if you see
> it where a type keyword makes sense, it is one".  I think you are
> using it to mean "decide that an identifier is a typedef name".]

Example code:

void func(void)		// 1
{			// 2
    typedef int Int;	// 3
    Int x;		// 4
    Int:		// 5

What I'm saying is that while parsing lines 4 and 5 of that example, the
compiler cannot mark 'Int' as a type until it has read the next token.
In line 4, that token is 'x', and Int is therefore a typedef. In the
line 5, that token is ':', which means that Int is a label. It's
precisely the fact that the next token has to be read, which was the
reason for David's message that started this thread.

I gather that you've been referring the parsing of "Int" in Line 3, but
that has nothing to do with anything David or I have been talking about.
In particular, the message you posted with the header
	Date: Sat, 15 Aug 2015 23:44:38 +0100
said "New named types simply take on the same syntactic role as type
keywords like int." That's not true, because keywords can be marked as
such regardless of context, while a typedef name, as shown above, needs
some of it's following context parsed as well, in order to unambiguously
identify it as a typedef. Also, unlike keywords, typedefs have scopes
that need to be taken into consideration.
-- 
James Kuyper

[toc] | [prev] | [next] | [standalone]


#67557

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2015-08-17 03:16 +0100
Message-ID<87pp2mek20.fsf@bsb.me.uk>
In reply to#67555
James Kuyper <jameskuyper@verizon.net> writes:

> On 08/16/2015 05:42 PM, Ben Bacarisse wrote:
>> James Kuyper <jameskuyper@verizon.net> writes:
> ...
>>> So am I. I'm talking about a use of the typedef, not the declaration of
>>> the typedef. After parsing the full typedef declarator, if you find an
>>> identifier with the same name at the start of a new line, it could be
>>> the first token of a declaration, or the first token of a labeled
>>> statement, with a label that happens to be the same as the typedef
>>> name.
>> 
>> [I think there may be confusion used by terms here.  I've left my reply
>> as it was typed and added a bit at the end to say what I think might be
>> causing the confusion.  That was the simplest way I could think of to
>> try to unravel what might, in fact, be total agreement.
>> 
>> I originally wrote:]
>> 
>> I'm a bit confused by the reference to a new line and your use of
>> declarator.  You need to mark the identifier right after seeing the
>> declarator (even before the declaration is over) in order to parse
>> subsequent declarators in the same declaration, for example,
>> 
>>   typedef int *ip, func(ip);
>>
>>> Therefore, you can't mark it as a type until you've read the next token
>>> and determined that it's not ':'.
>> 
>> Having marked ip as a typedef name does not mean that you must ignore
>> the possibility that it might be used in other contexts (as a label
>> being one).  But I don't see how you can delay marking it as being a
>> typedef name -- and certainly not until you see it used without
>> following a ':'.
>> 
>> [Then it occurred to that you are using the word "mark" differently.  I
>> was referring to the trick of setting a flag in the symbol table to say
>> "this name has been the subject of a typedef declaration -- if you see
>> it where a type keyword makes sense, it is one".  I think you are
>> using it to mean "decide that an identifier is a typedef name".]
>
> Example code:
>
> void func(void)		// 1
> {			// 2
>     typedef int Int;	// 3
>     Int x;		// 4
>     Int:		// 5
>
> What I'm saying is that while parsing lines 4 and 5 of that example, the
> compiler cannot mark 'Int' as a type until it has read the next token.
> In line 4, that token is 'x', and Int is therefore a typedef. In the
> line 5, that token is ':', which means that Int is a label. It's
> precisely the fact that the next token has to be read, which was the
> reason for David's message that started this thread.

We are certainly using "marked" in different ways.  The compiler must
make a note that Int has been typedefed (if I can invent that verb) as
soon as it sees the declarator.  After line 5 the parser must see Int as
both a label and a typedef name -- it can take on either role.

> I gather that you've been referring the parsing of "Int" in Line 3, but
> that has nothing to do with anything David or I have been talking about.
> In particular, the message you posted with the header
> 	Date: Sat, 15 Aug 2015 23:44:38 +0100
> said "New named types simply take on the same syntactic role as type
> keywords like int." That's not true, because keywords can be marked as
> such regardless of context, while a typedef name, as shown above, needs
> some of it's following context parsed as well, in order to unambiguously
> identify it as a typedef. Also, unlike keywords, typedefs have scopes
> that need to be taken into consideration.

Yes, the phrase of mine you quote is an oversimplification.  New named
types take on the *possibility* of acting like type keywords.  They
don't always behave like them.  I should not have put it like that.  You
can use a typedefed identifier in all sorts of places -- not just as a
label:

  struct Int { ... };

of even

  Int Int = 42;

-- 
Ben.

[toc] | [prev] | [next] | [standalone]


#67510

FromDavid Kleinecke <dkleinecke@gmail.com>
Date2015-08-15 19:01 -0700
Message-ID<ccf4fb6e-74d4-4b84-904a-b73a578ea575@googlegroups.com>
In reply to#67486
On Saturday, August 15, 2015 at 4:04:58 PM UTC-7, James Kuyper wrote:
> On 08/15/2015 06:44 PM, Ben Bacarisse wrote:
> > Bartc <bc@freeuk.com> writes:
> > <snip>
> >> Is 'A*B' an expression, or is it declaring a variable B of type
> >> pointer-to-A?
> >>
> >> Is 'F(G)' a function call to G with argument G, or is it declaring a
> >> variable G of type F, or is it the start of function declaration, or
> >> the start of function definition?
> >>
> >> I think you have your work cut out!
> > 
> > This makes it sound as if C is particularly hard to parse, but it isn't,
> > provided you know how to handle typedefs.  After reading a typedef, the
> > parser must mark the identifiers involved as referring to types.
> 
> As earlier messages in this thread have shown, you can't always do that
> immediately after parsing the identifier - the identifier could be a
> statement label, and you have to read the next token after the
> identifier to rule out that possibility. This doesn't strike me as a big
> problem, but David Kleinecke finds it so.
 
I called it a curious little problem.

> None of the other kinds of identifiers can cause this problem:
> definitions/declarations of the names of objects, functions, tags or
> members of structs, unions, or enumerations, and typedefs all have at
> least one of the tokens needed to identify them as such occurring before
> the identifier.

[toc] | [prev] | [next] | [standalone]


#67494

FromBartc <bc@freeuk.com>
Date2015-08-16 01:11 +0100
Message-ID<mqokd9$qv5$1@dont-email.me>
In reply to#67484
On 15/08/2015 23:44, Ben Bacarisse wrote:
> Bartc <bc@freeuk.com> writes:
> <snip>
>> Is 'A*B' an expression, or is it declaring a variable B of type
>> pointer-to-A?
>>
>> Is 'F(G)' a function call to G with argument G, or is it declaring a
>> variable G of type F, or is it the start of function declaration, or
>> the start of function definition?
>>
>> I think you have your work cut out!
>
> This makes it sound as if C is particularly hard to parse, but it isn't,

I was making the point that if the OP thought detecting labels was 
tricky, then other bits of syntax are worse. (I think labels are 
straightforward because you only have to look one symbol ahead, and you 
don't necessarily have to put back that symbol/token if it's not a colon.)

(FWIW I think C /is/ harder to parse compared with the syntaxes I come 
up with. Perhaps more so for humans, with some bits of obscure syntax.)

> provided you know how to handle typedefs.  After reading a typedef, the
> parser must mark the identifiers involved as referring to types.  This
> can be as simple as a flag in the symbol table.  With that done, C can
> be parsed using standard techniques to be found in any introductory text
> on parsing.  New named types simply take on the same syntactic role as
> type keywords like int.

With user-defined typedef names you can't rely on the 'shape' of the 
syntax, but do need this bit of name resolution that otherwise could be 
left until a later pass. (With F(G), F might appear as both a function 
name and a typedef name, but in different scopes; this then forces your 
hand in having the symbol table operate a certain way.)

But even knowing a starter symbol is a typedef name, then with 'T(' you 
might still be a long way from knowing if this is a simple variable 
declaration, or the start of a 1000-line function definition.

-- 
Bartc

[toc] | [prev] | [next] | [standalone]


#67507

FromKeith Thompson <kst-u@mib.org>
Date2015-08-15 19:13 -0700
Message-ID<ln4mk09e0k.fsf@kst-u.example.com>
In reply to#67494
Bartc <bc@freeuk.com> writes:
[...]
> But even knowing a starter symbol is a typedef name, then with 'T(' you 
> might still be a long way from knowing if this is a simple variable 
> declaration, or the start of a 1000-line function definition.

At block scope, function definitions are not permitted.  At file scope,
a function definition cannot start with 'T('; it requires at least a
type name and an identifier.  At least that's the case since C99 -- and
on the other hand, some (most?) compilers use a C90-compatible grammar
that permits implicit-int definitions and diagnoses them separately.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#67521

FromBartc <bc@freeuk.com>
Date2015-08-16 10:34 +0100
Message-ID<mqplbf$ipu$1@dont-email.me>
In reply to#67507
On 16/08/2015 03:13, Keith Thompson wrote:
> Bartc <bc@freeuk.com> writes:
> [...]
>> But even knowing a starter symbol is a typedef name, then with 'T(' you
>> might still be a long way from knowing if this is a simple variable
>> declaration, or the start of a 1000-line function definition.
>
> At block scope, function definitions are not permitted.  At file scope,
> a function definition cannot start with 'T('; it requires at least a
> type name and an identifier.

The following seems to be legal:

#include <stdio.h>

typedef int T;

T(main)(void) {
    printf("Hello World\n");
}

-- 
Bartc

[toc] | [prev] | [next] | [standalone]


#67544

FromKeith Thompson <kst-u@mib.org>
Date2015-08-16 13:58 -0700
Message-ID<ln7fov7xxw.fsf@kst-u.example.com>
In reply to#67521
Bartc <bc@freeuk.com> writes:
> On 16/08/2015 03:13, Keith Thompson wrote:
>> Bartc <bc@freeuk.com> writes:
>> [...]
>>> But even knowing a starter symbol is a typedef name, then with 'T(' you
>>> might still be a long way from knowing if this is a simple variable
>>> declaration, or the start of a 1000-line function definition.
>>
>> At block scope, function definitions are not permitted.  At file scope,
>> a function definition cannot start with 'T('; it requires at least a
>> type name and an identifier.
>
> The following seems to be legal:
>
> #include <stdio.h>
>
> typedef int T;
>
> T(main)(void) {
>     printf("Hello World\n");
> }

Interesting, so it is.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"

[toc] | [prev] | [next] | [standalone]


#67559

FromDavid Kleinecke <dkleinecke@gmail.com>
Date2015-08-16 20:42 -0700
Message-ID<c7547393-536e-4169-87e9-bf4fa5fc4c49@googlegroups.com>
In reply to#67521
On Sunday, August 16, 2015 at 2:34:31 AM UTC-7, Bart wrote:
> On 16/08/2015 03:13, Keith Thompson wrote:
> > Bartc <bc@freeuk.com> writes:
> > [...]
> >> But even knowing a starter symbol is a typedef name, then with 'T(' you
> >> might still be a long way from knowing if this is a simple variable
> >> declaration, or the start of a 1000-line function definition.
> >
> > At block scope, function definitions are not permitted.  At file scope,
> > a function definition cannot start with 'T('; it requires at least a
> > type name and an identifier.
> 
> The following seems to be legal:
> 
> #include <stdio.h>
> 
> typedef int T;
> 
> T(main)(void) {
>     printf("Hello World\n");
> }
> 
> -- 
> Bartc

It is my understanding that typedefs are not actual types but rather 
a kind of alsias for the type they are defined as. Hence
   typedef int T;
makes
   T main ....
compile eactly as if you had written
   int main ...

The compiler must maintain internally a table of what typedef names
mean. The meaning part of that table is a (possibly very complicated)
expression in non-typedef types and their decoration.  

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.c


csiph-web