Community
Participate
Working Groups
I am working on a grammar to specify cron expressions (like the ones within the crontab file in Unix). For some inputs the grammar works fine, but for others that seem to be right the generated Eclipse IDE shows an error. I search for help in stackoverflow (http://stackoverflow.com/questions/30880548/xtext-grammar-describing-cron-expression-not-working-as-expected) and a user suggested that the error comes from the use of hidden(), and effectively, when I removed the hidden statements all cases work ok (however in a cron expression spaces are important). The following grammar and input allow to reproduce the error. Grammar: --------------------------------- grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals generate myDsl "http://www.xtext.org/example/mydsl/MyDsl" Model: expressions+=CronExpression*; CronExpression : '(' seconds = CronElement minutes = CronElement hours = CronElement days = CronElement months = CronElement daysOfWeek = CronElement (year = CronElement)? ')' | '@' constant = ID ; CronElement : TerminalCronElement | RangeCronElement | PeriodicCronElement ; RangeCronElement hidden() : start = IntLiteral '-' end = IntLiteral | start = ID '-' end = ID ; TerminalCronElement : expression = (IntLiteral | ID | '*' | '?') ; PeriodicCronElement hidden() : expression = TerminalCronElement '/' elements = RangeCronList ; RangeCronList hidden() : elements += (TerminalCronElement | RangeCronElement) (',' elements += (TerminalCronElement | RangeCronElement))* ; IntLiteral : INT ; Demo input: --------------------------------- (0 */1,10-20 * * * *) // works ok! (0 */1 * * * *) // shows error: no viable alternative at input '1'
I don't see how whitespace is significant for parsing. If you just want to disallow whitespace you are better off invalidating it afterwards, because then you also have more control over what and how you tell the user (i.e. 'unexpected token RULE_WS' is not super useful). The problem here is, that we need a look ahead of 2 in order to decide whether to enter the rule TerminalCronElement or RangeCronElement. Both alternatives check the token at LA(2) for possible follow ups. Unfortunately as we are in a hidden() context the token is WS, but that is not listed as a possible follow up, since the rule where the follow up tokens come from does hide whitespaces. Your grammar works, if you rewrite the problematic part a bit like this: Model: expressions+=CronExpression*; CronExpression : '(' seconds = CronElement minutes = CronElement hours = CronElement days = CronElement months = CronElement daysOfWeek = CronElement (year = CronElement)? ')' | '@' constant = ID ; CronElement : RangeCronElement | PeriodicCronElement ; RangeCronElement hidden() : TerminalCronElement ({RangeCronElement.start=current}'-' end = IntLiteral)* ; TerminalCronElement : expression = (IntLiteral | ID | '*' | '?') ; PeriodicCronElement hidden() : expression = TerminalCronElement '/' elements = RangeCronList ; RangeCronList hidden() : elements += RangeCronElement (',' elements +=RangeCronElement)* ; IntLiteral : INT ; (note the change in RangeCronElement) But here you'll have to invalidate things like *-3 or ?-5. I suggest you try to do without the use of hidden().