[Prev][Next][Index]

Re: sage confused by complicated function type



This bug is an example of the (in)famous C++ grammar ambiguity
involving expression-statements and declarations. The ambiguity is
between function-style explicit type conversions (i.e., casts) and 

declarations. 

In general, backtracking (and infinite lookahead) are needed
to resolve those ambiguities (see section 6.8, pp. 93-94 of ARM for  
more details).
Backtracking is not an easy thing to do with a yacc parser and the  
yacc-based C++ parsers that I know and that can do it  accomplish it  
by doing a recursive-descent parse (with backtracking) right in the  
lexer. 

Needless to say, our current parser does not. An interesting bit of  
trivia (that I was actually not aware of until now) is that our  
parser picks one of the two possibilities in a quite "creative" way.  
Here's what I mean: 


int i = int(1.2);    // can't do this because for built-in types
                     // the declaration is always picked, 

                     //function-style casts are not allowed
foo(int(*fp)(int));  //fine

class A{
 public:
    A(double){}
};

A a = A(1.2);        // fine, for user-defined types (that also
                     // includes typedefs) expression-statement is
                     // picked
//foo(A(*fp)(int));  // parse error

As for the reason for such non-uniform behavior, I suspect that it  
has something to do with parsing pC++ (as opposed to plain C++), but  
maybe Dennis (or Pete when he comes back from vacation) could confirm  
that. Below is a relevant fragment of the y++.y file: 


expr_no_commas:
/*       basic_type_name '(' expr ')'  /* my new rule. dbg */
/*            { $$=installLowLevelNode(CAST_OP,$3,LLNULL,SMNULL);
              NODE_TYPE($$) = map_rid_to_type($1);
            }
REMOVED by PHB, was causing '(' parmlist ')' problems */       

        THROW
            { $$=installLowLevelNode(THROW_OP,LLNULL,LLNULL,SMNULL);
            }
        

       | THROW expr_no_commas %prec UNARY
            { $$=installLowLevelNode(THROW_OP,$2,LLNULL,SMNULL);
            }
     /* the following will cause the same conflict that pete found */
     /* that is, int foo(A (*f)()) will not parse correctly */
       | TYPENAME '(' exprlist ')'  

            { PTR_SYMB symb2;
              PTR_TYPE type2;
	      PTR_LLND ll2;
	      if($3) ll2 = $3;
	      else ll2 =  
installLowLevelNode(EXPR_LIST,LLNULL,LLNULL,SMNULL);
	      $$=installLowLevelNode(CAST_OP,ll2,LLNULL,SMNULL);
              symb2= find_type_symbol($1,TYPE_NAME,area());
              type2= (PTR_TYPE) newNode(T_DERIVED_TYPE);
              TYPE_SYMB_DERIVE(type2) = (PTR_SYMB) symb2;
              NODE_TYPE($$) = type2;
            }
       | TYPENAME '(' exprlist ')' '.' identifier 

            { 

             ...


--Beata