/* * (c) Thomas Pornin 1999, 2000 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. The name of the authors may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include <stdio.h>#include <string.h>#include <stddef.h>#include <limits.h>#include <time.h>#include "ucppi.h"#include "mem.h"#include "hash.h"#include "tune.h" /* * Assertion support. Each assertion is indexed by its predicate, and * the list of 'questions' which yield a true answer. */ static struct HT *assertions; static struct assert *new_assertion(void){ struct assert *a = getmem(sizeof(struct assert)); a->nbval = 0; return a;} static void del_assertion(void *va){ struct assert *a = va; size_t i, j; if (a->name) freemem(a->name); for (i = 0; i < a->nbval; i ++) { for (j = 0; j < a->val[i].nt; j ++) if (S_TOKEN(a->val[i].t[j].type)) freemem(a->val[i].t[j].name); if (a->val[i].nt) freemem(a->val[i].t); } if (a->nbval) freemem(a->val);} /* * print the contents of a token list */static void print_token_fifo(struct token_fifo *tf){ size_t i; for (i = 0; i < tf->nt; i ++) if (ttMWS(tf->t[i].type)) fputc(' ', emit_output); else fputs(token_name(tf->t + i), emit_output);} /* * print all assertions related to a given name */static void print_assert(void *va){ struct assert *a = va; size_t i; for (i = 0; i < a->nbval; i ++) { fprintf(emit_output, "#assert %s(", a->name); print_token_fifo(a->val + i); fprintf(emit_output, ")\n"); }} /* * compare two token_fifo, return 0 if they are identical, 1 otherwise. * All whitespace tokens are considered identical, but sequences of * whitespace are not shrinked. */int cmp_token_list(struct token_fifo *f1, struct token_fifo *f2){ size_t i; if (f1->nt != f2->nt) return 1; for (i = 0; i < f1->nt; i ++) { if (ttMWS(f1->t[i].type) && ttMWS(f2->t[i].type)) continue; if (f1->t[i].type != f2->t[i].type) return 1; if (f1->t[i].type == MACROARG && f1->t[i].line != f2->t[i].line) return 1; if (S_TOKEN(f1->t[i].type) && strcmp(f1->t[i].name, f2->t[i].name)) return 1; } return 0;} /* * for #assert * Assertions are not part of the ISO-C89 standard, but they are sometimes * encountered, for instance in Solaris standard include files. */int handle_assert(struct lexer_state *ls){ int ina = 0, ltww; struct token t; struct token_fifo *atl = 0; struct assert *a; int ret = -1; long l = ls->line; int nnp; size_t i; while (!next_token(ls)) { if (ls->ctok->type == NEWLINE) break; if (ttMWS(ls->ctok->type)) continue; if (ls->ctok->type == NAME) { if (!(a = getHT(assertions, &(ls->ctok->name)))) { a = new_assertion(); a->name = sdup(ls->ctok->name); ina = 1; } goto handle_assert_next; } error(l, "illegal assertion name for #assert"); goto handle_assert_warp_ign; } goto handle_assert_trunc; handle_assert_next: while (!next_token(ls)) { if (ls->ctok->type == NEWLINE) break; if (ttMWS(ls->ctok->type)) continue; if (ls->ctok->type != LPAR) { error(l, "syntax error in #assert"); goto handle_assert_warp_ign; } goto handle_assert_next2; } goto handle_assert_trunc; handle_assert_next2: atl = getmem(sizeof(struct token_fifo)); atl->art = atl->nt = 0; for (nnp = 1, ltww = 1; nnp && !next_token(ls);) { if (ls->ctok->type == NEWLINE) break; if (ltww && ttMWS(ls->ctok->type)) continue; ltww = ttMWS(ls->ctok->type); if (ls->ctok->type == LPAR) nnp ++; else if (ls->ctok->type == RPAR) { if (!(-- nnp)) goto handle_assert_next3; } t.type = ls->ctok->type; if (S_TOKEN(t.type)) t.name = sdup(ls->ctok->name); aol(atl->t, atl->nt, t, TOKEN_LIST_MEMG); } goto handle_assert_trunc; handle_assert_next3: while (!next_token(ls) && ls->ctok->type != NEWLINE) { if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD)) { warning(l, "trailing garbage in #assert"); } } if (atl->nt && ttMWS(atl->t[atl->nt - 1].type) && (-- atl->nt) == 0) freemem(atl->t); if (atl->nt == 0) { error(l, "void assertion in #assert"); freemem(atl); return ret; } for (i = 0; i < a->nbval && cmp_token_list(atl, a->val + i); i ++); if (i != a->nbval) { /* we already have it */ ret = 0; goto handle_assert_error; } /* This is a new assertion. Let's keep it. */ aol(a->val, a->nbval, *atl, TOKEN_LIST_MEMG); if (ina) putHT(assertions, a); if (emit_assertions) { fprintf(emit_output, "#assert %s(", a->name); print_token_fifo(atl); fputs(")\n", emit_output); } return 0; handle_assert_trunc: error(l, "unfinished #assert");handle_assert_error: if (atl && atl->nt) { for (i = 0; i < atl->nt; i ++) if (S_TOKEN(atl->t[i].type)) freemem(atl->t[i].name); freemem(atl->t); } return ret;handle_assert_warp_ign: while (!next_token(ls) && ls->ctok->type != NEWLINE); return ret;} /* * for #unassert */int handle_unassert(struct lexer_state *ls){ int ltww; struct token t; struct token_fifo *atl = 0; struct assert *a; int ret = -1; long l = ls->line; int nnp; size_t i; while (!next_token(ls)) { if (ls->ctok->type == NEWLINE) break; if (ttMWS(ls->ctok->type)) continue; if (ls->ctok->type == NAME) { if (!(a = getHT(assertions, &(ls->ctok->name)))) { ret = 0; goto handle_unassert_warp; } goto handle_unassert_next; } error(l, "illegal assertion name for #unassert"); goto handle_unassert_warp; } goto handle_unassert_trunc; handle_unassert_next: while (!next_token(ls)) { if (ls->ctok->type == NEWLINE) break; if (ttMWS(ls->ctok->type)) continue; if (ls->ctok->type != LPAR) { error(l, "syntax error in #unassert"); goto handle_unassert_warp; } goto handle_unassert_next2; } if (emit_assertions) fprintf(emit_output, "#unassert %s\n", a->name); delHT(assertions, a); return 0; handle_unassert_next2: atl = getmem(sizeof(struct token_fifo)); atl->art = atl->nt = 0; for (nnp = 1, ltww = 1; nnp && !next_token(ls);) { if (ls->ctok->type == NEWLINE) break; if (ltww && ttMWS(ls->ctok->type)) continue; ltww = ttMWS(ls->ctok->type); if (ls->ctok->type == LPAR) nnp ++; else if (ls->ctok->type == RPAR) { if (!(-- nnp)) goto handle_unassert_next3; } t.type = ls->ctok->type; if (S_TOKEN(t.type)) t.name = sdup(ls->ctok->name); aol(atl->t, atl->nt, t, TOKEN_LIST_MEMG); } goto handle_unassert_trunc; handle_unassert_next3: while (!next_token(ls) && ls->ctok->type != NEWLINE) { if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD)) { warning(l, "trailing garbage in #unassert"); } } if (atl->nt && ttMWS(atl->t[atl->nt - 1].type) && (-- atl->nt) == 0) freemem(atl->t); if (atl->nt == 0) { error(l, "void assertion in #unassert"); freemem(atl); return ret; } for (i = 0; i < a->nbval && cmp_token_list(atl, a->val + i); i ++); if (i != a->nbval) { /* we have it, undefine it */ if (i < (a->nbval - 1)) mmvwo(a->val + i, a->val + i + 1, (a->nbval - i - 1) * sizeof(struct token_fifo)); a->nbval --; if (emit_assertions) { fprintf(emit_output, "#unassert %s(", a->name); print_token_fifo(atl); fputs(")\n", emit_output); } } ret = 0; goto handle_unassert_finish; handle_unassert_trunc: error(l, "unfinished #unassert");handle_unassert_finish: if (atl && atl->nt) { for (i = 0; i < atl->nt; i ++) if (S_TOKEN(atl->t[i].type)) freemem(atl->t[i].name); freemem(atl->t); } return ret;handle_unassert_warp: while (!next_token(ls) && ls->ctok->type != NEWLINE); return ret;} /* * Add the given assertion (as string). */int make_assertion(char *aval){ struct lexer_state lls; size_t n = strlen(aval) + 1; char *c = sdup(aval); int ret; *(c + n - 1) = '\n'; init_buf_lexer_state(&lls, 0); lls.flags = DEFAULT_LEXER_FLAGS; lls.input = 0; lls.input_string = (unsigned char *)c; lls.pbuf = 0; lls.ebuf = n; lls.line = -1; ret = handle_assert(&lls); freemem(c); free_lexer_state(&lls); return ret;} /* * Remove the given assertion (as string). */int destroy_assertion(char *aval){ struct lexer_state lls; size_t n = strlen(aval) + 1; char *c = sdup(aval); int ret; *(c + n - 1) = '\n'; init_buf_lexer_state(&lls, 0); lls.flags = DEFAULT_LEXER_FLAGS; lls.input = 0; lls.input_string = (unsigned char *)c; lls.pbuf = 0; lls.ebuf = n; lls.line = -1; ret = handle_unassert(&lls); freemem(c); free_lexer_state(&lls); return ret;} /* * initialize the assertion table */void init_assertions(void){ if (assertions) killHT(assertions); assertions = newHT(128, cmp_struct, hash_struct, del_assertion);} /* * retrieve an assertion from the hash table */struct assert *get_assertion(char *name){ return getHT(assertions, &name);} /* * print already defined assertions */void print_assertions(void){ scanHT(assertions, print_assert);}
/*
* (c) Thomas Pornin 1999, 2000
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. The name of the authors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <limits.h>
#include <time.h>
#include "ucppi.h"
#include "mem.h"
#include "hash.h"
#include "tune.h"
/*
* Assertion support. Each assertion is indexed by its predicate, and
* the list of 'questions' which yield a true answer.
*/
static struct HT *assertions;
static struct assert *new_assertion(void)
{
struct assert *a = getmem(sizeof(struct assert));
a->nbval = 0;
return a;
}
static void del_assertion(void *va)
{
struct assert *a = va;
size_t i, j;
if (a->name) freemem(a->name);
for (i = 0; i < a->nbval; i ++) {
for (j = 0; j < a->val[i].nt; j ++)
if (S_TOKEN(a->val[i].t[j].type))
freemem(a->val[i].t[j].name);
if (a->val[i].nt) freemem(a->val[i].t);
}
if (a->nbval) freemem(a->val);
}
/*
* print the contents of a token list
*/
static void print_token_fifo(struct token_fifo *tf)
{
size_t i;
for (i = 0; i < tf->nt; i ++)
if (ttMWS(tf->t[i].type)) fputc(' ', emit_output);
else fputs(token_name(tf->t + i), emit_output);
}
/*
* print all assertions related to a given name
*/
static void print_assert(void *va)
{
struct assert *a = va;
size_t i;
for (i = 0; i < a->nbval; i ++) {
fprintf(emit_output, "#assert %s(", a->name);
print_token_fifo(a->val + i);
fprintf(emit_output, ")\n");
}
}
/*
* compare two token_fifo, return 0 if they are identical, 1 otherwise.
* All whitespace tokens are considered identical, but sequences of
* whitespace are not shrinked.
*/
int cmp_token_list(struct token_fifo *f1, struct token_fifo *f2)
{
size_t i;
if (f1->nt != f2->nt) return 1;
for (i = 0; i < f1->nt; i ++) {
if (ttMWS(f1->t[i].type) && ttMWS(f2->t[i].type)) continue;
if (f1->t[i].type != f2->t[i].type) return 1;
if (f1->t[i].type == MACROARG
&& f1->t[i].line != f2->t[i].line) return 1;
if (S_TOKEN(f1->t[i].type)
&& strcmp(f1->t[i].name, f2->t[i].name)) return 1;
}
return 0;
}
/*
* for #assert
* Assertions are not part of the ISO-C89 standard, but they are sometimes
* encountered, for instance in Solaris standard include files.
*/
int handle_assert(struct lexer_state *ls)
{
int ina = 0, ltww;
struct token t;
struct token_fifo *atl = 0;
struct assert *a;
int ret = -1;
long l = ls->line;
int nnp;
size_t i;
while (!next_token(ls)) {
if (ls->ctok->type == NEWLINE) break;
if (ttMWS(ls->ctok->type)) continue;
if (ls->ctok->type == NAME) {
if (!(a = getHT(assertions, &(ls->ctok->name)))) {
a = new_assertion();
a->name = sdup(ls->ctok->name);
ina = 1;
}
goto handle_assert_next;
}
error(l, "illegal assertion name for #assert");
goto handle_assert_warp_ign;
}
goto handle_assert_trunc;
handle_assert_next:
while (!next_token(ls)) {
if (ls->ctok->type == NEWLINE) break;
if (ttMWS(ls->ctok->type)) continue;
if (ls->ctok->type != LPAR) {
error(l, "syntax error in #assert");
goto handle_assert_warp_ign;
}
goto handle_assert_next2;
}
goto handle_assert_trunc;
handle_assert_next2:
atl = getmem(sizeof(struct token_fifo));
atl->art = atl->nt = 0;
for (nnp = 1, ltww = 1; nnp && !next_token(ls);) {
if (ls->ctok->type == NEWLINE) break;
if (ltww && ttMWS(ls->ctok->type)) continue;
ltww = ttMWS(ls->ctok->type);
if (ls->ctok->type == LPAR) nnp ++;
else if (ls->ctok->type == RPAR) {
if (!(-- nnp)) goto handle_assert_next3;
}
t.type = ls->ctok->type;
if (S_TOKEN(t.type)) t.name = sdup(ls->ctok->name);
aol(atl->t, atl->nt, t, TOKEN_LIST_MEMG);
}
goto handle_assert_trunc;
handle_assert_next3:
while (!next_token(ls) && ls->ctok->type != NEWLINE) {
if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD)) {
warning(l, "trailing garbage in #assert");
}
}
if (atl->nt && ttMWS(atl->t[atl->nt - 1].type) && (-- atl->nt) == 0)
freemem(atl->t);
if (atl->nt == 0) {
error(l, "void assertion in #assert");
freemem(atl);
return ret;
}
for (i = 0; i < a->nbval && cmp_token_list(atl, a->val + i); i ++);
if (i != a->nbval) {
/* we already have it */
ret = 0;
goto handle_assert_error;
}
/* This is a new assertion. Let's keep it. */
aol(a->val, a->nbval, *atl, TOKEN_LIST_MEMG);
if (ina) putHT(assertions, a);
if (emit_assertions) {
fprintf(emit_output, "#assert %s(", a->name);
print_token_fifo(atl);
fputs(")\n", emit_output);
}
return 0;
handle_assert_trunc:
error(l, "unfinished #assert");
handle_assert_error:
if (atl && atl->nt) {
for (i = 0; i < atl->nt; i ++)
if (S_TOKEN(atl->t[i].type)) freemem(atl->t[i].name);
freemem(atl->t);
}
return ret;
handle_assert_warp_ign:
while (!next_token(ls) && ls->ctok->type != NEWLINE);
return ret;
}
/*
* for #unassert
*/
int handle_unassert(struct lexer_state *ls)
{
int ltww;
struct token t;
struct token_fifo *atl = 0;
struct assert *a;
int ret = -1;
long l = ls->line;
int nnp;
size_t i;
while (!next_token(ls)) {
if (ls->ctok->type == NEWLINE) break;
if (ttMWS(ls->ctok->type)) continue;
if (ls->ctok->type == NAME) {
if (!(a = getHT(assertions, &(ls->ctok->name)))) {
ret = 0;
goto handle_unassert_warp;
}
goto handle_unassert_next;
}
error(l, "illegal assertion name for #unassert");
goto handle_unassert_warp;
}
goto handle_unassert_trunc;
handle_unassert_next:
while (!next_token(ls)) {
if (ls->ctok->type == NEWLINE) break;
if (ttMWS(ls->ctok->type)) continue;
if (ls->ctok->type != LPAR) {
error(l, "syntax error in #unassert");
goto handle_unassert_warp;
}
goto handle_unassert_next2;
}
if (emit_assertions) fprintf(emit_output, "#unassert %s\n", a->name);
delHT(assertions, a);
return 0;
handle_unassert_next2:
atl = getmem(sizeof(struct token_fifo));
atl->art = atl->nt = 0;
for (nnp = 1, ltww = 1; nnp && !next_token(ls);) {
if (ls->ctok->type == NEWLINE) break;
if (ltww && ttMWS(ls->ctok->type)) continue;
ltww = ttMWS(ls->ctok->type);
if (ls->ctok->type == LPAR) nnp ++;
else if (ls->ctok->type == RPAR) {
if (!(-- nnp)) goto handle_unassert_next3;
}
t.type = ls->ctok->type;
if (S_TOKEN(t.type)) t.name = sdup(ls->ctok->name);
aol(atl->t, atl->nt, t, TOKEN_LIST_MEMG);
}
goto handle_unassert_trunc;
handle_unassert_next3:
while (!next_token(ls) && ls->ctok->type != NEWLINE) {
if (!ttWHI(ls->ctok->type) && (ls->flags & WARN_STANDARD)) {
warning(l, "trailing garbage in #unassert");
}
}
if (atl->nt && ttMWS(atl->t[atl->nt - 1].type) && (-- atl->nt) == 0)
freemem(atl->t);
if (atl->nt == 0) {
error(l, "void assertion in #unassert");
freemem(atl);
return ret;
}
for (i = 0; i < a->nbval && cmp_token_list(atl, a->val + i); i ++);
if (i != a->nbval) {
/* we have it, undefine it */
if (i < (a->nbval - 1))
mmvwo(a->val + i, a->val + i + 1, (a->nbval - i - 1)
* sizeof(struct token_fifo));
a->nbval --;
if (emit_assertions) {
fprintf(emit_output, "#unassert %s(", a->name);
print_token_fifo(atl);
fputs(")\n", emit_output);
}
}
ret = 0;
goto handle_unassert_finish;
handle_unassert_trunc:
error(l, "unfinished #unassert");
handle_unassert_finish:
if (atl && atl->nt) {
for (i = 0; i < atl->nt; i ++)
if (S_TOKEN(atl->t[i].type)) freemem(atl->t[i].name);
freemem(atl->t);
}
return ret;
handle_unassert_warp:
while (!next_token(ls) && ls->ctok->type != NEWLINE);
return ret;
}
/*
* Add the given assertion (as string).
*/
int make_assertion(char *aval)
{
struct lexer_state lls;
size_t n = strlen(aval) + 1;
char *c = sdup(aval);
int ret;
*(c + n - 1) = '\n';
init_buf_lexer_state(&lls, 0);
lls.flags = DEFAULT_LEXER_FLAGS;
lls.input = 0;
lls.input_string = (unsigned char *)c;
lls.pbuf = 0;
lls.ebuf = n;
lls.line = -1;
ret = handle_assert(&lls);
freemem(c);
free_lexer_state(&lls);
return ret;
}
/*
* Remove the given assertion (as string).
*/
int destroy_assertion(char *aval)
{
struct lexer_state lls;
size_t n = strlen(aval) + 1;
char *c = sdup(aval);
int ret;
*(c + n - 1) = '\n';
init_buf_lexer_state(&lls, 0);
lls.flags = DEFAULT_LEXER_FLAGS;
lls.input = 0;
lls.input_string = (unsigned char *)c;
lls.pbuf = 0;
lls.ebuf = n;
lls.line = -1;
ret = handle_unassert(&lls);
freemem(c);
free_lexer_state(&lls);
return ret;
}
/*
* initialize the assertion table
*/
void init_assertions(void)
{
if (assertions) killHT(assertions);
assertions = newHT(128, cmp_struct, hash_struct, del_assertion);
}
/*
* retrieve an assertion from the hash table
*/
struct assert *get_assertion(char *name)
{
return getHT(assertions, &name);
}
/*
* print already defined assertions
*/
void print_assertions(void)
{
scanHT(assertions, print_assert);
}