Annotation of embedaddon/bird2/conf/cf-lex.l, revision 1.1.1.1

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

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