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)
===========================
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
#2995 SWIG now has generic handling for converting integer and
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
};
struct OrphanedComment
{
/** Doxygen quietly ignores this; SWIG < 4.3.0 gave parse error. */
};
#include "doxygen_misc_constructs.h"
%}

View File

@ -33,3 +33,16 @@ typedef struct {
typedef struct {
%include "inctest.h"
} 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 *last;
} pbuilder;
struct {
Node *node;
Node *last;
} nodebuilder;
};
/* Define special token END for end of input. */
@ -1832,6 +1836,7 @@ static String *add_qualifier_to_declarator(SwigType *type, SwigType *qualifier)
/* C++ declarations */
%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 <nodebuilder> cpp_members_builder;
%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_using_decl cpp_namespace_decl cpp_catch_decl cpp_lambda_decl;
@ -4841,43 +4846,51 @@ Printf(stdout, " Scope %s [creating single scope C++17 style]\n", scopename);
}
;
cpp_members : cpp_member cpp_members[in] {
$$ = $cpp_member;
/* 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);
cpp_members : cpp_members_builder {
$$ = $cpp_members_builder.node;
}
| cpp_members_builder DOXYGENSTRING {
/* Quietly ignore misplaced doxygen string after a member, like Doxygen does */
$$ = $cpp_members_builder.node;
}
| %empty {
$$ = 0;
}
| 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;
}
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 {
extendmode = 0;
} cpp_members[in] {
$$ = new_node("extend");
mark_nodes_as_extend($extend_members);
appendChild($$,$extend_members);
set_nextSibling($$,$in);
}
| include_directive
| %empty { $$ = 0;}
| error {
Swig_error(cparse_file,cparse_line,"Syntax error in input(3).\n");
Exit(EXIT_FAILURE);
}
;
/* ======================================================================
@ -4914,6 +4927,7 @@ cpp_member_no_dox : c_declaration
| cpp_using_decl
| cpp_template_decl
| cpp_catch_decl
| include_directive
| template_directive
| warn_directive
| anonymous_bitfield { $$ = 0; }
@ -4930,6 +4944,17 @@ cpp_member : cpp_member_no_dox
$$ = $cpp_member_no_dox;
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 */