57aba80eb62847315e9cb67fa94d33ee89448bfd
[senf.git] / Console / Parse.cc
1 // $Id$
2 //
3 // Copyright (C) 2008 
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 // Competence Center NETwork research (NET), St. Augustin, GERMANY
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief Parse non-inline non-template implementation */
25
26 #include "Parse.hh"
27 #include "Parse.ih"
28
29 // Custom includes
30 #include <cerrno>
31 #include <boost/iterator/transform_iterator.hpp>
32 #include <boost/spirit/iterator/file_iterator.hpp>
33 #include "../Utils/Exception.hh"
34
35 //#include "Parse.mpp"
36 #define prefix_
37 ///////////////////////////////cc.p////////////////////////////////////////
38
39 namespace senf {
40 namespace console {
41 namespace detail {
42
43 #ifndef DOXYGEN
44
45     struct ParserAccess
46     {
47         static void init(ParseCommandInfo & info)
48             { info.init(); }
49
50         static void setBuiltin(ParseCommandInfo & info, ParseCommandInfo::BuiltinCommand builtin)
51             { info.setBuiltin(builtin); }
52
53         static void setCommand(ParseCommandInfo & info, std::vector<Token> & commandPath)
54             { info.setCommand(commandPath); }
55
56         static void addToken(ParseCommandInfo & info, Token const & token)
57             { info.addToken(token); }
58     };
59
60     struct ParseDispatcher
61     {
62         ParseCommandInfo info_;
63         CommandParser::Callback cb_;
64
65         struct BindInfo {
66             BindInfo( ParseDispatcher & d, CommandParser::Callback cb)
67                 : dispatcher (d) { dispatcher.cb_ = cb; }
68             ~BindInfo() { dispatcher.cb_  = 0; }
69
70             ParseDispatcher & dispatcher;
71         };
72
73         void beginCommand(std::vector<Token> & command)
74             { ParserAccess::init(info_);
75               ParserAccess::setCommand(info_, command); }
76
77         void endCommand()
78             { cb_(info_); }
79
80         void pushToken(Token const & token)
81             { ParserAccess::addToken(info_, token); }
82
83         void builtin_cd(std::vector<Token> & path)
84             { ParserAccess::init(info_);
85               ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinCD);
86               setBuiltinPathArg(path);
87               cb_(info_); }
88
89         void builtin_ls(std::vector<Token> & path)
90             { ParserAccess::init(info_);
91               ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinLS);
92               setBuiltinPathArg(path);
93               cb_(info_); }
94
95         void pushDirectory(std::vector<Token> & path)
96             { ParserAccess::init(info_);
97               ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinPUSHD);
98               setBuiltinPathArg(path);
99               cb_(info_); }
100
101         void popDirectory()
102             { ParserAccess::init(info_);
103               ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinPOPD);
104               cb_(info_); }
105         
106         void builtin_exit()
107             { ParserAccess::init(info_);
108               ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinEXIT);
109               cb_(info_); }
110
111         void builtin_help(std::vector<Token> & path)
112             { ParserAccess::init(info_);
113               ParserAccess::setBuiltin(info_, ParseCommandInfo::BuiltinHELP);
114               setBuiltinPathArg(path);
115               cb_(info_); }
116
117         void setBuiltinPathArg(std::vector<Token> & path)
118             {
119                 pushToken(Token(Token::ArgumentGroupOpen, "("));
120                 for (std::vector<Token>::const_iterator i (path.begin());
121                      i != path.end(); ++i)
122                     pushToken(*i);
123                 pushToken(Token(Token::ArgumentGroupClose, ")"));
124             }
125     };
126
127 #endif
128
129 }}}
130
131 ///////////////////////////////////////////////////////////////////////////
132 // senf::console::Token
133
134 prefix_ std::ostream & senf::console::operator<<(std::ostream & os, Token const & token)
135 {
136     static char const * tokenTypeName[] = {
137         "None",
138         "PathSeparator",
139         "ArgumentGroupOpen",
140         "ArgumentGroupClose",
141         "DirectoryGroupOpen",
142         "DirectoryGroupClose",
143         "CommandTerminator",
144         "OtherPunctuation",
145         "BasicString",
146         "HexString",
147         "Word" };
148     // The real table is:
149     //     static const int bitPosition[32] = {
150     //         0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 
151     //         31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 };
152     // However, we have replaced all values > sizeof(tokenTypeName) with 0
153     static const int bitPosition[32] = {
154         0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 4, 8, 
155         0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 6, 0, 5, 10, 9 };
156     os << tokenTypeName[ token.type() 
157                          ? bitPosition[((token.type() & -token.type()) * 0x077CB531UL) >> 27]+1
158                          : 0 ]
159        << "('"
160        << token.value()
161        << "')";
162     return os;
163 }
164
165 ///////////////////////////////////////////////////////////////////////////
166 // senf::console::ParseCommandInfo
167
168 prefix_ std::ostream & senf::console::operator<<(std::ostream & stream,
169                                                  ParseCommandInfo const & info)
170 {
171     if (info.builtin() == ParseCommandInfo::NoBuiltin) {
172         ParseCommandInfo::TokensRange::const_iterator i (info.commandPath().begin());
173         ParseCommandInfo::TokensRange::const_iterator const i_end (info.commandPath().end());
174         if (i != i_end) {
175             for (;;) {
176                 stream << i->value();
177                 if ( ++i != i_end ) stream << "/";
178                 else                break;
179             }
180         }
181     }
182     else {
183         char const * builtins[] = { "", "cd", "ls", "pushd", "popd", "exit", "help" };
184         stream << "builtin-" << builtins[info.builtin()];
185     }
186         
187     ParseCommandInfo::ArgumentsRange args (info.arguments());
188     for (ParseCommandInfo::argument_iterator i (args.begin()); i != args.end(); ++i) {
189         ParseCommandInfo::token_iterator j (i->begin());
190         stream << " [";
191         if ( j != i->end() ) {
192             for (;;) {
193                 stream << "'" << j->value() << "'";
194                 if ( ++j != i->end() ) stream << ' ';
195                 else                   break;
196             }
197         }
198         stream << "]";
199     }
200
201     return stream;
202 }
203
204 ///////////////////////////////////////////////////////////////////////////
205 // senf::console::ParseCommandInfo::ArgumentIterator
206
207 prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::setRange()
208     const
209 {
210     if (b_->is(Token::ArgumentGroupOpen)) {
211         unsigned level (0);
212         e_ = b_;
213         for (;;) {
214             if (e_->is(Token::ArgumentGroupOpen))
215                 ++ level;
216             else if (e_->is(Token::ArgumentGroupClose)) {
217                 -- level;
218                 if (level == 0)
219                     break;
220             }
221             ++e_;
222         }
223     }
224     ++ e_;
225 }
226
227 prefix_ void senf::console::ParseCommandInfo::ArgumentIterator::decrement()
228 {
229     e_ = b_;
230     --b_;
231     if (b_->is(Token::ArgumentGroupClose)) {
232         unsigned level (0);
233         for (;;) {
234             if (b_->is(Token::ArgumentGroupClose))
235                 ++ level;
236             else if (b_->is(Token::ArgumentGroupOpen)) {
237                 -- level;
238                 if (level == 0)
239                     break;
240             }
241             --b_;
242         }
243     }
244 }
245
246 ///////////////////////////////////////////////////////////////////////////
247 // senf::console::CommandParser
248
249 #ifndef DOXYGEN
250
251 struct senf::console::CommandParser::Impl
252 {
253     typedef detail::CommandGrammar<detail::ParseDispatcher> Grammar;
254
255     detail::ParseDispatcher dispatcher;
256     Grammar::Context context;
257     Grammar grammar;
258
259     Impl() : dispatcher(), context(), grammar(dispatcher, context) {}
260 };
261
262 #endif
263
264 prefix_ senf::console::CommandParser::CommandParser()
265     : impl_ (new Impl())
266 {}
267
268 prefix_ senf::console::CommandParser::~CommandParser()
269 {}
270
271 prefix_ bool senf::console::CommandParser::parse(std::string command, Callback cb)
272 {
273     detail::ParseDispatcher::BindInfo bind (impl().dispatcher, cb);
274     return boost::spirit::parse( command.begin(), command.end(), 
275                                  impl().grammar.use_parser<Impl::Grammar::CommandParser>(),
276                                  impl().grammar.use_parser<Impl::Grammar::SkipParser>()
277         ).full;
278 }
279
280 prefix_ bool senf::console::CommandParser::parseFile(std::string filename, Callback cb)
281 {
282     detail::ParseDispatcher::BindInfo bind (impl().dispatcher, cb);
283     boost::spirit::file_iterator<> i (filename);
284     if (!i) throw SystemException(ENOENT SENF_EXC_DEBUGINFO);
285     boost::spirit::file_iterator<> const i_end (i.make_end());
286     
287     return boost::spirit::parse( i, i_end, 
288                                  impl().grammar.use_parser<Impl::Grammar::CommandParser>(),
289                                  impl().grammar.use_parser<Impl::Grammar::SkipParser>()
290         ).full;
291 }
292
293 ///////////////////////////////cc.e////////////////////////////////////////
294 #undef prefix_
295 //#include "Parse.mpp"
296
297 \f
298 // Local Variables:
299 // mode: c++
300 // fill-column: 100
301 // comment-column: 40
302 // c-file-style: "senf"
303 // indent-tabs-mode: nil
304 // ispell-local-dictionary: "american"
305 // compile-command: "scons -u test"
306 // End: