-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
implement __VA_OPT__ #135
Labels
Comments
Has so many corner cases that it seems too early to have a solid implementation. |
Test cases: #define foo1(...) __VA_OPT__(__VA_OPT__)
#define foo2(...) start __VA_OPT__(__VA_OPT__()) end
#define foo3(...) start __VA_OPT__(start __VA_OPT__(foo) end) end
#define foo4(...) ## __VA_OPT__(test)
#define foo5(...) test ## __VA_OPT__(test)
#define foo6(...) __VA_OPT__ ## (test)
#define foo7(...) __VA_OPT__##(test)
#define foo8(...) __VA_OPT__(##test)
#define foo9(...) test __VA_OPT__(##) test
#define foo10(...) test __VA_OPT__( ## test) test
#define foo11(...) __VA_OPT__(test ##)
#define foo12(...) test __VA_OPT__(test## ) test
#define foo13(...) __VA_OPT__(test)##
#define foo14(...) __VA_OPT__(test) ##
#define foo15(...) test __VA_OPT__(test) ##
#define foo16(...) # __VA_OPT__()
#define foo17(...) #__VA_OPT__(test)
#define foo18(...) __VA_OPT__#()
#define foo19(a, ...) __VA_OPT__ # (a)
#define foo20(...) __VA_OPT__(#)
#define foo21(a, ...) __VA_OPT__(#) a
#define foo22(a, ...) __VA_OPT__(#a)
#define foo23(...) __VA_OPT__(test #)
#define foo24(...) __VA_OPT__(test # ) test
#define foo25(a, ...) __VA_OPT__(test # ) a
#define foo26(...) __VA_OPT__ (test)
#define foo27(...) __VA_OPT__ ( test )
foo27(test)
foo27()
#define foo28(...) __VA_OPT__(test)fred
foo28()
foo28(test)
#define foo29(...) __VA_OPT__(test) fred
foo29()
foo29(test)
#define foo30(...) __VA_OPT__(test)__VA_OPT__(fred)
foo30()
foo30(test)
#define foo31(__VA_OPT__) #__VA_OPT__
foo31(foo)
#define foo32(__VA_OPT__, ...) #__VA_OPT__()
foo32(foo)
#define foo33(...) __VA_OPT__(fred)
#define foo33(...) __VA_OPT__ (fred)
#define foo34(...) __VA_OPT__ (a )
#define foo34(...) __VA_OPT__ ( a)
#define foo35(...) __VA_OPT__ (+a)
#define foo35(...) __VA_OPT__ (+ a)
#define foo36(...) __VA_OPT__ (a b)
#define foo36(...) __VA_OPT__(a) __VA_OPT__(b)
#define foo37(a, ...) start __VA_OPT__(,) end
foo37(foo)
foo37(foo,)
foo37(foo,bar)
/* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83063 */
#define ice(...) b##__VA_OPT__ ()
ice () |
diff --git lib/mcr.c lib/mcr.c
index 683c889..a3c80a8 100644
--- lib/mcr.c
+++ lib/mcr.c
@@ -510,13 +510,13 @@ static struct mtab *conflict(const char *chn)
lex_t *(mcr_define)(const lmap_t *pos, int cmd)
{
int n = -1;
- int sharp = 0;
lex_t *t, *pt, *v, *l;
const char *cn, *s;
- const lmap_t *idpos;
+ const lmap_t *idpos, *lpos;
arena_t *strg;
lex_t **param = NULL;
struct pel *pe = NULL;
+ int opt = 0, sharp = 0;
NEXTSP(t); /* consumes define */
if (t->id != LEX_ID) {
@@ -597,18 +597,41 @@ lex_t *(mcr_define)(const lmap_t *pos, int cmd)
if (t->id == LEX_SPACE) {
lex_t *u;
NEXTSP(u); /* consumes space */
- if (u->id != LEX_NEWLINE && u->id != LEX_EOI) {
+ if (u->id != LEX_NEWLINE && u->id != LEX_EOI && !(opt == 1 && u->id == ')')) {
SPELL(t, " ");
- l = lst_append(l, lst_copy(t, 0, strg));
+ l = lst_append(l, lst_copy(t, 0, strg)), l->f.vaopt = (opt > 0);
}
t = u;
continue;
}
- if (t->id == LEX_ID && t->spell[0] == '_' && !v) { /* before copy */
+ if (t->id == LEX_ID && t->spell[0] == '_') { /* before copy */
s = LEX_SPELL(t);
- MCR_IDVAARGS(s, t);
+ if (!v)
+ MCR_IDVAARGS(s, t);
+ else if (MCR_ISVAOPT(s)) {
+ if (opt > 0) {
+ return t;
+ }
+ NEXTSP(t); /* consumes __VA_OPT__ */
+ if (t->id == '(') {
+ opt = 1;
+ lpos = t->pos;
+ NEXTSP(t); /* consumes ( */
+ if (t->id == LEX_DSHARP) {
+ err_dpos(t->pos, ERR_PP_DSHARPPOS, "__VA_OPT__");
+ return t;
+ }
+ } else {
+ err_dpos(t->pos, ERR_PP_);
+ return t;
+ }
+ }
+ } else if (opt == 1 && t->id == ')') {
+ opt = 0;
+ t = lst_nexti();
+ continue;
}
- l = lst_append(l, lst_copy(t, 0, strg));
+ l = lst_append(l, lst_copy(t, 0, strg)), l->f.vaopt = (opt > 0);
if (n > 0 && t->id == LEX_ID) {
struct pel *p = pelookup(pe, t);
if (p)
@@ -621,13 +644,13 @@ lex_t *(mcr_define)(const lmap_t *pos, int cmd)
NEXTSP(u); /* consumes space */
if (u->id != LEX_NEWLINE && u->id != LEX_EOI) {
SPELL(t, " ");
- l = lst_append(l, lst_copy(t, 0, strg));
+ l = lst_append(l, lst_copy(t, 0, strg)), l->f.vaopt = (opt > 0);
}
t = u;
}
if (ts->id == LEX_DSHARP) {
if (l->next->id == LEX_DSHARP || (t->id == LEX_NEWLINE || t->id == LEX_EOI)) {
- err_dpos(ts->pos, ERR_PP_DSHARPPOS);
+ err_dpos(ts->pos, ERR_PP_DSHARPPOS, "macro expansion");
return t;
} else if (t->id == LEX_DSHARP) {
err_dpos(t->pos, ERR_PP_TWODSHARP);
@@ -653,11 +676,17 @@ lex_t *(mcr_define)(const lmap_t *pos, int cmd)
}
pt = ts;
continue;
+ } else if (opt > 0) {
+ if (t->id == '(')
+ opt++;
+ else if (t->id == ')')
+ opt--;
}
pt = l; /* not t */
t = lst_nexti();
}
-
+ if (opt > 0)
+ ;
{ /* installation */
struct mtab *p;
diff --git lib/mcr.h lib/mcr.h
index 15fd861..c4dc41d 100644
--- lib/mcr.h
+++ lib/mcr.h
@@ -30,15 +30,20 @@ void mcr_free(void);
#define mcr_addcmd(a) (mcr_cmd(0, (a)))
#define mcr_delcmd(a) (mcr_cmd(1, (a)))
-/* checks if __VA_ARGS__ */
-#define MCR_ISVAARGS(s) \
- ((s)[0] == '_' && (s)[1] == '_' && (s)[2] == 'V' && strcmp((s)+3, "A_ARGS__") == 0)
+/* checks if __VA_ARGS__ or __VA_OPT__ */
+#define MCR_ISVA(s) \
+ ((s)[0] == '_' && (s)[1] == '_' && (s)[2] == 'V' && (s)[3] == 'A' && (s)[4] == '_')
+#define MCR_ISVAARGS(s) (MCR_ISVA(s) && (s)[5] == 'A' && strcmp((s)+6, "RGS__") == 0)
+#define MCR_ISVAOPT(s) (MCR_ISVA(s) && (s)[5] == 'O' && strcmp((s)+6, "PT__") == 0)
+#define MCR_ISVAS(s) \
+ (MCR_ISVA(s) && (((s)[5] == 'A' && strcmp((s)+6, "RGS__") == 0) || \
+ ((s)[5] == 'O' && strcmp((s)+6, "PT__") == 0)))
/* issues diagnostics when __VA_ARGS__ encountered */
-#define MCR_IDVAARGS(s, t) \
- do { \
- if (MCR_ISVAARGS(s) && !(t)->f.vaarg) \
- err_dpos((t)->pos, ERR_PP_VAARGS), (t)->f.vaarg = 1; \
+#define MCR_IDVAARGS(s, t) \
+ do { \
+ if (MCR_ISVAS(s) && !(t)->f.vaarg) \
+ err_dpos((t)->pos, ERR_PP_VAS, (s)), (t)->f.vaarg = 1; \
} while(0)
diff --git lib/xerror.h lib/xerror.h
index 074e71b..a7c7618 100644
--- lib/xerror.h
+++ lib/xerror.h
@@ -48,7 +48,7 @@ xx(PP_PMCRREDEF, E|P , 0, "redefinition of built-in macro `%s'"
xx(PP_PMCRUNDEF, E|P , 0, "undefining built-in macro `%s'" )
xx(PP_UNDEFMCR, P , 4, "#undefining undefined macro `%s'" )
xx(PP_ELLSEEN, E|P , 0, "`...' must be the last in parameters" )
-xx(PP_VAARGS, P , 0, "__VA_ARGS__ can appear only in variadic replacement list" )
+xx(PP_VAS, P , 0, "%s can appear only in variadic replacement list" )
xx(PP_VARIADIC, P |A , 3, "C90 does not support variadic macros" )
xx(PP_NOPNAME, E|P , 0, "missing identifier for macro parameter name" )
xx(PP_NOPRPAREN, E|P , 0, "missing `)' in macro parameter list" )
@@ -59,7 +59,7 @@ xx(PP_MANYPARAM, P , 2, "too many parameters"
xx(PP_MANYPSTD, N |A|B|C, 3, "ISO C guarantees only %d parameters" )
xx(PP_MANYPPID, P , 2, "too many macros simultaneously defined" )
xx(PP_MANYPPIDSTD, N |A|B|C, 3, "ISO C guarantees only %d macros" )
-xx(PP_DSHARPPOS, E|P , 0, "`##' cannot appear at the boundaries of macro expansion" )
+xx(PP_DSHARPPOS, E|P , 0, "`##' cannot appear at the boundaries of %s" )
xx(PP_TWODSHARP, E|P , 0, "`##' cannot be an operand of `##'" )
xx(PP_NEEDPARAM, E|P , 0, "`#' must be followed by a macro parameter" )
xx(PP_EMPTYARG, P |A , 3, "C90 does not support empty argument to macro `%s'" ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Cases to handle:
__VA_OPT__
in__VA_OPT__()
__VA_OPT__
in other places__VA_OPT__
and##
## __VA_OPT__ (...)
__VA_OPT__ ## (...)
__VA_OPT__ (## ...)
__VA_OPT__ (... ##)
__VA_OPT__ (...) ##
__VA_OPT__
and#
# __VA_OPT__ (...)
__VA_OPT__ # (...)
__VA_OPT__ (# ...)
__VA_OPT__ (... #)
__VA_OPT__ (...) #
__VA_OPT__
and spaces__VA_OPT__ (...)
__VA_OPT__(...)
__VA_OPT__(...)
(trailing space)__VA_OPT__
and(
__VA_OPT__()
__VA_OPT__
s__VA_OPT__(foo)bar
__VA_OPT__(foo)__VA_OPT__(bar)
The text was updated successfully, but these errors were encountered: