Quantcast

A way of using multiple parsers in one: is this a safe code?

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

A way of using multiple parsers in one: is this a safe code?

oxygenecore
Hello, this is a repost of question on stackoverflow, posted there because I couldn't find a reference to discussion forums.

I have an application that uses xml config file, where I'm describing layouts for components.
Currently I have 3 layouts: grid, horizontal and vertical.
I want to create a layout which will use those three.

Finally I found a way to do this: for each of the layout class I define a protected package-protected field of that layout class a initialize them in declaration. My general rule uses those fields. The only thing to remember is that they all have their own stacks, which is not a problem, because you can call a code like this: `push(gridLayoutParser.pop())`.

Here is the example of usage of different parsers in one:

First child parser:

     public static class P1 extends BaseParser<String> {
        public Rule FullContent() {
            return Sequence(Content(), EOI);
        }

        public Rule Content() {
            return Sequence(
                    push(""),
                    String("STRING1"),
                    swap() && push(pop() + " fromParser1 "),
                    String(" SOMESTRING1 ")
            );
        }
    }

The second is the same:


    public static class P2 extends BaseParser<String> {
        public Rule FullContent() {
            return Sequence(Content(), EOI);
        }

        public Rule Content() {
            return Sequence(
                    push(""),
                    String("STRING2"),
                    swap() && push(pop() + " fromParser2 "),
                    String(" SOMESTRING2 ")
            );
        }
    }

And here the parser that uses both of them:

public class OP extends BaseParser<String> {

    protected P1 bool1 = Parboiled.createParser(P1.class);
    protected P2 bool2 = Parboiled.createParser(P2.class);

    public Rule FullContent() {
        return Sequence(
                push(""),
                OneOrMore(
                        FirstOf(
                                Sequence(
                                        bool1.Content(),
                                        swap() && push(pop() + bool1.pop())
                                        ),
                                Sequence(
                                        bool2.Content(),
                                        swap() && push(pop() + bool2.pop())
                                )
                        )

                )
        );
    }
}

For me it works fine. But will it be fine for more complex grammars?
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: A way of using multiple parsers in one: is this a safe code?

mathias
Administrator
Hmm.. I'm not sure as to the core of your question.

> For me it works fine. But will it be fine for more complex grammars?

What do you mean by more complex grammars?
Why do you suspect "it not working" then?

Note that I don't really see a benefit in creating fully separate parser as you do in your example.
You can simply "merge" smaller parsers into larger ones via inheritance or composition.

Cheers,
Mathias

---
[hidden email]
http://www.parboiled.org

On 16.11.2011, at 10:27, oxygenecore [via parboiled users] wrote:

> Hello, this is a repost of question on stackoverflow, because I couldn't find a reference to discussion forums.
>
> I have an application that uses xml config file, where I'm describing layouts for components.
> Currently I have 3 layouts: grid, horizontal and vertical.
> I want to create a layout which will use those three.
>
> Finally I found a way to do this: for each of the layout class I define a protected package-protected field of that layout class a initialize them in declaration. My general rule uses those fields. The only thing to remember is that they all have their own stacks, which is not a problem, because you can call a code like this: `push(gridLayoutParser.pop())`.
>
> Here is the example of usage of different parsers in one:
>
> First child parser:
>
>      public static class P1 extends BaseParser<String> {
>         public Rule FullContent() {
>             return Sequence(Content(), EOI);
>         }
>
>         public Rule Content() {
>             return Sequence(
>                     push(""),
>                     String("STRING1"),
>                     swap() && push(pop() + " fromParser1 "),
>                     String(" SOMESTRING1 ")
>             );
>         }
>     }
>
> The second is the same:
>
>
>     public static class P2 extends BaseParser<String> {
>         public Rule FullContent() {
>             return Sequence(Content(), EOI);
>         }
>
>         public Rule Content() {
>             return Sequence(
>                     push(""),
>                     String("STRING2"),
>                     swap() && push(pop() + " fromParser2 "),
>                     String(" SOMESTRING2 ")
>             );
>         }
>     }
>
> And here the parser that uses both of them:
>
> public class OP extends BaseParser<String> {
>
>     protected P1 bool1 = Parboiled.createParser(P1.class);
>     protected P2 bool2 = Parboiled.createParser(P2.class);
>
>     public Rule FullContent() {
>         return Sequence(
>                 push(""),
>                 OneOrMore(
>                         FirstOf(
>                                 Sequence(
>                                         bool1.Content(),
>                                         swap() && push(pop() + bool1.pop())
>                                         ),
>                                 Sequence(
>                                         bool2.Content(),
>                                         swap() && push(pop() + bool2.pop())
>                                 )
>                         )
>
>                 )
>         );
>     }
> }
>
> For me it works fine. But will it be fine for more complex grammars?
>
> If you reply to this email, your message will be added to the discussion below:
> http://users.parboiled.org/A-way-of-using-multiple-parsers-in-one-is-this-a-safe-code-tp3512129p3512129.html
> To start a new topic under parboiled users, email [hidden email]
> To unsubscribe from parboiled users, click here.
> NAML

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: A way of using multiple parsers in one: is this a safe code?

oxygenecore
I'm don't know how parboiled works under the hood, if it depends on some resources of the current parser class or not. Because when I tried to call parser.put() before parsing process, I got an exception.

I'm not sure what do you mean by "you can simply "merge" smaller parsers into larger ones via inheritance or composition", because I want to do exactly the same - use different parsers in composition.
Can you please explain? Is there any other way to use Rules defined in separate classes together in one parsing process?
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: A way of using multiple parsers in one: is this a safe code?

mathias
Administrator
I'm sorry, my reply from yesterday was somewhat misleading (aka "wrong").
With parboiled for Java you have two options of splitting up larger grammars into smaller pieces.

You can either use inheritance:

    class ParserA extends BaseParser<Object> {
        Rule A() { return ...; }
    }

    class ParserB extends ParserA {
        Rule B() { return Sequence("a", A()); }
    }

and simply instantiate your parser with `Parboiled.createParser(B.class)`.

Or you can use composition without inheritance in a way similar to what you already have:

    class ParserA extends BaseParser<Object> {
        Rule A() { return ...; }
    }

    class ParserB extends BaseParser<Object> {
        A a = Parboiled.createParser(A.class)
        Rule B() { return Sequence("a", a.A()); }

        @Override
        public void setContext(Context<V> context) {
           a.setContext(context);
           super.setContext(context);
        }
    }

and instantiate your parser with `Parboiled.createParser(B.class)`.

Note that there is only _one_ ValueStack for the whole parsing run (it's kept in the MatcherContext). What is important is to "connect" the setContext methods in the way shown above. Once you do this you don't have to do things like `push(gridLayoutParser.pop())`.

HTH and cheers,
Mathias

---
[hidden email]
http://www.parboiled.org

On 17.11.2011, at 04:15, oxygenecore [via parboiled users] wrote:

> I'm don't know how parboiled works under the hood, if it depends on some resources of the current parser class or not. Because when I tried to call parser.put() before parsing process, I get an exception.
>
> I'm not sure what do you mean by "you can simply "merge" smaller parsers into larger ones via inheritance or composition", because I want to do exactly the same - use different parsers in composition.
> Can you please explain? Is there any other way to use Rules defined in separate classes together in one parsing process?
>
> If you reply to this email, your message will be added to the discussion below:
> http://users.parboiled.org/A-way-of-using-multiple-parsers-in-one-is-this-a-safe-code-tp3512129p3514676.html
> To start a new topic under parboiled users, email [hidden email]
> To unsubscribe from parboiled users, click here.
> NAML

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: A way of using multiple parsers in one: is this a safe code?

oxygenecore
Thanks Mathias, your answer was very comprehensive.
foo
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: A way of using multiple parsers in one: is this a safe code?

foo
In reply to this post by mathias
I'm a bit confused. Can you give an example where not connecting contexts causes it to break?

Because if I do something like:

public class CompositionTest {
  static class AParser extends BaseParser<String> {
    BParser b = Parboiled.createParser(BParser.class);

    Rule A() {
      /* same behavior regardless */
      return Sequence(push("A"), b.B(), push("?"), drop());
      // return Sequence(push("A"), b.B(), push("?"), b.drop());
      // return Sequence(push("A"), b.B(), b.push("?"), drop());
      // return Sequence(push("A"), b.B(), b.push("?"), b.drop());
    }
  }

  static class BParser extends BaseParser<String> {
    Rule B() {
      return Sequence(drop(), push("B"));
    }
  }

  public static void main(String[] args) {
    AParser a = Parboiled.createParser(AParser.class);
    BasicParseRunner r = new BasicParseRunner<>(a.A());
    ParsingResult result = r.run("");
    System.out.println(result.matched);
    System.out.println(result.resultValue);
  }
}

It doesn't seem to make a difference. And while debugging, setContext() is called on b anyway.
Loading...