Пример #1
0
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;
}
Пример #2
0
/**
 * \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;
}
Пример #3
0
/**
 * \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;
}
Пример #4
0
void cparser_feed (int session, int ch)
{
	cparser_input(&this_cli[session].parser, ch, 1);
}