Alsalam alikom wa ra7mat Allah wa barakatoh (Peace Upon You)
Part I: Create the Grammar …What your users will write…
If you are writing enterprise software, you probably came across this problem many times when you want to give IT Admins the ability to customize your application through some sort of scripts. The typical solution used to be VBS on windows and now PowerShell.. they both offer great ability to expose your public APIs and let others consume them. However, there is no way to customize the syntax to your application needs.
If you are writing a software that does some reporting and want to let users decide what template should be used when sending to every customer… wouldn’t it be nice if you let them write something like this:
Send "D:\Reports\Templates\Regular.tmpl" to sm1@hotmail.com, sm2@hotmail.com
Send "D:\Reports\Templates\Special.tmpl" to sm3@hotmail.com
Or how about a language that describes mathematical equations such as this: [[x, y] ; [1, 2] ; [2, x + 5]] * Func(2, 3, 5) – x2 + y * j ^ 3 + d - mul(3) This may look similar to Matlab syntax… in fact it’s. The first part “[[x, y] ; [1, 2] ; [2, x + 5]]” declares a 2x2 matrix. You can think of all sorts of symbols and operations that can be put into an equation… Latex and MathML [Wikipedia links] come into mind. Latex is not only for representing equations but it’s one feature of it. My point is, even if you want to reuse one of the existing languages out there in your application, you don’t have to rewrite a parser, buy a commercial package or get an OSS that might limit how you will be able to distribute your software. MGrammer (included in Oslo) is one elegant way to achieve this…
Or maybe you just don’t like the brackets () in C# and want to define a bracketless C# (VB maybe 8-) )…
There might be a debate around this and whether you will want each app to have it’s own Domain Specific Language (DSL) or is it better to have a common known scripting language (like VBS or PowerShell).. I won’t go into this debate actually here… but I would just say, “it depends”.
Let’s get to work, First thing you need to do is to get Oslo installed [Microsoft Downloads Link]. It needs SQL server (Free Express Edition works fine) –I installed it without SQL Server, it gave me an error but it’s ok as long as you don’t do any stuff that requires this-…
Oslo comes with a toolchain. We will actually make use of only 2 tools out of these; IntelliPad.exe (GUI tool) and Mg.exe (CMD tool)
We will be using IntelliPad to write MGrammar (.mg file), test it on our examplr data and make sure the syntax tree is in the right format.
We will then use Mg tool to compile the MGrammar file into .mgx file which represents you compiled language parser.. you can then use it from any .NET app.
We will make a grammar that recognizes that first language above, let’s call it Reporter. We will get to know MGrammer as we move on…
Send "D:\Reports\Templates\Regular.tmpl" to sm1@hotmail.com Send "D:\Reports\Templates\Special.tmpl" to sm2@hotmail.com, sm3@hotmail.com
syntax SendCommand = "Send" any* "to" any*;syntax Main = SendCommand+;
token SendToken = "Send";token ToToken = "to";syntax SendCommand = SendToken any* ToToken any*;syntax Main = SendCommand+;
token AlphaNumeric = 'a'..'z' | 'A'..'Z' | '0'..'9' | '_' | '-';token Path = (AlphaNumeric | ':' | '\\' | '.')+;token Email = (AlphaNumeric | '@' | '.')+;token QuotedPath = '"' Path '"';syntax SendCommand = SendToken QuotedPath ToToken Email;
This is how the right preview tree should look like by now.
Things are getting to look better, right? maybe you started to get the feeling it’s just like regular expressions,in fact, it’s pretty much the same concept (String matching after all if you want the truth) but writing in MGrammar gives you a lot of other options when writing your rules than you have when matching with regExAlso you will almost write 0 Lines of code to get your abstract syntax tree (AST) built ;)
syntax ListOfEmails = Email | ListOfEmails "," Email;syntax SendCommand = SendToken QuotedPath ToToken ListOfEmails;
syntax SendCommand = SendToken p:QuotedPath ToToken list:ListOfEmails => Send[p, list];
Main[ [ Send[ "\"D:\\Reports\\Templates\\Regular.tmpl\"", ListOfEmails[ "sm1@hotmail.com" ] ], Send[ "\"D:\\Reports\\Templates\\Special.tmpl\"", ListOfEmails[ ListOfEmails[ "sm2@hotmail.com" ], ",", "sm3@hotmail.com" ] ] ]]
token QuotedPath = '"' p:Path '"' => Path[p];syntax SendCommand = SendToken p:QuotedPath ToToken list:ListOfEmails => Send[valuesof(p), list];
Commands[ Send[ "D:\\Reports\\Templates\\Regular.tmpl", Emails[ "sm1@hotmail.com" ] ], Send[ "D:\\Reports\\Templates\\Special.tmpl", Emails[ "sm2@hotmail.com", "sm3@hotmail.com" ] ]]
Conclusion:
Congrats, you reached your first Checkpoint!
Here is the full listing of Reporter.mg file.
module Basic.Languages{ language Reporter { token SendToken = "Send"; token ToToken = "to"; token AlphaNumeric = 'a'..'z' | 'A'..'Z' | '0'..'9'; token Path = (AlphaNumeric | ':' | '\\' | '.')+; token Email = (AlphaNumeric | '@' | '.')+; token QuotedPath = '"' p:Path '"' => Path{p}; syntax ListOfEmails = e:Email => Emails[e] | list:ListOfEmails "," e:Email => Emails[valuesof(list), e]; syntax SendCommand = SendToken p:QuotedPath ToToken list:ListOfEmails => Send{valuesof(p), list}; syntax Main = s:SendCommand+ => Main{Commands[valuesof(s)]}; interleave whitespace = (" " | "\r" | "\n" | "\t")+; }}
Path I: Create the Grammar (What your users write). [This post] Part II: Consume the abstract syntax tree (Do some action!). Path III: Compile your language into MSIL.
References: A good tutorial for MGrammar: http://msdn.microsoft.com/en-us/library/dd441702.aspx
You will also find some good documents in C:\Program Files\Microsoft Oslo SDK 1.0\Documents 2 in particular are interesting: MGrammar Language Specification.docx MGrammar in a Nutshell.docx
Have a nice time!