diff options
Diffstat (limited to 'src/belex.l')
-rw-r--r-- | src/belex.l | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/src/belex.l b/src/belex.l new file mode 100644 index 0000000..f35f114 --- /dev/null +++ b/src/belex.l @@ -0,0 +1,178 @@ +%option nounput +%option noinput + +%{ +#include "backend.h" + +enum { + T_BOGUS = 256, + T_IDENT, + T_NUMBER, + T_STRING, + T_BACKEND, + T_HOST, + T_PORT +}; + +static char const *input_string; +static size_t input_len; +static size_t input_pos; +static char const *string_start; +static size_t current_pos; + +#define YY_INPUT(buf,result,max_size) \ + do { \ + size_t n = input_len - input_pos; \ + if (n > max_size) \ + n = max_size; \ + memcpy(buf, input_string, n); \ + input_pos += n; \ + result = n; \ + } while (0) + +#define YY_USER_ACTION \ + current_pos += yyleng; + +#define YY_DECL static int yylex(void) +static int yywrap(void); + +static char const * +input_point(void) +{ + return input_string + current_pos; +} + +#define YYSTYPE be_string_t +#define YYSTYPE_INITIALIZER { NULL, 0 } + +static YYSTYPE yylval; +%} + +%x COMMENT STR + +%% + /* C-style comments */ +"/*" BEGIN(COMMENT); +<COMMENT>[^*]* /* eat anything that's not a '*' */ +<COMMENT>"*"+[^*/]* /* eat up '*'s not followed by '/'s */ +<COMMENT>"*"+"/" BEGIN(INITIAL); + + /* Single-line comments */ +"//".*\n ; +#.*\n ; + + /* Multi-line strings */ +"{\"" { BEGIN(STR); string_start = input_point(); } +<STR>[^\"]* /* eat anything that's not a '"' */ +<STR>"\""+[^"}]* /* eat up '"'s not followed by '}'s */ +<STR>"\""+"}" { BEGIN(INITIAL); + yylval.start = string_start; + yylval.len = input_point() - yylval.start - 2; + return T_STRING; + } + /* Single-line strings */ +\".*\" { + yylval.start = input_point() - yyleng + 1; + yylval.len = yyleng - 2; + return T_STRING; + } +backend return T_BACKEND; +".host" return T_HOST; +".port" return T_PORT; +"{"|"}"|"="|";" return yytext[0]; + +[a-zA-Z_][a-zA-Z0-9_.]+ { + yylval.start = input_point() - yyleng; + yylval.len = yyleng; + return T_IDENT; + } +[0-9]+ return T_NUMBER; + +[ \t\n]+ ; + +. return T_BOGUS; + +%% +int +yywrap(void) +{ + return 1; +} + +static void +set_input(char const *str, size_t len) +{ + input_string = str; + input_len = len; + input_pos = 0; + current_pos = 0; +} + +static int brace_nesting; + +static void +read_backend(regfun_t regfun, void *d) +{ + int c; + int in_statement; + YYSTYPE label, host = YYSTYPE_INITIALIZER, port = YYSTYPE_INITIALIZER; + + if ((c = yylex()) != T_IDENT && c != T_STRING) + return; + label = yylval; + if ((c = yylex()) != '{') + return; + brace_nesting++; + in_statement = 0; + while (brace_nesting == 1) { + c = yylex(); + if (c == 0) + break; + else if (c == '{') + brace_nesting++; + else if (c == '}') + brace_nesting++; + else if (in_statement) { + if (c == ';') + in_statement = 0; + } else { + in_statement = 1; + if (c == T_HOST || c == T_PORT) { + YYSTYPE *stk = c == T_HOST ? &host : &port; + in_statement = 1; + if ((c = yylex()) == '=') { + c = yylex(); + if (c == T_STRING || c == T_IDENT) { + *stk = yylval; + } + } + } + } + } + regfun(&label, &host, &port, d); +} + +void +backend_parser(const char *str, size_t len, regfun_t regfun, void *d) +{ + int c; + + set_input(str, len); + + brace_nesting = 0; + while ((c = yylex())) { + if (brace_nesting == 0) { + if (c == T_BACKEND) { + read_backend(regfun, d); + } + } + switch (c) { + case '{': + brace_nesting++; + break; + case '}': + brace_nesting--; + break; + } + } +} |