AirInv Logo  1.00.0
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/stdair_types.hpp>
9 #include <stdair/bom/BomRoot.hpp>
10 #include <stdair/service/Logger.hpp>
11 // AirInv
13 // #define BOOST_SPIRIT_DEBUG
15 
16 //
17 namespace bsc = boost::spirit::classic;
18 
19 namespace AIRINV {
20 
21  namespace ScheduleParserHelper {
22 
23  // //////////////////////////////////////////////////////////////////
24  // Semantic actions
25  // //////////////////////////////////////////////////////////////////
26 
29  : _flightPeriod (ioFlightPeriod) {
30  }
31 
32  // //////////////////////////////////////////////////////////////////
35  : ParserSemanticAction (ioFlightPeriod) {
36  }
37 
38  // //////////////////////////////////////////////////////////////////
40  iterator_t iStrEnd) const {
41  const stdair::AirlineCode_T lAirlineCode (iStr, iStrEnd);
42  _flightPeriod._airlineCode = lAirlineCode;
43 
44  // As that's the beginning of a new flight, the list of legs
45  // must be reset
46  _flightPeriod._legList.clear();
47  }
48 
49  // //////////////////////////////////////////////////////////////////
52  : ParserSemanticAction (ioFlightPeriod) {
53  }
54 
55  // //////////////////////////////////////////////////////////////////
56  void storeFlightNumber::operator() (unsigned int iNumber) const {
57  _flightPeriod._flightNumber = iNumber;
58  }
59 
60  // //////////////////////////////////////////////////////////////////
63  : ParserSemanticAction (ioFlightPeriod) {
64  }
65 
66  // //////////////////////////////////////////////////////////////////
68  iterator_t iStrEnd) const {
70 
71  // Reset the number of seconds
73  }
74 
75  // //////////////////////////////////////////////////////////////////
78  : ParserSemanticAction (ioFlightPeriod) {
79  }
80 
81  // //////////////////////////////////////////////////////////////////
83  iterator_t iStrEnd) const {
84  // As a Boost date period (DatePeriod_T) defines the last day of
85  // the period to be end-date - one day, we have to add one day to that
86  // end date before.
87  const stdair::DateOffset_T oneDay (1);
89 
90  // Transform the date pair (i.e., the date range) into a date period
92  stdair::DatePeriod_T (_flightPeriod._dateRangeStart,
94 
95  // Reset the number of seconds
97 
98  // Set the (default) operating airline and flight number
101 
102  }
103 
104  // //////////////////////////////////////////////////////////////////
106  : ParserSemanticAction (ioFlightPeriod) {
107  }
108 
109  // //////////////////////////////////////////////////////////////////
110  void storeDow::operator() (iterator_t iStr, iterator_t iStrEnd) const {
111  stdair::DOW_String_T lDow (iStr, iStrEnd);
112  _flightPeriod._dow = lDow;
113  }
114 
115  // //////////////////////////////////////////////////////////////////
118  : ParserSemanticAction (ioFlightPeriod) {
119  }
120 
121  // //////////////////////////////////////////////////////////////////
123  iterator_t iStrEnd) const {
124  stdair::AirportCode_T lBoardingPoint (iStr, iStrEnd);
125 
126  // If a leg has already been parsed, add it to the FlightPeriod
127  if (_flightPeriod._legAlreadyDefined == true) {
129  } else {
131  }
132 
133  // Set the (new) boarding point
134  _flightPeriod._itLeg._boardingPoint = lBoardingPoint;
135 
136  // As that's the beginning of a new leg, the list of cabins
137  // must be reset
139 
140  // Add the airport code if it is not already stored in the airport lists
141  _flightPeriod.addAirport (lBoardingPoint);
142  }
143 
144  // //////////////////////////////////////////////////////////////////
147  : ParserSemanticAction (ioFlightPeriod) {
148  }
149 
150  // //////////////////////////////////////////////////////////////////
152  iterator_t iStrEnd) const {
153  stdair::AirportCode_T lOffPoint (iStr, iStrEnd);
154  _flightPeriod._itLeg._offPoint = lOffPoint;
155 
156  // Add the airport code if it is not already stored in the airport lists
157  _flightPeriod.addAirport (lOffPoint);
158  }
159 
160  // //////////////////////////////////////////////////////////////////
163  : ParserSemanticAction (ioFlightPeriod) {
164  }
165 
166  // //////////////////////////////////////////////////////////////////
168  iterator_t iStrEnd) const {
169  const stdair::AirlineCode_T lAirlineCode (iStr, iStrEnd);
170  if (lAirlineCode.size() == 2) {
171  _flightPeriod._itLeg._airlineCode = lAirlineCode;
172  }
173  //STDAIR_LOG_DEBUG ("Airline code: " << lAirlineCode);
174  }
175 
176  // //////////////////////////////////////////////////////////////////
179  : ParserSemanticAction (ioFlightPeriod) {
180  }
181 
182  // //////////////////////////////////////////////////////////////////
183  void storeOperatingFlightNumber::operator() (unsigned int iNumber) const {
185  //STDAIR_LOG_DEBUG ("Flight number: " << iNumber);
186  }
187 
188  // //////////////////////////////////////////////////////////////////
191  : ParserSemanticAction (ioFlightPeriod) {
192  }
193 
194  // //////////////////////////////////////////////////////////////////
196  iterator_t iStrEnd) const {
198 
199  // Reset the number of seconds
201 
202  // Reset the date off-set
204  }
205 
206  // //////////////////////////////////////////////////////////////////
209  : ParserSemanticAction (ioFlightPeriod) {
210  }
211 
212  // //////////////////////////////////////////////////////////////////
214  iterator_t iStrEnd) const {
216 
217  // Reset the number of seconds
219 
220  // As the boarding date off set is optional, it can be set only
221  // afterwards, based on the staging date off-set value
222  // (_flightPeriod._dateOffset).
223  const stdair::DateOffset_T lDateOffset (_flightPeriod._dateOffset);
225  }
226 
227  // //////////////////////////////////////////////////////////////////
230  : ParserSemanticAction (ioFlightPeriod) {
231  }
232 
233  // //////////////////////////////////////////////////////////////////
235  iterator_t iStrEnd) const {
237 
238  // Reset the number of seconds
240 
241  // As the boarding date off set is optional, it can be set only
242  // afterwards, based on the staging date off-set value
243  // (_flightPeriod._dateOffset).
244  const stdair::DateOffset_T lDateOffset (_flightPeriod._dateOffset);
245  _flightPeriod._itLeg._offDateOffset = lDateOffset;
246  }
247 
248  // //////////////////////////////////////////////////////////////////
251  : ParserSemanticAction (ioFlightPeriod) {
252  }
253 
254  // //////////////////////////////////////////////////////////////////
255  void storeLegCabinCode::operator() (char iChar) const {
257  //std::cout << "Cabin code: " << iChar << std::endl;
258  }
259 
260  // //////////////////////////////////////////////////////////////////
263  : ParserSemanticAction (ioFlightPeriod) {
264  }
265 
266  // //////////////////////////////////////////////////////////////////
267  void storeCapacity::operator() (double iReal) const {
269  //std::cout << "Capacity: " << iReal << std::endl;
270 
271  // The capacity is the last (according to the arrival order
272  // within the schedule input file) detail of the leg cabin. Hence,
273  // when a capacity is parsed, it means that the full cabin
274  // details have already been parsed as well: the cabin can
275  // thus be added to the leg.
277  }
278 
279  // //////////////////////////////////////////////////////////////////
282  : ParserSemanticAction (ioFlightPeriod) {
283  }
284 
285  // //////////////////////////////////////////////////////////////////
286  void storeSegmentSpecificity::operator() (char iChar) const {
287  if (iChar == '0') {
289  } else {
291  }
292 
293  // Do a few sanity checks: the two lists should get exactly the same
294  // content (in terms of airport codes). The only difference is that one
295  // is a STL set, and the other a STL vector.
296  assert (_flightPeriod._airportList.size()
298  assert (_flightPeriod._airportList.size() >= 2);
299 
300  // Since all the legs have now been parsed, we get all the airports
301  // and the segments may be built.
303  }
304 
305  // //////////////////////////////////////////////////////////////////
308  : ParserSemanticAction (ioFlightPeriod) {
309  }
310 
311  // //////////////////////////////////////////////////////////////////
313  iterator_t iStrEnd) const {
314  stdair::AirportCode_T lBoardingPoint (iStr, iStrEnd);
315  _flightPeriod._itSegment._boardingPoint = lBoardingPoint;
316  }
317 
318  // //////////////////////////////////////////////////////////////////
321  : ParserSemanticAction (ioFlightPeriod) {
322  }
323 
324  // //////////////////////////////////////////////////////////////////
326  iterator_t iStrEnd) const {
327  stdair::AirportCode_T lOffPoint (iStr, iStrEnd);
328  _flightPeriod._itSegment._offPoint = lOffPoint;
329  }
330 
331  // //////////////////////////////////////////////////////////////////
334  : ParserSemanticAction (ioFlightPeriod) {
335  }
336 
337  // //////////////////////////////////////////////////////////////////
338  void storeSegmentCabinCode::operator() (char iChar) const {
340  }
341 
342  // //////////////////////////////////////////////////////////////////
345  : ParserSemanticAction (ioFlightPeriod) {
346  }
347 
348  // //////////////////////////////////////////////////////////////////
350  iterator_t iStrEnd) const {
351  std::string lClasses (iStr, iStrEnd);
353 
354  // The list of classes is the last (according to the arrival order
355  // within the schedule input file) detail of the segment cabin. Hence,
356  // when a list of classes is parsed, it means that the full segment
357  // cabin details have already been parsed as well: the segment cabin
358  // can thus be added to the segment.
362  } else {
364  }
365  }
366 
367  // //////////////////////////////////////////////////////////////////
370  : ParserSemanticAction (ioFlightPeriod) {
371  }
372 
373  // //////////////////////////////////////////////////////////////////
374  void storeFamilyCode::operator() (int iCode) const {
375  std::ostringstream ostr;
376  ostr << iCode;
378  }
379 
380  // //////////////////////////////////////////////////////////////////
383  : ParserSemanticAction (ioFlightPeriod) {
384  }
385 
386  // //////////////////////////////////////////////////////////////////
388  iterator_t iStrEnd) const {
389  const std::string lKey (iStr, iStrEnd);
391  //STDAIR_LOG_DEBUG ("FRAT5 key: " << lKey);
392  }
393 
394  // //////////////////////////////////////////////////////////////////
397  : ParserSemanticAction (ioFlightPeriod) {
398  }
399 
400  // //////////////////////////////////////////////////////////////////
402  iterator_t iStrEnd) const {
403  const std::string lKey (iStr, iStrEnd);
405  }
406 
407  // //////////////////////////////////////////////////////////////////
410  : ParserSemanticAction (ioFlightPeriod) {
411  }
412 
413  // //////////////////////////////////////////////////////////////////
415  iterator_t iStrEnd) const {
416  std::string lClasses (iStr, iStrEnd);
418 
419  // The list of classes is the last (according to the arrival order
420  // within the schedule input file) detail of the segment cabin. Hence,
421  // when a list of classes is parsed, it means that the full segment
422  // cabin details have already been parsed as well: the segment cabin
423  // can thus be added to the segment.
427  lFareFamily);
428  } else {
430  lFareFamily);
431  }
432  }
433 
434  // //////////////////////////////////////////////////////////////////
436  doEndFlight (stdair::BomRoot& ioBomRoot,
437  FlightPeriodStruct& ioFlightPeriod)
438  : ParserSemanticAction (ioFlightPeriod),
439  _bomRoot (ioBomRoot) {
440  }
441 
442  // //////////////////////////////////////////////////////////////////
443  // void doEndFlight::operator() (char iChar) const {
445  iterator_t iStrEnd) const {
446 
447  assert (_flightPeriod._legAlreadyDefined == true);
449 
450  // The lists of legs and cabins must be reset
453 
454  // DEBUG: Display the result
455  STDAIR_LOG_DEBUG ("FlightPeriod: " << _flightPeriod.describe());
456 
457  // Create the FlightDate BOM objects, and potentially the intermediary
458  // objects (e.g., Inventory).
459  InventoryGenerator::createFlightDate (_bomRoot, _flightPeriod);
460  }
461 
462 
463  // ///////////////////////////////////////////////////////////////////
464  //
465  // Utility Parsers
466  //
467  // ///////////////////////////////////////////////////////////////////
470 
473 
476 
479 
481  repeat_p_t airline_code_p (chset_t("0-9A-Z").derived(), 2, 3);
482 
484  bounded1_4_p_t flight_number_p (uint1_4_p.derived(), 0u, 9999u);
485 
487  bounded4_p_t year_p (uint4_p.derived(), 2000u, 2099u);
488 
490  bounded2_p_t month_p (uint2_p.derived(), 1u, 12u);
491 
493  bounded2_p_t day_p (uint2_p.derived(), 1u, 31u);
494 
496  repeat_p_t dow_p (chset_t("0-1").derived().derived(), 7, 7);
497 
499  repeat_p_t airport_p (chset_t("0-9A-Z").derived(), 3, 3);
500 
502  bounded2_p_t hours_p (uint2_p.derived(), 0u, 23u);
503 
505  bounded2_p_t minutes_p (uint2_p.derived(), 0u, 59u);
506 
508  bounded2_p_t seconds_p (uint2_p.derived(), 0u, 59u);
509 
511  chset_t cabin_code_p ("A-Z");
512 
515 
517  repeat_p_t key_p (chset_t("0-9A-Z").derived(), 1, 10);
518 
520  repeat_p_t class_code_list_p (chset_t("A-Z").derived(), 1, 26);
521 
522 
523  // //////////////////////////////////////////////////////////////////
524  // (Boost Spirit) Grammar Definition
525  // //////////////////////////////////////////////////////////////////
526 
527  // //////////////////////////////////////////////////////////////////
529  FlightPeriodParser (stdair::BomRoot& ioBomRoot,
530  FlightPeriodStruct& ioFlightPeriod)
531  : _bomRoot (ioBomRoot),
532  _flightPeriod (ioFlightPeriod) {
533  }
534 
535  // //////////////////////////////////////////////////////////////////
536  template<typename ScannerT>
539 
540  flight_period_list = *( not_to_be_parsed | flight_period )
541  ;
542 
543  not_to_be_parsed =
544  bsc::lexeme_d[ bsc::comment_p("//") | bsc::comment_p("/*", "*/")
545  | bsc::space_p ]
546  ;
547 
548  flight_period = flight_key
549  >> +( ';' >> leg )
550  >> ';' >> segment_section
551  >> flight_period_end[doEndFlight (self._bomRoot, self._flightPeriod)]
552  ;
553 
554  flight_period_end = bsc::ch_p(';')
555  ;
556 
557  flight_key = airline_code
558  >> ';' >> flight_number
559  >> ';' >> date[storeDateRangeStart(self._flightPeriod)]
560  >> ';' >> date[storeDateRangeEnd(self._flightPeriod)]
561  >> ';' >> dow[storeDow(self._flightPeriod)]
562  ;
563 
564  airline_code =
565  bsc::lexeme_d[(airline_code_p)[storeAirlineCode(self._flightPeriod)]]
566  ;
567 
568  flight_number =
569  bsc::lexeme_d[(flight_number_p)[storeFlightNumber(self._flightPeriod)]]
570  ;
571 
572  date =
573  bsc::lexeme_d[(year_p)[bsc::assign_a(self._flightPeriod._itYear)]
574  >> '-' >> (month_p)[bsc::assign_a(self._flightPeriod._itMonth)]
575  >> '-' >> (day_p)[bsc::assign_a(self._flightPeriod._itDay)]]
576  ;
577 
578  dow = bsc::lexeme_d[ dow_p ]
579  ;
580 
581  leg = !( operating_leg_details >> ';' )
582  >> leg_key
583  >> ';' >> leg_details
584  >> +( ';' >> leg_cabin_details )
585  ;
586 
587  leg_key = (airport_p)[storeLegBoardingPoint(self._flightPeriod)]
588  >> ';'
589  >> (airport_p)[storeLegOffPoint(self._flightPeriod)]
590  ;
591 
592  operating_leg_details =
593  bsc::lexeme_d[(airline_code_p)[storeOperatingAirlineCode(self._flightPeriod)] ]
594  >> ";"
595  >> bsc::lexeme_d[(flight_number_p)[storeOperatingFlightNumber(self._flightPeriod)] ]
596  ;
597 
598  leg_details =
599  time[storeBoardingTime(self._flightPeriod)]
600  >> !(date_offset)
601  >> ';'
602  >> time[storeOffTime(self._flightPeriod)]
603  >> !(date_offset)
604  >> ';'
605  >> time[storeElapsedTime(self._flightPeriod)]
606  ;
607 
608  time =
609  bsc::lexeme_d[(hours_p)[bsc::assign_a(self._flightPeriod._itHours)]
610  >> ':' >> (minutes_p)[bsc::assign_a(self._flightPeriod._itMinutes)]
611  >> !(':' >> (seconds_p)[bsc::assign_a(self._flightPeriod._itSeconds)])]
612  ;
613 
614  date_offset =
615  bsc::ch_p('/')
616  >> (int1_p)[bsc::assign_a(self._flightPeriod._dateOffset)]
617  ;
618 
619  leg_cabin_details =
620  (cabin_code_p)[storeLegCabinCode(self._flightPeriod)]
621  >> ';' >> (bsc::ureal_p)[storeCapacity(self._flightPeriod)]
622  ;
623 
624  segment_key =
625  (airport_p)[storeSegmentBoardingPoint(self._flightPeriod)]
626  >> ';'
627  >> (airport_p)[storeSegmentOffPoint(self._flightPeriod)]
628  ;
629 
630  segment_section =
631  generic_segment | specific_segment_list
632  ;
633 
634  generic_segment =
635  bsc::ch_p('0')[storeSegmentSpecificity(self._flightPeriod)]
636  >> +(';' >> segment_cabin_details)
637  ;
638 
639  specific_segment_list =
640  bsc::ch_p('1')[storeSegmentSpecificity(self._flightPeriod)]
641  >> +(';' >> segment_key >> full_segment_cabin_details)
642  ;
643 
644  full_segment_cabin_details =
645  +(';' >> segment_cabin_details)
646  ;
647 
648  segment_cabin_details =
649  (cabin_code_p)[storeSegmentCabinCode(self._flightPeriod)]
650  >> ';' >> (class_code_list_p)[storeClasses(self._flightPeriod)]
651  >> +(';' >> family_cabin_details)
652  ;
653 
654  family_cabin_details =
655  (family_code_p)[storeFamilyCode(self._flightPeriod)]
656  >> ';'
657  >> (key_p)[storeFRAT5CurveKey(self._flightPeriod)]
658  >> ';'
659  >> (key_p)[storeFFDisutilityCurveKey(self._flightPeriod)]
660  >> ';'
661  >> (class_code_list_p)[storeFClasses(self._flightPeriod)]
662  ;
663 
664  // BOOST_SPIRIT_DEBUG_NODE (FlightPeriodParser);
665  BOOST_SPIRIT_DEBUG_NODE (flight_period_list);
666  BOOST_SPIRIT_DEBUG_NODE (not_to_be_parsed);
667  BOOST_SPIRIT_DEBUG_NODE (flight_period);
668  BOOST_SPIRIT_DEBUG_NODE (flight_period_end);
669  BOOST_SPIRIT_DEBUG_NODE (flight_key);
670  BOOST_SPIRIT_DEBUG_NODE (airline_code);
671  BOOST_SPIRIT_DEBUG_NODE (flight_number);
672  BOOST_SPIRIT_DEBUG_NODE (date);
673  BOOST_SPIRIT_DEBUG_NODE (dow);
674  BOOST_SPIRIT_DEBUG_NODE (leg);
675  BOOST_SPIRIT_DEBUG_NODE (leg_key);
676  BOOST_SPIRIT_DEBUG_NODE (leg_details);
677  BOOST_SPIRIT_DEBUG_NODE (time);
678  BOOST_SPIRIT_DEBUG_NODE (date_offset);
679  BOOST_SPIRIT_DEBUG_NODE (leg_cabin_details);
680  BOOST_SPIRIT_DEBUG_NODE (segment_section);
681  BOOST_SPIRIT_DEBUG_NODE (segment_key);
682  BOOST_SPIRIT_DEBUG_NODE (generic_segment);
683  BOOST_SPIRIT_DEBUG_NODE (specific_segment_list);
684  BOOST_SPIRIT_DEBUG_NODE (full_segment_cabin_details);
685  BOOST_SPIRIT_DEBUG_NODE (segment_cabin_details);
686  BOOST_SPIRIT_DEBUG_NODE (family_cabin_details);
687  }
688 
689  // //////////////////////////////////////////////////////////////////
690  template<typename ScannerT>
691  bsc::rule<ScannerT> const&
693  return flight_period_list;
694  }
695  }
696 
697 
699  //
700  // Entry class for the file parser
701  //
703 
704  // //////////////////////////////////////////////////////////////////////
706  FlightPeriodFileParser (stdair::BomRoot& ioBomRoot,
707  const stdair::Filename_T& iFilename)
708  : _filename (iFilename), _bomRoot (ioBomRoot) {
709  init();
710  }
711 
712  // //////////////////////////////////////////////////////////////////////
713  void FlightPeriodFileParser::init() {
714  // Open the file
715  _startIterator = iterator_t (_filename);
716 
717  // Check the filename exists and can be open
718  if (!_startIterator) {
719  std::ostringstream oMessage;
720  oMessage << "The file " << _filename << " can not be open." << std::endl;
721  STDAIR_LOG_ERROR (oMessage.str());
722  throw ScheduleInputFileNotFoundException (oMessage.str());
723  }
724 
725  // Create an EOF iterator
726  _endIterator = _startIterator.make_end();
727  }
728 
729  // //////////////////////////////////////////////////////////////////////
731  bool oResult = false;
732 
733  STDAIR_LOG_DEBUG ("Parsing schedule input file: " << _filename);
734 
735  // Initialise the parser (grammar) with the helper/staging structure.
736  ScheduleParserHelper::FlightPeriodParser lFPParser (_bomRoot, _flightPeriod);
737 
738  // Launch the parsing of the file and, thanks to the doEndFlight
739  // call-back structure, the building of the whole BomRoot BOM
740  // (i.e., including Inventory, FlightDate, LegDate, SegmentDate, etc.)
741  bsc::parse_info<iterator_t> info = bsc::parse (_startIterator, _endIterator,
742  lFPParser,
743  bsc::space_p - bsc::eol_p);
744 
745  // Retrieves whether or not the parsing was successful
746  oResult = info.hit;
747 
748  const bool isFull = info.full;
749 
750  const std::string hasBeenFullyReadStr = (isFull == true)?"":"not ";
751  if (oResult == true && isFull == true) {
752  STDAIR_LOG_DEBUG ("Parsing of schedule input file: " << _filename
753  << " succeeded: read " << info.length
754  << " characters. The input file has "
755  << hasBeenFullyReadStr
756  << "been fully read. Stop point: " << info.stop);
757 
758  } else {
759  STDAIR_LOG_ERROR ("Parsing of schedule input file: " << _filename
760  << " failed: read " << info.length
761  << " characters. The input file has "
762  << hasBeenFullyReadStr
763  << "been fully read. Stop point: " << info.stop);
764  throw ScheduleFileParsingFailedException ("Parsing of schedule input file: "
765  + _filename + " failed.");
766  }
767 
768  return oResult;
769  }
770 
771 }