From 4eb191f350e0321bef21f6ad9ed6f17c3ffcaf8b Mon Sep 17 00:00:00 2001 From: Neil Booth Date: Sat, 2 Dec 2000 16:04:14 +0000 Subject: [PATCH] tradcpp.c (struct answer, [...]): New. * tradcpp.c (struct answer, parse_assertion, parse_answer, canonicalize_text, find_answer): New. (do_assert, do_unassert): Provide appropriate function bodies. (union hashval): New member answers. From-SVN: r37953 --- gcc/ChangeLog | 7 ++ gcc/tradcpp.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 238 insertions(+), 6 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f38ff599b44..17307b5cbf7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2000-12-02 Neil Booth + + * tradcpp.c (struct answer, parse_assertion, parse_answer, + canonicalize_text, find_answer): New. + (do_assert, do_unassert): Provide appropriate function bodies. + (union hashval): New member answers. + 2000-11-23 Marek Michalkiewicz * config/avr/avr.md: Document UNSPEC usage. diff --git a/gcc/tradcpp.c b/gcc/tradcpp.c index 3b79a20b5bd..51c8aff2b0f 100644 --- a/gcc/tradcpp.c +++ b/gcc/tradcpp.c @@ -188,14 +188,22 @@ struct definition { const U_CHAR *argnames; }; +/* Chained list of answers to an assertion. */ +struct answer +{ + struct answer *next; + const unsigned char *answer; + size_t len; +}; + /* different kinds of things that can appear in the value field of a hash node. Actually, this may be useless now. */ union hashval { const char *cpval; DEFINITION *defn; + struct answer *answers; }; - /* The structure of a node in the hash table. The hash table has entries for all tokens defined by #define commands (type T_MACRO), plus some special tokens like __LINE__ (these each have their own @@ -244,6 +252,17 @@ struct hashnode { typedef struct hashnode HASHNODE; +static HASHNODE *parse_assertion PARAMS ((const unsigned char *, + const unsigned char *, + struct answer **, int)); +static struct answer **find_answer PARAMS ((HASHNODE *, + const struct answer *)); +static int parse_answer PARAMS ((const unsigned char *, const unsigned char *, + struct answer **, int)); +static unsigned char *canonicalize_text PARAMS ((const unsigned char *, + const unsigned char *, + const unsigned char **)); + /* Some definitions for the hash table. The hash function MUST be computed as shown in hashf () below. That is because the rescan loop computes the hash value `on the fly' for most tokens, @@ -3021,22 +3040,228 @@ do_undef (buf, limit, op) } } -/* Function body to be provided later. */ +/* Read the tokens of the answer into the macro pool. Only commit the + memory if we intend it as permanent storage, i.e. the #assert case. + Returns 0 on success. */ + +static int +parse_answer (buf, limit, answerp, type) + const unsigned char *buf, *limit; + struct answer **answerp; + int type; +{ + const unsigned char *start; + + /* Skip leading whitespace. */ + if (buf < limit && *buf == ' ') + buf++; + + /* Parentheses are optional here. */ + if (buf == limit && (type == T_IF || type == T_UNASSERT)) + return 0; + + if (buf == limit || *buf++ != '(') + { + error ("missing '(' after predicate"); + return 1; + } + + /* Drop whitespace at start. */ + while (buf < limit && *buf == ' ') + buf++; + + start = buf; + while (buf < limit && *buf != ')') + buf++; + + if (buf == limit) + { + error ("missing ')' to complete answer"); + return 1; + } + + if (buf == start) + { + error ("predicate's answer is empty"); + return 1; + } + + if ((type == T_ASSERT || type == T_UNASSERT) && buf + 1 != limit) + { + error ("extra text at end of directive"); + return 1; + } + + /* Lose trailing whitespace. */ + if (buf[-1] == ' ') + buf--; + + *answerp = (struct answer *) xmalloc (sizeof (struct answer)); + (*answerp)->answer = start; + (*answerp)->len = buf - start; + + return 0; +} + +/* Parses an assertion, returning a pointer to the hash node of the + predicate, or 0 on error. If an answer was supplied, it is placed + in ANSWERP, otherwise it is set to 0. */ +static HASHNODE * +parse_assertion (buf, limit, answerp, type) + const unsigned char *buf, *limit; + struct answer **answerp; + int type; +{ + HASHNODE *result = 0; + const unsigned char *climit; + unsigned char *bp, *symname = canonicalize_text (buf, limit, &climit); + unsigned int len; + + bp = symname; + while (bp < climit && is_idchar[*bp]) + bp++; + len = bp - symname; + + *answerp = 0; + if (len == 0) + { + if (symname == climit) + error ("assertion without predicate"); + else + error ("predicate must be an identifier"); + } + else if (parse_answer (bp, climit, answerp, type) == 0) + { + unsigned char *sym = alloca (len + 1); + int hashcode; + + /* Prefix '#' to get it out of macro namespace. */ + sym[0] = '#'; + memcpy (sym + 1, symname, len); + + hashcode = hashf (sym, len + 1, HASHSIZE); + result = lookup (sym, len + 1, hashcode); + if (result == 0) + result = install (sym, len + 1, T_UNUSED, hashcode); + } + + return result; +} + +/* Handle a #assert directive. */ static void do_assert (buf, limit, op) - U_CHAR *buf ATTRIBUTE_UNUSED; - U_CHAR *limit ATTRIBUTE_UNUSED; + U_CHAR *buf; + U_CHAR *limit; FILE_BUF *op ATTRIBUTE_UNUSED; { + struct answer *new_answer; + HASHNODE *node; + + node = parse_assertion (buf, limit, &new_answer, T_ASSERT); + if (node) + { + /* Place the new answer in the answer list. First check there + is not a duplicate. */ + new_answer->next = 0; + if (node->type == T_ASSERT) + { + if (*find_answer (node, new_answer)) + { + free (new_answer); + warning ("\"%s\" re-asserted", node->name + 1); + return; + } + new_answer->next = node->value.answers; + } + node->type = T_ASSERT; + node->value.answers = new_answer; + } } /* Function body to be provided later. */ static void do_unassert (buf, limit, op) - U_CHAR *buf ATTRIBUTE_UNUSED; - U_CHAR *limit ATTRIBUTE_UNUSED; + U_CHAR *buf; + U_CHAR *limit; FILE_BUF *op ATTRIBUTE_UNUSED; { + HASHNODE *node; + struct answer *answer; + + node = parse_assertion (buf, limit, &answer, T_UNASSERT); + /* It isn't an error to #unassert something that isn't asserted. */ + if (node) + { + if (node->type == T_ASSERT) + { + if (answer) + { + struct answer **p = find_answer (node, answer), *temp; + + /* Remove the answer from the list. */ + temp = *p; + if (temp) + *p = temp->next; + + /* Did we free the last answer? */ + if (node->value.answers == 0) + delete_macro (node); + } + else + delete_macro (node); + } + + free (answer); + } +} + +/* Returns a pointer to the pointer to the answer in the answer chain, + or a pointer to NULL if the answer is not in the chain. */ +static struct answer ** +find_answer (node, candidate) + HASHNODE *node; + const struct answer *candidate; +{ + struct answer **result; + + for (result = &node->value.answers; *result; result = &(*result)->next) + { + struct answer *answer = *result; + + if (answer->len == candidate->len + && !memcmp (answer->answer, candidate->answer, answer->len)) + break; + } + + return result; +} + +/* Return a malloced buffer with leading and trailing whitespace + removed, and all instances of internal whitespace reduced to a + single space. */ +static unsigned char * +canonicalize_text (buf, limit, climit) + const unsigned char *buf, *limit, **climit; +{ + unsigned int len = limit - buf; + unsigned char *result = (unsigned char *) xmalloc (len), *dest; + + for (dest = result; buf < limit;) + { + if (! is_space[*buf]) + *dest++ = *buf++; + else + { + while (++buf < limit && is_space [*buf]) + ; + if (dest != result && buf != limit) + *dest++ = ' '; + } + } + + *climit = dest; + return result; } /* -- 2.30.2