Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

endless recursion when adding binary operation expressions to grammar #171

Closed
leeflix opened this issue Jun 5, 2024 · 3 comments
Closed
Labels

Comments

@leeflix
Copy link

leeflix commented Jun 5, 2024

i am implementing a parser for my own programming language. i am currently definining expressions as:

exp := lit | variable

this works but when i add binary expressions:

exp := lit | variable | binaryOperationExpression

i get a stack overflow for whatever i am trying to parse even when it does not contain an expression. here some more rules that could be relevant but it is kinda weird since i implemented the same grammar in scala and it worked:

statement := classDeclaration | ifStatement | whileStatement | methodCall | functionCall | expression
lit := floatLit | intLit | boolLit | stringLit | tupleLit | listLit2 | listLit1
binaryOperationExpression := expression & operator & expression

@renggli
Copy link
Member

renggli commented Jun 6, 2024

Please provide a minimal reproducible example (MRE).

An MRE is intended to reproduce an error using the smallest amount of code. It saves package developers time trying to reproduce the problem; and wading through code that is not relevant to the bug. Ultimately it helps you to get your problem solved quicker.

The MRE should include:

  1. Packages to be imported.
  2. The shortest amount of code needed to reproduce the problem.
  3. A main function that calls your code and demonstrates the problem, i.e. with a failing assertion.

@leeflix
Copy link
Author

leeflix commented Jun 6, 2024

import 'package:petitparser/petitparser.dart';

Parser a() => char("a");

Parser expression() => (ref0(binaryOperationExpression) | ref0(a)).cast();

Parser binaryOperationExpression() => (ref0(expression) & char("+") & ref0(expression));

Parser statement() => (ref0(expression)).cast();

main() {
  print(resolve(statement().end()).parse("a+a"));
}

@renggli
Copy link
Member

renggli commented Jun 6, 2024

Your grammar has left-recursive productions expression -> binaryOperationExpression, which leads to infinite recursion at runtime. Have a look look at the tutorial Writing a More Complicated Grammar and Using the Expression Builder, that demonstrate how to build expression grammars.

The simplest way to avoid the recursion is to rewrite the grammar as:

Parser a() => char("a");
Parser statement() => ref0(a).starSeparated(char('+'));

@renggli renggli closed this as completed Jun 12, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants