views:

333

answers:

6

I'm sorry I could not think of a better title.

The problem is the following:

For our customer we have created (as part of a larger application) a graphical designer which they can use to build "scenario's".

These scenario's consist of "Composites" which in turn consist of "Commands". These command objects all derive from CommandBase and implement an interface called ICompilable.

The scenario class also implements ICompilable. When Compile() is called on a command an array of bytes is returned which can then be send to the device for which they are intended (can't disclose to much info about that hardware, sorry)

Just to give you an idea:

var scenario = new Scenario();

scenario.Add(new DelayCommand(1));
scenario.Add(new CountWithValueCommand(1,ActionEnum.Add,1));
scenario.Add(new DirectPowerCommand(23,false,150));
scenario.Add(new WaitCommand(3));
scenario.Add(new DirectPowerCommand(23,false,150));
scenario.Add(new SkipIfCommand(1,OperatorEnum.SmallerThan,10));
scenario.Add(new JumpCommand(2));

byte[] compiledData = scenario.Compile();

The graphical designer abstracts all this from the user and allows him (or her) to simply drag en drop composites onto the designer surface. (Composites can group commands so we can provide building blocks for returning tasks)

Recently our customer came to us and said, "well the designer is really cool, but we have some people who would rather have some kind of programming language, just something simple."

(Simple to them of course)

I would very much like to provide them with a simple language, that can call various commmands and also replace SkipIfCommand with a nicer structure, etc...

I have no idea where to start or what my options are (without breaking what we have)

I have heard about people embedding languages such as Python, people writing their own language an parsers, etc...

Any suggestions?

PS: Users only work with composites, never with commands. Composites are loaded dynamically at runtime (along with their graphical designer) and may be provided by third parties in seperate assemblies.

+4  A: 

From what i think i've understood you have two options

you could either use an XML style "markup" to let them define entities and their groupings, but that may not be best.

Your alternatives are yes, yoou could embedd a language, but do you really need to, wouldnt that be overkill, and how can you control it?

If you only need really simple syntax then perhaps write your own language. Its actually not that hard to create a simple interpreter, as long as you have a strict, unambiguous language. Have a look for some examples of compilers in whatever youre using, c#?

I wrote a very simple interperter in java at uni, it wasnt as hard as you'd think.

Andrew Bullock
Any links to go with that?
TimothyP
i might have some code to go with it too, ill check when i get back to my pc
Andrew Bullock
+2  A: 

This looks like a perfect scenario for a simple DSL. See http://msdn.microsoft.com/en-us/library/bb126235(VS.80).aspx for some information.

You could also use a scripting language such as lua.Net.

Bogdan
Doesn't this require us to buy some kind of license and use that special version of VS.NET (Might be totally wrong here... I have a book on DSL but it wasn't clear on licensing)
TimothyP
I don't think that any special version of VS.NET is required as the DSL Tools are part of the SDK, not VS.NET.
Bogdan
But I would have to deploy VS.NET to the customers?
TimothyP
+2  A: 

If you really just want a dirt simple language, you want a 'recursive descent parser'.

For example, a language like this:

SCENARIO MyScenario
DELAY 1
COUNT 1 ADD 1
DIRECT_POWER 23, False, 150
WAIT 3
...
END_SCENARIO

You might have a grammar like:

scenario :: 'SCENARIO' label newline _cmds END_SCENARIO
cmds::  _delay or _count or _direct_power or...
delay:: 'DELAY' number

Which gives code like:

def scenario():
    match_word('SCENARIO')
    scenario_name = match_label()
    emit('var scenario = new Scenario();')
    cmds()
    match_word('END_SCENARIO')
    emit('byte[] ' + scenario_name + ' = scenario.Compile();')

def delay():
    match_word('DELAY')
    length = match_number()
    emit('scenario.Add(new DelayCommand('+ length +'))')

def cmds():
    word = peek_next_word()
    if word == 'DELAY':
       delay()
    elif ...
Charles Merriam
+1  A: 

Here's a Pythonic solution for building a DSL that you can use to compile and create byte code arrays.

  1. Write a simple module that makes your C# structures available to Python. The goal is to define each C# class that users are allowed to work with (Composites or Commands or whatever) as a Python class.

    Usually, this involves implementing a minimal set of methods with different conversions from C# types to native Python types and vice versa.

  2. Write some nice demos showing how to use these Python class definitions to create their scripts. You should be able to create things like this in Python.

    import * from someInterfaceModule
    scenario= Scenario(
        Delay(1),
        Repeat( Range(10),
            DirectPower( 23, False, 150),
            Wait(3),
            DirectPower( 23, False, 150)
        )
    )
    scenario.compile()
    

These are relatively simple classes to define. Each class here be reasonably easy to implement as Python modules that directly call your base C# modules.

The syntax is pure Python with no additional parsing or lexical scanning required.

S.Lott
+1  A: 

To add to S.Lott's comment, here's how you eval a Python script from C#

Chui Tey
A: 

While it might be great fun to create this mini-language and code it all up, the real questions you need to ask are:

  1. What is the business case for adding this feature / facility?
  2. Who is going to pay for this feature?
  3. Who is going to "sign off" on this feature if you build it?

"Really neat" features have a way of getting built when the reality might indicate the true answer to such a request is "no".

See if you have a stakeholder willing to sponsor this before proceeding. Then check with the end users to see what they really want before committing to the project.

Cheers,

-R

Huntrods
They are willing to pay... which means we are willing to implement :pThey explicitly asked for it (after the original plan was made :p)
TimothyP