cfgfile 0.2.11
Loading...
Searching...
No Matches
lex.hpp
Go to the documentation of this file.
1
31#ifndef CFGFILE__LEX_HPP__INCLUDED
32#define CFGFILE__LEX_HPP__INCLUDED
33
34// cfgfile include.
35#include "types.hpp"
36#include "input_stream.hpp"
37#include "exceptions.hpp"
38
39
40namespace cfgfile {
41
42//
43// lexeme_type_t
44//
45
47enum class lexeme_type_t {
49 null,
51 start,
53 finish,
55 string
56}; // enum class lexeme_type_t
57
58
59//
60// lexeme_t
61//
62
64template< typename Trait = string_trait_t >
66public:
68 : m_type( lexeme_type_t::null )
69 {
70 }
71
72 lexeme_t( lexeme_type_t type, const typename Trait::string_t & value )
73 : m_type( type )
74 , m_value( value )
75 {
76 }
77
80 {
81 return m_type;
82 }
83
85 const typename Trait::string_t & value() const
86 {
87 return m_value;
88 }
89
91 bool is_null() const
92 {
93 return ( m_type == lexeme_type_t::null );
94 }
95
96private:
98 lexeme_type_t m_type;
100 typename Trait::string_t m_value;
101}; // class lexeme_t
102
103
104//
105// lexical_analyzer_t
106//
107
109template< typename Trait = string_trait_t >
111public:
113 : m_stream( stream )
114 , m_line_number( m_stream.line_number() )
115 , m_column_number( m_stream.column_number() )
116 {
117 }
118
125 {
126 typename Trait::string_t result;
127
128 bool quoted_lexeme = false;
129 bool first_symbol = true;
130 bool skip_comment = false;
131
132 skip_spaces();
133
134 m_line_number = m_stream.line_number();
135 m_column_number = m_stream.column_number();
136
137 if( m_stream.at_end() )
139 typename Trait::string_t() );
140
141 while( true )
142 {
143 typename Trait::char_t ch = m_stream.get();
144
146 {
147 if( quoted_lexeme )
148 break;
149 else if( first_symbol )
150 quoted_lexeme = true;
151 else
152 {
153 m_stream.put_back( ch );
154
155 break;
156 }
157 }
159 {
160 typename Trait::char_t new_char( 0x00 );
161
162 if( !quoted_lexeme )
163 result.push_back( ch );
164 else if( process_back_slash( new_char ) )
165 result.push_back( new_char );
166 else
168 Trait::from_ascii( "Unrecognized back-slash "
169 "sequence: \"\\" ) +
170 typename Trait::string_t( 1, new_char ) +
171 Trait::from_ascii( "\". In file \"" ) +
172 m_stream.file_name() +
173 Trait::from_ascii( "\" on line " ) +
174 Trait::to_string( line_number() ) +
175 Trait::from_ascii( "." ) );
176 }
178 {
179 if( result.empty() )
181 typename Trait::string_t( 1, ch ) );
182 else if( quoted_lexeme )
183 result.push_back( ch );
184 else
185 {
186 m_stream.put_back( ch );
187
188 break;
189 }
190 }
191 else if( ch == const_t< Trait >::c_end_tag )
192 {
193 if( result.empty() )
195 typename Trait::string_t( 1, ch ) );
196 else if( quoted_lexeme )
197 result.push_back( ch );
198 else
199 {
200 m_stream.put_back( ch );
201
202 break;
203 }
204 }
205 else if( ch == const_t< Trait >::c_space ||
207 {
208 if( quoted_lexeme )
209 result.push_back( ch );
210 else
211 break;
212 }
215 {
216 if( quoted_lexeme )
218 Trait::from_ascii( "Unfinished quoted lexeme. " ) +
219 Trait::from_ascii( "New line detected. In file \"" ) +
220 m_stream.file_name() +
221 Trait::from_ascii( "\" on line " ) +
222 Trait::to_string( line_number() ) +
223 Trait::from_ascii( "." ) );
224 else
225 break;
226 }
228 {
229 if( quoted_lexeme )
230 result.push_back( ch );
231 else
232 {
233 if( !m_stream.at_end() )
234 {
235 typename Trait::char_t next_char = m_stream.get();
236
238 {
239 skip_comment = true;
240
241 skip_one_line_comment();
242
243 if( first_symbol )
244 skip_spaces();
245 else
246 break;
247 }
249 {
250 skip_comment = true;
251
252 skip_multi_line_comment();
253
254 if( first_symbol )
255 skip_spaces();
256 else
257 break;
258 }
259 else
260 {
261 result.push_back( ch );
262
263 m_stream.put_back( next_char );
264 }
265 }
266 else
267 result.push_back( ch );
268 }
269 }
270 else
271 result.push_back( ch );
272
273 if( m_stream.at_end() )
274 {
275 if( quoted_lexeme )
277 Trait::from_ascii( "Unfinished quoted lexeme. " ) +
278 Trait::from_ascii( "End of file riched. In file \"" ) +
279 m_stream.file_name() +
280 Trait::from_ascii( "\" on line " ) +
281 Trait::to_string( line_number() ) +
282 Trait::from_ascii( "." ) );
283 else if( result.empty() )
285 typename Trait::string_t() );
286 else
287 break;
288 }
289
290 if( !skip_comment )
291 first_symbol = false;
292 else
293 skip_comment = false;
294 }
295
297 }
298
301 {
302 return m_stream;
303 }
304
306 typename Trait::pos_t line_number() const
307 {
308 return m_line_number;
309 }
310
312 typename Trait::pos_t column_number() const
313 {
314 return m_column_number;
315 }
316
317private:
319 bool is_space_char( typename Trait::char_t ch )
320 {
324 return true;
325 else
326 return false;
327 }
328
330 void skip_spaces()
331 {
332 if( m_stream.at_end() )
333 return;
334
335 typename Trait::char_t ch = m_stream.get();
336
337 while( is_space_char( ch ) )
338 {
339 if( m_stream.at_end() )
340 return;
341
342 ch = m_stream.get();
343 }
344
345 m_stream.put_back( ch );
346 }
347
349 bool process_back_slash( typename Trait::char_t & ch )
350 {
351 if( m_stream.at_end() )
352 throw exception_t< Trait >(
353 Trait::from_ascii( "Unexpected end of file. "
354 "Unfinished back slash sequence. In file \"" ) +
355 m_stream.file_name() + Trait::from_ascii( "\" on line " ) +
356 Trait::to_string( m_stream.line_number() ) +
357 Trait::from_ascii( "." ) );
358
359 ch = m_stream.get();
360
361 if( ch == const_t< Trait >::c_n )
363 else if( ch == const_t< Trait >::c_t )
365 else if( ch == const_t< Trait >::c_r )
367 else if( ch == const_t< Trait >::c_quotes )
369 else if( ch == const_t< Trait >::c_back_slash )
371 else
372 return false;
373
374 return true;
375 }
376
378 void skip_one_line_comment()
379 {
380 if( !m_stream.at_end() )
381 {
382 typename Trait::char_t ch = m_stream.get();
383
386 !m_stream.at_end() )
387 ch = m_stream.get();
388 }
389 }
390
392 void skip_multi_line_comment()
393 {
394 if( !m_stream.at_end() )
395 {
396 typename Trait::char_t ch = m_stream.get();
397
398 if( m_stream.at_end() )
399 return;
400
401 typename Trait::char_t next_char = m_stream.get();
402
403 if( ch == const_t< Trait >::c_sharp &&
405 return;
406
407 while( !m_stream.at_end() )
408 {
409 ch = next_char;
410
411 next_char = m_stream.get();
412
413 if( ch == const_t< Trait >::c_sharp &&
415 break;
416 }
417 }
418 }
419
420private:
421 DISABLE_COPY( lexical_analyzer_t )
422
423
424 input_stream_t< Trait > & m_stream;
426 typename Trait::pos_t m_line_number;
428 typename Trait::pos_t m_column_number;
429}; // class lexical_analyzer_t
430
431} /* namespace cfgfile */
432
433#endif // CFGFILE__LEX_HPP__INCLUDED
Exception in the library.
Definition exceptions.hpp:51
Lexeme.
Definition lex.hpp:65
const Trait::string_t & value() const
Definition lex.hpp:85
lexeme_type_t type() const
Definition lex.hpp:79
lexeme_t()
Definition lex.hpp:67
bool is_null() const
Definition lex.hpp:91
lexeme_t(lexeme_type_t type, const typename Trait::string_t &value)
Definition lex.hpp:72
Lexical analyzer.
Definition lex.hpp:110
Trait::pos_t line_number() const
Definition lex.hpp:306
lexeme_t< Trait > next_lexeme()
Definition lex.hpp:124
Trait::pos_t column_number() const
Definition lex.hpp:312
input_stream_t< Trait > & input_stream()
Definition lex.hpp:300
lexical_analyzer_t(input_stream_t< Trait > &stream)
Definition lex.hpp:112
Definition const.hpp:38
lexeme_type_t
Type of the lexeme.
Definition lex.hpp:47
@ finish
Finish tag lexeme "}".
@ string
String lexeme.
@ start
Start tag lexeme "{".
Definition const.hpp:45
static const Trait::char_t c_sharp
Definition const.hpp:58
static const Trait::char_t c_line_feed
Definition const.hpp:56
static const Trait::char_t c_back_slash
Definition const.hpp:52
static const Trait::char_t c_r
Definition const.hpp:51
static const Trait::char_t c_tab
Definition const.hpp:54
static const Trait::char_t c_n
Definition const.hpp:49
static const Trait::char_t c_vertical_bar
Definition const.hpp:57
static const Trait::char_t c_quotes
Definition const.hpp:48
static const Trait::char_t c_t
Definition const.hpp:50
static const Trait::char_t c_carriage_return
Definition const.hpp:55
#define DISABLE_COPY(Class)
Macro for disabling copy.
Definition types.hpp:580