AirTSP Logo  1.01.0
C++ Simulated Airline Travel Solution Provider 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/basic/BasFileMgr.hpp>
8 #include <stdair/bom/BomRoot.hpp>
9 #include <stdair/service/Logger.hpp>
10 // AirTSP
11 //#define BOOST_SPIRIT_DEBUG
14 
15 namespace bsc = boost::spirit::classic;
16 
17 namespace AIRTSP {
18 
19  namespace ScheduleParserHelper {
20 
21  // //////////////////////////////////////////////////////////////////
22  // Semantic actions
23  // //////////////////////////////////////////////////////////////////
24 
27  : _flightPeriod (ioFlightPeriod) {
28  }
29 
30  // //////////////////////////////////////////////////////////////////
33  : ParserSemanticAction (ioFlightPeriod) {
34  }
35 
36  // //////////////////////////////////////////////////////////////////
38  iterator_t iStrEnd) const {
39  const stdair::AirlineCode_T lAirlineCode (iStr, iStrEnd);
40  _flightPeriod._airlineCode = lAirlineCode;
41  //STDAIR_LOG_DEBUG ("Airline code: " << 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  //STDAIR_LOG_DEBUG ("Flight number: " << 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  // //////////////////////////////////////////////////////////////////
105  : ParserSemanticAction (ioFlightPeriod) {
106  }
107 
108  // //////////////////////////////////////////////////////////////////
109  void storeDow::operator() (iterator_t iStr, iterator_t iStrEnd) const {
110  stdair::DOW_String_T lDow (iStr, iStrEnd);
111  _flightPeriod._dow = lDow;
112  //STDAIR_LOG_DEBUG ("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 
174  //STDAIR_LOG_DEBUG ("Airline code: " << lAirlineCode);
175  }
176 
177  // //////////////////////////////////////////////////////////////////
180  : ParserSemanticAction (ioFlightPeriod) {
181  }
182 
183  // //////////////////////////////////////////////////////////////////
184  void storeOperatingFlightNumber::operator() (unsigned int iNumber) const {
186  //STDAIR_LOG_DEBUG ("Flight number: " << iNumber);
187  }
188 
189  // //////////////////////////////////////////////////////////////////
192  : ParserSemanticAction (ioFlightPeriod) {
193  }
194 
195  // //////////////////////////////////////////////////////////////////
197  iterator_t iStrEnd) const {
199 
200  // Reset the number of seconds
202 
203  // Reset the date off-set
205  }
206 
207  // //////////////////////////////////////////////////////////////////
210  : ParserSemanticAction (ioFlightPeriod) {
211  }
212 
213  // //////////////////////////////////////////////////////////////////
215  iterator_t iStrEnd) const {
217 
218  // Reset the number of seconds
220 
221  // As the boarding date off set is optional, it can be set only
222  // afterwards, based on the staging date off-set value
223  // (_flightPeriod._dateOffset).
224  const stdair::DateOffset_T lDateOffset (_flightPeriod._dateOffset);
226  }
227 
228  // //////////////////////////////////////////////////////////////////
231  : ParserSemanticAction (ioFlightPeriod) {
232  }
233 
234  // //////////////////////////////////////////////////////////////////
236  iterator_t iStrEnd) const {
238 
239  // Reset the number of seconds
241 
242  // As the boarding date off set is optional, it can be set only
243  // afterwards, based on the staging date off-set value
244  // (_flightPeriod._dateOffset).
245  const stdair::DateOffset_T lDateOffset (_flightPeriod._dateOffset);
246  _flightPeriod._itLeg._offDateOffset = lDateOffset;
247  }
248 
249  // //////////////////////////////////////////////////////////////////
252  : ParserSemanticAction (ioFlightPeriod) {
253  }
254 
255  // //////////////////////////////////////////////////////////////////
256  void storeLegCabinCode::operator() (char iChar) const {
258  //STDAIR_LOG_DEBUG ("Cabin code: " << iChar);
259  }
260 
261  // //////////////////////////////////////////////////////////////////
264  : ParserSemanticAction (ioFlightPeriod) {
265  }
266 
267  // //////////////////////////////////////////////////////////////////
268  void storeCapacity::operator() (double iReal) const {
270  //STDAIR_LOG_DEBUG ("Capacity: " << iReal);
271 
272  // The capacity is the last (according to the arrival order
273  // within the schedule input file) detail of the leg cabin. Hence,
274  // when a capacity is parsed, it means that the full cabin
275  // details have already been parsed as well: the cabin can
276  // thus be added to the leg.
278  }
279 
280  // //////////////////////////////////////////////////////////////////
283  : ParserSemanticAction (ioFlightPeriod) {
284  }
285 
286  // //////////////////////////////////////////////////////////////////
287  void storeSegmentSpecificity::operator() (char iChar) const {
288  if (iChar == '0') {
290  } else {
292  }
293 
294  // Do a few sanity checks: the two lists should get exactly the same
295  // content (in terms of airport codes). The only difference is that one
296  // is a STL set, and the other a STL vector.
297  assert (_flightPeriod._airportList.size()
299  assert (_flightPeriod._airportList.size() >= 2);
300 
301  // Since all the legs have now been parsed, we get all the airports
302  // and the segments may be built.
304  }
305 
306  // //////////////////////////////////////////////////////////////////
309  : ParserSemanticAction (ioFlightPeriod) {
310  }
311 
312  // //////////////////////////////////////////////////////////////////
314  iterator_t iStrEnd) const {
315  stdair::AirportCode_T lBoardingPoint (iStr, iStrEnd);
316  _flightPeriod._itSegment._boardingPoint = lBoardingPoint;
317  }
318 
319  // //////////////////////////////////////////////////////////////////
322  : ParserSemanticAction (ioFlightPeriod) {
323  }
324 
325  // //////////////////////////////////////////////////////////////////
327  iterator_t iStrEnd) const {
328  stdair::AirportCode_T lOffPoint (iStr, iStrEnd);
329  _flightPeriod._itSegment._offPoint = lOffPoint;
330  }
331 
332  // //////////////////////////////////////////////////////////////////
335  : ParserSemanticAction (ioFlightPeriod) {
336  }
337 
338  // //////////////////////////////////////////////////////////////////
339  void storeSegmentCabinCode::operator() (char iChar) const {
341  }
342 
343  // //////////////////////////////////////////////////////////////////
346  : ParserSemanticAction (ioFlightPeriod) {
347  }
348 
349  // //////////////////////////////////////////////////////////////////
351  iterator_t iStrEnd) const {
352  std::string lClasses (iStr, iStrEnd);
354 
355  // The list of classes is the last (according to the arrival order
356  // within the schedule input file) detail of the segment cabin. Hence,
357  // when a list of classes is parsed, it means that the full segment
358  // cabin details have already been parsed as well: the segment cabin
359  // can thus be added to the segment.
363  } else {
365  }
366  }
367 
368  // //////////////////////////////////////////////////////////////////
371  : ParserSemanticAction (ioFlightPeriod) {
372  }
373 
374  // //////////////////////////////////////////////////////////////////
375  void storeFamilyCode::operator() (int iCode) const {
376  std::ostringstream ostr;
377  ostr << iCode;
379  }
380 
381  // //////////////////////////////////////////////////////////////////
384  : ParserSemanticAction (ioFlightPeriod) {
385  }
386 
387  // //////////////////////////////////////////////////////////////////
389  iterator_t iStrEnd) const {
390  const std::string lKey (iStr, iStrEnd);
392  //STDAIR_LOG_DEBUG ("FRAT5 key: " << lKey);
393  }
394 
395  // //////////////////////////////////////////////////////////////////
398  : ParserSemanticAction (ioFlightPeriod) {
399  }
400 
401  // //////////////////////////////////////////////////////////////////
403  iterator_t iStrEnd) const {
404  const std::string lKey (iStr, iStrEnd);
406  }
407 
408  // //////////////////////////////////////////////////////////////////
411  : ParserSemanticAction (ioFlightPeriod) {
412  }
413 
414  // //////////////////////////////////////////////////////////////////
416  iterator_t iStrEnd) const {
417  std::string lClasses (iStr, iStrEnd);
421  lClasses);
422 
423  // The list of classes is the last (according to the arrival order
424  // within the schedule input file) detail of the segment cabin. Hence,
425  // when a list of classes is parsed, it means that the full segment
426  // cabin details have already been parsed as well: the segment cabin
427  // can thus be added to the segment.
431  lFareFamily);
432  } else {
434  lFareFamily);
435  }
436  }
437 
438  // //////////////////////////////////////////////////////////////////
440  doEndFlight (stdair::BomRoot& ioBomRoot,
441  FlightPeriodStruct& ioFlightPeriod)
442  : ParserSemanticAction (ioFlightPeriod),
443  _bomRoot (ioBomRoot) {
444  }
445 
446  // //////////////////////////////////////////////////////////////////
447  // void doEndFlight::operator() (char iChar) const {
449  iterator_t iStrEnd) const {
450 
451  assert (_flightPeriod._legAlreadyDefined == true);
453 
454  // The lists of legs and cabins must be reset
457 
458  // DEBUG: Display the result
459  STDAIR_LOG_DEBUG ("FlightPeriod: " << _flightPeriod.describe());
460 
461  // Create the FlightPeriod BOM objects, and potentially the intermediary
462  // objects (e.g., Inventory).
463  InventoryGenerator::createFlightPeriod (_bomRoot, _flightPeriod);
464  }
465 
466 
467  // ///////////////////////////////////////////////////////////////////
468  //
469  // Utility Parsers
470  //
471  // ///////////////////////////////////////////////////////////////////
474 
477 
480 
483 
485  repeat_p_t airline_code_p (chset_t("0-9A-Z").derived(), 2, 3);
486 
488  bounded1_4_p_t flight_number_p (uint1_4_p.derived(), 0u, 9999u);
489 
491  bounded4_p_t year_p (uint4_p.derived(), 2000u, 2099u);
492 
494  bounded2_p_t month_p (uint2_p.derived(), 1u, 12u);
495 
497  bounded2_p_t day_p (uint2_p.derived(), 1u, 31u);
498 
500  repeat_p_t dow_p (chset_t("0-1").derived().derived(), 7, 7);
501 
503  repeat_p_t airport_p (chset_t("0-9A-Z").derived(), 3, 3);
504 
506  bounded2_p_t hours_p (uint2_p.derived(), 0u, 23u);
507 
509  bounded2_p_t minutes_p (uint2_p.derived(), 0u, 59u);
510 
512  bounded2_p_t seconds_p (uint2_p.derived(), 0u, 59u);
513 
515  chset_t cabin_code_p ("A-Z");
516 
519 
521  repeat_p_t key_p (chset_t("0-9A-Z").derived(), 1, 10);
522 
524  repeat_p_t class_code_list_p (chset_t("A-Z").derived(), 1, 26);
525 
526 
527  // //////////////////////////////////////////////////////////////////
528  // (Boost Spirit) Grammar Definition
529  // //////////////////////////////////////////////////////////////////
530 
531  // //////////////////////////////////////////////////////////////////
533  FlightPeriodParser (stdair::BomRoot& ioBomRoot,
534  FlightPeriodStruct& ioFlightPeriod)
535  : _bomRoot (ioBomRoot),
536  _flightPeriod (ioFlightPeriod) {
537  }
538 
539  // //////////////////////////////////////////////////////////////////
540  template<typename ScannerT>
543 
544  flight_period_list = *(not_to_be_parsed
545  | flight_period )
546  ;
547 
548  not_to_be_parsed =bsc::
549  lexeme_d[bsc::comment_p("//") |bsc::comment_p("/*", "*/")
550  |bsc::eol_p];
551 
552  flight_period = flight_key
553  >> +( ';' >> leg )
554  >> ';' >> segment_section
555  >> flight_period_end[doEndFlight (self._bomRoot, self._flightPeriod)]
556  ;
557 
558  flight_period_end =
559  bsc::ch_p(';')
560  ;
561 
562  flight_key = airline_code
563  >> ';' >> flight_number
564  >> ';' >> date[storeDateRangeStart(self._flightPeriod)]
565  >> ';' >> date[storeDateRangeEnd(self._flightPeriod)]
566  >> ';' >> dow[storeDow(self._flightPeriod)]
567  ;
568 
569  airline_code =bsc::
570  lexeme_d[(airline_code_p)[storeAirlineCode(self._flightPeriod)] ]
571  ;
572 
573  flight_number =bsc::
574  lexeme_d[(flight_number_p)[storeFlightNumber(self._flightPeriod)] ]
575  ;
576 
577  date =bsc::
578  lexeme_d[(year_p)[bsc::assign_a(self._flightPeriod._itYear)]
579  >> '-'
580  >> (month_p)[bsc::assign_a(self._flightPeriod._itMonth)]
581  >> '-'
582  >> (day_p)[bsc::assign_a(self._flightPeriod._itDay)]
583  ]
584  ;
585 
586  dow =bsc::lexeme_d[ dow_p ]
587  ;
588 
589  leg = !( operating_leg_details >> ';' )
590  >> leg_key
591  >> ';' >> leg_details
592  >> +( ';' >> leg_cabin_details )
593  ;
594 
595  leg_key = (airport_p)[storeLegBoardingPoint(self._flightPeriod)]
596  >> ';'
597  >> (airport_p)[storeLegOffPoint(self._flightPeriod)]
598  ;
599 
600  operating_leg_details =
601  bsc::lexeme_d[(airline_code_p)[storeOperatingAirlineCode(self._flightPeriod)] ]
602  >> ";"
603  >> bsc::lexeme_d[(flight_number_p)[storeOperatingFlightNumber(self._flightPeriod)] ]
604  ;
605 
606  leg_details =
607  time[storeBoardingTime(self._flightPeriod)]
608  >> !(date_offset)
609  >> ';'
610  >> time[storeOffTime(self._flightPeriod)]
611  >> !(date_offset)
612  >> ';'
613  >> time[storeElapsedTime(self._flightPeriod)]
614  ;
615 
616  time =bsc::
617  lexeme_d[(hours_p)[bsc::assign_a(self._flightPeriod._itHours)]
618  >> ':'
619  >> (minutes_p)[bsc::assign_a(self._flightPeriod._itMinutes)]
620  >> !(':'
621  >> (seconds_p)[bsc::assign_a(self._flightPeriod._itSeconds)])
622  ]
623  ;
624 
625  date_offset =bsc::ch_p('/')
626  >> (int1_p)[bsc::assign_a(self._flightPeriod._dateOffset)]
627  ;
628 
629  leg_cabin_details = (cabin_code_p)[storeLegCabinCode(self._flightPeriod)]
630  >> ';' >> (bsc::ureal_p)[storeCapacity(self._flightPeriod)]
631  ;
632 
633  segment_key =
634  (airport_p)[storeSegmentBoardingPoint(self._flightPeriod)]
635  >> ';'
636  >> (airport_p)[storeSegmentOffPoint(self._flightPeriod)]
637  ;
638 
639  segment_section =
640  generic_segment | specific_segment_list
641  ;
642 
643  generic_segment =bsc::
644  ch_p('0')[storeSegmentSpecificity(self._flightPeriod)]
645  >> +(';' >> segment_cabin_details)
646  ;
647 
648  specific_segment_list =bsc::
649  ch_p('1')[storeSegmentSpecificity(self._flightPeriod)]
650  >> +(';' >> segment_key >> full_segment_cabin_details)
651  ;
652 
653  full_segment_cabin_details =
654  +(';' >> segment_cabin_details)
655  ;
656 
657  segment_cabin_details =
658  (cabin_code_p)[storeSegmentCabinCode(self._flightPeriod)]
659  >> ';' >> (class_code_list_p)[storeClasses(self._flightPeriod)]
660  >> *(';' >> family_cabin_details)
661  ;
662 
663  family_cabin_details =
664  (family_code_p)[storeFamilyCode(self._flightPeriod)]
665  >> ';'
666  >> (key_p)[storeFRAT5CurveKey(self._flightPeriod)]
667  >> ';'
668  >> (key_p)[storeFFDisutilityCurveKey(self._flightPeriod)]
669  >> ';'
670  >> (class_code_list_p)[storeFClasses(self._flightPeriod)]
671  ;
672 
673  // BOOST_SPIRIT_DEBUG_NODE (FlightPeriodParser);
674  BOOST_SPIRIT_DEBUG_NODE (flight_period_list);
675  BOOST_SPIRIT_DEBUG_NODE (flight_period);
676  BOOST_SPIRIT_DEBUG_NODE (not_to_be_parsed);
677  BOOST_SPIRIT_DEBUG_NODE (flight_period_end);
678  BOOST_SPIRIT_DEBUG_NODE (flight_key);
679  BOOST_SPIRIT_DEBUG_NODE (airline_code);
680  BOOST_SPIRIT_DEBUG_NODE (flight_number);
681  BOOST_SPIRIT_DEBUG_NODE (date);
682  BOOST_SPIRIT_DEBUG_NODE (dow);
683  BOOST_SPIRIT_DEBUG_NODE (leg);
684  BOOST_SPIRIT_DEBUG_NODE (leg_key);
685  BOOST_SPIRIT_DEBUG_NODE (leg_details);
686  BOOST_SPIRIT_DEBUG_NODE (time);
687  BOOST_SPIRIT_DEBUG_NODE (date_offset);
688  BOOST_SPIRIT_DEBUG_NODE (leg_cabin_details);
689  BOOST_SPIRIT_DEBUG_NODE (segment_section);
690  BOOST_SPIRIT_DEBUG_NODE (segment_key);
691  BOOST_SPIRIT_DEBUG_NODE (generic_segment);
692  BOOST_SPIRIT_DEBUG_NODE (specific_segment_list);
693  BOOST_SPIRIT_DEBUG_NODE (full_segment_cabin_details);
694  BOOST_SPIRIT_DEBUG_NODE (segment_cabin_details);
695  BOOST_SPIRIT_DEBUG_NODE (family_cabin_details);
696  }
697 
698  // //////////////////////////////////////////////////////////////////
699  template<typename ScannerT>
700  bsc::rule<ScannerT> const&
702  return flight_period_list;
703  }
704 
705  }
706 
707 
709  //
710  // Entry class for the file parser
711  //
713 
714  // //////////////////////////////////////////////////////////////////////
716  FlightPeriodFileParser (stdair::BomRoot& ioBomRoot,
717  const stdair::Filename_T& iFilename)
718  : _filename (iFilename), _bomRoot (ioBomRoot) {
719  init();
720  }
721 
722  // //////////////////////////////////////////////////////////////////////
723  void FlightPeriodFileParser::init() {
724  // Check that the file exists and is readable
725  const bool doesExistAndIsReadable =
726  stdair::BasFileMgr::doesExistAndIsReadable (_filename);
727 
728  if (doesExistAndIsReadable == false) {
729  STDAIR_LOG_ERROR ("The schedule file " << _filename
730  << " does not exist or can not be read.");
731 
732  throw ScheduleInputFileNotFoundException ("The schedule file " + _filename
733  + " does not exist or can not be read");
734  }
735 
736  // Open the file
737  _startIterator = iterator_t (_filename);
738 
739  // Check the filename exists and can be open
740  if (!_startIterator) {
741  STDAIR_LOG_ERROR ("The schedule file " << _filename << " can not be open."
742  << std::endl);
743 
744  throw ScheduleInputFileNotFoundException ("The file " + _filename
745  + " does not exist or can not be read");
746  }
747 
748  // Create an EOF iterator
749  _endIterator = _startIterator.make_end();
750  }
751 
752  // //////////////////////////////////////////////////////////////////////
754  bool oResult = false;
755 
756  STDAIR_LOG_DEBUG ("Parsing schedule input file: " << _filename);
757 
758  // Initialise the parser (grammar) with the helper/staging structure.
759  ScheduleParserHelper::FlightPeriodParser lFPParser (_bomRoot,
760  _flightPeriod);
761 
762  // Launch the parsing of the file and, thanks to the doEndFlight
763  // call-back structure, the building of the whole BomRoot BOM
764  // (i.e., including Inventory, FlightDate, LegDate, SegmentDate, etc.)
765  bsc::parse_info<iterator_t> info =
766  bsc::parse (_startIterator, _endIterator, lFPParser,
767  bsc::space_p - bsc::eol_p);
768 
769  // Retrieves whether or not the parsing was successful
770  oResult = info.hit;
771 
772  const std::string hasBeenFullyReadStr = (info.full == true)?"":"not ";
773  if (oResult == true) {
774  STDAIR_LOG_DEBUG ("Parsing of schedule input file: " << _filename
775  << " succeeded: read " << info.length
776  << " characters. The input file has "
777  << hasBeenFullyReadStr
778  << "been fully read. Stop point: " << info.stop);
779 
780  } else {
781  // TODO: decide whether to throw an exception
782  STDAIR_LOG_ERROR ("Parsing of schedule input file: " << _filename
783  << " failed: read " << info.length
784  << " characters. The input file has "
785  << hasBeenFullyReadStr
786  << "been fully read. Stop point: " << info.stop);
787  }
788 
789  return oResult;
790  }
791 
792 }