On Sep 28, 2011, at 6:46 PM, Aaron Ballman wrote:

> On Fri, Sep 23, 2011 at 3:23 PM, Douglas Gregor <[email protected]> wrote:
>> 
>> On Sep 23, 2011, at 1:22 PM, Aaron Ballman wrote:
>> 
>>> On Fri, Sep 23, 2011 at 1:35 PM, Douglas Gregor <[email protected]> wrote:
>>>> 
>>>> On Sep 21, 2011, at 8:45 PM, Aaron Ballman wrote:
>>>> 
>>>>> On Wed, Sep 21, 2011 at 8:11 PM, Eli Friedman <[email protected]> 
>>>>> wrote:
>>>>>>> Also, the diagnostic wording was taken from MSVC, but could likely be
>>>>>>> improved.  Suggestions welcome.
>>>>>> 
>>>>>> I would say something more along the lines of "parser recusion limit
>>>>>> reached"; using the term "stack overflow" makes it sound like a bug in
>>>>>> the compiler.
>>>>> 
>>>>> Here is a revised patch with the new diagnostic wording.
>>>> 
>>>> Minor stuff: there's a typo "recusion" in the diagnostic wording, and the 
>>>> new test case hasn't been updated for the new wording.
>>> 
>>> Good catches!
>>> 
>>>> I like this general direction, but I do wonder about adding another RAII 
>>>> object for this. You've added the RAII object in two places, but aren't 
>>>> there many other similar places? Can we be more methodical, so we can be 
>>>> sure that we don't lose the benefits of this checking with later 
>>>> maintenance?
>>> 
>>> The intention was to see if folks liked the direction, and then add it
>>> to more places.  Why add it everywhere under the sun if people think
>>> it is the wrong way to solve the problem?
>>> 
>>>> I have one idea: what if we expanded the mandate of this RAII object a 
>>>> bit, so that it was responsible for both balancing the delimiters 
>>>> (parentheses, square brackets, braces, etc.)? In other words, we introduce 
>>>> the RAII object to consume the opening paren/bracket/brace and also to 
>>>> find the matching ')':
>>> 
>>> When I started out, I had intended this to have a bit more to do with
>>> [implimits].  But what I ended up with is really is about depth of
>>> recursion in the parser.  Without further accessors, it's not useful
>>> for iterative limit checking (such as the number of constants in an
>>> enumeration).  But do we care?
>> 
>> Probably not. We should be able to handle 'lots' of enumerators. Recursion 
>> is really the killer for us, since we have limited stack space (and Clang 
>> uses a lot of it).
>> 
>>>>  BalancedDelimiterTracket Parens(*this, tok::l_paren); // tries to consume 
>>>> the opening '('
>>>>  if (!Parens) // checks whether an error occurred in consuming the opening 
>>>> ')'
>>>>    return error;
>>>> 
>>>>  // parse whatever is in the parens
>>>> 
>>>>  if (Parens.close()) { // tries to consume the closing ')'
>>>>    // couldn't find closing ')'
>>>>  }
>>>> 
>>>> The idea here would be to encapsulate all of the behavior that now uses 
>>>> MatchRHSPunctuation into an RAII object, and have that also check for 
>>>> implementation limits. There are three benefits here:
>>>> 
>>>>  (1) It becomes clearer where we're matching delimited sets, so the 
>>>> structure of the parser improves in general.
>>>>  (2) Implementation limits checking comes "free" when we use the right 
>>>> abstraction, so it won't be forgotten or lost.
>>>>  (3) These RAII objects, in aggregate, outline the source as we're parsing 
>>>> it. We should be able to use that information to improve parser recovery.
>>>> 
>>>> What do you think?
>>> 
>>> I think I'll play around with the idea and get back to you.  :-)  On
>>> its face, it sounds like a clean way to go about it, so I'll see if it
>>> works in practice as well.  Thank you for the idea!
>> 
>> Great! I'm looking forward to your next patch.
> 
> Going off Douglas' suggestions, I've created a new patch for parsing
> balanced delimiters.
> 
> There is a Parser::DelimiterTracker class which is responsible for
> tracking the "depth" any individual delimiter is at.  The parser owns
> an instance of this class.  There is a
> Parser::BalancedDelimiterTracker class which is used by the parsing
> methods to navigate the balanced delimiters.  It works in conjunction
> with the Parser::DelimiterTracker so that we can track recursion
> limits.  The class comes with three methods: consumeOpen,
> expectAndConsume and consumeClose.
> 
> I've refactored all occurrences of MatchRHSPunctuation to now use a
> BalancedDelimiterTracker object instead.  Due to this, I've removed
> the MatchRHSPunctuation function entirely.

Excellent.

> I've tested this patch against the test suite and all tests continue
> to behave as expected.  I've also checked to make sure this doesn't
> regress performance, and it hasn't.
> 
> This patch does still address bug 10332, and contains a test case for
> it as well.


A few comments below.

+  class DelimiterTracker {
+  private:
+    friend class Parser;
+
+    unsigned P, B, S, L, LLL, T;

Some more-descriptive variable names would be useful here :)

+    BalancedDelimiterTracker(Parser& p, tok::TokenKind k);
+    ~BalancedDelimiterTracker();
+
+    bool consumeOpen(SourceLocation *open) const;
+    bool expectAndConsume(SourceLocation *open, 
+                           unsigned DiagID, 
+                           const char *Msg = "", 
+                           tok::TokenKind SkipToTok = tok::unknown) const;
+    bool consumeClose(const SourceLocation& open, SourceLocation *close) const;
+  };

I'd prefer that we keep the open/close source locations within 
BalancedDelimiterTracker, which would simplify the interface a bit, since 
*every* user of BalancedDelimiterTracker needs to track this information anyway.

Otherwise, this looks great. Thanks for working on it!

        - Doug
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to