Originally published on: Wed, 20 May 2009 02:24:36 +0000
Domain-Specific Languages (DSL's) have gotten quite a bit of press in the last few years. The idea is that DSL's should provide a means to control a piece of software or larger system. Some believe that DSL's should be restricted functionally so that they can only act as controlling agents. Others believe that DSL's should provide general programming facilities.
I believe that the answer really depends on what one's goals are in using the DSL. If one of the goals is to limit access to things that the DSL programmer should not be using, then a restricted DSL is likely better for that purpose.
I do believe that a DSL should always be Turing-complete, but I don't think all DSL's should have complete I/O function bindings.
There are a myriad of approaches to building DSL's ... some people build them in XML using a tag syntax and evaluate them in Java or C# or whatever by using an XML parser to traverse the script.
Some use compiler development tools such as ANTLR to transform the DSL into something more easily interpreted or perhaps source-code for another programming language.
The language Groovy has internal facilities for devising JSON-like builder structures intended for DSL development.
A simple approach to DSL implementation using dynamic languages such as Perl, Ruby, Python, or the Lisp family ( among many others ) is to simply call that language's eval() function to dynamically evaluate/execute a given snippet of code. This, of course, limits the syntax to that of the hosting language and would not likely allow customized syntax.
Calling eval() would then allow the DSL script author to leverage any facility that can legally be invoked by eval(). So, if one uses eval() in Perl to expose a DSL whose purpose is to monitor web site up-time, the author could send e-mails or write to databases or anything that Perl is capable of within the DSL.
I decided to explore the concept of using eval() to implement a DSL, but I wanted to be able to limit access to various system resources. I chose to use JavaScript as a target language, but this approach can be used with numerous dynamic languages. Let's refer to this mini-language as ProtoDSL.
My goals for ProtoDSL
In the numerous DSL samples I've seen, many like to use OOP in their DSL leveraging the dot operator in their examples to chain together a series of invocations into one big line. In an act of sheer heresy, I've gone the other direction; I'm limiting the ProtoDSL user to a syntax more akin to AWK as opposed to the chained-object syntax.
Let's take a peek at the full code and then let's run the example.
dsl.htm
I first define a map of keywords called keyword. This map is incomplete ... you might wish to add other keywords, but I suspect that you may implement this overall concept in something other than JavaScript anyhow.
Next, I defined a function called transform_dsl() whose purpose is to transform a snippet of ProtoDSL text into a snippet of JavaScript text, ready for eval()'ing. The transform_dsl() function leverages a regular expression as a simple lexical analyzer / scanner. This may need more fine-tuning as I try to write more complicated ProtoDSL scripts.
The code in the function then splits the ProtoDSL into an array of tokens based on the regex and begins the transformation.
If the token is an identifier, the code checks to see if the map keyword has an associated entry with a value of "1". If so, the token is left untouched. Otherwise, the string "dsl_" is added to the beginning of the token.
All non-identifier tokens with the exception of the dot are passed through as-is. The new keyword is not allowed in ProtoDSL and becomes dsl_new.
So, the ProtoDSL code snippet below:
becomes:
Note that the transformed code is legal JavaScript.
Let's try this using a browser.
http://www.mailsend-online.com/wp/dsl.htm
If you click the Show Transformed Code button, you should then see an alert() message with the code after transformation.
If you click the Transform and Eval! button, the code should tranform and then be evaluated, which will cause the following to appear in the lower text area:
So, we have a limited DSL that allows the author to compute just about anything they want and display the results in the lower text area.
A rather large caveat is that since we've sidestepped formal compilation procedures ... true lexical analysis, parsing, and then semantic analysis, it's difficult to convey meaningful information to the author should the ProtoDSL system encounter a syntax error in the DSL text.
Go back to the web page above and change the for( text so that it is syntactically incorrect; let's add an extra "r" making it forr(.
When the system transforms this code, it becomes:
Note that since we did not use the for keyword properly, the identifier forr was transformed into dsl_forr. There's no such keyword, so our evaluation function eval_string() catches the exception in the try/catch block and displays an error from the JavaScript engine. In Firefox 2.x, the message reads:
...because the system thinks we're trying to call a function forr() and have interjected some semicolons in there.
I think that the ProtoDSL concept has merit, but I believe we should leverage a true set of compiler tools (such as ANTLR) to handle the syntax transformation process so that meaningful error messages can be conveyed to the author. If we go that route, we could also then customize the syntax more directly to suit the problem domain.
Unless otherwise noted, all code and text entries are Copyright ©2009 by James K. Lawless.
0 test.
1 test.
2 test.
3 test.
4 test.
5 test.
6 test.
7 test.
8 test.
9 test.
forr(dsl_i=0;dsl_i<10;dsl_i++) {
dsl_print(dsl_i + " test.");
}
dsl_forr(dsl_i=0;dsl_i<10;dsl_i++) {
dsl_print(dsl_i + " test.");
}
missing ) after argument list
Views expressed in this blog are those of the author and do not necessary reflect those of the author's employer. Views expressed in the comments are those of the responding individual.

Save to StumbleUpon
Digg it
Save to Reddit
Share on Facebook
Share on Twitter
More bookmarks
| Previous post: | BPL: Batch Programming Language Interpreter |
|---|---|
| Next post: | Twimmando: A Command-line Twitter Client |
Click **here**
A JavaScript REPL for Android Devices
A Review of Kevin Mitnick's Book Ghost in the Wires
Play MP3 Files with Python on Windows
Mad Schemes : Learning Lisp via SICP
BPL: Batch Programming Language Interpreter
An Interview with Game Developer James Hague
Directory Traversal in Rhino JavaScript
An Interview with Brad Templeton
A Simple Media Control Interface Script Processor
An SMTP Server Simulator in Perl
Why Some Web Sites will go Dark on Jan 18th
Book Review : Paull Allen - Idea Man
A 90's Experiment in Online Systems - The U.S. West CommunityLink Service