+/* ---------------------------------------------------------------------- */
+/* comma list parser, used for fn params, fn args, enums, initlists,
+ #define params */
+
+/* enums: enum_decl, edots_when(TEllipsis,enum_decl_one)
+fun s d -> P.mkedots "..." d
+fun c -> Ast0.EComma c
+ */
+
+empty_list_start(elem,dotter):
+ /* empty */ { fun build_dots build_comma -> [] }
+| nonempty_list_start(elem,dotter) { $1 }
+
+nonempty_list_start(elem,dotter): /* dots allowed */
+ elem { fun build_dots build_comma -> [$1] }
+| elem TComma
+ { fun build_dots build_comma ->
+ $1::[Ast0.wrap(build_comma(P.clt2mcode "," $2))] }
+| elem TComma nonempty_list_start(elem,dotter)
+ { fun build_dots build_comma ->
+ $1::(Ast0.wrap(build_comma(P.clt2mcode "," $2)))::
+ ($3 build_dots build_comma) }
+| TNothing nonempty_list_start(elem,dotter) { $2 }
+| d=dotter { fun build_dots build_comma -> [(build_dots "..." d)] }
+| d=dotter TComma
+ { fun build_dots build_comma ->
+ [(build_dots "..." d);Ast0.wrap(build_comma(P.clt2mcode "," $2))] }
+| d=dotter TComma r=continue_list(elem,dotter)
+ { fun build_dots build_comma ->
+ (build_dots "..." d)::
+ (Ast0.wrap(build_comma(P.clt2mcode "," $2)))::
+ (r build_dots build_comma) }
+
+continue_list(elem,dotter): /* dots not allowed */
+ elem { fun build_dots build_comma -> [$1] }
+| elem TComma
+ { fun build_dots build_comma ->
+ $1::[Ast0.wrap(build_comma(P.clt2mcode "," $2))] }
+| elem TComma nonempty_list_start(elem,dotter)
+ { fun build_dots build_comma ->
+ $1::(Ast0.wrap(build_comma(P.clt2mcode "," $2)))::
+ ($3 build_dots build_comma) }
+| TNothing nonempty_list_start(elem,dotter) { $2 }