С Новым годом! Форум программистов, компьютерный форум, киберфорум
Boost C++
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.64/42: Рейтинг темы: голосов - 42, средняя оценка - 4.64
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562

boost::spirit

08.09.2011, 12:17. Показов 8148. Ответов 11
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Пишу парсер на спирите. Задаюсь вопросом как нормально сделать примерно такое

C++
1
lexeme[+(char_)] [push_back(_val, _1)]
Где _val - вектор стрингов.
А _1 имеет тип вектор чаров, который не приводится в string автоматически.
Однако если сделать отдельное правило.

C++
1
value = lexeme[+(char_)];
где value -
C++
1
qi::rule<Iterator, std::string(), ascii::space_type>
И написать
C++
1
value [push_back(_val, _1)]
то все ок. Это конечно вариант, но он мне не особо нравится.
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
08.09.2011, 12:17
Ответы с готовыми решениями:

Метапрограммирование в boost::proto (boost::spirit)
В библиотеке boost:: proto есть такой код calculator&lt;proto::terminal&lt;placeholder&lt;0&gt; &gt;::type&gt; const _1; ...

Производительность boost::spirit::qi
#include &lt;iostream&gt; #include &lt;sstream&gt; #include &lt;chrono&gt; #include &lt;boost/spirit/include/qi.hpp&gt; #include...

Boost::Spirit. Разбор конфигурационного файла
Есть конфигурационный файл, содержащий текстовое описание данных. Каждая запись конфигурационного файла состоит из полей. Формальное...

11
Эксперт С++
 Аватар для niXman
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
08.09.2011, 13:52
Цитата Сообщение от ForEveR Посмотреть сообщение
Где _val - вектор стрингов.
А _1 имеет тип вектор чаров, который не приводится в string автоматически.
полагаю, ты правильно решил проблему...
0
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
09.09.2011, 14:20  [ТС]
Появился еще вопрос...

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        type = string("number") | string("string");
        name = lexeme[+(char_("a-zA-Z0-9_"))];
        not_null_spec = string("not null") | string("");
        name_and_type %= name
            > type
            > not_null_spec
        ;
        
        names_and_types = +(name_and_type)  [push_back(_val, at_c<0>(qi::_1))]
            [push_back(_val, at_c<1>(qi::_1))] [push_back(_val, at_c<2>(qi::_1))]
        ;
 
    qi::rule<Iterator, fusion::vector<std::string, std::string, std::string, std::string>(), ascii::space_type> name_and_type; 
    qi::rule<Iterator, std::vector<std::string>(), ascii::space_type> names_and_types;
    qi::rule<Iterator, std::string(), ascii::space_type> table_name_for_create, type, name, not_null_spec;
C++
1
2
3
4
5
6
7
8
        create = string("create") [push_back(_val, qi::_1)]
            > name [push_back(_val, qi::_1)]
            > '('
            > names_and_types 
            > ')'
            > ';'
        ;
    qi::rule<Iterator, std::vector<std::string>(), qi::locals<std::string>, ascii::space_type> create;
Как бы добавить в вектор стрингов create возвращенный вектор стрингов из правила names_and_types?

Добавлено через 19 часов 28 минут
Решено. Решил через bind и вектор в классе.
0
Эксперт С++
 Аватар для niXman
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
09.09.2011, 22:22
Цитата Сообщение от ForEveR Посмотреть сообщение
Решено.
а на решение можно взглянуть?
0
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
10.09.2011, 09:28  [ТС]
Лучший ответ Сообщение было отмечено как решение

Решение

niXman,
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/bind.hpp>
 
#include <iostream>
#include <string>
#include <vector>
 
namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
 
void push_tokens(std::vector<std::string>& tokens, const std::vector<std::string>& values)
{
    tokens.insert(tokens.end(), values.begin(), values.end());
}
 
void push_token(std::vector<std::string>& tokens, const std::string& val)
{
    tokens.push_back(val);
}
 
/* Grammar
 *
 * Expr : PrimaryCommand
 * PrimaryCommand : InsertCommand | SelectCommand | CreateCommand | DeleteCommand | AlterCommand | TruncateCommand |
 * UpdateCommand | DescCommand | ShowCommand | DropCommand | QuitCommand | HelpCommand
 * InsertCommand : insert into Name ([Names]) values (Values);
 * SelectCommand : select Names | * from Name [Conditions];
 * CreateCommand : create Name (Names and Types);
 * DeleteCommand : delete from Name [Conditions];
 * AlterCommand : alter Name Alter_add | Alter_drop | Alter_alter;
 * TruncateCommand : truncate Name;
 * UpdateCommand : update Name set Names and Values [Conditions];
 * DescCommand : desc | describe Name
 * ShowCommand : show Name
 * DropCommand : drop Name
 * Help : help
 * QuitCommand : quit | exit
 * Names : Name +[, Name]
 * Name : name of table, variable ect
 * Conditions : where Condition +[Cond Condition];
 * Condition : Name Oper Value
 * Oper : = | <= | >= | != | < | >
 * Value : value
 * Cond : and | or
 * Types : Type +[, Type]
 * Type : number | string
 * Not_null : not null | " "
 * Name and Type : Name Type Not_null
 * Names and Types : Name and Type +[, Name and Type]
 * Name and Value : Name = Value
 * Names and Values : Name and Value +[, Name and Value]
 *
*/
 
template<typename Iterator>
struct sql_grammar:qi::grammar<Iterator, std::vector<std::string>(), qi::locals<std::string>, ascii::space_type>
{
    sql_grammar():sql_grammar::base_type(root, "sql")
    {
        using qi::lit;
        using qi::lexeme;
        using qi::on_error;
        using qi::fail;
        using qi::omit;
        using ascii::char_;
        using ascii::string;
 
        using phoenix::construct;
        using phoenix::val;
        using phoenix::push_back;
        
        type = string("number") | string("string");
        name = lexeme[+(char_("a-zA-Z0-9_"))];
        not_null_spec = string("not null") | string("");
        value = lexeme[+(char_("a-zA-Z0-9_"))];
        oper = string("=") | string("!=") | string("<=") | string(">=") | string("<") | string(">");
        cond = string("and") | string("or");
 
        names = name [push_back(qi::_val, qi::_1)]
            > -(+(omit[char_(',')] > name [push_back(qi::_val, qi::_1)]))
        ;
 
        name_and_type = name [push_back(qi::_val, qi::_1)]
            > type [push_back(qi::_val, qi::_1)]
            > not_null_spec [push_back(qi::_val, qi::_1)]
        ;
 
        name_and_value = name [push_back(qi::_val, qi::_1)]
            > string("=") [push_back(qi::_val, qi::_1)]
            > value [push_back(qi::_val, qi::_1)]
        ;
 
        names_and_values = name_and_value [boost::bind(&push_tokens, ref(tokens), _1)]
            > -(+(omit[char_(',')] > name_and_value [boost::bind(&push_tokens, ref(tokens), _1)]))
        ;
 
        names_and_types = name_and_type [boost::bind(&push_tokens, ref(tokens), _1)]
            > -(+(omit[char_(',')] > name_and_type [boost::bind(&push_tokens, ref(tokens), _1)]))
        ;
        
        values = value [push_back(qi::_val, qi::_1)]
            > -(+(omit[char_(',')]> value [push_back(qi::_val, qi::_1)]))
        ;
        
        condition = name [push_back(qi::_val, qi::_1)]
            > oper [push_back(qi::_val, qi::_1)]
            > value [push_back(qi::_val, qi::_1)]
        ;
 
        conditions = condition [boost::bind(&push_tokens, ref(tokens), _1)]
            > -(+(cond [boost::bind(&push_token, ref(tokens), _1)]
            > condition [boost::bind(&push_tokens, ref(tokens), _1)]))
        ;
 
        where = string("where") [boost::bind(&push_token, ref(tokens), _1)]
            > conditions;
        
        alter_add = string("add") [boost::bind(&push_token, ref(tokens), _1)]
            > names_and_types
        ;
 
        alter_drop = string("drop") [boost::bind(&push_token, ref(tokens), _1)]
            > names [boost::bind(&push_tokens, ref(tokens), _1)]
        ;
 
        alter_alter = string("alter") [boost::bind(&push_token, ref(tokens), _1)]
            > names_and_types
        ;
 
        create = string("create") [boost::bind(&push_token, ref(tokens), _1)]
            > name [boost::bind(&push_token, ref(tokens), _1)]
            > omit[char_('(')] > names_and_types > omit[char_(')')]
            > omit[char_(';')]
        ;
 
        insert = string("insert") [boost::bind(&push_token, ref(tokens), _1)]
            > string("into") [boost::bind(&push_token, ref(tokens), _1)]
            > name [boost::bind(&push_token, ref(tokens), _1)]
            > -(omit[char_('(')] > names [boost::bind(&push_tokens, ref(tokens), _1)] > omit[char_(')')])
            > string("values") [boost::bind(&push_token, ref(tokens), _1)]
            > omit[char_('(')] > values [boost::bind(&push_tokens, ref(tokens), _1)] > omit[char_(')')]
            > omit[char_(';')]
        ;
        
        select = string("select") [boost::bind(&push_token, ref(tokens), _1)]
            > (names [boost::bind(&push_tokens, ref(tokens), _1)] | string("*") [boost::bind(&push_token, ref(tokens), _1)])
            > string("from") [boost::bind(&push_token, ref(tokens), _1)]
            > name [boost::bind(&push_token, ref(tokens), _1)]
            > -where
            > omit[char_(';')]
        ;
 
        delete_ = string("delete") [boost::bind(&push_token, ref(tokens), _1)]
            > string("from") [boost::bind(&push_token, ref(tokens), _1)]
            > name [boost::bind(&push_token, ref(tokens), _1)]
            > -where
            > omit[char_(';')]
        ;
        
        update = string("update") [boost::bind(&push_token, ref(tokens), _1)]
            > name [boost::bind(&push_token, ref(tokens), _1)]
            > string("set") [boost::bind(&push_token, ref(tokens), _1)]
            > names_and_values
            > -where
            > omit[char_(';')]
        ;
        
        alter = string("alter") [boost::bind(&push_token, ref(tokens), _1)]
            > name [boost::bind(&push_token, ref(tokens), _1)]
            > (alter_add | alter_drop | alter_alter)
            > omit[char_(';')]
        ;
        
        truncate = string("truncate") [boost::bind(&push_token, ref(tokens), _1)]
            > name [boost::bind(&push_token, ref(tokens), _1)]
            > omit[char_(';')]
        ;
        
        drop = string("drop") [boost::bind(&push_token, ref(tokens), _1)]
            > name [boost::bind(&push_token, ref(tokens), _1)]
            > omit[char_(';')]
        ;
        
        desc = (string("desc") | string("describe")) [boost::bind(&push_token, ref(tokens), _1)]
            > name [boost::bind(&push_token, ref(tokens), _1)]
            > -omit[char_(';')]
        ;
 
        show = (string("show")) [boost::bind(&push_token, ref(tokens), _1)]
            > -omit[char_(';')]
        ;
 
        quit = (string("quit") | string("exit")) [boost::bind(&push_token, ref(tokens), _1)]
            > -omit[char_(';')]
        ;
 
        help = string("help") [boost::bind(&push_token, ref(tokens), _1)]
            > -omit[char_(';')]
        ;
 
        root = create | insert | select | delete_ | update | alter | truncate
            | drop | desc | show | quit | help;
        
        root.name("expression");
        create.name("create command");
        table_name_for_create.name("table name");
        name_and_type.name("name and type");
        names_and_types.name("names and types");
        type.name("value type");
        name.name("name");
        names.name("names");
        insert.name("insert command");
        value.name("value");
        values.name("values");
        select.name("select command");
        cond.name("cond");
        condition.name("condition");
        conditions.name("conditions");
        where.name("where");
        delete_.name("delete");
        name_and_value.name("name and value");
        names_and_values.name("names and values");
        alter_add.name("alter add command");
        alter_drop.name("alter drop command");
        alter_alter.name("alter alter command");
        alter.name("alter command");
        truncate.name("truncate command");
        drop.name("drop command");
        desc.name("describe command");
        show.name("show command");
        quit.name("quit command");
        help.name("help command");
 
        on_error<fail>
        (
           root,
           std::cout << val("Error! Expected ")
           << qi::_4
           << val(" here: \"")
           << construct<std::string>(qi::_3, qi::_2)
           << val("\"")
           << std::endl
        );
    }
    
    qi::rule<Iterator, std::vector<std::string>(), qi::locals<std::string>, ascii::space_type> root;
    qi::rule<Iterator, std::vector<std::string>(), ascii::space_type> names_and_types, name_and_type, names,
        create, values, insert, select, where, conditions, condition, delete_, names_and_values, name_and_value,
        update, alter_add, alter_drop, alter_alter, alter, truncate, drop, desc, show, quit, help;
    qi::rule<Iterator, std::string(), ascii::space_type> table_name_for_create, type, name, not_null_spec, value,
        oper, cond;
 
    std::vector<std::string> tokens;
};
 
int main()
{
    std::string command;
    std::getline(std::cin, command);
    std::vector<std::string> vec;
    using boost::spirit::ascii::space;
    sql_grammar<std::string::const_iterator> sql;
    std::string::const_iterator begin = command.begin();
    std::string::const_iterator end = command.end();
    bool r = phrase_parse(begin, end, sql, space, vec);
    if (r && begin == end)
    {
        std::cout << "PARSING SUCCESFULL" << std::endl;
        std::copy(sql.tokens.begin(), sql.tokens.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
    }
    else
    {
        std::cout << "PARSING FAILED" << std::endl;
    }
}
2
Эксперт С++
 Аватар для niXman
3211 / 1459 / 74
Регистрация: 09.08.2009
Сообщений: 3,441
Записей в блоге: 2
10.09.2011, 11:34
ForEveR, спасибо.
0
Эксперт С++
623 / 467 / 57
Регистрация: 28.01.2011
Сообщений: 605
14.09.2011, 00:12
Лучший ответ Сообщение было отмечено как решение

Решение

ForEveR, по поводу первого вопроса: на самом деле, новое правило — выход идеологически правильный, но если хочется конкретно в рамках одного правила поменять атрибут парсера и не хочется новое правило строить, то есть директива парсинга as<T>, которая преобразовывает атрибут подконтрольного парсера в тип T, для неё также существует два синонима, специально для типов std::string и std::wstring, называются as_string и as_wstring. C их использованием правило
C++
1
lexeme[+(char_)] [push_back(_val, _1)]
можно переписать либо так:
C++
1
qi::as_string[qi::lexeme[+qi::char_]] [phx::push_back(qi::_val, qi::_1)]
либо так:
C++
1
qi::as<std::string>()[qi::lexeme[+qi::char_]] [phx::push_back(qi::_val, qi::_1)]
А по поводу второго вопроса, насчёт добавления вектора std::string, вообще использование семантических правил на самом деле излишне, их можно просто убрать

C++
1
2
3
4
5
6
7
8
create = string("create") [push_back(_val, qi::_1)]
        > name [push_back(_val, qi::_1)]
        > '('
        > names_and_types 
        > ')'
        > ';'
    ;
qi::rule<Iterator, std::vector<std::string>(), qi::locals<std::string>, ascii::space_type> create;
Во-первых, вот эта часть лишняя, а конкретно семантическое действие:

C++
1
string("create") [push_back(_val, qi::_1)]
Потому что синтезируемый атрибут у string типа std::string, он автоматически добавляется в std::vector<std::string>, который является атрибутом всего правила (эквивалентно семантическому действию с push_back). Далее, поскольку у парсера name атрибут тоже типа std::string, то он прозрачно добавляется в атрибут-вектор правила, так что семантическое правило с push_back не нужно. Ну и наконец, names_and_types имеет тип атрибута std::vector<std::string>, здесь тоже всё делается автоматически, то есть: то есть те std::string'и , что мы получили от string("create") и правила name просто "прицепляются" к вектору, полученному из names_and_types, в итоге получается один вектор точно так же, как если бы вы писали например семантическое действие, которое делало бы push_back в _val всех элементов вектора (что Вы, собственно и сделали через bind ). Короче, в этом правиле можно вообще избавиться от семантических действий и выглядеть оно будет так:

C++
1
2
3
4
5
6
7
create = string("create")
        > name
        > '('
        > names_and_types 
        > ')'
        > ';'
    ;
В качестве атрибута будет std::vector<std::string> следущего содержания: {"create", name, names_and_types}. И кстати точно так же можно поступить и в другой части, где вы привели пример:

C++
1
2
names_and_types = +(name_and_type)  [push_back(_val, at_c<0>(qi::_1))]
    [push_back(_val, at_c<1>(qi::_1))] [push_back(_val, at_c<2>(qi::_1))]
name_and_type в Вашем случае имеет тип fusion::vector<std::string... >, но мне не очень понятно, зачем именно так, ибо можно было бы сделать тип атрибута std::vector<std::string>, а в правиле names_and_types вместо того, чтобы делать push_back'и с выборкой по позиции из фьюжн-вектора, просто оставить правило без семантических действий, тогда каждый следующий вектор от распознанного name_and_type просто "прицеплялся" бы в конец вектора для атрибута всего правила. Плюс к тому, насколько помню, если подключить phoenix_operator.hpp (хотя, может и другой заголовок, не помню точно), то если нужно написать несколько семантических действий подряд, можно это делать через запятую, то есть вот так:

C++
1
2
3
4
5
6
7
names_and_types = +(name_and_type)
    [
        phx::push_back(qi::_val, phx::at_c<0>(qi::_1)),
        phx::push_back(qi::_val, phx::at_c<1>(qi::_1)),
        phx::push_back(qi::_val, phx::at_c<2>(qi::_1))
    ]
;
Также я часто у Вас в коде вижу конструкцию с директивой omit[char_(...)], на самом деле, для этого есть специальный символьный (да и строковый тоже) парсер lit, он игнорирует атрибут распознаваемых символов, то есть lit(...) эквивалентно omit[char_(...)]. То есть для того, чтобы считать какой-то символ, но атрибут игнорировать, можно написать просто lit(...), а можно и вообще оставить символьный или строковый литерал (например '(' >> expr >> ')' ), при условии, что слева или справа находится парсер spirit, такие литералы автоматически превращаются в парсеры lit (то есть '(' >> expr >> ')' будет эквивалентно lit('(') >> expr >> lit(')') ).

Кое-где также видно использование такой альтернативы в правилах: string(""). Если требуется распознать пустую строку (эпсилон-цепочку), то для этого есть специальный парсер qi::eps, который не имеет атрибута и возвращает результат считывания строки нулевой длины (то есть попросту никаких входных данных не поглощает), в таком случае атрибут левой части будет сконструирован значением по-умолчанию, то есть в данном случае пустой строкой.

И ещё один очень важный момент, благодаря которому Ваш код, скорее всего, можно будет либо почти полностью, либо полностью переписать без семантических правил вообще. Есть такая штука в спирите как автоматическое распространение атрибутов (automatic attribute propagation), суть его в том, что сложные парсеры в правых частях правил могут быть иногда (если атрибут левой части и правой части совместимы между собой) сконвертированы автоматически в атрибут левой части, так что никаких семантических правил писать вообще не нужно. Но если добавить в правило хотя бы одно семантическое действие, например, здесь:

C++
1
2
3
4
5
6
7
create = string("create") [push_back(_val, qi::_1)]
        > name [push_back(_val, qi::_1)]
        > '('
        > names_and_types 
        > ')'
        > ';'
    ;
то автоматическое распространение атрибутов перестаёт работать (для того, чтобы оно снова заработало, нужно = заменить на %=, но иногда этого делать и не надо; если в правиле нет семантических действий, то = и %= действуют абсолютно одинаково), поэтому, например, в этом примере атрибут от names_and_types будет игнорирован и никуда не пойдёт. А вот если избавиться от семантических действий, когда автоматическое распространение работает, тогда получится следующее:

от "string("create") > name" атрибут будет чем-то вроде fusion::vector<std::string, std::string>, по сути и не важно, чем конкретно, потом при соединении с std::vector<std::string>, который атрибут от names_and_types, он будет вектором (опять же, реальные типы здесь и не важны, по сути), у которого в начале будет два std::string, которые являются элементами того fusion::vector'а, а далее пойдут элементы от names_and_types. Важно здесь что: контейнер из правой части правила совместим (в любом случае, хоть это будет std::vector<std::string> или что-то другое на самом деле) с контейнером-атрибутом от левой части, так что просто прозрачно присваивается контейнер из правой части контейнеру из левой части.
Так что писать собственноручно функции типа push_tokens, а потом с помощью bind "добавлять" эти векторы в конец атрибута _val ни к чему, до тех пор, пока вы используете stl контейнеры в качестве атрибутов правил, они могут заполняться автоматически, вот такая есть полезная возможность.

Иначе говоря, во всех правилах, где Вы синтезируете атрибут типа вектора строк, а каждый из парсеров имеет атрибут строки или вектора строк, то push_back'и писать не стоит, ибо всё сконвертируется автоматически и без семантических правил вообще.

Ну и напоследок: наличие семантических действий очень сильно бьёт по compile-time performance'у (а если каждое из них будет более, чем односложной phoenix-лямбдой, то вообще можно вешаться), так что очень стоит стремиться избавиться от них там, где это только возможно, спасают только предкомпилированные заголовки, да и то лишь частично И вместо обычных функций вкупе с phoenix::bind рекомендуется использовать вариант с phoenix::funcion, состоит он в том, чтобы писать ленивый функтор, а потом из него создавать объект phoenix::function, который уже будет передаваться в семантическое действие. Например, как обычно дают реализацию того же push_back в ленивом варианте с помощью phoenix:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct push_back_impl
    {
    // для работы boost::result_of
    template <typename T>
        struct result
        {
        typedef void type;
        };
        
    template <typename Container, typename Arg>
    void operator() (Container & container, Arg & arg) const
        {
        container.push_back(arg);
        }
    };
    
boost::phoenix::function<push_back_impl> const
    push_back = push_back_impl();
6
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
14.09.2011, 10:56  [ТС]
Ma3a, С as_string вышел небольшой косяк. А именно версия буста на работе 1.42. Еще нет as_string, as<T> в той версии, Пришлось извращаться)

Добавлено через 25 минут
Ну и в плюс к тому.

У вас скомпилируется?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_stl.hpp>
#include <boost/spirit/include/phoenix_object.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/bind.hpp>
 
#include <iostream>
#include <string>
#include <vector>
 
namespace fusion = boost::fusion;
namespace phoenix = boost::phoenix;
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
 
template<typename Iterator>
struct sql_grammar:qi::grammar<Iterator, std::vector<std::string>(), qi::locals<std::string>, ascii::space_type>
{
    sql_grammar():sql_grammar::base_type(root, "sql")
    {
        using qi::lit;
        using qi::lexeme;
        using qi::on_error;
        using qi::fail;
        using qi::omit;
        using ascii::char_;
        using ascii::string;
 
        using phoenix::construct;
        using phoenix::val;
        using phoenix::push_back;
        
        name = lexeme[+(char_("a-zA-Z0-9_"))];
        
        names = name
           > lit(',') 
           > name
        ;
        
        root = names;
    }
    qi::rule<Iterator, std::string(), ascii::space_type> name;
    qi::rule<Iterator, std::vector<std::string>(), ascii::space_type> names;
    qi::rule<Iterator, std::vector<std::string>(), qi::locals<std::string>, ascii::space_type> root;
};
У меня пара листов ошибок.

Все понятно. Из-за старой версии буста.

Этот вариант работает на онлайн-компилере.

http://liveworkspace.org/code/... 081d9a840c

Так что мне пока такой вариант не пойдет. Но запомню. Спасибо!
1
Эксперт С++
623 / 467 / 57
Регистрация: 28.01.2011
Сообщений: 605
15.09.2011, 16:23
ForEveR, вот ещё один момент заметил: у Вас сигнатура грамматики и главного нетерминала root содержит объявление локальной переменной qi::locals<std::string> в посте N5, это просто неокончательный вариант и Вы потом код с использованием этой переменной написали, или просто как-то так получилось? В случае, если код всё-таки законченный, то его можно просто вырезать, так как фениксовая локальная переменная _a нигде не используется.

Добавлено через 29 секунд
код из поста N8 работает
2
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
22.05.2012, 16:13  [ТС]
Вопрос все о том же, потому подниму тему из небытия.
C++
1
2
3
4
5
6
7
8
9
10
        on_error<fail>
        (
           root,
           std::cout << val("Error! Expected ")
           << qi::_4
           << val(" here: \"")
           << construct<std::string>(qi::_3, qi::_2)
           << val("\"")
           << std::endl
        );
Работает. Создаем поток std::ostringstream/std::stringstream в классе. И пытаемся вывести в него - не работает.

Сделал так.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
      auto function = [&stream_]
      (
         fusion::vector<Iterator, const Iterator&, const Iterator&, const boost::spirit::info&>,
         const typename grammar::base_type::start_type::context_type&, const qi::error_handler_result&
      )
      {
         std::cout << "error handler called" << std::endl;
         stream_ << qi::_4 << val(" here: \"") << construct<std::string>(qi::_3, qi::_2)
           << val("\"") << std::endl;
      };
      on_error<fail>
      (
         root, function
      );
Но тоже работать не собирается, компилируется и все нормально, но вывод в поток не происходит.

Добавлено через 1 час 27 минут
Временно сделал так, но мне очень очень не нравится этот вариант.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
      auto function = [&stream_]
      (
         const fusion::vector<Iterator, const Iterator&, const Iterator&, const boost::spirit::info&>& pars,
         const typename grammar::base_type::start_type::context_type&, const qi::error_handler_result&
      )
      {
         stream_ << "Error! Expected: " << fusion::at_c<3>(pars) << " here: \""
         << std::string(fusion::at_c<2>(pars), fusion::at_c<1>(pars)) << "\"" << std::endl;
      };
      on_error<fail>
      (
         root, function
      );
0
Эксперт С++
623 / 467 / 57
Регистрация: 28.01.2011
Сообщений: 605
26.05.2012, 17:41
ForEveR, а можно более полный пример? А то следующий пример с потоком в классе у меня отрабатывает без проблем в MSVC и gcc:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <iostream>
#include <string>
#include <utility>
#include <vector>
 
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
 
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/adapted.hpp>
 
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
namespace fusion = boost::fusion;
 
template <typename Iterator>
    struct test_grammar_2
        : qi::grammar<Iterator, std::string()>
    {
    test_grammar_2()
        : test_grammar_2::base_type(main_rule)
        {
        main_rule = qi::eps > qi::string("shit!");
        
        qi::on_error<qi::fail>
            (
            main_rule,
            mystream << phx::val("Error! Expected ")
            << qi::_4
            << phx::val(" here: \"")
            << phx::construct<std::string>(qi::_3, qi::_2)
            << phx::val("\"")
            << std::endl
            );
        }
 
    qi::rule<Iterator, std::string()> main_rule;
    std::ostringstream mystream;
    };
    
int main()
    {
    std::string input = "shi-";
    test_grammar_2<std::string::iterator> gr;
 
    std::string::iterator begin = input.begin(), end = input.end();
 
    std::string result;
    bool success = qi::parse(begin, end, gr, result);
 
    std::cout << '"' << result << '"' << std::endl;
    std::cout << gr.mystream.str();
    }
1
В астрале
Эксперт С++
 Аватар для ForEveR
8049 / 4806 / 655
Регистрация: 24.06.2010
Сообщений: 10,562
27.05.2012, 12:53  [ТС]
Ma3a, Такой пример отработает судя по всему, у меня в примере не было #define для использования 3 феникса. Что ж. Будем знать. Спасибо!
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
27.05.2012, 12:53
Помогаю со студенческими работами здесь

Boost начало работы: Undefined reference to `boost::system::generic_category() '
Добрый день Собственно говоря возникла необходимость использовать boost в работе. Поставил так: sudo apt-get install boostlib-all-dev ...

Boost Log - undefined reference to `boost::system::system_category()'
Пытаюсь скомпилировать код из примеров Boost Log:#include &lt;boost/log/trivial.hpp&gt; int main(int, char*) { ...

Использование boost и boost.build с несколькими компиляторами
Здравствуйте! Собрал библиотеку boost и boost.build для двух компиляторов: MinGW 4.5.2 и Visual C++ 2010 Express Edition. Для этого...

Spirit::qi - семантическое действие
Суть - парсим значения в мапу (ключ, значение), после, есть правило expr, которое должно парсить примерно такой текст: val1 = val2 + val3;....

Spirit не видит юникод символы
Здавствуйте форумчане. Необходимо разобрать строку и заполнить полученными данными структуру. Ниже приведенный код отлично справляется...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
Новые блоги и статьи
Изучаю kubernetes
lagorue 13.01.2026
А пригодятся-ли мне знания kubernetes в России?
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
Модель микоризы: классовый агентный подход 3
anaschu 06.01.2026
aa0a7f55b50dd51c5ec569d2d10c54f6/ O1rJuneU_ls https:/ / vkvideo. ru/ video-115721503_456239114
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR
ФедосеевПавел 06.01.2026
Owen Logic: О недопустимости использования связки «аналоговый ПИД» + RegKZR ВВЕДЕНИЕ Введу сокращения: аналоговый ПИД — ПИД регулятор с управляющим выходом в виде числа в диапазоне от 0% до. . .
Модель микоризы: классовый агентный подход 2
anaschu 06.01.2026
репозиторий https:/ / github. com/ shumilovas/ fungi ветка по-частям. коммит Create переделка под биомассу. txt вход sc, но sm считается внутри мицелия. кстати, обьем тоже должен там считаться. . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru