Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #67454 > unrolled thread
| Started by | David Kleinecke <dkleinecke@gmail.com> |
|---|---|
| First post | 2015-08-15 09:46 -0700 |
| Last post | 2015-08-15 19:00 -0700 |
| Articles | 20 on this page of 26 — 5 participants |
Back to article view | Back to comp.lang.c
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 →
| From | David Kleinecke <dkleinecke@gmail.com> |
|---|---|
| Date | 2015-08-15 09:46 -0700 |
| Subject | Labels |
| 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]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2015-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]
| From | David Kleinecke <dkleinecke@gmail.com> |
|---|---|
| Date | 2015-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]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-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]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2015-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-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]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2015-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]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-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]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-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]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2015-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-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]
| From | James Kuyper <jameskuyper@verizon.net> |
|---|---|
| Date | 2015-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-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]
| From | David Kleinecke <dkleinecke@gmail.com> |
|---|---|
| Date | 2015-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]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-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]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-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]
| From | Bartc <bc@freeuk.com> |
|---|---|
| Date | 2015-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]
| From | Keith Thompson <kst-u@mib.org> |
|---|---|
| Date | 2015-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]
| From | David Kleinecke <dkleinecke@gmail.com> |
|---|---|
| Date | 2015-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