Какой путь я должен выбрать для разбора команд оболочки? - PullRequest
0 голосов
/ 26 мая 2019

Для учебы мне нужно сделать оболочку на С

Я хочу разобрать команду оболочки

Моя функция parse_sequence выводит command_t *, который представляет собой структуру, содержащую:

char *program_name;
int fd_input;
bool override;
int fd_output;
bool heredoc_mode;
char **args;
command_t *next; // kind of linked_list

То, что я называю последовательностью, - это команда с перенаправлениями и каналами

Последовательности сокращены на &&, || и ;

ls > file | sort - это одна последовательность, где ls && echo OK состоит из двух последовательностей

Я колеблюсь между двумя способами достижения парсинга

считать это псевдокодом

первый путь : рекурсия

command_t *parse_sequence(char *sequence)
{
    command_t *ret = malloc(sizeof(command_t));
    char **tokens = split(sequence);
    int i = 0;

    while (tokens[i]) {
        if (!strcmp(commands[i], "<")) {
            // set input file (open commands[i + 1])
        }
        if (!strcmp(commands[i], ">")) {
            // set output file (open commands[i + 1])
        }
        if (!strcmp(commands[i], "|")) {
            // recursion: ret->next = parse_sequence(tokens[i + 1]);
        }
        else {
            if (i == 0)
                // set program name
            else
                // append args 
        }
    }
    return (ret);
}

пример : ls > file | sort --rev

i == 0: ls is set as program_name
i == 1: ++i (file) is opened and set as output file descriptor (using dup2)
i == 3: *recursion and setup pipe*
// in the recursive call commands[0] is "sort"
(recursion) i == 0: set program name
(recursion) i == 1: append argument "--rev"
(recursion) i == 2: exit function because commands[i] == NULL

второй способ : разделить каждую команду с конвейером в качестве разделителя

command_t *parse_sequence(char *sequence)
{
    command_t *ret = malloc(sizeof(command_t));
    command_t current_command = ret;
    char **tokens = split_tokens(sequence, (char **){"|", NULL});
    int i = 0;

    while (commands[i]) {
        if (!strcmp(commands[i], "<")) {
            // set input file (open commands[++i])
        }
        if (!strcmp(commands[i], ">")) {
            // set output file (open commands[++i])
        }
        if (!strcmp(commands[i], "|") // tokens are kept when splitting
            // setup pipe
            // current_command = current_command->next
            // i++
        else {
            if (i > 0 && commands[i - 1] pipe or redirection)
                // set program name
            else
                // append args 
        }

    }
    return (ret);
}

пример : ls > file | sort --rev

i == 0: ls is set as program_name
i == 1: ++i (file) is opened and set as output file descriptor (using dup2)
i == 3: *setup pipe* and current_command = current_command->next
i == 4: set program name
i == 5: append argument "--rev"
i == 6: exit function because commands[i] == NULL

Какой из двух способов лучше? С какими проблемами я столкнусь?

Я знаю, что мои примеры неверны в tcsh, но это не важно для моего вопроса

У меня мало времени, поэтому я хочу самый быстрый способ реализации

Спасибо!

...