vcc_parse.c \
vcc_fixed_token.c \
vcc_obj.c \
- vcc_token.c
+ vcc_token.c \
+ vcc_xref.c
libvcl_la_CFLAGS = -include config.h
-e763 // Redundant declaration for symbol '...' previously declared
--e737 // Loss of sign in promotion from int to unsigned int
+-e737 // Loss of sign in promotion from int to unsigned int
-e715 // Symbol 'arg' (line 43) not referenced
-e818 // Pointer parameter '...' could be declared as pointing to const
case '~':
vcc_NextToken(tl);
ExpectErr(tl, ID);
- AddRef(tl, tl->t, R_ACL);
+ vcc_AddRef(tl, tl->t, R_ACL);
Fc(tl, 1, "VRT_acl_match(sp, \"%.*s\", acl_%.*s)\n",
PF(tl->t), PF(tl->t));
vcc_NextToken(tl);
an = tl->t;
vcc_NextToken(tl);
- AddDef(tl, an, R_ACL);
+ vcc_AddDef(tl, an, R_ACL);
Fh(tl, 0, "static struct vrt_acl acl_%.*s[];\n", PF(an));
Fc(tl, 1, "static struct vrt_acl acl_%.*s[] = {\n", PF(an));
#include "vrt.h"
#include "libvcl.h"
-static struct method method_tab[] = {
+struct method method_tab[] = {
#define VCL_RET_MAC(l,U,b,n)
#define VCL_MET_MAC(l,U,m) { "vcl_"#l, m },
#include "vcl_returns.h"
EncString(sb, t->dec, NULL, 0);
}
-/*--------------------------------------------------------------------
- * Keep track of definitions and references
- */
-
-static struct ref *
-FindRef(struct tokenlist *tl, struct token *t, enum ref_type type)
-{
- struct ref *r;
-
- TAILQ_FOREACH(r, &tl->refs, list) {
- if (r->type != type)
- continue;
- if (vcc_Teq(r->name, t))
- return (r);
- }
- r = TlAlloc(tl, sizeof *r);
- assert(r != NULL);
- r->name = t;
- r->type = type;
- TAILQ_INSERT_TAIL(&tl->refs, r, list);
- return (r);
-}
-
-void
-AddRef(struct tokenlist *tl, struct token *t, enum ref_type type)
-{
-
- FindRef(tl, t, type)->refcnt++;
-}
-
-void
-AddDef(struct tokenlist *tl, struct token *t, enum ref_type type)
-{
- struct ref *r;
-
- r = FindRef(tl, t, type);
- r->defcnt++;
- r->name = t;
-}
-
/*--------------------------------------------------------------------*/
static struct var *
return (NULL);
}
-/*--------------------------------------------------------------------
- * Consistency check
- */
-
-struct proc *
-AddProc(struct tokenlist *tl, struct token *t, int def)
-{
- struct proc *p;
-
- TAILQ_FOREACH(p, &tl->procs, list) {
- if (!vcc_Teq(p->name, t))
- continue;
- if (def)
- p->name = t;
- return (p);
- }
- p = TlAlloc(tl, sizeof *p);
- assert(p != NULL);
- p->name = t;
- TAILQ_INIT(&p->calls);
- TAILQ_INSERT_TAIL(&tl->procs, p, list);
- return (p);
-}
-
-void
-AddCall(struct tokenlist *tl, struct token *t)
-{
- struct proccall *pc;
- struct proc *p;
-
- p = AddProc(tl, t, 0);
- TAILQ_FOREACH(pc, &tl->curproc->calls, list) {
- if (pc->p == p)
- return;
- }
- pc = TlAlloc(tl, sizeof *pc);
- assert(pc != NULL);
- pc->p = p;
- pc->t = t;
- TAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list);
-}
-
-static int
-Consist_Decend(struct tokenlist *tl, struct proc *p, unsigned returns)
-{
- unsigned u;
- struct proccall *pc;
-
- if (!p->exists) {
- vsb_printf(tl->sb, "Function %.*s does not exist\n",
- PF(p->name));
- return (1);
- }
- if (p->active) {
- vsb_printf(tl->sb, "Function recurses on\n");
- vcc_ErrWhere(tl, p->name);
- return (1);
- }
- u = p->returns & ~returns;
- if (u) {
-#define VCL_RET_MAC(a, b, c, d) \
- if (u & VCL_RET_##b) { \
- vsb_printf(tl->sb, "Illegal action \"%s\"\n", #a); \
- vcc_ErrWhere(tl, p->returnt[d]); \
- }
-#include "vcl_returns.h"
-#undef VCL_RET_MAC
- vsb_printf(tl->sb, "\n...in function \"%.*s\"\n", PF(p->name));
- vcc_ErrWhere(tl, p->name);
- return (1);
- }
- p->active = 1;
- TAILQ_FOREACH(pc, &p->calls, list) {
- if (Consist_Decend(tl, pc->p, returns)) {
- vsb_printf(tl->sb, "\n...called from \"%.*s\"\n",
- PF(p->name));
- vcc_ErrWhere(tl, pc->t);
- return (1);
- }
- }
- p->active = 0;
- p->called++;
- return (0);
-}
-
-static int
-Consistency(struct tokenlist *tl)
-{
- struct proc *p;
- struct method *m;
-
- TAILQ_FOREACH(p, &tl->procs, list) {
- for(m = method_tab; m->name != NULL; m++) {
- if (vcc_IdIs(p->name, m->name))
- break;
- }
- if (m->name == NULL)
- continue;
- if (Consist_Decend(tl, p, m->returns)) {
- vsb_printf(tl->sb,
- "\n...which is the \"%s\" method\n", m->name);
- vsb_printf(tl->sb, "Legal actions are:");
-#define VCL_RET_MAC(a, b, c, d) \
- if (m->returns & c) \
- vsb_printf(tl->sb, " \"%s\"", #a);
-#define VCL_RET_MAC_E(a, b, c, d) VCL_RET_MAC(a, b, c, d)
-#include "vcl_returns.h"
-#undef VCL_RET_MAC
-#undef VCL_RET_MAC_E
- vsb_printf(tl->sb, "\n");
- return (1);
- }
- }
- TAILQ_FOREACH(p, &tl->procs, list) {
- if (p->called)
- continue;
- vsb_printf(tl->sb, "Function unused\n");
- vcc_ErrWhere(tl, p->name);
- return (1);
- }
- return (0);
-}
-
-/*--------------------------------------------------------------------*/
-
-static int
-CheckRefs(struct tokenlist *tl)
-{
- struct ref *r;
- const char *type;
- int nerr = 0;
-
- TAILQ_FOREACH(r, &tl->refs, list) {
- if (r->defcnt != 0 && r->refcnt != 0)
- continue;
- nerr++;
-
- switch(r->type) {
- case R_FUNC:
- type = "function";
- break;
- case R_ACL:
- type = "acl";
- break;
- case R_BACKEND:
- type = "backend";
- break;
- default:
- ErrInternal(tl);
- vsb_printf(tl->sb, "Ref ");
- vcc_ErrToken(tl, r->name);
- vsb_printf(tl->sb, " has unknown type %d\n",
- r->type);
- continue;
- }
- if (r->defcnt == 0 && r->name->tok == METHOD) {
- vsb_printf(tl->sb,
- "No definition for method %.*s\n", PF(r->name));
- continue;
- }
-
- if (r->defcnt == 0) {
- vsb_printf(tl->sb,
- "Undefined %s %.*s, first reference:\n",
- type, PF(r->name));
- vcc_ErrWhere(tl, r->name);
- continue;
- }
-
- vsb_printf(tl->sb, "Unused %s %.*s, defined:\n",
- type, PF(r->name));
- vcc_ErrWhere(tl, r->name);
- }
- return (nerr);
-}
-
/*--------------------------------------------------------------------
* Output the location/profiling table. For each counted token, we
* record source+line+charpos for the first character in the token.
if (tl->err)
return (vcc_DestroyTokenList(tl, NULL));
- /* Perform consistency checks */
- Consistency(tl);
- if (tl->err)
+ /* Check for orphans */
+ if (vcc_CheckReferences(tl))
return (vcc_DestroyTokenList(tl, NULL));
- /* Check for orphans */
- if (CheckRefs(tl))
+ /* Check that all action returns are legal */
+ vcc_CheckAction(tl);
+ if (tl->err)
return (vcc_DestroyTokenList(tl, NULL));
Ff(tl, 0, "\tVRT_free_backends(&VCL_conf);\n");
struct method {
const char *name;
- unsigned returns;
-};
-
-struct proccall {
- TAILQ_ENTRY(proccall) list;
- struct proc *p;
- struct token *t;
-};
-
-struct proc {
- TAILQ_ENTRY(proc) list;
- TAILQ_HEAD(,proccall) calls;
- struct token *name;
- unsigned returns;
- unsigned exists;
- unsigned called;
- unsigned active;
- struct token *returnt[VCL_RET_MAX];
+ unsigned actions;
};
+struct proc;
/*--------------------------------------------------------------------*/
void vcc_Cond_Ip(struct var *vp, struct tokenlist *tl);
/* vcc_compile.c */
+extern struct method method_tab[];
void Fh(struct tokenlist *tl, int indent, const char *fmt, ...);
void Fc(struct tokenlist *tl, int indent, const char *fmt, ...);
void Fb(struct tokenlist *tl, int indent, const char *fmt, ...);
void Fi(struct tokenlist *tl, int indent, const char *fmt, ...);
void Ff(struct tokenlist *tl, int indent, const char *fmt, ...);
unsigned UintVal(struct tokenlist *tl);
-void AddDef(struct tokenlist *tl, struct token *t, enum ref_type type);
-void AddRef(struct tokenlist *tl, struct token *t, enum ref_type type);
void EncToken(struct vsb *sb, struct token *t);
struct var *FindVar(struct tokenlist *tl, struct token *t, struct var *vl);
-void AddCall(struct tokenlist *tl, struct token *t);
-struct proc *AddProc(struct tokenlist *tl, struct token *t, int def);
int IsMethod(struct token *t);
void *TlAlloc(struct tokenlist *tl, unsigned len);
void vcc_AddToken(struct tokenlist *tl, unsigned tok, const char *b, const char *e);
void vcc_FreeToken(struct token *t);
+/* vcc_expr.c */
+void vcc_AddDef(struct tokenlist *tl, struct token *t, enum ref_type type);
+void vcc_AddRef(struct tokenlist *tl, struct token *t, enum ref_type type);
+int vcc_CheckReferences(struct tokenlist *tl);
+
+void vcc_AddCall(struct tokenlist *tl, struct token *t);
+struct proc *vcc_AddProc(struct tokenlist *tl, struct token *t);
+void vcc_ProcAction(struct proc *p, unsigned action, struct token *t);
+int vcc_CheckAction(struct tokenlist *tl);
+
#define ERRCHK(tl) do { if ((tl)->err) return; } while (0)
#define ErrInternal(tl) vcc__ErrInternal(tl, __func__, __LINE__)
#define Expect(a, b) vcc__Expect(a, b, __LINE__)
return;
#define VCL_RET_MAC(a,b,c,d) case T_##b: \
Fb(tl, 1, "VRT_done(sp, VCL_RET_%s);\n", #b); \
- tl->curproc->returns |= VCL_RET_##b; \
- tl->curproc->returnt[d] = at; \
+ vcc_ProcAction(tl->curproc, d, at); \
return;
#include "vcl_returns.h"
#undef VCL_RET_MAC
return;
case T_CALL:
ExpectErr(tl, ID);
- AddCall(tl, tl->t);
- AddRef(tl, tl->t, R_FUNC);
+ vcc_AddCall(tl, tl->t);
+ vcc_AddRef(tl, tl->t, R_FUNC);
Fb(tl, 1, "if (VGC_function_%.*s(sp))\n", PF(tl->t));
Fb(tl, 1, "\treturn (1);\n");
vcc_NextToken(tl);
case BACKEND:
if (tl->t->tok == '=') {
vcc_NextToken(tl);
- AddRef(tl, tl->t, R_BACKEND);
+ vcc_AddRef(tl, tl->t, R_BACKEND);
Fb(tl, 0, "VGC_backend_%.*s", PF(tl->t));
vcc_NextToken(tl);
Fb(tl, 0, ");\n");
vcc_NextToken(tl);
ExpectErr(tl, ID);
t_be = tl->t;
- AddDef(tl, tl->t, R_BACKEND);
+ vcc_AddDef(tl, tl->t, R_BACKEND);
if (tl->nbackend == 0)
- AddRef(tl, tl->t, R_BACKEND);
+ vcc_AddRef(tl, tl->t, R_BACKEND);
Fh(tl, 1, "#define VGC_backend_%.*s (VCL_conf.backend[%d])\n",
PF(tl->t), tl->nbackend);
Fc(tl, 0, "\n");
assert(m < N_METHODS);
tl->fb = tl->fm[m];
if (tl->mprocs[m] == NULL) {
- tl->mprocs[m] = AddProc(tl, tl->t, 1);
- tl->mprocs[m]->exists++;
- AddDef(tl, tl->t, R_FUNC);
- AddRef(tl, tl->t, R_FUNC);
+ tl->mprocs[m] = vcc_AddProc(tl, tl->t);
+ vcc_AddDef(tl, tl->t, R_FUNC);
+ vcc_AddRef(tl, tl->t, R_FUNC);
}
tl->curproc = tl->mprocs[m];
} else {
tl->fb = tl->fc;
- tl->curproc = AddProc(tl, tl->t, 1);
- tl->curproc->exists++;
- AddDef(tl, tl->t, R_FUNC);
+ tl->curproc = vcc_AddProc(tl, tl->t);
+ vcc_AddDef(tl, tl->t, R_FUNC);
Fh(tl, 0, "static int VGC_function_%.*s (struct sess *sp);\n",
PF(tl->t));
Fc(tl, 1, "static int\n");
--- /dev/null
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006 Linpro AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * 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 AUTHOR 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.
+ *
+ * $Id$
+ *
+ * This fine contains code for two cross-reference or consistency checks.
+ *
+ * The first check is simply that all functions, acls and backends are
+ * both defined and referenced. Complaints about referenced but undefined
+ * or defined but unreferenced objects will be emitted.
+ *
+ * The second check recursively decends through function calls to make
+ * sure that action actions are correct for the methods through which
+ * they are called.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "vsb.h"
+
+#include "vcc_priv.h"
+#include "vcc_compile.h"
+
+/*--------------------------------------------------------------------*/
+
+struct proccall {
+ TAILQ_ENTRY(proccall) list;
+ struct proc *p;
+ struct token *t;
+};
+
+struct proc {
+ TAILQ_ENTRY(proc) list;
+ TAILQ_HEAD(,proccall) calls;
+ struct token *name;
+ unsigned actions;
+ unsigned exists;
+ unsigned called;
+ unsigned active;
+ struct token *action_tok[VCL_RET_MAX];
+};
+
+/*--------------------------------------------------------------------*/
+
+static const char *
+vcc_typename(struct tokenlist *tl, const struct ref *r)
+{
+ switch (r->type) {
+ case R_FUNC: return ("function");
+ case R_ACL: return ("acl");
+ case R_BACKEND: return ("backend");
+ default:
+ ErrInternal(tl);
+ vsb_printf(tl->sb, "Ref ");
+ vcc_ErrToken(tl, r->name);
+ vsb_printf(tl->sb, " has unknown type %d\n",
+ r->type);
+ return "???";
+ }
+}
+
+/*--------------------------------------------------------------------
+ * Keep track of definitions and references
+ */
+
+static struct ref *
+vcc_findref(struct tokenlist *tl, struct token *t, enum ref_type type)
+{
+ struct ref *r;
+
+ TAILQ_FOREACH(r, &tl->refs, list) {
+ if (r->type != type)
+ continue;
+ if (vcc_Teq(r->name, t))
+ return (r);
+ }
+ r = TlAlloc(tl, sizeof *r);
+ assert(r != NULL);
+ r->name = t;
+ r->type = type;
+ TAILQ_INSERT_TAIL(&tl->refs, r, list);
+ return (r);
+}
+
+void
+vcc_AddRef(struct tokenlist *tl, struct token *t, enum ref_type type)
+{
+
+ vcc_findref(tl, t, type)->refcnt++;
+}
+
+void
+vcc_AddDef(struct tokenlist *tl, struct token *t, enum ref_type type)
+{
+ struct ref *r;
+ const char *tp;
+
+ r = vcc_findref(tl, t, type);
+ if (r->defcnt > 0) {
+ tp = vcc_typename(tl, r);
+ vsb_printf(tl->sb, "Multiple definitions of %s \"%.*s\"\n",
+ tp, PF(t));
+ vcc_ErrWhere(tl, r->name);
+ vsb_printf(tl->sb, "...and\n");
+ vcc_ErrWhere(tl, t);
+ }
+ r->defcnt++;
+ r->name = t;
+}
+
+/*--------------------------------------------------------------------*/
+
+int
+vcc_CheckReferences(struct tokenlist *tl)
+{
+ struct ref *r;
+ const char *type;
+ int nerr = 0;
+
+ TAILQ_FOREACH(r, &tl->refs, list) {
+ if (r->defcnt != 0 && r->refcnt != 0)
+ continue;
+ nerr++;
+
+ type = vcc_typename(tl, r);
+ if (r->defcnt == 0 && r->name->tok == METHOD) {
+ vsb_printf(tl->sb,
+ "No definition for method %.*s\n", PF(r->name));
+ continue;
+ }
+
+ if (r->defcnt == 0) {
+ vsb_printf(tl->sb,
+ "Undefined %s %.*s, first reference:\n",
+ type, PF(r->name));
+ vcc_ErrWhere(tl, r->name);
+ continue;
+ }
+
+ vsb_printf(tl->sb, "Unused %s %.*s, defined:\n",
+ type, PF(r->name));
+ vcc_ErrWhere(tl, r->name);
+ }
+ return (nerr);
+}
+
+/*--------------------------------------------------------------------
+ * Returned action checks
+ */
+
+static struct proc *
+vcc_findproc(struct tokenlist *tl, struct token *t)
+{
+ struct proc *p;
+
+ TAILQ_FOREACH(p, &tl->procs, list)
+ if (vcc_Teq(p->name, t))
+ return (p);
+ p = TlAlloc(tl, sizeof *p);
+ assert(p != NULL);
+ TAILQ_INIT(&p->calls);
+ TAILQ_INSERT_TAIL(&tl->procs, p, list);
+ p->name = t;
+ return (p);
+}
+
+struct proc *
+vcc_AddProc(struct tokenlist *tl, struct token *t)
+{
+ struct proc *p;
+
+ p = vcc_findproc(tl, t);
+ p->name = t; /* make sure the name matches the definition */
+ p->exists++;
+ return (p);
+}
+
+void
+vcc_AddCall(struct tokenlist *tl, struct token *t)
+{
+ struct proccall *pc;
+ struct proc *p;
+
+ p = vcc_findproc(tl, t);
+ pc = TlAlloc(tl, sizeof *pc);
+ assert(pc != NULL);
+ pc->p = p;
+ pc->t = t;
+ TAILQ_INSERT_TAIL(&tl->curproc->calls, pc, list);
+}
+
+void
+vcc_ProcAction(struct proc *p, unsigned action, struct token *t)
+{
+
+ p->actions |= (1 << action);
+ /* Record the first instance of this action */
+ if (p->action_tok[action] == NULL)
+ p->action_tok[action] = t;
+}
+
+static int
+vcc_CheckActionRecurse(struct tokenlist *tl, struct proc *p, unsigned actions)
+{
+ unsigned u;
+ struct proccall *pc;
+
+ if (!p->exists) {
+ vsb_printf(tl->sb, "Function %.*s does not exist\n",
+ PF(p->name));
+ return (1);
+ }
+ if (p->active) {
+ vsb_printf(tl->sb, "Function recurses on\n");
+ vcc_ErrWhere(tl, p->name);
+ return (1);
+ }
+ u = p->actions & ~actions;
+ if (u) {
+#define VCL_RET_MAC(a, b, c, d) \
+ if (u & VCL_RET_##b) { \
+ vsb_printf(tl->sb, "Illegal action \"%s\"\n", #a); \
+ vcc_ErrWhere(tl, p->action_tok[d]); \
+ }
+#include "vcl_returns.h"
+#undef VCL_RET_MAC
+ vsb_printf(tl->sb, "\n...in function \"%.*s\"\n", PF(p->name));
+ vcc_ErrWhere(tl, p->name);
+ return (1);
+ }
+ p->active = 1;
+ TAILQ_FOREACH(pc, &p->calls, list) {
+ if (vcc_CheckActionRecurse(tl, pc->p, actions)) {
+ vsb_printf(tl->sb, "\n...called from \"%.*s\"\n",
+ PF(p->name));
+ vcc_ErrWhere(tl, pc->t);
+ return (1);
+ }
+ }
+ p->active = 0;
+ p->called++;
+ return (0);
+}
+
+int
+vcc_CheckAction(struct tokenlist *tl)
+{
+ struct proc *p;
+ struct method *m;
+ int i;
+
+ TAILQ_FOREACH(p, &tl->procs, list) {
+ i = IsMethod(p->name);
+ if (i < 0)
+ continue;
+ m = method_tab + i;
+ if (vcc_CheckActionRecurse(tl, p, m->actions)) {
+ vsb_printf(tl->sb,
+ "\n...which is the \"%s\" method\n", m->name);
+ vsb_printf(tl->sb, "Legal actions are:");
+#define VCL_RET_MAC(a, b, c, d) \
+ if (m->actions & c) \
+ vsb_printf(tl->sb, " \"%s\"", #a);
+#define VCL_RET_MAC_E(a, b, c, d) VCL_RET_MAC(a, b, c, d)
+#include "vcl_returns.h"
+#undef VCL_RET_MAC
+#undef VCL_RET_MAC_E
+ vsb_printf(tl->sb, "\n");
+ return (1);
+ }
+ }
+ TAILQ_FOREACH(p, &tl->procs, list) {
+ if (p->called)
+ continue;
+ vsb_printf(tl->sb, "Function unused\n");
+ vcc_ErrWhere(tl, p->name);
+ return (1);
+ }
+ return (0);
+}
+