Index: trunk/willow/src/include/confgrammar.h |
— | — | @@ -0,0 +1,215 @@ |
| 2 | +/* Willow: Lightweight HTTP reverse-proxy. */ |
| 3 | +/* confgrammar: Spirit grammar for confparse */ |
| 4 | +/* Copyright (c) 2005, 2006 River Tarnell <river@attenuate.org>. */ |
| 5 | +/* |
| 6 | + * Permission is granted to anyone to use this software for any purpose, |
| 7 | + * including commercial applications, and to alter it and redistribute it |
| 8 | + * freely. This software is provided 'as-is', without any express or implied |
| 9 | + * warranty. |
| 10 | + */ |
| 11 | + |
| 12 | +/* $Id$ */ |
| 13 | + |
| 14 | +#ifndef CONFGRAMMAR_H |
| 15 | +#define CONFGRAMMAR_H |
| 16 | + |
| 17 | +#include <iostream> |
| 18 | +#include <vector> |
| 19 | +#include <exception> |
| 20 | + |
| 21 | +#include <boost/mpl/vector_c.hpp> |
| 22 | +#include <boost/mpl/equal.hpp> |
| 23 | +#include <boost/mpl/plus.hpp> |
| 24 | +#include <boost/mpl/minus.hpp> |
| 25 | +#include <boost/mpl/transform.hpp> |
| 26 | +#include <boost/mpl/placeholders.hpp> |
| 27 | +#include <boost/static_assert.hpp> |
| 28 | +#include <boost/variant.hpp> |
| 29 | +using std::vector; |
| 30 | +using std::ostream; |
| 31 | +using std::exception; |
| 32 | +using boost::variant; |
| 33 | + |
| 34 | +namespace mpl = boost::mpl; |
| 35 | +namespace mpp = boost::mpl::placeholders; |
| 36 | + |
| 37 | +#include "willow.h" |
| 38 | +#include "util.h" |
| 39 | +#include "preprocessor.h" |
| 40 | +#include "expr.h" |
| 41 | + |
| 42 | +struct parser_error : exception { |
| 43 | + parser_error(char const *e) : _err(e) {} |
| 44 | + char const *what(void) const throw() { |
| 45 | + return _err; |
| 46 | + } |
| 47 | + |
| 48 | +private: |
| 49 | + char const *_err; |
| 50 | +}; |
| 51 | + |
| 52 | +enum string_type { |
| 53 | + string_tag, |
| 54 | + quoted_string_tag |
| 55 | +}; |
| 56 | + |
| 57 | +template<string_type tag> |
| 58 | +struct tagged_string { |
| 59 | + tagged_string() {} |
| 60 | + tagged_string(string const &s) : v(s) {} |
| 61 | + tagged_string(tagged_string const &other) : v(other.v) {} |
| 62 | + template<typename iter> |
| 63 | + tagged_string(iter begin, iter end) : v(begin, end) {} |
| 64 | + tagged_string &operator= (tagged_string const &other) { |
| 65 | + v = other.v; |
| 66 | + return *this; |
| 67 | + } |
| 68 | + |
| 69 | + string const &value(void) const { |
| 70 | + return v; |
| 71 | + } |
| 72 | + |
| 73 | + string &value(void) { |
| 74 | + return v; |
| 75 | + } |
| 76 | +private: |
| 77 | + string v; |
| 78 | +}; |
| 79 | + |
| 80 | +typedef tagged_string<string_tag> u_string; |
| 81 | +typedef tagged_string<quoted_string_tag> q_string; |
| 82 | + |
| 83 | +typedef mpl::vector_c<int, 0, 0> scalar_d; |
| 84 | +typedef mpl::vector_c<int, 1, 0> time_d; |
| 85 | +typedef mpl::vector_c<int, 0, 1> size_d; |
| 86 | + |
| 87 | +template<typename T, typename D> |
| 88 | +struct quantity { |
| 89 | + quantity() : _value(0) {} |
| 90 | + explicit quantity(T v) : _value(v) {} |
| 91 | + explicit quantity(quantity<T, scalar_d> const &o) |
| 92 | + : _value(o.value()) {} |
| 93 | + |
| 94 | + template<typename D2> |
| 95 | + quantity(quantity<T, D2> const &other) |
| 96 | + : _value(other.value()) { |
| 97 | + BOOST_STATIC_ASSERT(( |
| 98 | + mpl::equal<D, D2>::type::value |
| 99 | + )); |
| 100 | + } |
| 101 | + |
| 102 | + quantity<T, D> &operator= (quantity<T, D> const &o) { |
| 103 | + _value = o.value(); |
| 104 | + return *this; |
| 105 | + } |
| 106 | + |
| 107 | + template<typename D2> |
| 108 | + quantity<T, D> &operator= (quantity<T, D> const &o) { |
| 109 | + BOOST_STATIC_ASSERT(( |
| 110 | + mpl::equal<D, D2>::type::value |
| 111 | + )); |
| 112 | + _value = o.value(); |
| 113 | + return *this; |
| 114 | + } |
| 115 | + |
| 116 | + quantity<T, D> &operator+= (quantity<T, D> const &o) { |
| 117 | + _value += o._value; |
| 118 | + return *this; |
| 119 | + } |
| 120 | + |
| 121 | + quantity<T, D> &operator-= (quantity<T, D> const &o) { |
| 122 | + _value -= o._value; |
| 123 | + return *this; |
| 124 | + } |
| 125 | + |
| 126 | + template<typename D2> |
| 127 | + quantity<T, D> &operator*= (quantity<T, D2> const &o) { |
| 128 | + *this = *this * o; |
| 129 | + return *this; |
| 130 | + } |
| 131 | + |
| 132 | + template<typename D2> |
| 133 | + quantity<T, D> &operator/= (quantity<T, D2> const &o) { |
| 134 | + *this = *this / o; |
| 135 | + return *this; |
| 136 | + } |
| 137 | + |
| 138 | + T value(void) const { return _value; } |
| 139 | +private: |
| 140 | + T _value; |
| 141 | +}; |
| 142 | + |
| 143 | +template<typename T, typename D> |
| 144 | +quantity<T, D> |
| 145 | +operator+ (quantity<T, D> a, quantity<T, D> b) |
| 146 | +{ |
| 147 | + return quantity<T, D>(a.value() + b.value()); |
| 148 | +} |
| 149 | + |
| 150 | +template<typename T, typename D> |
| 151 | +quantity<T, D> |
| 152 | +operator- (quantity<T, D> a, quantity<T, D> b) |
| 153 | +{ |
| 154 | + return quantity<T, D>(a.value() + b.value()); |
| 155 | +} |
| 156 | + |
| 157 | +template<typename T, typename D1, typename D2> |
| 158 | +quantity<T, typename mpl::transform<D1, D2, mpl::plus<mpp::_1, mpp::_2> >::type> |
| 159 | +operator* (quantity<T, D1> a, quantity<T, D2> b) |
| 160 | +{ |
| 161 | + return quantity<T, typename mpl::transform<D1, D2, |
| 162 | + mpl::plus<mpp::_1, mpp::_2> >::type |
| 163 | + >(a.value() * b.value()); |
| 164 | +} |
| 165 | + |
| 166 | +template<typename T, typename D1, typename D2> |
| 167 | +quantity<T, typename mpl::transform<D1, D2, mpl::minus<mpp::_1, mpp::_2> >::type> |
| 168 | +operator/ (quantity<T, D1> a, quantity<T, D2> b) |
| 169 | +{ |
| 170 | + return quantity<T, typename mpl::transform<D1, D2, |
| 171 | + mpl::minus<mpp::_1, mpp::_2> >::type |
| 172 | + >(a.value() / b.value()); |
| 173 | +} |
| 174 | + |
| 175 | +template<typename T, typename D> |
| 176 | +ostream& |
| 177 | +operator<< (ostream &o, quantity<T, D> q) |
| 178 | +{ |
| 179 | + o << q.value(); |
| 180 | + return o; |
| 181 | +} |
| 182 | + |
| 183 | +typedef quantity<int, scalar_d> scalar_q; |
| 184 | +typedef quantity<int, time_d> time_q; |
| 185 | +typedef quantity<int, size_d> size_q; |
| 186 | + |
| 187 | +typedef variant<u_string, q_string, bool, int, time_q, size_q> avalue_t; |
| 188 | + |
| 189 | +struct value_t { |
| 190 | + string name; |
| 191 | + vector<avalue_t> values; |
| 192 | + |
| 193 | + value_t(string const &name_, vector<avalue_t> const &vals_) |
| 194 | + : name(name_), values(vals_) {} |
| 195 | +}; |
| 196 | + |
| 197 | +struct block { |
| 198 | + block(); |
| 199 | + block(string const &name_, string const &value_, vector<value_t> const &values_) |
| 200 | + : name(name_), key(value_), values(values_) {} |
| 201 | + |
| 202 | + string name; |
| 203 | + string key; |
| 204 | + |
| 205 | + vector<value_t> values; |
| 206 | +}; |
| 207 | + |
| 208 | +struct confgrammar { |
| 209 | + confgrammar(expr::parser const &expr); |
| 210 | + vector<block> parse(string const &file); |
| 211 | + |
| 212 | +private: |
| 213 | + expr::parser const &_expr; |
| 214 | +}; |
| 215 | + |
| 216 | +#endif /* CONFGRAMMAR_H */ |
Property changes on: trunk/willow/src/include/confgrammar.h |
___________________________________________________________________ |
Added: svn:keywords |
1 | 217 | + Id Revision |
Index: trunk/willow/src/include/expr.h |
— | — | @@ -15,16 +15,16 @@ |
16 | 16 | |
17 | 17 | namespace expr { |
18 | 18 | |
19 | | -struct expression_error : runtime_error { |
20 | | - expression_error(char const *err) : runtime_error(err) {} |
| 19 | +struct error : runtime_error { |
| 20 | + error(char const *err) : runtime_error(err) {} |
21 | 21 | }; |
22 | 22 | |
23 | | -struct stack_underflow : expression_error { |
24 | | - stack_underflow() : expression_error("stack underflow in expression parser") {} |
| 23 | +struct stack_underflow : error { |
| 24 | + stack_underflow() : error("stack underflow in expression parser") {} |
25 | 25 | }; |
26 | 26 | |
27 | | -struct syntax_error : expression_error { |
28 | | - syntax_error() : expression_error("syntax error in expression parser") {} |
| 27 | +struct syntax_error : error { |
| 28 | + syntax_error() : error("syntax error in expression parser") {} |
29 | 29 | }; |
30 | 30 | |
31 | 31 | struct expression_parser_impl; |
— | — | @@ -52,16 +52,16 @@ |
53 | 53 | * test whether a variable exists: defined(x) has the value '1' if 'x' is |
54 | 54 | * defined. |
55 | 55 | */ |
56 | | -struct expression_parser { |
| 56 | +struct parser { |
57 | 57 | /** |
58 | 58 | * Construct a new parser. |
59 | 59 | */ |
60 | | - expression_parser(); |
| 60 | + parser(); |
61 | 61 | |
62 | 62 | /** |
63 | 63 | * Destructor. |
64 | 64 | */ |
65 | | - ~expression_parser(); |
| 65 | + ~parser(); |
66 | 66 | |
67 | 67 | /** |
68 | 68 | * Add a new variable to this parser. |
Index: trunk/willow/src/include/preprocessor.h |
— | — | @@ -0,0 +1,127 @@ |
| 2 | +/* Willow: Lightweight HTTP reverse-proxy. */ |
| 3 | +/* confgrammar: Spirit grammar for confparse */ |
| 4 | +/* Copyright (c) 2005, 2006 River Tarnell <river@attenuate.org>. */ |
| 5 | +/* |
| 6 | + * Permission is granted to anyone to use this software for any purpose, |
| 7 | + * including commercial applications, and to alter it and redistribute it |
| 8 | + * freely. This software is provided 'as-is', without any express or implied |
| 9 | + * warranty. |
| 10 | + */ |
| 11 | + |
| 12 | +/* $Id$ */ |
| 13 | + |
| 14 | +#ifndef PREPROCESSOR_H |
| 15 | +#define PREPROCESSOR_H |
| 16 | + |
| 17 | +#include <iterator> |
| 18 | +#include <iostream> |
| 19 | +#include <exception> |
| 20 | +using std::exception; |
| 21 | +using std::ostream; |
| 22 | +using std::random_access_iterator_tag; |
| 23 | + |
| 24 | +#include "willow.h" |
| 25 | +#include "expr.h" |
| 26 | + |
| 27 | +struct preprocessor_exception : exception { |
| 28 | + preprocessor_exception(char const *err) : _err(err) {} |
| 29 | + char const *what(void) const throw() { |
| 30 | + return _err; |
| 31 | + } |
| 32 | +private: |
| 33 | + char const *_err; |
| 34 | +}; |
| 35 | + |
| 36 | +struct file_position { |
| 37 | + file_position(string const &f, int l, int p); |
| 38 | + file_position(file_position const &o); |
| 39 | + file_position &operator= (file_position const &o); |
| 40 | + |
| 41 | + string file; |
| 42 | + int line; |
| 43 | + int col; |
| 44 | +}; |
| 45 | + |
| 46 | +ostream& operator<< (ostream &o, file_position const &p); |
| 47 | + |
| 48 | +struct preprocessor { |
| 49 | + struct iterator { |
| 50 | + typedef char value_type; |
| 51 | + typedef value_type const &reference; |
| 52 | + typedef reference const_reference; |
| 53 | + typedef value_type const *pointer; |
| 54 | + typedef vector<char>::difference_type difference_type; |
| 55 | + typedef vector<char>::size_type size_type; |
| 56 | + typedef random_access_iterator_tag iterator_category; |
| 57 | + |
| 58 | + preprocessor const *_cpp; |
| 59 | + vector<char>::const_iterator _it; |
| 60 | + |
| 61 | + iterator(); |
| 62 | + iterator(preprocessor const &cpp, vector<char>::const_iterator it); |
| 63 | + iterator(iterator const &other); |
| 64 | + |
| 65 | + iterator& operator= (iterator const &other); |
| 66 | + iterator& operator++(void); |
| 67 | + iterator operator++(int); |
| 68 | + iterator& operator--(void); |
| 69 | + iterator operator--(int); |
| 70 | + reference operator*(void) const; |
| 71 | + |
| 72 | + bool operator< (iterator const &other) const; |
| 73 | + bool operator== (iterator const &other) const; |
| 74 | + bool operator!= (iterator const &other) const; |
| 75 | + bool operator> (iterator const &other) const; |
| 76 | + |
| 77 | + bool operator<= (iterator const &other) const; |
| 78 | + bool operator>= (iterator const &other) const; |
| 79 | + difference_type operator- (iterator const &other) const; |
| 80 | + iterator operator- (size_type s) const; |
| 81 | + iterator operator+ (size_type s) const; |
| 82 | + file_position get_position(void) const; |
| 83 | + string const &get_line(int i) const; |
| 84 | + }; |
| 85 | + |
| 86 | + typedef iterator const_iterator; |
| 87 | + typedef char value_type; |
| 88 | + typedef value_type const &reference; |
| 89 | + typedef value_type const &const_reference; |
| 90 | + typedef vector<char>::size_type size_type; |
| 91 | + typedef vector<char>::difference_type difference_type; |
| 92 | + |
| 93 | + map<vector<char>::difference_type, file_position> positions; |
| 94 | + vector<string> lines; |
| 95 | + |
| 96 | + void set_position(vector<char>::const_iterator n); |
| 97 | + |
| 98 | + string const &get_line(int line) const; |
| 99 | + file_position get_position(vector<char>::const_iterator it) const; |
| 100 | + |
| 101 | + preprocessor(string const &file, expr::parser const &expr); |
| 102 | + |
| 103 | + iterator begin(void); |
| 104 | + const_iterator begin(void) const; |
| 105 | + iterator end(void); |
| 106 | + const_iterator end(void) const; |
| 107 | + |
| 108 | +private: |
| 109 | + template<typename iterT> |
| 110 | + void process(iterT begin, iterT end); |
| 111 | + |
| 112 | + template<typename iterT> |
| 113 | + bool evaluate_expr(iterT begin, iterT end, bool ignoring); |
| 114 | + |
| 115 | + template<typename iterT> |
| 116 | + bool itercmp(iterT begin, iterT end, char const *s); |
| 117 | + |
| 118 | + vector<char> _data; |
| 119 | + string _curfile; |
| 120 | + int _curline; |
| 121 | + int _curpos; |
| 122 | + iterator _end; |
| 123 | + expr::parser const & |
| 124 | + _expr; |
| 125 | +}; |
| 126 | + |
| 127 | + |
| 128 | +#endif /* PREPROCESSOR_H */ |
Property changes on: trunk/willow/src/include/preprocessor.h |
___________________________________________________________________ |
Added: svn:keywords |
1 | 129 | + Id Revision |
Index: trunk/willow/src/willow/parser.y |
— | — | @@ -1,558 +0,0 @@ |
2 | | -/* Willow: Lightweight HTTP reverse-proxy. */ |
3 | | -/* Copyright (c) 2005, 2006 River Tarnell <river@attenuate.org>. */ |
4 | | -/* |
5 | | - * Permission is granted to anyone to use this software for any purpose, |
6 | | - * including commercial applications, and to alter it and redistribute it |
7 | | - * freely. This software is provided 'as-is', without any express or implied |
8 | | - * warranty. |
9 | | - */ |
10 | | - |
11 | | -/* From: $Nightmare: nightmare/src/main/parser.y,v 1.2.2.1.2.1 2002/07/02 03:42:10 ejb Exp $ */ |
12 | | -/* $Id$ */ |
13 | | - |
14 | | -%{ |
15 | | -#include <sys/types.h> |
16 | | -#include <sys/stat.h> |
17 | | - |
18 | | -#include <netinet/in.h> |
19 | | -#include <arpa/inet.h> |
20 | | -#include <netdb.h> |
21 | | - |
22 | | -#include <vector> |
23 | | -#include <cstdlib> |
24 | | -#include <cstdarg> |
25 | | -#include <cstdio> |
26 | | -using std::vector; |
27 | | -using std::sprintf; |
28 | | - |
29 | | -#define NEED_PARSING_TREE |
30 | | -#include "willow.h" |
31 | | -#include "confparse.h" |
32 | | - |
33 | | -/* |
34 | | - * Certain bison/gcc combinations result in compilation errors in gcc-specific |
35 | | - * code. Work around this by undefining here. |
36 | | - */ |
37 | | -#undef __GNUC_MINOR__ |
38 | | - |
39 | | -#define YY_NO_UNPUT |
40 | | - |
41 | | -/* icc emits these with -w2 */ |
42 | | -#ifdef __INTEL_COMPILER |
43 | | -# pragma warning (disable : 193) |
44 | | -#endif |
45 | | - |
46 | | -static time_t conf_find_time(string const &); |
47 | | - |
48 | | -static struct { |
49 | | - const char * name; |
50 | | - const char * plural; |
51 | | - time_t val; |
52 | | -} conf_times[] = { |
53 | | - {"second", "seconds", 1}, |
54 | | - {"minute", "minutes", 60}, |
55 | | - {"hour", "hours", 60 * 60}, |
56 | | - {"day", "days", 60 * 60 * 24}, |
57 | | - {"week", "weeks", 60 * 60 * 24 * 7}, |
58 | | - {"fortnight", "fortnights", 60 * 60 * 24 * 14}, |
59 | | - {"month", "months", 60 * 60 * 24 * 7 * 4}, |
60 | | - {"year", "years", 60 * 60 * 24 * 365}, |
61 | | - /* ok-- we now do sizes here too. they aren't times, but |
62 | | - it's close enough */ |
63 | | - {"byte", "bytes", 1}, |
64 | | - {"kb", NULL, 1024}, |
65 | | - {"kbyte", "kbytes", 1024}, |
66 | | - {"kilobyte", "kilebytes", 1024}, |
67 | | - {"mb", NULL, 1024 * 1024}, |
68 | | - {"mbyte", "mbytes", 1024 * 1024}, |
69 | | - {"megabyte", "megabytes", 1024 * 1024}, |
70 | | - {NULL, NULL, 0}, |
71 | | -}; |
72 | | - |
73 | | -time_t conf_find_time(string const &name) |
74 | | -{ |
75 | | - int i; |
76 | | - |
77 | | - for (i = 0; conf_times[i].name; i++) |
78 | | - { |
79 | | - if (!strcasecmp(conf_times[i].name, name.c_str()) || |
80 | | - (conf_times[i].plural && !strcasecmp(conf_times[i].plural, name.c_str()))) |
81 | | - return conf_times[i].val; |
82 | | - } |
83 | | - |
84 | | - return 0; |
85 | | -} |
86 | | - |
87 | | -/*ARGSUSED*/ |
88 | | -static conf::value * |
89 | | -f_hostname(vector<conf::avalue> *) |
90 | | -{ |
91 | | -#ifndef HOST_NAME_MAX |
92 | | -# define HOST_NAME_MAX 255 /* SUSv2 */ |
93 | | -#endif |
94 | | -char host[HOST_NAME_MAX] = { 0 }; |
95 | | -conf::value *ret; |
96 | | -conf::avalue aval; |
97 | | - gethostname(host, sizeof(host)); |
98 | | - ret = new conf::value(conf::declpos::here()); |
99 | | - aval.av_type = conf::cv_qstring; |
100 | | - aval.av_strval = host; |
101 | | - ret->cv_values.push_back(aval); |
102 | | - return ret; |
103 | | -} |
104 | | - |
105 | | -static conf::value * |
106 | | -f_dns(vector<conf::avalue> *args) |
107 | | -{ |
108 | | -struct addrinfo *res, hints; |
109 | | -string aftype; |
110 | | -conf::value *ret; |
111 | | -int i; |
112 | | -conf::avalue aval; |
113 | | -char tmp[64]; |
114 | | - ret = new conf::value(conf::declpos::here()); |
115 | | - aftype = (*args)[0].av_strval.c_str(); |
116 | | - memset(&hints, 0, sizeof(hints)); |
117 | | - if (aftype == "ipv4") |
118 | | - hints.ai_family = AF_INET; |
119 | | - else if (aftype == "ipv6") |
120 | | - hints.ai_family = AF_INET6; |
121 | | - else { |
122 | | - return ret; |
123 | | - } |
124 | | - if ((i = getaddrinfo((*args)[0].av_strval.c_str(), "80", &hints, &res)) != 0) { |
125 | | - conf::report_parse_error("getaddrinfo(%s): %s", |
126 | | - (*args)[0].av_strval.c_str(), gai_strerror(i)); |
127 | | - return ret; |
128 | | - } |
129 | | - |
130 | | - /* format the address as an IP */ |
131 | | - aval.av_type = conf::cv_qstring; |
132 | | - inet_ntop(res->ai_family, res->ai_addr->sa_data, tmp, sizeof(tmp)); |
133 | | - aval.av_strval = tmp; |
134 | | - ret->cv_values.push_back(aval); |
135 | | - freeaddrinfo(res); |
136 | | - return ret; |
137 | | -} |
138 | | - |
139 | | -typedef struct function_stru { |
140 | | - const char *name; |
141 | | - conf::value *(*execute)(vector<conf::avalue> *args); |
142 | | - int args[3]; /* XXX */ |
143 | | -} function_t; |
144 | | - |
145 | | -static function_t functions[] = { |
146 | | - { "hostname", f_hostname, { 0, 0, 0 } }, |
147 | | - { "dns", f_dns, { conf::cv_qstring, conf::cv_string, 0 } }, |
148 | | - { NULL, NULL, { } } |
149 | | -}; |
150 | | - |
151 | | -static int |
152 | | -match_func_parms(function_t *f, vector<conf::avalue> *args) |
153 | | -{ |
154 | | -size_t i; |
155 | | -vector<conf::avalue>::const_iterator it, end; |
156 | | - it = args->begin(); |
157 | | - end = args->end(); |
158 | | - for (i = 0; f->args[i]; ++i) { |
159 | | - if (i+1 > args->size()) { |
160 | | - conf::report_parse_error("not enough arguments to function '%s' (got %d)", |
161 | | - f->name, i+1); |
162 | | - return 0; |
163 | | - } |
164 | | - if (f->args[i] != (it)->av_type) { |
165 | | - conf::report_parse_error("wrong type %d for argument %d to '%s' (expected %d)", |
166 | | - (it)->av_type, i + 1, f->name, f->args[i]); |
167 | | - return 0; |
168 | | - } |
169 | | - it++; |
170 | | - } |
171 | | - if (args->size() > i) { |
172 | | - conf::report_parse_error("too many arguments to function '%s'", f->name); |
173 | | - return 0; |
174 | | - } |
175 | | - return 1; |
176 | | -} |
177 | | - |
178 | | -static function_t* |
179 | | -find_function(string const &name, vector<conf::avalue> *args) |
180 | | -{ |
181 | | -function_t *f; |
182 | | - for (f = functions; f->name; ++f) |
183 | | - if (f->name == name) |
184 | | - { |
185 | | - if (match_func_parms(f, args)) |
186 | | - return f; |
187 | | - else |
188 | | - break; |
189 | | - } |
190 | | - return NULL; |
191 | | -} |
192 | | - |
193 | | -static struct |
194 | | -{ |
195 | | - const char *word; |
196 | | - int yesno; |
197 | | -} yesno[] = { |
198 | | - {"yes", 1}, |
199 | | - {"no", 0}, |
200 | | - {"true", 1}, |
201 | | - {"false", 0}, |
202 | | - {"on", 1}, |
203 | | - {"off", 0}, |
204 | | - {NULL, 0} |
205 | | -}; |
206 | | - |
207 | | -static int |
208 | | -conf_get_yesno_value(string const &str) |
209 | | -{ |
210 | | -int i; |
211 | | - for (i = 0; yesno[i].word; i++) |
212 | | - if (str == yesno[i].word) |
213 | | - return yesno[i].yesno; |
214 | | - |
215 | | - return -1; |
216 | | -} |
217 | | - |
218 | | -%} |
219 | | - |
220 | | -%union { |
221 | | - long number; |
222 | | - string *string_; |
223 | | - conf::avalue *avalue; |
224 | | - conf::value *value; |
225 | | - vector<conf::value> *value_list; |
226 | | - vector<conf::avalue> *avalue_list; |
227 | | - bool bool_; |
228 | | -} |
229 | | - |
230 | | -%token TWODOTS VAR TEMPLATE FROM |
231 | | - |
232 | | -%token <string_> QSTRING STRING VARNAME |
233 | | -%token <number> NUMBER |
234 | | - |
235 | | -%type <string_> qstring string varname astring from_clause key_clause |
236 | | -%type <number> number timespec |
237 | | -%type <avalue> oneitem |
238 | | -%type <avalue_list> single |
239 | | -%type <avalue_list> itemlist |
240 | | -%type <value_list> block_items optional_block |
241 | | -%type <value> block_item |
242 | | -%type <bool_> template_clause |
243 | | -%type <avalue_list> func_args |
244 | | -%type <value> function |
245 | | - |
246 | | -%left '+' |
247 | | -%nonassoc poneitem |
248 | | -%nonassoc ptimespec |
249 | | -%start conf |
250 | | - |
251 | | -%% |
252 | | - |
253 | | -conf: | items |
254 | | - |
255 | | -items: conf_item |
256 | | - | items conf_item |
257 | | - ; |
258 | | - |
259 | | -conf_item: block |
260 | | - ; |
261 | | - |
262 | | -from_clause: |
263 | | - { $$ = NULL; } |
264 | | - | FROM astring { |
265 | | - $$ = $2; |
266 | | - } |
267 | | - ; |
268 | | -key_clause: |
269 | | - { $$ = NULL; } |
270 | | - | astring { |
271 | | - $$ = $1; |
272 | | - } |
273 | | - ; |
274 | | - |
275 | | -template_clause: |
276 | | - { $$ = 0; } |
277 | | - | TEMPLATE { $$ = 1; } |
278 | | - ; |
279 | | - |
280 | | -semicolon: |
281 | | - ';' |
282 | | - | { conf::report_parse_error("expected ';'"); } |
283 | | - ; |
284 | | - |
285 | | -equals: |
286 | | - '=' |
287 | | - | { conf::report_parse_error("expected '='"); } |
288 | | - ; |
289 | | - |
290 | | -func_args: |
291 | | - { $$ = new vector<conf::avalue>; } |
292 | | - | itemlist { |
293 | | - $$ = $1; |
294 | | - delete $1; |
295 | | - } |
296 | | - ; |
297 | | - |
298 | | -function: |
299 | | - string '(' func_args ')' |
300 | | - { |
301 | | - function_t *func; |
302 | | - if ((func = find_function(*$1, $3)) == NULL) { |
303 | | - conf::report_parse_error("undefined function %s", $1); |
304 | | - $$ = new conf::value(conf::declpos::here()); |
305 | | - } else { |
306 | | - $$ = func->execute($3); |
307 | | - } |
308 | | - delete $1; |
309 | | - } |
310 | | - ; |
311 | | - |
312 | | -optional_block: |
313 | | - { |
314 | | - $$ = NULL; |
315 | | - } |
316 | | - | '{' block_items '}' |
317 | | - { |
318 | | - $$ = $2; |
319 | | - } |
320 | | - ; |
321 | | - |
322 | | -block: template_clause string key_clause from_clause optional_block semicolon |
323 | | - { |
324 | | - const char *block_key; |
325 | | - char nname[10]; |
326 | | - static int nseq; |
327 | | - bool unnamed = false; |
328 | | - conf::tree_entry *e; |
329 | | - vector<conf::value>::const_iterator it, end; |
330 | | - if ($3) |
331 | | - block_key = $3->c_str(); |
332 | | - else { |
333 | | - sprintf(nname, "__%d", nseq++); |
334 | | - block_key = nname; |
335 | | - unnamed = true; |
336 | | - } |
337 | | - if ($4) { |
338 | | - if ((e = conf::new_tree_entry_from_template(conf::parsing_tree, *$2, block_key, *$4, |
339 | | - conf::declpos::here(), unnamed, $1)) == NULL) { |
340 | | - conf::report_parse_error("template block \"%s\" not found", $4); |
341 | | - goto end; |
342 | | - } |
343 | | - } else { |
344 | | -#if 0 |
345 | | - if ((e = conf::parsing_tree.find(*$2, block_key)) != NULL) { |
346 | | - conf::report_parse_error("%s \"%s\" already defined at %s", |
347 | | - $2->c_str(), block_key, e->item_pos.format().c_str()); |
348 | | - goto end; |
349 | | - } |
350 | | -#endif |
351 | | - e = conf::parsing_tree.create(*$2, block_key, conf::declpos::here(), unnamed, $1); |
352 | | - } |
353 | | - |
354 | | - if ($5) for (it = $5->begin(), end = $5->end(); it != end; ++it) { |
355 | | - e->add(*it); |
356 | | - } |
357 | | - end: |
358 | | - delete $2; |
359 | | - delete $3; |
360 | | - delete $4; |
361 | | - delete $5; |
362 | | - } |
363 | | - | VAR varname equals itemlist semicolon |
364 | | - { |
365 | | - conf::value *value; |
366 | | - value = new conf::value(conf::declpos::here()); |
367 | | - value->cv_name = $2->substr(1); |
368 | | - value->cv_values = *$4; |
369 | | - conf::add_variable(value); |
370 | | - delete $4; |
371 | | - } |
372 | | - | error |
373 | | - ; |
374 | | - |
375 | | -block_items: |
376 | | - block_items block_item |
377 | | - { |
378 | | - $$ = new vector<conf::value>($1->begin(), $1->end()); |
379 | | - $$->push_back(*$2); |
380 | | - delete $1; |
381 | | - delete $2; |
382 | | - } |
383 | | - | block_item |
384 | | - { |
385 | | - $$ = new vector<conf::value>; |
386 | | - $$->push_back(*$1); |
387 | | - delete $1; |
388 | | - } |
389 | | - ; |
390 | | - |
391 | | -block_item: |
392 | | - string equals itemlist semicolon |
393 | | - { |
394 | | - $$ = new conf::value(conf::declpos::here()); |
395 | | - $$->cv_name = *$1; |
396 | | - $$->cv_values = *$3; |
397 | | - delete $1; |
398 | | - delete $3; |
399 | | - } |
400 | | - ; |
401 | | - |
402 | | -/* |
403 | | - * "single" is a list of items. |
404 | | - */ |
405 | | -itemlist: itemlist ',' single |
406 | | - { |
407 | | - $$ = $1; |
408 | | - $$->insert($$->end(), $3->begin(), $3->end()); |
409 | | - delete $3; |
410 | | - } |
411 | | - | single |
412 | | - { |
413 | | - $$ = new vector<conf::avalue>; |
414 | | - $$->insert($$->end(), $1->begin(), $1->end()); |
415 | | - delete $1; |
416 | | - } |
417 | | - ; |
418 | | - |
419 | | -single: oneitem |
420 | | - { |
421 | | - $$ = new vector<conf::avalue>; |
422 | | - $$->push_back(*$1); |
423 | | - delete $1; |
424 | | - } |
425 | | - | oneitem TWODOTS oneitem |
426 | | - { |
427 | | - $$ = new vector<conf::avalue>; |
428 | | - /* "1 .. 5" meaning 1,2,3,4,5 - only valid for integers */ |
429 | | - if ($1->av_type != conf::cv_int || $3->av_type != conf::cv_int) { |
430 | | - conf::report_parse_error("both arguments in '..' notation must be integers."); |
431 | | - break; |
432 | | - } else { |
433 | | - int i; |
434 | | - conf::avalue val; |
435 | | - for (i = $1->av_intval; i <= $3->av_intval; i++) { |
436 | | - val.av_type = conf::cv_int; |
437 | | - val.av_intval = i; |
438 | | - $$->push_back(val); |
439 | | - } |
440 | | - } |
441 | | - delete $1; |
442 | | - delete $3; |
443 | | - } |
444 | | - | varname |
445 | | - { |
446 | | - string varname_; |
447 | | - conf::value *value; |
448 | | - $$ = new vector<conf::avalue>; |
449 | | - varname_ = $1->substr(1); |
450 | | - value = conf::value_from_variable("", varname_, conf::declpos::here()); |
451 | | - if (value == NULL) { |
452 | | - conf::report_parse_error("undefined variable %s", varname_.c_str()); |
453 | | - } else { |
454 | | - $$->insert($$->begin(), value->cv_values.begin(), value->cv_values.end()); |
455 | | - } |
456 | | - delete $1; |
457 | | - } |
458 | | - | single '+' single |
459 | | - { |
460 | | - int flen, slen; |
461 | | - flen = $1->size(); |
462 | | - slen = $3->size(); |
463 | | - if (flen == 1 && slen == 1) { |
464 | | - conf::avalue n; |
465 | | - n.av_type = conf::cv_qstring; |
466 | | - n.av_strval = (*$1)[0].av_strval + (*$3)[0].av_strval; |
467 | | - $$->push_back(n); |
468 | | - } else { |
469 | | - conf::report_parse_error("do not know how to add these values (%d+%d)", flen, slen); |
470 | | - } |
471 | | - delete $1; |
472 | | - delete $3; |
473 | | - } |
474 | | - ; |
475 | | - |
476 | | -oneitem: astring |
477 | | - { |
478 | | - $$ = new conf::avalue; |
479 | | - $$->av_type = conf::cv_qstring; |
480 | | - $$->av_strval = *$1; |
481 | | - delete $1; |
482 | | - } |
483 | | - | timespec |
484 | | - { |
485 | | - $$ = new conf::avalue; |
486 | | - $$->av_type = conf::cv_time; |
487 | | - $$->av_intval = $1; |
488 | | - } |
489 | | - | number |
490 | | - { |
491 | | - $$ = new conf::avalue; |
492 | | - $$->av_type = conf::cv_int; |
493 | | - $$->av_intval = $1; |
494 | | - } |
495 | | - | string |
496 | | - { |
497 | | - /* a 'string' could also be a yes/no value .. |
498 | | - so pass it as that, if so */ |
499 | | - int val = conf_get_yesno_value(*$1); |
500 | | - |
501 | | - $$ = new conf::avalue; |
502 | | - |
503 | | - if (val != -1) { |
504 | | - $$->av_type = conf::cv_yesno; |
505 | | - $$->av_intval = val; |
506 | | - } else { |
507 | | - $$->av_type = conf::cv_string; |
508 | | - $$->av_strval = *$1; |
509 | | - } |
510 | | - delete $1; |
511 | | - } |
512 | | - ; |
513 | | - |
514 | | -astring: |
515 | | - qstring { |
516 | | - $$ = $1; |
517 | | - } |
518 | | - | function { |
519 | | - conf::value *value; |
520 | | - value = $1; |
521 | | - if (!value->is_single(conf::cv_qstring)) { |
522 | | - value->report_error("function in concatenation must return quoted string"); |
523 | | - $$ = new string(""); |
524 | | - } else { |
525 | | - $$ = new string($1->cv_values[0].av_strval); |
526 | | - } |
527 | | - delete $1; |
528 | | - } |
529 | | - ; |
530 | | - |
531 | | -qstring: |
532 | | - QSTRING { |
533 | | - $$ = $1; |
534 | | - } |
535 | | - | QSTRING QSTRING { |
536 | | - $$ = new string (*$1 + *$2); |
537 | | - delete $1; |
538 | | - delete $2; |
539 | | - } |
540 | | - ; |
541 | | -string: STRING { $$ = $1; } ; |
542 | | -number: NUMBER { $$ = $1; } ; |
543 | | -varname: VARNAME { $$ = $1; } ; |
544 | | - |
545 | | -timespec: number string |
546 | | - { |
547 | | - time_t t; |
548 | | - if ((t = conf_find_time(*$2)) == 0) { |
549 | | - conf::report_parse_error("unrecognised time type/size \"%s\"", $2->c_str()); |
550 | | - t = 1; |
551 | | - } |
552 | | - delete $2; |
553 | | - $$ = $1 * t; |
554 | | - } |
555 | | - | timespec timespec |
556 | | - { |
557 | | - $$ = $1 + $2; |
558 | | - } |
559 | | - ; |
Index: trunk/willow/src/willow/lexer.l |
— | — | @@ -1,177 +0,0 @@ |
2 | | -/* Willow: Lightweight HTTP reverse-proxy. */ |
3 | | -/* lexer: config lexer */ |
4 | | -/* Copyright (c) 2005, 2006 River Tarnell <river@attenuate.org>. */ |
5 | | -/* |
6 | | - * Permission is granted to anyone to use this software for any purpose, |
7 | | - * including commercial applications, and to alter it and redistribute it |
8 | | - * freely. This software is provided 'as-is', without any express or implied |
9 | | - * warranty. |
10 | | - */ |
11 | | - |
12 | | -/* $Id$ */ |
13 | | - |
14 | | -%option noyywrap |
15 | | -%option nounput |
16 | | - |
17 | | -%{ |
18 | | -#include <iostream> |
19 | | -#include <string> |
20 | | -#include <cerrno> |
21 | | -#include <cstdio> |
22 | | - |
23 | | -using std::strerror; |
24 | | -using std::fopen; |
25 | | - |
26 | | -#include "confparse.h" |
27 | | -#include "y.tab.h" |
28 | | -#include "willow.h" |
29 | | - |
30 | | -struct func_attrs; |
31 | | - |
32 | | -int yylex(void); |
33 | | - |
34 | | -#define MAXINCLUDE 10 |
35 | | -struct statestack_stru { |
36 | | - YY_BUFFER_STATE state; |
37 | | - string file; |
38 | | - int lineno; |
39 | | -} statestack[MAXINCLUDE + 1]; |
40 | | -int inclevel; |
41 | | -static bool in_if; |
42 | | - |
43 | | -#undef YY_INPUT |
44 | | - |
45 | | -#define YY_FATAL_ERROR(msg) conf::catastrophic_error(msg) |
46 | | - |
47 | | -%} |
48 | | - |
49 | | -ws [ \t]* |
50 | | -space [ \t]{ws} |
51 | | -digit [0-9] |
52 | | -number {digit}{digit}* |
53 | | -qstring \"[^\"\n]*[\"\n] |
54 | | -string [a-zA-Z_][a-zA-Z0-9_-]* |
55 | | -include %{ws}include{space}(\<.*\>|\".*\") |
56 | | -pragma %{ws}pragma{space}.*$ |
57 | | -if %{ws}if{space}.*$ |
58 | | -else %{ws}else{ws}$ |
59 | | -endif %{ws}endif{ws}$ |
60 | | -define %{ws}define{space}{string}{space}.*$ |
61 | | -ifdef %{ws}ifdef{space}{string}{ws}$ |
62 | | -ifndef %{ws}ifndef{space}{string}{ws}$ |
63 | | - |
64 | | -%x COMMENT IGNORING |
65 | | -%% |
66 | | - |
67 | | -^.* { |
68 | | - conf::linebuf.assign(yytext, yyleng); |
69 | | - conf::curpos = 0; |
70 | | - yyless(0); |
71 | | - } |
72 | | -<IGNORING>{if} { conf::report_parse_error("%%if may not be nested"); } |
73 | | -<IGNORING>{endif} { BEGIN 0; } |
74 | | -<IGNORING>{else} { in_if = true; BEGIN 0; } |
75 | | -<IGNORING>. ; |
76 | | -<IGNORING>\n { conf::lineno++; } |
77 | | - |
78 | | -"/*" { BEGIN COMMENT; } |
79 | | -<COMMENT>\*\/ { BEGIN 0; } |
80 | | -<COMMENT>. ; |
81 | | -<COMMENT>\n { conf::lineno++; conf::curpos = 0; } |
82 | | -\/\/.*$ ; |
83 | | -#.*$ ; |
84 | | -\n conf::lineno++; |
85 | | -{pragma} { conf::handle_pragma(yytext); } |
86 | | -{if} { if (!conf::if_true(yytext)) |
87 | | - BEGIN IGNORING; |
88 | | - else |
89 | | - in_if = true; |
90 | | - } |
91 | | -{define} { conf::define_if(yytext + 8); } |
92 | | -{ifdef} { if (conf::if_defined(yytext + 6)) |
93 | | - in_if = true; |
94 | | - else |
95 | | - BEGIN IGNORING; |
96 | | - } |
97 | | -{ifndef} { if (conf::if_defined(yytext + 7)) |
98 | | - BEGIN IGNORING; |
99 | | - else |
100 | | - in_if = true; |
101 | | - } |
102 | | -{else} { if (in_if) |
103 | | - BEGIN IGNORING; |
104 | | - else |
105 | | - conf::report_parse_error("%%else without %%if"); |
106 | | - } |
107 | | -{endif} { if (in_if) |
108 | | - in_if = false; |
109 | | - else |
110 | | - conf::report_parse_error("%%endif without %%if"); |
111 | | - } |
112 | | -{include} { |
113 | | - FILE *f; |
114 | | - char *s, *t, c; |
115 | | - string file, path; |
116 | | - s = yytext + yyleng - 1; |
117 | | - c = *s; |
118 | | - t = s - 1; |
119 | | - while (*t != c) |
120 | | - t--; |
121 | | - file.assign(t + 1, s); |
122 | | - if (conf::find_include(file) == false) { |
123 | | - conf::catastrophic_error("cannot locate include file"); |
124 | | - } else if ((f = fopen(file.c_str(), "r")) == NULL) { |
125 | | - string error = "cannot open include: "; |
126 | | - error += file; error += " "; |
127 | | - error += strerror(errno); |
128 | | - conf::catastrophic_error(error.c_str()); |
129 | | - } else { |
130 | | - if (inclevel + 1 == MAXINCLUDE) { |
131 | | - conf::catastrophic_error("maximum include depth reached"); |
132 | | - } else { |
133 | | - statestack[inclevel].state = YY_CURRENT_BUFFER; |
134 | | - statestack[inclevel].lineno = conf::lineno; |
135 | | - statestack[inclevel].file = conf::current_file; |
136 | | - inclevel++; |
137 | | - statestack[inclevel].state = yy_create_buffer(f, YY_BUF_SIZE); |
138 | | - conf::current_file = file; |
139 | | - conf::lineno = 1; |
140 | | - yy_switch_to_buffer(statestack[inclevel].state); |
141 | | - } |
142 | | - } |
143 | | - } |
144 | | -<<EOF>> { |
145 | | - if (inclevel) { |
146 | | - yy_delete_buffer(statestack[inclevel].state); |
147 | | - yy_switch_to_buffer(statestack[inclevel - 1].state); |
148 | | - inclevel--; |
149 | | - conf::current_file = statestack[inclevel].file; |
150 | | - conf::lineno = statestack[inclevel].lineno; |
151 | | - } else |
152 | | - yyterminate(); |
153 | | - } |
154 | | - |
155 | | -\t { conf::curpos += 8; } |
156 | | -{ws} { conf::curpos += yyleng; } |
157 | | -var { conf::curpos += yyleng; return VAR; } |
158 | | -template { conf::curpos += yyleng; return TEMPLATE; } |
159 | | -from { conf::curpos += yyleng; return FROM; } |
160 | | -\.\. { conf::curpos += yyleng; return TWODOTS; } |
161 | | - |
162 | | -{qstring} { |
163 | | - yylval.string_ = new string(yytext + 1, yyleng - 2); |
164 | | - conf::curpos += yyleng; |
165 | | - return QSTRING; |
166 | | - } |
167 | | -{string} { |
168 | | - yylval.string_ = new string(yytext, yyleng); |
169 | | - conf::curpos += yyleng; |
170 | | - return STRING; |
171 | | - } |
172 | | -{number} { |
173 | | - yylval.number = strtol(yytext, NULL, 0); |
174 | | - conf::curpos += yyleng; |
175 | | - return NUMBER; |
176 | | - } |
177 | | -. { conf::curpos++; return yytext[0]; } |
178 | | -%% |
Index: trunk/willow/src/willow/confgrammar.cc |
— | — | @@ -0,0 +1,361 @@ |
| 2 | +/* Willow: Lightweight HTTP reverse-proxy. */ |
| 3 | +/* confgrammar: Spirit grammar for confparse */ |
| 4 | +/* Copyright (c) 2005, 2006 River Tarnell <river@attenuate.org>. */ |
| 5 | +/* |
| 6 | + * Permission is granted to anyone to use this software for any purpose, |
| 7 | + * including commercial applications, and to alter it and redistribute it |
| 8 | + * freely. This software is provided 'as-is', without any express or implied |
| 9 | + * warranty. |
| 10 | + */ |
| 11 | + |
| 12 | +/* $Id$ */ |
| 13 | + |
| 14 | +#include <iostream> |
| 15 | +#include <iterator> |
| 16 | +#include <string> |
| 17 | +#include <map> |
| 18 | +#include <exception> |
| 19 | + |
| 20 | +#include <boost/spirit.hpp> |
| 21 | +#include <boost/spirit/attribute.hpp> |
| 22 | +#include <boost/spirit/phoenix.hpp> |
| 23 | +#include <boost/spirit/phoenix/casts.hpp> |
| 24 | +#include <boost/spirit/phoenix/closures.hpp> |
| 25 | + |
| 26 | +#include <boost/variant.hpp> |
| 27 | +#include <boost/static_assert.hpp> |
| 28 | + |
| 29 | +#include <boost/mpl/vector_c.hpp> |
| 30 | +#include <boost/mpl/equal.hpp> |
| 31 | +#include <boost/mpl/plus.hpp> |
| 32 | +#include <boost/mpl/minus.hpp> |
| 33 | +#include <boost/mpl/transform.hpp> |
| 34 | +#include <boost/mpl/placeholders.hpp> |
| 35 | + |
| 36 | +#include "util.h" |
| 37 | +#include "willow.h" |
| 38 | +#include "confgrammar.h" |
| 39 | +#include "preprocessor.h" |
| 40 | + |
| 41 | +using std::random_access_iterator_tag; |
| 42 | +using std::pair; |
| 43 | +using std::make_pair; |
| 44 | + |
| 45 | +namespace mpl = boost::mpl; |
| 46 | +namespace mpp = boost::mpl::placeholders; |
| 47 | +namespace spirit = boost::spirit; |
| 48 | +using boost::variant; |
| 49 | +using spirit::grammar; |
| 50 | +using spirit::scanner; |
| 51 | +using spirit::chset; |
| 52 | +using spirit::c_escape_ch_p; |
| 53 | +using spirit::int_p; |
| 54 | +using spirit::rule; |
| 55 | +using spirit::ch_p; |
| 56 | +using spirit::confix_p; |
| 57 | +using spirit::file_iterator; |
| 58 | +using spirit::parse_info; |
| 59 | +using spirit::comment_p; |
| 60 | +using spirit::str_p; |
| 61 | +using spirit::assertion; |
| 62 | +using spirit::guard; |
| 63 | +using spirit::error_status; |
| 64 | +using spirit::lexeme_d; |
| 65 | +using spirit::as_lower_d; |
| 66 | +using spirit::symbols; |
| 67 | +using phoenix::var; |
| 68 | +using phoenix::arg1; |
| 69 | +using phoenix::arg2; |
| 70 | +using phoenix::construct_; |
| 71 | + |
| 72 | +struct block_closure : spirit::closure<block_closure, |
| 73 | + string, string, vector<value_t> > { |
| 74 | + member1 name; |
| 75 | + member2 key; |
| 76 | + member3 values; |
| 77 | +}; |
| 78 | + |
| 79 | +struct file_closure : spirit::closure<file_closure, vector<block> > { |
| 80 | + member1 blocks; |
| 81 | +}; |
| 82 | + |
| 83 | +struct value_closure : spirit::closure< |
| 84 | + value_closure, |
| 85 | + string, |
| 86 | + vector<avalue_t> |
| 87 | + > { |
| 88 | + member1 name; |
| 89 | + member2 values; |
| 90 | +}; |
| 91 | + |
| 92 | +struct avalue_closure : spirit::closure< |
| 93 | + avalue_closure, |
| 94 | + avalue_t |
| 95 | + > { |
| 96 | + member1 value; |
| 97 | +}; |
| 98 | + |
| 99 | +struct expr_closure : spirit::closure<expr_closure, int> { |
| 100 | + member1 val; |
| 101 | +}; |
| 102 | + |
| 103 | +struct size_closure : spirit::closure<size_closure, size_q, scalar_q> { |
| 104 | + member1 value; |
| 105 | + member2 multiplier; |
| 106 | +}; |
| 107 | + |
| 108 | +struct time_closure : spirit::closure<time_closure, time_q, scalar_q> { |
| 109 | + member1 value; |
| 110 | + member2 multiplier; |
| 111 | +}; |
| 112 | + |
| 113 | +struct sizev_closure : spirit::closure<sizev_closure, size_q> { |
| 114 | + member1 val; |
| 115 | +}; |
| 116 | + |
| 117 | +struct timev_closure : spirit::closure<timev_closure, time_q> { |
| 118 | + member1 val; |
| 119 | +}; |
| 120 | + |
| 121 | +enum errors { |
| 122 | + semicolon_expected, |
| 123 | + equals_expected, |
| 124 | + close_brace_expected, |
| 125 | + open_brace_expected |
| 126 | +}; |
| 127 | + |
| 128 | +struct error_handler { |
| 129 | + template<typename ScannerT, typename ErrorT> |
| 130 | + error_status<> operator()(ScannerT const &scan, ErrorT const &err) const { |
| 131 | + file_position pos = err.where.get_position(); |
| 132 | + string errtxt; |
| 133 | + |
| 134 | + switch (err.descriptor) { |
| 135 | + case semicolon_expected: |
| 136 | + errtxt = "expected semicolon"; |
| 137 | + break; |
| 138 | + case equals_expected: |
| 139 | + errtxt = "expected '='"; |
| 140 | + break; |
| 141 | + case close_brace_expected: |
| 142 | + errtxt = "expected '}'"; |
| 143 | + break; |
| 144 | + case open_brace_expected: |
| 145 | + errtxt = "expected '{'"; |
| 146 | + break; |
| 147 | + } |
| 148 | + |
| 149 | + wlog.error(format("%s(%d): %s") % pos.file % pos.line % errtxt); |
| 150 | + wlog.error('\t' + err.where.get_line(pos.line)); |
| 151 | + wlog.error(format("\t%s^") % string(pos.col - 1, ' ')); |
| 152 | + |
| 153 | + while (*scan.first != ';') |
| 154 | + ++scan.first; |
| 155 | + |
| 156 | + ++scan.first; |
| 157 | + |
| 158 | + return error_status<>(error_status<>::fail); |
| 159 | + } |
| 160 | +}; |
| 161 | + |
| 162 | +struct conf_parser_impl : public grammar<conf_parser_impl, file_closure::context_t> { |
| 163 | + struct comment_parser { |
| 164 | + comment_parser() { |
| 165 | + comment = comment_p("/*", "*/") | comment_p("#"); |
| 166 | +BOOST_SPIRIT_DEBUG_RULE(comment); |
| 167 | + } |
| 168 | + |
| 169 | + rule<> const &start(void) const { |
| 170 | + return comment; |
| 171 | + } |
| 172 | + |
| 173 | + rule<> comment; |
| 174 | + }; |
| 175 | + |
| 176 | + symbols<int> times; |
| 177 | + symbols<int> sizes; |
| 178 | + |
| 179 | + conf_parser_impl() { |
| 180 | + times.add("second", 1); |
| 181 | + times.add("minute", 60); |
| 182 | + times.add("hour", 60 * 60); |
| 183 | + times.add("day", 60 * 60 * 24); |
| 184 | + times.add("week", 60 * 60 * 24 * 7); |
| 185 | + times.add("fortnight", 60 * 60 * 24 * 7 * 2); |
| 186 | + |
| 187 | + sizes.add("byte", 1); |
| 188 | + |
| 189 | + sizes.add("kilobyte", 1024); |
| 190 | + sizes.add("megabyte", 1024 * 1024); |
| 191 | + sizes.add("gigabyte", 1024 * 1024 * 1024); |
| 192 | + |
| 193 | + sizes.add("kbyte", 1024); |
| 194 | + sizes.add("mbyte", 1024 * 1024); |
| 195 | + sizes.add("gbyte", 1024 * 1024 * 1024); |
| 196 | + |
| 197 | + sizes.add("kb", 1024); |
| 198 | + sizes.add("mb", 1024 * 1024); |
| 199 | + sizes.add("gb", 1024 * 1024 * 1024); |
| 200 | + } |
| 201 | + |
| 202 | + template<typename scanner> |
| 203 | + struct definition { |
| 204 | + rule<scanner> const &start(void) const { |
| 205 | + return file; |
| 206 | + } |
| 207 | + |
| 208 | + assertion<errors> expect_semicolon; |
| 209 | + assertion<errors> expect_close_brace; |
| 210 | + assertion<errors> expect_equals; |
| 211 | + assertion<errors> expect_open_brace; |
| 212 | + |
| 213 | + struct push_back_impl { |
| 214 | + template<typename C, typename I> |
| 215 | + struct result { |
| 216 | + typedef void type; |
| 217 | + }; |
| 218 | + |
| 219 | + template<typename C, typename I> |
| 220 | + void operator() (C &c, I const &i) const { |
| 221 | + c.push_back(i); |
| 222 | + } |
| 223 | + }; |
| 224 | + |
| 225 | + rule<scanner> tstring, qstring, semicolon, equals, |
| 226 | + close_brace, open_brace; |
| 227 | + rule<scanner> file, require_value; |
| 228 | + rule<scanner, time_closure::context_t> time_m, atime; |
| 229 | + rule<scanner, size_closure::context_t> size_m, asize; |
| 230 | + rule<scanner, timev_closure::context_t> time; |
| 231 | + rule<scanner, sizev_closure::context_t> size; |
| 232 | + rule<scanner, value_closure::context_t> value; |
| 233 | + rule<scanner, block_closure::context_t> block; |
| 234 | + rule<scanner, avalue_closure::context_t> avalue; |
| 235 | + |
| 236 | + error_handler err; |
| 237 | + guard<errors> errguard; |
| 238 | + phoenix::function<push_back_impl> const push_back; |
| 239 | + |
| 240 | + definition(conf_parser_impl const &self) |
| 241 | + : expect_semicolon(semicolon_expected) |
| 242 | + , expect_close_brace(close_brace_expected) |
| 243 | + , expect_equals(equals_expected) |
| 244 | + , expect_open_brace(open_brace_expected) |
| 245 | + , push_back(push_back_impl()) |
| 246 | + { |
| 247 | +/* |
| 248 | + * Conf grammar definition. |
| 249 | + */ |
| 250 | +tstring = lexeme_d[chset<>("a-zA-Z_") >> *chset<>("a-zA-Z0-9_-")]; |
| 251 | +qstring = lexeme_d[confix_p('"', *c_escape_ch_p, '"')]; |
| 252 | +semicolon = expect_semicolon(ch_p(';')); |
| 253 | +equals = expect_equals(ch_p('=')); |
| 254 | +open_brace = expect_open_brace(ch_p('{')); |
| 255 | +close_brace = expect_close_brace(ch_p('}')); |
| 256 | + |
| 257 | +file = *block; |
| 258 | +require_value = value; |
| 259 | + |
| 260 | +block = (tstring[block.name = construct_<string>(arg1, arg2)] |
| 261 | + >> !confix_p('"', (*c_escape_ch_p)[block.key = construct_<string>(arg1, arg2)], '"') |
| 262 | + >> errguard(open_brace)[err] |
| 263 | + >> *errguard(require_value)[err] |
| 264 | + >> errguard(close_brace)[err] |
| 265 | + >> errguard(semicolon)[err])[push_back(self.blocks, |
| 266 | + construct_<struct block>(block.name, |
| 267 | + block.key, |
| 268 | + block.values))]; |
| 269 | + |
| 270 | +value = tstring [value.name = construct_<string>(arg1, arg2)] |
| 271 | + >> errguard(equals)[err] |
| 272 | + >> errguard(list_p(avalue, ','))[err] |
| 273 | + >> errguard(semicolon)[err] [push_back(block.values, |
| 274 | + construct_<value_t>(value.name, value.values))]; |
| 275 | + |
| 276 | +avalue = (size [push_back(value.values, avalue.value)]) |
| 277 | + | (time [push_back(value.values, avalue.value)]) |
| 278 | + | str_p("yes") [push_back(value.values, true)] |
| 279 | + | str_p("no") [push_back(value.values, false)] |
| 280 | + | int_p [push_back(value.values, arg1)] |
| 281 | + | tstring [push_back(value.values, construct_<u_string>(arg1, arg2))] |
| 282 | + | confix_p('"', (*c_escape_ch_p) |
| 283 | + [push_back(value.values, construct_<q_string>(arg1, arg2))], '"') |
| 284 | + ; |
| 285 | + |
| 286 | +/* size values: "30 megabytes" */ |
| 287 | +size = size_m[avalue.value = construct_<avalue_t>(size.val)]; |
| 288 | + |
| 289 | +asize = int_p[size_m.value = construct_<size_q>(arg1)] >> |
| 290 | + lexeme_d |
| 291 | + [ |
| 292 | + as_lower_d |
| 293 | + [ |
| 294 | + self.sizes[size_m.multiplier = construct_<scalar_q>(arg1)] |
| 295 | + ] |
| 296 | + >> !ch_p('s') |
| 297 | + ] |
| 298 | + ; |
| 299 | + |
| 300 | +size_m = +(asize [size.val += size_m.value * size_m.multiplier]); |
| 301 | + |
| 302 | +/* time values: "1 hour 30 seconds" */ |
| 303 | +time = time_m[avalue.value = construct_<avalue_t>(time.val)]; |
| 304 | + |
| 305 | +atime = int_p[time_m.value = construct_<time_q>(arg1)] >> |
| 306 | + lexeme_d |
| 307 | + [ |
| 308 | + as_lower_d |
| 309 | + [ |
| 310 | + self.times[time_m.multiplier = construct_<scalar_q>(arg1)] |
| 311 | + ] |
| 312 | + >> !ch_p('s') |
| 313 | + ]; |
| 314 | + |
| 315 | +time_m = +(atime [time.val += time_m.value * time_m.multiplier]); |
| 316 | + |
| 317 | +/**/ |
| 318 | + |
| 319 | +BOOST_SPIRIT_DEBUG_RULE(block); |
| 320 | +BOOST_SPIRIT_DEBUG_RULE(string); |
| 321 | +BOOST_SPIRIT_DEBUG_RULE(qstring); |
| 322 | +BOOST_SPIRIT_DEBUG_RULE(value); |
| 323 | +BOOST_SPIRIT_DEBUG_RULE(avalue); |
| 324 | +BOOST_SPIRIT_DEBUG_RULE(file); |
| 325 | +BOOST_SPIRIT_DEBUG_RULE(size); |
| 326 | +BOOST_SPIRIT_DEBUG_RULE(time); |
| 327 | + } |
| 328 | + }; |
| 329 | +}; |
| 330 | + |
| 331 | +confgrammar::confgrammar(expr::parser const &expr) |
| 332 | + : _expr(expr) |
| 333 | +{ |
| 334 | +} |
| 335 | + |
| 336 | +vector<block> |
| 337 | +confgrammar::parse(string const &file) |
| 338 | +{ |
| 339 | + typedef char char_t; |
| 340 | + typedef preprocessor::iterator iterator_t; |
| 341 | + typedef scanner<iterator_t> scanner_t; |
| 342 | + conf_parser_impl g; |
| 343 | + conf_parser_impl::comment_parser skip; |
| 344 | + |
| 345 | + vector<block> result; |
| 346 | + |
| 347 | + error_handler err; |
| 348 | + |
| 349 | + try { |
| 350 | + preprocessor p(file, _expr); |
| 351 | + |
| 352 | + parse_info<iterator_t> info = spirit::parse(p.begin(), p.end(), |
| 353 | + g[var(result) = arg1], |
| 354 | + comment_p("/*", "*/") | comment_p("#") | chset<>("\n\t ")); |
| 355 | + if (!info.full) |
| 356 | + throw parser_error("failed to parse configuration file"); |
| 357 | + } catch (exception &e) { |
| 358 | + throw parser_error(e.what()); |
| 359 | + } |
| 360 | + |
| 361 | + return result; |
| 362 | +} |
Property changes on: trunk/willow/src/willow/confgrammar.cc |
___________________________________________________________________ |
Added: svn:keywords |
1 | 363 | + Id Revision |
Index: trunk/willow/src/willow/Makefile.in |
— | — | @@ -21,6 +21,7 @@ |
22 | 22 | cachedir_data_store.cc \ |
23 | 23 | chunking.cc \ |
24 | 24 | config.cc \ |
| 25 | + confgrammar.cc \ |
25 | 26 | confparse.cc \ |
26 | 27 | dbwrap.cc \ |
27 | 28 | expr.cc \ |
— | — | @@ -32,36 +33,24 @@ |
33 | 34 | ifname_to_address.cc \ |
34 | 35 | log.cc \ |
35 | 36 | net.cc \ |
| 37 | + preprocessor.cc \ |
36 | 38 | radix.cc \ |
37 | 39 | willow.cc \ |
38 | 40 | |
39 | 41 | OBJS= $(BASESRCS:.cc=.o) |
40 | 42 | |
41 | 43 | SRCS=$(BASESRCS) |
42 | | -OBJADD = @LIBOBJS@ y.tab.o lex.yy.o |
| 44 | +OBJADD = @LIBOBJS@ |
43 | 45 | |
44 | 46 | EXTRA_DIST= strlcat.c strlcpy.c \ |
45 | | - lexer.l parser.y \ |
46 | 47 | daemon.c \ |
47 | 48 | Makefile.in |
48 | 49 | |
49 | 50 | LDFLAGS = $(LIBOBJS) -L../libwillow -lwillow |
50 | 51 | EXTRADEPS=../libwillow/libwillow.a |
51 | 52 | |
52 | | -.SUFFIXES: .y .l .c .cc .o |
| 53 | +.SUFFIXES: .c .cc .o |
53 | 54 | |
54 | 55 | default: all |
55 | 56 | |
56 | | -y.tab.o: y.tab.cc ../include/confparse.h ../include/willow.h |
57 | | -lex.yy.o: lex.yy.cc y.tab.h ../include/confparse.h ../include/willow.h |
58 | | - |
59 | | -y.tab.cc y.tab.h: parser.y |
60 | | - @echo " $(_YACC) -d parser.y" |
61 | | - @$(_YACC) -d parser.y |
62 | | - @mv y.tab.c y.tab.cc |
63 | | -lex.yy.cc: lexer.l y.tab.h |
64 | | - @echo " $(_LEX) lexer.l" |
65 | | - @$(_LEX) lexer.l || rm -f lex.yy.c |
66 | | - @test -f lex.yy.c && mv lex.yy.c lex.yy.cc |
67 | | - |
68 | 57 | @include@ @q@@top_srcdir@/mk/prog.mk@q@ |
Index: trunk/willow/src/willow/config.cc |
— | — | @@ -574,7 +574,7 @@ |
575 | 575 | |
576 | 576 | if (!read_config(file)) { |
577 | 577 | wlog.error("cannot load configuration"); |
578 | | - nerrors++; |
| 578 | + exit(8); |
579 | 579 | } |
580 | 580 | |
581 | 581 | if (!listeners.size()) { |
Index: trunk/willow/src/willow/expr.cc |
— | — | @@ -12,7 +12,7 @@ |
13 | 13 | |
14 | 14 | #include "autoconf.h" |
15 | 15 | |
16 | | -#ifdef WILLOW_DEBUG |
| 16 | +#if defined(WILLOW_DEBUG) && 0 |
17 | 17 | # define BOOST_SPIRIT_DEBUG |
18 | 18 | #endif |
19 | 19 | |
— | — | @@ -175,33 +175,30 @@ |
176 | 176 | |
177 | 177 | namespace expr { |
178 | 178 | |
179 | | -using expr::expression_parser; |
180 | | -using expr::expression_error; |
181 | | - |
182 | | -expression_parser::expression_parser() |
| 179 | +expr::parser::parser() |
183 | 180 | { |
184 | 181 | impl = new expression_parser_impl; |
185 | 182 | } |
186 | 183 | |
187 | | -expression_parser::~expression_parser() |
| 184 | +expr::parser::~parser() |
188 | 185 | { |
189 | 186 | delete impl; |
190 | 187 | } |
191 | 188 | |
192 | 189 | void |
193 | | -expression_parser::add_variable(string const &name, int64_t val) |
| 190 | +expr::parser::add_variable(string const &name, int64_t val) |
194 | 191 | { |
195 | 192 | impl->add_variable(name, val); |
196 | 193 | } |
197 | 194 | |
198 | 195 | bool |
199 | | -expression_parser::variable_defined(string const &name) const |
| 196 | +expr::parser::variable_defined(string const &name) const |
200 | 197 | { |
201 | 198 | return impl->variable_defined(name); |
202 | 199 | } |
203 | 200 | |
204 | 201 | int64_t |
205 | | -expression_parser::run(string const &str) const |
| 202 | +expr::parser::run(string const &str) const |
206 | 203 | { |
207 | 204 | return impl->run(str); |
208 | 205 | } |
Index: trunk/willow/src/willow/confparse.cc |
— | — | @@ -29,6 +29,7 @@ |
30 | 30 | #define NEED_PARSING_TREE |
31 | 31 | |
32 | 32 | #include "confparse.h" |
| 33 | +#include "confgrammar.h" |
33 | 34 | #include "willow.h" |
34 | 35 | #include "log.h" |
35 | 36 | #include "backend.h" |
— | — | @@ -38,7 +39,7 @@ |
39 | 40 | |
40 | 41 | namespace conf { |
41 | 42 | |
42 | | -expr::expression_parser if_parser; |
| 43 | +expr::parser if_parser; |
43 | 44 | |
44 | 45 | tree global_conf_tree; |
45 | 46 | map<string, value> variable_list; |
— | — | @@ -78,6 +79,7 @@ |
79 | 80 | add_if_entry(unm.sysname, 1); |
80 | 81 | } |
81 | 82 | |
| 83 | +#if 0 |
82 | 84 | if ((yyin = fopen(file.c_str(), "r")) == NULL) { |
83 | 85 | wlog.error(format("could not open configuration file %s: %s") |
84 | 86 | % file % strerror(errno)); |
— | — | @@ -85,6 +87,77 @@ |
86 | 88 | } |
87 | 89 | if (yyparse() || parse_error) |
88 | 90 | return NULL; |
| 91 | +#endif |
| 92 | + |
| 93 | + confgrammar g(if_parser); |
| 94 | + vector<block> result; |
| 95 | + |
| 96 | + try { |
| 97 | + result = g.parse(file); |
| 98 | + } catch (parser_error &e) { |
| 99 | + wlog.error(format("cannot parse configuration file: %s") |
| 100 | + % e.what()); |
| 101 | + return NULL; |
| 102 | + } |
| 103 | + |
| 104 | + vector<block>::iterator blockit, blockend; |
| 105 | + vector<value_t>::iterator valueit, valueend; |
| 106 | + vector<avalue_t>::iterator avalueit, avalueend; |
| 107 | + |
| 108 | + for (blockit = result.begin(), blockend = result.end(); |
| 109 | + blockit != blockend; ++blockit) { |
| 110 | + tree_entry e = declpos(); |
| 111 | + e.item_name = blockit->name; |
| 112 | + e.item_key = blockit->key; |
| 113 | + |
| 114 | + for (valueit = blockit->values.begin(), |
| 115 | + valueend = blockit->values.end(); |
| 116 | + valueit != valueend; ++valueit) { |
| 117 | + value v = declpos(); |
| 118 | + v.cv_name = valueit->name; |
| 119 | + |
| 120 | + for (avalueit = valueit->values.begin(), |
| 121 | + avalueend = valueit->values.end(); |
| 122 | + avalueit != avalueend; ++avalueit) { |
| 123 | + avalue av; |
| 124 | + switch (avalueit->which()) { |
| 125 | + case 0: // bare string |
| 126 | + av.av_type = cv_string; |
| 127 | + av.av_strval = boost::get<u_string>(*avalueit).value(); |
| 128 | + break; |
| 129 | + |
| 130 | + case 1: // quoted string |
| 131 | + av.av_type = cv_qstring; |
| 132 | + av.av_strval = boost::get<q_string>(*avalueit).value(); |
| 133 | + break; |
| 134 | + |
| 135 | + case 2: // yesno |
| 136 | + av.av_type = cv_yesno; |
| 137 | + av.av_intval = boost::get<bool>(*avalueit); |
| 138 | + break; |
| 139 | + |
| 140 | + case 3: // int |
| 141 | + av.av_type = cv_int; |
| 142 | + av.av_intval = boost::get<int>(*avalueit); |
| 143 | + break; |
| 144 | + |
| 145 | + case 4: // time |
| 146 | + av.av_type = cv_time; |
| 147 | + av.av_intval = boost::get<time_q>(*avalueit).value(); |
| 148 | + break; |
| 149 | + |
| 150 | + case 5: // size |
| 151 | + av.av_type = cv_time; |
| 152 | + av.av_intval = boost::get<size_q>(*avalueit).value(); |
| 153 | + break; |
| 154 | + } |
| 155 | + v.cv_values.push_back(av); |
| 156 | + } |
| 157 | + e.add(v); |
| 158 | + } |
| 159 | + parsing_tree.add(e); |
| 160 | + } |
| 161 | + |
89 | 162 | return &parsing_tree; |
90 | 163 | } |
91 | 164 | |
— | — | @@ -146,7 +219,7 @@ |
147 | 220 | |
148 | 221 | try { |
149 | 222 | return if_parser.run(dir); |
150 | | - } catch (expr::expression_error &e) { |
| 223 | + } catch (expr::error &e) { |
151 | 224 | report_parse_error("error in %%if expression: %s", e.what()); |
152 | 225 | return false; |
153 | 226 | } |
Index: trunk/willow/src/willow/log.cc |
— | — | @@ -92,7 +92,7 @@ |
93 | 93 | } |
94 | 94 | |
95 | 95 | if (config.foreground) |
96 | | - cout << r << '\n'; |
| 96 | + cout << sev_names[sev] << ": " << e << '\n'; |
97 | 97 | } |
98 | 98 | |
99 | 99 | void |
Index: trunk/willow/src/willow/preprocessor.cc |
— | — | @@ -0,0 +1,312 @@ |
| 2 | +/* Willow: Lightweight HTTP reverse-proxy. */ |
| 3 | +/* preprocessor: cpp-style preprocessor for config parsing */ |
| 4 | +/* Copyright (c) 2005, 2006 River Tarnell <river@attenuate.org>. */ |
| 5 | +/* |
| 6 | + * Permission is granted to anyone to use this software for any purpose, |
| 7 | + * including commercial applications, and to alter it and redistribute it |
| 8 | + * freely. This software is provided 'as-is', without any express or implied |
| 9 | + * warranty. |
| 10 | + */ |
| 11 | + |
| 12 | +/* $Id$ */ |
| 13 | + |
| 14 | +#include <utility> |
| 15 | +#include <boost/spirit.hpp> |
| 16 | +using std::pair; |
| 17 | +using std::make_pair; |
| 18 | +using boost::spirit::file_iterator; |
| 19 | + |
| 20 | +#include "preprocessor.h" |
| 21 | + |
| 22 | +file_position::file_position(string const &f, int l, int p) |
| 23 | + : file(f), line(l), col(p) {} |
| 24 | + |
| 25 | +file_position::file_position(file_position const &o) |
| 26 | + : file(o.file), line(o.line), col(o.col) {} |
| 27 | + |
| 28 | +file_position & |
| 29 | +file_position::operator= (file_position const &o) { |
| 30 | + file = o.file; |
| 31 | + line = o.line; |
| 32 | + col = o.col; |
| 33 | + return *this; |
| 34 | +} |
| 35 | + |
| 36 | +ostream& |
| 37 | +operator<< (ostream &o, file_position const &p) { |
| 38 | + o << p.file << '(' << p.line << ')'; |
| 39 | + return o; |
| 40 | +} |
| 41 | + |
| 42 | +preprocessor::iterator::iterator() |
| 43 | + : _cpp(NULL) {} |
| 44 | + |
| 45 | +preprocessor::iterator::iterator(preprocessor const &cpp, |
| 46 | + vector<char>::const_iterator it) |
| 47 | + : _cpp(&cpp) |
| 48 | + , _it(it) { |
| 49 | +} |
| 50 | + |
| 51 | +preprocessor::iterator::iterator(preprocessor::iterator::iterator const &other) |
| 52 | + : _cpp(other._cpp) |
| 53 | + , _it(other._it) { |
| 54 | +} |
| 55 | + |
| 56 | +preprocessor::iterator & |
| 57 | +preprocessor::iterator::operator= (preprocessor::iterator const &other) { |
| 58 | + _cpp = other._cpp; |
| 59 | + _it = other._it; |
| 60 | + return *this; |
| 61 | +} |
| 62 | + |
| 63 | +preprocessor::iterator & |
| 64 | +preprocessor::iterator::operator++(void) { |
| 65 | + ++_it; |
| 66 | + return *this; |
| 67 | +} |
| 68 | + |
| 69 | +preprocessor::iterator |
| 70 | +preprocessor::iterator::operator++(int) { |
| 71 | +iterator ret (*this); |
| 72 | + ++_it; |
| 73 | + return ret; |
| 74 | +} |
| 75 | + |
| 76 | +preprocessor::iterator & |
| 77 | +preprocessor::iterator::operator--(void) { |
| 78 | + --_it; |
| 79 | + return *this; |
| 80 | +} |
| 81 | + |
| 82 | +preprocessor::iterator |
| 83 | +preprocessor::iterator::operator--(int) { |
| 84 | +iterator ret (*this); |
| 85 | + --_it; |
| 86 | + return ret; |
| 87 | +} |
| 88 | + |
| 89 | +preprocessor::iterator::reference |
| 90 | +preprocessor::iterator::operator*(void) const { |
| 91 | + return *_it; |
| 92 | +} |
| 93 | + |
| 94 | +bool |
| 95 | +preprocessor::iterator::operator< (preprocessor::iterator const &other) const { |
| 96 | + return _it < other._it; |
| 97 | +} |
| 98 | + |
| 99 | +bool |
| 100 | +preprocessor::iterator::operator== (preprocessor::iterator const &other) const { |
| 101 | + return !(*this < other) && !(other < *this); |
| 102 | +} |
| 103 | + |
| 104 | +bool |
| 105 | +preprocessor::iterator::operator!= (preprocessor::iterator const &other) const { |
| 106 | + return !(*this == other); |
| 107 | +} |
| 108 | + |
| 109 | +bool |
| 110 | +preprocessor::iterator::operator> (preprocessor::iterator const &other) const { |
| 111 | + return !(*this < other) && !(*this == other); |
| 112 | +} |
| 113 | + |
| 114 | +bool |
| 115 | +preprocessor::iterator::operator<= (preprocessor::iterator const &other) const { |
| 116 | + return (*this < other) || (*this == other); |
| 117 | +} |
| 118 | + |
| 119 | +bool |
| 120 | +preprocessor::iterator::operator>= (preprocessor::iterator const &other) const { |
| 121 | + return (*this > other) || (*this == other); |
| 122 | +} |
| 123 | + |
| 124 | +preprocessor::iterator::difference_type |
| 125 | +preprocessor::iterator::operator- (preprocessor::iterator const &other) const { |
| 126 | + return _it - other._it; |
| 127 | +} |
| 128 | + |
| 129 | +preprocessor::iterator |
| 130 | +preprocessor::iterator::operator- (size_type s) const { |
| 131 | + return iterator(*_cpp, _it - s); |
| 132 | +} |
| 133 | + |
| 134 | +preprocessor::iterator |
| 135 | +preprocessor::iterator::operator+ (size_type s) const { |
| 136 | + return iterator(*_cpp, _it + s); |
| 137 | +} |
| 138 | + |
| 139 | +file_position |
| 140 | +preprocessor::iterator::get_position(void) const { |
| 141 | + return _cpp->get_position(_it); |
| 142 | +} |
| 143 | + |
| 144 | +string const & |
| 145 | +preprocessor::iterator::get_line(int i) const { |
| 146 | + return _cpp->get_line(i); |
| 147 | +} |
| 148 | + |
| 149 | +void |
| 150 | +preprocessor::set_position(vector<char>::const_iterator n) |
| 151 | +{ |
| 152 | + positions.insert(make_pair(distance( |
| 153 | + static_cast<vector<char> const &>(_data).begin(), n), |
| 154 | + file_position(_curfile, _curline, _curpos))); |
| 155 | +} |
| 156 | + |
| 157 | +string const & |
| 158 | +preprocessor::get_line(int line) const |
| 159 | +{ |
| 160 | + return lines[line - 1]; |
| 161 | +} |
| 162 | + |
| 163 | +file_position |
| 164 | +preprocessor::get_position(vector<char>::const_iterator it) const |
| 165 | +{ |
| 166 | +map<vector<char>::difference_type, file_position>::const_iterator posit; |
| 167 | + |
| 168 | + posit = positions.upper_bound(distance(_data.begin(), it)); |
| 169 | + assert(posit != positions.end()); |
| 170 | + |
| 171 | +file_position p(posit->second); |
| 172 | +vector<char>::const_iterator lit = it; |
| 173 | + |
| 174 | + p.col = 0; |
| 175 | + for (; lit > _data.begin() && *lit != '\n'; --lit) |
| 176 | + if (*lit == '\t') |
| 177 | + p.col += 8; |
| 178 | + else |
| 179 | + ++p.col; |
| 180 | + return p; |
| 181 | +} |
| 182 | + |
| 183 | +preprocessor::preprocessor(string const &file, expr::parser const &expr) |
| 184 | + : _curfile(file) |
| 185 | + , _curline(1) |
| 186 | + , _curpos(0) |
| 187 | + , _expr(expr) |
| 188 | +{ |
| 189 | + file_iterator<> first(file.c_str()); |
| 190 | + file_iterator<> last = first.make_end(); |
| 191 | + process(first, last); |
| 192 | + _end = iterator(*this, _data.end()); |
| 193 | +} |
| 194 | + |
| 195 | +preprocessor::iterator |
| 196 | +preprocessor::begin(void) |
| 197 | +{ |
| 198 | + return iterator(*this, _data.begin()); |
| 199 | +} |
| 200 | + |
| 201 | +preprocessor::const_iterator |
| 202 | +preprocessor::begin(void) const |
| 203 | +{ |
| 204 | + return iterator(*this, _data.begin()); |
| 205 | +} |
| 206 | + |
| 207 | +preprocessor::iterator |
| 208 | +preprocessor::end(void) |
| 209 | +{ |
| 210 | + return iterator(*this, _data.end()); |
| 211 | +} |
| 212 | + |
| 213 | +preprocessor::const_iterator |
| 214 | +preprocessor::end(void) const |
| 215 | +{ |
| 216 | + return iterator(*this, _data.end()); |
| 217 | +} |
| 218 | + |
| 219 | +template<typename iterT> |
| 220 | +void |
| 221 | +preprocessor::process(iterT begin, iterT end) |
| 222 | +{ |
| 223 | +bool ateol = false; |
| 224 | +bool ignoring = false; |
| 225 | +iterT lbegin = begin; |
| 226 | + for (; begin != end; ++begin) { |
| 227 | + switch (*begin) { |
| 228 | + case '%': { |
| 229 | + /* everything until the end of the line is a directive */ |
| 230 | + if (ateol) { |
| 231 | + iterT eol = find(begin, end, '\n'); |
| 232 | + string expr(begin, eol); |
| 233 | + ignoring = evaluate_expr(begin, eol, ignoring); |
| 234 | + lines.push_back(string(lbegin, begin)); |
| 235 | + set_position(_data.end()); |
| 236 | + begin = eol; |
| 237 | + lbegin = begin + 1; |
| 238 | + _curline++; |
| 239 | + _curpos = 0; |
| 240 | + break; |
| 241 | + } |
| 242 | + goto normal; |
| 243 | + } |
| 244 | + |
| 245 | + case '\n': |
| 246 | + ateol = true; |
| 247 | + lines.push_back(string(lbegin, begin)); |
| 248 | + set_position(_data.end()); |
| 249 | + lbegin = begin + 1; |
| 250 | + _curline++; |
| 251 | + _curpos = 0; |
| 252 | + _data.push_back(*begin); |
| 253 | + break; |
| 254 | + |
| 255 | + normal: |
| 256 | + default: |
| 257 | + if (!ignoring) { |
| 258 | + _data.push_back(*begin); |
| 259 | + } |
| 260 | + if (*begin == '\t') |
| 261 | + _curpos += 8; |
| 262 | + else |
| 263 | + ++_curpos; |
| 264 | + ateol = false; |
| 265 | + break; |
| 266 | + } |
| 267 | + } |
| 268 | +} |
| 269 | + |
| 270 | +template<typename iterT> |
| 271 | +bool |
| 272 | +preprocessor::evaluate_expr(iterT begin, iterT end, bool ignoring) |
| 273 | +{ |
| 274 | +iterT space = find(begin, end, ' '); |
| 275 | + if (itercmp(begin, space, "%if")) { |
| 276 | + if (space == end) |
| 277 | + return false; |
| 278 | + |
| 279 | + string expr(space + 1, end); |
| 280 | + try { |
| 281 | + if (_expr.run(expr)) |
| 282 | + return false; |
| 283 | + } catch (expr::error &e) { |
| 284 | + wlog.error(format("%s(%d): error parsing expression: %s") |
| 285 | + % _curfile % _curline % e.what()); |
| 286 | + wlog.error('\t' + string(begin, end) + '\n'); |
| 287 | + throw preprocessor_exception(e.what()); |
| 288 | + } |
| 289 | + |
| 290 | + return true; |
| 291 | + } else if (itercmp(begin, space, "%else")) { |
| 292 | + return !ignoring; |
| 293 | + } else if (itercmp(begin, space, "%endif")) { |
| 294 | + return false; |
| 295 | + } else { |
| 296 | + wlog.error(format("%s(%d): unrecognised directive") |
| 297 | + % _curfile % _curline); |
| 298 | + wlog.error('\t' + string(begin, end) + '\n'); |
| 299 | + throw preprocessor_exception( |
| 300 | + "syntax error in preprocessor directive"); |
| 301 | + } |
| 302 | + return false; |
| 303 | +} |
| 304 | + |
| 305 | +template<typename iterT> |
| 306 | +bool |
| 307 | +preprocessor::itercmp(iterT begin, iterT end, char const *s) |
| 308 | +{ |
| 309 | +int len = strlen(s); |
| 310 | + if (distance(begin, end) != len) |
| 311 | + return false; |
| 312 | + return equal(begin, end, s); |
| 313 | +} |
Property changes on: trunk/willow/src/willow/preprocessor.cc |
___________________________________________________________________ |
Added: svn:keywords |
1 | 314 | + Id Revision |