9

I want to make a simple, proof-of-concept application (REPL) that takes a number and then processes commands on that number.

Example: I start with 1. Then I write "add 2", it gives me 3. Then I write "multiply 7", it gives me 21. Then I want to know if it is prime, so I write "is prime" (on the current number - 21), it gives me false. "is odd" would give me true. And so on.

Now, for a simple application with few commands, even a simple switch would do for processing the commands. But if I want extensibility, how would I need to implement the functionality? Do I use the command pattern? Do I build a simple parser/interpreter for the language? What if I want more complex commands, like "multiply 5 until >200" ? What would be an easy way to extend it (add new commands) without recompiling?

Edit: to clarify a few things, my end goal would not be to make something similar to WolframAlpha, but rather a list (of numbers) processor. But I want to start slowly at first (on single numbers).

I'm having in mind something similar to the way one would use Haskell to process lists, but a very simple version. I'm wondering if something like the command pattern (or equivalent) would suffice, or if I have to make a new mini-language and a parser for it to achieve my goals?

Edit2: Thanks for all the responses, all have been very helpful to me, but Emmad Kareem's helped me the most, so I'll chose it as the answer. Thanks again!

Nini Michaels
  • 283
  • 1
  • 7
  • 2
    I don't get the downvotes. Please state your reason so I can better formulate my question next time. – Nini Michaels Nov 07 '12 at 11:24
  • 2
    I really like this question. Looking forward to see what designs people suggest. Are you specifically looking for object oriented design (you mention command pattern, which is an OO pattern)? – Bjarke Freund-Hansen Nov 07 '12 at 11:39
  • thank you :) yes, I would prefer OOP, but I won't mind if other methods are suggested! – Nini Michaels Nov 07 '12 at 11:42
  • Are you looking for a solution that is extensible to handle queries like [WolframAlpha](http://www.wolframalpha.com/)? The challenges go far beyond parsing. – HABO Nov 07 '12 at 11:58
  • 2
    It seems an implementation of [Reverse Polish Notation](http://en.wikipedia.org/wiki/Reverse_Polish_notation), a very cool programming subject! – Alberto De Caro Nov 07 '12 at 12:00
  • @HABO: do you mean if I want to make a computation engine like WA? If so, then no. My goal would be more like a list processor (take a list of numbers and process all of them). But I want to start slowly. I'll make an edit to the original post to clarify a few things. ADC: that sounds like a good place to start, thanks! – Nini Michaels Nov 07 '12 at 12:13
  • 2
    You are probably falling foul of the *book* clause from **[What kind of questions should I *not* ask here?](http://programmers.stackexchange.com/faq#dontask)** in the FAQ, i.e. **If you can imagine an *entire book* that answers your question, you’re asking too much**. – Mark Booth Nov 07 '12 at 13:57
  • @MarkBooth: I guess I may have worded my question a bit poorly, but In the end I only wanted to know what approach is generally used in what I wanted to achieve. Anyway, thank you for telling me and I'll be more careful next time I'm asking a question! – Nini Michaels Nov 07 '12 at 14:02

4 Answers4

5

This sounds like an interpreter. It looks like you are worried about the implementation more than the detailed functionality (I am only guessing here). This project if extended is not a trivial task. Make sure you study the scope clearly as this requires engineering approach and not an ad-hoc development approach to get a reliable product rather than a product with 1000 patches that works sometimes only.

Decide on a syntax and be ready to parse it and perform the necessary syntax checks. This link may help you with this:Create your own parser.

Take a look at: this topic as it touches on different aspects of the work, also there are good links that may help you (specially the answer by RMK).:Creating a Language interpreter. You may want to see an example of a nice looking project that is somewhat similar at: Ultimate Programmable Scientific Calculator. You can find source code and working program for a command line C# interpreter here Command-Line-Implementation-of-C#-Made-for-Teaching. Using the compiler to do the complex tasks for you like parsing and variable typing, etc. may be a clever way to escape the complexities of writing all this yourself. Also, there is the Mono option which provides a charp shell feature that you may want to take a look at: CsharpRepl.

NoChance
  • 12,412
  • 1
  • 22
  • 39
2

Unless you're specifically interested in writing the actual parser for yourself, I'd suggest having a look at one of the parser generator frameworks. For C you have YACC or Bison, but there should be other alternatives for other languages if you prefer.

These takes away the complexities of parsing complex grammars and lets you concentrate on the task you want to do. Of course this may be overkill for the grammar you suggest in the question, but since you mention having the option of expanding to a more complex grammar later, it's at least worth getting some inspiration from these frameworks.

harald
  • 1,953
  • 13
  • 16
  • 1
    The problem with most parser generators is that their artifacts are static, and don't lend themselves easily to extension. I think OP would be better served with something more like a rules engine, where the "rules" (keywords and syntax) are stored in a flexible data structure and evaluated after each input. – TMN Nov 07 '12 at 14:58
2

What you are describing is very close to a stack language.

For instance in Factor what you describe would be done like

1
2 +
7 *
even? not

Or you could define your own words and then use them, like

: add ( x y -- sum ) + ;
: multiply ( x y -- product ) * ;
: odd? ( n -- ? ) even? not ;

With these definitions the above example becomes

1
2 add
7 multiply
odd?

Usually stack languages are trivial to parse because they use single words that are space separated. I suggest you have a look at Factor - it may be eaxctly what you want. It should be easy to define the words that do the processing you need.

EDIT: If you actually want to design a similar language, I suggest that you play with one of them anyway. Parsing a stack language is trivial - you split on blank spaces, and a naive implementation of processing is easy: you just need to take care of what happens on a stack.

Andrea
  • 5,355
  • 4
  • 31
  • 36
1

But if I want extensibility, how would I need to implement the functionality?

You shouldn't. Extensibility creates a whole lot of complexity for very little gain. That said, you'll need to provide a hook into the existing state. A way to see the state, modify the state, and provide a mechanism to return other results (print to screen). You'll need a way for the core code to discover modules, load them, and dispatch commands to them.

Do I use the command pattern?

You can, but it's likely not appropriate.

You're not going to take the entire input and send it off for processing, but instead parse the input, dispatch to the correct handler and let it do its work. The command doesn't vary in that communication; so no command pattern.

Do I build a simple parser/interpreter for the language?

You'll need something to handle breaking the input into tokens. For an extensible solution, you probably won't do much more. For a well-defined solution, having a full parse tree will provide better performance, error handling, and debug-ability.

but rather a list (of numbers) processor

Then perhaps you should look into the LISt Processing language. The juxtaposition of code and data should fit in well with what you describe.

Telastyn
  • 108,850
  • 29
  • 239
  • 365
  • Thank you for the suggestions. As for LISP, I am familiar with it, and even more familiar with Haskell, which inspired me with this idea. However, even though I may be reinventing the wheel a bit, I want to get my hands dirty with processing commands and interpreting them. So it also has an educational purpose besides the actual "list processing" :) – Nini Michaels Nov 07 '12 at 17:56
  • @NiniMichaels certainly, but as far as a design for extensibility goes, using lisp's organization/chaining of code/data isn't a bad option. – Telastyn Nov 07 '12 at 18:14