alex / rply

An attempt to port David Beazley's PLY to RPython, and give it a cooler API.
BSD 3-Clause "New" or "Revised" License
381 stars 60 forks source link

How would you parse a standard if - else if - else statement? #86

Open jonhue opened 5 years ago

jonhue commented 5 years ago

I tried quite a few things and still did not find a way to do this.

It seems to me as if the parser desperately tries to follow one path and when it fails, instead of looking for another, it just stops.

Here is my current implementation of a parser:

        @self.pg.production('file : ')
        @self.pg.production('file : expression_seq')

        @self.pg.production('block : INDENT expression_seq DEDENT')

        @self.pg.production('expression_seq : expression')
        @self.pg.production('expression_seq : expression NEWLINE expression_seq')

        @self.pg.production('else_clause : else NEWLINE block')

        @self.pg.production('else_if_clause : else_if expression NEWLINE block')

        @self.pg.production('else_if_clause_seq : else_if_clause')
        @self.pg.production('else_if_clause_seq : else_if_clause NEWLINE else_if_clause_seq')

        @self.pg.production('expression : if expression NEWLINE block')
        @self.pg.production('expression : if expression NEWLINE block NEWLINE else_if_clause_seq')
        @self.pg.production('expression : if expression NEWLINE block NEWLINE else_clause')
        @self.pg.production('expression : if expression NEWLINE block NEWLINE else_if_clause_seq NEWLINE else_clause')

        @self.pg.production('expression : INTEGER')

        @self.pg.production('expression : false')
        @self.pg.production('expression : true')

Here is the grammar:

file = [ expression_seq ] ;
expression_seq = expression , { NEWLINE , expression } ;
block = INDENT , expression_seq , DEDENT ;
expression = if | INTEGER | 'false' | 'true' ;
if = 'if' , expression , NEWLINE , block , { NEWLINE , else_if_clause_seq } , [ NEWLINE , else_clause ] ;
else_clause = 'else' , block ;
else_if_clause = 'else if' , expression , NEWLINE , block ;
else_if_clause_seq = else_if_clause , { NEWLINE , else_if_clause } ;

Is there something wrong with my rules? How would you implement such a (common) grammar?

jonhue commented 5 years ago

So as of now, the parser parses:

if true
  1
else
  1

true

but not:

if true
  1

true
=> rply.errors.ParsingError: (None, SourcePosition(idx=13, lineno=4, colno=1))

or

if true
  1
else if true
  1
else
  1

true
=> rply.errors.ParsingError: (None, SourcePosition(idx=29, lineno=5, colno=1))
shellbit32 commented 5 years ago

Have you managed to figure this out? I'm facing a similar problem

jonhue commented 5 years ago

@FernandoLGL https://stackoverflow.com/questions/54205626/how-would-you-parse-a-standard-if-else-if-else-statement-with-rply

shellbit32 commented 5 years ago

Thanks! My problem wasn't really a shift/reduce problem, but this rep https://github.com/joshsharp/python-braid helped me. I'm just making a simple SQL-like language but was having a similar issue when defining SELECT