/* * BIRD -- Configuration Parser Top * * (c) 1998--2000 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ /** * DOC: Parser * * Both the configuration and CLI commands are analysed using a syntax * driven parser generated by the |bison| tool from a grammar which * is constructed from information gathered from grammar snippets by * the |gen_parser.m4| script. * * Grammar snippets are files (usually with extension |.Y|) contributed * by various BIRD modules to provide information about syntax of their * configuration and their CLI commands. Each snipped consists of several * section, each of them starting with a special keyword: |CF_HDR| for * a list of |#include| directives needed by the C code, |CF_DEFINES| * for a list of C declarations, |CF_DECLS| for |bison| declarations * including keyword definitions specified as |CF_KEYWORDS|, |CF_GRAMMAR| * for the grammar rules, |CF_CODE| for auxillary C code and finally * |CF_END| at the end of the snippet. * * To create references between the snippets, it's possible to define * multi-part rules by utilizing the |CF_ADDTO| macro which adds a new * alternative to a multi-part rule. * * CLI commands are defined using a |CF_CLI| macro. Its parameters are: * the list of keywords determining the command, the list of paramaters, * help text for the parameters and help text for the command. * * Values of |enum| filter types can be defined using |CF_ENUM| with * the following parameters: name of filter type, prefix common for all * literals of this type, names of all the possible values. */ CF_HDR #include "nest/bird.h" #include "conf/conf.h" #include "lib/resource.h" #include "lib/socket.h" #include "lib/timer.h" #include "lib/string.h" #include "nest/protocol.h" #include "nest/iface.h" #include "nest/route.h" #include "nest/cli.h" #include "filter/filter.h" /* FIXME: Turn on YYERROR_VERBOSE and work around lots of bison bugs? */ CF_DECLS %union { int i; u32 i32; ip_addr a; struct symbol *s; char *t; struct rtable_config *r; struct f_inst *x; struct filter *f; struct f_tree *e; struct f_val v; struct f_path_mask *h; struct password_item *p; struct rt_show_data *ra; void *g; bird_clock_t time; struct prefix px; } %token END CLI_MARKER INVALID_TOKEN %token GEQ LEQ NEQ AND OR %token NUM ENUM %token RTRID %token IPA %token SYM %token TEXT %type expr bool pxlen %type ipa %type prefix prefix_or_ipa %nonassoc PREFIX_DUMMY %nonassoc '=' '<' '>' '~' '.' GEQ LEQ NEQ AND OR %left '+' '-' %left '*' '/' '%' %left '!' CF_KEYWORDS(DEFINE, ON, OFF, YES, NO) CF_GRAMMAR /* Basic config file structure */ config: conf_entries END { return 0; } | CLI_MARKER cli_cmd { return 0; } ; conf_entries: /* EMPTY */ | conf_entries conf ; CF_ADDTO(conf, ';') /* Constant expressions */ expr: NUM | '(' term ')' { $$ = f_eval_int($2); } | SYM { if ($1->class != SYM_NUMBER) cf_error("Number expected"); else $$ = $1->aux; } ; CF_ADDTO(conf, definition) definition: DEFINE SYM '=' expr ';' { cf_define_symbol($2, SYM_NUMBER, NULL); $2->aux = $4; } | DEFINE SYM '=' IPA ';' { cf_define_symbol($2, SYM_IPA, cfg_alloc(sizeof(ip_addr))); *(ip_addr *)$2->def = $4; } ; /* Switches */ bool: expr {$$ = !!$1; } | ON { $$ = 1; } | YES { $$ = 1; } | OFF { $$ = 0; } | NO { $$ = 0; } | /* Silence means agreement */ { $$ = 1; } ; /* Addresses, prefixes and netmasks */ ipa: IPA | SYM { if ($1->class != SYM_IPA) cf_error("IP address expected"); $$ = *(ip_addr *)$1->def; } ; prefix: ipa pxlen { if (!ip_is_prefix($1, $2)) cf_error("Invalid prefix"); $$.addr = $1; $$.len = $2; } ; prefix_or_ipa: prefix | ipa { $$.addr = $1; $$.len = BITS_PER_IP_ADDRESS; } ; pxlen: '/' expr { if ($2 < 0 || $2 > BITS_PER_IP_ADDRESS) cf_error("Invalid prefix length %d", $2); $$ = $2; } | ':' ipa { $$ = ipa_mklen($2); if ($$ < 0) cf_error("Invalid netmask %I", $2); } ; datetime: TEXT { $$ = tm_parse_date($1); if (!$$) cf_error("Invalid date"); } ; CF_CODE CF_END