Warning, /libraries/kopeninghours/src/lib/openinghoursparser.y is written in an unsupported language. File is not indexed.

0001 %{
0002 /*
0003     SPDX-FileCopyrightText: 2020 Volker Krause <vkrause@kde.org>
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "openinghours_p.h"
0008 #include "openinghoursparser_p.h" // generated
0009 #include "openinghoursscanner_p.h" // generated
0010 #include "logging.h"
0011 
0012 using namespace KOpeningHours;
0013 
0014 void yyerror(YYLTYPE *loc, OpeningHoursPrivate *parser, yyscan_t scanner, char const* msg)
0015 {
0016     Q_UNUSED(scanner);
0017     qCDebug(Log) << "PARSER ERROR:" << msg << "at position" << loc->first_column;
0018     parser->m_error = OpeningHours::SyntaxError;
0019 }
0020 
0021 static void initSelectors(Selectors &sels)
0022 {
0023     sels.timeSelector = nullptr;
0024     sels.weekdaySelector = nullptr;
0025     sels.weekSelector = nullptr;
0026     sels.monthdaySelector = nullptr;
0027     sels.yearSelector = nullptr;
0028     sels.wideRangeSelectorComment.str = nullptr;
0029     sels.wideRangeSelectorComment.len = 0;
0030     sels.seen_24_7 = false;
0031     sels.colonAfterWideRangeSelector = false;
0032 }
0033 
0034 static void applySelectors(const Selectors &sels, Rule *rule)
0035 {
0036     rule->m_timeSelector.reset(sels.timeSelector);
0037     rule->m_weekdaySelector.reset(sels.weekdaySelector);
0038     rule->m_weekSelector.reset(sels.weekSelector);
0039     rule->m_monthdaySelector.reset(sels.monthdaySelector);
0040     rule->m_yearSelector.reset(sels.yearSelector);
0041     rule->m_seen_24_7 = sels.seen_24_7;
0042     rule->m_colonAfterWideRangeSelector = sels.colonAfterWideRangeSelector;
0043     rule->m_wideRangeSelectorComment = QString::fromUtf8(sels.wideRangeSelectorComment.str, sels.wideRangeSelectorComment.len);
0044 }
0045 
0046 static bool extendMonthdaySelector(MonthdayRange *monthdaySelector, int beginDay, int endDay)
0047 {
0048     const auto prevSelector = lastSelector(monthdaySelector);
0049     if (prevSelector->begin.year == prevSelector->end.year
0050      && prevSelector->begin.month == prevSelector->end.month)
0051     {
0052         auto sel = new MonthdayRange;
0053         sel->begin = sel->end = prevSelector->end;
0054         sel->begin.day = beginDay;
0055         sel->end.day = endDay;
0056         appendSelector(prevSelector, sel);
0057         return true;
0058     }
0059     return false;
0060 }
0061 
0062 %}
0063 
0064 %code requires {
0065 
0066 #include "openinghours_p.h"
0067 #include "interval.h"
0068 
0069 using namespace KOpeningHours;
0070 
0071 struct StringRef {
0072     const char *str;
0073     int len;
0074 };
0075 
0076 struct Selectors {
0077     Timespan *timeSelector;
0078     WeekdayRange *weekdaySelector;
0079     Week *weekSelector;
0080     MonthdayRange *monthdaySelector;
0081     YearRange *yearSelector;
0082     StringRef wideRangeSelectorComment;
0083     bool seen_24_7;
0084     bool colonAfterWideRangeSelector;
0085 };
0086 
0087 #ifndef YY_TYPEDEF_YY_SCANNER_T
0088 #define YY_TYPEDEF_YY_SCANNER_T
0089 typedef void* yyscan_t;
0090 #endif
0091 
0092 }
0093 
0094 %define api.pure
0095 %define parse.error verbose
0096 
0097 %locations
0098 %lex-param { yyscan_t scanner }
0099 %parse-param { KOpeningHours::OpeningHoursPrivate *parser }
0100 %parse-param { yyscan_t scanner }
0101 
0102 %glr-parser
0103 %expect 18
0104 // (1) is for "T_YEAR T_COMMA T_YEAR T_MONTH", which is syntactically invalid anyway
0105 // (2) and (3) are for overlaps between weekday/holiday sequences and holiday-on-weekday selectors, which are also invalid
0106 %expect-rr 3
0107 
0108 %union {
0109     int num;
0110     StringRef strRef;
0111     State state;
0112     Rule *rule;
0113     Time time;
0114     Selectors selectors;
0115     Timespan *timespan;
0116     NthEntry nthEntry;
0117     NthSequence *nthSequence;
0118     WeekdayRange *weekdayRange;
0119     Week *week;
0120     Date date;
0121     MonthdayRange *monthdayRange;
0122     DateOffset dateOffset;
0123     YearRange *yearRange;
0124 }
0125 
0126 %token T_NORMAL_RULE_SEPARATOR
0127 %token T_ADDITIONAL_RULE_SEPARATOR
0128 %token T_FALLBACK_SEPARATOR
0129 
0130 %token <state> T_STATE
0131 
0132 %token T_24_7
0133 %token <num> T_YEAR
0134 
0135 %token T_PLUS
0136 %token T_MINUS
0137 %token T_SLASH
0138 %token T_COLON
0139 %token T_COMMA
0140 
0141 %token T_ALT_TIME_SEP
0142 %token T_ALT_TIME_SEP_OR_SUFFIX
0143 %token <num> T_ALT_TIME_AM
0144 %token <num> T_ALT_TIME_PM
0145 %token <num> T_4DIGIT_TIME
0146 
0147 %token T_ALT_RANGE_SEP
0148 
0149 %token <time> T_EVENT
0150 
0151 %token T_LBRACKET
0152 %token T_RBRACKET
0153 %token T_LPAREN
0154 %token T_RPAREN
0155 
0156 %token T_PH
0157 %token T_SH
0158 
0159 %token T_KEYWORD_DAY
0160 %token T_KEYWORD_WEEK
0161 
0162 %token T_EASTER
0163 %token T_WHITSUN
0164 
0165 %token <num> T_WEEKDAY
0166 %token <num> T_MONTH
0167 %token <num> T_INTEGER
0168 
0169 %token <strRef> T_COMMENT
0170 
0171 %token T_INVALID
0172 
0173 %type <rule> Rule
0174 %type <selectors> SelectorSequence
0175 %type <selectors> WideRangeSelector
0176 %type <selectors> SmallRangeSelector
0177 %type <selectors> TimeSelector
0178 %type <selectors> WeekdaySelector
0179 %type <selectors> WeekSelector
0180 %type <selectors> MonthdaySelector
0181 %type <selectors> YearSelector
0182 %type <selectors> YearSelectorCombined
0183 %type <timespan> Timespan
0184 %type <time> Time
0185 %type <time> VariableTime
0186 %type <time> ExtendedHourMinute
0187 %type <weekdayRange> HolidayAndWeekdaySequence
0188 %type <weekdayRange> HolidayAndWeekday
0189 %type <weekdayRange> HolidayOrWeekdaySequence
0190 %type <weekdayRange> WeekdaySequence
0191 %type <weekdayRange> WeekdayRange
0192 %type <weekdayRange> HolidaySequence
0193 %type <weekdayRange> Holiday
0194 %type <nthSequence> NthSequence
0195 %type <nthEntry> NthEntry
0196 %type <num> DayOffset
0197 %type <dateOffset> DateOffset
0198 %type <week> Week
0199 %type <date> DateFrom
0200 %type <date> DateTo
0201 %type <date> VariableDate
0202 %type <monthdayRange> MonthdayRange
0203 %type <monthdayRange> MonthdayRangeAdditional
0204 %type <dateOffset> AltMonthdayOffset
0205 %type <yearRange> YearRange
0206 %type <yearRange> YearRangeStandalone
0207 
0208 %destructor { delete $$; } <rule>
0209 %destructor {
0210     delete $$.timeSelector;
0211     delete $$.weekdaySelector;
0212     delete $$.weekSelector;
0213     delete $$.monthdaySelector;
0214     delete $$.yearSelector;
0215 } <selectors>
0216 %destructor { delete $$; } <timespan>
0217 %destructor { delete $$; } <nthSequence>
0218 %destructor { delete $$; } <weekdayRange>
0219 %destructor { delete $$; } <week>
0220 %destructor { delete $$; } <monthdayRange>
0221 %destructor { delete $$; } <yearRange>
0222 
0223 // resolve SR conflict between the YearSelector and MonthdaySelector on T_YEAR T_MONTH
0224 %nonassoc T_YEAR
0225 %nonassoc T_MONTH
0226 
0227 %verbose
0228 
0229 %%
0230 // see https://wiki.openstreetmap.org/wiki/Key:opening_hours/specification
0231 
0232 Ruleset:
0233   Rule[R] { parser->addRule($R); }
0234 | Ruleset T_NORMAL_RULE_SEPARATOR Rule[R] { parser->addRule($R); }
0235 | Ruleset T_ADDITIONAL_RULE_SEPARATOR Rule[R] {
0236     $R->m_ruleType = Rule::AdditionalRule;
0237     parser->addRule($R);
0238   }
0239 | Ruleset T_FALLBACK_SEPARATOR Rule[R] {
0240     $R->m_ruleType = Rule::FallbackRule;
0241     parser->addRule($R);
0242   }
0243 | Ruleset T_SLASH error {
0244     if (!parser->isRecovering()) {
0245         parser->restartFrom(@3.first_column, Rule::NormalRule);
0246         parser->m_ruleSeparatorRecovery = true;
0247         yyerrok;
0248     } else {
0249         YYERROR;
0250     }
0251   }
0252 | Ruleset error {
0253     if (!parser->isRecovering()) {
0254         parser->restartFrom(@2.first_column, Rule::GuessRuleType);
0255         parser->m_ruleSeparatorRecovery = true;
0256         yyerrok;
0257     } else {
0258         YYERROR;
0259     }
0260   }
0261 ;
0262 
0263 Rule:
0264   SelectorSequence[S] {
0265     $$ = new Rule;
0266     applySelectors($S, $$);
0267   }
0268 | SelectorSequence[S] T_COMMENT[C] {
0269     $$ = new Rule;
0270     $$->setComment($C.str, $C.len);
0271     applySelectors($S, $$);
0272   }
0273 | SelectorSequence[S] T_STATE[T] {
0274     $$ = new Rule;
0275     $$->setState($T);
0276     applySelectors($S, $$);
0277   }
0278 | SelectorSequence[S] T_STATE[T] T_COMMENT[C] {
0279     $$ = new Rule;
0280     $$->setComment($C.str, $C.len);
0281     $$->setState($T);
0282     applySelectors($S, $$);
0283   }
0284 | T_COMMENT[C] {
0285     $$ = new Rule;
0286     $$->setComment($C.str, $C.len);
0287   }
0288 | T_STATE[T] {
0289     $$ = new Rule;
0290     $$->setState($T);
0291   }
0292 | T_STATE[T] T_COMMENT[C] {
0293     $$ = new Rule;
0294     $$->setComment($C.str, $C.len);
0295     $$->setState($T);
0296   }
0297 ;
0298 
0299 SelectorSequence:
0300   T_24_7 { initSelectors($$); $$.seen_24_7 = true; }
0301 | SmallRangeSelector[S] { $$ = $S; }
0302 | WideRangeSelector[W] { $$ = $W; }
0303 | WideRangeSelector[W] T_COLON {
0304     $$ = $W;
0305     $$.colonAfterWideRangeSelector = true;
0306   }
0307 | WideRangeSelector[W] SmallRangeSelector[S] {
0308     $$.timeSelector = $S.timeSelector;
0309     $$.weekdaySelector = $S.weekdaySelector;
0310     $$.weekSelector = $W.weekSelector;
0311   }
0312 | WideRangeSelector[W] T_COLON SmallRangeSelector[S] {
0313     $$.timeSelector = $S.timeSelector;
0314     $$.weekdaySelector = $S.weekdaySelector;
0315     $$.weekSelector = $W.weekSelector;
0316     $$.colonAfterWideRangeSelector = true;
0317   }
0318 ;
0319 
0320 WideRangeSelector:
0321   YearSelector[Y] { $$ = $Y; }
0322 | MonthdaySelector[M] { $$ = $M; }
0323 | WeekSelector[W] { $$ = $W; }
0324 | YearSelector[Y] MonthdaySelector[M] {
0325     $$.yearSelector = $Y.yearSelector;
0326     $$.monthdaySelector = $M.monthdaySelector;
0327 }
0328 | YearSelector[Y] WeekSelector[W] {
0329     $$.yearSelector = $Y.yearSelector;
0330     $$.weekSelector = $W.weekSelector;
0331   }
0332 | MonthdaySelector[M] WeekSelector[W] {
0333     $$.monthdaySelector = $M.monthdaySelector;
0334     $$.weekSelector = $W.weekSelector;
0335   }
0336 | YearSelector[Y] MonthdaySelector[M] WeekSelector[W] {
0337     $$.yearSelector = $Y.yearSelector;
0338     $$.monthdaySelector = $M.monthdaySelector;
0339     $$.weekSelector = $W.weekSelector;
0340   }
0341 | T_COMMENT[C] T_COLON {
0342     initSelectors($$);
0343     $$.wideRangeSelectorComment = $C;
0344     $$.colonAfterWideRangeSelector = true;
0345   }
0346 ;
0347 
0348 SmallRangeSelector:
0349   TimeSelector[T] { $$ = $T; }
0350 | WeekdaySelector[W] { $$ = $W; }
0351 | WeekdaySelector[W] T_COLON { $$ = $W; }
0352 | WeekdaySelector[W] TimeSelector[T] {
0353     $$.timeSelector = $T.timeSelector;
0354     $$.weekdaySelector = $W.weekdaySelector;
0355   }
0356 | WeekdaySelector[W] T_COLON TimeSelector[T] {
0357     $$.timeSelector = $T.timeSelector;
0358     $$.weekdaySelector = $W.weekdaySelector;
0359   }
0360 ;
0361 
0362 // Time selector
0363 TimeSelector:
0364   Timespan[T] {
0365     initSelectors($$);
0366     $$.timeSelector = $T;
0367   }
0368 | TimeSelector[T1] T_COMMA Timespan[T2] {
0369     $$ = $T1;
0370     appendSelector($$.timeSelector, $T2);
0371   }
0372 | TimeSelector[T] T_COMMA error {
0373     $$ = $T;
0374     parser->restartFrom(@3.first_column, Rule::AdditionalRule);
0375     yyerrok;
0376   }
0377 | TimeSelector[T] T_SLASH Time[E] error { /* wrong use of slash as a timespan separator */
0378     $$ = $T;
0379     parser->restartFrom(@E.first_column, Rule::AdditionalRule);
0380     yyerrok;
0381   }
0382 ;
0383 
0384 Timespan:
0385   Time[T] {
0386     $$ = new Timespan;
0387     $$->begin = $$->end = $T;
0388     $$->pointInTime = true;
0389   }
0390 | Time[T] T_PLUS {
0391     $$ = new Timespan;
0392     $$->begin = $$->end = $T;
0393     $$->pointInTime = true;
0394     $$->openEnd = true;
0395   }
0396 | Time[T1] RangeSeparator Time[T2] {
0397     $$ = new Timespan;
0398     $$->begin = $T1;
0399     $$->end = $T2;
0400   }
0401 | Time[T1] RangeSeparator Time[T2] T_PLUS {
0402     $$ = new Timespan;
0403     $$->begin = $T1;
0404     $$->end = $T2;
0405     $$->openEnd = true;
0406   }
0407 | Time[T1] RangeSeparator Time[T2] T_SLASH T_INTEGER[I] {
0408     $$ = new Timespan;
0409     $$->begin = $T1;
0410     $$->end = $T2;
0411     $$->interval = $I;
0412   }
0413 | Time[T1] RangeSeparator Time[T2] T_SLASH ExtendedHourMinute[I] {
0414     $$ = new Timespan;
0415     $$->begin = $T1;
0416     $$->end = $T2;
0417     $$->interval = $I.hour * 60 + $I.minute;
0418   }
0419 ;
0420 
0421 Time:
0422   ExtendedHourMinute[T] { $$ = $T; }
0423 | VariableTime[T] { $$ = $T; }
0424 ;
0425 
0426 VariableTime:
0427   T_EVENT[E] { $$ = $E; }
0428 | T_LPAREN T_EVENT[E] T_PLUS ExtendedHourMinute[O] T_RPAREN {
0429     $$ = $E;
0430     $$.hour = $O.hour;
0431     $$.minute = $O.minute;
0432   }
0433 | T_LPAREN T_EVENT[E] T_MINUS ExtendedHourMinute[O] T_RPAREN {
0434     $$ = $E;
0435     $$.hour = -$O.hour;
0436     $$.minute = -$O.minute;
0437   }
0438 ;
0439 
0440 // Weekday selector
0441 WeekdaySelector:
0442   HolidayOrWeekdaySequence[S] {
0443     initSelectors($$);
0444     $$.weekdaySelector = $S;
0445   }
0446 | HolidayAndWeekdaySequence[S] {
0447     initSelectors($$);
0448     $$.weekdaySelector = $S;
0449   }
0450 ;
0451 
0452 HolidayAndWeekdaySequence:
0453   HolidayAndWeekday[HW] { $$ = $HW; }
0454 | HolidayAndWeekdaySequence[HW1] T_COMMA HolidayAndWeekday[HW2] {
0455     $$ = $HW1;
0456     appendSelector($$, $HW2);
0457   }
0458 ;
0459 
0460 HolidayAndWeekday:
0461   HolidaySequence[H] WeekdaySequence[W] {
0462     $$ = new WeekdayRange;
0463     $$->lhsAndSelector.reset($H);
0464     $$->rhsAndSelector.reset($W);
0465   }
0466 | WeekdaySequence[W] HolidaySequence[H] { // wrong order according to the specification
0467     $$ = new WeekdayRange;
0468     $$->lhsAndSelector.reset($H);
0469     $$->rhsAndSelector.reset($W);
0470   }
0471 ;
0472 
0473 HolidayOrWeekdaySequence:
0474   WeekdayRange[W] { $$ = $W; }
0475 | Holiday[H] { $$ = $H; }
0476 | HolidayOrWeekdaySequence[S] T_COMMA WeekdayRange[W] {
0477     $$ = $S;
0478     appendSelector($$, $W);
0479   }
0480 | HolidayOrWeekdaySequence[S] T_COMMA Holiday[H] {
0481     $$ = $S;
0482     appendSelector($$, $H);
0483   }
0484 ;
0485 
0486 WeekdaySequence:
0487   WeekdayRange[W] { $$ = $W; }
0488 | WeekdaySequence[S] T_COMMA WeekdayRange[W] {
0489     $$ = $S;
0490     appendSelector($$, $W);
0491   }
0492 ;
0493 
0494 WeekdayRange:
0495   T_WEEKDAY[D] {
0496     $$ = new WeekdayRange;
0497     $$->beginDay = $D;
0498     $$->endDay = $D;
0499   }
0500 | T_WEEKDAY[D1] RangeSeparator T_WEEKDAY[D2] {
0501     $$ = new WeekdayRange;
0502     $$->beginDay = $D1;
0503     $$->endDay = $D2;
0504   }
0505 | T_WEEKDAY[D] T_LBRACKET NthSequence[N] T_RBRACKET {
0506     $$ = new WeekdayRange;
0507     $$->beginDay = $$->endDay = $D;
0508     $$->nthSequence.reset($N);
0509   }
0510 | T_WEEKDAY[D] T_LBRACKET NthSequence[N] T_RBRACKET DayOffset[O] {
0511     $$ = new WeekdayRange;
0512     $$->beginDay = $$->endDay = $D;
0513     $$->nthSequence.reset($N);
0514     $$->offset = $O;
0515   }
0516 ;
0517 
0518 HolidaySequence:
0519   Holiday[H] { $$ = $H; }
0520 | HolidaySequence[S] T_COMMA Holiday[H] { $$ = $S; appendSelector($$, $H); }
0521 ;
0522 
0523 Holiday:
0524   T_PH {
0525     $$ = new WeekdayRange;
0526     $$->holiday = WeekdayRange::PublicHoliday;
0527   }
0528 | T_PH DayOffset[O] {
0529     $$ = new WeekdayRange;
0530     $$->holiday = WeekdayRange::PublicHoliday;
0531     $$->offset = $O;
0532   }
0533 | T_SH {
0534     $$ = new WeekdayRange;
0535     $$->holiday = WeekdayRange::SchoolHoliday;
0536   }
0537 ;
0538 
0539 NthSequence:
0540   NthEntry[N] {
0541       $$ = new NthSequence;
0542       $$->add($N);
0543   }
0544 | NthSequence[N1] T_COMMA NthEntry[N2] {
0545       $N1->add($N2);
0546       $$ = $N1;
0547   }
0548 
0549 NthEntry:
0550   T_INTEGER[N] {
0551     if ($N < 1 || $N > 5) { YYABORT; }
0552     $$ = {$N,$N};
0553   }
0554 | T_INTEGER[N1] T_MINUS T_INTEGER[N2] {
0555     if ($N1 < 1 || $N1 > 5 || $N2 < 1 || $N2 > 5 || $N2 <= $N1) { YYABORT; }
0556     $$ = {$N1,$N2};
0557   }
0558 | T_MINUS T_INTEGER[N] {
0559     if ($N < 1 || $N > 5) { YYABORT; }
0560     $$ = {-$N,-$N};
0561   }
0562 ;
0563 
0564 DayOffset:
0565   T_PLUS T_INTEGER[N] T_KEYWORD_DAY { $$ = $N; }
0566 | T_MINUS T_INTEGER[N] T_KEYWORD_DAY { $$ = -$N; }
0567 ;
0568 
0569 // Week selector
0570 WeekSelector:
0571   T_KEYWORD_WEEK Week[W] {
0572     initSelectors($$);
0573     $$.weekSelector = $W;
0574   }
0575 | WeekSelector[W1] T_COMMA Week[W2] {
0576     $$ = $W1;
0577     appendSelector($$.weekSelector, $W2);
0578   }
0579 ;
0580 
0581 Week:
0582   T_INTEGER[N] {
0583     $$ = new Week;
0584     $$->beginWeek = $$->endWeek = $N;
0585   }
0586 | T_INTEGER[N1] T_MINUS T_INTEGER[N2] {
0587     $$ = new Week;
0588     $$->beginWeek = $N1;
0589     $$->endWeek = $N2;
0590   }
0591 | T_INTEGER[N1] T_MINUS T_INTEGER[N2] T_SLASH T_INTEGER[I] {
0592     $$ = new Week;
0593     $$->beginWeek = $N1;
0594     $$->endWeek = $N2;
0595     $$->interval = $I;
0596   }
0597 ;
0598 
0599 // Month selector
0600 // the split between MonthdayRange and MonthdayRangeAdditional is to avoid matching a list of years
0601 // to avoid an ambiguity with YearRange below
0602 MonthdaySelector:
0603   MonthdayRange[M] {
0604     initSelectors($$);
0605     $$.monthdaySelector = $M;
0606   }
0607 | MonthdaySelector[S] T_COMMA MonthdayRangeAdditional[M] {
0608     $$ = $S;
0609     appendSelector($$.monthdaySelector, $M);
0610   }
0611 | MonthdaySelector[S] T_COMMA T_INTEGER[D] {
0612     // month day sets, not covered the official grammar but in the
0613     // description in https://wiki.openstreetmap.org/wiki/Key:opening_hours#Summary_syntax
0614     $$ = $S;
0615     if (!extendMonthdaySelector($$.monthdaySelector, $D, $D)) {
0616         delete $$.monthdaySelector;
0617         YYABORT;
0618     }
0619   }
0620 | MonthdaySelector[S] T_ADDITIONAL_RULE_SEPARATOR T_INTEGER[D] {
0621     // same as the above, just with the wrong ", " separator
0622     $$ = $S;
0623     if (!extendMonthdaySelector($$.monthdaySelector, $D, $D)) {
0624         delete $$.monthdaySelector;
0625         YYABORT;
0626     }
0627   }
0628 | MonthdaySelector[S] T_COMMA T_INTEGER[D1] T_MINUS T_INTEGER[D2] {
0629     // same with a range of days
0630     $$ = $S;
0631     if (!extendMonthdaySelector($$.monthdaySelector, $D1, $D2)) {
0632         delete $$.monthdaySelector;
0633         YYABORT;
0634     }
0635   }
0636 | MonthdaySelector[S] T_ADDITIONAL_RULE_SEPARATOR T_INTEGER[D1] T_MINUS T_INTEGER[D2] {
0637     // same as the above, just with the wrong ", " separator
0638     $$ = $S;
0639     if (!extendMonthdaySelector($$.monthdaySelector, $D1, $D2)) {
0640         delete $$.monthdaySelector;
0641         YYABORT;
0642     }
0643   }
0644 ;
0645 
0646 MonthdayRange:
0647   T_YEAR[Y] {
0648     $$ = new MonthdayRange;
0649     $$->begin = $$->end = { $Y, 0, 0, Date::FixedDate, { 0, 0, 0 } };
0650   }
0651 | MonthdayRangeAdditional[M] { $$ = $M; }
0652 
0653 MonthdayRangeAdditional:
0654   T_MONTH[M] {
0655     $$ = new MonthdayRange;
0656     $$->begin = $$->end = { 0, $M, 0, Date::FixedDate, { 0, 0, 0 } };
0657   }
0658 | T_YEAR[Y] T_MONTH[M] {
0659     $$ = new MonthdayRange;
0660     $$->begin = $$->end = { $Y, $M, 0, Date::FixedDate, { 0, 0, 0 } };
0661   }
0662 | T_MONTH[M1] RangeSeparator T_MONTH[M2] {
0663     $$ = new MonthdayRange;
0664     $$->begin = { 0, $M1, 0, Date::FixedDate, { 0, 0, 0 } };
0665     $$->end = { 0, $M2, 0, Date::FixedDate, { 0, 0, 0 } };
0666   }
0667 | T_YEAR[Y] T_MONTH[M1] RangeSeparator T_MONTH[M2] {
0668     $$ = new MonthdayRange;
0669     $$->begin = { $Y, $M1, 0, Date::FixedDate, { 0, 0, 0 } };
0670     $$->end = { $Y, $M2, 0, Date::FixedDate, { 0, 0, 0 } };
0671   }
0672 | T_YEAR[Y1] T_MONTH[M1] RangeSeparator T_YEAR[Y2] T_MONTH[M2] {
0673     $$ = new MonthdayRange;
0674     $$->begin = { $Y1, $M1, 0, Date::FixedDate, { 0, 0, 0 } };
0675     $$->end = { $Y2, $M2, 0, Date::FixedDate, { 0, 0, 0 } };
0676   }
0677 | T_MONTH[M1] AltMonthdayOffset[O1] RangeSeparator T_MONTH[M2] AltMonthdayOffset[O2] {
0678     $$ = new MonthdayRange;
0679     $$->begin = { 0, $M1, 0, Date::FixedDate, $O1 };
0680     $$->end = { 0, $M2, 0, Date::FixedDate, $O2 };
0681   }
0682 | DateFrom[D] {
0683     $$ = new MonthdayRange;
0684     $$->begin = $$->end = $D;
0685   }
0686 | DateFrom[D] DateOffset[O] {
0687     $$ = new MonthdayRange;
0688     $$->begin = $D;
0689     $$->begin.offset += $O;
0690     $$->end = $$->begin;
0691   }
0692 | DateFrom[F] RangeSeparator DateTo[T] {
0693     $$ = new MonthdayRange;
0694     $$->begin = $F;
0695     $$->end = $T;
0696     if ($$->end.year == 0) { $$->end.year = $$->begin.year; }
0697     if ($$->end.month == 0) { $$->end.month = $$->begin.month; }
0698   }
0699 | DateFrom[F] DateOffset[OF] RangeSeparator DateTo[T] {
0700     $$ = new MonthdayRange;
0701     $$->begin = $F;
0702     $$->begin.offset += $OF;
0703     $$->end = $T;
0704     if ($$->end.year == 0) { $$->end.year = $$->begin.year; }
0705     if ($$->end.month == 0) { $$->end.month = $$->begin.month; }
0706   }
0707 | DateFrom[F] RangeSeparator DateTo[T] DateOffset[OT] {
0708     $$ = new MonthdayRange;
0709     $$->begin = $F;
0710     $$->end = $T;
0711     if ($$->end.year == 0) { $$->end.year = $$->begin.year; }
0712     if ($$->end.month == 0) { $$->end.month = $$->begin.month; }
0713     $$->end.offset += $OT;
0714   }
0715 | DateFrom[F] RangeSeparator T_MONTH[M] AltMonthdayOffset[O] {
0716     $$ = new MonthdayRange;
0717     $$->begin = $F;
0718     $$->end = { $F.year, $M, 0, Date::FixedDate, $O };
0719   }
0720 | T_MONTH[M] AltMonthdayOffset[O] RangeSeparator DateTo[T] {
0721     $$ = new MonthdayRange;
0722     $$->begin = { 0, $M, 0, Date::FixedDate, $O };
0723     $$->end = $T;
0724   }
0725 | DateFrom[F] DateOffset[OF] RangeSeparator DateTo[T] DateOffset[OT] {
0726     $$ = new MonthdayRange;
0727     $$->begin = $F;
0728     $$->begin.offset += $OF;
0729     $$->end = $T;
0730     if ($$->end.year == 0) { $$->end.year = $$->begin.year; }
0731     if ($$->end.month == 0) { $$->end.month = $$->begin.month; }
0732     $$->end.offset += $OT;
0733   }
0734 ;
0735 
0736 DateOffset:
0737   T_PLUS T_WEEKDAY[D] { $$ = { 0, (int8_t)$D, 1 }; }
0738 | T_MINUS T_WEEKDAY[D] { $$ = { 0, (int8_t)$D, -1 }; }
0739 | DayOffset[O] { $$ = { (int16_t)$O, 0, 0 }; }
0740 ;
0741 
0742 DateFrom:
0743   T_MONTH[M] T_INTEGER[D] { $$ = { 0, $M, $D, Date::FixedDate, { 0, 0, 0 } }; }
0744 | T_YEAR[Y] T_MONTH[M] T_INTEGER[D] { $$ = { $Y, $M, $D, Date::FixedDate, { 0, 0, 0 } }; }
0745 | VariableDate[D] { $$ = $D; }
0746 | T_YEAR[Y] VariableDate[D] {
0747     $$ = $D;
0748     $$.year = $Y;
0749   }
0750 ;
0751 
0752 DateTo:
0753   DateFrom[D] { $$ = $D; }
0754 | T_INTEGER[N] { $$ = { 0, 0, $N, Date::FixedDate, { 0, 0, 0 } }; }
0755 ;
0756 
0757 VariableDate:
0758   T_EASTER { $$ = { 0, 0, 0, Date::Easter, { 0, 0, 0 } }; }
0759 | T_WHITSUN { $$ = { 0, 0, 0, Date::Easter, { 49, 0, 0 } }; }
0760 ;
0761 
0762 AltMonthdayOffset:
0763   T_WEEKDAY[D] T_LBRACKET T_INTEGER[N] T_RBRACKET { $$ = { 0, (int8_t)$D, (int8_t)$N }; }
0764 | T_WEEKDAY[D] T_LBRACKET T_MINUS T_INTEGER[N] T_RBRACKET { $$ = { 0, (int8_t)$D, (int8_t)-$N }; }
0765 | T_WEEKDAY[D] T_LBRACKET T_INTEGER[N] T_RBRACKET DayOffset[O] { $$ = { (int16_t)$O, (int8_t)$D, (int8_t)$N }; }
0766 | T_WEEKDAY[D] T_LBRACKET T_MINUS T_INTEGER[N] T_RBRACKET DayOffset[O] { $$ = { (int16_t)$O, (int8_t)$D, (int8_t)-$N }; }
0767 
0768 // Year selector
0769 // the split between the standalone and combined rules here is to avoid matching a single year
0770 // to avoid a practically relevant ambiguity with MonthdayRange
0771 YearSelector:
0772   YearRangeStandalone[Y] {
0773     initSelectors($$);
0774     $$.yearSelector = $Y;
0775   }
0776 | YearSelectorCombined[S] T_COMMA YearRange[Y] {
0777     $$ = $S;
0778     appendSelector($$.yearSelector, $Y);
0779   }
0780 ;
0781 YearSelectorCombined:
0782   YearRange[Y] {
0783     initSelectors($$);
0784     $$.yearSelector = $Y;
0785   }
0786 | YearSelectorCombined[S] T_COMMA YearRange[Y] {
0787     $$ = $S;
0788     appendSelector($$.yearSelector, $Y);
0789   }
0790 ;
0791 
0792 YearRange:
0793   T_YEAR[Y] {
0794     $$ = new YearRange;
0795     $$->begin = $$->end = $Y;
0796   }
0797 | YearRangeStandalone[Y] { $$ = $Y; }
0798 ;
0799 
0800 YearRangeStandalone:
0801   T_YEAR[Y1] RangeSeparator T_YEAR[Y2] {
0802     $$ = new YearRange;
0803     $$->begin = $Y1;
0804     $$->end = $Y2;
0805     if ($$->end < $$->begin) {
0806         delete $$;
0807         YYABORT;
0808     }
0809   }
0810 | T_YEAR[Y] T_SLASH T_INTEGER[I] {
0811     $$ = new YearRange;
0812     $$->begin = $Y;
0813     $$->interval = $I;
0814   }
0815 | T_YEAR[Y1] RangeSeparator T_YEAR[Y2] T_SLASH T_INTEGER[I] {
0816     $$ = new YearRange;
0817     $$->begin = $Y1;
0818     $$->end = $Y2;
0819     if ($$->end < $$->begin) {
0820         delete $$;
0821         YYABORT;
0822     }
0823     $$->interval = $I;
0824   }
0825 | T_YEAR[Y] T_PLUS {
0826     $$ = new YearRange;
0827     $$->begin = $Y;
0828   }
0829 
0830 // basic building blocks
0831 ExtendedHourMinute:
0832   T_INTEGER[H] T_COLON T_INTEGER[M] {
0833     $$ = { Time::NoEvent, $H, $M };
0834     if (!Time::isValid($$)) { YYABORT; }
0835   }
0836 | T_INTEGER[H] T_ALT_TIME_SEP T_INTEGER[M] {
0837     $$ = { Time::NoEvent, $H, $M };
0838     if (!Time::isValid($$)) { YYABORT; }
0839   }
0840 | T_INTEGER[H] T_COLON T_INTEGER[M] T_ALT_TIME_SEP_OR_SUFFIX {
0841     $$ = { Time::NoEvent, $H, $M };
0842     if (!Time::isValid($$)) { YYABORT; }
0843   }
0844 | T_INTEGER[H] T_ALT_TIME_SEP_OR_SUFFIX T_INTEGER[M] {
0845     $$ = { Time::NoEvent, $H, $M };
0846     if (!Time::isValid($$)) { YYABORT; }
0847   }
0848 | T_INTEGER[H] T_ALT_TIME_SEP_OR_SUFFIX {
0849     $$ = { Time::NoEvent, $H, 0 };
0850     if (!Time::isValid($$)) { YYABORT; }
0851   }
0852 | T_INTEGER[H] T_COLON T_ALT_TIME_AM[M] {
0853     $$ = { Time::NoEvent, $H, $M };
0854     Time::convertFromAm($$);
0855     if (!Time::isValid($$)) { YYABORT; }
0856   }
0857 | T_INTEGER[H] T_ALT_TIME_SEP T_ALT_TIME_AM[M] {
0858     $$ = { Time::NoEvent, $H, $M };
0859     Time::convertFromAm($$);
0860     if (!Time::isValid($$)) { YYABORT; }
0861   }
0862 | T_INTEGER[H] T_COLON T_ALT_TIME_PM[M] {
0863     $$ = { Time::NoEvent, $H, $M };
0864     Time::convertFromPm($$);
0865     if (!Time::isValid($$)) { YYABORT; }
0866   }
0867 | T_INTEGER[H] T_ALT_TIME_SEP T_ALT_TIME_PM[M] {
0868     $$ = { Time::NoEvent, $H, $M };
0869     Time::convertFromPm($$);
0870     if (!Time::isValid($$)) { YYABORT; }
0871   }
0872 | T_ALT_TIME_AM[H] {
0873     $$ = { Time::NoEvent, $H, 0 };
0874     Time::convertFromAm($$);
0875     if (!Time::isValid($$)) { YYABORT; }
0876   }
0877 | T_ALT_TIME_PM[H] {
0878     $$ = { Time::NoEvent, $H, 0 };
0879     Time::convertFromPm($$);
0880     if (!Time::isValid($$)) { YYABORT; }
0881   }
0882 | T_4DIGIT_TIME[T] {
0883     $$ = { Time::NoEvent, $T / 100, $T % 100 }; // lexer ensures this is always a valid time
0884 }
0885 ;
0886 
0887 RangeSeparator:
0888   T_MINUS
0889 | T_ALT_RANGE_SEP
0890 %%