[cfe-dev] [PATCH] C++ nested-name-specifier (Parser)

Argiris Kirtzidis akyrtzi at gmail.com
Sat Aug 9 16:49:44 PDT 2008


Chris Lattner wrote:
>
>> The attached 'pp-caching' patch, modifies Preprocessor::LookAhead 
>> (making it efficient enough to replace LookNext) and adds 'rewinding' 
>> functionality.
>> That is, one can call Preprocessor::EnableRewindAtThisPos, lex and 
>> consume any number of tokens, and later call Preprocessor::Rewind to 
>> make the preprocessor re-lex the tokens that were previsouly lexed 
>> since EnableRewindAtThisPos was called.
>
> I think we will need this functionality (aka 'tentative parsing' or 
> 'backtracking') at some point, but I'm not sure why we need it for 
> this.  As a prolog, I haven't dug into the part of the spec, so if I'm 
> missing something obvious, please be gentle on me :)

This is not a requirement of the spec, it just simplifies the parser in 
a similar way to how introducing NextToken() simplified it.

>
> My basic understanding (again, based on intuition, not reading of the 
> spec) of scope resolution was that it could actually be implemented 
> without lookahead.  My thought was that if you see ::A::B or A::B that 
> you start by looking up the ::A /A part and decide what it 
> references.  when looking up A, consider if it resolves to a 
> namespace.  My though would be that the parser invokes an action to 
> look up the decl corresponding to A.
>
> Options are that it could either be:
> 1) typedef name
> 2) variable/ivar/etc
> 3) namespace
> 4) struct
> ...
>
> One ::A is looked up, based on what the action returns, my assumption 
> is that the parser would see the next :: and do a subscope lookup.  
> Basically it would parse "::B" and then invoke an action to look up 
> ::B in the decl returned by the ::A lookup.  At some point presumably, 
> you end up with a type or a variable etc, which we'd need to treat as 
> the start of a declspec etc.  One nice thing about this is that it 
> would not require the parser to build up an explicit 'CXXScopeSpec' 
> object, Sema could build it if it wanted, but it wouldn't be required.

As far as the spec is concerned, you basically want to do something like 
this:

-You have "A::B"
-Parse "A::", not just 'A'. This is because "A::" indicates 
nested-name-specifier, and you want to do a specialized name lookup for 
nested-names. This specialized lookup will only consider 
classes/namespaces and ignore the rest. For example:

namespace A { int x; }
void f() {
   int A;
   A::x = 0;  // We don't want 'A' lookup to return 'int A' here, we 
want the namespace A.
}

-Now parse "B" and lookup 'B' in the scope of 'A'.

> Is this approach achievable?  I'd prefer to avoid parsing and 
> rewinding unless absolutely necessary. 

The advantage of the rewinding part is that there's no need for the 
Parser or Sema to keep and look after a 'C++ scoping' state (a state 
that is not just local to functions, but part of the Parser/Sema class).
This also means that we can drop the rewinding part if the Parser or 
Sema keep and look after a 'C++ scoping' state.
If the Parser keeps the state, it will build and pass 'CXXScopeSpec' 
objects to action methods, (like in my patch).
If the Sema keeps the state, it will make error recovery awkward. For 
example:

namespace A{}
A:: ;  // Oops, forgot an identifier before ';'

-Parser calls ActOnNestedNameSpecifier for "A::"
-Sema goes into "look identifiers in namespace A" mode
-Parsing error at ';'

How should Sema know that it should go back into normal lookup mode ?


And about the preprocessor changes: Is it ok to commit them, and is it 
more intuitive to change 'Rewind' to 'Backtrack' ?


-Argiris



More information about the cfe-dev mailing list