dlang-community / Pegged

A Parsing Expression Grammar (PEG) module, using the D programming language.
534 stars 66 forks source link

Can't get this grammar to work, failure on second writeln. Bug? #162

Closed enjoysmath closed 8 years ago

enjoysmath commented 9 years ago

import std.stdio; import pegged.grammar; import pegged.parser; import pegged.peg;

mixin(grammar(" Math: AbstractList <- List(Var / '...') List(A) <- A (:',' A) Var <- VarBase Sub? Sub <- '_' (Nat / VarBase) VarBase <~ [a-zA-Z] Set <- VarCap Sub? / StdSets Nat <- [0-9]+ VarCap <~ [A-Z] Word <~ ([a-z]+ / [A-Z] [a-z]+) Vocab <- Word (:' ' Word) StdSets <- 'RR' / 'CC' / 'ZZ' / 'NN' / 'QQ' "));

mixin(grammar(" Let: LetStmt <- Let_X_in_Y / Let_X_be_a_Y / Let_X_be_Y Let_X_in_Y <- 'Let ' :'(' Math.AbstractList ' in ' Math.Set :')' Let_X_be_a_Y <- 'Let ' :'(' Math.Var ' be a ' Math.Vocab :')' Let_X_be_Y <- 'Let ' :'(' Math.AbstractList ' be ' Math.Vocab :')' "));

int main(string[] argv) { writeln(Let("Let (a,b,c,... in G_1)")); writeln(Let("Let (K,H,G be groups)")); readln(); return 0; }

I've tried several ways of doing it and it keeps coming back with the same error:

Let [0, 22]["Let ", "a", "b", "c", "...", " in ", "G", "", "1"] +-Let.LetStmt [0, 22]["Let ", "a", "b", "c", "...", " in ", "G", "", "1"] +-Let.Let_X_inY [0, 22]["Let ", "a", "b", "c", "...", " in ", "G", "", "1"]

Let (failure) +-Let.LetStmt (failure) +-literal!(" be ") failure at line 0, col 14, after "(K,H,G be " expected " be ", but got "groups)"

The list is absorbing the ' be' as well as if spaces can be in the list, but I coded them not to be!

Thanks for your help.

enjoysmath commented 9 years ago

I verified that it either writeln will fail, but it's always the second one. So something is wrong with your library.

veelo commented 8 years ago

Confirmed.

The problem goes away when you turn off memoization on the composed grammar (the one(s) not directly called) like this (read on for another workaround):

import std.stdio;
import pegged.grammar;

mixin(grammar!(Memoization.no)("
    Math:
        AbstractList    <- List(Var / '...')
        List(A)         <- A (:',' A)*
        Var             <- VarBase Sub?
        Sub             <- '_' (Nat / VarBase)
        VarBase         <~ [a-zA-Z]
        Set             <- VarCap Sub? / StdSets
        Nat             <- [0-9]+
        VarCap          <~ [A-Z]
        Word            <~ ([a-z]+ / [A-Z] [a-z]+)
        Vocab           <- Word (:' ' Word)*
        StdSets         <- 'RR' / 'CC' / 'ZZ' / 'NN' / 'QQ'
"));

mixin(grammar("
    Let:
        LetStmt         <- Let_X_in_Y / Let_X_be_a_Y / Let_X_be_Y
        Let_X_in_Y      <- 'Let ' :'(' Math.AbstractList ' in ' Math.Set :')'
        Let_X_be_a_Y    <- 'Let ' :'(' Math.Var ' be a ' Math.Vocab :')'
        Let_X_be_Y      <- 'Let ' :'(' Math.AbstractList ' be ' Math.Vocab :')'
"));

void main(string[] argv)
{
    writeln(Let("Let (a,b,c,... in G_1)"));
    writeln(Let("Let (K,H,G be groups)"));
}

I think I know what the problem is. Every grammar has its own memoization table. The memoization table is cleared when a rule is called with a string, which usually means a new parse is started. But that happens only for the outer grammar, not for the ones called indirectly through composition.

So we need a way so clear all memoization tables in all grammars.

In the mean time, the workaround for memoizing parsers is to insert a dummy direct call to the other grammar like this:

import std.stdio;
import pegged.grammar;

mixin(grammar("
    Math:
        AbstractList    <- List(Var / '...')
        List(A)         <- A (:',' A)*
        Var             <- VarBase Sub?
        Sub             <- '_' (Nat / VarBase)
        VarBase         <~ [a-zA-Z]
        Set             <- VarCap Sub? / StdSets
        Nat             <- [0-9]+
        VarCap          <~ [A-Z]
        Word            <~ ([a-z]+ / [A-Z] [a-z]+)
        Vocab           <- Word (:' ' Word)*
        StdSets         <- 'RR' / 'CC' / 'ZZ' / 'NN' / 'QQ'
"));

mixin(grammar("
    Let:
        LetStmt         <- Let_X_in_Y / Let_X_be_a_Y / Let_X_be_Y
        Let_X_in_Y      <- 'Let ' :'(' Math.AbstractList ' in ' Math.Set :')'
        Let_X_be_a_Y    <- 'Let ' :'(' Math.Var ' be a ' Math.Vocab :')'
        Let_X_be_Y      <- 'Let ' :'(' Math.AbstractList ' be ' Math.Vocab :')'
"));

void main(string[] argv)
{
    writeln(Let("Let (a,b,c,... in G_1)"));
    auto dummy = Math("");
    writeln(Let("Let (K,H,G be groups)"));
}

Bastiaan.