Hi! Please, keep the CCs.
> Le 17 août 2018 à 22:43, Victor Khomenko <victor.khome...@newcastle.ac.uk> 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 buf_loc=@3; > buf_loc.last_line=@5.last_line; > > buf_loc.last_column=@5.last_column; (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 <a...@lrde.epita.fr> >> Sent: Friday, August 17, 2018 6:56 PM >> To: Victor Khomenko <victor.khome...@newcastle.ac.uk> >> Cc: Bison Bugs <bug-bison@gnu.org> >> Subject: Re: Enhancement request: enabling Variant in C parsers >> >> Hi! >> >>> Le 12 juil. 2016 à 23:12, Victor Khomenko >> <victor.khome...@newcastle.ac.uk> 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.