использование boost :: iostreams для чтения специально созданных данных, затем на основе этого объекта создания и добавления его в список - PullRequest
2 голосов
/ 03 февраля 2010

У меня интересная проблема. Допустим, у меня есть файл со строками, заполненными так:

name1[xp,y,z321](a,b,c){text};//comment
#comment
name2(aaaa);

также у меня есть (упрощенный) класс:

class something {
public:
 something(const std::string& name);
 addOptionalParam(const std::string& value);
 addMandatoryParam(const std::string& value);
 setData((const std::string& value);
};

имя соответствует имени параметра какого-либо конструктора класса. Вещи, перечисленные в скобках [], являются необязательными, а (() - обязательными, и все, что между {} должно быть заключено в строку.

Для первой строки следует вызвать конструктор с именем name1; 3 раза вызвать addOptionalParam, один раз для каждого элемента, разделенного двоеточием; также 3 раза addMandatoryParam и setData с «текстом».

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

Теперь мне нужен хороший совет, как (или если) это возможно, если я могу разобраться, как это сделать для простых объектов, я могу решить, как обрабатывать все лишние детали, такие как семантическая корректность и все такое.

Ответы [ 3 ]

5 голосов
/ 03 февраля 2010

Ваше описание немного сбивает с толку (например, вы упоминаете «разделены двоеточием», но я не вижу двоеточий во входных данных). Я предполагаю, что вы предполагаете, что элементы в квадратных скобках являются необязательными параметрами, в скобках - обязательными параметрами, а в фигурных скобках - «данными».

В этом случае кажется, что ваша грамматика выглядит примерно так:

func: name optionalParams '(' paramList ')' '{' data '}'

paramList: param |
          paramlist ',' param

optionalParams:  // empty
              | '[' paramList ']'

name: WORD
param: WORD
data: WORD

Это достаточно простая грамматика, и Дух, вероятно, будет с ней работать очень хорошо. Spirit имеет тенденцию приводить к очень длинному времени компиляции для больших грамматик, но эта грамматика достаточно мала, чтобы время компиляции было вполне разумным.

Очевидной альтернативой было бы написать вместо этого анализатор спуска (как рекурсивный анализатор спуска, но в этом случае рекурсия не понадобится). В этом случае вы в основном пишете функцию для каждого уровня грамматики, читаете соответствующий ввод и возвращаете структуру (например, вектор), содержащую прочитанные данные. Например, optionalParams, вероятно, наиболее сложный для анализа (просто потому, что он необязательный):

typedef std::string param;

std::vector<param> read_optional_params(std::istream &in) { 
    std::vector<param> ret;

    char ch = in.peek();
    if (ch == '[' ) {
        in >> ch;
        param temp;
        while (in >> temp && temp != "]") 
            ret.push_back(temp);
            if ((ch=in.peek) == ',')
                in >> ch;
    }
    return ret;    
}

На верхнем уровне у вас будет что-то вроде:

function read_func(std::istream &in) { 
    std::string name = read_name(in);
    std::vector<param> optional_params = read_optional_params(in);
    std::vector<param> mandatory_params = read_mandatory_params(in);
    std::string data = read_data(in);

    if (in.fail()) {
        // malformed input
    }

    function func = function(name);
    for (int i=0; i<optional_params.size(); i++)
        func.addOptionalParam(optional_params[i]);
    for (int i=0; i<mandatory_params.size(); i++)
        func.addMandatoryParam(mandatoryParams[i]);
    func.setData(data);
    return func;
}
5 голосов
/ 03 февраля 2010

Рассматривали ли вы такой синтаксический анализатор, как Boost Spirit ?

0 голосов
/ 04 февраля 2010

Ух ты, просто уау ...

Я никогда не знал, что это будет сделано в других терминах, кроме чтения из файла, и, исходя из минимального знания Boost, я не знал, что существует что-то вроде boost :: spirit. Однако теперь, просматривая документацию, мне очень трудно следить, в большинстве случаев это похоже на «use real_p», и нет никакой информации о пространствах имен, так что это довольно запутанно, где найти данный элемент ... Однако, видя, что он может выполнить я действительно поражен.

Я хотел бы расширить информацию о грамматике (однако я не приблизился к расшифровке, как именно это сделать в терминах кода):

name: может быть любой строкой, которая не начинается с цифры, не содержит никаких символов, кроме строчных букв, цифр и '_'
param: может быть целым, двойным или строкой, содержащей только символы 'a-z'
данные: все, что находится между фигурными скобками (даже если это возможно, разрывы строк), поэтому {{{{{} должно привести к '{{{{', а {} {} {} {} должно произойти сбой (грамматически)
';': должен действовать как разделитель и иметь определенный конец, поэтому он должен иметь

Другие вещи - это комментарии, которые я не вижу в примерах, как их реализовать.

Спасибо за помощь, мне нравится видеть, куда она идет.

...