mirror of
git://gcc.gnu.org/git/gcc.git
synced 2024-12-19 11:59:55 +08:00
cpplib.h (CPP_ASSERTION, [...]): New token types.
* cpplib.h (CPP_ASSERTION, CPP_STRINGIZE, CPP_TOKPASTE): New token types. (struct cpp_reader): Add parsing_if_directive and parsing_define_directive flags. (struct cpp_options): Remove output_conditionals flag. (check_macro_name): Delete prototype. * cpphash.h (struct macrodef): Delete. (struct reflist): Separate from struct definition. (struct definition): Remove unused fields. Add column number. (create_definition): Returns a DEFINITION *. Takes a cpp_reader * and an int. * cpphash.c (SKIP_WHITE_SPACE): Delete. (PEEKC): Copy defn from cpplib.c. (rest_extension, REST_EXTENSION_LENGTH): Delete. (struct arg): New. (struct arglist): Simplify. (collect_expansion): Rewrite. Get tokens by calling cpp_get_token. Add more error checking. (collect_formal_parameters): New function, broken out of create_definition and reworked to use get_directive_token. (create_definition): All real work is now in collect_expansion and collect_formal_parameters. do_define handles finding the macro name. Return a DEFINITION, not a MACRODEF. (macroexpand): Replace bcopy with memcpy throughout. Replace character-at-a-time copy loop with memcpy and pointer increments. (compare-defs): d1->argnames / d2->argnames might be null. * cpplib.c (copy_rest_of_line): Delete function. (skip_rest_of_line): Do all the work ourselves. (skip_string): New function. (parse_string): Use skip_string. (get_macro_name): New function. (check_macro_name): Delete. (copy_comment): Use CPP_RESERVE and CPP_PUTC_Q. (cpp_skip_hspace): Use CPP_BUMP_LINE. (handle_directive): ICE if we're called on a macro buffer. (do_define): Determine macro name and type (funlike/objlike) here. Expunge all uses of MACRODEF. (cpp_push_buffer): Set line_base to NULL. (do_undef, read_line_number): Don't worry about getting a POP token. (eval_if_expression): Set/reset parsing_if_directive around cpp_parse_expr. Don't clear only_seen_white. (skip_if_group): Remove output_conditionals logic. Use skip_rest_of_line. (cpp_get_token): Return ASSERTION, STRINGIZE, and TOKPASTE tokens under appropriate conditions. (cpp_unassert): Call do_unassert not do_assert. Oops. * cppexp.c (parse_defined): New function, break out of cpp_lex. (cpp_lex): We now get CPP_ASSERTION tokens and can check them ourselves, with cpp_defined. * cppinit.c (cpp_handle_option, print_help): Delete -ifoutput. * gcc.dg/20000209-2.c: Turn off -pedantic-errors. * gcc.dg/strpaste-2.c: New. From-SVN: r32274
This commit is contained in:
parent
38769add25
commit
ba412f14ad
@ -1,3 +1,64 @@
|
||||
2000-02-29 Zack Weinberg <zack@wolery.cumb.org>
|
||||
|
||||
* cpplib.h (CPP_ASSERTION, CPP_STRINGIZE, CPP_TOKPASTE): New
|
||||
token types.
|
||||
(struct cpp_reader): Add parsing_if_directive and
|
||||
parsing_define_directive flags.
|
||||
(struct cpp_options): Remove output_conditionals flag.
|
||||
(check_macro_name): Delete prototype.
|
||||
|
||||
* cpphash.h (struct macrodef): Delete.
|
||||
(struct reflist): Separate from struct definition.
|
||||
(struct definition): Remove unused fields. Add column number.
|
||||
(create_definition): Returns a DEFINITION *. Takes a
|
||||
cpp_reader * and an int.
|
||||
|
||||
* cpphash.c (SKIP_WHITE_SPACE): Delete.
|
||||
(PEEKC): Copy defn from cpplib.c.
|
||||
(rest_extension, REST_EXTENSION_LENGTH): Delete.
|
||||
(struct arg): New.
|
||||
(struct arglist): Simplify.
|
||||
(collect_expansion): Rewrite. Get tokens by calling
|
||||
cpp_get_token. Add more error checking.
|
||||
(collect_formal_parameters): New function, broken out of
|
||||
create_definition and reworked to use get_directive_token.
|
||||
(create_definition): All real work is now in collect_expansion
|
||||
and collect_formal_parameters. do_define handles finding the
|
||||
macro name. Return a DEFINITION, not a MACRODEF.
|
||||
(macroexpand): Replace bcopy with memcpy throughout. Replace
|
||||
character-at-a-time copy loop with memcpy and pointer increments.
|
||||
(compare-defs): d1->argnames / d2->argnames might be null.
|
||||
|
||||
* cpplib.c (copy_rest_of_line): Delete function.
|
||||
(skip_rest_of_line): Do all the work ourselves.
|
||||
(skip_string): New function.
|
||||
(parse_string): Use skip_string.
|
||||
(get_macro_name): New function.
|
||||
(check_macro_name): Delete.
|
||||
(copy_comment): Use CPP_RESERVE and CPP_PUTC_Q.
|
||||
(cpp_skip_hspace): Use CPP_BUMP_LINE.
|
||||
(handle_directive): ICE if we're called on a macro buffer.
|
||||
(do_define): Determine macro name and type (funlike/objlike)
|
||||
here. Expunge all uses of MACRODEF.
|
||||
(cpp_push_buffer): Set line_base to NULL.
|
||||
(do_undef, read_line_number): Don't worry about getting a POP token.
|
||||
(eval_if_expression): Set/reset parsing_if_directive around
|
||||
cpp_parse_expr. Don't clear only_seen_white.
|
||||
(skip_if_group): Remove output_conditionals logic. Use
|
||||
skip_rest_of_line.
|
||||
(cpp_get_token): Return ASSERTION, STRINGIZE, and TOKPASTE
|
||||
tokens under appropriate conditions.
|
||||
(cpp_unassert): Call do_unassert not do_assert. Oops.
|
||||
|
||||
* cppexp.c (parse_defined): New function, break out of
|
||||
cpp_lex.
|
||||
(cpp_lex): We now get CPP_ASSERTION tokens and can check them
|
||||
ourselves, with cpp_defined.
|
||||
* cppinit.c (cpp_handle_option, print_help): Delete -ifoutput.
|
||||
|
||||
* gcc.dg/20000209-2.c: Turn off -pedantic-errors.
|
||||
* gcc.dg/strpaste-2.c: New.
|
||||
|
||||
2000-02-29 Mark Mitchell <mark@codesourcery.com>
|
||||
|
||||
* fold-const.c (size_binop): Don't asert inputs are the same and
|
||||
|
106
gcc/cppexp.c
106
gcc/cppexp.c
@ -81,6 +81,7 @@ static HOST_WIDEST_INT left_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT, int, u
|
||||
static HOST_WIDEST_INT right_shift PARAMS ((cpp_reader *, HOST_WIDEST_INT, int, unsigned HOST_WIDEST_INT));
|
||||
static struct operation parse_number PARAMS ((cpp_reader *, U_CHAR *, U_CHAR *));
|
||||
static struct operation parse_charconst PARAMS ((cpp_reader *, U_CHAR *, U_CHAR *));
|
||||
static struct operation parse_defined PARAMS ((cpp_reader *));
|
||||
static struct operation cpp_lex PARAMS ((cpp_reader *, int));
|
||||
extern HOST_WIDEST_INT cpp_parse_expr PARAMS ((cpp_reader *));
|
||||
static HOST_WIDEST_INT cpp_parse_escape PARAMS ((cpp_reader *, U_CHAR **, HOST_WIDEST_INT));
|
||||
@ -349,6 +350,53 @@ parse_charconst (pfile, start, end)
|
||||
return op;
|
||||
}
|
||||
|
||||
static struct operation
|
||||
parse_defined (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
int paren = 0, len;
|
||||
U_CHAR *tok;
|
||||
enum cpp_token token;
|
||||
struct operation op;
|
||||
long old_written = CPP_WRITTEN (pfile);
|
||||
|
||||
op.unsignedp = 0;
|
||||
op.op = INT;
|
||||
|
||||
pfile->no_macro_expand++;
|
||||
token = get_directive_token (pfile);
|
||||
if (token == CPP_LPAREN)
|
||||
{
|
||||
paren++;
|
||||
CPP_SET_WRITTEN (pfile, old_written);
|
||||
token = get_directive_token (pfile);
|
||||
}
|
||||
|
||||
if (token != CPP_NAME)
|
||||
goto oops;
|
||||
|
||||
tok = pfile->token_buffer + old_written;
|
||||
len = CPP_PWRITTEN (pfile) - tok;
|
||||
op.value = cpp_defined (pfile, tok, len);
|
||||
|
||||
if (paren)
|
||||
{
|
||||
if (get_directive_token (pfile) != CPP_RPAREN)
|
||||
goto oops;
|
||||
}
|
||||
CPP_SET_WRITTEN (pfile, old_written);
|
||||
pfile->no_macro_expand--;
|
||||
return op;
|
||||
|
||||
oops:
|
||||
CPP_SET_WRITTEN (pfile, old_written);
|
||||
pfile->no_macro_expand--;
|
||||
cpp_error (pfile, "`defined' without an identifier");
|
||||
|
||||
op.op = ERROR;
|
||||
return op;
|
||||
}
|
||||
|
||||
|
||||
struct token {
|
||||
const char *operator;
|
||||
@ -389,7 +437,7 @@ cpp_lex (pfile, skip_evaluation)
|
||||
tok_end = CPP_PWRITTEN (pfile);
|
||||
CPP_SET_WRITTEN (pfile, old_written);
|
||||
switch (token)
|
||||
{
|
||||
{
|
||||
case CPP_EOF: /* Should not happen ... */
|
||||
case CPP_VSPACE:
|
||||
op.op = 0;
|
||||
@ -407,51 +455,22 @@ cpp_lex (pfile, skip_evaluation)
|
||||
return parse_charconst (pfile, tok_start, tok_end);
|
||||
|
||||
case CPP_NAME:
|
||||
if (!strcmp (tok_start, "defined"))
|
||||
return parse_defined (pfile);
|
||||
|
||||
op.op = INT;
|
||||
op.unsignedp = 0;
|
||||
op.value = 0;
|
||||
if (strcmp (tok_start, "defined"))
|
||||
{
|
||||
if (CPP_WARN_UNDEF (pfile) && !skip_evaluation)
|
||||
cpp_warning (pfile, "`%.*s' is not defined",
|
||||
(int) (tok_end - tok_start), tok_start);
|
||||
}
|
||||
else
|
||||
{
|
||||
int paren = 0, len;
|
||||
U_CHAR *tok;
|
||||
|
||||
pfile->no_macro_expand++;
|
||||
token = get_directive_token (pfile);
|
||||
if (token == CPP_LPAREN)
|
||||
{
|
||||
paren++;
|
||||
CPP_SET_WRITTEN (pfile, old_written);
|
||||
token = get_directive_token (pfile);
|
||||
}
|
||||
|
||||
if (token != CPP_NAME)
|
||||
goto oops;
|
||||
|
||||
tok = pfile->token_buffer + old_written;
|
||||
len = CPP_PWRITTEN (pfile) - tok;
|
||||
if (cpp_defined (pfile, tok, len))
|
||||
op.value = 1;
|
||||
|
||||
if (paren)
|
||||
{
|
||||
if (get_directive_token (pfile) != CPP_RPAREN)
|
||||
goto oops;
|
||||
}
|
||||
CPP_SET_WRITTEN (pfile, old_written);
|
||||
pfile->no_macro_expand--;
|
||||
}
|
||||
if (CPP_WARN_UNDEF (pfile) && !skip_evaluation)
|
||||
cpp_warning (pfile, "`%.*s' is not defined",
|
||||
(int) (tok_end - tok_start), tok_start);
|
||||
return op;
|
||||
|
||||
oops:
|
||||
CPP_SET_WRITTEN (pfile, old_written);
|
||||
pfile->no_macro_expand--;
|
||||
cpp_error (pfile, "`defined' without an identifier");
|
||||
case CPP_ASSERTION:
|
||||
op.op = INT;
|
||||
op.unsignedp = 0;
|
||||
op.value = cpp_defined (pfile, tok_start, tok_end - tok_start);
|
||||
return op;
|
||||
|
||||
case CPP_OTHER:
|
||||
@ -468,13 +487,6 @@ cpp_lex (pfile, skip_evaluation)
|
||||
op.op = toktab->token;
|
||||
return op;
|
||||
}
|
||||
else if (tok_start + 1 == tok_end && *tok_start == '#')
|
||||
{
|
||||
CPP_FORWARD (CPP_BUFFER (pfile), -1);
|
||||
op.op = INT;
|
||||
op.value = cpp_read_check_assertion (pfile);
|
||||
return op;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
op.op = *tok_start;
|
||||
|
966
gcc/cpphash.c
966
gcc/cpphash.c
File diff suppressed because it is too large
Load Diff
@ -18,15 +18,6 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
#ifndef __GCC_CPPHASH__
|
||||
#define __GCC_CPPHASH__
|
||||
|
||||
/* Structure returned by create_definition */
|
||||
typedef struct macrodef MACRODEF;
|
||||
struct macrodef
|
||||
{
|
||||
struct definition *defn;
|
||||
const U_CHAR *symnam;
|
||||
int symlen;
|
||||
};
|
||||
|
||||
/* Structure allocated for every #define. For a simple replacement
|
||||
such as
|
||||
#define foo bar ,
|
||||
@ -48,30 +39,35 @@ struct macrodef
|
||||
{ (0, 1), (1, 1), (1, 1), ..., (1, 1), NULL }
|
||||
where (x, y) means (nchars, argno). */
|
||||
|
||||
struct reflist
|
||||
{
|
||||
struct reflist *next;
|
||||
char stringify; /* nonzero if this arg was preceded by a
|
||||
# operator. */
|
||||
char raw_before; /* Nonzero if a ## operator before arg. */
|
||||
char raw_after; /* Nonzero if a ## operator after arg. */
|
||||
char rest_args; /* Nonzero if this arg. absorbs the rest */
|
||||
int nchars; /* Number of literal chars to copy before
|
||||
this arg occurrence. */
|
||||
int argno; /* Number of arg to substitute (origin-0) */
|
||||
};
|
||||
|
||||
typedef struct definition DEFINITION;
|
||||
struct definition {
|
||||
struct definition
|
||||
{
|
||||
int nargs;
|
||||
int length; /* length of expansion string */
|
||||
unsigned char *expansion;
|
||||
U_CHAR *expansion;
|
||||
int line; /* Line number of definition */
|
||||
int col;
|
||||
const char *file; /* File of definition */
|
||||
char rest_args; /* Nonzero if last arg. absorbs the rest */
|
||||
struct reflist {
|
||||
struct reflist *next;
|
||||
char stringify; /* nonzero if this arg was preceded by a
|
||||
# operator. */
|
||||
char raw_before; /* Nonzero if a ## operator before arg. */
|
||||
char raw_after; /* Nonzero if a ## operator after arg. */
|
||||
char rest_args; /* Nonzero if this arg. absorbs the rest */
|
||||
int nchars; /* Number of literal chars to copy before
|
||||
this arg occurrence. */
|
||||
int argno; /* Number of arg to substitute (origin-0) */
|
||||
} *pattern;
|
||||
/* Names of macro args, concatenated in reverse order
|
||||
with comma-space between them.
|
||||
The only use of this is that we warn on redefinition
|
||||
if this differs between the old and new definitions. */
|
||||
unsigned char *argnames;
|
||||
struct reflist *pattern;
|
||||
|
||||
/* Names of macro args, concatenated in order with commas between
|
||||
them. The only use of this is that we warn on redefinition if
|
||||
this differs between the old and new definitions. */
|
||||
U_CHAR *argnames;
|
||||
};
|
||||
|
||||
/* different kinds of things that can appear in the value field
|
||||
@ -102,8 +98,7 @@ extern HASHNODE *cpp_lookup PARAMS ((cpp_reader *, const U_CHAR *, int));
|
||||
extern void free_definition PARAMS ((DEFINITION *));
|
||||
extern void delete_macro PARAMS ((HASHNODE *));
|
||||
|
||||
extern MACRODEF create_definition PARAMS ((U_CHAR *, U_CHAR *,
|
||||
cpp_reader *));
|
||||
extern DEFINITION *create_definition PARAMS ((cpp_reader *, int));
|
||||
extern int compare_defs PARAMS ((cpp_reader *, DEFINITION *,
|
||||
DEFINITION *));
|
||||
extern void macroexpand PARAMS ((cpp_reader *, HASHNODE *));
|
||||
|
@ -1256,9 +1256,6 @@ cpp_handle_option (pfile, argc, argv)
|
||||
opts->include_prefix_len = strlen (argv[i]);
|
||||
}
|
||||
}
|
||||
else if (!strcmp (argv[i], "-ifoutput"))
|
||||
opts->output_conditionals = 1;
|
||||
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
@ -1736,7 +1733,6 @@ Switches:\n\
|
||||
-dD Preserve macro definitions in output\n\
|
||||
-dN As -dD except that only the names are preserved\n\
|
||||
-dI Include #include directives in the output\n\
|
||||
-ifoutput Describe skipped code blocks in output \n\
|
||||
-P Do not generate #line directives\n\
|
||||
-$ Do not allow '$' in identifiers\n\
|
||||
-remap Remap file names when including files.\n\
|
||||
|
344
gcc/cpplib.c
344
gcc/cpplib.c
@ -46,7 +46,8 @@ extern HOST_WIDEST_INT cpp_parse_expr PARAMS ((cpp_reader *));
|
||||
|
||||
/* `struct directive' defines one #-directive, including how to handle it. */
|
||||
|
||||
struct directive {
|
||||
struct directive
|
||||
{
|
||||
int length; /* Length of name */
|
||||
int (*func) /* Function to handle directive */
|
||||
PARAMS ((cpp_reader *, const struct directive *));
|
||||
@ -93,7 +94,7 @@ static enum cpp_token null_underflow PARAMS ((cpp_reader *));
|
||||
static int null_cleanup PARAMS ((cpp_buffer *, cpp_reader *));
|
||||
static int skip_comment PARAMS ((cpp_reader *, int));
|
||||
static int copy_comment PARAMS ((cpp_reader *, int));
|
||||
static void copy_rest_of_line PARAMS ((cpp_reader *));
|
||||
static void skip_string PARAMS ((cpp_reader *, int));
|
||||
static void skip_rest_of_line PARAMS ((cpp_reader *));
|
||||
static void cpp_skip_hspace PARAMS ((cpp_reader *));
|
||||
static int handle_directive PARAMS ((cpp_reader *));
|
||||
@ -108,6 +109,7 @@ static void skip_block_comment PARAMS ((cpp_reader *));
|
||||
static void skip_line_comment PARAMS ((cpp_reader *));
|
||||
static void parse_set_mark PARAMS ((cpp_reader *));
|
||||
static void parse_goto_mark PARAMS ((cpp_reader *));
|
||||
static int get_macro_name PARAMS ((cpp_reader *));
|
||||
|
||||
/* Here is the actual list of #-directives.
|
||||
This table is ordered by frequency of occurrence; the numbers
|
||||
@ -410,10 +412,13 @@ copy_comment (pfile, m)
|
||||
if (skip_comment (pfile, m) == m)
|
||||
return m;
|
||||
|
||||
CPP_PUTC (pfile, m);
|
||||
for (limit = CPP_BUFFER (pfile)->cur; start <= limit; start++)
|
||||
limit = CPP_BUFFER (pfile)->cur;
|
||||
CPP_RESERVE (pfile, limit - start + 2);
|
||||
CPP_PUTC_Q (pfile, m);
|
||||
for (; start <= limit; start++)
|
||||
if (*start != '\r')
|
||||
CPP_PUTC (pfile, *start);
|
||||
CPP_PUTC_Q (pfile, *start);
|
||||
|
||||
return ' ';
|
||||
}
|
||||
|
||||
@ -447,7 +452,7 @@ cpp_skip_hspace (pfile)
|
||||
break;
|
||||
}
|
||||
else
|
||||
CPP_BUFFER (pfile)->lineno++;
|
||||
CPP_BUMP_LINE (pfile);
|
||||
}
|
||||
else if (c == '/' || c == '-')
|
||||
{
|
||||
@ -461,11 +466,10 @@ cpp_skip_hspace (pfile)
|
||||
FORWARD(-1);
|
||||
}
|
||||
|
||||
/* Read the rest of the current line.
|
||||
The line is appended to PFILE's output buffer. */
|
||||
/* Read and discard the rest of the current line. */
|
||||
|
||||
static void
|
||||
copy_rest_of_line (pfile)
|
||||
skip_rest_of_line (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
for (;;)
|
||||
@ -476,32 +480,21 @@ copy_rest_of_line (pfile)
|
||||
case '\n':
|
||||
FORWARD(-1);
|
||||
case EOF:
|
||||
CPP_NUL_TERMINATE (pfile);
|
||||
return;
|
||||
|
||||
case '\r':
|
||||
if (CPP_BUFFER (pfile)->has_escapes)
|
||||
break;
|
||||
else
|
||||
{
|
||||
CPP_BUFFER (pfile)->lineno++;
|
||||
continue;
|
||||
}
|
||||
if (! CPP_BUFFER (pfile)->has_escapes)
|
||||
CPP_BUMP_LINE (pfile);
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
case '\"':
|
||||
parse_string (pfile, c);
|
||||
continue;
|
||||
skip_string (pfile, c);
|
||||
break;
|
||||
|
||||
case '/':
|
||||
if (PEEKC() == '*')
|
||||
{
|
||||
if (CPP_TRADITIONAL (pfile))
|
||||
CPP_PUTS (pfile, "/**/", 4);
|
||||
skip_block_comment (pfile);
|
||||
continue;
|
||||
}
|
||||
/* else fall through */
|
||||
case '-':
|
||||
c = skip_comment (pfile, c);
|
||||
skip_comment (pfile, c);
|
||||
break;
|
||||
|
||||
case '\f':
|
||||
@ -512,23 +505,9 @@ copy_rest_of_line (pfile)
|
||||
break;
|
||||
|
||||
}
|
||||
CPP_PUTC (pfile, c);
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: It is almost definitely a performance win to make this do
|
||||
the scan itself. >75% of calls to copy_r_o_l are from here or
|
||||
skip_if_group, which means the common case is to copy stuff into the
|
||||
token_buffer only to discard it. */
|
||||
static void
|
||||
skip_rest_of_line (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
long old = CPP_WRITTEN (pfile);
|
||||
copy_rest_of_line (pfile);
|
||||
CPP_SET_WRITTEN (pfile, old);
|
||||
}
|
||||
|
||||
/* Handle a possible # directive.
|
||||
'#' has already been read. */
|
||||
|
||||
@ -542,6 +521,12 @@ handle_directive (pfile)
|
||||
U_CHAR *ident;
|
||||
long old_written = CPP_WRITTEN (pfile);
|
||||
|
||||
if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
|
||||
{
|
||||
cpp_ice (pfile, "handle_directive called on macro buffer");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cpp_skip_hspace (pfile);
|
||||
|
||||
c = PEEKC ();
|
||||
@ -629,71 +614,88 @@ pass_thru_directive (buf, len, pfile, keyword)
|
||||
CPP_PUTS_Q (pfile, buf, len);
|
||||
}
|
||||
|
||||
/* Check a purported macro name SYMNAME, and yield its length. */
|
||||
/* Subroutine of do_define: determine the name of the macro to be
|
||||
defined. */
|
||||
|
||||
int
|
||||
check_macro_name (pfile, symname)
|
||||
static int
|
||||
get_macro_name (pfile)
|
||||
cpp_reader *pfile;
|
||||
const U_CHAR *symname;
|
||||
{
|
||||
const U_CHAR *p;
|
||||
int sym_length;
|
||||
long here, len;
|
||||
|
||||
for (p = symname; is_idchar(*p); p++)
|
||||
;
|
||||
sym_length = p - symname;
|
||||
if (sym_length == 0
|
||||
|| (sym_length == 1 && *symname == 'L' && (*p == '\'' || *p == '"')))
|
||||
cpp_error (pfile, "invalid macro name");
|
||||
else if (!is_idstart(*symname)
|
||||
|| (! strncmp (symname, "defined", 7) && sym_length == 7)) {
|
||||
U_CHAR *msg; /* what pain... */
|
||||
msg = (U_CHAR *) alloca (sym_length + 1);
|
||||
bcopy (symname, msg, sym_length);
|
||||
msg[sym_length] = 0;
|
||||
cpp_error (pfile, "invalid macro name `%s'", msg);
|
||||
}
|
||||
return sym_length;
|
||||
here = CPP_WRITTEN (pfile);
|
||||
pfile->no_macro_expand++;
|
||||
if (get_directive_token (pfile) != CPP_NAME)
|
||||
{
|
||||
cpp_error (pfile, "`#define' must be followed by an identifier");
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
len = CPP_WRITTEN (pfile) - here;
|
||||
if (len == 7 && !strncmp (pfile->token_buffer + here, "defined", 7))
|
||||
{
|
||||
cpp_error (pfile, "`defined' is not a legal macro name");
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
pfile->no_macro_expand--;
|
||||
return len;
|
||||
|
||||
invalid:
|
||||
skip_rest_of_line (pfile);
|
||||
pfile->no_macro_expand--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Process a #define command.
|
||||
KEYWORD is the keyword-table entry for #define,
|
||||
or NULL for a "predefined" macro,
|
||||
or the keyword-table entry for #pragma in the case of a #pragma poison. */
|
||||
or NULL for a "predefined" macro. */
|
||||
|
||||
static int
|
||||
do_define (pfile, keyword)
|
||||
cpp_reader *pfile;
|
||||
const struct directive *keyword;
|
||||
{
|
||||
MACRODEF mdef;
|
||||
HASHNODE *hp;
|
||||
DEFINITION *def;
|
||||
long here;
|
||||
U_CHAR *macro, *buf, *end;
|
||||
int len, c;
|
||||
int funlike = 0;
|
||||
U_CHAR *sym;
|
||||
|
||||
here = CPP_WRITTEN (pfile);
|
||||
copy_rest_of_line (pfile);
|
||||
|
||||
/* Copy out the line so we can pop the token buffer. */
|
||||
buf = pfile->token_buffer + here;
|
||||
end = CPP_PWRITTEN (pfile);
|
||||
macro = (U_CHAR *) alloca (end - buf + 1);
|
||||
memcpy (macro, buf, end - buf + 1);
|
||||
end = macro + (end - buf);
|
||||
|
||||
CPP_SET_WRITTEN (pfile, here);
|
||||
|
||||
mdef = create_definition (macro, end, pfile);
|
||||
if (mdef.defn == 0)
|
||||
len = get_macro_name (pfile);
|
||||
if (len == 0)
|
||||
return 0;
|
||||
|
||||
if ((hp = cpp_lookup (pfile, mdef.symnam, mdef.symlen)) != NULL)
|
||||
/* Copy out the name so we can pop the token buffer. */
|
||||
len = CPP_WRITTEN (pfile) - here;
|
||||
sym = (U_CHAR *) alloca (len + 1);
|
||||
memcpy (sym, pfile->token_buffer + here, len);
|
||||
sym[len] = '\0';
|
||||
CPP_SET_WRITTEN (pfile, here);
|
||||
|
||||
/* If the next character, with no intervening whitespace, is '(',
|
||||
then this is a function-like macro. */
|
||||
c = PEEKC ();
|
||||
if (c == '(')
|
||||
funlike = 1;
|
||||
else if (c != '\n' && !is_hspace (c))
|
||||
/* Otherwise, C99 requires white space after the name. We treat it
|
||||
as an object-like macro if this happens, with a warning. */
|
||||
cpp_pedwarn (pfile, "missing white space after `#define %.*s'", len, sym);
|
||||
|
||||
def = create_definition (pfile, funlike);
|
||||
if (def == 0)
|
||||
return 0;
|
||||
|
||||
if ((hp = cpp_lookup (pfile, sym, len)) != NULL)
|
||||
{
|
||||
int ok;
|
||||
|
||||
/* Redefining a macro is ok if the definitions are the same. */
|
||||
if (hp->type == T_MACRO)
|
||||
ok = ! compare_defs (pfile, mdef.defn, hp->value.defn);
|
||||
ok = ! compare_defs (pfile, def, hp->value.defn);
|
||||
/* Redefining a constant is ok with -D. */
|
||||
else if (hp->type == T_CONST || hp->type == T_STDC)
|
||||
ok = ! CPP_OPTIONS (pfile)->done_initializing;
|
||||
@ -704,14 +706,15 @@ do_define (pfile, keyword)
|
||||
if (! ok)
|
||||
{
|
||||
if (hp->type == T_POISON)
|
||||
cpp_error (pfile, "redefining poisoned `%.*s'",
|
||||
mdef.symlen, mdef.symnam);
|
||||
cpp_error (pfile, "redefining poisoned `%.*s'", len, sym);
|
||||
else
|
||||
cpp_pedwarn (pfile, "`%.*s' redefined", mdef.symlen, mdef.symnam);
|
||||
cpp_pedwarn (pfile, "`%.*s' redefined", len, sym);
|
||||
if (hp->type == T_MACRO && CPP_OPTIONS (pfile)->done_initializing)
|
||||
cpp_pedwarn_with_file_and_line (pfile, hp->value.defn->file,
|
||||
hp->value.defn->line, -1,
|
||||
{
|
||||
DEFINITION *d = hp->value.defn;
|
||||
cpp_pedwarn_with_file_and_line (pfile, d->file, d->line, d->col,
|
||||
"this is the location of the previous definition");
|
||||
}
|
||||
}
|
||||
if (hp->type != T_POISON)
|
||||
{
|
||||
@ -719,19 +722,19 @@ do_define (pfile, keyword)
|
||||
if (hp->type == T_MACRO)
|
||||
free_definition (hp->value.defn);
|
||||
hp->type = T_MACRO;
|
||||
hp->value.defn = mdef.defn;
|
||||
hp->value.defn = def;
|
||||
}
|
||||
}
|
||||
else
|
||||
cpp_install (pfile, mdef.symnam, mdef.symlen, T_MACRO, (char *)mdef.defn);
|
||||
cpp_install (pfile, sym, len, T_MACRO, (char *) def);
|
||||
|
||||
if (keyword != NULL && keyword->type == T_DEFINE)
|
||||
{
|
||||
if (CPP_OPTIONS (pfile)->debug_output
|
||||
|| CPP_OPTIONS (pfile)->dump_macros == dump_definitions)
|
||||
dump_definition (pfile, mdef.symnam, mdef.symlen, mdef.defn);
|
||||
dump_definition (pfile, sym, len, def);
|
||||
else if (CPP_OPTIONS (pfile)->dump_macros == dump_names)
|
||||
pass_thru_directive (mdef.symnam, mdef.symlen, pfile, keyword);
|
||||
pass_thru_directive (sym, len, pfile, keyword);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -766,6 +769,7 @@ cpp_push_buffer (pfile, buffer, length)
|
||||
new->alimit = new->rlimit = buffer + length;
|
||||
new->prev = buf;
|
||||
new->mark = -1;
|
||||
new->line_base = NULL;
|
||||
|
||||
CPP_BUFFER (pfile) = new;
|
||||
return new;
|
||||
@ -1309,7 +1313,7 @@ read_line_number (pfile, num)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (token != CPP_VSPACE && token != CPP_EOF && token != CPP_POP)
|
||||
if (token != CPP_VSPACE && token != CPP_EOF)
|
||||
cpp_error (pfile, "invalid format `#line' command");
|
||||
return 0;
|
||||
}
|
||||
@ -1467,15 +1471,14 @@ do_undef (pfile, keyword)
|
||||
len = limit - buf;
|
||||
name = (U_CHAR *) alloca (len + 1);
|
||||
memcpy (name, buf, len);
|
||||
name[limit - buf] = '\0';
|
||||
name[len] = '\0';
|
||||
|
||||
token = get_directive_token (pfile);
|
||||
if (token != CPP_VSPACE && token != CPP_POP)
|
||||
if (token != CPP_VSPACE)
|
||||
{
|
||||
cpp_pedwarn (pfile, "junk on line after #undef");
|
||||
skip_rest_of_line (pfile);
|
||||
}
|
||||
|
||||
CPP_SET_WRITTEN (pfile, here);
|
||||
|
||||
while ((hp = cpp_lookup (pfile, name, len)) != NULL)
|
||||
@ -1950,11 +1953,9 @@ eval_if_expression (pfile)
|
||||
HOST_WIDEST_INT value;
|
||||
long old_written = CPP_WRITTEN (pfile);
|
||||
|
||||
/* Work around bug in cpp_get_token where it may mistake an
|
||||
assertion for a directive. */
|
||||
pfile->only_seen_white = 0;
|
||||
|
||||
pfile->parsing_if_directive++;
|
||||
value = cpp_parse_expr (pfile);
|
||||
pfile->parsing_if_directive--;
|
||||
|
||||
skip_rest_of_line (pfile);
|
||||
CPP_SET_WRITTEN (pfile, old_written); /* Pop */
|
||||
@ -2148,13 +2149,6 @@ skip_if_group (pfile)
|
||||
U_CHAR *beg_of_line;
|
||||
long old_written;
|
||||
|
||||
if (CPP_OPTIONS (pfile)->output_conditionals)
|
||||
{
|
||||
CPP_PUTS (pfile, "#failed\n", 8);
|
||||
pfile->lineno++;
|
||||
output_line_command (pfile, same_file);
|
||||
}
|
||||
|
||||
old_written = CPP_WRITTEN (pfile);
|
||||
|
||||
for (;;)
|
||||
@ -2166,8 +2160,6 @@ skip_if_group (pfile)
|
||||
c = GETC();
|
||||
if (c == '\n')
|
||||
{
|
||||
if (CPP_OPTIONS (pfile)->output_conditionals)
|
||||
CPP_PUTC (pfile, c);
|
||||
CPP_BUMP_LINE (pfile);
|
||||
continue;
|
||||
}
|
||||
@ -2180,41 +2172,19 @@ skip_if_group (pfile)
|
||||
return; /* Caller will issue error. */
|
||||
|
||||
FORWARD(-1);
|
||||
if (CPP_OPTIONS (pfile)->output_conditionals)
|
||||
{
|
||||
CPP_PUTS (pfile, beg_of_line, CPP_BUFFER (pfile)->cur - beg_of_line);
|
||||
copy_rest_of_line (pfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
copy_rest_of_line (pfile);
|
||||
CPP_SET_WRITTEN (pfile, old_written); /* discard it */
|
||||
}
|
||||
skip_rest_of_line (pfile);
|
||||
|
||||
c = GETC();
|
||||
if (c == EOF)
|
||||
return; /* Caller will issue error. */
|
||||
else
|
||||
{
|
||||
/* \n */
|
||||
if (CPP_OPTIONS (pfile)->output_conditionals)
|
||||
{
|
||||
CPP_PUTC (pfile, c);
|
||||
pfile->lineno++;
|
||||
}
|
||||
CPP_BUMP_LINE (pfile);
|
||||
}
|
||||
CPP_BUMP_LINE (pfile);
|
||||
}
|
||||
|
||||
/* Back up to the beginning of this line. Caller will process the
|
||||
directive. */
|
||||
CPP_BUFFER (pfile)->cur = beg_of_line;
|
||||
pfile->only_seen_white = 1;
|
||||
if (CPP_OPTIONS (pfile)->output_conditionals)
|
||||
{
|
||||
CPP_PUTS (pfile, "#endfailed\n", 11);
|
||||
pfile->lineno++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -2443,6 +2413,27 @@ cpp_get_token (pfile)
|
||||
}
|
||||
|
||||
case '#':
|
||||
if (pfile->parsing_if_directive)
|
||||
{
|
||||
cpp_skip_hspace (pfile);
|
||||
parse_assertion (pfile);
|
||||
return CPP_ASSERTION;
|
||||
}
|
||||
|
||||
if (pfile->parsing_define_directive && ! CPP_TRADITIONAL (pfile))
|
||||
{
|
||||
CPP_RESERVE (pfile, 3);
|
||||
CPP_PUTC_Q (pfile, '#');
|
||||
CPP_NUL_TERMINATE_Q (pfile);
|
||||
if (PEEKC () != '#')
|
||||
return CPP_STRINGIZE;
|
||||
|
||||
FORWARD (1);
|
||||
CPP_PUTC_Q (pfile, '#');
|
||||
CPP_NUL_TERMINATE_Q (pfile);
|
||||
return CPP_TOKPASTE;
|
||||
}
|
||||
|
||||
if (!pfile->only_seen_white)
|
||||
goto randomchar;
|
||||
/* -traditional directives are recognized only with the # in
|
||||
@ -2886,35 +2877,24 @@ parse_name (pfile, c)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Parse a string starting with C. A single quoted string is treated
|
||||
like a double -- some programs (e.g., troff) are perverse this way.
|
||||
(However, a single quoted string is not allowed to extend over
|
||||
multiple lines.) */
|
||||
/* Parse and skip over a string starting with C. A single quoted
|
||||
string is treated like a double -- some programs (e.g., troff) are
|
||||
perverse this way. (However, a single quoted string is not allowed
|
||||
to extend over multiple lines.) */
|
||||
static void
|
||||
parse_string (pfile, c)
|
||||
skip_string (pfile, c)
|
||||
cpp_reader *pfile;
|
||||
int c;
|
||||
{
|
||||
long start_line, start_column;
|
||||
|
||||
cpp_buf_line_and_col (cpp_file_buffer (pfile), &start_line, &start_column);
|
||||
|
||||
CPP_PUTC (pfile, c);
|
||||
while (1)
|
||||
{
|
||||
int cc = GETC();
|
||||
if (cc == EOF)
|
||||
switch (cc)
|
||||
{
|
||||
if (CPP_IS_MACRO_BUFFER (CPP_BUFFER (pfile)))
|
||||
{
|
||||
/* try harder: this string crosses a macro expansion
|
||||
boundary. This can happen naturally if -traditional.
|
||||
Otherwise, only -D can make a macro with an unmatched
|
||||
quote. */
|
||||
cpp_pop_buffer (pfile);
|
||||
continue;
|
||||
}
|
||||
|
||||
case EOF:
|
||||
cpp_error_with_line (pfile, start_line, start_column,
|
||||
"unterminated string or character constant");
|
||||
if (pfile->multiline_string_line != start_line
|
||||
@ -2923,22 +2903,20 @@ parse_string (pfile, c)
|
||||
pfile->multiline_string_line, -1,
|
||||
"possible real start of unterminated constant");
|
||||
pfile->multiline_string_line = 0;
|
||||
break;
|
||||
}
|
||||
CPP_PUTC (pfile, cc);
|
||||
switch (cc)
|
||||
{
|
||||
return;
|
||||
|
||||
case '\n':
|
||||
CPP_BUMP_LINE (pfile);
|
||||
pfile->lineno++;
|
||||
|
||||
/* In Fortran and assembly language, silently terminate
|
||||
strings of either variety at end of line. This is a
|
||||
kludge around not knowing where comments are in these
|
||||
languages. */
|
||||
if (CPP_OPTIONS (pfile)->lang_fortran
|
||||
|| CPP_OPTIONS (pfile)->lang_asm)
|
||||
return;
|
||||
{
|
||||
FORWARD(-1);
|
||||
return;
|
||||
}
|
||||
/* Character constants may not extend over multiple lines.
|
||||
In Standard C, neither may strings. We accept multiline
|
||||
strings as an extension. */
|
||||
@ -2946,6 +2924,7 @@ parse_string (pfile, c)
|
||||
{
|
||||
cpp_error_with_line (pfile, start_line, start_column,
|
||||
"unterminated character constant");
|
||||
FORWARD(-1);
|
||||
return;
|
||||
}
|
||||
if (CPP_PEDANTIC (pfile) && pfile->multiline_string_line == 0)
|
||||
@ -2956,7 +2935,6 @@ parse_string (pfile, c)
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
CPP_ADJUST_WRITTEN (pfile, -1);
|
||||
if (CPP_BUFFER (pfile)->has_escapes)
|
||||
{
|
||||
cpp_ice (pfile, "\\r escape inside string constant");
|
||||
@ -2968,9 +2946,7 @@ parse_string (pfile, c)
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
cc = GETC();
|
||||
if (cc != EOF)
|
||||
CPP_PUTC (pfile, cc);
|
||||
FORWARD(1);
|
||||
break;
|
||||
|
||||
case '\"':
|
||||
@ -2982,6 +2958,26 @@ parse_string (pfile, c)
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse a string and copy it to the output. */
|
||||
|
||||
static void
|
||||
parse_string (pfile, c)
|
||||
cpp_reader *pfile;
|
||||
int c;
|
||||
{
|
||||
U_CHAR *start = CPP_BUFFER (pfile)->cur; /* XXX Layering violation */
|
||||
U_CHAR *limit;
|
||||
|
||||
skip_string (pfile, c);
|
||||
|
||||
limit = CPP_BUFFER (pfile)->cur;
|
||||
CPP_RESERVE (pfile, limit - start + 2);
|
||||
CPP_PUTC_Q (pfile, c);
|
||||
for (; start < limit; start++)
|
||||
if (*start != '\r')
|
||||
CPP_PUTC_Q (pfile, *start);
|
||||
}
|
||||
|
||||
/* Read an assertion into the token buffer, converting to
|
||||
canonical form: `#predicate(a n swe r)' The next non-whitespace
|
||||
character to read should be the first letter of the predicate.
|
||||
@ -3199,33 +3195,11 @@ cpp_unassert (pfile, str)
|
||||
{
|
||||
if (cpp_push_buffer (pfile, str, strlen (str)) != NULL)
|
||||
{
|
||||
do_assert (pfile, NULL);
|
||||
do_unassert (pfile, NULL);
|
||||
cpp_pop_buffer (pfile);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
cpp_read_check_assertion (pfile)
|
||||
cpp_reader *pfile;
|
||||
{
|
||||
U_CHAR *name;
|
||||
int result;
|
||||
long written = CPP_WRITTEN (pfile);
|
||||
|
||||
FORWARD (1); /* Skip '#' */
|
||||
cpp_skip_hspace (pfile);
|
||||
if (! parse_assertion (pfile))
|
||||
result = 0;
|
||||
else
|
||||
{
|
||||
name = pfile->token_buffer + written;
|
||||
result = cpp_defined (pfile, name, CPP_PWRITTEN (pfile) - name);
|
||||
}
|
||||
|
||||
CPP_SET_WRITTEN (pfile, written);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Remember the current position of PFILE so it may be returned to
|
||||
after looking ahead a bit.
|
||||
|
||||
|
35
gcc/cpplib.h
35
gcc/cpplib.h
@ -47,14 +47,17 @@ enum cpp_token {
|
||||
CPP_STRING,
|
||||
CPP_WSTRING,
|
||||
CPP_DIRECTIVE,
|
||||
CPP_LPAREN, /* "(" */
|
||||
CPP_RPAREN, /* ")" */
|
||||
CPP_LBRACE, /* "{" */
|
||||
CPP_RBRACE, /* "}" */
|
||||
CPP_COMMA, /* "," */
|
||||
CPP_SEMICOLON,/* ";" */
|
||||
CPP_3DOTS, /* "..." */
|
||||
CPP_POP /* We're about to pop the buffer stack. */
|
||||
CPP_ASSERTION, /* #machine(a29k) */
|
||||
CPP_STRINGIZE, /* stringize macro argument */
|
||||
CPP_TOKPASTE, /* paste macro arg with next/prev token */
|
||||
CPP_LPAREN, /* "(" */
|
||||
CPP_RPAREN, /* ")" */
|
||||
CPP_LBRACE, /* "{" */
|
||||
CPP_RBRACE, /* "}" */
|
||||
CPP_COMMA, /* "," */
|
||||
CPP_SEMICOLON, /* ";" */
|
||||
CPP_3DOTS, /* "..." */
|
||||
CPP_POP /* We're about to pop the buffer stack. */
|
||||
};
|
||||
|
||||
typedef enum cpp_token (*parse_underflow_t) PARAMS((cpp_reader *));
|
||||
@ -193,7 +196,6 @@ struct cpp_reader
|
||||
|
||||
/* If non-zero, directives cause a hard error. Used when parsing
|
||||
macro arguments. */
|
||||
|
||||
char no_directives;
|
||||
|
||||
/* Print column number in error messages. */
|
||||
@ -205,6 +207,12 @@ struct cpp_reader
|
||||
/* If true, character between '<' and '>' are a single (string) token. */
|
||||
char parsing_include_directive;
|
||||
|
||||
/* If true, # introduces an assertion (see do_assert) */
|
||||
char parsing_if_directive;
|
||||
|
||||
/* If true, # and ## are the STRINGIZE and TOKPASTE operators */
|
||||
char parsing_define_directive;
|
||||
|
||||
/* True if escape sequences (as described for has_escapes in
|
||||
parse_buffer) should be emitted. */
|
||||
char output_escapes;
|
||||
@ -217,7 +225,7 @@ struct cpp_reader
|
||||
/* Nonzero means this file was included with a -imacros or -include
|
||||
command line and should not be recorded as an include file. */
|
||||
|
||||
int no_record_file;
|
||||
char no_record_file;
|
||||
|
||||
long lineno;
|
||||
|
||||
@ -427,11 +435,6 @@ struct cpp_options {
|
||||
|
||||
char no_line_commands;
|
||||
|
||||
/* Nonzero means output the text in failing conditionals,
|
||||
inside #failed ... #endfailed. */
|
||||
|
||||
char output_conditionals;
|
||||
|
||||
/* Nonzero means -I- has been seen,
|
||||
so don't look for #include "foo" the source-file directory. */
|
||||
char ignore_srcdir;
|
||||
@ -689,14 +692,12 @@ extern int cpp_defined PARAMS ((cpp_reader *, const U_CHAR *, int));
|
||||
extern void cpp_reader_init PARAMS ((cpp_reader *));
|
||||
extern void cpp_options_init PARAMS ((cpp_options *));
|
||||
extern int cpp_start_read PARAMS ((cpp_reader *, char *));
|
||||
extern int cpp_read_check_assertion PARAMS ((cpp_reader *));
|
||||
extern void cpp_finish PARAMS ((cpp_reader *));
|
||||
|
||||
extern void quote_string PARAMS ((cpp_reader *, const char *));
|
||||
extern void cpp_expand_to_buffer PARAMS ((cpp_reader *, const U_CHAR *,
|
||||
int));
|
||||
extern void cpp_scan_buffer PARAMS ((cpp_reader *));
|
||||
extern int check_macro_name PARAMS ((cpp_reader *, const U_CHAR *));
|
||||
|
||||
/* Last arg to output_line_command. */
|
||||
enum file_change_code {same_file, rename_file, enter_file, leave_file};
|
||||
|
@ -1,5 +1,7 @@
|
||||
/* { dg-do compile } */
|
||||
/* Distilled from glibc sources. Tests preprocessor corner cases. */
|
||||
/* { dg-options "-Wall" } */
|
||||
/* Distilled from glibc sources. Tests preprocessor corner cases.
|
||||
Since it uses rest args, we must turn off -pedantic-errors. */
|
||||
|
||||
#define NO_PAREN(rest...) rest
|
||||
#define DEFINE_CATEGORY(category, items) \
|
||||
|
23
gcc/testsuite/gcc.dg/strpaste-2.c
Normal file
23
gcc/testsuite/gcc.dg/strpaste-2.c
Normal file
@ -0,0 +1,23 @@
|
||||
/* { dg-do run } */
|
||||
|
||||
/* Test for odd corner cases in stringizing/pasting.
|
||||
Taken more or less verbatim from C99 section 6.10.3.3. */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define hash_hash # ## #
|
||||
#define mkstr(a) # a
|
||||
#define in_between(a) mkstr(a)
|
||||
#define join(c, d) in_between(c hash_hash d)
|
||||
|
||||
const char p[] = join(x, y);
|
||||
const char q[] = "x ## y";
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
if (strcmp (p, q))
|
||||
abort ();
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user