Clean up parser rules for cpp_members

This simplifies the grammar rules and resolves some corner cases
which currently failed to parse.

This change:

* Simplifies the grammar rules and handles some things in more
  appropriate places

* fixes a parse error for a misplaced Doxygen comment which
  is the only thing in a class/struct.

* fixes a parse error for %include/#include in a class/struct followed
  by a member declaration.

* eliminates an instance of right recursion in the grammar, which the
  bison docs warn against due to O(n) stack use.  See #2884
This commit is contained in:
Olly Betts 2024-09-18 15:46:49 +12:00
parent 2947806421
commit 846d5d2286
5 changed files with 88 additions and 36 deletions

View File

@ -7,6 +7,14 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
Version 4.3.0 (in progress) Version 4.3.0 (in progress)
=========================== ===========================
2024-09-18: olly
Fix parse error for a misplaced Doxygen comment which is the only
thing in a class/struct.
2024-09-18: olly
Fix parse error for %include/#include in a class/struct followed
by a member declaration.
2024-09-16: olly 2024-09-16: olly
#2995 SWIG now has generic handling for converting integer and #2995 SWIG now has generic handling for converting integer and
boolean literal values for use in target language code, replacing boolean literal values for use in target language code, replacing

View File

@ -183,6 +183,11 @@
int bbbb; //! not for bbbb value, is quietly ignored by Doxygen and SWIG int bbbb; //! not for bbbb value, is quietly ignored by Doxygen and SWIG
}; };
struct OrphanedComment
{
/** Doxygen quietly ignores this; SWIG < 4.3.0 gave parse error. */
};
#include "doxygen_misc_constructs.h" #include "doxygen_misc_constructs.h"
%} %}

View File

@ -33,3 +33,16 @@ typedef struct {
typedef struct { typedef struct {
%include "inctest.h" %include "inctest.h"
} MY_THINGS; } MY_THINGS;
// Regression test: we failed to handle the case of a member after the include.
%{
struct MY_THINGS2 {
#include "inctest2.h"
int failed_before_swig_430;
};
%}
struct MY_THINGS2 {
%include "inctest2.h"
int failed_before_swig_430;
};

View File

@ -0,0 +1 @@
int IntegerMember;

View File

@ -1753,6 +1753,10 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier)
Parm *parms; Parm *parms;
Parm *last; Parm *last;
} pbuilder; } pbuilder;
struct {
Node *node;
Node *last;
} nodebuilder;
}; };
/* Define special token END for end of input. */ /* Define special token END for end of input. */
@ -1832,6 +1836,7 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier)
/* C++ declarations */ /* C++ declarations */
%type <node> cpp_declaration cpp_class_decl cpp_forward_class_decl cpp_template_decl; %type <node> cpp_declaration cpp_class_decl cpp_forward_class_decl cpp_template_decl;
%type <node> cpp_members cpp_member cpp_member_no_dox; %type <node> cpp_members cpp_member cpp_member_no_dox;
%type <nodebuilder> cpp_members_builder;
%type <node> cpp_constructor_decl cpp_destructor_decl cpp_protection_decl cpp_conversion_operator cpp_static_assert; %type <node> cpp_constructor_decl cpp_destructor_decl cpp_protection_decl cpp_conversion_operator cpp_static_assert;
%type <node> cpp_swig_directive cpp_template_possible cpp_opt_declarators ; %type <node> cpp_swig_directive cpp_template_possible cpp_opt_declarators ;
%type <node> cpp_using_decl cpp_namespace_decl cpp_catch_decl cpp_lambda_decl; %type <node> cpp_using_decl cpp_namespace_decl cpp_catch_decl cpp_lambda_decl;
@ -4841,44 +4846,52 @@ Printf(stdout, " Scope %s [creating single scope C++17 style]\n", scopename);
} }
; ;
cpp_members : cpp_member cpp_members[in] { cpp_members : cpp_members_builder {
$$ = $cpp_member; $$ = $cpp_members_builder.node;
/* Insert cpp_member (including any siblings) to the front of the cpp_members linked list */
if ($$) {
Node *p = $$;
Node *pp =0;
while (p) {
pp = p;
p = nextSibling(p);
}
set_nextSibling(pp,$in);
if ($in)
set_previousSibling($in, pp);
} else {
$$ = $in;
}
}
| cpp_member DOXYGENSTRING /* Misplaced doxygen string after a member, quietly ignore, like Doxygen does */
| EXTEND LBRACE {
extendmode = 1;
if (cplus_mode != CPLUS_PUBLIC) {
Swig_error(cparse_file,cparse_line,"%%extend can only be used in a public section\n");
} }
} cpp_members[extend_members] RBRACE { | cpp_members_builder DOXYGENSTRING {
extendmode = 0; /* Quietly ignore misplaced doxygen string after a member, like Doxygen does */
} cpp_members[in] { $$ = $cpp_members_builder.node;
$$ = new_node("extend"); }
mark_nodes_as_extend($extend_members); | %empty {
appendChild($$,$extend_members); $$ = 0;
set_nextSibling($$,$in); }
| DOXYGENSTRING {
/* Quietly ignore misplaced doxygen string in empty class, like Doxygen does */
$$ = 0;
}
| error {
Swig_error(cparse_file, cparse_line, "Syntax error in input(3).\n");
Exit(EXIT_FAILURE);
}
;
cpp_members_builder : cpp_member {
$$.node = $$.last = $cpp_member;
}
| cpp_members_builder[in] cpp_member {
// Build a linked list in the order specified, but avoiding
// a right recursion rule because "Right recursion uses up
// space on the Bison stack in proportion to the number of
// elements in the sequence".
if ($cpp_member) {
if ($in.node) {
Node *last = $in.last;
/* Advance to the last sibling. */
for (Node *p = last; p; p = nextSibling(p)) {
last = p;
}
set_nextSibling(last, $cpp_member);
set_previousSibling($cpp_member, last);
$$.node = $in.node;
} else {
$$.node = $$.last = $cpp_member;
}
} else {
$$ = $in;
} }
| include_directive }
| %empty { $$ = 0;} ;
| error {
Swig_error(cparse_file,cparse_line,"Syntax error in input(3).\n");
Exit(EXIT_FAILURE);
}
;
/* ====================================================================== /* ======================================================================
* C++ Class members * C++ Class members
@ -4914,6 +4927,7 @@ cpp_member_no_dox : c_declaration
| cpp_using_decl | cpp_using_decl
| cpp_template_decl | cpp_template_decl
| cpp_catch_decl | cpp_catch_decl
| include_directive
| template_directive | template_directive
| warn_directive | warn_directive
| anonymous_bitfield { $$ = 0; } | anonymous_bitfield { $$ = 0; }
@ -4930,6 +4944,17 @@ cpp_member : cpp_member_no_dox
$$ = $cpp_member_no_dox; $$ = $cpp_member_no_dox;
set_comment($cpp_member_no_dox, $DOXYGENPOSTSTRING); set_comment($cpp_member_no_dox, $DOXYGENPOSTSTRING);
} }
| EXTEND LBRACE {
extendmode = 1;
if (cplus_mode != CPLUS_PUBLIC) {
Swig_error(cparse_file,cparse_line,"%%extend can only be used in a public section\n");
}
} cpp_members RBRACE {
extendmode = 0;
$$ = new_node("extend");
mark_nodes_as_extend($cpp_members);
appendChild($$, $cpp_members);
}
; ;
/* Possibly a constructor */ /* Possibly a constructor */