openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

api_mode.c (10668B)


      1 /* 
      2  * 
      3  * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file.
      4  * 
      5  * Copyright 2007-2019 Broadcom Inc. All rights reserved.
      6  *
      7  * File:        api_mode.c
      8  * Purpose:     API mode grammar implementation
      9  */
     10 
     11 #include "sal/core/alloc.h"
     12 #include "sal/core/libc.h"
     13 #include "sal/appl/io.h"
     14 #include "tokenizer.h"
     15 #include "context.h"
     16 #include "completion.h"
     17 #include "api_mode_yy.h"
     18 #include "api_grammar.tab.h"
     19 
     20 
     21 /*
     22  * API Mode grammar handler functions
     23  */
     24 
     25 
     26 /* allocate a grammar node */
     27 STATIC api_mode_arg_t *
     28 alloc_node(api_mode_parse_t *prs,
     29            const char *value, int kind,
     30            api_mode_token_t *token, const cint_datatype_t *dt)
     31 {
     32     api_mode_arg_t *arg;
     33 
     34     arg = sal_alloc(sizeof(*arg),"api_mode");
     35     if (!arg) {
     36         return NULL;
     37     }
     38     sal_memset(arg,0,sizeof(*arg));
     39     arg->kind = kind;
     40     arg->value = sal_strdup(value);
     41     arg->token = token;
     42     arg->dt = dt;
     43     arg->mm = prs->root;
     44     prs->root = arg;
     45     if (prs->base == NULL) {
     46         prs->base = arg;
     47     }
     48 
     49     return arg;
     50 }
     51 
     52 /* free a grammar node */
     53 STATIC void
     54 free_node(api_mode_arg_t *arg)
     55 {
     56     sal_free((void *)arg->value);
     57     sal_memset(arg, 0, sizeof(*arg));
     58     sal_free(arg);
     59 }
     60 
     61 /* free a list of grammar nodes */
     62 STATIC void
     63 free_node_list(api_mode_arg_t *arg)
     64 {
     65     api_mode_arg_t *next; 
     66     while (arg) {
     67         next = arg->mm;
     68         free_node(arg);
     69         arg = next;
     70     }
     71 }
     72 
     73 /* return a string corresponding to a node kind id */
     74 STATIC char *
     75 node_kind(int x)
     76 {
     77     char *s = "???";
     78     
     79     switch (x) {
     80         case IDENT: s="IDENT"; break;
     81         case KEY: s="KEY"; break;
     82         case CONSTANT: s="CONSTANT"; break;
     83         case AGGREGATE: s="{}"; break;
     84         case PROMPT: s="PROMPT"; break;
     85         case EMPTY: s="<>"; break;
     86         case KEY_VALUE: s="="; break;
     87         case RANGE: s="RANGE"; break;
     88         case ITEM: s="ITEM"; break;
     89         case ASSIGN: s="ASSIGN"; break;
     90         case VALUE: s="VALUE"; break;
     91         case PRINT: s="PRINT"; break;
     92         case VAR: s="VAR"; break;
     93         case CREATE: s="CREATE"; break;
     94         case '!': s="INFO"; break;
     95         case '=': s="="; break;
     96         case ';': s=";"; break;
     97         case '?': s="?"; break;
     98         case '.': s="."; break;
     99         case ',': s=","; break;
    100         case '{': s="{"; break;
    101         case '}': s="}"; break;
    102     }
    103 
    104     return s;
    105 }
    106 
    107 /* print node information */
    108 STATIC void
    109 show_node(int indent, api_mode_arg_t *arg)
    110 {
    111     sal_printf("%*s%s %s %s\n",
    112                indent*2,"",
    113                node_kind(arg->kind),
    114                arg->value,
    115                arg->flags&IS_FIRST?"+":"");
    116 }
    117 
    118 /* set the parent for a list of child nodes */
    119 STATIC void
    120 set_parent(api_mode_arg_t *arg, api_mode_arg_t *parent)
    121 {
    122     for (; arg; arg=arg->next) {
    123         arg->parent = parent;
    124     }
    125 }
    126 
    127 /* print node information for a tree of nodes */
    128 void
    129 api_mode_show(int indent, api_mode_arg_t *start)
    130 {
    131     api_mode_arg_t *arg;
    132 
    133     for (arg=start; arg; arg=arg->next) {
    134         show_node(indent,arg);
    135         if (arg->sub) {
    136             api_mode_show(indent+1, arg->sub);
    137         }
    138     }
    139 }
    140 
    141 /* allocate a node of a certain kind with a value */
    142 api_mode_arg_t *
    143 api_mode_node(void *prs, const char *value, int kind)
    144 {
    145     return alloc_node((api_mode_parse_t *)prs, value, kind, NULL, NULL);
    146 }
    147 
    148 /* execute a grammar tree via a parser callback */
    149 api_mode_arg_t *
    150 api_mode_execute(void *p, api_mode_arg_t *arg)
    151 {
    152     api_mode_parse_t *prs = (api_mode_parse_t *)p;
    153 
    154     if (prs->verbose) {
    155         prs->result = prs->callback(arg, prs->user_data);
    156     }
    157     
    158     return arg;
    159 }
    160 
    161 /* set node flags */
    162 api_mode_arg_t *
    163 api_mode_mark(api_mode_arg_t *arg, int flag)
    164 {
    165     arg->flags |= flag;
    166 
    167     return arg;
    168 }
    169 
    170 /* set 'sec' as a sublist of 'pri' */
    171 api_mode_arg_t *
    172 api_mode_sub(api_mode_arg_t *pri, api_mode_arg_t *sec)
    173 {
    174     pri->sub = sec;
    175     set_parent(sec, pri);
    176 
    177     return pri;
    178 }
    179 
    180 /* create a key/value node */
    181 api_mode_arg_t *
    182 api_mode_key_value(api_mode_arg_t *key, api_mode_arg_t *value)
    183 {
    184     key->kind = KEY_VALUE;
    185     api_mode_sub(key, value);
    186     return key;
    187 }
    188 
    189 /* create a range node */
    190 api_mode_arg_t *
    191 api_mode_range(api_mode_arg_t *from, api_mode_arg_t *to,
    192                api_mode_arg_t *times, api_mode_arg_t *incr)
    193 {
    194     from->kind = RANGE;
    195     api_mode_append(incr, times);
    196     api_mode_append(times, to);
    197     api_mode_sub(from, to);
    198     return from;
    199 }
    200 
    201 /* append 'arg' to node list 'src' */
    202 api_mode_arg_t *
    203 api_mode_append(api_mode_arg_t *src, api_mode_arg_t *arg)
    204 {
    205     api_mode_arg_t *target;
    206 
    207     for (target=src; target->next; target=target->next) {
    208         if (target == target->next) {
    209             (void)api_mode_unexpected();
    210             break;
    211         }
    212     }
    213 
    214     target->next = arg;
    215     if (src->parent != NULL && arg->parent == NULL) {
    216         arg->parent = src->parent;
    217     }
    218 
    219     return src;
    220 }
    221 
    222 /* append 'arg' to child node list of 'src' */
    223 api_mode_arg_t *
    224 api_mode_sub_append(api_mode_arg_t *src, api_mode_arg_t *arg)
    225 {
    226     if (src->sub == NULL) {
    227         src->sub = arg;
    228     } else {
    229         api_mode_append(src->sub, arg);
    230     }
    231     set_parent(arg, src);
    232 
    233     return src;
    234 }
    235 
    236 /* display a parse error */
    237 void
    238 api_mode_error(yyltype *loc, yyscan_t yyscanner, void *p, char const *s)
    239 {
    240     api_mode_parse_t *prs = (api_mode_parse_t *)p;
    241 
    242     COMPILER_REFERENCE(loc);
    243     COMPILER_REFERENCE(yyscanner);
    244     sal_printf("%s\n", s);
    245     prs->done = 1;
    246 }
    247 
    248 /* return the next node after 'arg'. if arg is the last child node,
    249    recurse back up to the next parent node. */
    250 api_mode_arg_t *
    251 api_mode_arg_next(api_mode_arg_t *arg)
    252 {
    253     api_mode_arg_t *next = NULL;
    254 
    255     if (arg->next) {
    256         next = arg->next;
    257     } else if (arg->parent) {
    258         next = api_mode_arg_next(arg->parent);
    259     }
    260 
    261     return next;
    262 }
    263 
    264 
    265 /* Pull parser lex function -
    266    not used, but still referenced by the pull parser */
    267 
    268 int
    269 api_mode_lex(YYSTYPE *lvalp, YYLTYPE *llocp, yyscan_t scanner)
    270 {
    271     COMPILER_REFERENCE(lvalp);
    272     COMPILER_REFERENCE(llocp);
    273     COMPILER_REFERENCE(scanner);
    274 
    275     return api_mode_unexpected();
    276 }
    277 
    278 /* show scanner tokens for diagnostic purposes */
    279 STATIC void
    280 show_scanner_tokens(yyscan_t scanner, api_mode_context_t *ctx)
    281 {
    282     int i;
    283 
    284     for (i=0; i<scanner->tok.len; i++) {
    285         sal_printf("%s ", node_kind(ctx->info[i].grammar_type));
    286     }
    287     sal_printf("\n");
    288 }
    289    
    290 /*
    291  *
    292  * API Mode parser
    293  */
    294 
    295 /*
    296   parse the output of the scanner
    297  */
    298 STATIC int
    299 api_mode_parser(yyscan_t scanner, api_mode_context_t *ctx, int flags,
    300                 api_mode_arg_cb_t cb, void *user_data)
    301 {
    302     int status;
    303     api_mode_pstate *ps;
    304     enum yytokentype code;
    305     api_mode_parse_t parser;
    306     api_mode_arg_t *yylval;
    307     yyltype_t yylloc;
    308     api_mode_token_t *token;
    309     const cint_datatype_t *dt;
    310 
    311     /* Setup parser context */
    312     sal_memset(&parser, 0, sizeof(parser));
    313 
    314     if (flags & PARSE_VERBOSE) {
    315         parser.verbose = 1;
    316     }
    317 
    318     if (flags & PARSE_DEBUG) {
    319         api_mode_debug = 1;
    320     }
    321 
    322     parser.callback = cb;
    323     parser.user_data = user_data;
    324     scanner->idx = 0;
    325     status = 0;
    326 
    327     if (api_mode_debug) {
    328         show_scanner_tokens(scanner, ctx);
    329     }
    330     /* Call scanner and parser */
    331     ps = api_mode_pstate_new();
    332     do {
    333         if (scanner->idx < scanner->tok.len) {
    334             token = &scanner->tok.token[scanner->idx];
    335             code = ctx->info[scanner->idx].grammar_type;
    336             dt = ctx->info[scanner->idx].dt;
    337             yylval = alloc_node(&parser, token->str, code, token, dt);
    338             if (yylval == NULL) {
    339                 status = API_MODE_E_FAIL;
    340                 break;
    341             }
    342             /* location */
    343             yylloc.first_line   = token->first_line;
    344             yylloc.first_column = token->first_column;
    345             yylloc.last_line    = token->last_line;
    346             yylloc.last_column  = token->last_column;
    347             /* next token */
    348             scanner->idx++;
    349         } else {
    350             /* no more tokens; signal end-of-input */
    351             code = 0;
    352             yylval = NULL;
    353             yylloc.first_line   = -1;
    354             yylloc.first_column = -1;
    355             yylloc.last_line    = -1;
    356             yylloc.last_column  = -1;
    357         }
    358 
    359         status = api_mode_push_parse(ps, code, &yylval, &yylloc,
    360                                      scanner, &parser);
    361         
    362     } while (status == YYPUSH_MORE);
    363     api_mode_pstate_delete(ps);
    364 
    365     /* free resources */
    366     free_node_list(parser.root);
    367 
    368     if (scanner->idx < scanner->tok.len) {
    369         printf("api_mode_parser: %d tokens left over\n",
    370                scanner->tok.len-scanner->idx);
    371     }
    372     
    373     return status;
    374 }
    375 
    376 /*
    377   Parse an API mode string. This is the top level interface to the
    378   API mode parser.
    379 
    380   The string 'input' is parsed, and the callback is called when the
    381   parse input is exhausted.
    382 
    383   In practice, this function is called either in some sort of
    384   completion context, where the callback is used to facilitate command
    385   or argument completion, or an execution context, where the callback
    386   is used to execute the parsed string.
    387 
    388   In principle, it's possible to reuse parse information from a
    389   completion, it's not clear that it's worth the complexity, so
    390   completion and execution are considered separate contexts, where
    391   completion just facilitates building up the command line, and
    392   execution parses the final result. This assumes that parsing is not
    393   very expensive. If it is, then some sort of caching between completion
    394   and execution will be needed.
    395   
    396  */
    397 int
    398 api_mode_parse_string(const char *input, int flags,
    399                       api_mode_arg_cb_t cb,
    400                       void *user_data)
    401 {
    402     int rv = API_MODE_E_FAIL;
    403     api_mode_scanner_t scan;
    404     api_mode_context_t ctx;
    405     api_mode_completion_type_t ctype;
    406 
    407     rv = api_mode_tokenizer(input, &scan.tok);
    408     if (!rv) {
    409         /* tokenized OK, now contextualize */
    410         if (scan.tok.len > 0) {
    411             rv = api_mode_contextualizer(&scan.tok, &ctx);
    412             if (!rv) {
    413                 /* ignore errors at this point, because if the parser errors
    414                    out, don't pass the command to the shell. */
    415                 ctype = api_mode_completion_set(api_mode_completion_none);
    416                 (void)api_mode_parser(&scan, &ctx, flags, cb, user_data);
    417                 (void)api_mode_completion_set(ctype);
    418             }
    419             api_mode_contextualizer_free(&ctx);
    420         }
    421     }
    422 
    423     (void)api_mode_tokenizer_free(&scan.tok);
    424 
    425     return rv;
    426 }
    427 
    428 /* called for unexpected conditions */
    429 int
    430 api_mode_unexpected(void)
    431 {
    432     sal_printf("Unexpected condition.\n");
    433 
    434     return API_MODE_E_INTERNAL;
    435 }
    436