]> err.no Git - varnish/commitdiff
Twist the compiler logic around a bit.
authorphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Sat, 24 Mar 2007 22:09:53 +0000 (22:09 +0000)
committerphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Sat, 24 Mar 2007 22:09:53 +0000 (22:09 +0000)
Concatenate all definitions of the method functions into one
instance of the function:

sub vcl_pipe {
foo;
}

sub vcl_pipe {
bar;
}

is now the same as

sub vcl_pipe {
foo;
bar;
}

This avoids all the magic related to the default functions and
hopefully makes the newly introduced "include" facility much more
useful.

git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@1284 d4fa192b-c00b-0410-8231-f00ffab90ce4

varnish-cache/bin/varnishd/mgt_vcc.c
varnish-cache/include/vcl_returns.h
varnish-cache/lib/libvcl/vcc_compile.c
varnish-cache/lib/libvcl/vcc_compile.h
varnish-cache/lib/libvcl/vcc_gen_fixed_token.tcl
varnish-cache/lib/libvcl/vcc_parse.c

index 301c0147044fd22607278ad99ca2a548658be584..0e01241a881a201169580b0b78bd8c92b0ebe5f5 100644 (file)
@@ -66,7 +66,7 @@ static TAILQ_HEAD(, vclprog) vclhead = TAILQ_HEAD_INITIALIZER(vclhead);
 
 /* keep this in synch with man/vcl.7 */
 static const char *default_vcl =
-    "sub default_vcl_recv {\n"
+    "sub vcl_recv {\n"
     "    if (req.request != \"GET\" && req.request != \"HEAD\") {\n"
     "        pipe;\n"
     "    }\n"
@@ -79,30 +79,30 @@ static const char *default_vcl =
     "    lookup;\n"
     "}\n"
     "\n"
-    "sub default_vcl_pipe {\n"
+    "sub vcl_pipe {\n"
     "    pipe;\n"
     "}\n"
     "\n"
-    "sub default_vcl_pass {\n"
+    "sub vcl_pass {\n"
     "    pass;\n"
     "}\n"
     "\n"
-    "sub default_vcl_hash {\n"
+    "sub vcl_hash {\n"
     "    hash;\n"
     "}\n"
     "\n"
-    "sub default_vcl_hit {\n"
+    "sub vcl_hit {\n"
     "    if (!obj.cacheable) {\n"
     "        pass;\n"
     "    }\n"
     "    deliver;\n"
     "}\n"
     "\n"
-    "sub default_vcl_miss {\n"
+    "sub vcl_miss {\n"
     "    fetch;\n"
     "}\n"
     "\n"
-    "sub default_vcl_fetch {\n"
+    "sub vcl_fetch {\n"
     "    if (!obj.valid) {\n"
     "        error;\n"
     "    }\n"
@@ -114,7 +114,7 @@ static const char *default_vcl =
     "    }\n"
     "    insert;\n"
     "}\n"
-    "sub default_vcl_timeout {\n"
+    "sub vcl_timeout {\n"
     "    discard;\n"
     "}\n";
 
index 59fcc65761ac9c010c12d077b2f2ad5daa4fea12..b3b057dd565a5de4ed7f6255c6c946c2b0783f29 100644 (file)
@@ -41,3 +41,4 @@ VCL_MET_MAC(hit,HIT,(VCL_RET_ERROR|VCL_RET_PASS|VCL_RET_DELIVER))
 VCL_MET_MAC(fetch,FETCH,(VCL_RET_ERROR|VCL_RET_PASS|VCL_RET_INSERT))
 VCL_MET_MAC(timeout,TIMEOUT,(VCL_RET_FETCH|VCL_RET_DISCARD))
 #endif
+#define N_METHODS 8
index 4d9c6b217c2c179f954dd40ef7b153dd7537842f..dfc4163ddffd1ad39354727e7b58ffbfeac282b1 100644 (file)
@@ -87,7 +87,7 @@
 
 static struct method method_tab[] = {
 #define VCL_RET_MAC(l,U,b,n)
-#define VCL_MET_MAC(l,U,m)     { "vcl_"#l, "default_vcl_"#l, m },
+#define VCL_MET_MAC(l,U,m)     { "vcl_"#l, m },
 #include "vcl_returns.h"
 #undef VCL_MET_MAC
 #undef VCL_RET_MAC
@@ -96,7 +96,21 @@ static struct method method_tab[] = {
 
 /*--------------------------------------------------------------------*/
 
-const char *vcc_default_vcl_b, *vcc_default_vcl_e;
+static const char *vcc_default_vcl_b, *vcc_default_vcl_e;
+
+/*--------------------------------------------------------------------*/
+
+int
+IsMethod(struct token *t)
+{
+       struct method *m;
+
+       for(m = method_tab; m->name != NULL; m++) {
+               if (vcc_IdIs(t, m->name))
+                       return (m - method_tab);
+       }
+       return (-1);
+}
 
 /*--------------------------------------------------------------------
  * Printf output to the two vsbs, possibly indented
@@ -114,6 +128,19 @@ Fh(struct tokenlist *tl, int indent, const char *fmt, ...)
        va_end(ap);
 }
 
+void
+Fb(struct tokenlist *tl, int indent, const char *fmt, ...)
+{
+       va_list ap;
+
+       assert(tl->fb != NULL);
+       if (indent)
+               vsb_printf(tl->fb, "%*.*s", tl->indent, tl->indent, "");
+       va_start(ap, fmt);
+       vsb_vprintf(tl->fb, fmt, ap);
+       va_end(ap);
+}
+
 void
 Fc(struct tokenlist *tl, int indent, const char *fmt, ...)
 {
@@ -152,8 +179,8 @@ Ff(struct tokenlist *tl, int indent, const char *fmt, ...)
 
 /*--------------------------------------------------------------------*/
 
-void
-EncString(struct vsb *sb, const char *b, const char *e)
+static void
+EncString(struct vsb *sb, const char *b, const char *e, int mode)
 {
 
        if (e == NULL)
@@ -166,7 +193,11 @@ EncString(struct vsb *sb, const char *b, const char *e)
                case '"':
                        vsb_printf(sb, "\\%c", *b);
                        break;
-               case '\n': vsb_printf(sb, "\\n"); break;
+               case '\n':
+                       vsb_printf(sb, "\\n");
+                       if (mode) 
+                               vsb_printf(sb, "\"\n\t\"");
+                       break;
                case '\t': vsb_printf(sb, "\\t"); break;
                case '\r': vsb_printf(sb, "\\r"); break;
                case ' ': vsb_printf(sb, " "); break;
@@ -186,7 +217,7 @@ EncToken(struct vsb *sb, struct token *t)
 {
 
        assert(t->tok == CSTR);
-       EncString(sb, t->dec, NULL);
+       EncString(sb, t->dec, NULL, 0);
 }
 
 /*--------------------------------------------------------------------
@@ -212,20 +243,6 @@ FindRef(struct tokenlist *tl, struct token *t, enum ref_type type)
        return (r);
 }
 
-static int
-FindRefStr(struct tokenlist *tl, const char *s, enum ref_type type)
-{
-       struct ref *r;
-
-       TAILQ_FOREACH(r, &tl->refs, list) {
-               if (r->type != type)
-                       continue;
-               if (vcc_IdIs(r->name, s))
-                       return (1);
-       }
-       return (0);
-}
-
 void
 AddRef(struct tokenlist *tl, struct token *t, enum ref_type type)
 {
@@ -233,20 +250,6 @@ AddRef(struct tokenlist *tl, struct token *t, enum ref_type type)
        FindRef(tl, t, type)->refcnt++;
 }
 
-static void
-AddRefStr(struct tokenlist *tl, const char *s, enum ref_type type)
-{
-       struct token *t;
-
-       t = calloc(sizeof *t, 1);
-       assert(t != NULL);
-       t->b = s;
-       t->e = strchr(s, '\0');
-       t->tok = METHOD;
-       AddRef(tl, t, type);
-       /* XXX: possibly leaking t */
-}
-
 void
 AddDef(struct tokenlist *tl, struct token *t, enum ref_type type)
 {
@@ -407,8 +410,6 @@ Consistency(struct tokenlist *tl)
 
        TAILQ_FOREACH(p, &tl->procs, list) {
                for(m = method_tab; m->name != NULL; m++) {
-                       if (vcc_IdIs(p->name, m->defname))
-                               p->called = 1;
                        if (vcc_IdIs(p->name, m->name))
                                break;
                }
@@ -564,15 +565,18 @@ EmitStruct(struct tokenlist *tl)
        Fc(tl, 0, "\nconst char *srcname[%u] = {\n", tl->nsources);
        TAILQ_FOREACH(sp, &tl->sources, list) {
                Fc(tl, 0, "\t");
-               EncString(tl->fc, sp->name, NULL);
+               EncString(tl->fc, sp->name, NULL, 0);
                Fc(tl, 0, ",\n");
        }
        Fc(tl, 0, "};\n");
        
        Fc(tl, 0, "\nconst char *srcbody[%u] = {\n", tl->nsources);
        TAILQ_FOREACH(sp, &tl->sources, list) {
+               Fc(tl, 0, "    /* ");
+               EncString(tl->fc, sp->name, NULL, 0);
+               Fc(tl, 0, "*/\n");
                Fc(tl, 0, "\t");
-               EncString(tl->fc, sp->b, sp->e);
+               EncString(tl->fc, sp->b, sp->e, 1);
                Fc(tl, 0, ",\n");
        }
        Fc(tl, 0, "};\n");
@@ -589,13 +593,7 @@ EmitStruct(struct tokenlist *tl)
        Fc(tl, 0, "\t.srcbody = srcbody,\n");
 #define VCL_RET_MAC(l,u,b,n)
 #define VCL_MET_MAC(l,u,b) \
-       if (FindRefStr(tl, "vcl_" #l, R_FUNC)) { \
-               Fc(tl, 0, "\t." #l "_func = VGC_function_vcl_" #l ",\n"); \
-               AddRefStr(tl, "vcl_" #l, R_FUNC); \
-       } else { \
-               Fc(tl, 0, "\t." #l "_func = VGC_function_default_vcl_" #l ",\n"); \
-       } \
-       AddRefStr(tl, "default_vcl_" #l, R_FUNC);
+       Fc(tl, 0, "\t." #l "_func = VGC_function_vcl_" #l ",\n"); 
 #include "vcl_returns.h"
 #undef VCL_MET_MAC
 #undef VCL_RET_MAC
@@ -744,11 +742,10 @@ vcc_CompileSource(struct vsb *sb, struct source *sp)
        assert(tl->ff != NULL);
 
        /* body code of methods */
-#define VCL_MET_MAC(l,U,m) \
-               tl->fm_##l = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); \
-               assert(tl->fm_##l != NULL);
-#include "vcl_returns.h"
-#undef VCL_MET_MAC
+       for (i = 0; i < N_METHODS; i++) {
+               tl->fm[i] = vsb_new(NULL, NULL, 0, VSB_AUTOEXTEND); \
+               assert(tl->fm[i] != NULL);
+       }
 
        Fh(tl, 0, "extern struct VCL_conf VCL_conf;\n");
 
@@ -779,6 +776,18 @@ vcc_CompileSource(struct vsb *sb, struct source *sp)
        Consistency(tl);
        if (tl->err)
                goto done;
+
+       /* Emit method functions */
+       for (i = 0; i < N_METHODS; i++) {
+               Fc(tl, 1, "static int\n");
+               Fc(tl, 1, "VGC_function_%s (struct sess *sp)\n",
+                   method_tab[i].name);
+               vsb_finish(tl->fm[i]);
+               Fc(tl, 1, "{\n");
+               Fc(tl, 1, "%s", vsb_data(tl->fm[i]));
+               Fc(tl, 1, "}\n\n");
+       }
+
        LocTable(tl);
 
        Ff(tl, 0, "\tVRT_free_backends(&VCL_conf);\n");
@@ -824,9 +833,8 @@ vcc_CompileSource(struct vsb *sb, struct source *sp)
        }
 done:
 
-#define VCL_MET_MAC(l,U,m) vsb_delete(tl->fm_##l);
-#include "vcl_returns.h"
-#undef VCL_MET_MAC
+       for (i = 0; i < N_METHODS; i++)
+               vsb_delete(tl->fm[i]);
 
        /* Free References */
        while (!TAILQ_EMPTY(&tl->refs)) {
index 187dee6c03c39259b238c184d60f460b2ac0cb03..f6307a74f4feabc694e5edb36e723fbcf8eb1163 100644 (file)
@@ -62,16 +62,15 @@ struct tokenlist {
        struct token            *t;
        int                     indent;
        unsigned                cnt;
-       struct vsb              *fc, *fh, *fi, *ff;
-#define VCL_MET_MAC(l,U,m) struct vsb *fm_##l;
-#include "vcl_returns.h"
-#undef VCL_MET_MAC
+       struct vsb              *fc, *fh, *fi, *ff, *fb;
+       struct vsb              *fm[N_METHODS];
        TAILQ_HEAD(, ref)       refs;
        struct vsb              *sb;
        int                     err;
        int                     nbackend;
        TAILQ_HEAD(, proc)      procs;
        struct proc             *curproc;
+       struct proc             *mprocs[N_METHODS];
 
        unsigned                recnt;
 };
@@ -115,7 +114,6 @@ struct var {
 
 struct method {
        const char              *name;
-       const char              *defname;
        unsigned                returns;
 };
 
@@ -145,19 +143,19 @@ void vcc_Acl(struct tokenlist *tl);
 void vcc_Cond_Ip(struct var *vp, struct tokenlist *tl);
 
 /* vcc_compile.c */
-extern const char *vcc_default_vcl_b, *vcc_default_vcl_e;
 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);
-void EncString(struct vsb *sb, const char *b, const char *e);
 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);
 
 /* vcc_obj.c */
 extern struct var vcc_be_vars[];
index 0b2f98043c5103c161261e530c3d07f5725a92c4..317d3c1b1e0c8577d2afb1358d09824646d60f94 100755 (executable)
@@ -185,6 +185,7 @@ puts $for "#define VCL_RET_MAX $i"
 puts $for "#endif"
 puts $for ""
 puts $for "#ifdef VCL_MET_MAC"
+set u 0
 foreach m $methods {
        puts -nonewline $for "VCL_MET_MAC([lindex $m 0]"
        puts -nonewline $for ",[string toupper [lindex $m 0]]"
@@ -195,8 +196,10 @@ foreach m $methods {
        }
        puts -nonewline $for ")"
        puts $for ")"
+       incr u
 }
 puts $for "#endif"
+puts $for "#define N_METHODS $u"
 close $for
 
 #----------------------------------------------------------------------
index 53f18b0004672beab927c3a5831696a408396eea..6bfe344f6f9f090363199522b7742077df1c946e 100644 (file)
 #include "vrt.h"
 #include "libvcl.h"
 
-static struct method method_tab[] = {
-#define VCL_RET_MAC(l,U,b,n)
-#define VCL_MET_MAC(l,U,m)     { "vcl_"#l, "default_vcl_"#l, m },
-#include "vcl_returns.h"
-#undef VCL_MET_MAC
-#undef VCL_RET_MAC
-       { NULL, 0U }
-};
-
 /*--------------------------------------------------------------------*/
 
 static void Compound(struct tokenlist *tl);
 static void Cond_0(struct tokenlist *tl);
-const char *vcc_default_vcl_b, *vcc_default_vcl_e;
 
 /*--------------------------------------------------------------------*/
 
@@ -109,26 +99,10 @@ const char *vcc_default_vcl_b, *vcc_default_vcl_e;
 } while (0)
 
 #define C(tl, sep)     do {                                    \
-       Fc(tl, 1, "VRT_count(sp, %u)%s\n", ++tl->cnt, sep);     \
+       Fb(tl, 1, "VRT_count(sp, %u)%s\n", ++tl->cnt, sep);     \
        tl->t->cnt = tl->cnt;                                   \
 } while (0)
 
-/*--------------------------------------------------------------------*/
-
-static int
-IsMethod(struct token *t)
-{
-       struct method *m;
-
-       for(m = method_tab; m->name != NULL; m++) {
-               if (vcc_IdIs(t, m->defname))
-                       return (2);
-               if (vcc_IdIs(t, m->name))
-                       return (1);
-       }
-       return (0);
-}
-
 /*--------------------------------------------------------------------
  * Recognize and convert units of time, return seconds.
  */
@@ -264,7 +238,7 @@ TimeVal(struct tokenlist *tl)
        v = DoubleVal(tl);
        ExpectErr(tl, ID);
        sc = TimeUnit(tl);
-       Fc(tl, 0, "(%g * %g)", v, sc);
+       Fb(tl, 0, "(%g * %g)", v, sc);
 }
 
 static void
@@ -275,7 +249,7 @@ SizeVal(struct tokenlist *tl)
        v = DoubleVal(tl);
        ExpectErr(tl, ID);
        sc = SizeUnit(tl);
-       Fc(tl, 0, "(%g * %g)", v, sc);
+       Fb(tl, 0, "(%g * %g)", v, sc);
 }
 
 static void
@@ -286,7 +260,7 @@ RateVal(struct tokenlist *tl)
        v = DoubleVal(tl);
        ExpectErr(tl, ID);
        sc = RateUnit(tl);
-       Fc(tl, 0, "(%g * %g)", v, sc);
+       Fb(tl, 0, "(%g * %g)", v, sc);
 }
 
 /*--------------------------------------------------------------------*/
@@ -303,7 +277,7 @@ vcc_re(struct tokenlist *tl, const char *str, struct token *re)
        }
        sprintf(buf, "VGC_re_%u", tl->recnt++);
 
-       Fc(tl, 1, "VRT_re_match(%s, %s)\n", str, buf);
+       Fb(tl, 1, "VRT_re_match(%s, %s)\n", str, buf);
        Fh(tl, 0, "void *%s;\n", buf);
        Fi(tl, 0, "\tVRT_re_init(&%s, ",buf);
        EncToken(tl->fi, re);
@@ -327,16 +301,16 @@ Cond_String(struct var *vp, struct tokenlist *tl)
                break;
        case T_EQ:
        case T_NEQ:
-               Fc(tl, 1, "%sstrcmp(%s, ",
+               Fb(tl, 1, "%sstrcmp(%s, ",
                    tl->t->tok == T_EQ ? "!" : "", vp->rname);
                vcc_NextToken(tl);
                ExpectErr(tl, CSTR);
-               EncToken(tl->fc, tl->t);
-               Fc(tl, 0, ")\n");
+               EncToken(tl->fb, tl->t);
+               Fb(tl, 0, ")\n");
                vcc_NextToken(tl);
                break;
        default:
-               Fc(tl, 1, "%s != (void*)0", vp->rname);
+               Fb(tl, 1, "%s != (void*)0\n", vp->rname);
                break;
        }
 }
@@ -345,7 +319,7 @@ static void
 Cond_Int(struct var *vp, struct tokenlist *tl)
 {
 
-       Fc(tl, 1, "%s ", vp->rname);
+       Fb(tl, 1, "%s ", vp->rname);
        switch (tl->t->tok) {
        case T_EQ:
        case T_NEQ:
@@ -353,7 +327,7 @@ Cond_Int(struct var *vp, struct tokenlist *tl)
        case T_GEQ:
        case '>':
        case '<':
-               Fc(tl, 0, "%.*s ", PF(tl->t));
+               Fb(tl, 0, "%.*s ", PF(tl->t));
                vcc_NextToken(tl);
                switch(vp->fmt) {
                case TIME:
@@ -361,7 +335,7 @@ Cond_Int(struct var *vp, struct tokenlist *tl)
                        break;
                case INT:
                        ExpectErr(tl, CNUM);
-                       Fc(tl, 0, "%.*s ", PF(tl->t));
+                       Fb(tl, 0, "%.*s ", PF(tl->t));
                        vcc_NextToken(tl);
                        break;
                case SIZE:
@@ -374,7 +348,7 @@ Cond_Int(struct var *vp, struct tokenlist *tl)
                        vcc_ErrWhere(tl, tl->t);
                        return;
                }
-               Fc(tl, 0, "\n");
+               Fb(tl, 0, "\n");
                break;
        default:
                vsb_printf(tl->sb, "Illegal condition ");
@@ -391,14 +365,14 @@ static void
 Cond_Bool(struct var *vp, struct tokenlist *tl)
 {
 
-       Fc(tl, 1, "%s\n", vp->rname);
+       Fb(tl, 1, "%s\n", vp->rname);
 }
 
 static void
 Cond_Backend(struct var *vp, struct tokenlist *tl)
 {
 
-       Fc(tl, 1, "%s\n", vp->rname);
+       Fb(tl, 1, "%s\n", vp->rname);
 }
 
 static void
@@ -408,10 +382,10 @@ Cond_2(struct tokenlist *tl)
 
        C(tl, ",");
        if (tl->t->tok == '!') {
-               Fc(tl, 1, "!(\n");
+               Fb(tl, 1, "!(\n");
                vcc_NextToken(tl);
        } else {
-               Fc(tl, 1, "(\n");
+               Fb(tl, 1, "(\n");
        }
        if (tl->t->tok == '(') {
                vcc_NextToken(tl);
@@ -448,35 +422,35 @@ Cond_2(struct tokenlist *tl)
                vcc_ErrWhere(tl, tl->t);
                return;
        }
-       Fc(tl, 1, ")\n");
+       Fb(tl, 1, ")\n");
 }
 
 static void
 Cond_1(struct tokenlist *tl)
 {
 
-       Fc(tl, 1, "(\n");
+       Fb(tl, 1, "(\n");
        L(tl, Cond_2(tl));
        while (tl->t->tok == T_CAND) {
                vcc_NextToken(tl);
-               Fc(tl, 1, ") && (\n");
+               Fb(tl, 1, ") && (\n");
                L(tl, Cond_2(tl));
        }
-       Fc(tl, 1, ")\n");
+       Fb(tl, 1, ")\n");
 }
 
 static void
 Cond_0(struct tokenlist *tl)
 {
 
-       Fc(tl, 1, "(\n");
+       Fb(tl, 1, "(\n");
        L(tl, Cond_1(tl));
        while (tl->t->tok == T_COR) {
                vcc_NextToken(tl);
-               Fc(tl, 1, ") || (\n");
+               Fb(tl, 1, ") || (\n");
                L(tl, Cond_1(tl));
        }
-       Fc(tl, 1, ")\n");
+       Fb(tl, 1, ")\n");
 }
 
 static void
@@ -485,10 +459,10 @@ Conditional(struct tokenlist *tl)
 
        ExpectErr(tl, '(');
        vcc_NextToken(tl);
-       Fc(tl, 1, "(\n");
+       Fb(tl, 1, "(\n");
        L(tl, Cond_0(tl));
        ERRCHK(tl);
-       Fc(tl, 1, ")\n");
+       Fb(tl, 1, ")\n");
        ExpectErr(tl, ')');
        vcc_NextToken(tl);
 }
@@ -500,7 +474,7 @@ IfStmt(struct tokenlist *tl)
 {
 
        ExpectErr(tl, T_IF);
-       Fc(tl, 1, "if \n");
+       Fb(tl, 1, "if \n");
        vcc_NextToken(tl);
        L(tl, Conditional(tl));
        ERRCHK(tl);
@@ -511,7 +485,7 @@ IfStmt(struct tokenlist *tl)
                case T_ELSE:
                        vcc_NextToken(tl);
                        if (tl->t->tok != T_IF) {
-                               Fc(tl, 1, "else \n");
+                               Fb(tl, 1, "else \n");
                                L(tl, Compound(tl));
                                ERRCHK(tl);
                                return;
@@ -519,7 +493,7 @@ IfStmt(struct tokenlist *tl)
                        /* FALLTHROUGH */
                case T_ELSEIF:
                case T_ELSIF:
-                       Fc(tl, 1, "else if \n");
+                       Fb(tl, 1, "else if \n");
                        vcc_NextToken(tl);
                        L(tl, Conditional(tl));
                        ERRCHK(tl);
@@ -546,13 +520,13 @@ Action(struct tokenlist *tl)
        vcc_NextToken(tl);
        switch (at->tok) {
        case T_NO_NEW_CACHE:
-               Fc(tl, 1, "VCL_no_new_cache(sp);\n");
+               Fb(tl, 1, "VCL_no_new_cache(sp);\n");
                return;
        case T_NO_CACHE:
-               Fc(tl, 1, "VCL_no_cache(sp);\n");
+               Fb(tl, 1, "VCL_no_cache(sp);\n");
                return;
 #define VCL_RET_MAC(a,b,c,d) case T_##b: \
-               Fc(tl, 1, "VRT_done(sp, VCL_RET_%s);\n", #b); \
+               Fb(tl, 1, "VRT_done(sp, VCL_RET_%s);\n", #b); \
                tl->curproc->returns |= VCL_RET_##b; \
                tl->curproc->returnt[d] = at; \
                return;
@@ -563,35 +537,35 @@ Action(struct tokenlist *tl)
                        a = UintVal(tl);
                else
                        a = 0;
-               Fc(tl, 1, "VRT_error(sp, %u", a);
+               Fb(tl, 1, "VRT_error(sp, %u", a);
                if (tl->t->tok == CSTR) {
-                       Fc(tl, 0, ", %.*s", PF(tl->t));
+                       Fb(tl, 0, ", %.*s", PF(tl->t));
                        vcc_NextToken(tl);
                } else {
-                       Fc(tl, 0, ", (const char *)0");
+                       Fb(tl, 0, ", (const char *)0");
                }
-               Fc(tl, 0, ");\n");
-               Fc(tl, 1, "VRT_done(sp, VCL_RET_ERROR);\n");
+               Fb(tl, 0, ");\n");
+               Fb(tl, 1, "VRT_done(sp, VCL_RET_ERROR);\n");
                return;
        case T_SWITCH_CONFIG:
                ExpectErr(tl, ID);
-               Fc(tl, 1, "VCL_switch_config(\"%.*s\");\n", PF(tl->t));
+               Fb(tl, 1, "VCL_switch_config(\"%.*s\");\n", PF(tl->t));
                vcc_NextToken(tl);
                return;
        case T_CALL:
                ExpectErr(tl, ID);
                AddCall(tl, tl->t);
                AddRef(tl, tl->t, R_FUNC);
-               Fc(tl, 1, "if (VGC_function_%.*s(sp))\n", PF(tl->t));
-               Fc(tl, 1, "\treturn (1);\n");
+               Fb(tl, 1, "if (VGC_function_%.*s(sp))\n", PF(tl->t));
+               Fb(tl, 1, "\treturn (1);\n");
                vcc_NextToken(tl);
                return;
        case T_REWRITE:
                ExpectErr(tl, CSTR);
-               Fc(tl, 1, "VCL_rewrite(%.*s", PF(tl->t));
+               Fb(tl, 1, "VCL_rewrite(%.*s", PF(tl->t));
                vcc_NextToken(tl);
                ExpectErr(tl, CSTR);
-               Fc(tl, 0, ", %.*s);\n", PF(tl->t));
+               Fb(tl, 0, ", %.*s);\n", PF(tl->t));
                vcc_NextToken(tl);
                return;
        case T_SET:
@@ -599,7 +573,7 @@ Action(struct tokenlist *tl)
                vp = FindVar(tl, tl->t, vcc_vars);
                ERRCHK(tl);
                assert(vp != NULL);
-               Fc(tl, 1, "%s", vp->lname);
+               Fb(tl, 1, "%s", vp->lname);
                vcc_NextToken(tl);
                switch (vp->fmt) {
                case INT:
@@ -608,11 +582,11 @@ Action(struct tokenlist *tl)
                case TIME:
                case FLOAT:
                        if (tl->t->tok != '=')
-                               Fc(tl, 0, "%s %c ", vp->rname, *tl->t->b);
+                               Fb(tl, 0, "%s %c ", vp->rname, *tl->t->b);
                        a = tl->t->tok;
                        vcc_NextToken(tl);
                        if (a == T_MUL || a == T_DIV)
-                               Fc(tl, 0, "%g", DoubleVal(tl));
+                               Fb(tl, 0, "%g", DoubleVal(tl));
                        else if (vp->fmt == TIME)
                                TimeVal(tl);
                        else if (vp->fmt == SIZE)
@@ -620,15 +594,15 @@ Action(struct tokenlist *tl)
                        else if (vp->fmt == RATE)
                                RateVal(tl);
                        else
-                               Fc(tl, 0, "%g", DoubleVal(tl));
-                       Fc(tl, 0, ");\n");
+                               Fb(tl, 0, "%g", DoubleVal(tl));
+                       Fb(tl, 0, ");\n");
                        break;
 #if 0  /* XXX: enable if we find a legit use */
                case IP:
                        if (tl->t->tok == '=') {
                                vcc_NextToken(tl);
                                u = vcc_IpVal(tl);
-                               Fc(tl, 0, "= %uU; /* %u.%u.%u.%u */\n",
+                               Fb(tl, 0, "= %uU; /* %u.%u.%u.%u */\n",
                                    u,
                                    (u >> 24) & 0xff,
                                    (u >> 16) & 0xff,
@@ -647,9 +621,9 @@ Action(struct tokenlist *tl)
                        if (tl->t->tok == '=') {
                                vcc_NextToken(tl);
                                AddRef(tl, tl->t, R_BACKEND);
-                               Fc(tl, 0, "VGC_backend_%.*s", PF(tl->t));
+                               Fb(tl, 0, "VGC_backend_%.*s", PF(tl->t));
                                vcc_NextToken(tl);
-                               Fc(tl, 0, ");\n");
+                               Fb(tl, 0, ");\n");
                                break;
                        }
                        vsb_printf(tl->sb, "Illegal assignment operator ");
@@ -679,7 +653,7 @@ Compound(struct tokenlist *tl)
 {
 
        ExpectErr(tl, '{');
-       Fc(tl, 1, "{\n");
+       Fb(tl, 1, "{\n");
        tl->indent += INDENT;
        C(tl, ";");
        vcc_NextToken(tl);
@@ -695,7 +669,7 @@ Compound(struct tokenlist *tl)
                case '}':
                        vcc_NextToken(tl);
                        tl->indent -= INDENT;
-                       Fc(tl, 1, "}\n");
+                       Fb(tl, 1, "}\n");
                        return;
                case EOI:
                        vsb_printf(tl->sb,
@@ -853,28 +827,40 @@ Backend(struct tokenlist *tl)
 static void
 Function(struct tokenlist *tl)
 {
-       struct token *tn;
+       int m;
 
        vcc_NextToken(tl);
        ExpectErr(tl, ID);
-       tl->curproc = AddProc(tl, tl->t, 1);
-       tl->curproc->exists++;
-       tn = tl->t;
-       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");
-       Fc(tl, 1, "VGC_function_%.*s (struct sess *sp)\n", PF(tl->t));
+
+       m = IsMethod(tl->t);
+       if (m != -1) {
+               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->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);
+               Fh(tl, 0, "static int VGC_function_%.*s (struct sess *sp);\n",
+                   PF(tl->t));
+               Fc(tl, 1, "static int\n");
+               Fc(tl, 1, "VGC_function_%.*s (struct sess *sp)\n", PF(tl->t));
+       }
        vcc_NextToken(tl);
        tl->indent += INDENT;
-       Fc(tl, 1, "{\n");
+       Fb(tl, 1, "{\n");
        L(tl, Compound(tl));
-       if (IsMethod(tn) == 1) {
-               Fc(tl, 1, "VGC_function_default_%.*s(sp);\n", PF(tn));
-       }
-       Fc(tl, 1, "}\n");
+       Fb(tl, 1, "}\n");
        tl->indent -= INDENT;
-       Fc(tl, 0, "\n");
+       Fb(tl, 0, "\n");
+       tl->fb = NULL;
 }
 
 /*--------------------------------------------------------------------