From 5c40780440c0e8661fc7cfcec72dab48b934631d Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Fri, 20 Mar 2009 08:12:18 +0100 Subject: Add support for scoping and symbol binding As a first step towards stand-alone sets, add support for scoping and binding symbols. This will be used for user-defined constants, as well as declarations of modifiable (stand-alone) sets once the kernel side is ready. Scopes are currently limited to three nesting levels: the global scope, table block scopes and chain block scopes. Signed-off-by: Patrick McHardy --- include/parser.h | 8 ++++++++ include/rule.h | 33 +++++++++++++++++++++++++++++++++ src/parser.y | 32 ++++++++++++++++++++++++++++++-- src/rule.c | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+), 2 deletions(-) diff --git a/include/parser.h b/include/parser.h index a47bd0f0..f5dd6f4b 100644 --- a/include/parser.h +++ b/include/parser.h @@ -2,6 +2,7 @@ #define NFTABLES_PARSER_H #include +#include // FIXME #define MAX_INCLUDE_DEPTH 16 #define TABSIZE 8 @@ -10,12 +11,19 @@ #define YYLTYPE_IS_TRIVIAL 0 #define YYENABLE_NLS 0 +#define SCOPE_NEST_MAX 3 + struct parser_state { struct input_descriptor *indesc; struct input_descriptor indescs[MAX_INCLUDE_DEPTH]; unsigned int indesc_idx; struct list_head *msgs; + + struct scope top_scope; + struct scope *scopes[SCOPE_NEST_MAX]; + unsigned int scope; + struct list_head cmds; }; diff --git a/include/rule.h b/include/rule.h index 991d1125..4e5da064 100644 --- a/include/rule.h +++ b/include/rule.h @@ -23,6 +23,37 @@ struct handle { extern void handle_merge(struct handle *dst, const struct handle *src); extern void handle_free(struct handle *h); +/** + * struct scope + * + * @parent: pointer to parent scope + * @symbols: symbols bound in the scope + */ +struct scope { + const struct scope *parent; + struct list_head symbols; +}; + +extern struct scope *scope_init(struct scope *scope, const struct scope *parent); + +/** + * struct symbol + * + * @list: scope symbol list node + * @identifier: identifier + * @expr: initializer + */ +struct symbol { + struct list_head list; + const char *identifier; + struct expr *expr; +}; + +extern void symbol_bind(struct scope *scope, const char *identifier, + struct expr *expr); +extern struct symbol *symbol_lookup(const struct scope *scope, + const char *identifier); + /** * struct table - nftables table * @@ -33,6 +64,7 @@ extern void handle_free(struct handle *h); struct table { struct list_head list; struct handle handle; + struct scope scope; struct list_head chains; }; @@ -55,6 +87,7 @@ struct chain { struct handle handle; unsigned int hooknum; unsigned int priority; + struct scope scope; struct list_head rules; }; diff --git a/src/parser.y b/src/parser.y index b13e932e..1ca5981b 100644 --- a/src/parser.y +++ b/src/parser.y @@ -33,6 +33,7 @@ void parser_init(struct parser_state *state, struct list_head *msgs) memset(state, 0, sizeof(*state)); init_list_head(&state->cmds); state->msgs = msgs; + state->scopes[0] = scope_init(&state->top_scope, NULL); } static void yyerror(struct location *loc, void *scanner, @@ -41,6 +42,22 @@ static void yyerror(struct location *loc, void *scanner, erec_queue(error(loc, "%s", s), state->msgs); } +static struct scope *current_scope(const struct parser_state *state) +{ + return state->scopes[state->scope]; +} + +static void open_scope(struct parser_state *state, struct scope *scope) +{ + scope_init(scope, current_scope(state)); + state->scopes[++state->scope] = scope; +} + +static void close_scope(struct parser_state *state) +{ + state->scope--; +} + static void location_init(void *scanner, struct parser_state *state, struct location *loc) { @@ -474,6 +491,7 @@ add_cmd : TABLE table_spec '{' table_block '}' { handle_merge(&$3->handle, &$2); + close_scope(state); $$ = cmd_alloc(CMD_ADD, CMD_OBJ_TABLE, &$2, $5); } | CHAIN chain_spec @@ -484,6 +502,7 @@ add_cmd : TABLE table_spec '{' chain_block '}' { handle_merge(&$3->handle, &$2); + close_scope(state); $$ = cmd_alloc(CMD_ADD, CMD_OBJ_CHAIN, &$2, $5); } | RULE ruleid_spec rule @@ -530,7 +549,11 @@ flush_cmd : TABLE table_spec } ; -table_block_alloc : /* empty */ { $$ = table_alloc(); } +table_block_alloc : /* empty */ + { + $$ = table_alloc(); + open_scope(state, &$$->scope); + } ; table_block : /* empty */ { $$ = $-1; } @@ -547,11 +570,16 @@ table_line : CHAIN chain_identifier chain_block_alloc '{' chain_block '}' { handle_merge(&$3->handle, &$2); + close_scope(state); $$ = $3; } ; -chain_block_alloc : /* empty */ { $$ = chain_alloc(NULL); } +chain_block_alloc : /* empty */ + { + $$ = chain_alloc(NULL); + open_scope(state, &$$->scope); + } ; chain_block : /* empty */ { $$ = $-1; } diff --git a/src/rule.c b/src/rule.c index e86c78aa..8efbd887 100644 --- a/src/rule.c +++ b/src/rule.c @@ -68,6 +68,38 @@ void rule_print(const struct rule *rule) printf("\n"); } +struct scope *scope_init(struct scope *scope, const struct scope *parent) +{ + scope->parent = parent; + init_list_head(&scope->symbols); + return scope; +} + +void symbol_bind(struct scope *scope, const char *identifier, struct expr *expr) +{ + struct symbol *sym; + + sym = xzalloc(sizeof(*sym)); + sym->identifier = xstrdup(identifier); + sym->expr = expr; + + list_add_tail(&sym->list, &scope->symbols); +} + +struct symbol *symbol_lookup(const struct scope *scope, const char *identifier) +{ + struct symbol *sym; + + while (scope != NULL) { + list_for_each_entry(sym, &scope->symbols, list) { + if (!strcmp(sym->identifier, identifier)) + return sym; + } + scope = scope->parent; + } + return NULL; +} + struct chain *chain_alloc(const char *name) { struct chain *chain; -- cgit v1.2.3