Allegro.cc - Online Community

Allegro.cc Forums » Off-Topic Ordeals » C++ parsing libraries for symbolic input.

Credits go to axilmar and Tobias Dammers for helping out!
This thread is locked; no one can reply to it. rss feed Print
 1   2 
C++ parsing libraries for symbolic input.
verthex
Member #11,340
September 2009
avatar

I'm using a windows GUI (made with Irrlicht, but it doesn't matter) with textbox and I want some library written with C++ and made for parsing symbols, etc. Basically I create the mnemonic and some run time machinery sorts the mnenomics out to do some operation. Is there such a thing? Is yacc/bison or lex capable of this or thats made for making a compiler?

axilmar
Member #1,204
April 2001

verthex
Member #11,340
September 2009
avatar

In your calculator.cpp example you have AST declarations, what are those for? It starts on line 61 and goes to 155?

axilmar
Member #1,204
April 2001

The AST declarations are the classes of the objects that the source code is converted into.

For example, when the rule 'num' is parsed successfully, an object of type 'num_t' is created.

verthex
Member #11,340
September 2009
avatar

Would it be easy to modify the code to include mnemonics as operators such as run,pause,repeat, etc?

axilmar
Member #1,204
April 2001

Yes, it would be easy. Just write the grammar, then the objects you wish the input to be converted to, and you're good to go.

I can assist you in it, if you tell me which commands would you like to support.

EDIT:

For example, if your input consists of simple commands, your grammar can be like this:

rule whitespace = *expr(' ');
rule run_command = "run";
rule pause_command = "pause";
rule command = run_command | pause_command;
rule grammar = *command;

Your AST would look like this:

class command : public ast_node {
};

class run : public command {
};

class pause : public command {
};

class commands : public ast_container {
public:
    ast_list<command> commands;
};

And the connections between the grammar and the AST would look like this:

ast<commands> ast_commands(grammar);
ast<run> ast_run_command(run_command);
ast<pause> ast_pause_command(pause_command);

You could then parse the input with the following code:

error_list errors;
commands *cmds;
parse(input, grammar, whitespace, errors, cmds);

When the above returns, the pointer 'cmds' would contain a pointer to a commands object, with all the commands the user typed.

Tobias Dammers
Member #2,604
August 2002
avatar

Whee, parsing is fun!

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

axilmar
Member #1,204
April 2001

Do you mean it or was it sarcasm?

In case it was sarcasm, could you please indicate to me in which areas should the parser library be improved?

verthex
Member #11,340
September 2009
avatar

What would I need to compile your calculator example using codeblocks. Anything tricky or special.

axilmar said:

Yes, it would be easy. Just write the grammar, then the objects you wish the input to be converted to, and you're good to go.

I can assist you in it, if you tell me which commands would you like to support.

I can see now from your edits on how to do it. It seems in my case I have a gui which would grab the text input and invoke the rule for example "run" when the gui button is pressed. Then I would use that to set a boolean in some other class to true. So far I think I could manage that.

Whee, parsing is fun!

This is the real world, who the fuck plays games around here anyways? :'(

Arthur Kalliokoski
Second in Command
February 2005
avatar

Quote:

This is the real world, who the plays games around here anyways? :'(

If you're not having fun, why do it? If it's only for money, I feel sorry for you.

They all watch too much MSNBC... they get ideas.

verthex
Member #11,340
September 2009
avatar

If you're not having fun, why do it? If it's only for money, I feel sorry for you.

Its for making a simple interface for a 3d engine. Basically my theory is that using a text box input would allow me to design a gui with only one text box and one button and use commands to do things. Right now I have 20 text boxes and 4 buttons and the gui is getting really complicatedly ugly and difficult to read.

Arthur Kalliokoski
Second in Command
February 2005
avatar

So simplifying it is at least satisfying, if not fun? OK then.

They all watch too much MSNBC... they get ideas.

verthex
Member #11,340
September 2009
avatar

So simplifying it is at least satisfying, if not fun? OK then.

Sometimes I get this angry feeling whenever I type code with c++, its not the same with Python though. Its the wordiness of it all.

Tobias Dammers
Member #2,604
August 2002
avatar

axilmar said:

Do you mean it or was it sarcasm?

I absolutely sincerely meant it. Writing parsers is fun.

Except if you use (f)lex/bison/yacc; those are atrociously hard to use, full of obscure edge cases, and the output has the aesthetic appeal of elephant droppings.

I've written quite a bunch of parsers myself lately: a few iterations of a template engine in PHP (started out as a four-line function that went something like preg_match_all -> array_map -> str_replace, but by now, it's a fully-fledged template language with loops and includes and whatnot). A fast C parser for a custom network protocol. A few parsers (query strings, POST message bodies, HTTP requests, etc.) for an experimental web server framework. Another template engine, this time in Haskell (allowing for arbitrary Haskell expressions to be interpolated into the template while still providing HTML-encoding where needed). A parser for my custom sheet music language, also in Haskell.

So yes, writing parsers is fun.

I like the parser-combinator approach - build a generic parser interface, a bunch of atomic parsers, a bunch of combinator parsers, and then build your final parser from these blocks, following along a BNF representation of the grammar. Haskell's Parsec library takes this to the extreme, providing a native Haskell syntax that closely resembles BNF itself:

literal = stringLiteral
        <|> charLiteral
        <|> numberLiteral

But even in a language with less flexible syntax, a similar parser can be built. E.g., in (functional-style) C++, the above could look like this:

AST_Expression* parseLiteral(ParserState& p) {
    AST_Expression* e;
    if (e = parseStringLiteral(p)) return e;
    if (e = parseCharLiteral(p)) return e;
    if (e = parseNumberLiteral(p)) return e;
    return 0; // fail, no parse.
}

Or you could do it OOP-style, which would yield something like:

#SelectExpand
1class LiteralParser : public BaseParser<AST_Expression> { 2 private: 3 AlternativesParser<AST_Expression>* subparser; 4 public: 5 LiteralParser() { 6 subparser = new AlternativesParser<AST_Expression>(); 7 subparser->addAlternative(new StringLiteralParser()); 8 subparser->addAlternative(new CharLiteralParser()); 9 subparser->addAlternative(new NumberLiteralParser()); 10 } 11 virtual ~LiteralParser() { 12 delete subparser; 13 } 14 virtual AST_Expression* parse(ParserState& p) { 15 return subparser->parse(p); 16 } 17} 18// implementing AlternativesParser left as an exercise to the reader...

I guess at this point it may be obvious why I like Haskell.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

axilmar
Member #1,204
April 2001

verthex said:

What would I need to compile your calculator example using codeblocks. Anything tricky or special.

Nothing tricky or special. A Codeblocks project file is already provided for the specific example.

So yes, writing parsers is fun.

Maybe it is, but it is a solved problem for me. This parser library allows me to convert any grammar to an AST, even if the grammar has left recursion.

Quote:

But even in a language with less flexible syntax, ... I guess at this point it may be obvious why I like Haskell.

But my c++ parser has EBNF-like syntax too. Unless I overlook something, I do not see Haskell having a particular advantage over c++ in this.

Tobias Dammers
Member #2,604
August 2002
avatar

Hey, I'm not attacking anyone here. Just saying that at least for me, Haskell is the perfect fit for these things. There's about a dozen reasons, but the obvious one is how ridiculously expressive the language is, and how little boilerplate there is in typical Haskell code. C++ isn't bad at all, but you can't deny it is pretty verbose.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

axilmar
Member #1,204
April 2001

Can you please show me how to do the Model-View-Controller pattern in Haskell?

Tobias Dammers
Member #2,604
August 2002
avatar

axilmar said:

Can you please show me how to do the Model-View-Controller pattern in Haskell?

Just like I'd do it in any other language, only I do it in Haskell. In fact, the Haskell community has produced some very fine building blocks for MVC-style web development (assuming that's what you're talking about). Really, MVC can be done in Haskell just like in any other language - it's an architectural pattern, not a language-specific one.

Also, I don't see how this has anything to do with the fact that I prefer Haskell over C++ for building parsers.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

axilmar
Member #1,204
April 2001

Really, MVC can be done in Haskell just like in any other language

The MVC pattern requires mutable objects, which Haskell does not have.

I have tried to do the MVC pattern in Haskell, but it eludes me, perhaps because I am too accustomed to imperative programming.

So, since you seem to have more experience in Haskell than me, could you please post some code on how to do the MVC pattern? more specifically, how to do the Model part?

I'll give you what I wanted to achieve: I was trying to make a pacman level editor. My model, in Java, looked like this:

#SelectExpand
1 public interface LevelContainerObserver { 2 void handleEvent(LevelContainerEvent e); 3 } 4 5 public class LevelContainer { 6 private List<Level> m_levels; 7 private List<LevelContainerObserver> m_observers; 8 9 private void invokeObservers(LevelContainerEvent ev) { 10 ListIterator<LevelContainerObserver> it = m_levelObservers.getIterator(); 11 while(it.hasNext()) { 12 LevelContainerObserver o = it.next(); 13 o.handleEvent(ev); 14 } 15 } 16 17 public void addLevel(Level level) { 18 m_levels.add(level); 19 invokeObservers(new AddLevelContainerEvent(level)); 20 } 21 22 public void removeLevel(Level level) { 23 m_levels.remove(level); 24 invokeObservers(new RemoveLevelContainerEvent(level)); 25 } 26 27 public void clearLevels() { 28 m_levels.clear(); 29 invokeObservers(new ClearLevelContainerEvent()); 30 } 31 }

The model obviously had other classes as well (Level, LevelObserver, etc).

The model allowed the view (Swing classes) to be linked to the model so as that when the model changed, the view was automatically refreshed.

I would be extremely pleased if you could do just the above class in Haskell for me. Personally, I tried to do it but I always end up with type errors.

Tobias Dammers
Member #2,604
August 2002
avatar

axilmar said:

The MVC pattern requires mutable objects, which Haskell does not have.

Uh... what? No. MVC, again, is an architectural pattern; whether or not your programming language provides mutable data structures or not is completely irrelevant.

Just because Haskell values are immutable doesn't mean you can't have mutable state; you just have to implement it on top of immutable objects (this is what the State, Reader and Writer monads and monad transformers are for). You don't modify objects in-place; instead, you write your logic in terms of functions that map old state to new state, and wrap them in a State monad to provide the syntactic sugar to make them behave as if they were mutable.

Quote:

I would be extremely pleased if you could do just the above class in Haskell for me. Personally, I tried to do it but I always end up with type errors.

I'd have to look into how Haskell's GTK bindings do things, but my guess would be that Java's event listener model doesn't translate easily to Haskell; you'll have to do it the Haskell way.

I'd design it so that the controller polls the view for input, then dispatches it to the model and receives a response that tells it what has been changed; this in turn would be used to update the view accordingly. The controller would probably run some kind of main loop, something like:

#SelectExpand
1data AppState = AppState { 2 appstateView :: View, 3 appstateModel :: Model 4 } 5 6mainLoop :: AppState -> IO AppState 7mainLoop a = 8 if isExitCondition a 9 then a 10 else (mainLoopStep a >>= mainLoop) 11 12mainLoopStep :: AppState -> IO AppState 13mainLoopStep a = do 14 let view = appstateView a 15 model = appstateModel a 16 command <- getNextCommand view 17 (newModel, commandResult) <- runCommand model command 18 newView <- processCommandResult view commandResult 19 return $ a { view = newView; model = newModel }

And then you could define a bunch of commands and command results, and implement runCommand and processCommandResult to dispatch them.

Note, however, that I haven't written any desktop GUI applications in a while, and there are probably more elegant ways of solving this. For starters, you could wrap the main loop in a state monad of type AppState, but I'll leave it as explicit as this.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

axilmar
Member #1,204
April 2001

That's not MVC. There are no registrations and unregistrations of observers anywhere in your code.

Tobias Dammers
Member #2,604
August 2002
avatar

MVC does not mandate registrations and unregistrations of observers. The whole event listener / observer pattern thing is a Javaism (or rather, a class-based-OOP-ism), and it doesn't translate to other paradigms as-is. It is completely orthogonal to MVC design. MVC simply means: Model = representation of domain logic; View = present data to the user; Controller = get user input and dispatch to model and view.

The observer pattern is one way of doing this, but it's not the only one, and not necessarily the best.

Here's the relevant wikipedia entry to remind you: https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

Matthew Leverton
Supreme Loser
January 1999
avatar

Tobias got owned by an axilmar setup. 8-)

Tobias Dammers
Member #2,604
August 2002
avatar

Heh, yeah. Walked right into at least two consecutive strawmen. At least we have established that Haskell is unsuitable for building parsers because I don't know how to implement Swing event listeners with it.

---
Me make music: Triofobie
---
"We need Tobias and his awesome trombone, too." - Johan Halmén

axilmar
Member #1,204
April 2001

The wikipedia article says that "the view observes the model", and therefore the solution you provided is not an implementation of the MVC pattern.

 1   2 


Go to: