1998-11-28 03:35:50 +08:00
|
|
|
/*
|
|
|
|
* BIRD -- Configuration Lexer
|
|
|
|
*
|
2000-01-17 19:52:50 +08:00
|
|
|
* (c) 1998--2000 Martin Mares <mj@ucw.cz>
|
1998-11-28 03:35:50 +08:00
|
|
|
*
|
|
|
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
|
|
|
*/
|
|
|
|
|
2000-06-04 02:23:00 +08:00
|
|
|
/**
|
|
|
|
* DOC: Lexical analyser
|
|
|
|
*
|
|
|
|
* The lexical analyser used for configuration files and CLI commands
|
|
|
|
* is generated using the |flex| tool accompanied with a couple of
|
|
|
|
* functions maintaining the hash tables containing information about
|
|
|
|
* symbols and keywords.
|
|
|
|
*
|
|
|
|
* Each symbol is represented by a &symbol structure containing name
|
|
|
|
* of the symbol, its scope, symbol class (%SYM_PROTO for a name of a protocol,
|
|
|
|
* %SYM_NUMBER for a numeric constant etc.) and class dependent data.
|
|
|
|
* When an unknown symbol is encountered, it's automatically added to the
|
|
|
|
* symbol table with class %SYM_VOID.
|
|
|
|
*
|
|
|
|
* The keyword tables are generated from the grammar templates
|
|
|
|
* using the |gen_keywords.m4| script.
|
|
|
|
*/
|
|
|
|
|
1998-11-28 03:35:50 +08:00
|
|
|
%{
|
1998-12-07 07:10:28 +08:00
|
|
|
#undef REJECT /* Avoid name clashes */
|
1998-11-28 03:35:50 +08:00
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
1998-12-07 07:10:28 +08:00
|
|
|
#include <stdarg.h>
|
1998-11-28 03:35:50 +08:00
|
|
|
|
|
|
|
#include "nest/bird.h"
|
1999-11-15 19:35:41 +08:00
|
|
|
#include "nest/route.h"
|
|
|
|
#include "filter/filter.h"
|
1998-11-28 03:35:50 +08:00
|
|
|
#include "conf/conf.h"
|
|
|
|
#include "conf/cf-parse.tab.h"
|
2000-01-17 19:52:50 +08:00
|
|
|
#include "lib/string.h"
|
1998-11-28 03:35:50 +08:00
|
|
|
|
2000-04-28 23:12:03 +08:00
|
|
|
struct keyword {
|
1998-11-28 03:35:50 +08:00
|
|
|
byte *name;
|
|
|
|
int value;
|
|
|
|
struct keyword *next;
|
2000-04-28 23:12:03 +08:00
|
|
|
};
|
|
|
|
|
1999-01-10 08:18:32 +08:00
|
|
|
#include "conf/keywords.h"
|
1998-11-28 03:35:50 +08:00
|
|
|
|
|
|
|
#define KW_HASH_SIZE 64
|
1999-11-30 22:03:36 +08:00
|
|
|
static struct keyword *kw_hash[KW_HASH_SIZE];
|
|
|
|
static int kw_hash_inited;
|
|
|
|
|
1998-11-28 03:35:50 +08:00
|
|
|
#define SYM_HASH_SIZE 128
|
|
|
|
#define SYM_MAX_LEN 32
|
|
|
|
|
1999-11-04 21:51:52 +08:00
|
|
|
struct sym_scope {
|
|
|
|
struct sym_scope *next; /* Next on scope stack */
|
|
|
|
struct symbol *name; /* Name of this scope */
|
|
|
|
int active; /* Currently entered */
|
|
|
|
};
|
|
|
|
static struct sym_scope *conf_this_scope;
|
|
|
|
|
1999-02-06 05:37:34 +08:00
|
|
|
int conf_lino;
|
|
|
|
|
1998-11-28 03:35:50 +08:00
|
|
|
static int cf_hash(byte *c);
|
|
|
|
static struct symbol *cf_find_sym(byte *c, unsigned int h0);
|
|
|
|
|
1998-12-06 19:59:18 +08:00
|
|
|
linpool *cfg_mem;
|
1998-11-28 03:35:50 +08:00
|
|
|
|
|
|
|
int (*cf_read_hook)(byte *buf, unsigned int max);
|
|
|
|
|
|
|
|
#define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max);
|
|
|
|
#define YY_NO_UNPUT
|
|
|
|
#define YY_FATAL_ERROR(msg) cf_error(msg)
|
|
|
|
|
|
|
|
%}
|
|
|
|
|
|
|
|
%option noyywrap
|
|
|
|
|
Parse CLI commands. We use the same parser as for configuration files (because
we want to allow filter and similar complex constructs to be used in commands
and we should avoid code duplication), only with CLI_MARKER token prepended
before the whole input.
Defined macro CF_CLI(cmd, args, help) for defining CLI commands in .Y files.
The first argument specifies the command itself, the remaining two arguments
are copied to the help file (er, will be copied after the help file starts
to exist). This macro automatically creates a skeleton rule for the command,
you only need to append arguments as in:
CF_CLI(STEAL MONEY, <$>, [[Steal <$> US dollars or equivalent in any other currency]]): NUM {
cli_msg(0, "%d$ stolen", $3);
} ;
Also don't forget to reset lexer state between inputs.
1999-11-01 01:47:47 +08:00
|
|
|
%x COMMENT CCOMM CLI
|
1998-11-28 03:35:50 +08:00
|
|
|
|
|
|
|
ALPHA [a-zA-Z_]
|
|
|
|
DIGIT [0-9]
|
|
|
|
XIGIT [0-9a-fA-F]
|
|
|
|
ALNUM [a-zA-Z_0-9]
|
|
|
|
WHITE [ \t]
|
|
|
|
|
|
|
|
%%
|
|
|
|
|
|
|
|
{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
|
1999-08-04 03:36:06 +08:00
|
|
|
#ifdef IPV6
|
|
|
|
if (ipv4_pton_u32(yytext, &cf_lval.i32))
|
|
|
|
return RTRID;
|
|
|
|
cf_error("Invalid IPv4 address %s", yytext);
|
|
|
|
#else
|
1998-11-28 03:35:50 +08:00
|
|
|
if (ip_pton(yytext, &cf_lval.a))
|
|
|
|
return IPA;
|
1999-08-04 03:36:06 +08:00
|
|
|
cf_error("Invalid IP address %s", yytext);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) {
|
|
|
|
#ifdef IPV6
|
|
|
|
if (ip_pton(yytext, &cf_lval.a))
|
|
|
|
return IPA;
|
|
|
|
cf_error("Invalid IP address %s", yytext);
|
|
|
|
#else
|
|
|
|
cf_error("This is an IPv4 router, therefore IPv6 addresses are not supported");
|
|
|
|
#endif
|
1998-11-28 03:35:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
0x{DIGIT}+ {
|
|
|
|
char *e;
|
|
|
|
long int l;
|
|
|
|
errno = 0;
|
|
|
|
l = strtoul(yytext+2, &e, 16);
|
|
|
|
if (e && *e || errno == ERANGE || (long int)(int) l != l)
|
|
|
|
cf_error("Number out of range");
|
|
|
|
cf_lval.i = l;
|
|
|
|
return NUM;
|
|
|
|
}
|
|
|
|
|
|
|
|
{DIGIT}+ {
|
|
|
|
char *e;
|
|
|
|
long int l;
|
|
|
|
errno = 0;
|
|
|
|
l = strtoul(yytext, &e, 10);
|
|
|
|
if (e && *e || errno == ERANGE || (long int)(int) l != l)
|
|
|
|
cf_error("Number out of range");
|
|
|
|
cf_lval.i = l;
|
|
|
|
return NUM;
|
|
|
|
}
|
|
|
|
|
|
|
|
{ALPHA}{ALNUM}* {
|
|
|
|
unsigned int h = cf_hash(yytext);
|
|
|
|
struct keyword *k = kw_hash[h & (KW_HASH_SIZE-1)];
|
|
|
|
while (k)
|
|
|
|
{
|
|
|
|
if (!strcmp(k->name, yytext))
|
1999-11-15 19:35:41 +08:00
|
|
|
{
|
|
|
|
if (k->value > 0)
|
|
|
|
return k->value;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cf_lval.i = -k->value;
|
|
|
|
return ENUM;
|
|
|
|
}
|
|
|
|
}
|
1998-11-28 03:35:50 +08:00
|
|
|
k=k->next;
|
|
|
|
}
|
|
|
|
cf_lval.s = cf_find_sym(yytext, h);
|
|
|
|
return SYM;
|
|
|
|
}
|
|
|
|
|
1999-12-02 20:04:39 +08:00
|
|
|
<CLI>(.|\n) {
|
Parse CLI commands. We use the same parser as for configuration files (because
we want to allow filter and similar complex constructs to be used in commands
and we should avoid code duplication), only with CLI_MARKER token prepended
before the whole input.
Defined macro CF_CLI(cmd, args, help) for defining CLI commands in .Y files.
The first argument specifies the command itself, the remaining two arguments
are copied to the help file (er, will be copied after the help file starts
to exist). This macro automatically creates a skeleton rule for the command,
you only need to append arguments as in:
CF_CLI(STEAL MONEY, <$>, [[Steal <$> US dollars or equivalent in any other currency]]): NUM {
cli_msg(0, "%d$ stolen", $3);
} ;
Also don't forget to reset lexer state between inputs.
1999-11-01 01:47:47 +08:00
|
|
|
BEGIN(INITIAL);
|
|
|
|
return CLI_MARKER;
|
|
|
|
}
|
|
|
|
|
2000-05-31 05:46:21 +08:00
|
|
|
[={}:;,.()+*/%<>~\[\]?!-] {
|
1998-11-28 03:35:50 +08:00
|
|
|
return yytext[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
["][^"\n]*["] {
|
1998-11-30 05:59:37 +08:00
|
|
|
yytext[yyleng-1] = 0;
|
2000-01-17 07:36:53 +08:00
|
|
|
cf_lval.t = cfg_strdup(yytext+1);
|
1998-11-28 03:35:50 +08:00
|
|
|
return TEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
["][^"\n]*\n cf_error("Unterminated string");
|
|
|
|
|
|
|
|
<INITIAL,COMMENT><<EOF>> return END;
|
|
|
|
|
|
|
|
{WHITE}+
|
|
|
|
|
1999-03-30 03:04:14 +08:00
|
|
|
\n conf_lino++;
|
1998-11-28 03:35:50 +08:00
|
|
|
|
1999-02-14 05:34:33 +08:00
|
|
|
# BEGIN(COMMENT);
|
1998-11-28 03:35:50 +08:00
|
|
|
|
1999-02-14 05:34:33 +08:00
|
|
|
\/\* BEGIN(CCOMM);
|
1998-11-28 03:35:50 +08:00
|
|
|
|
|
|
|
. cf_error("Unknown character");
|
|
|
|
|
|
|
|
<COMMENT>\n {
|
1999-02-06 05:37:34 +08:00
|
|
|
conf_lino++;
|
1998-11-28 03:35:50 +08:00
|
|
|
BEGIN(INITIAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
<COMMENT>.
|
|
|
|
|
|
|
|
<CCOMM>\*\/ BEGIN(INITIAL);
|
1999-02-06 05:37:34 +08:00
|
|
|
<CCOMM>\n conf_lino++;
|
1998-11-28 03:35:50 +08:00
|
|
|
<CCOMM>\/\* cf_error("Comment nesting not supported");
|
|
|
|
<CCOMM><<EOF>> cf_error("Unterminated comment");
|
|
|
|
<CCOMM>.
|
|
|
|
|
2000-03-11 04:21:12 +08:00
|
|
|
\!\= return NEQ;
|
|
|
|
\<\= return LEQ;
|
|
|
|
\>\= return GEQ;
|
2000-06-01 16:43:29 +08:00
|
|
|
\&\& return AND;
|
|
|
|
\|\| return OR;
|
2000-03-11 04:21:12 +08:00
|
|
|
|
1998-11-28 03:35:50 +08:00
|
|
|
%%
|
|
|
|
|
|
|
|
static int
|
|
|
|
cf_hash(byte *c)
|
|
|
|
{
|
|
|
|
unsigned int h = 13;
|
|
|
|
|
|
|
|
while (*c)
|
|
|
|
h = (h * 37) + *c++;
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct symbol *
|
|
|
|
cf_find_sym(byte *c, unsigned int h0)
|
|
|
|
{
|
|
|
|
unsigned int h = h0 & (SYM_HASH_SIZE-1);
|
1999-11-30 22:03:36 +08:00
|
|
|
struct symbol *s, **ht;
|
1998-11-28 03:35:50 +08:00
|
|
|
int l;
|
|
|
|
|
1999-11-30 22:03:36 +08:00
|
|
|
if (ht = new_config->sym_hash)
|
|
|
|
{
|
|
|
|
for(s = ht[h]; s; s=s->next)
|
|
|
|
if (!strcmp(s->name, c) && s->scope->active)
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
if (new_config->sym_fallback)
|
|
|
|
{
|
|
|
|
/* We know only top-level scope is active */
|
|
|
|
for(s = new_config->sym_fallback[h]; s; s=s->next)
|
1999-11-04 21:51:52 +08:00
|
|
|
if (!strcmp(s->name, c) && s->scope->active)
|
Parse CLI commands. We use the same parser as for configuration files (because
we want to allow filter and similar complex constructs to be used in commands
and we should avoid code duplication), only with CLI_MARKER token prepended
before the whole input.
Defined macro CF_CLI(cmd, args, help) for defining CLI commands in .Y files.
The first argument specifies the command itself, the remaining two arguments
are copied to the help file (er, will be copied after the help file starts
to exist). This macro automatically creates a skeleton rule for the command,
you only need to append arguments as in:
CF_CLI(STEAL MONEY, <$>, [[Steal <$> US dollars or equivalent in any other currency]]): NUM {
cli_msg(0, "%d$ stolen", $3);
} ;
Also don't forget to reset lexer state between inputs.
1999-11-01 01:47:47 +08:00
|
|
|
return s;
|
1999-11-30 22:03:36 +08:00
|
|
|
}
|
|
|
|
if (!ht)
|
|
|
|
ht = new_config->sym_hash = cfg_allocz(SYM_HASH_SIZE * sizeof(struct keyword *));
|
1998-11-28 03:35:50 +08:00
|
|
|
l = strlen(c);
|
|
|
|
if (l > SYM_MAX_LEN)
|
|
|
|
cf_error("Symbol too long");
|
1998-11-30 05:59:37 +08:00
|
|
|
s = cfg_alloc(sizeof(struct symbol) + l);
|
1999-11-30 22:03:36 +08:00
|
|
|
s->next = ht[h];
|
|
|
|
ht[h] = s;
|
1999-11-04 21:51:52 +08:00
|
|
|
s->scope = conf_this_scope;
|
1998-11-28 03:35:50 +08:00
|
|
|
s->class = SYM_VOID;
|
|
|
|
s->def = NULL;
|
1998-11-28 05:32:45 +08:00
|
|
|
s->aux = 0;
|
1998-11-28 03:35:50 +08:00
|
|
|
strcpy(s->name, c);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2000-06-04 02:23:00 +08:00
|
|
|
/**
|
|
|
|
* cf_find_symbol - find a symbol by name
|
|
|
|
* @c: symbol name
|
|
|
|
*
|
|
|
|
* This functions searches the symbol table for a symbol of given
|
|
|
|
* name. First it examines the current scope, then the second recent
|
|
|
|
* one and so on until it either finds the symbol and returns a pointer
|
|
|
|
* to its &symbol structure or reaches the end of the scope chain
|
|
|
|
* and returns %NULL to signify no match.
|
|
|
|
*/
|
1999-05-18 04:06:19 +08:00
|
|
|
struct symbol *
|
|
|
|
cf_find_symbol(byte *c)
|
|
|
|
{
|
|
|
|
return cf_find_sym(c, cf_hash(c));
|
|
|
|
}
|
|
|
|
|
1998-11-28 05:07:02 +08:00
|
|
|
struct symbol *
|
2000-01-17 19:52:50 +08:00
|
|
|
cf_default_name(char *template, int *counter)
|
1998-11-28 05:07:02 +08:00
|
|
|
{
|
|
|
|
char buf[32];
|
|
|
|
struct symbol *s;
|
2000-01-17 19:52:50 +08:00
|
|
|
char *perc = strchr(template, '%');
|
1998-11-28 05:07:02 +08:00
|
|
|
|
2000-01-17 19:52:50 +08:00
|
|
|
for(;;)
|
1998-11-28 05:07:02 +08:00
|
|
|
{
|
2000-01-17 19:52:50 +08:00
|
|
|
bsprintf(buf, template, ++(*counter));
|
1998-11-28 05:07:02 +08:00
|
|
|
s = cf_find_sym(buf, cf_hash(buf));
|
2000-01-17 19:52:50 +08:00
|
|
|
if (!s)
|
|
|
|
break;
|
|
|
|
if (s->class == SYM_VOID)
|
|
|
|
return s;
|
|
|
|
if (!perc)
|
|
|
|
break;
|
1998-11-28 05:07:02 +08:00
|
|
|
}
|
2000-01-17 19:52:50 +08:00
|
|
|
cf_error("Unable to generate default name");
|
1998-11-28 05:07:02 +08:00
|
|
|
}
|
|
|
|
|
2000-06-04 02:23:00 +08:00
|
|
|
/**
|
|
|
|
* cf_define_symbol - define meaning of a symbol
|
|
|
|
* @sym: symbol to be defined
|
|
|
|
* @type: symbol class to assign
|
|
|
|
* @def: class dependent data
|
|
|
|
*
|
|
|
|
* This function takes a symbol, checks whether it's really
|
|
|
|
* an undefined one (else it raises an error) and assigns the
|
|
|
|
* given class and definition to it.
|
|
|
|
*/
|
1999-05-18 04:06:19 +08:00
|
|
|
void
|
|
|
|
cf_define_symbol(struct symbol *sym, int type, void *def)
|
|
|
|
{
|
|
|
|
if (sym->class)
|
|
|
|
cf_error("Symbol already defined");
|
|
|
|
sym->class = type;
|
|
|
|
sym->def = def;
|
|
|
|
}
|
|
|
|
|
1999-11-30 22:03:36 +08:00
|
|
|
static void
|
|
|
|
cf_lex_init_kh(void)
|
|
|
|
{
|
|
|
|
struct keyword *k;
|
|
|
|
|
|
|
|
for(k=keyword_list; k->name; k++)
|
|
|
|
{
|
|
|
|
unsigned h = cf_hash(k->name) & (KW_HASH_SIZE-1);
|
|
|
|
k->next = kw_hash[h];
|
|
|
|
kw_hash[h] = k;
|
|
|
|
}
|
|
|
|
kw_hash_inited = 1;
|
|
|
|
}
|
|
|
|
|
2000-06-04 02:23:00 +08:00
|
|
|
/**
|
|
|
|
* cf_lex_init - initialize the lexer
|
|
|
|
* @is_cli: true if we're going to parse CLI command, false for configuration
|
|
|
|
*
|
|
|
|
* cf_lex_init() initializes the lexical analyser and prepares it for
|
|
|
|
* parsing of a new input.
|
|
|
|
*/
|
1998-11-28 03:35:50 +08:00
|
|
|
void
|
Parse CLI commands. We use the same parser as for configuration files (because
we want to allow filter and similar complex constructs to be used in commands
and we should avoid code duplication), only with CLI_MARKER token prepended
before the whole input.
Defined macro CF_CLI(cmd, args, help) for defining CLI commands in .Y files.
The first argument specifies the command itself, the remaining two arguments
are copied to the help file (er, will be copied after the help file starts
to exist). This macro automatically creates a skeleton rule for the command,
you only need to append arguments as in:
CF_CLI(STEAL MONEY, <$>, [[Steal <$> US dollars or equivalent in any other currency]]): NUM {
cli_msg(0, "%d$ stolen", $3);
} ;
Also don't forget to reset lexer state between inputs.
1999-11-01 01:47:47 +08:00
|
|
|
cf_lex_init(int is_cli)
|
1998-11-28 03:35:50 +08:00
|
|
|
{
|
1999-11-30 22:03:36 +08:00
|
|
|
if (!kw_hash_inited)
|
|
|
|
cf_lex_init_kh();
|
1999-02-06 05:37:34 +08:00
|
|
|
conf_lino = 1;
|
Parse CLI commands. We use the same parser as for configuration files (because
we want to allow filter and similar complex constructs to be used in commands
and we should avoid code duplication), only with CLI_MARKER token prepended
before the whole input.
Defined macro CF_CLI(cmd, args, help) for defining CLI commands in .Y files.
The first argument specifies the command itself, the remaining two arguments
are copied to the help file (er, will be copied after the help file starts
to exist). This macro automatically creates a skeleton rule for the command,
you only need to append arguments as in:
CF_CLI(STEAL MONEY, <$>, [[Steal <$> US dollars or equivalent in any other currency]]): NUM {
cli_msg(0, "%d$ stolen", $3);
} ;
Also don't forget to reset lexer state between inputs.
1999-11-01 01:47:47 +08:00
|
|
|
yyrestart(NULL);
|
|
|
|
if (is_cli)
|
|
|
|
BEGIN(CLI);
|
|
|
|
else
|
|
|
|
BEGIN(INITIAL);
|
1999-11-04 21:51:52 +08:00
|
|
|
conf_this_scope = cfg_allocz(sizeof(struct sym_scope));
|
|
|
|
conf_this_scope->active = 1;
|
1998-11-28 03:35:50 +08:00
|
|
|
}
|
|
|
|
|
2000-06-04 02:23:00 +08:00
|
|
|
/**
|
|
|
|
* cf_push_scope - enter new scope
|
|
|
|
* @sym: symbol representing scope name
|
|
|
|
*
|
|
|
|
* If we want to enter a new scope to process declarations inside
|
|
|
|
* a nested block, we can just call cf_push_scope() to push a new
|
|
|
|
* scope onto the scope stack which will cause all new symbols to be
|
|
|
|
* defined in this scope and all existing symbols to be sought for
|
|
|
|
* in all scopes stored on the stack.
|
|
|
|
*/
|
1999-11-04 21:51:52 +08:00
|
|
|
void
|
|
|
|
cf_push_scope(struct symbol *sym)
|
|
|
|
{
|
|
|
|
struct sym_scope *s = cfg_alloc(sizeof(struct sym_scope));
|
|
|
|
|
|
|
|
s->next = conf_this_scope;
|
|
|
|
conf_this_scope = s;
|
|
|
|
s->active = 1;
|
|
|
|
s->name = sym;
|
|
|
|
}
|
|
|
|
|
2000-06-04 02:23:00 +08:00
|
|
|
/**
|
|
|
|
* cf_pop_scope - leave a scope
|
|
|
|
*
|
|
|
|
* cf_pop_scope() pops the topmost scope from the scope stack,
|
|
|
|
* leaving all its symbols in the symbol table, but making them
|
|
|
|
* invisible to the rest of the config.
|
|
|
|
*/
|
1999-11-04 21:51:52 +08:00
|
|
|
void
|
|
|
|
cf_pop_scope(void)
|
|
|
|
{
|
|
|
|
conf_this_scope->active = 0;
|
|
|
|
conf_this_scope = conf_this_scope->next;
|
|
|
|
ASSERT(conf_this_scope);
|
|
|
|
}
|
2000-01-19 20:30:19 +08:00
|
|
|
|
|
|
|
struct symbol *
|
|
|
|
cf_walk_symbols(struct config *cf, struct symbol *sym, int *pos)
|
|
|
|
{
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
if (!sym)
|
|
|
|
{
|
|
|
|
if (*pos >= SYM_HASH_SIZE)
|
|
|
|
return NULL;
|
|
|
|
sym = cf->sym_hash[(*pos)++];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
sym = sym->next;
|
|
|
|
if (sym && sym->scope->active)
|
|
|
|
return sym;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-06-04 02:23:00 +08:00
|
|
|
/**
|
|
|
|
* cf_symbol_class_name - get name of a symbol class
|
|
|
|
* @sym: symbol
|
|
|
|
*
|
|
|
|
* This function returns a string representing the class
|
|
|
|
* of the given symbol.
|
|
|
|
*/
|
2000-01-19 20:30:19 +08:00
|
|
|
char *
|
|
|
|
cf_symbol_class_name(struct symbol *sym)
|
|
|
|
{
|
|
|
|
switch (sym->class)
|
|
|
|
{
|
|
|
|
case SYM_VOID:
|
|
|
|
return "undefined";
|
|
|
|
case SYM_PROTO:
|
|
|
|
return "protocol";
|
|
|
|
case SYM_NUMBER:
|
|
|
|
return "numeric constant";
|
|
|
|
case SYM_FUNCTION:
|
|
|
|
return "function";
|
|
|
|
case SYM_FILTER:
|
|
|
|
return "filter";
|
|
|
|
case SYM_TABLE:
|
|
|
|
return "routing table";
|
2000-06-04 00:56:00 +08:00
|
|
|
case SYM_IPA:
|
|
|
|
return "network address";
|
2000-01-19 20:30:19 +08:00
|
|
|
default:
|
|
|
|
return "unknown type";
|
|
|
|
}
|
|
|
|
}
|
2000-06-04 23:22:20 +08:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|