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
This commit is contained in:
parent
1b83352ef7
commit
4eb191f350
|
@ -1,3 +1,10 @@
|
|||
2000-12-02 Neil Booth <neilb@earthling.net>
|
||||
|
||||
* 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 <marekm@linux.org.pl>
|
||||
|
||||
* config/avr/avr.md: Document UNSPEC usage.
|
||||
|
|
237
gcc/tradcpp.c
237
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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue