Annotation of embedaddon/bird/conf/cf-lex.l, revision 1.1.1.2

1.1       misho       1: /*
                      2:  *     BIRD -- Configuration Lexer
                      3:  *
                      4:  *     (c) 1998--2000 Martin Mares <mj@ucw.cz>
                      5:  *
                      6:  *     Can be freely distributed and used under the terms of the GNU GPL.
                      7:  */
                      8: 
                      9: /**
                     10:  * DOC: Lexical analyzer
                     11:  *
                     12:  * The lexical analyzer used for configuration files and CLI commands
                     13:  * is generated using the |flex| tool accompanied by a couple of
                     14:  * functions maintaining the hash tables containing information about
                     15:  * symbols and keywords.
                     16:  *
                     17:  * Each symbol is represented by a &symbol structure containing name
                     18:  * of the symbol, its lexical scope, symbol class (%SYM_PROTO for a
                     19:  * name of a protocol, %SYM_CONSTANT for a constant etc.) and class
                     20:  * dependent data.  When an unknown symbol is encountered, it's
                     21:  * automatically added to the symbol table with class %SYM_VOID.
                     22:  *
                     23:  * The keyword tables are generated from the grammar templates
                     24:  * using the |gen_keywords.m4| script.
                     25:  */
                     26: 
                     27: %{
                     28: #undef REJECT     /* Avoid name clashes */
                     29: 
                     30: #include <errno.h>
                     31: #include <stdlib.h>
                     32: #include <stdarg.h>
                     33: #include <stdint.h>
                     34: #include <unistd.h>
                     35: #include <libgen.h>
                     36: #include <glob.h>
                     37: #include <fcntl.h>
                     38: #include <sys/stat.h>
                     39: #include <sys/types.h>
                     40: #include <sys/stat.h>
                     41: 
                     42: #define PARSER 1
                     43: 
                     44: #include "nest/bird.h"
                     45: #include "nest/route.h"
                     46: #include "nest/protocol.h"
                     47: #include "filter/filter.h"
                     48: #include "conf/conf.h"
                     49: #include "conf/cf-parse.tab.h"
                     50: #include "lib/string.h"
1.1.1.2 ! misho      51: #include "lib/hash.h"
1.1       misho      52: 
                     53: struct keyword {
                     54:   byte *name;
                     55:   int value;
                     56:   struct keyword *next;
                     57: };
                     58: 
                     59: #include "conf/keywords.h"
                     60: 
1.1.1.2 ! misho      61: /* Could be defined by Bison in cf-parse.tab.h, inteferes with SYM hash */
        !            62: #ifdef SYM
        !            63: #undef SYM
        !            64: #endif
        !            65: 
        !            66: 
        !            67: static uint cf_hash(byte *c);
        !            68: 
        !            69: #define KW_KEY(n)              n->name
        !            70: #define KW_NEXT(n)             n->next
        !            71: #define KW_EQ(a,b)             !strcmp(a,b)
        !            72: #define KW_FN(k)               cf_hash(k)
        !            73: #define KW_ORDER               8 /* Fixed */
        !            74: 
        !            75: #define SYM_KEY(n)             n->name, n->scope->active
        !            76: #define SYM_NEXT(n)            n->next
        !            77: #define SYM_EQ(a,s1,b,s2)      !strcmp(a,b) && s1 == s2
        !            78: #define SYM_FN(k,s)            cf_hash(k)
        !            79: #define SYM_ORDER              6 /* Initial */
1.1       misho      80: 
1.1.1.2 ! misho      81: #define SYM_REHASH             sym_rehash
        !            82: #define SYM_PARAMS             /8, *1, 2, 2, 6, 20
        !            83: 
        !            84: 
        !            85: HASH_DEFINE_REHASH_FN(SYM, struct symbol)
        !            86: 
        !            87: HASH(struct keyword) kw_hash;
        !            88: 
        !            89: 
        !            90: static struct sym_scope *conf_this_scope;
1.1       misho      91: 
                     92: linpool *cfg_mem;
                     93: 
                     94: int (*cf_read_hook)(byte *buf, unsigned int max, int fd);
                     95: struct include_file_stack *ifs;
                     96: static struct include_file_stack *ifs_head;
                     97: 
                     98: #define MAX_INCLUDE_DEPTH 8
                     99: 
                    100: #define YY_INPUT(buf,result,max) result = cf_read_hook(buf, max, ifs->fd);
                    101: #define YY_NO_UNPUT
                    102: #define YY_FATAL_ERROR(msg) cf_error(msg)
1.1.1.2 ! misho     103: #define YY_USER_ACTION ifs->chno += yyleng; ifs->toklen = yyleng;
1.1       misho     104: 
                    105: static void cf_include(char *arg, int alen);
                    106: static int check_eof(void);
                    107: 
                    108: %}
                    109: 
                    110: %option noyywrap
                    111: %option noinput
                    112: %option nounput
                    113: %option noreject
                    114: 
                    115: %x COMMENT CCOMM CLI
                    116: 
                    117: ALPHA [a-zA-Z_]
                    118: DIGIT [0-9]
                    119: XIGIT [0-9a-fA-F]
                    120: ALNUM [a-zA-Z_0-9]
                    121: WHITE [ \t]
                    122: include   ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
                    123: 
                    124: %%
                    125: {include} {
                    126:   char *start, *end;
                    127: 
                    128:   if (!ifs->depth)
                    129:     cf_error("Include not allowed in CLI");
                    130: 
                    131:   start = strchr(yytext, '"');
                    132:   start++;
                    133: 
                    134:   end = strchr(start, '"');
                    135:   *end = 0;
                    136: 
                    137:   if (start == end)
                    138:     cf_error("Include with empty argument");
                    139: 
                    140:   cf_include(start, end-start);
                    141: }
                    142: 
                    143: {DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+ {
                    144:   ip4_addr a;
                    145:   if (!ip4_pton(yytext, &a))
                    146:     cf_error("Invalid IPv4 address %s", yytext);
                    147: 
                    148: #ifdef IPV6
                    149:   cf_lval.i32 = ip4_to_u32(a);
                    150:   return RTRID;
                    151: #else
                    152:   cf_lval.a = ipa_from_ip4(a);
                    153:   return IPA;
                    154: #endif
                    155: }
                    156: 
                    157: ({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) {
                    158: #ifdef IPV6
                    159:   if (ipa_pton(yytext, &cf_lval.a))
                    160:     return IPA;
                    161:   cf_error("Invalid IPv6 address %s", yytext);
                    162: #else
                    163:   cf_error("This is an IPv4 router, therefore IPv6 addresses are not supported");
                    164: #endif
                    165: }
                    166: 
                    167: 0x{XIGIT}+ {
                    168:   char *e;
                    169:   unsigned long int l;
                    170:   errno = 0;
                    171:   l = strtoul(yytext+2, &e, 16);
                    172:   if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
                    173:     cf_error("Number out of range");
                    174:   cf_lval.i = l;
                    175:   return NUM;
                    176: }
                    177: 
                    178: {DIGIT}+ {
                    179:   char *e;
                    180:   unsigned long int l;
                    181:   errno = 0;
                    182:   l = strtoul(yytext, &e, 10);
                    183:   if (e && *e || errno == ERANGE || (unsigned long int)(unsigned int) l != l)
                    184:     cf_error("Number out of range");
                    185:   cf_lval.i = l;
                    186:   return NUM;
                    187: }
                    188: 
                    189: else: {
                    190:   /* Hack to distinguish if..else from else: in case */
                    191:   return ELSECOL;
                    192: }
                    193: 
                    194: ({ALPHA}{ALNUM}*|[']({ALNUM}|[-]|[\.]|[:])*[']) {
                    195:   if(*yytext == '\'') {
                    196:     yytext[yyleng-1] = 0;
                    197:     yytext++;
                    198:   }
1.1.1.2 ! misho     199: 
        !           200:   struct keyword *k = HASH_FIND(kw_hash, KW, yytext);
        !           201:   if (k)
        !           202:   {
        !           203:     if (k->value > 0)
        !           204:       return k->value;
        !           205:     else
1.1       misho     206:     {
1.1.1.2 ! misho     207:       cf_lval.i = -k->value;
        !           208:       return ENUM;
1.1       misho     209:     }
1.1.1.2 ! misho     210:   }
        !           211: 
        !           212:   cf_lval.s = cf_get_symbol(yytext);
1.1       misho     213:   return SYM;
                    214: }
                    215: 
                    216: <CLI>(.|\n) {
                    217:   BEGIN(INITIAL);
                    218:   return CLI_MARKER;
                    219: }
                    220: 
                    221: \.\. {
                    222:   return DDOT;
                    223: }
                    224: 
                    225: [={}:;,.()+*/%<>~\[\]?!\|-] {
                    226:   return yytext[0];
                    227: }
                    228: 
                    229: ["][^"\n]*["] {
                    230:   yytext[yyleng-1] = 0;
                    231:   cf_lval.t = cfg_strdup(yytext+1);
                    232:   return TEXT;
                    233: }
                    234: 
                    235: ["][^"\n]*\n   cf_error("Unterminated string");
                    236: 
                    237: <INITIAL,COMMENT><<EOF>>       { if (check_eof()) return END; }
                    238: 
                    239: {WHITE}+
                    240: 
1.1.1.2 ! misho     241: \n     ifs->lino++; ifs->chno = 0;
1.1       misho     242: 
                    243: #      BEGIN(COMMENT);
                    244: 
                    245: \/\*   BEGIN(CCOMM);
                    246: 
                    247: .      cf_error("Unknown character");
                    248: 
                    249: <COMMENT>\n {
                    250:   ifs->lino++;
1.1.1.2 ! misho     251:   ifs->chno = 0;
1.1       misho     252:   BEGIN(INITIAL);
                    253: }
                    254: 
                    255: <COMMENT>.
                    256: 
                    257: <CCOMM>\*\/    BEGIN(INITIAL);
1.1.1.2 ! misho     258: <CCOMM>\n      ifs->lino++; ifs->chno = 0;
1.1       misho     259: <CCOMM>\/\*    cf_error("Comment nesting not supported");
                    260: <CCOMM><<EOF>> cf_error("Unterminated comment");
                    261: <CCOMM>.
                    262: 
                    263: \!\= return NEQ;
                    264: \!\~ return NMA;
                    265: \<\= return LEQ;
                    266: \>\= return GEQ;
                    267: \&\& return AND;
                    268: \|\| return OR;
                    269: 
                    270: \[\= return PO;
                    271: \=\] return PC;
                    272: 
                    273: %%
                    274: 
1.1.1.2 ! misho     275: static uint
1.1       misho     276: cf_hash(byte *c)
                    277: {
1.1.1.2 ! misho     278:   uint h = 13 << 24;
1.1       misho     279: 
                    280:   while (*c)
1.1.1.2 ! misho     281:     h = h + (h >> 2) + (h >> 5) + ((uint) *c++ << 24);
1.1       misho     282:   return h;
                    283: }
                    284: 
                    285: 
                    286: /*
                    287:  * IFS stack - it contains structures needed for recursive processing
                    288:  * of include in config files. On the top of the stack is a structure
                    289:  * for currently processed file. Other structures are either for
                    290:  * active files interrupted because of include directive (these have
                    291:  * fd and flex buffer) or for inactive files scheduled to be processed
                    292:  * later (when parent requested including of several files by wildcard
                    293:  * match - these do not have fd and flex buffer yet).
                    294:  *
                    295:  * FIXME: Most of these ifs and include functions are really sysdep/unix.
                    296:  */
                    297: 
                    298: static struct include_file_stack *
                    299: push_ifs(struct include_file_stack *old)
                    300: {
                    301:   struct include_file_stack *ret;
                    302:   ret = cfg_allocz(sizeof(struct include_file_stack));
                    303:   ret->lino = 1;
                    304:   ret->prev = old;
                    305:   return ret;
                    306: }
                    307: 
                    308: static struct include_file_stack *
                    309: pop_ifs(struct include_file_stack *old)
                    310: {
                    311:  yy_delete_buffer(old->buffer);
                    312:  close(old->fd);
                    313:  return old->prev;
                    314: }
                    315: 
                    316: static void
                    317: enter_ifs(struct include_file_stack *new)
                    318: {
                    319:   if (!new->buffer)
                    320:     {
                    321:       new->fd = open(new->file_name, O_RDONLY);
                    322:       if (new->fd < 0)
                    323:         {
                    324:           ifs = ifs->up;
                    325:          cf_error("Unable to open included file %s: %m", new->file_name);
                    326:         }
                    327: 
                    328:       new->buffer = yy_create_buffer(NULL, YY_BUF_SIZE);
                    329:     }
                    330: 
                    331:   yy_switch_to_buffer(new->buffer);
                    332: }
                    333: 
                    334: /**
                    335:  * cf_lex_unwind - unwind lexer state during error
                    336:  *
                    337:  * cf_lex_unwind() frees the internal state on IFS stack when the lexical
                    338:  * analyzer is terminated by cf_error().
                    339:  */
                    340: void
                    341: cf_lex_unwind(void)
                    342: {
                    343:   struct include_file_stack *n;
                    344: 
                    345:   for (n = ifs; n != ifs_head; n = n->prev)
                    346:     {
                    347:       /* Memory is freed automatically */
                    348:       if (n->buffer)
                    349:        yy_delete_buffer(n->buffer);
                    350:       if (n->fd)
                    351:         close(n->fd);
                    352:     }
                    353: 
                    354:   ifs = ifs_head;
                    355: }
                    356: 
                    357: static void
                    358: cf_include(char *arg, int alen)
                    359: {
                    360:   struct include_file_stack *base_ifs = ifs;
                    361:   int new_depth, rv, i;
                    362:   char *patt;
                    363:   glob_t g = {};
                    364: 
                    365:   new_depth = ifs->depth + 1;
                    366:   if (new_depth > MAX_INCLUDE_DEPTH)
                    367:     cf_error("Max include depth reached");
                    368: 
                    369:   /* expand arg to properly handle relative filenames */
                    370:   if (*arg != '/')
                    371:     {
                    372:       int dlen = strlen(ifs->file_name);
                    373:       char *dir = alloca(dlen + 1);
                    374:       patt = alloca(dlen + alen + 2);
                    375:       memcpy(dir, ifs->file_name, dlen + 1);
                    376:       sprintf(patt, "%s/%s", dirname(dir), arg);
                    377:     }
                    378:   else
                    379:     patt = arg;
                    380: 
                    381:   /* Skip globbing if there are no wildcards, mainly to get proper
                    382:      response when the included config file is missing */
                    383:   if (!strpbrk(arg, "?*["))
                    384:     {
                    385:       ifs = push_ifs(ifs);
                    386:       ifs->file_name = cfg_strdup(patt);
                    387:       ifs->depth = new_depth;
                    388:       ifs->up = base_ifs;
                    389:       enter_ifs(ifs);
                    390:       return;
                    391:     }
                    392: 
                    393:   /* Expand the pattern */
                    394:   rv = glob(patt, GLOB_ERR | GLOB_NOESCAPE, NULL, &g);
                    395:   if (rv == GLOB_ABORTED)
                    396:     cf_error("Unable to match pattern %s: %m", patt);
                    397:   if ((rv != 0) || (g.gl_pathc <= 0))
                    398:     return;
                    399: 
                    400:   /*
                    401:    * Now we put all found files to ifs stack in reverse order, they
                    402:    * will be activated and processed in order as ifs stack is popped
                    403:    * by pop_ifs() and enter_ifs() in check_eof().
                    404:    */
                    405:   for(i = g.gl_pathc - 1; i >= 0; i--)
                    406:     {
                    407:       char *fname = g.gl_pathv[i];
                    408:       struct stat fs;
                    409: 
                    410:       if (stat(fname, &fs) < 0)
                    411:        {
                    412:          globfree(&g);
                    413:          cf_error("Unable to stat included file %s: %m", fname);
                    414:        }
                    415: 
                    416:       if (fs.st_mode & S_IFDIR)
                    417:         continue;
                    418: 
                    419:       /* Prepare new stack item */
                    420:       ifs = push_ifs(ifs);
                    421:       ifs->file_name = cfg_strdup(fname);
                    422:       ifs->depth = new_depth;
                    423:       ifs->up = base_ifs;
                    424:     }
                    425: 
                    426:   globfree(&g);
                    427:   enter_ifs(ifs);
                    428: }
                    429: 
                    430: static int
                    431: check_eof(void)
                    432: {
                    433:   if (ifs == ifs_head)
                    434:     {
                    435:       /* EOF in main config file */
                    436:       ifs->lino = 1; /* Why this? */
                    437:       return 1;
                    438:     }
                    439: 
                    440:   ifs = pop_ifs(ifs);
                    441:   enter_ifs(ifs);
                    442:   return 0;
                    443: }
                    444: 
                    445: static struct symbol *
1.1.1.2 ! misho     446: cf_new_symbol(byte *c)
1.1       misho     447: {
1.1.1.2 ! misho     448:   struct symbol *s;
        !           449: 
        !           450:   uint l = strlen(c);
1.1       misho     451:   if (l > SYM_MAX_LEN)
                    452:     cf_error("Symbol too long");
1.1.1.2 ! misho     453: 
1.1       misho     454:   s = cfg_alloc(sizeof(struct symbol) + l);
                    455:   s->scope = conf_this_scope;
                    456:   s->class = SYM_VOID;
                    457:   s->def = NULL;
                    458:   s->aux = 0;
                    459:   strcpy(s->name, c);
                    460: 
1.1.1.2 ! misho     461:   if (!new_config->sym_hash.data)
        !           462:     HASH_INIT(new_config->sym_hash, new_config->pool, SYM_ORDER);
1.1       misho     463: 
1.1.1.2 ! misho     464:   HASH_INSERT2(new_config->sym_hash, SYM, new_config->pool, s);
1.1       misho     465: 
1.1.1.2 ! misho     466:   return s;
1.1       misho     467: }
                    468: 
                    469: /**
                    470:  * cf_find_symbol - find a symbol by name
                    471:  * @cfg: specificed config
                    472:  * @c: symbol name
                    473:  *
                    474:  * This functions searches the symbol table in the config @cfg for a symbol of
                    475:  * given name. First it examines the current scope, then the second recent one
                    476:  * and so on until it either finds the symbol and returns a pointer to its
                    477:  * &symbol structure or reaches the end of the scope chain and returns %NULL to
                    478:  * signify no match.
                    479:  */
                    480: struct symbol *
                    481: cf_find_symbol(struct config *cfg, byte *c)
                    482: {
1.1.1.2 ! misho     483:   struct symbol *s;
        !           484: 
        !           485:   if (cfg->sym_hash.data &&
        !           486:       (s = HASH_FIND(cfg->sym_hash, SYM, c, 1)))
        !           487:     return s;
        !           488: 
        !           489:   if (cfg->fallback &&
        !           490:       cfg->fallback->sym_hash.data &&
        !           491:       (s = HASH_FIND(cfg->fallback->sym_hash, SYM, c, 1)))
        !           492:     return s;
        !           493: 
        !           494:   return NULL;
1.1       misho     495: }
                    496: 
                    497: /**
                    498:  * cf_get_symbol - get a symbol by name
                    499:  * @c: symbol name
                    500:  *
                    501:  * This functions searches the symbol table of the currently parsed config
                    502:  * (@new_config) for a symbol of given name. It returns either the already
                    503:  * existing symbol or a newly allocated undefined (%SYM_VOID) symbol if no
                    504:  * existing symbol is found.
                    505:  */
                    506: struct symbol *
                    507: cf_get_symbol(byte *c)
                    508: {
1.1.1.2 ! misho     509:   return cf_find_symbol(new_config, c) ?: cf_new_symbol(c);
1.1       misho     510: }
                    511: 
                    512: struct symbol *
                    513: cf_default_name(char *template, int *counter)
                    514: {
                    515:   char buf[SYM_MAX_LEN];
                    516:   struct symbol *s;
                    517:   char *perc = strchr(template, '%');
                    518: 
                    519:   for(;;)
                    520:     {
                    521:       bsprintf(buf, template, ++(*counter));
1.1.1.2 ! misho     522:       s = cf_get_symbol(buf);
1.1       misho     523:       if (s->class == SYM_VOID)
                    524:        return s;
                    525:       if (!perc)
                    526:        break;
                    527:     }
                    528:   cf_error("Unable to generate default name");
                    529: }
                    530: 
                    531: /**
                    532:  * cf_define_symbol - define meaning of a symbol
                    533:  * @sym: symbol to be defined
                    534:  * @type: symbol class to assign
                    535:  * @def: class dependent data
                    536:  *
                    537:  * Defines new meaning of a symbol. If the symbol is an undefined
                    538:  * one (%SYM_VOID), it's just re-defined to the new type. If it's defined
                    539:  * in different scope, a new symbol in current scope is created and the
                    540:  * meaning is assigned to it. If it's already defined in the current scope,
                    541:  * an error is reported via cf_error().
                    542:  *
                    543:  * Result: Pointer to the newly defined symbol. If we are in the top-level
                    544:  * scope, it's the same @sym as passed to the function.
                    545:  */
                    546: struct symbol *
                    547: cf_define_symbol(struct symbol *sym, int type, void *def)
                    548: {
                    549:   if (sym->class)
                    550:     {
                    551:       if (sym->scope == conf_this_scope)
                    552:        cf_error("Symbol already defined");
1.1.1.2 ! misho     553:       sym = cf_new_symbol(sym->name);
1.1       misho     554:     }
                    555:   sym->class = type;
                    556:   sym->def = def;
                    557:   return sym;
                    558: }
                    559: 
                    560: static void
                    561: cf_lex_init_kh(void)
                    562: {
1.1.1.2 ! misho     563:   HASH_INIT(kw_hash, &root_pool, KW_ORDER);
1.1       misho     564: 
1.1.1.2 ! misho     565:   struct keyword *k;
        !           566:   for (k=keyword_list; k->name; k++)
        !           567:     HASH_INSERT(kw_hash, KW, k);
1.1       misho     568: }
                    569: 
                    570: /**
                    571:  * cf_lex_init - initialize the lexer
                    572:  * @is_cli: true if we're going to parse CLI command, false for configuration
                    573:  * @c: configuration structure
                    574:  *
                    575:  * cf_lex_init() initializes the lexical analyzer and prepares it for
                    576:  * parsing of a new input.
                    577:  */
                    578: void
                    579: cf_lex_init(int is_cli, struct config *c)
                    580: {
1.1.1.2 ! misho     581:   if (!kw_hash.data)
1.1       misho     582:     cf_lex_init_kh();
                    583: 
                    584:   ifs_head = ifs = push_ifs(NULL);
                    585:   if (!is_cli)
                    586:     {
                    587:       ifs->file_name = c->file_name;
                    588:       ifs->fd = c->file_fd;
                    589:       ifs->depth = 1;
                    590:     }
                    591: 
                    592:   yyrestart(NULL);
                    593:   ifs->buffer = YY_CURRENT_BUFFER;
                    594: 
                    595:   if (is_cli)
                    596:     BEGIN(CLI);
                    597:   else
                    598:     BEGIN(INITIAL);
                    599: 
                    600:   conf_this_scope = cfg_allocz(sizeof(struct sym_scope));
                    601:   conf_this_scope->active = 1;
                    602: }
                    603: 
                    604: /**
                    605:  * cf_push_scope - enter new scope
                    606:  * @sym: symbol representing scope name
                    607:  *
                    608:  * If we want to enter a new scope to process declarations inside
                    609:  * a nested block, we can just call cf_push_scope() to push a new
                    610:  * scope onto the scope stack which will cause all new symbols to be
                    611:  * defined in this scope and all existing symbols to be sought for
                    612:  * in all scopes stored on the stack.
                    613:  */
                    614: void
                    615: cf_push_scope(struct symbol *sym)
                    616: {
                    617:   struct sym_scope *s = cfg_alloc(sizeof(struct sym_scope));
                    618: 
                    619:   s->next = conf_this_scope;
                    620:   conf_this_scope = s;
                    621:   s->active = 1;
                    622:   s->name = sym;
                    623: }
                    624: 
                    625: /**
                    626:  * cf_pop_scope - leave a scope
                    627:  *
                    628:  * cf_pop_scope() pops the topmost scope from the scope stack,
                    629:  * leaving all its symbols in the symbol table, but making them
                    630:  * invisible to the rest of the config.
                    631:  */
                    632: void
                    633: cf_pop_scope(void)
                    634: {
                    635:   conf_this_scope->active = 0;
                    636:   conf_this_scope = conf_this_scope->next;
                    637:   ASSERT(conf_this_scope);
                    638: }
                    639: 
                    640: /**
                    641:  * cf_symbol_class_name - get name of a symbol class
                    642:  * @sym: symbol
                    643:  *
                    644:  * This function returns a string representing the class
                    645:  * of the given symbol.
                    646:  */
                    647: char *
                    648: cf_symbol_class_name(struct symbol *sym)
                    649: {
                    650:   if (cf_symbol_is_constant(sym))
                    651:     return "constant";
                    652: 
                    653:   switch (sym->class)
                    654:     {
                    655:     case SYM_VOID:
                    656:       return "undefined";
                    657:     case SYM_PROTO:
                    658:       return "protocol";
                    659:     case SYM_TEMPLATE:
                    660:       return "protocol template";
                    661:     case SYM_FUNCTION:
                    662:       return "function";
                    663:     case SYM_FILTER:
                    664:       return "filter";
                    665:     case SYM_TABLE:
                    666:       return "routing table";
                    667:     case SYM_ROA:
                    668:       return "ROA table";
                    669:     default:
                    670:       return "unknown type";
                    671:     }
                    672: }
                    673: 
                    674: 
                    675: /**
                    676:  * DOC: Parser
                    677:  *
                    678:  * Both the configuration and CLI commands are analyzed using a syntax
                    679:  * driven parser generated by the |bison| tool from a grammar which
                    680:  * is constructed from information gathered from grammar snippets by
                    681:  * the |gen_parser.m4| script.
                    682:  *
                    683:  * Grammar snippets are files (usually with extension |.Y|) contributed
                    684:  * by various BIRD modules in order to provide information about syntax of their
                    685:  * configuration and their CLI commands. Each snipped consists of several
                    686:  * sections, each of them starting with a special keyword: |CF_HDR| for
                    687:  * a list of |#include| directives needed by the C code, |CF_DEFINES|
                    688:  * for a list of C declarations, |CF_DECLS| for |bison| declarations
                    689:  * including keyword definitions specified as |CF_KEYWORDS|, |CF_GRAMMAR|
                    690:  * for the grammar rules, |CF_CODE| for auxiliary C code and finally
                    691:  * |CF_END| at the end of the snippet.
                    692:  *
                    693:  * To create references between the snippets, it's possible to define
                    694:  * multi-part rules by utilizing the |CF_ADDTO| macro which adds a new
                    695:  * alternative to a multi-part rule.
                    696:  *
                    697:  * CLI commands are defined using a |CF_CLI| macro. Its parameters are:
                    698:  * the list of keywords determining the command, the list of parameters,
                    699:  * help text for the parameters and help text for the command.
                    700:  *
                    701:  * Values of |enum| filter types can be defined using |CF_ENUM| with
                    702:  * the following parameters: name of filter type, prefix common for all
                    703:  * literals of this type and names of all the possible values.
                    704:  */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>