Skip to content

Commit

Permalink
Catch incorrectly terminated productions.
Browse files Browse the repository at this point in the history
Previously, if action code was followed by symbols, those would be added
to the rule, which clearly isn't what should happen. So:

```
R: A {B} C;
```

would be a rule "R" with symbols [A, C] and action code C. Whatever the
user intended to write, this probably wasn't the outcome they expected!

This commit catches this syntax error, removing a footgun.
  • Loading branch information
ltratt committed Jun 6, 2024
1 parent 05e40d1 commit ec9ad7a
Showing 1 changed file with 25 additions and 1 deletion.
26 changes: 25 additions & 1 deletion cfgrammar/src/lib/yacc/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub enum YaccGrammarErrorKind {
MismatchedBrace,
NonEmptyProduction,
PrematureEnd,
ProductionNotTerminated,
ProgramsNotSupported,
UnknownDeclaration,
PrecNotFollowedByToken,
Expand Down Expand Up @@ -91,6 +92,7 @@ impl fmt::Display for YaccGrammarErrorKind {
YaccGrammarErrorKind::MismatchedBrace => "Mismatched brace",
YaccGrammarErrorKind::NonEmptyProduction => "%empty used in non-empty production",
YaccGrammarErrorKind::PrematureEnd => "File ends prematurely",
YaccGrammarErrorKind::ProductionNotTerminated => "Production not terminated correctly",
YaccGrammarErrorKind::ProgramsNotSupported => "Programs not currently supported",
YaccGrammarErrorKind::UnknownDeclaration => "Unknown declaration",
YaccGrammarErrorKind::DuplicatePrecedence => "Token has multiple precedences specified",
Expand Down Expand Up @@ -231,6 +233,7 @@ impl Spanned for YaccGrammarError {
| YaccGrammarErrorKind::MismatchedBrace
| YaccGrammarErrorKind::NonEmptyProduction
| YaccGrammarErrorKind::PrematureEnd
| YaccGrammarErrorKind::ProductionNotTerminated
| YaccGrammarErrorKind::PrecNotFollowedByToken
| YaccGrammarErrorKind::ProgramsNotSupported
| YaccGrammarErrorKind::UnknownDeclaration
Expand Down Expand Up @@ -685,8 +688,14 @@ impl YaccParser {
i = k;
} else if self.lookahead_is("{", i).is_some() {
let (j, a) = self.parse_action(i)?;
i = j;
i = self.parse_ws(j, true)?;
action = Some(a);

if syms.is_empty()
|| !(self.lookahead_is("|", i).is_some() || self.lookahead_is(";", i).is_some())
{
return Err(self.mk_error(YaccGrammarErrorKind::ProductionNotTerminated, i));
}
} else if let Some(mut j) = self.lookahead_is("%empty", i) {
j = self.parse_ws(j, true)?;
// %empty could be followed by all sorts of weird syntax errors: all we try and do
Expand Down Expand Up @@ -2606,4 +2615,19 @@ B";
16,
);
}

#[test]
fn test_action_successor() {
let src = "
%%
A: B {} B;
B: ;
";
parse(YaccKind::Original(YaccOriginalActionKind::NoAction), src).expect_error_at_line_col(
src,
YaccGrammarErrorKind::ProductionNotTerminated,
3,
17,
);
}
}

0 comments on commit ec9ad7a

Please sign in to comment.