bug-bison
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Enhancement request: enabling Variant in C parsers


From: Akim Demaille
Subject: Re: Enhancement request: enabling Variant in C parsers
Date: Sat, 18 Aug 2018 06:12:50 +0200

Hi!

Please, keep the CCs.

> Le 17 août 2018 à 22:43, Victor Khomenko <address@hidden> a écrit :
> 
> Hi Akim,
> My main concern is memory management. With Variant the destructors are called 
> automatically, but in C parsers I currently have to use %union with pointers 
> and explicit "delete". This is not exception-safe and results in ugly code 
> littered with "delete" statements. (Using api.value.type is not good enough 
> as it makes the types monolithic, so I’d have to select the corresponding 
> members manually.)

I don’t understand what you mean here, by monolithic.  The parser needs a 
single type to store all the possible types, so, yes, it is monolithic.


> I don’t want to go all the way to C++ parsers for the reasons explained in my 
> previous email.

So you can’t expect the C++ features to work properly.

You wrote:

> * I (and probably some other people) find some aspects of C++ parsers 
> unwieldy, so prefer the good old C parsers in my C++ programs.

You’d have to provide more details.  I don’t think there is much to change to 
make to move to a C++ parser.

> So I'd like to use Variant to represent %union, but otherwise I want an old 
> C-style parser. This will be ok for C++ compilers.
> 
> Below is a motivating piece of code - with variants I'd just use object types 
> rather than pointers in %union, replace "->" by ".", remove the "delete" 
> statements, and use move-assignments instead of pointer assignments.
> 
> Regards,
> Victor.  
> 
> 
> [...]
>       | exp '?' exp ':' exp   {
>                                       if($1->type_c.type!=t_bool){
>                                               report_error(&@1,"Type mismatch 
> in '?:': the condition must be Boolean");
>                                               delete $1;
>                                               delete $3;
>                                               delete $5;
>                                               YYERROR;
>                                       }

Your code is not typical.  Traditionally you build an AST in the parser, and 
process the tree elsewhere.  That’s why you have so many deletes imho.  Using 
the syntax_error exception, you could still raise a syntax error, as if it were 
from YYERROR, but from your routine (however, I don’t think type errors should 
be handled by the parser).

Cheers!

>                                       else if($3->type_c.type==t_fail || 
> $5->type_c.type==t_fail){
>                                               if(!$1->type_c.is_const){
>                                                       report_error(&@1,"The 
> condition of '?:' must be constant if the 'then' or 'else' expressions are of 
> type fail");
>                                                       delete $1;
>                                                       delete $3;
>                                                       delete $5;
>                                                       YYERROR;
>                                               }
>                                               else if($3->type_c.type!=t_bool 
> && $5->type_c.type!=t_bool && (!$1->type_c.is_const || !$3->type_c.is_const 
> || !$5->type_c.is_const)){
>                                                       report_error(&@$,"The 
> operands of '?:' must be either Boolean or constant");
>                                                       delete $1;
>                                                       delete $3;
>                                                       delete $5;
>                                                       YYERROR;
>                                               }
>                                               else{
>                                                       exp_data* failed=$3;
>                                                       $$=$5;
>                                                       
> if($3->type_c.type!=t_fail){ failed=$5; $$=$3; }
>                                                       
> $$->expr=ReachExpIf(move($1->expr),move($3->expr),move($5->expr));
>                                                       $$->type_c.is_const &= 
> $1->type_c.is_const;
>                                                       $$->type_c.is_const &= 
> failed->type_c.is_const;
>                                                       delete $1;
>                                                       delete failed;
>                                               }
>                                       }
>                                       else 
> if($3->type_c.type!=$5->type_c.type){
>                                               YYLTYPE address@hidden;
>                                               address@hidden;
>                                               address@hidden;

(Using C++ location, there’s a bunch of code that would easily go away)

>                                               report_error(&buf_loc,"Type 
> mismatch in '?:': the 'then' and 'else' expressions must be of the same 
> type");
>                                               delete $1;
>                                               delete $3;
>                                               delete $5;
>                                               YYERROR;
>                                       }
>                                       else if($3->type_c.type!=t_bool && 
> $5->type_c.type!=t_bool && (!$1->type_c.is_const || !$3->type_c.is_const || 
> !$5->type_c.is_const)){
>                                               report_error(&@$,"The operands 
> of '?:' must be either Boolean or constant");
>                                               delete $1;
>                                               delete $3;
>                                               delete $5;
>                                               YYERROR;
>                                       }
>                                       else{
>                                               
> $3->expr=ReachExpIf(move($1->expr),move($3->expr),move($5->expr));
>                                               $3->type_c.is_const &= 
> $1->type_c.is_const;
>                                               $3->type_c.is_const &= 
> $5->type_c.is_const;
>                                               delete $1;
>                                               delete $5;
>                                               $$=$3;
>                                       }
>                               }
> 
> [...]
> 
> 
> 
> 
> 
> 
>> -----Original Message-----
>> From: Akim Demaille <address@hidden>
>> Sent: Friday, August 17, 2018 6:56 PM
>> To: Victor Khomenko <address@hidden>
>> Cc: Bison Bugs <address@hidden>
>> Subject: Re: Enhancement request: enabling Variant in C parsers
>> 
>> Hi!
>> 
>>> Le 12 juil. 2016 à 23:12, Victor Khomenko
>> <address@hidden> a écrit :
>>> 
>>> Dear developers,
>>> 
>>> It would be nice to enable Variant in C parsers - these obviously have to be
>> compiled with a C++ compiler.
>>> 
>>> Motivation:
>>> * I (and probably some other people) find some aspects of C++ parsers
>> unwieldy, so prefer the good old C parsers in my C++ programs.
>>> * Maintaining/refactoring existing C parsers using variants is
>> straightforward, whereas rewriting them as C++ parsers requires much effort.
>>> 
>>> Apologies if this was discussed earlier - I didn’t find anything relevant 
>>> in the
>> mail archives though.
>> 
>> Yes, the answer is quite late…  I’m trying to catch up…
>> 
>> I do not understand what you mean: the raison d’être of variants is C++, and
>> C++ only.  Was that sentence proper English?  Lemme try again.  Variants were
>> introduce because C++ forbid to put objects into unions (roughly).  And 
>> variants
>> are objects, so that doesn’t make sense in C.
>> 
>> So maybe it’s something else that you like.  For instance I do like not to 
>> have to
>> use %union and be able to use types directly.  You can do that in C, just 
>> look at
>> the examples from NEWS for instance:
>> 
>>> ** Variable api.value.type
>>> 
>>>  This new %define variable supersedes the #define macro YYSTYPE.  The use
>>>  of YYSTYPE is discouraged.  In particular, #defining YYSTYPE *and* either
>>>  using %union or %defining api.value.type results in undefined behavior.
>>> 
>>>  Either define api.value.type, or use "%union":
>>> 
>>>    %union
>>>    {
>>>      int ival;
>>>      char *sval;
>>>    }
>>>    %token <ival> INT "integer"
>>>    %token <sval> STRING "string"
>>>    %printer { fprintf (yyo, "%d", $$); } <ival>
>>>    %destructor { free ($$); } <sval>
>>> 
>>>    /* In yylex().  */
>>>    yylval.ival = 42; return INT;
>>>    yylval.sval = "42"; return STRING;
>>> 
>>>  The %define variable api.value.type supports both keyword and code values.
>>> 
>>>  The keyword value 'union' means that the user provides genuine types, not
>>>  union member names such as "ival" and "sval" above (WARNING: will fail if
>>>  -y/--yacc/%yacc is enabled).
>>> 
>>>    %define api.value.type union
>>>    %token <int> INT "integer"
>>>    %token <char *> STRING "string"
>>>    %printer { fprintf (yyo, "%d", $$); } <int>
>>>    %destructor { free ($$); } <char *>
>>> 
>>>    /* In yylex().  */
>>>    yylval.INT = 42; return INT;
>>>    yylval.STRING = "42"; return STRING;
>>> 
>> 
>> If what you like is symbol constructors, i.e., this:
>> 
>>> *** %define api.token.constructor
>>> 
>>>  When variants are enabled, Bison can generate functions to build the
>>>  tokens.  This guarantees that the token type (e.g., NUMBER) is consistent
>>>  with the semantic value (e.g., int):
>>> 
>>>    parser::symbol_type yylex ()
>>>    {
>>>      parser::location_type loc = ...;
>>>      ...
>>>      return parser::make_TEXT ("Hello, world!", loc);
>>>      ...
>>>      return parser::make_NUMBER (42, loc);
>>>      ...
>>>      return parser::make_SEMICOLON (loc);
>>>      ...
>>>    }
>> 
>> then I agree with you: this is an interesting concept that could exist in C 
>> too.
>> And in C++ without variants.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]