cparser_result_t cparser_run(cparser_t *parser) { int ch; cparser_char_t ch_type = 0; if (!VALID_PARSER(parser)) return CPARSER_ERR_INVALID_PARAMS; parser->cfg.io_init(parser); cparser_print_prompt(parser); parser->done = 0; while (!parser->done) { parser->cfg.getch(parser, &ch, &ch_type); cparser_input(parser, ch, ch_type); } /* while not done */ parser->cfg.io_cleanup(parser); return CPARSER_OK; }
/** * \brief If the command is not complete, attempt to complete the *command. * If there is a complete comamnd, execute the glue (& action) * function of a command. * * \param parser Pointer to the parser structure. * * \return CPARSER_OK if a valid command is executed; CPARSER_NOT_OK * otherwise. */ static cparser_result_t cparser_execute_cmd(cparser_t *parser) { int do_echo; cparser_result_t rc = CPARSER_OK; assert(VALID_PARSER(parser)); /* * Enter a command. There are three possibilites: * 1. If we are in WHITESPACE state, we check if there is * only one child of keyword type. If yes, we recurse * into it and repeat until either: a) there is more than * one choice, b) We are at a END node. If there is more * than one choice, we look for an END node. In either * case, if an END node is found, we execute the action * function. * * 2. If we are in TOKEN state, we check if we have an unique * match. If yes, re recurse into it and repeat just * like WHITESPACE state until we find an END node. * * 3. If we are in ERROR state, we print out an error. * * Afterward, we reset the parser state and move to the * next line buffer. */ if ((CPARSER_STATE_TOKEN == parser->state) || (CPARSER_STATE_WHITESPACE == parser->state)) { cparser_node_t *child; if (CPARSER_STATE_TOKEN == parser->state) { cparser_token_t *token; cparser_node_t *match; int is_complete; token = CUR_TOKEN(parser); if ((1 <= cparser_match(parser, token->buf, token->token_len, parser->cur_node, &match, &is_complete)) && (is_complete)) { cparser_complete_fn fn = cparser_complete_fn_tbl[match->type]; if (fn) { fn(parser, match, token->buf, token->token_len); } rc = cparser_input(parser, ' ', CPARSER_CHAR_REGULAR); assert(CPARSER_OK == rc); } else { cparser_print_error(parser, "Incomplete command\n"); rc = CPARSER_ERR_INCOMP_CMD; /* * Reset the internal buffer, state and cur_node */ cparser_record_command(parser, rc); cparser_fsm_reset(parser); cparser_print_prompt(parser); return rc; } } /* * Look for a single keyword node child */ child = parser->cur_node->children; assert(child); while ((CPARSER_NODE_KEYWORD == child->type) && NODE_USABLE(parser, child) && (!child->sibling)) { cparser_token_t *token = CUR_TOKEN(parser); cparser_complete_keyword(parser, child, token->buf, token->token_len); rc = cparser_input(parser, ' ', CPARSER_CHAR_REGULAR); assert(CPARSER_OK == rc); child = parser->cur_node->children; assert(child); } /* * Look for an end node */ child = parser->cur_node->children; while ((NULL != child) && !((CPARSER_NODE_END == child->type) && NODE_USABLE(parser, child))) { child = child->sibling; } if (child) { assert(CPARSER_NODE_END == child->type); /* * Execute the glue function */ parser->cur_node = child; parser->cfg.printc(parser, '\n'); rc = ((cparser_glue_fn)child->param)(parser); } else { if (parser->token_tos) { cparser_print_error(parser, "Incomplete command\n"); rc = CPARSER_ERR_INCOMP_CMD; } /* * Reset FSM states and advance to the next line */ cparser_record_command(parser, rc); cparser_fsm_reset(parser); if (CPARSER_OK == rc) { /* * This is just a blank line */ parser->cfg.printc(parser, '\n'); } cparser_print_prompt(parser); return rc; } } else if (CPARSER_STATE_ERROR == parser->state) { cparser_print_error(parser, "Parse error\n"); rc = CPARSER_ERR_PARSE_ERR; } /* * Reset FSM states and advance to the next line */ cparser_record_command(parser, rc); cparser_fsm_reset(parser); if (!cparser_is_user_input(parser, &do_echo)) { cparser_print_prompt(parser); } return rc; }
/** * \brief Complete one level in the parse tree. * \details There are serveral cases we will complete one level: * * 1. If in TOKEN state, the token is unique and complete. * 2. If in WHITESPACE state, there is only one child and it * is not a LF. */ static int cparser_complete_one_level(cparser_t *parser) { cparser_token_t *token; cparser_node_t *match; int is_complete = 0, num_matches, keep_going = 0, rc; char *ch_ptr; switch (parser->state) { case CPARSER_STATE_ERROR: /* * If we are in ERROR, there cannot be a match. So, just quit */ parser->cfg.printc(parser, '\a'); break; case CPARSER_STATE_WHITESPACE: if (parser->cur_node && parser->cur_node->children && !parser->cur_node->children->sibling && (CPARSER_NODE_KEYWORD == parser->cur_node->children->type)) { ch_ptr = parser->cur_node->children->param; while (*ch_ptr) { rc = cparser_input(parser, *ch_ptr, CPARSER_CHAR_REGULAR); assert(CPARSER_OK == rc); ch_ptr++; } rc = cparser_input(parser, ' ', CPARSER_CHAR_REGULAR); assert(CPARSER_OK == rc); } else { /* * If we are in WHITESPACE, just dump all children. Since there is * no * way any token can match to a NULL string. */ cparser_help(parser); } break; case CPARSER_STATE_TOKEN: { /* * Complete a command */ token = CUR_TOKEN(parser); num_matches = cparser_match(parser, token->buf, token->token_len, parser->cur_node, &match, &is_complete); if ((1 == num_matches) && (is_complete)) { cparser_complete_fn fn = cparser_complete_fn_tbl[match->type]; /* * If the only matched node is a keyword, we feel the rest of * keyword in. Otherwise, we assume this parameter is complete * and just insert a space. */ if (fn) { fn(parser, match, token->buf, token->token_len); } rc = cparser_input(parser, ' ', CPARSER_CHAR_REGULAR); assert(CPARSER_OK == rc); keep_going = 1; } else { int offset, orig_offset; /* * If we have more than one match, we should try to complete * as much as possible. To do that, we grab the node in the * (first) matched node and check that the next character * from it is common among all matched nodes. If it is common * to all matched nodes, we continue to feed them into the * parser. However, this is only useful for keywords. If there * is a parameter token in the match, we automatically abort. */ offset = orig_offset = token->token_len; ch_ptr = match->param + token->token_len; while (('\0' != *ch_ptr) && (CPARSER_OK == cparser_match_prefix(parser, token->buf, token->token_len, parser->cur_node, *ch_ptr, offset))) { rc = cparser_input(parser, *ch_ptr, CPARSER_CHAR_REGULAR); assert(CPARSER_OK == rc); ch_ptr++; offset++; } if (orig_offset == offset) { /* * If there is no common prefix at all, just display * help */ cparser_help(parser); } } break; } default: assert(0); } return keep_going; }
void cparser_feed (int session, int ch) { cparser_input(&this_cli[session].parser, ch, 1); }