AirSched Logo  0.1.4
C++ Simulated Airline Schedule Manager 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 // AIRSCHED
11 //#define BOOST_SPIRIT_DEBUG
14 
15 namespace bsc = boost::spirit::classic;
16 
17 namespace AIRSCHED {
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 
42  // As that's the beginning of a new flight, the list of legs
43  // must be reset
44  _flightPeriod._legList.clear();
45  }
46 
47  // //////////////////////////////////////////////////////////////////
50  : ParserSemanticAction (ioFlightPeriod) {
51  }
52 
53  // //////////////////////////////////////////////////////////////////
54  void storeFlightNumber::operator() (unsigned int iNumber) const {
55  _flightPeriod._flightNumber = iNumber;
56  }
57 
58  // //////////////////////////////////////////////////////////////////
61  : ParserSemanticAction (ioFlightPeriod) {
62  }
63 
64  // //////////////////////////////////////////////////////////////////
66  iterator_t iStrEnd) const {
68 
69  // Reset the number of seconds
71  }
72 
73  // //////////////////////////////////////////////////////////////////
76  : ParserSemanticAction (ioFlightPeriod) {
77  }
78 
79  // //////////////////////////////////////////////////////////////////
81  iterator_t iStrEnd) const {
82  // As a Boost date period (DatePeriod_T) defines the last day of
83  // the period to be end-date - one day, we have to add one day to that
84  // end date before.
85  const stdair::DateOffset_T oneDay (1);
87 
88  // Transform the date pair (i.e., the date range) into a date period
90  stdair::DatePeriod_T (_flightPeriod._dateRangeStart,
92 
93  // Reset the number of seconds
95  }
96 
97  // //////////////////////////////////////////////////////////////////
99  : ParserSemanticAction (ioFlightPeriod) {
100  }
101 
102  // //////////////////////////////////////////////////////////////////
103  void storeDow::operator() (iterator_t iStr, iterator_t iStrEnd) const {
104  stdair::DOW_String_T lDow (iStr, iStrEnd);
105  _flightPeriod._dow = lDow;
106  }
107 
108  // //////////////////////////////////////////////////////////////////
111  : ParserSemanticAction (ioFlightPeriod) {
112  }
113 
114  // //////////////////////////////////////////////////////////////////
116  iterator_t iStrEnd) const {
117  stdair::AirportCode_T lBoardingPoint (iStr, iStrEnd);
118 
119  // If a leg has already been parsed, add it to the FlightPeriod
120  if (_flightPeriod._legAlreadyDefined == true) {
122  } else {
124  }
125 
126  // Set the (new) boarding point
127  _flightPeriod._itLeg._boardingPoint = lBoardingPoint;
128 
129  // As that's the beginning of a new leg, the list of cabins
130  // must be reset
132 
133  // Add the airport code if it is not already stored in the airport lists
134  _flightPeriod.addAirport (lBoardingPoint);
135  }
136 
137  // //////////////////////////////////////////////////////////////////
140  : ParserSemanticAction (ioFlightPeriod) {
141  }
142 
143  // //////////////////////////////////////////////////////////////////
145  iterator_t iStrEnd) const {
146  stdair::AirportCode_T lOffPoint (iStr, iStrEnd);
147  _flightPeriod._itLeg._offPoint = lOffPoint;
148 
149  // Add the airport code if it is not already stored in the airport lists
150  _flightPeriod.addAirport (lOffPoint);
151  }
152 
153  // //////////////////////////////////////////////////////////////////
156  : ParserSemanticAction (ioFlightPeriod) {
157  }
158 
159  // //////////////////////////////////////////////////////////////////
161  iterator_t iStrEnd) const {
163 
164  // Reset the number of seconds
166 
167  // Reset the date off-set
169  }
170 
171  // //////////////////////////////////////////////////////////////////
174  : ParserSemanticAction (ioFlightPeriod) {
175  }
176 
177  // //////////////////////////////////////////////////////////////////
179  iterator_t iStrEnd) const {
181 
182  // Reset the number of seconds
184 
185  // As the boarding date off set is optional, it can be set only
186  // afterwards, based on the staging date off-set value
187  // (_flightPeriod._dateOffset).
188  const stdair::DateOffset_T lDateOffset (_flightPeriod._dateOffset);
190  }
191 
192  // //////////////////////////////////////////////////////////////////
195  : ParserSemanticAction (ioFlightPeriod) {
196  }
197 
198  // //////////////////////////////////////////////////////////////////
200  iterator_t iStrEnd) const {
202 
203  // Reset the number of seconds
205 
206  // As the boarding date off set is optional, it can be set only
207  // afterwards, based on the staging date off-set value
208  // (_flightPeriod._dateOffset).
209  const stdair::DateOffset_T lDateOffset (_flightPeriod._dateOffset);
210  _flightPeriod._itLeg._offDateOffset = lDateOffset;
211  }
212 
213  // //////////////////////////////////////////////////////////////////
216  : ParserSemanticAction (ioFlightPeriod) {
217  }
218 
219  // //////////////////////////////////////////////////////////////////
220  void storeLegCabinCode::operator() (char iChar) const {
222  //std::cout << "Cabin code: " << iChar << std::endl;
223  }
224 
225  // //////////////////////////////////////////////////////////////////
228  : ParserSemanticAction (ioFlightPeriod) {
229  }
230 
231  // //////////////////////////////////////////////////////////////////
232  void storeCapacity::operator() (double iReal) const {
234  //std::cout << "Capacity: " << iReal << std::endl;
235 
236  // The capacity is the last (according to the arrival order
237  // within the schedule input file) detail of the leg cabin. Hence,
238  // when a capacity is parsed, it means that the full cabin
239  // details have already been parsed as well: the cabin can
240  // thus be added to the leg.
242  }
243 
244  // //////////////////////////////////////////////////////////////////
247  : ParserSemanticAction (ioFlightPeriod) {
248  }
249 
250  // //////////////////////////////////////////////////////////////////
251  void storeSegmentSpecificity::operator() (char iChar) const {
252  if (iChar == '0') {
254  } else {
256  }
257 
258  // Do a few sanity checks: the two lists should get exactly the same
259  // content (in terms of airport codes). The only difference is that one
260  // is a STL set, and the other a STL vector.
261  assert (_flightPeriod._airportList.size()
263  assert (_flightPeriod._airportList.size() >= 2);
264 
265  // Since all the legs have now been parsed, we get all the airports
266  // and the segments may be built.
268  }
269 
270  // //////////////////////////////////////////////////////////////////
273  : ParserSemanticAction (ioFlightPeriod) {
274  }
275 
276  // //////////////////////////////////////////////////////////////////
278  iterator_t iStrEnd) const {
279  stdair::AirportCode_T lBoardingPoint (iStr, iStrEnd);
280  _flightPeriod._itSegment._boardingPoint = lBoardingPoint;
281  }
282 
283  // //////////////////////////////////////////////////////////////////
286  : ParserSemanticAction (ioFlightPeriod) {
287  }
288 
289  // //////////////////////////////////////////////////////////////////
291  iterator_t iStrEnd) const {
292  stdair::AirportCode_T lOffPoint (iStr, iStrEnd);
293  _flightPeriod._itSegment._offPoint = lOffPoint;
294  }
295 
296  // //////////////////////////////////////////////////////////////////
299  : ParserSemanticAction (ioFlightPeriod) {
300  }
301 
302  // //////////////////////////////////////////////////////////////////
303  void storeSegmentCabinCode::operator() (char iChar) const {
305  }
306 
307  // //////////////////////////////////////////////////////////////////
310  : ParserSemanticAction (ioFlightPeriod) {
311  }
312 
313  // //////////////////////////////////////////////////////////////////
315  iterator_t iStrEnd) const {
316  std::string lClasses (iStr, iStrEnd);
318 
319  // The list of classes is the last (according to the arrival order
320  // within the schedule input file) detail of the segment cabin. Hence,
321  // when a list of classes is parsed, it means that the full segment
322  // cabin details have already been parsed as well: the segment cabin
323  // can thus be added to the segment.
327  } else {
329  }
330  }
331 
332  // //////////////////////////////////////////////////////////////////
335  : ParserSemanticAction (ioFlightPeriod) {
336  }
337 
338  // //////////////////////////////////////////////////////////////////
339  void storeFamilyCode::operator() (int iCode) const {
340  std::ostringstream ostr;
341  ostr << iCode;
343  }
344 
345  // //////////////////////////////////////////////////////////////////
348  : ParserSemanticAction (ioFlightPeriod) {
349  }
350 
351  // //////////////////////////////////////////////////////////////////
353  iterator_t iStrEnd) const {
354  std::string lClasses (iStr, iStrEnd);
356  lClasses);
357 
358  // The list of classes is the last (according to the arrival order
359  // within the schedule input file) detail of the segment cabin. Hence,
360  // when a list of classes is parsed, it means that the full segment
361  // cabin details have already been parsed as well: the segment cabin
362  // can thus be added to the segment.
366  lFareFamily);
367  } else {
369  lFareFamily);
370  }
371  }
372 
373  // //////////////////////////////////////////////////////////////////
375  doEndFlight (stdair::BomRoot& ioBomRoot,
376  FlightPeriodStruct& ioFlightPeriod)
377  : ParserSemanticAction (ioFlightPeriod),
378  _bomRoot (ioBomRoot) {
379  }
380 
381  // //////////////////////////////////////////////////////////////////
382  // void doEndFlight::operator() (char iChar) const {
384  iterator_t iStrEnd) const {
385 
386  assert (_flightPeriod._legAlreadyDefined == true);
388 
389  // The lists of legs and cabins must be reset
392 
393  // DEBUG: Display the result
394  STDAIR_LOG_DEBUG ("FlightPeriod: " << _flightPeriod.describe());
395 
396  // Create the FlightPeriod BOM objects, and potentially the intermediary
397  // objects (e.g., Inventory).
398  InventoryGenerator::createFlightPeriod (_bomRoot, _flightPeriod);
399  }
400 
401 
402  // ///////////////////////////////////////////////////////////////////
403  //
404  // Utility Parsers
405  //
406  // ///////////////////////////////////////////////////////////////////
409 
412 
415 
418 
420  repeat_p_t airline_code_p (chset_t("0-9A-Z").derived(), 2, 3);
421 
423  bounded1_4_p_t flight_number_p (uint1_4_p.derived(), 0u, 9999u);
424 
426  bounded4_p_t year_p (uint4_p.derived(), 2000u, 2099u);
427 
429  bounded2_p_t month_p (uint2_p.derived(), 1u, 12u);
430 
432  bounded2_p_t day_p (uint2_p.derived(), 1u, 31u);
433 
435  repeat_p_t dow_p (chset_t("0-1").derived().derived(), 7, 7);
436 
438  repeat_p_t airport_p (chset_t("0-9A-Z").derived(), 3, 3);
439 
441  bounded2_p_t hours_p (uint2_p.derived(), 0u, 23u);
442 
444  bounded2_p_t minutes_p (uint2_p.derived(), 0u, 59u);
445 
447  bounded2_p_t seconds_p (uint2_p.derived(), 0u, 59u);
448 
450  chset_t cabin_code_p ("A-Z");
451 
454 
456  repeat_p_t class_code_list_p (chset_t("A-Z").derived(), 1, 26);
457 
458 
459  // //////////////////////////////////////////////////////////////////
460  // (Boost Spirit) Grammar Definition
461  // //////////////////////////////////////////////////////////////////
462 
463  // //////////////////////////////////////////////////////////////////
465  FlightPeriodParser (stdair::BomRoot& ioBomRoot,
466  FlightPeriodStruct& ioFlightPeriod)
467  : _bomRoot (ioBomRoot),
468  _flightPeriod (ioFlightPeriod) {
469  }
470 
471  // //////////////////////////////////////////////////////////////////
472  template<typename ScannerT>
475 
476  flight_period_list = *(not_to_be_parsed
477  | flight_period )
478  ;
479 
480  not_to_be_parsed =bsc::
481  lexeme_d[bsc::comment_p("//") |bsc::comment_p("/*", "*/")
482  |bsc::eol_p];
483 
484  flight_period = flight_key
485  >> +( ';' >> leg )
486  >> ';' >> segment_section
487  >> flight_period_end[doEndFlight (self._bomRoot, self._flightPeriod)]
488  ;
489 
490  flight_period_end =
491  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 =bsc::
502  lexeme_d[(airline_code_p)[storeAirlineCode(self._flightPeriod)] ]
503  ;
504 
505  flight_number =bsc::
506  lexeme_d[(flight_number_p)[storeFlightNumber(self._flightPeriod)] ]
507  ;
508 
509  date =bsc::
510  lexeme_d[(year_p)[bsc::assign_a(self._flightPeriod._itYear)]
511  >> '-'
512  >> (month_p)[bsc::assign_a(self._flightPeriod._itMonth)]
513  >> '-'
514  >> (day_p)[bsc::assign_a(self._flightPeriod._itDay)]
515  ]
516  ;
517 
518  dow =bsc::lexeme_d[ dow_p ]
519  ;
520 
521  leg = leg_key >> ';' >> leg_details >> +( ';' >> leg_cabin_details )
522  ;
523 
524  leg_key =
525  (airport_p)[storeLegBoardingPoint(self._flightPeriod)]
526  >> ';'
527  >> (airport_p)[storeLegOffPoint(self._flightPeriod)]
528  ;
529 
530  leg_details =
531  time[storeBoardingTime(self._flightPeriod)]
532  >> !(date_offset)
533  >> ';'
534  >> time[storeOffTime(self._flightPeriod)]
535  >> !(date_offset)
536  >> ';'
537  >> time[storeElapsedTime(self._flightPeriod)]
538  ;
539 
540  time =bsc::
541  lexeme_d[(hours_p)[bsc::assign_a(self._flightPeriod._itHours)]
542  >> ':'
543  >> (minutes_p)[bsc::assign_a(self._flightPeriod._itMinutes)]
544  >> !(':'
545  >> (seconds_p)[bsc::assign_a(self._flightPeriod._itSeconds)])
546  ]
547  ;
548 
549  date_offset =bsc::ch_p('/')
550  >> (int1_p)[bsc::assign_a(self._flightPeriod._dateOffset)]
551  ;
552 
553  leg_cabin_details = (cabin_code_p)[storeLegCabinCode(self._flightPeriod)]
554  >> ';' >> (bsc::ureal_p)[storeCapacity(self._flightPeriod)]
555  ;
556 
557  segment_key =
558  (airport_p)[storeSegmentBoardingPoint(self._flightPeriod)]
559  >> ';'
560  >> (airport_p)[storeSegmentOffPoint(self._flightPeriod)]
561  ;
562 
563  segment_section =
564  generic_segment | specific_segment_list
565  ;
566 
567  generic_segment =bsc::
568  ch_p('0')[storeSegmentSpecificity(self._flightPeriod)]
569  >> +(';' >> segment_cabin_details)
570  ;
571 
572  specific_segment_list =bsc::
573  ch_p('1')[storeSegmentSpecificity(self._flightPeriod)]
574  >> +(';' >> segment_key >> full_segment_cabin_details)
575  ;
576 
577  full_segment_cabin_details =
578  +(';' >> segment_cabin_details)
579  ;
580 
581  segment_cabin_details =
582  (cabin_code_p)[storeSegmentCabinCode(self._flightPeriod)]
583  >> ';' >> (class_code_list_p)[storeClasses(self._flightPeriod)]
584  >> *(';' >> family_cabin_details)
585  ;
586 
587  family_cabin_details =
588  (family_code_p)[storeFamilyCode(self._flightPeriod)]
589  >> ';'
590  >> (class_code_list_p)[storeFClasses(self._flightPeriod)]
591  ;
592 
593  // BOOST_SPIRIT_DEBUG_NODE (FlightPeriodParser);
594  BOOST_SPIRIT_DEBUG_NODE (flight_period_list);
595  BOOST_SPIRIT_DEBUG_NODE (flight_period);
596  BOOST_SPIRIT_DEBUG_NODE (not_to_be_parsed);
597  BOOST_SPIRIT_DEBUG_NODE (flight_period_end);
598  BOOST_SPIRIT_DEBUG_NODE (flight_key);
599  BOOST_SPIRIT_DEBUG_NODE (airline_code);
600  BOOST_SPIRIT_DEBUG_NODE (flight_number);
601  BOOST_SPIRIT_DEBUG_NODE (date);
602  BOOST_SPIRIT_DEBUG_NODE (dow);
603  BOOST_SPIRIT_DEBUG_NODE (leg);
604  BOOST_SPIRIT_DEBUG_NODE (leg_key);
605  BOOST_SPIRIT_DEBUG_NODE (leg_details);
606  BOOST_SPIRIT_DEBUG_NODE (time);
607  BOOST_SPIRIT_DEBUG_NODE (date_offset);
608  BOOST_SPIRIT_DEBUG_NODE (leg_cabin_details);
609  BOOST_SPIRIT_DEBUG_NODE (segment_section);
610  BOOST_SPIRIT_DEBUG_NODE (segment_key);
611  BOOST_SPIRIT_DEBUG_NODE (generic_segment);
612  BOOST_SPIRIT_DEBUG_NODE (specific_segment_list);
613  BOOST_SPIRIT_DEBUG_NODE (full_segment_cabin_details);
614  BOOST_SPIRIT_DEBUG_NODE (segment_cabin_details);
615  BOOST_SPIRIT_DEBUG_NODE (family_cabin_details);
616  }
617 
618  // //////////////////////////////////////////////////////////////////
619  template<typename ScannerT>
620  bsc::rule<ScannerT> const&
622  return flight_period_list;
623  }
624 
625  }
626 
627 
629  //
630  // Entry class for the file parser
631  //
633 
634  // //////////////////////////////////////////////////////////////////////
636  FlightPeriodFileParser (stdair::BomRoot& ioBomRoot,
637  const stdair::Filename_T& iFilename)
638  : _filename (iFilename), _bomRoot (ioBomRoot) {
639  init();
640  }
641 
642  // //////////////////////////////////////////////////////////////////////
643  void FlightPeriodFileParser::init() {
644  // Check that the file exists and is readable
645  const bool doesExistAndIsReadable =
646  stdair::BasFileMgr::doesExistAndIsReadable (_filename);
647 
648  if (doesExistAndIsReadable == false) {
649  STDAIR_LOG_ERROR ("The schedule file " << _filename
650  << " does not exist or can not be read.");
651 
652  throw ScheduleInputFileNotFoundException ("The schedule file " + _filename
653  + " does not exist or can not be read");
654  }
655 
656  // Open the file
657  _startIterator = iterator_t (_filename);
658 
659  // Check the filename exists and can be open
660  if (!_startIterator) {
661  STDAIR_LOG_ERROR ("The schedule file " << _filename << " can not be open."
662  << std::endl);
663 
664  throw ScheduleInputFileNotFoundException ("The file " + _filename
665  + " does not exist or can not be read");
666  }
667 
668  // Create an EOF iterator
669  _endIterator = _startIterator.make_end();
670  }
671 
672  // //////////////////////////////////////////////////////////////////////
674  bool oResult = false;
675 
676  STDAIR_LOG_DEBUG ("Parsing schedule input file: " << _filename);
677 
678  // Initialise the parser (grammar) with the helper/staging structure.
679  ScheduleParserHelper::FlightPeriodParser lFPParser (_bomRoot,
680  _flightPeriod);
681 
682  // Launch the parsing of the file and, thanks to the doEndFlight
683  // call-back structure, the building of the whole BomRoot BOM
684  // (i.e., including Inventory, FlightDate, LegDate, SegmentDate, etc.)
685  bsc::parse_info<iterator_t> info =
686  bsc::parse (_startIterator, _endIterator, lFPParser,
687  bsc::space_p - bsc::eol_p);
688 
689  // Retrieves whether or not the parsing was successful
690  oResult = info.hit;
691 
692  const std::string hasBeenFullyReadStr = (info.full == true)?"":"not ";
693  if (oResult == true) {
694  STDAIR_LOG_DEBUG ("Parsing of schedule input file: " << _filename
695  << " succeeded: read " << info.length
696  << " characters. The input file has "
697  << hasBeenFullyReadStr
698  << "been fully read. Stop point: " << info.stop);
699 
700  } else {
701  // TODO: decide whether to throw an exception
702  STDAIR_LOG_ERROR ("Parsing of schedule input file: " << _filename
703  << " failed: read " << info.length
704  << " characters. The input file has "
705  << hasBeenFullyReadStr
706  << "been fully read. Stop point: " << info.stop);
707  }
708 
709  return oResult;
710  }
711 
712 }