Application-Specific Languages
General-purpose languages
• A general-purpose language is designed for a wide variety of programming problems
• Examples: C, C++, Fortran, Algol, Pascal, Java
• To meet conflicting demands, a general-purpose language must make many compromises
ASLs
• An Application-Specific Language (ASL) is designed for a particular class of problems– ZIL (Zork Implementation Language)
– MOO (an O-O language for MUDs)
– Bard (for manipulating Abstract Syntax Trees)
– ML (originally designed for just one program--Edinburgh LCF, Logic for Computable Functions)
Advantages of an ASL
• An ASL is not a "Jack of all trades, master of none" -- it's very focused
• An ASL can often avoid compromises, or at least bias them in favor of the application
• An ASL can use very high-level constructs
• An ASL can be simpler to learn and to use
• An ASL can boost productivity up to 10x
Disadvantages of an ASL
• You have to find or implement the ASL
• It's yet another language to learn
• It may be much worse for programming problems that the designer didn't anticipate– I've found this to be true of JavaScript
Deciding to use an ASL
• Consider using an ASL if– The problem area has unique features– There are suitable high-level operations– The high-level operations are ubiquitous– There is a lot of very similar code to write– You can find a suitable existing ASL, or...– …you know how to write compilers
Zork
Sample ZIL
Object -> tasty_food "tasty food" with description "Sure looks yummy!", article "some", initial "There is tasty food here.", name "food" "ration" "rations", after [; Eat: "Delicious!"; ], has edible;
More sample ZIL
Object -> wicker_cage "wicker cage" with description "It's a small wicker cage.", initial "There is a small wicker cage discarded nearby.", name "cage" "small" "wicker", after [; Open: if (little_bird notin self) rfalse; print "(releasing the little bird)^"; <>; ], has container open openable transparent;
Khufu Mongo
Telephone scenario (MOO)
dial #350 The phone is ringing.The other phone is ringing.The other phone is ringing. The phone is ringing. answer phone
It sounds like you have It sounds like you havea connection. a connection. say helloMongo says, "hello" You say, "hello"
MOO Example 1
@program generic_telephone:dial. . .fork (1)while (this_phone.off_hook && connected == 0 && nrings < maxrings) other_party = other_phone.location; . . . suspend(1);endwhile
MOO Example 2
@program generic_telephone:answerthis_phone = this;if (player != this_phone.location) player:tell("You must first take the phone.");else this_phone.off_hook = 1; other_phone = this_phone.connected_to; player.is_on_phone = this_phone; if (other_phone == 0) player:tell("You hear a dial tone."); endifendif.
How do you write an ASL?
• Compilers generally consist of three parts:– A lexical scanner, to turn an input stream of
characters into tokens.– A parser, to construct an Abstract Syntax Tree
(AST) from the token stream.– Either a code generator, to walk the AST and
translate it into some other computer language, or– An interpreter, to walk the AST and perform the
operations indicated therein
The lexical scanner
• Input to the ASL compiler is just a stream of characters
• The characters have to be grouped into tokens that are meaningful for the particular language
• Example:• Input: i f ( m i n < 0 ) m i n + + ;• Tokens: if ( min < 0 ) min ++ ;
The parser
• The parser constructs an Abstract Syntax Tree (AST) from the token stream
• The AST defines the operations to be performed and the order in which to perform them
• The AST is abstract because it leaves out information that may have been needed to construct the tree, but is no longer needed
Example Abstract Syntax Tree
IF
LESS_THAN INCREMENT
min min0
• if (min < 0 ) min++ ;
Compilers and interpreters
• Once you have the AST, you have two choices:– Compile it: Generate code in some other
computer language that does the same thing as the program in the ASL
– Interpret it: Walk the tree and do what it says
• Compiling gives you faster code
• Interpreting is much easier and more flexible
lex and yacc
• One of the easiest and best ways to write a compiler or interpreter is to use a pair of UNIX programs called lex and yacc
• lex is an ASL for writing lexical scanners
• yacc is an ASL for writing code generators
• These ASLs have been ported to most platforms
Sample lex code
• Definitions– D [0-9]
OD [0-7] HD [a-fA-F0-9]
• Tokens– {D}+ {return Make_Constant;}
"16#"{HD}+ {return Make_Hex_Constant;} "and" {return Return_Token (AND_OP);} "array" {return Return_Token (ARRAY_TERM);} ":=" {return Return_Token (ASSIGN_OP);}
Sample yacc code
• Token Definitions– %token AND_OP ARRAY_TERM ASSIGN_OP
%token BEGIN_TERM %token IDENTIFIER_TERM IF_TERM IN_TERM
• Nonterminal Definitions– assignment_statement
: variable ASSIGN_OP expression { $$ := Apply (Assignment, $1, $3); } ;
– while_statement : WHILE_TERM expression DO_TERM statement { $$ := Apply (While_Op, $2, $4); } ;
Bard example
idiom remove_null_statements; -- Remove null statements, except empty loop bodies. procedure remove_null_statements (1, Null_Statement); go to first child of parent; not match While_Op; not match Do_While; not match C_For_Loop; commit; go to @trigger; delete; end procedure;end idiom;
Summary I
• A programmer's goal should be to write the best code with the least time and effort.
• General-purpose languages provide tools to let you expand the program's "vocabulary":– functions (procedures, methods...)– structs, objects, tables and databases, etc.
• Much of the work is customizing the language
• ...so why not start with a better language?
Summary II
• Application-specific languages are most useful if:– You can find suitable high-level operations.– The high-level operations are unusual. – The high-level operations are ubiquitous. – There is a lot of very similar code to write.
Laymen need to be able to do the programming.– You know how to write compilers.
The End