AirInv Logo  0.1.2
C++ Simulated Airline Inventory Management System library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ScheduleParserHelper.cpp
Go to the documentation of this file.
1 // //////////////////////////////////////////////////////////////////////
2 // Import section
3 // //////////////////////////////////////////////////////////////////////
4 // STL
5 #include <cassert>
6 // StdAir
7 #include <stdair/stdair_exceptions.hpp>
8 #include <stdair/bom/BomRoot.hpp>
9 #include <stdair/service/Logger.hpp>
10 // AirInv
12 // #define BOOST_SPIRIT_DEBUG
14 
15 //
16 namespace bsc = boost::spirit::classic;
17 
18 namespace AIRINV {
19 
20  namespace ScheduleParserHelper {
21 
22  // //////////////////////////////////////////////////////////////////
23  // Semantic actions
24  // //////////////////////////////////////////////////////////////////
25 
28  : _flightPeriod (ioFlightPeriod) {
29  }
30 
31  // //////////////////////////////////////////////////////////////////
34  : ParserSemanticAction (ioFlightPeriod) {
35  }
36 
37  // //////////////////////////////////////////////////////////////////
39  iterator_t iStrEnd) const {
40  const stdair::AirlineCode_T lAirlineCode (iStr, iStrEnd);
41  _flightPeriod._airlineCode = lAirlineCode;
42 
43  // As that's the beginning of a new flight, the list of legs
44  // must be reset
45  _flightPeriod._legList.clear();
46  }
47 
48  // //////////////////////////////////////////////////////////////////
51  : ParserSemanticAction (ioFlightPeriod) {
52  }
53 
54  // //////////////////////////////////////////////////////////////////
55  void storeFlightNumber::operator() (unsigned int iNumber) const {
56  _flightPeriod._flightNumber = iNumber;
57  }
58 
59  // //////////////////////////////////////////////////////////////////
62  : ParserSemanticAction (ioFlightPeriod) {
63  }
64 
65  // //////////////////////////////////////////////////////////////////
67  iterator_t iStrEnd) const {
69 
70  // Reset the number of seconds
72  }
73 
74  // //////////////////////////////////////////////////////////////////
77  : ParserSemanticAction (ioFlightPeriod) {
78  }
79 
80  // //////////////////////////////////////////////////////////////////
82  iterator_t iStrEnd) const {
83  // As a Boost date period (DatePeriod_T) defines the last day of
84  // the period to be end-date - one day, we have to add one day to that
85  // end date before.
86  const stdair::DateOffset_T oneDay (1);
88 
89  // Transform the date pair (i.e., the date range) into a date period
91  stdair::DatePeriod_T (_flightPeriod._dateRangeStart,
93 
94  // Reset the number of seconds
96  }
97 
98  // //////////////////////////////////////////////////////////////////
100  : ParserSemanticAction (ioFlightPeriod) {
101  }
102 
103  // //////////////////////////////////////////////////////////////////
104  void storeDow::operator() (iterator_t iStr, iterator_t iStrEnd) const {
105  stdair::DOW_String_T lDow (iStr, iStrEnd);
106  _flightPeriod._dow = lDow;
107  }
108 
109  // //////////////////////////////////////////////////////////////////
112  : ParserSemanticAction (ioFlightPeriod) {
113  }
114 
115  // //////////////////////////////////////////////////////////////////
117  iterator_t iStrEnd) const {
118  stdair::AirportCode_T lBoardingPoint (iStr, iStrEnd);
119 
120  // If a leg has already been parsed, add it to the FlightPeriod
121  if (_flightPeriod._legAlreadyDefined == true) {
123  } else {
125  }
126 
127  // Set the (new) boarding point
128  _flightPeriod._itLeg._boardingPoint = lBoardingPoint;
129 
130  // As that's the beginning of a new leg, the list of cabins
131  // must be reset
133 
134  // Add the airport code if it is not already stored in the airport lists
135  _flightPeriod.addAirport (lBoardingPoint);
136  }
137 
138  // //////////////////////////////////////////////////////////////////
141  : ParserSemanticAction (ioFlightPeriod) {
142  }
143 
144  // //////////////////////////////////////////////////////////////////
146  iterator_t iStrEnd) const {
147  stdair::AirportCode_T lOffPoint (iStr, iStrEnd);
148  _flightPeriod._itLeg._offPoint = lOffPoint;
149 
150  // Add the airport code if it is not already stored in the airport lists
151  _flightPeriod.addAirport (lOffPoint);
152  }
153 
154  // //////////////////////////////////////////////////////////////////
157  : ParserSemanticAction (ioFlightPeriod) {
158  }
159 
160  // //////////////////////////////////////////////////////////////////
162  iterator_t iStrEnd) const {
164 
165  // Reset the number of seconds
167 
168  // Reset the date off-set
170  }
171 
172  // //////////////////////////////////////////////////////////////////
175  : ParserSemanticAction (ioFlightPeriod) {
176  }
177 
178  // //////////////////////////////////////////////////////////////////
180  iterator_t iStrEnd) const {
182 
183  // Reset the number of seconds
185 
186  // As the boarding date off set is optional, it can be set only
187  // afterwards, based on the staging date off-set value
188  // (_flightPeriod._dateOffset).
189  const stdair::DateOffset_T lDateOffset (_flightPeriod._dateOffset);
191  }
192 
193  // //////////////////////////////////////////////////////////////////
196  : ParserSemanticAction (ioFlightPeriod) {
197  }
198 
199  // //////////////////////////////////////////////////////////////////
201  iterator_t iStrEnd) const {
203 
204  // Reset the number of seconds
206 
207  // As the boarding date off set is optional, it can be set only
208  // afterwards, based on the staging date off-set value
209  // (_flightPeriod._dateOffset).
210  const stdair::DateOffset_T lDateOffset (_flightPeriod._dateOffset);
211  _flightPeriod._itLeg._offDateOffset = lDateOffset;
212  }
213 
214  // //////////////////////////////////////////////////////////////////
217  : ParserSemanticAction (ioFlightPeriod) {
218  }
219 
220  // //////////////////////////////////////////////////////////////////
221  void storeLegCabinCode::operator() (char iChar) const {
223  //std::cout << "Cabin code: " << iChar << std::endl;
224  }
225 
226  // //////////////////////////////////////////////////////////////////
229  : ParserSemanticAction (ioFlightPeriod) {
230  }
231 
232  // //////////////////////////////////////////////////////////////////
233  void storeCapacity::operator() (double iReal) const {
235  //std::cout << "Capacity: " << iReal << std::endl;
236 
237  // The capacity is the last (according to the arrival order
238  // within the schedule input file) detail of the leg cabin. Hence,
239  // when a capacity is parsed, it means that the full cabin
240  // details have already been parsed as well: the cabin can
241  // thus be added to the leg.
243  }
244 
245  // //////////////////////////////////////////////////////////////////
248  : ParserSemanticAction (ioFlightPeriod) {
249  }
250 
251  // //////////////////////////////////////////////////////////////////
252  void storeSegmentSpecificity::operator() (char iChar) const {
253  if (iChar == '0') {
255  } else {
257  }
258 
259  // Do a few sanity checks: the two lists should get exactly the same
260  // content (in terms of airport codes). The only difference is that one
261  // is a STL set, and the other a STL vector.
262  assert (_flightPeriod._airportList.size()
264  assert (_flightPeriod._airportList.size() >= 2);
265 
266  // Since all the legs have now been parsed, we get all the airports
267  // and the segments may be built.
269  }
270 
271  // //////////////////////////////////////////////////////////////////
274  : ParserSemanticAction (ioFlightPeriod) {
275  }
276 
277  // //////////////////////////////////////////////////////////////////
279  iterator_t iStrEnd) const {
280  stdair::AirportCode_T lBoardingPoint (iStr, iStrEnd);
281  _flightPeriod._itSegment._boardingPoint = lBoardingPoint;
282  }
283 
284  // //////////////////////////////////////////////////////////////////
287  : ParserSemanticAction (ioFlightPeriod) {
288  }
289 
290  // //////////////////////////////////////////////////////////////////
292  iterator_t iStrEnd) const {
293  stdair::AirportCode_T lOffPoint (iStr, iStrEnd);
294  _flightPeriod._itSegment._offPoint = lOffPoint;
295  }
296 
297  // //////////////////////////////////////////////////////////////////
300  : ParserSemanticAction (ioFlightPeriod) {
301  }
302 
303  // //////////////////////////////////////////////////////////////////
304  void storeSegmentCabinCode::operator() (char iChar) const {
306  }
307 
308  // //////////////////////////////////////////////////////////////////
311  : ParserSemanticAction (ioFlightPeriod) {
312  }
313 
314  // //////////////////////////////////////////////////////////////////
316  iterator_t iStrEnd) const {
317  std::string lClasses (iStr, iStrEnd);
319 
320  // The list of classes is the last (according to the arrival order
321  // within the schedule input file) detail of the segment cabin. Hence,
322  // when a list of classes is parsed, it means that the full segment
323  // cabin details have already been parsed as well: the segment cabin
324  // can thus be added to the segment.
328  } else {
330  }
331  }
332 
333  // //////////////////////////////////////////////////////////////////
336  : ParserSemanticAction (ioFlightPeriod) {
337  }
338 
339  // //////////////////////////////////////////////////////////////////
340  void storeFamilyCode::operator() (int iCode) const {
341  std::ostringstream ostr;
342  ostr << iCode;
344  }
345 
346  // //////////////////////////////////////////////////////////////////
349  : ParserSemanticAction (ioFlightPeriod) {
350  }
351 
352  // //////////////////////////////////////////////////////////////////
354  iterator_t iStrEnd) const {
355  std::string lClasses (iStr, iStrEnd);
357  lClasses);
358 
359  // The list of classes is the last (according to the arrival order
360  // within the schedule input file) detail of the segment cabin. Hence,
361  // when a list of classes is parsed, it means that the full segment
362  // cabin details have already been parsed as well: the segment cabin
363  // can thus be added to the segment.
367  lFareFamily);
368  } else {
370  lFareFamily);
371  }
372  }
373 
374  // //////////////////////////////////////////////////////////////////
376  doEndFlight (stdair::BomRoot& ioBomRoot,
377  FlightPeriodStruct& ioFlightPeriod)
378  : ParserSemanticAction (ioFlightPeriod),
379  _bomRoot (ioBomRoot) {
380  }
381 
382  // //////////////////////////////////////////////////////////////////
383  // void doEndFlight::operator() (char iChar) const {
385  iterator_t iStrEnd) const {
386 
387  assert (_flightPeriod._legAlreadyDefined == true);
389 
390  // The lists of legs and cabins must be reset
393 
394  // DEBUG: Display the result
395  STDAIR_LOG_DEBUG ("FlightPeriod: " << _flightPeriod.describe());
396 
397  // Create the FlightDate BOM objects, and potentially the intermediary
398  // objects (e.g., Inventory).
399  InventoryGenerator::createFlightDate (_bomRoot, _flightPeriod);
400  }
401 
402 
403  // ///////////////////////////////////////////////////////////////////
404  //
405  // Utility Parsers
406  //
407  // ///////////////////////////////////////////////////////////////////
410 
413 
416 
419 
421  repeat_p_t airline_code_p (chset_t("0-9A-Z").derived(), 2, 3);
422 
424  bounded1_4_p_t flight_number_p (uint1_4_p.derived(), 0u, 9999u);
425 
427  bounded4_p_t year_p (uint4_p.derived(), 2000u, 2099u);
428 
430  bounded2_p_t month_p (uint2_p.derived(), 1u, 12u);
431 
433  bounded2_p_t day_p (uint2_p.derived(), 1u, 31u);
434 
436  repeat_p_t dow_p (chset_t("0-1").derived().derived(), 7, 7);
437 
439  repeat_p_t airport_p (chset_t("0-9A-Z").derived(), 3, 3);
440 
442  bounded2_p_t hours_p (uint2_p.derived(), 0u, 23u);
443 
445  bounded2_p_t minutes_p (uint2_p.derived(), 0u, 59u);
446 
448  bounded2_p_t seconds_p (uint2_p.derived(), 0u, 59u);
449 
451  chset_t cabin_code_p ("A-Z");
452 
455 
457  repeat_p_t class_code_list_p (chset_t("A-Z").derived(), 1, 26);
458 
459 
460  // //////////////////////////////////////////////////////////////////
461  // (Boost Spirit) Grammar Definition
462  // //////////////////////////////////////////////////////////////////
463 
464  // //////////////////////////////////////////////////////////////////
466  FlightPeriodParser (stdair::BomRoot& ioBomRoot,
467  FlightPeriodStruct& ioFlightPeriod)
468  : _bomRoot (ioBomRoot),
469  _flightPeriod (ioFlightPeriod) {
470  }
471 
472  // //////////////////////////////////////////////////////////////////
473  template<typename ScannerT>
476 
477  flight_period_list = *( not_to_be_parsed | flight_period )
478  ;
479 
480  not_to_be_parsed =
481  bsc::lexeme_d[ bsc::comment_p("//") | bsc::comment_p("/*", "*/")
482  | bsc::space_p ]
483  ;
484 
485  flight_period = flight_key
486  >> +( ';' >> leg )
487  >> ';' >> segment_section
488  >> flight_period_end[doEndFlight (self._bomRoot, self._flightPeriod)]
489  ;
490 
491  flight_period_end = bsc::ch_p(';')
492  ;
493 
494  flight_key = airline_code
495  >> ';' >> flight_number
496  >> ';' >> date[storeDateRangeStart(self._flightPeriod)]
497  >> ';' >> date[storeDateRangeEnd(self._flightPeriod)]
498  >> ';' >> dow[storeDow(self._flightPeriod)]
499  ;
500 
501  airline_code =
502  bsc::lexeme_d[(airline_code_p)[storeAirlineCode(self._flightPeriod)]]
503  ;
504 
505  flight_number =
506  bsc::lexeme_d[(flight_number_p)[storeFlightNumber(self._flightPeriod)]]
507  ;
508 
509  date =
510  bsc::lexeme_d[(year_p)[bsc::assign_a(self._flightPeriod._itYear)]
511  >> '-' >> (month_p)[bsc::assign_a(self._flightPeriod._itMonth)]
512  >> '-' >> (day_p)[bsc::assign_a(self._flightPeriod._itDay)]]
513  ;
514 
515  dow = bsc::lexeme_d[ dow_p ]
516  ;
517 
518  leg = leg_key >> ';' >> leg_details >> +( ';' >> leg_cabin_details )
519  ;
520 
521  leg_key =
522  (airport_p)[storeLegBoardingPoint(self._flightPeriod)]
523  >> ';'
524  >> (airport_p)[storeLegOffPoint(self._flightPeriod)]
525  ;
526 
527  leg_details =
528  time[storeBoardingTime(self._flightPeriod)]
529  >> !(date_offset)
530  >> ';'
531  >> time[storeOffTime(self._flightPeriod)]
532  >> !(date_offset)
533  >> ';'
534  >> time[storeElapsedTime(self._flightPeriod)]
535  ;
536 
537  time =
538  bsc::lexeme_d[(hours_p)[bsc::assign_a(self._flightPeriod._itHours)]
539  >> ':' >> (minutes_p)[bsc::assign_a(self._flightPeriod._itMinutes)]
540  >> !(':' >> (seconds_p)[bsc::assign_a(self._flightPeriod._itSeconds)])]
541  ;
542 
543  date_offset =
544  bsc::ch_p('/')
545  >> (int1_p)[bsc::assign_a(self._flightPeriod._dateOffset)]
546  ;
547 
548  leg_cabin_details =
549  (cabin_code_p)[storeLegCabinCode(self._flightPeriod)]
550  >> ';' >> (bsc::ureal_p)[storeCapacity(self._flightPeriod)]
551  ;
552 
553  segment_key =
554  (airport_p)[storeSegmentBoardingPoint(self._flightPeriod)]
555  >> ';'
556  >> (airport_p)[storeSegmentOffPoint(self._flightPeriod)]
557  ;
558 
559  segment_section =
560  generic_segment | specific_segment_list
561  ;
562 
563  generic_segment =
564  bsc::ch_p('0')[storeSegmentSpecificity(self._flightPeriod)]
565  >> +(';' >> segment_cabin_details)
566  ;
567 
568  specific_segment_list =
569  bsc::ch_p('1')[storeSegmentSpecificity(self._flightPeriod)]
570  >> +(';' >> segment_key >> full_segment_cabin_details)
571  ;
572 
573  full_segment_cabin_details =
574  +(';' >> segment_cabin_details)
575  ;
576 
577  segment_cabin_details =
578  (cabin_code_p)[storeSegmentCabinCode(self._flightPeriod)]
579  >> ';' >> (class_code_list_p)[storeClasses(self._flightPeriod)]
580  >> +(';' >> family_cabin_details)
581  ;
582 
583  family_cabin_details =
584  (family_code_p)[storeFamilyCode(self._flightPeriod)]
585  >> ';'
586  >> (class_code_list_p)[storeFClasses(self._flightPeriod)]
587  ;
588 
589  // BOOST_SPIRIT_DEBUG_NODE (FlightPeriodParser);
590  BOOST_SPIRIT_DEBUG_NODE (flight_period_list);
591  BOOST_SPIRIT_DEBUG_NODE (not_to_be_parsed);
592  BOOST_SPIRIT_DEBUG_NODE (flight_period);
593  BOOST_SPIRIT_DEBUG_NODE (flight_period_end);
594  BOOST_SPIRIT_DEBUG_NODE (flight_key);
595  BOOST_SPIRIT_DEBUG_NODE (airline_code);
596  BOOST_SPIRIT_DEBUG_NODE (flight_number);
597  BOOST_SPIRIT_DEBUG_NODE (date);
598  BOOST_SPIRIT_DEBUG_NODE (dow);
599  BOOST_SPIRIT_DEBUG_NODE (leg);
600  BOOST_SPIRIT_DEBUG_NODE (leg_key);
601  BOOST_SPIRIT_DEBUG_NODE (leg_details);
602  BOOST_SPIRIT_DEBUG_NODE (time);
603  BOOST_SPIRIT_DEBUG_NODE (date_offset);
604  BOOST_SPIRIT_DEBUG_NODE (leg_cabin_details);
605  BOOST_SPIRIT_DEBUG_NODE (segment_section);
606  BOOST_SPIRIT_DEBUG_NODE (segment_key);
607  BOOST_SPIRIT_DEBUG_NODE (generic_segment);
608  BOOST_SPIRIT_DEBUG_NODE (specific_segment_list);
609  BOOST_SPIRIT_DEBUG_NODE (full_segment_cabin_details);
610  BOOST_SPIRIT_DEBUG_NODE (segment_cabin_details);
611  BOOST_SPIRIT_DEBUG_NODE (family_cabin_details);
612  }
613 
614  // //////////////////////////////////////////////////////////////////
615  template<typename ScannerT>
616  bsc::rule<ScannerT> const&
618  return flight_period_list;
619  }
620  }
621 
622 
624  //
625  // Entry class for the file parser
626  //
628 
629  // //////////////////////////////////////////////////////////////////////
631  FlightPeriodFileParser (stdair::BomRoot& ioBomRoot,
632  const stdair::Filename_T& iFilename)
633  : _filename (iFilename), _bomRoot (ioBomRoot) {
634  init();
635  }
636 
637  // //////////////////////////////////////////////////////////////////////
638  void FlightPeriodFileParser::init() {
639  // Open the file
640  _startIterator = iterator_t (_filename);
641 
642  // Check the filename exists and can be open
643  if (!_startIterator) {
644  std::ostringstream oMessage;
645  oMessage << "The file " << _filename << " can not be open." << std::endl;
646  STDAIR_LOG_ERROR (oMessage.str());
647  throw ScheduleInputFileNotFoundException (oMessage.str());
648  }
649 
650  // Create an EOF iterator
651  _endIterator = _startIterator.make_end();
652  }
653 
654  // //////////////////////////////////////////////////////////////////////
656  bool oResult = false;
657 
658  STDAIR_LOG_DEBUG ("Parsing schedule input file: " << _filename);
659 
660  // Initialise the parser (grammar) with the helper/staging structure.
661  ScheduleParserHelper::FlightPeriodParser lFPParser (_bomRoot, _flightPeriod);
662 
663  // Launch the parsing of the file and, thanks to the doEndFlight
664  // call-back structure, the building of the whole BomRoot BOM
665  // (i.e., including Inventory, FlightDate, LegDate, SegmentDate, etc.)
666  bsc::parse_info<iterator_t> info = bsc::parse (_startIterator, _endIterator,
667  lFPParser,
668  bsc::space_p - bsc::eol_p);
669 
670  // Retrieves whether or not the parsing was successful
671  oResult = info.hit;
672 
673  const bool isFull = info.full;
674 
675  const std::string hasBeenFullyReadStr = (isFull == true)?"":"not ";
676  if (oResult == true && isFull == true) {
677  STDAIR_LOG_DEBUG ("Parsing of schedule input file: " << _filename
678  << " succeeded: read " << info.length
679  << " characters. The input file has "
680  << hasBeenFullyReadStr
681  << "been fully read. Stop point: " << info.stop);
682 
683  } else {
684  STDAIR_LOG_ERROR ("Parsing of schedule input file: " << _filename
685  << " failed: read " << info.length
686  << " characters. The input file has "
687  << hasBeenFullyReadStr
688  << "been fully read. Stop point: " << info.stop);
689  throw ScheduleFileParsingFailedException ("Parsing of schedule input file: "
690  + _filename + " failed.");
691  }
692 
693  return oResult;
694  }
695 
696 }