indent(1): Use bsearch() for looking up type keywords.

Reference:
f3b8e6e57f

Submitted by:	Piotr Stefaniak
Differential Revision: https://reviews.freebsd.org/D6966
This commit is contained in:
Pedro F. Giffuni 2016-08-04 15:27:09 +00:00
parent b0316526b0
commit a6bcfda487
4 changed files with 106 additions and 84 deletions

View File

@ -298,7 +298,7 @@ found:
char *str = strdup(param_start); char *str = strdup(param_start);
if (str == NULL) if (str == NULL)
err(1, NULL); err(1, NULL);
addkey(str, 4); add_typename(str);
} }
break; break;
@ -342,6 +342,7 @@ add_typedefs_from_file(const char *str)
{ {
FILE *file; FILE *file;
char line[BUFSIZ]; char line[BUFSIZ];
char *copy;
if ((file = fopen(str, "r")) == NULL) { if ((file = fopen(str, "r")) == NULL) {
fprintf(stderr, "indent: cannot open file %s\n", str); fprintf(stderr, "indent: cannot open file %s\n", str);
@ -349,8 +350,11 @@ add_typedefs_from_file(const char *str)
} }
while ((fgets(line, BUFSIZ, file)) != NULL) { while ((fgets(line, BUFSIZ, file)) != NULL) {
/* Remove trailing whitespace */ /* Remove trailing whitespace */
*(line + strcspn(line, " \t\n\r")) = '\0'; line[strcspn(line, " \t\n\r")] = '\0';
addkey(strdup(line), 4); if ((copy = strdup(line)) == NULL) {
err(1, NULL);
}
add_typename(copy);
} }
fclose(file); fclose(file);
} }

View File

@ -119,6 +119,7 @@ main(int argc, char **argv)
tokenbuf = (char *) malloc(bufsize); tokenbuf = (char *) malloc(bufsize);
if (tokenbuf == NULL) if (tokenbuf == NULL)
err(1, NULL); err(1, NULL);
alloc_typenames();
l_com = combuf + bufsize - 5; l_com = combuf + bufsize - 5;
l_lab = labbuf + bufsize - 5; l_lab = labbuf + bufsize - 5;
l_code = codebuf + bufsize - 5; l_code = codebuf + bufsize - 5;

View File

@ -28,7 +28,8 @@
__FBSDID("$FreeBSD$"); __FBSDID("$FreeBSD$");
#endif #endif
void addkey(char *, int); void add_typename(const char *);
void alloc_typenames(void);
int compute_code_target(void); int compute_code_target(void);
int compute_label_target(void); int compute_label_target(void);
int count_spaces(int, char *); int count_spaces(int, char *);

View File

@ -64,42 +64,49 @@ struct templ {
int rwcode; int rwcode;
}; };
struct templ specials[16384] = /*
* This table has to be sorted alphabetically, because it'll be used in binary
* search. For the same reason, string must be the first thing in struct templ.
*/
struct templ specials[] =
{ {
{"switch", 7},
{"case", 8},
{"break", 9}, {"break", 9},
{"struct", 3}, {"case", 8},
{"union", 3},
{"enum", 3},
{"default", 8},
{"int", 4},
{"char", 4}, {"char", 4},
{"float", 4},
{"double", 4},
{"long", 4},
{"short", 4},
{"typedef", 4},
{"unsigned", 4},
{"register", 4},
{"static", 4},
{"global", 4},
{"extern", 4},
{"void", 4},
{"const", 4}, {"const", 4},
{"volatile", 4}, {"default", 8},
{"goto", 9},
{"return", 9},
{"if", 5},
{"while", 5},
{"for", 5},
{"else", 6},
{"do", 6}, {"do", 6},
{"sizeof", 2}, {"double", 4},
{"else", 6},
{"enum", 3},
{"extern", 4},
{"float", 4},
{"for", 5},
{"global", 4},
{"goto", 9},
{"if", 5},
{"int", 4},
{"long", 4},
{"offsetof", 1}, {"offsetof", 1},
{0, 0} {"register", 4},
{"return", 9},
{"short", 4},
{"sizeof", 2},
{"static", 4},
{"struct", 3},
{"switch", 7},
{"typedef", 4},
{"union", 3},
{"unsigned", 4},
{"void", 4},
{"volatile", 4},
{"while", 5}
}; };
const char **typenames;
int typename_count;
int typename_top = -1;
char chartype[128] = char chartype[128] =
{ /* this is used to facilitate the decision of { /* this is used to facilitate the decision of
* what type (alphanumeric, operator) each * what type (alphanumeric, operator) each
@ -122,6 +129,12 @@ char chartype[128] =
1, 1, 1, 0, 3, 0, 3, 0 1, 1, 1, 0, 3, 0, 3, 0
}; };
static int
strcmp_type(const void *e1, const void *e2)
{
return (strcmp(e1, *(const char * const *)e2));
}
int int
lexi(void) lexi(void)
{ {
@ -150,9 +163,6 @@ lexi(void)
/* /*
* we have a character or number * we have a character or number
*/ */
const char *j; /* used for searching thru list of
*
* reserved words */
struct templ *p; struct templ *p;
if (isdigit(*buf_ptr) || (buf_ptr[0] == '.' && isdigit(buf_ptr[1]))) { if (isdigit(*buf_ptr) || (buf_ptr[0] == '.' && isdigit(buf_ptr[1]))) {
@ -247,37 +257,24 @@ lexi(void)
last_code = ident; /* Remember that this is the code we will last_code = ident; /* Remember that this is the code we will
* return */ * return */
if (auto_typedefs) { p = bsearch(s_token,
const char *q = s_token; specials,
size_t q_len = strlen(q); sizeof(specials) / sizeof(specials[0]),
/* Check if we have an "_t" in the end */ sizeof(specials[0]),
if (q_len > 2 && strcmp_type);
(strcmp(q + q_len - 2, "_t") == 0)) { if (p == NULL) { /* not a special keyword... */
ps.keyword = 4; /* a type name */ char *u;
ps.last_u_d = true;
goto found_auto_typedef;
}
}
/* /* ... so maybe a type_t or a typedef */
* This loop will check if the token is a keyword. if ((auto_typedefs && ((u = strrchr(s_token, '_')) != NULL) &&
*/ strcmp(u, "_t") == 0) || (typename_top >= 0 &&
for (p = specials; (j = p->rwd) != NULL; p++) { bsearch(s_token, typenames, typename_top + 1,
const char *q = s_token; /* point at scanned token */ sizeof(typenames[0]), strcmp_type))) {
if (*j++ != *q++ || *j++ != *q++) ps.keyword = 4; /* a type name */
continue; /* This test depends on the fact that ps.last_u_d = true;
* identifiers are always at least 1 character goto found_typename;
* long (ie. the first two bytes of the }
* identifier are always meaningful) */ } else { /* we have a keyword */
if (q[-1] == 0)
break; /* If its a one-character identifier */
while (*q++ == *j)
if (*j++ == 0)
goto found_keyword; /* I wish that C had a multi-level
* break... */
}
if (p->rwd) { /* we have a keyword */
found_keyword:
ps.keyword = p->rwcode; ps.keyword = p->rwcode;
ps.last_u_d = true; ps.last_u_d = true;
switch (p->rwcode) { switch (p->rwcode) {
@ -295,7 +292,7 @@ lexi(void)
/* FALLTHROUGH */ /* FALLTHROUGH */
case 4: /* one of the declaration keywords */ case 4: /* one of the declaration keywords */
found_auto_typedef: found_typename:
if (ps.p_l_follow) { if (ps.p_l_follow) {
/* inside parens: cast, param list, offsetof or sizeof */ /* inside parens: cast, param list, offsetof or sizeof */
ps.cast_mask |= (1 << ps.p_l_follow) & ~ps.not_cast_mask; ps.cast_mask |= (1 << ps.p_l_follow) & ~ps.not_cast_mask;
@ -583,24 +580,43 @@ stop_lit:
return (code); return (code);
} }
/*
* Add the given keyword to the keyword table, using val as the keyword type
*/
void void
addkey(char *key, int val) alloc_typenames(void)
{ {
struct templ *p = specials;
while (p->rwd) typenames = (const char **)malloc(sizeof(typenames[0]) *
if (p->rwd[0] == key[0] && strcmp(p->rwd, key) == 0) (typename_count = 16));
return; if (typenames == NULL)
else err(1, NULL);
p++; }
if (p >= specials + sizeof(specials) / sizeof(specials[0])) {
fprintf(stderr, "indent: typedef table overflow\n"); void
exit(1); add_typename(const char *key)
} {
p->rwd = key; int comparison;
p->rwcode = val;
p[1].rwd = NULL; if (typename_top + 1 >= typename_count) {
p[1].rwcode = 0; typenames = realloc((void *)typenames,
sizeof(typenames[0]) * (typename_count *= 2));
if (typenames == NULL)
err(1, NULL);
}
if (typename_top == -1)
typenames[++typename_top] = key;
else if ((comparison = strcmp(key, typenames[typename_top])) >= 0) {
/* take advantage of sorted input */
if (comparison != 0) /* remove duplicates */
typenames[++typename_top] = key;
}
else {
int p;
for (p = 0; (comparison = strcmp(key, typenames[p])) >= 0; p++)
/* find place for the new key */;
if (comparison == 0) /* remove duplicates */
return;
memmove(&typenames[p + 1], &typenames[p],
sizeof(typenames[0]) * (++typename_top - p));
typenames[p] = key;
}
} }