реклама на сайте
подробности

 
 
> Command line parser
Jenya7
сообщение Apr 13 2015, 07:03
Сообщение #1


Профессионал
*****

Группа: Участник
Сообщений: 1 778
Регистрация: 29-03-12
Пользователь №: 71 075



До сих пор пользовался таким парсером
Код
void PARSER_ParseUart(char *str)
{
    str = ToLower(str);
    if(strlen(str) == 0)
        goto exit;
    char *command;
    char *argument1="";
    char *argument2="";
    char *argument3="";
    command = strtok(str," ");
    argument1 = strtok (NULL, " ");
    argument2 = strtok (NULL, " ");
    argument3 = strtok (NULL, " ");
    if(strcmp(command,"command1")==0)
    {
        if(argument1 == NULL)
        {
                  UART_SendInt(UART0,FunctionReadsValue());    
          }
        else
        {
            int val1 = atoi(argument1);
            FunctionWritesValue(val1);
        }
    }
    else if(strcmp(command,"command2")==0)
    {
        if(argument1 == NULL)
        {
                UART_SendInt(UART0,FunctionReadsValue());
        }
        else if (argument2 == NULL || argument3 == NULL)
        {
           FunctionDoSmething();
        }
             else
             {
                FunctionDoAnotherThing();
             }
       }
       //and so on………………        
}

В принципе я этим способом доволен, работает четко. Но сейчас количество команд перевалило за 100. Функция стала монструозной к тому же жрет много флэша.
Поэтому я решил замутить что то вроде этого
Код
struct command
{
    char *name;  //command name
    char mode;   //0-read, 1- read/write
    int minval;  
    int maxval;
    char val_changed;  
    void (*fp) (void);  //function pointer
};

struct command commands[10];

struct command commands[] = {
    {"imax", 1, 1000, 10000, 0, get_imax},
    {"inow", 0, 1000, 10000, 0, get_inow},
    {"top",  1, 100,  2500,  0, get_top},
    {"pos",  0, 100000, 100000, 0, get_pos},
};

void get_command(char *com)
{
     int I;
     for (i = 0; i < sizeof(commands); i++)
     {
         if(strcmp(commands[i].name, com) == 0)
         {
            //do something
         }
     }
}

Вопрос как сделать универсальный указатель на функцию чтоб могла возвращать значение и содержать любое количество аргументов.
А может у кого нибудь есть более интересное решение?
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
A. Fig Lee
сообщение Apr 13 2015, 11:49
Сообщение #2


Знающий
****

Группа: Участник
Сообщений: 974
Регистрация: 4-04-08
Из: далека
Пользователь №: 36 467



Я себе сделал "универсальный command line парсер"

Примерно так.
Хедер:
Код
#define PARAM_CHAR      0x01
#define PARAM_STRING    0x02
#define PARAM_UINT8     0x04
#define PARAM_UINT16    0x08
#define PARAM_UINT32    0x10
#define PARAM_ARRAY_CNT 0x40
#define PARAM_ARRAY     0x80


typedef struct sCmd {
    const char *name;
    void       *params;
    void       *parsed;
    const char *help; //help string
    char       *stoppedAt;
    uint8_t     num_parsed;
}tCmd;

int8_t process_cmd(char *line, tCmd *cmd);


И пользую в сурсе:

Код
#define CMD_PING    "ping "
#define CMD_ADDR    "addr"
#define CMD_SEND    "send "              // panId is used current, first 0x04X dest addr, then arbitrary number of bytes
#define CMD_ACK     "ack"
#define CMD_RESET   "reset"
#define CMD_ID      "id"
#define CMD_VERSION "version"
#define CMD_HELP    "help"


uint8_t paramsPing[] = {PARAM_UINT16, PARAM_UINT16, 0};
uint8_t paramsAddr[] = {PARAM_UINT16, 0};
uint8_t paramsSend[] = {PARAM_UINT16, PARAM_UINT16, PARAM_ARRAY_CNT, PARAM_ARRAY | PARAM_UINT8, 0};
//...
tCmd cmds[] = {
    {CMD_ADDR, paramsAddr, &parsedAddr, "[address]"},
    {CMD_SEND, paramsSend, &parsedSend, "panId address byte byte ..."},
    {CMD_ACK, NULL, NULL, NULL},
    {CMD_RESET, NULL, NULL, NULL},
    {CMD_PING, paramsPing, parsedPing, "destinationPanID destinationAddr"},
    {CMD_ID, NULL, NULL, NULL},
    {CMD_VERSION, NULL, NULL, NULL},
    {CMD_HELP, NULL, NULL, NULL},
    {NULL, NULL, NULL, NULL}
};

void mailn_loop()
{
  int indx = = process_cmd((char*) read_buffer, &cmds[0]);
        switch (index) {
            case -1:
            {
                    printf( "Unknown cmd\n>");
                
            }
                break;
            case 0:
                // empty string
                break;
           case 1: // 1- based index..
                          if (cmds[index - 1].num_parsed) {
                    cmd_set_addr(parsedAddr);
                } else {
                    cmd_get_addr();
                }
                cmds[index-1].num_parsed = 0;
//......
       }
}


Код фактически не растет с добавлением комманд, только структуры добавляются.
И не болит голова у дятла с разборкой параметров.
Указываешь тип параметра, если сможет, распарсит.


Цитата(Сергей Борщ @ Apr 13 2015, 06:01) *
Чем не устраивает классический вариант - каждая функция получает первым параметром количество аргументов и вторым - массив указателей на аргументы?
Все функции имеют вид error_code_type (*function)(int argc, char *argv[]), поиск по названию в цикле, необходимое количество аргументов можно держать в массиве вместе с имененм и проверять соответствие фактическому количеству аргументов перед вызовом. Тогда и первый параметр функции не нужен.


Не всегда комманд лайн приходит в классической форме.
Частенько это стрим характеров, которые надо просто читать с сериал порта или сокета.
И с количеством параметров таким образом будут проблемы.


--------------------
Верить нельзя никому, даже себе. Мне - можно.
Go to the top of the page
 
+Quote Post



Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 30th July 2025 - 22:28
Рейтинг@Mail.ru


Страница сгенерированна за 0.01411 секунд с 7
ELECTRONIX ©2004-2016