Commit f18684bb authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Add first cut of VCL compiler to the tree.

The Makefile is a temporary shim until I get the auto* stuff working.

The sample.vcl is a small mock-up to test the compiler.

Some of the .h files needs to move other places in the fullness of time.

But other than that...



git-svn-id: http://www.varnish-cache.org/svn/trunk/varnish-cache@43 d4fa192b-c00b-0410-8231-f00ffab90ce4
parent 6ee76cd7
......@@ -2,4 +2,5 @@
SUBDIRS = \
libvarnish \
libvarnishapi
libvarnishapi \
libvcl
PROG = vpc
SRCS += vcl_compile.c
SRCS += vcl_fixed_token.c
NO_MAN = yes
WARNS ?= 5
LDADD += -lsbuf
.include <bsd.prog.mk>
test: ${PROG}
./${PROG} ${.CURDIR}/sample.vcl
cc -Wall -c _.c
flint:
flint flint.lnt -I/usr/include -I. ${SRCS}
acl rfc1918 {
10.0.0.0/8;
172.16.0.0/12;
192.168.0.0/16;
}
sub request_policy {
if (client.ip == 10.1.2.3) {
no_cache;
finish;
}
if (client.ip ~ rfc1918) {
no_cache;
finish;
}
if (req.url.host ~ "cnn.no$") {
rewrite "cnn.no$" "vg.no";
}
if (req.url.path ~ "cgi-bin") {
no_cache;
}
if (req.useragent ~ "spider") {
no_new_cache;
}
# comment
if (backend.response_time <= 0.8s) {
set req.ttlfactor = 1.5;
} elseif (backend.response_time > 1.5s) {
set req.ttlfactor = 2.0;
} elseif (backend.response_time > 2.5m) {
set req.ttlfactor = 5.0;
}
/*
* the program contains no references to
* maxage, s-maxage and expires, so the
* default handling (RFC2616) applies
*/
}
backend vg {
set backend.ip = 10.0.0.100;
set backend.timeout = 4s;
set backend.bandwidth = 2000Mb/s;
}
backend chat {
set backend.ip = 10.0.0.4;
set backend.timeout = 4s;
set backend.bandwidth = 2000Mb/s;
}
sub bail {
error 404 "Bailing out";
finish;
}
sub fetch_policy {
if (!req.url.host ~ "/vg.no$/") {
set req.backend = vg;
} else {
/* XXX: specify 404 page url ? */
error 404;
}
if (backend.response_time > 2.0s) {
if (req.url.path ~ "/landbrugspriser/") {
call bail;
}
}
fetch;
if (backend.down) {
if (obj.exist) {
set obj.ttl += 10m;
finish;
}
switch_config ohhshit;
}
if (obj.result == 404) {
error 300 "http://www.vg.no";
}
if (obj.result != 200) {
finish;
}
if (obj.size > 256kb) {
no_cache;
} else if (obj.size > 32kb && obj.ttl < 2m) {
set obj.ttl = 5m;
}
if (backend.response_time > 2.0s) {
set obj.ttl *= 2.0;
}
}
sub prefetch_policy {
if (obj.usage < 10 && obj.ttl < 5m) {
fetch;
}
}
This diff is collapsed.
/*
* NB: This file is machine generated, DO NOT EDIT!
* instead, edit the Tcl script vcl_gen_fixed_token.tcl and run it by hand
*/
#include "vcl_priv.h"
unsigned
fixed_token(const char *p, const char **q)
{
switch (p[0]) {
case '!':
if (p[0] == '!' && p[1] == '=') {
*q = p + 2;
return (T_NEQ);
}
if (p[0] == '!') {
*q = p + 1;
return ('!');
}
return (0);
case '%':
if (p[0] == '%') {
*q = p + 1;
return ('%');
}
return (0);
case '&':
if (p[0] == '&' && p[1] == '&') {
*q = p + 2;
return (T_CAND);
}
if (p[0] == '&') {
*q = p + 1;
return ('&');
}
return (0);
case '(':
if (p[0] == '(') {
*q = p + 1;
return ('(');
}
return (0);
case ')':
if (p[0] == ')') {
*q = p + 1;
return (')');
}
return (0);
case '*':
if (p[0] == '*' && p[1] == '=') {
*q = p + 2;
return (T_MUL);
}
if (p[0] == '*') {
*q = p + 1;
return ('*');
}
return (0);
case '+':
if (p[0] == '+' && p[1] == '=') {
*q = p + 2;
return (T_INCR);
}
if (p[0] == '+' && p[1] == '+') {
*q = p + 2;
return (T_INC);
}
if (p[0] == '+') {
*q = p + 1;
return ('+');
}
return (0);
case ',':
if (p[0] == ',') {
*q = p + 1;
return (',');
}
return (0);
case '-':
if (p[0] == '-' && p[1] == '-') {
*q = p + 2;
return (T_DEC);
}
if (p[0] == '-') {
*q = p + 1;
return ('-');
}
return (0);
case '.':
if (p[0] == '.') {
*q = p + 1;
return ('.');
}
return (0);
case '/':
if (p[0] == '/' && p[1] == '=') {
*q = p + 2;
return (T_DECR);
}
if (p[0] == '/' && p[1] == '=') {
*q = p + 2;
return (T_DIV);
}
if (p[0] == '/') {
*q = p + 1;
return ('/');
}
return (0);
case ';':
if (p[0] == ';') {
*q = p + 1;
return (';');
}
return (0);
case '<':
if (p[0] == '<' && p[1] == '=') {
*q = p + 2;
return (T_LEQ);
}
if (p[0] == '<' && p[1] == '<') {
*q = p + 2;
return (T_SHL);
}
if (p[0] == '<') {
*q = p + 1;
return ('<');
}
return (0);
case '=':
if (p[0] == '=' && p[1] == '=') {
*q = p + 2;
return (T_EQ);
}
if (p[0] == '=') {
*q = p + 1;
return ('=');
}
return (0);
case '>':
if (p[0] == '>' && p[1] == '>') {
*q = p + 2;
return (T_SHR);
}
if (p[0] == '>' && p[1] == '=') {
*q = p + 2;
return (T_GEQ);
}
if (p[0] == '>') {
*q = p + 1;
return ('>');
}
return (0);
case 'a':
if (p[0] == 'a' && p[1] == 'c' && p[2] == 'l'
&& !isvar(p[3])) {
*q = p + 3;
return (T_ACL);
}
return (0);
case 'b':
if (p[0] == 'b' && p[1] == 'a' && p[2] == 'c' &&
p[3] == 'k' && p[4] == 'e' && p[5] == 'n' &&
p[6] == 'd' && !isvar(p[7])) {
*q = p + 7;
return (T_BACKEND);
}
return (0);
case 'c':
if (p[0] == 'c' && p[1] == 'a' && p[2] == 'l' &&
p[3] == 'l' && !isvar(p[4])) {
*q = p + 4;
return (T_CALL);
}
return (0);
case 'e':
if (p[0] == 'e' && p[1] == 'r' && p[2] == 'r' &&
p[3] == 'o' && p[4] == 'r' && !isvar(p[5])) {
*q = p + 5;
return (T_ERROR);
}
if (p[0] == 'e' && p[1] == 'l' && p[2] == 's' &&
p[3] == 'i' && p[4] == 'f' && !isvar(p[5])) {
*q = p + 5;
return (T_ELSIF);
}
if (p[0] == 'e' && p[1] == 'l' && p[2] == 's' &&
p[3] == 'e' && p[4] == 'i' && p[5] == 'f'
&& !isvar(p[6])) {
*q = p + 6;
return (T_ELSEIF);
}
if (p[0] == 'e' && p[1] == 'l' && p[2] == 's' &&
p[3] == 'e' && !isvar(p[4])) {
*q = p + 4;
return (T_ELSE);
}
return (0);
case 'f':
if (p[0] == 'f' && p[1] == 'u' && p[2] == 'n' &&
p[3] == 'c' && !isvar(p[4])) {
*q = p + 4;
return (T_FUNC);
}
if (p[0] == 'f' && p[1] == 'i' && p[2] == 'n' &&
p[3] == 'i' && p[4] == 's' && p[5] == 'h'
&& !isvar(p[6])) {
*q = p + 6;
return (T_FINISH);
}
if (p[0] == 'f' && p[1] == 'e' && p[2] == 't' &&
p[3] == 'c' && p[4] == 'h' && !isvar(p[5])) {
*q = p + 5;
return (T_FETCH);
}
return (0);
case 'i':
if (p[0] == 'i' && p[1] == 'f' && !isvar(p[2])) {
*q = p + 2;
return (T_IF);
}
return (0);
case 'n':
if (p[0] == 'n' && p[1] == 'o' && p[2] == '_' &&
p[3] == 'n' && p[4] == 'e' && p[5] == 'w' &&
p[6] == '_' && p[7] == 'c' && p[8] == 'a' &&
p[9] == 'c' && p[10] == 'h' && p[11] == 'e'
&& !isvar(p[12])) {
*q = p + 12;
return (T_NO_NEW_CACHE);
}
if (p[0] == 'n' && p[1] == 'o' && p[2] == '_' &&
p[3] == 'c' && p[4] == 'a' && p[5] == 'c' &&
p[6] == 'h' && p[7] == 'e' && !isvar(p[8])) {
*q = p + 8;
return (T_NO_CACHE);
}
return (0);
case 'p':
if (p[0] == 'p' && p[1] == 'r' && p[2] == 'o' &&
p[3] == 'c' && !isvar(p[4])) {
*q = p + 4;
return (T_PROC);
}
return (0);
case 'r':
if (p[0] == 'r' && p[1] == 'e' && p[2] == 'w' &&
p[3] == 'r' && p[4] == 'i' && p[5] == 't' &&
p[6] == 'e' && !isvar(p[7])) {
*q = p + 7;
return (T_REWRITE);
}
return (0);
case 's':
if (p[0] == 's' && p[1] == 'w' && p[2] == 'i' &&
p[3] == 't' && p[4] == 'c' && p[5] == 'h' &&
p[6] == '_' && p[7] == 'c' && p[8] == 'o' &&
p[9] == 'n' && p[10] == 'f' && p[11] == 'i' &&
p[12] == 'g' && !isvar(p[13])) {
*q = p + 13;
return (T_SWITCH_CONFIG);
}
if (p[0] == 's' && p[1] == 'u' && p[2] == 'b'
&& !isvar(p[3])) {
*q = p + 3;
return (T_SUB);
}
if (p[0] == 's' && p[1] == 'e' && p[2] == 't'
&& !isvar(p[3])) {
*q = p + 3;
return (T_SET);
}
return (0);
case '{':
if (p[0] == '{') {
*q = p + 1;
return ('{');
}
return (0);
case '|':
if (p[0] == '|' && p[1] == '|') {
*q = p + 2;
return (T_COR);
}
if (p[0] == '|') {
*q = p + 1;
return ('|');
}
return (0);
case '}':
if (p[0] == '}') {
*q = p + 1;
return ('}');
}
return (0);
case '~':
if (p[0] == '~') {
*q = p + 1;
return ('~');
}
return (0);
default:
return (0);
}
}
const char *tnames[256] = {
['!'] = "'!'" /* t2 '!' T! */,
['%'] = "'%'" /* t2 '%' T% */,
['&'] = "'&'" /* t2 '&' T& */,
['('] = "'('" /* t2 '(' T( */,
[')'] = "')'" /* t2 ')' T) */,
['*'] = "'*'" /* t2 '*' T* */,
['+'] = "'+'" /* t2 '+' T+ */,
[','] = "','" /* t2 ',' T, */,
['-'] = "'-'" /* t2 '-' T- */,
['.'] = "'.'" /* t2 '.' T. */,
['/'] = "'/'" /* t2 '/' T/ */,
['<'] = "'<'" /* t2 '<' T< */,
['='] = "'='" /* t2 '=' T= */,
['>'] = "'>'" /* t2 '>' T> */,
['{'] = "'{'" /* t2 '\{' T\{ */,
['}'] = "'}'" /* t2 '\}' T\} */,
['|'] = "'|'" /* t2 '|' T| */,
['~'] = "'~'" /* t2 '~' T~ */,
[';'] = "';'" /* t2 {';'} {T;} */,
[CNUM] = "CNUM" /* t CNUM CNUM */,
[CSTR] = "CSTR" /* t CSTR CSTR */,
[EOI] = "EOI" /* t EOI EOI */,
[ID] = "ID" /* t ID ID */,
[T_ACL] = "acl" /* t T_ACL acl */,
[T_BACKEND] = "backend" /* t T_BACKEND backend */,
[T_CALL] = "call" /* t T_CALL call */,
[T_CAND] = "&&" /* t T_CAND && */,
[T_COR] = "||" /* t T_COR || */,
[T_DEC] = "--" /* t T_DEC -- */,
[T_DECR] = "/=" /* t T_DECR /= */,
[T_DIV] = "/=" /* t T_DIV /= */,
[T_ELSE] = "else" /* t T_ELSE else */,
[T_ELSEIF] = "elseif" /* t T_ELSEIF elseif */,
[T_ELSIF] = "elsif" /* t T_ELSIF elsif */,
[T_EQ] = "==" /* t T_EQ == */,
[T_ERROR] = "error" /* t T_ERROR error */,
[T_FETCH] = "fetch" /* t T_FETCH fetch */,
[T_FINISH] = "finish" /* t T_FINISH finish */,
[T_FUNC] = "func" /* t T_FUNC func */,
[T_GEQ] = ">=" /* t T_GEQ >= */,
[T_IF] = "if" /* t T_IF if */,
[T_INC] = "++" /* t T_INC ++ */,
[T_INCR] = "+=" /* t T_INCR += */,
[T_LEQ] = "<=" /* t T_LEQ <= */,
[T_MUL] = "*=" /* t T_MUL *= */,
[T_NEQ] = "!=" /* t T_NEQ != */,
[T_NO_CACHE] = "no_cache" /* t T_NO_CACHE no_cache */,
[T_NO_NEW_CACHE] = "no_new_cache" /* t T_NO_NEW_CACHE no_new_cache */,
[T_PROC] = "proc" /* t T_PROC proc */,
[T_REWRITE] = "rewrite" /* t T_REWRITE rewrite */,
[T_SET] = "set" /* t T_SET set */,
[T_SHL] = "<<" /* t T_SHL << */,
[T_SHR] = ">>" /* t T_SHR >> */,
[T_SUB] = "sub" /* t T_SUB sub */,
[T_SWITCH_CONFIG] = "switch_config" /* t T_SWITCH_CONFIG switch_config */,
[VAR] = "VAR" /* t VAR VAR */,
};
#!/usr/local/bin/tclsh8.4
#
# Generate a C source file to recognize a set of tokens for the
# Varnish
set keywords {
if else elseif elsif
func proc sub
acl
backend
error
fetch
call
no_cache
no_new_cache
set
rewrite
finish
switch_config
}
set magic {
{"++" INC}
{"--" DEC}
{"&&" CAND}
{"||" COR}
{"<=" LEQ}
{"==" EQ}
{"!=" NEQ}
{">=" GEQ}
{">>" SHR}
{"<<" SHL}
{"+=" INCR}
{"/=" DECR}
{"*=" MUL}
{"/=" DIV}
}
set char {{}()*+-/%><=;!&.|~,}
set extras {ID VAR CNUM CSTR EOI}
set fo [open "vcl_fixed_token.c" w]
puts $fo {/*
* NB: This file is machine generated, DO NOT EDIT!
* instead, edit the Tcl script vcl_gen_fixed_token.tcl and run it by hand
*/
}
set foh [open "vcl_token_defs.h" w]
puts $foh {/*
* NB: This file is machine generated, DO NOT EDIT!
* instead, edit the Tcl script vcl_gen_fixed_token.tcl and run it by hand
*/
}
puts $fo "#include \"vcl_priv.h\""
set tn 128
puts $foh "#define LOW_TOKEN $tn"
foreach k $keywords {
set t T_[string toupper $k]
lappend tokens [list $t $k]
puts $foh "#define $t $tn"
incr tn
lappend fixed [list $k $t 1]
}
foreach k $magic {
set t T_[string toupper [lindex $k 1]]
lappend tokens [list $t [lindex $k 0]]
puts $foh "#define $t $tn"
incr tn
lappend fixed [list [lindex $k 0] $t 0]
}
foreach k $extras {
set t [string toupper $k]
lappend tokens [list $t $t]
puts $foh "#define [string toupper $k] $tn"
incr tn
}
for {set i 0} {$i < [string length $char]} {incr i} {
set t [string index $char $i]
lappend token2 [list '$t' T$t]
lappend fixed [list "$t" '$t' 0]
}
set tokens [lsort $tokens]
set token2 [lsort $token2]
# We want to output in ascii order: create sorted first char list
foreach t $fixed {
set xx([string index [lindex $t 0] 0]) 1
}
set seq [lsort [array names xx]]
set ll 0
puts $fo {
unsigned
fixed_token(const char *p, const char **q)}
puts $fo "{"
puts $fo ""
puts $fo " switch (p\[0\]) {"
foreach ch "$seq" {
# Now find all tokens starting with ch
set l ""
foreach t $fixed {
if {[string index [lindex $t 0] 0] == $ch} {
lappend l $t
}
}
# And do then in reverse order to match longest first
set l [lsort -index 0 -decreasing $l]
scan "$ch" "%c" cx
if {$cx != $ll} {
if {$ll} {
puts $fo " return (0);"
}
puts $fo " case '$ch':"
set ll $cx
}
foreach tt $l {
set k [lindex $tt 0]
puts -nonewline $fo " if ("
for {set i 0} {$i < [string length $k]} {incr i} {
if {$i > 0} {
puts -nonewline $fo " && "
if {![expr $i % 3]} {
puts -nonewline $fo "\n\t\t "
}
}
puts -nonewline $fo "p\[$i\] == '[string index $k $i]'"
}
if {[lindex $tt 2]} {
if {![expr $i % 3]} {
puts -nonewline $fo "\n\t\t "
}
puts -nonewline $fo " && !isvar(p\[$i\])"
}
puts $fo ") {"
puts $fo " *q = p + [string length $k];"
puts $fo " return ([lindex $tt 1]);"
puts $fo " }"
}
}
puts $fo " return (0);"
puts $fo " default:"
puts $fo " return (0);"
puts $fo " }"
puts $fo "}"
puts $fo ""
puts $fo "const char *tnames\[256\] = {"
foreach i $token2 {
puts $fo "\t\[[lindex $i 0]\] = \"[lindex $i 0]\" /* t2 $i */,"
}
foreach i $tokens {
puts $fo "\t\[[lindex $i 0]\] = \"[lindex $i 1]\" /* t $i */,"
}
puts $fo "};"
close $foh
close $fo
/*
* Stuff necessary to compile a VCL programs C code
*/
struct vcl_ref {
unsigned line;
unsigned pos;
unsigned count;
const char *token;
};
struct vcl_acl {
unsigned ip;
unsigned mask;
};
struct client {
unsigned ip;
};
struct req {
char *req;
char *useragent;
struct {
char *path;
char *host;
} url;
double ttlfactor;
struct backend *backend;
};
struct backend {
unsigned ip;
double responsetime;
double timeout;
double bandwidth;
int down;
};
struct obj {
int exists;
double ttl;
unsigned result;
unsigned size;
unsigned usage;
};
#define VCL_FARGS struct client *client, struct obj *obj, struct req *req, struct backend *backend
#define VCL_PASS_ARGS client, obj, req, backend
void VCL_count(unsigned);
void VCL_no_cache();
void VCL_no_new_cache();
int ip_match(unsigned, struct vcl_acl *);
int string_match(const char *, const char *);
int VCL_rewrite(const char *, const char *);
int VCL_error(unsigned, const char *);
int VCL_fetch(void);
int VCL_switch_config(const char *);
/*
* Stuff shared between main.c and fixed_token.c
*/
#include "vcl_token_defs.h"
#include <ctype.h>
#define isident1(c) (isalpha(c))
#define isident(c) (isalpha(c) || isdigit(c) || (c) == '_')
#define isvar(c) (isident(c) || (c) == '.')
unsigned fixed_token(const char *p, const char **q);
extern const char *tnames[256];
/*
* NB: This file is machine generated, DO NOT EDIT!
* instead, edit the Tcl script vcl_gen_fixed_token.tcl and run it by hand
*/
#define LOW_TOKEN 128
#define T_IF 128
#define T_ELSE 129
#define T_ELSEIF 130
#define T_ELSIF 131
#define T_FUNC 132
#define T_PROC 133
#define T_SUB 134
#define T_ACL 135
#define T_BACKEND 136
#define T_ERROR 137
#define T_FETCH 138
#define T_CALL 139
#define T_NO_CACHE 140
#define T_NO_NEW_CACHE 141
#define T_SET 142
#define T_REWRITE 143
#define T_FINISH 144
#define T_SWITCH_CONFIG 145
#define T_INC 146
#define T_DEC 147
#define T_CAND 148
#define T_COR 149
#define T_LEQ 150
#define T_EQ 151
#define T_NEQ 152
#define T_GEQ 153
#define T_SHR 154
#define T_SHL 155
#define T_INCR 156
#define T_DECR 157
#define T_MUL 158
#define T_DIV 159
#define ID 160
#define VAR 161
#define CNUM 162
#define CSTR 163
#define EOI 164
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment