The way the toplevel declaration parser is currently arranged requires
shifting every declarator symbol before any part of the full declarator
list is reduced. Thus, very long declarations (with about 5000 or more
full declarators) can lead to a parse error since the symbol stack is
exhausted (even if there would otherwise be enough memory to allocate
this many declarator items).
Technically this kind of failure is permitted by the C language, as
implementations are not required to support declarations of this size.
However, it is better to avoid arbitrary limits like this and it is not
a big problem to do so.
Simply collecting the declarators in reverse order allows for the list
elements to be reduced as they are encountered, which avoids excessive
use of the symbol stack. However in this case the order matters, so
the final list must be reversed before it is returned from the parser.
Add a new test case to cover this behaviour.
+/*
+ * Reverse the order of a "struct cdecl" list, and return the new first
+ * element of the list (i.e., the last element of the original list).
+ */
+static struct cdecl *reverse_decls(struct cdecl *decl)
+{
+ struct cdecl *prev, *next;
+
+ for (prev = NULL; decl; decl = next) {
+ next = decl->next;
+ decl->next = prev;
+ prev = decl;
+ }
+
+ return prev;
+}
+
/*
* Alter an abstract declarator (type name) to declare an identifier instead,
* used by the English parser rules to reduce "identifier as type" sequences.
*/
/*
* Alter an abstract declarator (type name) to declare an identifier instead,
* used by the English parser rules to reduce "identifier as type" sequences.
*/
-static struct cdecl *insert_identifier(struct cdecl *decl, struct parse_item *ident)
+static struct cdecl *
+insert_identifier(struct cdecl *decl, struct parse_item *ident)
{
struct cdecl_declarator *d, **p = &decl->declarators;
{
struct cdecl_declarator *d, **p = &decl->declarators;
semi: | T_SEMICOLON
declaration: declspecs declarators semi {
semi: | T_SEMICOLON
declaration: declspecs declarators semi {
+ $$ = reverse_decls($2);
-declarators: declarator_wrap | declarator_wrap T_COMMA declarators {
- $$ = $1;
- $$->next = $3;
+declarators: declarator_wrap | declarators T_COMMA declarator_wrap {
+ $$ = $3;
+ $$->next = $1;
}
declarator_wrap: declarator {
}
declarator_wrap: declarator {
+
+# Check that we can parse declarations with more than 10000 declarators.
+AT_SETUP([Excessive declarators])
+
+AT_DATA([check.awk],
+[[# We don't need any field splitting, so choose a character that does not
+# appear in C code to avoid tripping over 199-field limit in HP-UX 11 awk.
+BEGIN { FS = "@"; runstart = 0; }
+END { finish_run(NR); }
+
+$0 != lastline {
+ finish_run(NR-1);
+ lastline = $0;
+ runstart = NR;
+ print;
+}
+
+function finish_run(nr) {
+ count = nr - runstart;
+ if (count > 0)
+ print "[repeated " count " more times]";
+}
+]])
+
+a="a"
+for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14; do
+ AS_VAR_APPEND([a], [",$a"])
+done
+
+cat >test.dat <<EOF
+explain int $a
+EOF
+
+AT_CHECK([cdecl99 -f test.dat >test.out; status=$?;
+$AWK -f check.awk test.out
+exit $status], [0],
+[[declare a as int
+[repeated 16383 more times]
+]])
+
+AT_CLEANUP