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 %%