From: Zack Weinberg Date: Thu, 18 May 2000 15:55:46 +0000 (+0000) Subject: cppexp.c (parse_assertion): New. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=15dad1d9085624c3bce83e0fa0d9b2764f65bccb;p=gcc.git cppexp.c (parse_assertion): New. * cppexp.c (parse_assertion): New. (lex): Call it for CPP_HASH. Remove CPP_ASSERTION case. (_cpp_parse_expr): Remove case '#'. Don't set parsing_if_directive. * cpphash.c (collect_objlike_expansion, collect_funlike_expansion, collect_params, _cpp_create_definition): The list no longer has a trailing VSPACE token. * cpphash.h (enum node_type): Add T_ASSERTION. (struct hashnode): Remove aschain, add pred. (struct predicate): New. Update prototypes. * cpplex.c (expand_token_space): Handle both offset and nonoffset lists. (init_token_list, _cpp_free_token_list, _cpp_parse_assertion): Delete. (_cpp_init_toklist, _cpp_clear_toklist, _cpp_free_toklist, _cpp_slice_toklist, _cpp_squeeze_toklist, _cpp_equiv_tokens, _cpp_equiv_toklists): New. (_cpp_scan_line): Rename to _cpp_scan_until; add ability to stop at any single-character token, not just newline. (_cpp_lex_token): Remove special cases for #define and #if. (cpp_get_token): Expect # as a separate token type. Remove DIRECTIVE case. (_cpp_get_directive_token): Remove DIRECTIVE case. (_cpp_lex_line, _cpp_lex_file, _cpp_init_input_buffer): Update. * cpplib.c (_cpp_check_directive): Set dirno and SYNTAX_INCLUDE bit of flags, not dir_handler and dir_flags. (_cpp_handle_directive): Run # through the same logic as normal directives. (do_define): Don't set parsing_define_directive. Use _cpp_scan_until. The list does not have a VSPACE at the end. (do_if): Save, clear, and restore only_seen_white around _cpp_parse_expr. (skip_if_group): s/CPP_DIRECTIVE/CPP_HASH/ (do_assert, do_unassert): Rewrite. * cpplib.h (TTYPE_TABLE): Remove CPP_ASSERTION. (LIST_OFFSET): New flag. (struct cpp_toklist): Replace dir_handler and dir_flags with dirno and flags. (struct cpp_reader): Remove parsing_if_directive and parsing_define_directive. From-SVN: r33984 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1637585c78a..66fdc617a77 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,50 @@ +2000-05-18 Zack Weinberg + + * cppexp.c (parse_assertion): New. + (lex): Call it for CPP_HASH. Remove CPP_ASSERTION case. + (_cpp_parse_expr): Remove case '#'. Don't set + parsing_if_directive. + * cpphash.c (collect_objlike_expansion, + collect_funlike_expansion, collect_params, + _cpp_create_definition): The list no longer has a trailing + VSPACE token. + * cpphash.h (enum node_type): Add T_ASSERTION. + (struct hashnode): Remove aschain, add pred. + (struct predicate): New. + Update prototypes. + + * cpplex.c (expand_token_space): Handle both offset and + nonoffset lists. + (init_token_list, _cpp_free_token_list, _cpp_parse_assertion): Delete. + (_cpp_init_toklist, _cpp_clear_toklist, _cpp_free_toklist, + _cpp_slice_toklist, _cpp_squeeze_toklist, _cpp_equiv_tokens, + _cpp_equiv_toklists): New. + (_cpp_scan_line): Rename to _cpp_scan_until; add ability to + stop at any single-character token, not just newline. + (_cpp_lex_token): Remove special cases for #define and #if. + (cpp_get_token): Expect # as a separate token type. Remove + DIRECTIVE case. + (_cpp_get_directive_token): Remove DIRECTIVE case. + (_cpp_lex_line, _cpp_lex_file, _cpp_init_input_buffer): Update. + + * cpplib.c (_cpp_check_directive): Set dirno and + SYNTAX_INCLUDE bit of flags, not dir_handler and dir_flags. + (_cpp_handle_directive): Run # through the same logic + as normal directives. + (do_define): Don't set parsing_define_directive. Use + _cpp_scan_until. The list does not have a VSPACE at the end. + (do_if): Save, clear, and restore only_seen_white around + _cpp_parse_expr. + (skip_if_group): s/CPP_DIRECTIVE/CPP_HASH/ + (do_assert, do_unassert): Rewrite. + + * cpplib.h (TTYPE_TABLE): Remove CPP_ASSERTION. + (LIST_OFFSET): New flag. + (struct cpp_toklist): Replace dir_handler and dir_flags with + dirno and flags. + (struct cpp_reader): Remove parsing_if_directive and + parsing_define_directive. + 2000-05-18 Kaveh R. Ghazi * fixinc/inclhack.def (broken_cabs): Update fix to handle comments diff --git a/gcc/cppexp.c b/gcc/cppexp.c index 7e99292f9a1..4e619150487 100644 --- a/gcc/cppexp.c +++ b/gcc/cppexp.c @@ -82,6 +82,7 @@ static struct operation parse_number PARAMS ((cpp_reader *, 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 parse_assertion PARAMS ((cpp_reader *)); static HOST_WIDEST_INT parse_escape PARAMS ((cpp_reader *, U_CHAR **, HOST_WIDEST_INT)); static struct operation lex PARAMS ((cpp_reader *, int)); @@ -110,6 +111,15 @@ struct operation HOST_WIDEST_INT value; /* The value logically "right" of op. */ }; +/* With -O2, gcc appears to produce nice code, moving the error + message load and subsequent jump completely out of the main path. */ +#define CPP_ICE(msgid) \ + do { cpp_ice (pfile, msgid); goto syntax_error; } while(0) +#define SYNTAX_ERROR(msgid) \ + do { cpp_error (pfile, msgid); goto syntax_error; } while(0) +#define SYNTAX_ERROR2(msgid, arg) \ + do { cpp_error (pfile, msgid, arg); goto syntax_error; } while(0) + /* Parse and convert an integer for #if. Accepts decimal, hex, or octal with or without size suffixes. */ @@ -379,6 +389,81 @@ parse_defined (pfile) return op; } +static struct operation +parse_assertion (pfile) + cpp_reader *pfile; +{ + struct operation op; + HASHNODE *hp; + struct predicate *pred; + cpp_toklist query; + enum cpp_ttype type; + U_CHAR *tok; + size_t len; + unsigned int old_written; + int specific = 0; + + old_written = CPP_WRITTEN (pfile); + CPP_PUTC (pfile, '#'); + pfile->no_macro_expand++; + type = _cpp_get_directive_token (pfile); + if (type == CPP_VSPACE) + SYNTAX_ERROR ("assertion without predicate"); + else if (type != CPP_NAME) + SYNTAX_ERROR ("assertion predicate is not an identifier"); + + tok = pfile->token_buffer + old_written; + len = CPP_WRITTEN (pfile) - old_written; + hp = _cpp_lookup (pfile, tok, len); + + /* Look ahead for an open paren. */ + _cpp_skip_hspace (pfile); + if (CPP_BUF_PEEK (CPP_BUFFER (pfile)) == '(') + { + if (_cpp_get_directive_token (pfile) != CPP_OPEN_PAREN) + CPP_ICE ("impossible token, expecting ( in parse_assertion"); + + _cpp_init_toklist (&query); + specific = 1; + if (_cpp_scan_until (pfile, &query, CPP_CLOSE_PAREN) != CPP_CLOSE_PAREN) + SYNTAX_ERROR ("missing close paren on assertion answer"); + + if (_cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN) + CPP_ICE ("impossible token, expecting ) in parse_assertion"); + } + + /* If we get here, the syntax is valid. */ + op.op = INT; + op.value = 0; + /* Has this predicate been asserted at all? */ + if (hp->type == T_ASSERTION) + { + if (specific) + { + for (pred = hp->value.pred; pred; pred = pred->next) + if (_cpp_equiv_toklists (&query, &pred->answer)) + { + op.value = 1; + break; + } + _cpp_free_toklist (&query); + } + else + op.value = 1; + } + + out: + pfile->no_macro_expand--; + CPP_SET_WRITTEN (pfile, old_written); + return op; + + syntax_error: + if (specific) + _cpp_free_toklist (&query); + op.op = ERROR; + goto out; +} + struct token { const char *operator; @@ -451,11 +536,8 @@ lex (pfile, skip_evaluation) (int) (tok_end - tok_start), tok_start); return op; - case CPP_ASSERTION: - op.op = INT; - op.unsignedp = 0; - op.value = cpp_defined (pfile, tok_start, tok_end - tok_start); - return op; + case CPP_HASH: + return parse_assertion (pfile); case CPP_OTHER: /* See if it is a special token of length 2. */ @@ -734,15 +816,6 @@ be handled with operator-specific code. */ top->value = v1 OP v2; \ top->unsignedp = unsigned1 | unsigned2; -/* With -O2, gcc appears to produce nice code, moving the error - message load and subsequent jump completely out of the main path. */ -#define CPP_ICE(msgid) \ - do { cpp_ice (pfile, msgid); goto syntax_error; } while(0) -#define SYNTAX_ERROR(msgid) \ - do { cpp_error (pfile, msgid); goto syntax_error; } while(0) -#define SYNTAX_ERROR2(msgid, arg) \ - do { cpp_error (pfile, msgid, arg); goto syntax_error; } while(0) - /* Parse and evaluate a C expression, reading from PFILE. Returns the truth value of the expression. */ @@ -770,7 +843,6 @@ _cpp_parse_expr (pfile) int result; char buff[5]; - pfile->parsing_if_directive++; /* We've finished when we try to reduce this. */ top->op = FINISHED; /* Nifty way to catch missing '('. */ @@ -796,11 +868,6 @@ _cpp_parse_expr (pfile) CPP_ICE ("lex returns a NAME"); case ERROR: goto syntax_error; - case '#': - /* We get '#' when get_directive_token hits a syntactically - invalid assertion predicate. _cpp_parse_assertion has - already issued an error. */ - goto syntax_error; default: SYNTAX_ERROR ("invalid character in #if"); @@ -1094,7 +1161,6 @@ _cpp_parse_expr (pfile) /* Free dynamic stack if we allocated one. */ if (stack != init_stack) free (stack); - pfile->parsing_if_directive--; CPP_SET_WRITTEN (pfile, old_written); return result; } diff --git a/gcc/cpphash.c b/gcc/cpphash.c index 21efb090ad4..3eb7d1a0e7a 100644 --- a/gcc/cpphash.c +++ b/gcc/cpphash.c @@ -480,12 +480,6 @@ collect_objlike_expansion (pfile, list) { switch (TOK_TYPE (list, i)) { - case CPP_EOF: - cpp_ice (pfile, "EOF in collect_expansion"); - /* fall through */ - case CPP_VSPACE: - goto done; - case CPP_PASTE: /* ## is not special if it appears right after another ##; nor is it special if -traditional. */ @@ -506,7 +500,6 @@ collect_objlike_expansion (pfile, list) CPP_PUTS (pfile, TOK_NAME (list, i), TOK_LEN (list, i)); last_was_paste = 0; } - done: if (last_was_paste) cpp_error (pfile, "`##' at end of macro definition"); @@ -568,12 +561,6 @@ collect_funlike_expansion (pfile, list, arglist, replacement) len = TOK_LEN (list, i); switch (token) { - case CPP_EOF: - cpp_ice (pfile, "EOF in collect_expansion"); - /* fall through */ - case CPP_VSPACE: - goto done; - case CPP_HASH: /* # is special in function-like macros with no args. (6.10.3.2 para 1.) However, it is not special after @@ -677,7 +664,6 @@ collect_funlike_expansion (pfile, list, arglist, replacement) } last_token = ARG; } - done: if (last_token == STRIZE) cpp_error (pfile, "`#' is not followed by a macro argument name"); @@ -759,8 +745,8 @@ collect_params (pfile, list, arglist) case CPP_CLOSE_PAREN: goto scanned; case CPP_VSPACE: - cpp_error_with_line (pfile, list->line, TOK_COL (list, i), - "missing right paren in macro argument list"); + case CPP_EOF: + cpp_ice (pfile, "impossible token in macro argument list"); return 0; default: @@ -783,9 +769,8 @@ collect_params (pfile, list, arglist) } goto scanned; } - - cpp_ice (pfile, "collect_params: unreachable - i=%d, ntokens=%d, type=%d", - i, list->tokens_used, TOK_TYPE (list, i-1)); + cpp_error_with_line (pfile, list->line, TOK_COL (list, i-1), + "missing right paren in macro argument list"); return 0; scanned: @@ -892,9 +877,9 @@ _cpp_create_definition (pfile, list, hp) #define FUNC(a, b, ...) // nothing #define FUNC(a, b, c) FUNC(a, b, c) */ - if (list->tokens_used == 2) + if (list->tokens_used == 1) ntype = T_EMPTY; /* Empty definition of object-like macro. */ - else if (list->tokens_used == 3 && TOK_TYPE (list, 1) == CPP_NAME + else if (list->tokens_used == 2 && TOK_TYPE (list, 1) == CPP_NAME && TOK_LEN (list, 0) == TOK_LEN (list, 1) && !ustrncmp (TOK_NAME (list, 0), TOK_NAME (list, 1), TOK_LEN (list, 0))) diff --git a/gcc/cpphash.h b/gcc/cpphash.h index 4b8c50ec7c0..927927c03d3 100644 --- a/gcc/cpphash.h +++ b/gcc/cpphash.h @@ -49,7 +49,8 @@ enum node_type T_MACRO, /* object-like macro */ T_FMACRO, /* function-like macro */ T_IDENTITY, /* macro defined to itself */ - T_EMPTY /* macro defined to nothing */ + T_EMPTY, /* macro defined to nothing */ + T_ASSERTION /* predicate for #assert */ }; typedef struct hashnode HASHNODE; @@ -64,12 +65,19 @@ struct hashnode const U_CHAR *cpval; /* some predefined macros */ const struct object_defn *odefn; /* #define foo bar */ const struct funct_defn *fdefn; /* #define foo(x) bar(x) */ - struct hashnode *aschain; /* #assert */ + struct predicate *pred; /* #assert */ } value; const U_CHAR name[1]; /* name[length] */ }; +/* Structure used for assertion predicates. */ +struct predicate +{ + struct predicate *next; + struct cpp_toklist answer; +}; + /* List of directories to look for include files in. */ struct file_name_list { @@ -250,7 +258,20 @@ extern enum cpp_ttype _cpp_get_directive_token PARAMS ((cpp_reader *)); extern enum cpp_ttype _cpp_get_define_token PARAMS ((cpp_reader *)); -extern void _cpp_scan_line PARAMS ((cpp_reader *, cpp_toklist *)); +extern enum cpp_ttype _cpp_scan_until PARAMS ((cpp_reader *, cpp_toklist *, + enum cpp_ttype)); +extern void _cpp_init_toklist PARAMS ((cpp_toklist *)); +extern void _cpp_clear_toklist PARAMS ((cpp_toklist *)); +extern void _cpp_free_toklist PARAMS ((cpp_toklist *)); +extern void _cpp_slice_toklist PARAMS ((cpp_toklist *, + const cpp_token *, + const cpp_token *)); +extern void _cpp_squeeze_toklist PARAMS ((cpp_toklist *)); +extern int _cpp_equiv_tokens PARAMS ((const cpp_token *, + const cpp_token *)); +extern int _cpp_equiv_toklists PARAMS ((const cpp_toklist *, + const cpp_toklist *)); + /* In cpplib.c */ extern int _cpp_handle_directive PARAMS ((cpp_reader *)); diff --git a/gcc/cpplex.c b/gcc/cpplex.c index f0414a0fdca..117f61039f3 100644 --- a/gcc/cpplex.c +++ b/gcc/cpplex.c @@ -55,7 +55,6 @@ static void bump_column PARAMS ((cpp_printer *, unsigned int, unsigned int)); static void expand_name_space PARAMS ((cpp_toklist *, unsigned int)); static void expand_token_space PARAMS ((cpp_toklist *)); -static void init_token_list PARAMS ((cpp_reader *, cpp_toklist *, int)); static void pedantic_whitespace PARAMS ((cpp_reader *, U_CHAR *, unsigned int)); @@ -491,7 +490,7 @@ cpp_scan_buffer (pfile, print) for (;;) { token = cpp_get_token (pfile); - if (token == CPP_EOF || token == CPP_VSPACE + if (token == CPP_VSPACE || token == CPP_EOF /* XXX Temporary kluge - force flush after #include only */ || (token == CPP_DIRECTIVE && CPP_BUFFER (pfile)->nominal_fname != print->last_fname)) @@ -548,63 +547,212 @@ expand_token_space (list) cpp_toklist *list; { list->tokens_cap *= 2; + if (list->flags & LIST_OFFSET) + list->tokens--; list->tokens = (cpp_token *) - xrealloc (list->tokens - 1, (list->tokens_cap + 1) * sizeof (cpp_token)); - list->tokens++; /* Skip the dummy. */ + xrealloc (list->tokens, (list->tokens_cap + 1) * sizeof (cpp_token)); + if (list->flags & LIST_OFFSET) + list->tokens++; /* Skip the dummy. */ } /* Initialize a token list. We allocate an extra token in front of the token list, as this allows us to always peek at the previous token without worrying about underflowing the list. */ -static void -init_token_list (pfile, list, recycle) - cpp_reader *pfile; +void +_cpp_init_toklist (list) cpp_toklist *list; - int recycle; { - /* Recycling a used list saves 3 free-malloc pairs. */ - if (!recycle) - { - /* Initialize token space. Put a dummy token before the start - that will fail matches. */ - list->tokens_cap = 256; /* 4K's worth. */ - list->tokens = (cpp_token *) - xmalloc ((list->tokens_cap + 1) * sizeof (cpp_token)); - list->tokens[0].type = CPP_EOF; - list->tokens++; - - /* Initialize name space. */ - list->name_cap = 1024; - list->namebuf = (unsigned char *) xmalloc (list->name_cap); - - /* Only create a comment space on demand. */ - list->comments_cap = 0; - list->comments = 0; - } + /* Initialize token space. Put a dummy token before the start + that will fail matches. */ + list->tokens_cap = 256; /* 4K's worth. */ + list->tokens = (cpp_token *) + xmalloc ((list->tokens_cap + 1) * sizeof (cpp_token)); + list->tokens[0].type = CPP_EOF; + list->tokens++; + + /* Initialize name space. */ + list->name_cap = 1024; + list->namebuf = (unsigned char *) xmalloc (list->name_cap); + + /* Only create a comment space on demand. */ + list->comments_cap = 0; + list->comments = 0; + + list->flags = LIST_OFFSET; + _cpp_clear_toklist (list); +} +/* Clear a token list. */ +void +_cpp_clear_toklist (list) + cpp_toklist *list; +{ list->tokens_used = 0; list->name_used = 0; list->comments_used = 0; - if (pfile->buffer) - list->line = pfile->buffer->lineno; - list->dir_handler = 0; - list->dir_flags = 0; + list->dirno = -1; + list->flags &= LIST_OFFSET; /* clear all but that one */ +} + +/* Free a token list. Does not free the list itself, which may be + embedded in a larger structure. */ +void +_cpp_free_toklist (list) + cpp_toklist *list; +{ + if (list->comments) + free (list->comments); + if (list->flags & LIST_OFFSET) + free (list->tokens - 1); /* Backup over dummy token. */ + else + free (list->tokens); + free (list->namebuf); } -/* Scan an entire line and create a token list for it. Does not - macro-expand or execute directives. */ +/* Slice a token list: copy the sublist [START, FINISH) into COPY. + COPY is assumed not to be initialized. The comment space is not + copied. */ +void +_cpp_slice_toklist (copy, start, finish) + cpp_toklist *copy; + const cpp_token *start, *finish; +{ + unsigned int i, n; + size_t bytes; + + n = finish - start; + copy->tokens_cap = n; + copy->tokens = (cpp_token *) xmalloc (n * sizeof (cpp_token)); + memcpy (copy->tokens, start, n * sizeof (cpp_token)); + + bytes = 0; + for (i = 0; i < n; i++) + if (token_spellings[start[i].type].type > SPELL_NONE) + bytes += start[i].val.name.len; + + copy->namebuf = xmalloc (bytes); + bytes = 0; + for (i = 0; i < n; i++) + if (token_spellings[start[i].type].type > SPELL_NONE) + { + memcpy (copy->namebuf + bytes, + start[i].val.name.text, start[i].val.name.len); + copy->tokens[i].val.name.text = copy->namebuf + bytes; + bytes += start[i].val.name.len; + } + + copy->tokens_cap = n; + copy->tokens_used = n; + copy->name_used = bytes; + copy->name_cap = bytes; + copy->comments = 0; + copy->comments_cap = 0; + copy->comments_used = 0; + + copy->flags = 0; + copy->dirno = -1; +} +/* Shrink a token list down to the minimum size. */ void -_cpp_scan_line (pfile, list) +_cpp_squeeze_toklist (list) + cpp_toklist *list; +{ + long delta; + const U_CHAR *old_namebuf; + + if (list->flags & LIST_OFFSET) + { + list->tokens--; + memmove (list->tokens, list->tokens + 1, + list->tokens_used * sizeof (cpp_token)); + list->tokens = xrealloc (list->tokens, + list->tokens_used * sizeof (cpp_token)); + list->flags &= ~LIST_OFFSET; + } + else + list->tokens = xrealloc (list->tokens, + list->tokens_used * sizeof (cpp_token)); + list->tokens_cap = list->tokens_used; + + old_namebuf = list->namebuf; + list->namebuf = xrealloc (list->namebuf, list->name_used); + list->name_cap = list->name_used; + + /* Fix up token text pointers. */ + delta = list->namebuf - old_namebuf; + if (delta) + { + unsigned int i; + + for (i = 0; i < list->tokens_used; i++) + if (token_spellings[list->tokens[i].type].type > SPELL_NONE) + list->tokens[i].val.name.text += delta; + } + + if (list->comments_cap) + { + list->comments = xrealloc (list->comments, + list->comments_used * sizeof (cpp_token)); + list->comments_cap = list->comments_used; + } +} + +/* Compare two tokens. */ +int +_cpp_equiv_tokens (a, b) + const cpp_token *a, *b; +{ + if (a->type != b->type + || a->flags != b->flags + || a->aux != b->aux) + return 0; + + if (token_spellings[a->type].type > SPELL_NONE) + { + if (a->val.name.len != b->val.name.len + || ustrncmp(a->val.name.text, + b->val.name.text, + a->val.name.len)) + return 0; + } + return 1; +} + +/* Compare two token lists. */ +int +_cpp_equiv_toklists (a, b) + const cpp_toklist *a, *b; +{ + unsigned int i; + + if (a->tokens_used != b->tokens_used) + return 0; + + for (i = 0; i < a->tokens_used; i++) + if (! _cpp_equiv_tokens (&a->tokens[i], &b->tokens[i])) + return 0; + return 1; +} + +/* Scan until we encounter a token of type STOP or a newline, and + create a token list for it. Does not macro-expand or execute + directives. The final token is not included in the list or + consumed from the input. Returns the type of the token stopped at. */ + +enum cpp_ttype +_cpp_scan_until (pfile, list, stop) cpp_reader *pfile; cpp_toklist *list; + enum cpp_ttype stop; { int i, col; long written, len; enum cpp_ttype type; int space_before; - init_token_list (pfile, list, 1); + _cpp_clear_toklist (list); + list->line = CPP_BUF_LINE (CPP_BUFFER (pfile)); written = CPP_WRITTEN (pfile); i = 0; @@ -636,14 +784,14 @@ _cpp_scan_line (pfile, list) if (type == CPP_MACRO) type = CPP_NAME; + if (type == CPP_VSPACE || type == stop) + break; + list->tokens_used++; TOK_TYPE (list, i) = type; TOK_COL (list, i) = col; TOK_FLAGS (list, i) = space_before ? PREV_WHITESPACE : 0; - if (type == CPP_VSPACE) - break; - TOK_LEN (list, i) = len; if (token_spellings[type].type > SPELL_NONE) { @@ -656,12 +804,14 @@ _cpp_scan_line (pfile, list) i++; space_before = 0; } - TOK_AUX (list, i) = CPP_BUFFER (pfile)->lineno + 1; - /* XXX Temporary kluge: put back the newline. */ + /* XXX Temporary kluge: put back the newline (or whatever). */ FORWARD(-1); -} + /* Don't consider the first token to have white before. */ + TOK_FLAGS (list, 0) &= ~PREV_WHITESPACE; + return type; +} /* Skip a C-style block comment. We know it's a comment, and point is at the second character of the starter. */ @@ -1060,85 +1210,6 @@ parse_string (pfile, c) 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. - Returns 0 for syntax error, 1 for bare predicate, 2 for predicate - with answer (see callers for why). In case of 0, an error has been - printed. */ -int -_cpp_parse_assertion (pfile) - cpp_reader *pfile; -{ - int c, dropwhite; - _cpp_skip_hspace (pfile); - c = PEEKC(); - if (c == '\n') - { - cpp_error (pfile, "assertion without predicate"); - return 0; - } - else if (! is_idstart(c)) - { - cpp_error (pfile, "assertion predicate is not an identifier"); - return 0; - } - CPP_PUTC(pfile, '#'); - FORWARD(1); - _cpp_parse_name (pfile, c); - - c = PEEKC(); - if (c != '(') - { - if (is_hspace(c) || c == '\r') - _cpp_skip_hspace (pfile); - c = PEEKC(); - } - if (c != '(') - return 1; - - CPP_PUTC(pfile, '('); - FORWARD(1); - dropwhite = 1; - while ((c = GETC()) != ')') - { - if (is_space(c)) - { - if (! dropwhite) - { - CPP_PUTC(pfile, ' '); - dropwhite = 1; - } - } - else if (c == '\n' || c == EOF) - { - if (c == '\n') FORWARD(-1); - cpp_error (pfile, "un-terminated assertion answer"); - return 0; - } - else if (c == '\r') - /* \r cannot be a macro escape here. */ - CPP_BUMP_LINE (pfile); - else - { - CPP_PUTC (pfile, c); - dropwhite = 0; - } - } - - if (pfile->limit[-1] == ' ') - pfile->limit[-1] = ')'; - else if (pfile->limit[-1] == '(') - { - cpp_error (pfile, "empty token sequence in assertion"); - return 0; - } - else - CPP_PUTC (pfile, ')'); - - return 2; -} - /* Get the next token, and add it to the text in pfile->token_buffer. Return the kind of token we got. */ @@ -1176,11 +1247,7 @@ _cpp_lex_token (pfile) if (!CPP_OPTION (pfile, discard_comments)) return CPP_COMMENT; else if (CPP_TRADITIONAL (pfile)) - { - if (pfile->parsing_define_directive) - return CPP_COMMENT; - goto get_next; - } + goto get_next; else { CPP_PUTC (pfile, c); @@ -1191,42 +1258,24 @@ _cpp_lex_token (pfile) CPP_PUTC (pfile, c); hash: - if (pfile->parsing_if_directive) + c2 = PEEKC (); + if (c2 == '#') { - CPP_ADJUST_WRITTEN (pfile, -1); - if (_cpp_parse_assertion (pfile)) - return CPP_ASSERTION; - return CPP_OTHER; + FORWARD (1); + CPP_PUTC (pfile, c2); + return CPP_PASTE; } - - if (pfile->parsing_define_directive) + else if (c2 == '%' && PEEKN (1) == ':') { - c2 = PEEKC (); - if (c2 == '#') - { - FORWARD (1); - CPP_PUTC (pfile, c2); - } - else if (c2 == '%' && PEEKN (1) == ':') - { - /* Digraph: "%:" == "#". */ - FORWARD (1); - CPP_RESERVE (pfile, 2); - CPP_PUTC_Q (pfile, c2); - CPP_PUTC_Q (pfile, GETC ()); - } - else - return CPP_HASH; - + /* Digraph: "%:" == "#". */ + FORWARD (1); + CPP_RESERVE (pfile, 2); + CPP_PUTC_Q (pfile, c2); + CPP_PUTC_Q (pfile, GETC ()); return CPP_PASTE; } - - if (!pfile->only_seen_white) - return CPP_OTHER; - - /* Remove the "#" or "%:" from the token buffer. */ - CPP_ADJUST_WRITTEN (pfile, (c == '#' ? -1 : -2)); - return CPP_DIRECTIVE; + else + return CPP_HASH; case '\"': case '\'': @@ -1697,13 +1746,22 @@ cpp_get_token (pfile) case CPP_COMMENT: return token; - case CPP_DIRECTIVE: + case CPP_HASH: pfile->potential_control_macro = 0; + if (!pfile->only_seen_white) + return CPP_HASH; + /* XXX shouldn't have to do this - remove the hash or %: from + the token buffer. */ + if (CPP_PWRITTEN (pfile)[-1] == '#') + CPP_ADJUST_WRITTEN (pfile, -1); + else + CPP_ADJUST_WRITTEN (pfile, -2); + if (_cpp_handle_directive (pfile)) - return CPP_DIRECTIVE; + return CPP_DIRECTIVE; pfile->only_seen_white = 0; CPP_PUTC (pfile, '#'); - return CPP_OTHER; + return CPP_HASH; case CPP_MACRO: pfile->potential_control_macro = 0; @@ -1777,11 +1835,6 @@ _cpp_get_directive_token (pfile) goto get_next; return CPP_HSPACE; - case CPP_DIRECTIVE: - /* Don't execute the directive, but don't smash it to OTHER either. */ - CPP_PUTC (pfile, '#'); - return CPP_DIRECTIVE; - case CPP_MACRO: if (! pfile->no_macro_expand && maybe_macroexpand (pfile, old_written)) @@ -2134,7 +2187,7 @@ _cpp_init_input_buffer (pfile) U_CHAR *tmp; init_chartab (); - init_token_list (pfile, &pfile->directbuf, 0); + _cpp_init_toklist (&pfile->directbuf); /* Determine the appropriate size for the input buffer. Normal C source files are smaller than eight K. */ @@ -2294,17 +2347,6 @@ expand_comment_space (list) } } -void -cpp_free_token_list (list) - cpp_toklist *list; -{ - if (list->comments) - free (list->comments); - free (list->tokens - 1); /* Backup over dummy token. */ - free (list->namebuf); - free (list); -} - void init_trigraph_map () { @@ -3175,7 +3217,7 @@ _cpp_lex_line (pfile, list) break; } /* Is this the beginning of a header name? */ - if (list->dir_flags & SYNTAX_INCLUDE) + if (list->flags & SYNTAX_INCLUDE) { c = '>'; /* Terminator. */ cur_token->type = CPP_HEADER_NAME; @@ -3304,7 +3346,7 @@ _cpp_lex_line (pfile, list) invalid directives in assembly source, we don't know where the comments are, and # may introduce assembler pseudo-ops. */ - if (IS_DIRECTIVE (list) && list->dir_handler == 0 + if (IS_DIRECTIVE (list) && list->dirno == -1 && list->tokens[1].type != CPP_VSPACE && !CPP_OPTION (pfile, lang_asm)) cpp_error_with_line (pfile, list->line, list->tokens[1].col, @@ -3385,31 +3427,25 @@ void _cpp_lex_file (pfile) cpp_reader* pfile; { - int recycle; cpp_toklist* list; init_trigraph_map (); list = (cpp_toklist *) xmalloc (sizeof (cpp_toklist)); + _cpp_init_toklist (list); - for (recycle = 0; ;) + for (;;) { - init_token_list (pfile, list, recycle); - recycle = 1; - _cpp_lex_line (pfile, list); if (list->tokens[0].type == CPP_EOF) break; - if (list->dir_handler) - { - if (list->dir_handler (pfile)) - { - list = (cpp_toklist *) xmalloc (sizeof (cpp_toklist)); - recycle = 0; - } - } +#if 0 + if (list->dirno) + _cpp_handle_directive (pfile, list); else +#endif _cpp_output_list (pfile, list); + _cpp_clear_toklist (list); } } diff --git a/gcc/cpplib.c b/gcc/cpplib.c index e249555057a..23b522c2b95 100644 --- a/gcc/cpplib.c +++ b/gcc/cpplib.c @@ -160,14 +160,15 @@ _cpp_check_directive (list, token) size_t len = token->val.name.len; unsigned int i; - list->dir_handler = 0; - list->dir_flags = 0; + list->dirno = -1; + list->flags &= ~SYNTAX_INCLUDE; for (i = 0; i < N_DIRECTIVES; i++) if (dtable[i].length == len && !ustrncmp (dtable[i].name, name, len)) { - list->dir_handler = dtable[i].func; - list->dir_flags = dtable[i].flags; + list->dirno = i; + if (dtable[i].flags & SYNTAX_INCLUDE) + list->flags |= SYNTAX_INCLUDE; break; } } @@ -219,8 +220,8 @@ _cpp_handle_directive (pfile) && CPP_BUFFER (pfile)->ihash && ! CPP_OPTION (pfile, preprocessed)) cpp_pedwarn (pfile, "# followed by integer"); - do_line (pfile); - return 1; + i = T_LINE; + goto process_directive; } /* If we are rescanning preprocessed input, don't obey any directives @@ -300,6 +301,7 @@ _cpp_handle_directive (pfile) pfile->no_macro_expand--; CPP_SET_WRITTEN (pfile, old_written); + process_directive: /* Some directives (e.g. #if) may return a request to execute another directive handler immediately. No directive ever requests that #define be executed immediately, so it is safe for @@ -343,14 +345,14 @@ do_define (pfile) cpp_toklist *list = &pfile->directbuf; pfile->no_macro_expand++; - pfile->parsing_define_directive++; CPP_OPTION (pfile, discard_comments)++; - _cpp_scan_line (pfile, list); + _cpp_scan_until (pfile, list, CPP_VSPACE); - /* First token on the line must be a NAME. There must be at least - one token (the VSPACE at the end). */ - if (TOK_TYPE (list, 0) != CPP_NAME) + /* First token on the line must be a NAME. There may not be any + tokens in the list (if we had #define all by itself on a line). */ + if (list->tokens_used == 0 + || TOK_TYPE (list, 0) != CPP_NAME) { cpp_error_with_line (pfile, list->line, TOK_COL (list, 0), "#define must be followed by an identifier"); @@ -389,7 +391,6 @@ do_define (pfile) out: pfile->no_macro_expand--; - pfile->parsing_define_directive--; CPP_OPTION (pfile, discard_comments)--; return 0; } @@ -1097,8 +1098,16 @@ static int do_if (pfile) cpp_reader *pfile; { - U_CHAR *control_macro = detect_if_not_defined (pfile); - int value = _cpp_parse_expr (pfile); + U_CHAR *control_macro; + int value; + int save_only_seen_white = pfile->only_seen_white; + + control_macro = detect_if_not_defined (pfile); + + pfile->only_seen_white = 0; + value = _cpp_parse_expr (pfile); + pfile->only_seen_white = save_only_seen_white; + return conditional_skip (pfile, value == 0, T_IF, control_macro); } @@ -1383,7 +1392,7 @@ skip_if_group (pfile) token = _cpp_get_directive_token (pfile); - if (token == CPP_DIRECTIVE) + if (token == CPP_HASH) { ret = consider_directive_while_skipping (pfile, save_if_stack); if (ret) @@ -1509,56 +1518,84 @@ _cpp_unwind_if_stack (pfile, pbuf) pfile->if_stack = ifs; } +#define WARNING(msgid) do { cpp_warning(pfile, msgid); goto error; } while (0) +#define ERROR(msgid) do { cpp_error(pfile, msgid); goto error; } while (0) +#define ICE(msgid) do { cpp_ice(pfile, msgid); goto error; } while (0) static int do_assert (pfile) cpp_reader *pfile; { long old_written; U_CHAR *sym; - int ret; - HASHNODE *base, *this; - size_t blen, tlen; + size_t len; + HASHNODE *hp; + struct predicate *pred = 0; + enum cpp_ttype type; - old_written = CPP_WRITTEN (pfile); /* remember where it starts */ - ret = _cpp_parse_assertion (pfile); - if (ret == 0) - goto error; - else if (ret == 1) - { - cpp_error (pfile, "missing token-sequence in #assert"); - goto error; - } - tlen = CPP_WRITTEN (pfile) - old_written; + old_written = CPP_WRITTEN (pfile); + pfile->no_macro_expand++; + + CPP_PUTC (pfile, '#'); /* force token out of macro namespace */ + type = _cpp_get_directive_token (pfile); + if (type == CPP_VSPACE) + ERROR ("#assert without predicate"); + else if (type != CPP_NAME) + ERROR ("assertion predicate is not an identifier"); - if (_cpp_get_directive_token (pfile) != CPP_VSPACE) - { - cpp_error (pfile, "junk at end of #assert"); - goto error; - } sym = pfile->token_buffer + old_written; + len = CPP_WRITTEN (pfile) - old_written; + hp = _cpp_lookup (pfile, sym, len); + + if (_cpp_get_directive_token (pfile) != CPP_OPEN_PAREN) + ERROR ("missing token-sequence in #assert"); + + pred = (struct predicate *) xmalloc (sizeof (struct predicate)); + _cpp_init_toklist (&pred->answer); + + if (_cpp_scan_until (pfile, &pred->answer, CPP_CLOSE_PAREN) + != CPP_CLOSE_PAREN) + ERROR ("missing close paren in #assert"); - this = _cpp_lookup (pfile, sym, tlen); - if (this->type == T_ASSERT) + if (_cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN) + ICE ("impossible token, expecting ) in do_assert"); + + if (_cpp_get_directive_token (pfile) != CPP_VSPACE) + ERROR ("junk at end of #assert"); + + if (hp->type == T_ASSERTION) { - cpp_warning (pfile, "%s re-asserted", sym); - goto error; + /* Check for reassertion. */ + const struct predicate *old; + + for (old = hp->value.pred; old; old = old->next) + if (_cpp_equiv_toklists (&pred->answer, &old->answer)) + /* We used to warn about this, but SVR4 cc doesn't, so let's + match that (also consistent with #define). goto error will + clean up. */ + goto error; + pred->next = hp->value.pred; } - - blen = ustrchr (sym, '(') - sym; - base = _cpp_lookup (pfile, sym, blen); - if (base->type == T_VOID) + else { - base->type = T_ASSERT; - base->value.aschain = 0; + hp->type = T_ASSERTION; + pred->next = 0; } - - this->type = T_ASSERT; - this->value.aschain = base->value.aschain; - base->value.aschain = this; + + _cpp_squeeze_toklist (&pred->answer); + hp->value.pred = pred; + pfile->no_macro_expand--; + CPP_SET_WRITTEN (pfile, old_written); + return 0; error: _cpp_skip_rest_of_line (pfile); + pfile->no_macro_expand--; CPP_SET_WRITTEN (pfile, old_written); + if (pred) + { + _cpp_free_toklist (&pred->answer); + free (pred); + } return 0; } @@ -1566,68 +1603,90 @@ static int do_unassert (pfile) cpp_reader *pfile; { - int ret; long old_written; U_CHAR *sym; - long baselen, thislen; - HASHNODE *base, *this, *next; + size_t len; + HASHNODE *hp; + struct predicate *pred = 0; + enum cpp_ttype type; old_written = CPP_WRITTEN (pfile); - ret = _cpp_parse_assertion (pfile); - if (ret == 0) - goto out; - thislen = CPP_WRITTEN (pfile) - old_written; + pfile->no_macro_expand++; - if (_cpp_get_directive_token (pfile) != CPP_VSPACE) + CPP_PUTC (pfile, '#'); /* force token out of macro namespace */ + if (_cpp_get_directive_token (pfile) != CPP_NAME) + ERROR ("#unassert must be followed by an identifier"); + + sym = pfile->token_buffer + old_written; + len = CPP_WRITTEN (pfile) - old_written; + hp = _cpp_lookup (pfile, sym, len); + + type = _cpp_get_directive_token (pfile); + if (type == CPP_OPEN_PAREN) { - cpp_error (pfile, "junk at end of #unassert"); - goto out; + pred = (struct predicate *) xmalloc (sizeof (struct predicate)); + _cpp_init_toklist (&pred->answer); + + if (_cpp_scan_until (pfile, &pred->answer, CPP_CLOSE_PAREN) + != CPP_CLOSE_PAREN) + ERROR ("missing close paren in #unassert"); + + if (_cpp_get_directive_token (pfile) != CPP_CLOSE_PAREN) + ICE ("impossible token, expecting ) in do_unassert"); + + type = _cpp_get_directive_token (pfile); } - sym = pfile->token_buffer + old_written; - CPP_SET_WRITTEN (pfile, old_written); - if (ret == 1) + if (type != CPP_VSPACE) + ERROR ("junk at end of #unassert"); + + if (hp->type != T_ASSERTION) + /* Not an error to #unassert something that isn't asserted. + goto error to clean up. */ + goto error; + + if (pred) { - base = _cpp_lookup (pfile, sym, thislen); - if (base->type == T_VOID) - goto out; /* It isn't an error to #undef what isn't #defined, - so it isn't an error to #unassert what isn't - #asserted either. */ - - for (this = base->value.aschain; this; this = next) - { - next = this->value.aschain; - this->value.aschain = NULL; - this->type = T_VOID; - } - base->value.aschain = NULL; - base->type = T_VOID; + /* Find this specific answer and remove it. */ + struct predicate *o, *p; + + for (p = NULL, o = hp->value.pred; o; p = o, o = o->next) + if (_cpp_equiv_toklists (&pred->answer, &o->answer)) + { + if (p) + p->next = o->next; + else + hp->value.pred = o->next; + + _cpp_free_toklist (&o->answer); + free (o); + break; + } } else { - baselen = ustrchr (sym, '(') - sym; - base = _cpp_lookup (pfile, sym, baselen); - if (base->type == T_VOID) goto out; - this = _cpp_lookup (pfile, sym, thislen); - if (this->type == T_VOID) goto out; - - next = base; - while (next->value.aschain != this) - next = next->value.aschain; - - next->value.aschain = this->value.aschain; - this->value.aschain = NULL; - this->type = T_VOID; - - if (base->value.aschain == NULL) - /* Last answer for this predicate deleted. */ - base->type = T_VOID; + struct predicate *o, *p; + for (o = hp->value.pred; o; o = p) + { + p = o->next; + _cpp_free_toklist ((cpp_toklist *) &o->answer); + free (o); + } + hp->value.pred = NULL; } - return 0; - out: + if (hp->value.pred == NULL) + hp->type = T_VOID; /* Last answer for this predicate deleted. */ + + error: _cpp_skip_rest_of_line (pfile); + pfile->no_macro_expand--; CPP_SET_WRITTEN (pfile, old_written); + if (pred) + { + _cpp_free_toklist (&pred->answer); + free (pred); + } return 0; } diff --git a/gcc/cpplib.h b/gcc/cpplib.h index a46ada3eacc..6ecab526c48 100644 --- a/gcc/cpplib.h +++ b/gcc/cpplib.h @@ -124,7 +124,6 @@ typedef struct cpp_name cpp_name; T(CPP_VSPACE, "\n") /* End of line. */ \ N(CPP_EOF, 0) /* End of file. */ \ N(CPP_HEADER_NAME, 0) /* in #include */ \ - N(CPP_ASSERTION, 0) /* (...) in #assert */ \ \ /* Obsolete - will be removed when no code uses them still. */ \ N(CPP_HSPACE, 0) /* Horizontal white space. */ \ @@ -189,6 +188,9 @@ struct cpp_token } val; }; +/* General flags. */ +#define LIST_OFFSET (1 << 0) + /* Directive flags. */ #define SYNTAX_INCLUDE (1 << 8) @@ -211,12 +213,12 @@ struct cpp_toklist unsigned int comments_used; /* comment tokens used. */ unsigned int comments_cap; /* comment token capacity. */ - /* Only used if tokens[0].type == CPP_DIRECTIVE. This is the - handler to call after lexing the rest of this line. The flags - indicate whether the rest of the line gets special treatment - during lexing (#include, #if, #assert, #unassert). */ - directive_handler dir_handler; - unsigned short dir_flags; + /* The handler to call after lexing the rest of this line. + -1 for none */ + short dirno; + + /* Per-list flags, see above */ + unsigned short flags; }; struct cpp_buffer @@ -544,12 +546,6 @@ struct cpp_reader /* If true, characters between '<' and '>' are a single (string) token. */ unsigned char parsing_include_directive; - /* If true, # introduces an assertion (see do_assert) */ - unsigned char parsing_if_directive; - - /* If true, # and ## are the STRINGIZE and TOKPASTE operators */ - unsigned char parsing_define_directive; - /* True if escape sequences (as described for has_escapes in parse_buffer) should be emitted. */ unsigned char output_escapes;