Click here to Skip to main content
Click here to Skip to main content

Twiggery Scripting Language

By , 12 Aug 2010
 

Introduction

Twiggery is a tiny but useful scripting language. A full Twiggery system consists of a compiler and a virtual machine. And it’s easier than any other scripting languages to combine the script with the host program (C++, Java, C#, etc.), minimum TVM implementation is no more than 25KB of source code.

Background

Programming games are so funny! The simple reason is that you get to code so many different types of subsystems in a game, regardless of whether a renderer, sound system, AI, or game logical code; it’s full of challenges in all of these types of programming that you get to solve. In a lot of cases, using scripting is an ideal way of isolating game code from the main engine. On PC platform, MAC and consoles there are many powerful and mature scripting languages for developers to chose, such as Lua, Python, Ruby etc. But on mobile platforms like J2ME cell phones, there is no choice for a developer, that’s why this fine scripting language was created. You’ll learn what a Twiggery scripting language is and how it works; the best usage of Twiggery is using it as a cell phone scripting language; and, of course, you’ll learn a little about compiler theory. You’ll even get to examine how a full Twiggery Virtual Machine is developed! And if you love coding especially coding games, I'm confident that you'll enjoy finding out more about this tiny scripting language. Have fun!

How to Code with Twiggery

Basic Syntax

Keywords

There are only 17 keywords in Twiggery, see below:

  • function
  • if
  • elseif
  • else
  • for
  • to
  • step
  • while
  • do
  • break
  • continue
  • return
  • and
  • or
  • not
  • true
  • false

The meaning of each word will be mentioned in the following parts.

Twiggery is a case sensitive language, it is to say that “function” is a keyword and means a head of a script function, but Function or FUNCTION is different from “function” in syntax.

Operators

There are 15 operators in Twiggery, see below:

Type

Lexicon

Description

Example

Assignment

=

Assign a value to a variable

pi = 3.14: pi is 3.14

Numeric

calculation

+

Add a pair of value up

r = 2 + 3: r is 5

-

Minus one value with another

r = 5 – 2: r is 3

*

Multiply two value together

r = 3 * 7: r is 21

/

Divide one value with another

r = 18 / 3: r is 6

%

Mod operation

r = 10 % 3: r is 1

Numeric

comparison

<

Be less than

c = 1 < 2: c is true

>

Be greater than

c = 1 > 2: c is false

<=

Be less than or equals with

c = 1 <= 2: c is true

>=

Be greater than or equals with

c = 1 >= 1: c is true

==

Equals with

c = 4 == 5: c is false

~=

Not equals with

c = 4 ~= 5: c is true

Boolean

operation

and

“And” logic

See “operators”

or

“Or” logic

not

“Not” logic

The keyword “false” means result of an expression which is false, it is equal to numeric zero like in C language; and “true” means true or not zero. “false” or “true” is a result value of a numeric comparison or a Boolean operation.

Keywords “and”, “or” and “not” are also operators. See the Twiggery operation priority level table.

Level Operation
1 * / %
2 + -
3 < > <= >= ~= ==
4 not
5 and or
6 =

The priority of level 1 is the highest and level 6 is the lowest. Higher level operations are done before the lower ones. A formula is processed from left to right; operations in a same level are dealt in the same way. Brackets ‘(‘ and ‘)’ are used in pair to process formula between them; like 5 * (1 + 2) % 4 returns value 3.

Comment

A compiler would do nothing but skipping with comments. That does not mean comments are not important, comment plays an important role as code notes and can give much information to the code reader.

Twiggery comments begin with a character ‘ and end at the end of line. Anything after ‘ would be skipped. See below:

' Welcome to Twiggery Scripting Language. This line is a comment.
function main() {
  output("Hello, Twiggery!"); ' Output a string. This is also a comment.
} 

Variable and Operation

Data Type

There are three data types in Twiggery, Numeric, Boolean and String.

Numeric is a basic data type. Twiggery only contains one numerical type; it is stored in 32bit, and always defined as an IEEE754 standard float type. Its range is 3.402823e+38 ~ 1.401298e-45.

Boolean can be assigned with one of two values, “true” or “false”. In Twiggery, a boolean is stored and treated similar as Numeric in 32bit; numerical value zero means “false”, and all non zero means “true”.

String is implemented by native string type in different TVM coding languages. String can only be used as the argument of a function. Like: output("Twiggery");.

You can do Numeric and Boolean calculation, comparison and assignment in Twiggery, as shown below:

' assignment 
 pi = 3.14; 
' remote function call, input a value into 'r' 
 input ( r );  
 ' calculation  
 s  = pi * r * r; 
' compare two value and assignment the result to a boolean 
 t = 1 < 2; ' t is true 
 f = 1 == 2; ' f is false 
' two simple variables 
 a = 1; 
 b = 0; 
' boolean operation between a numeric and a boolean const 
 b1 = a or false; ' b1 is true 
 b2 = not b and true; ' b2 is true 

Every variable in a script is global, that is to say, you can access any variable wherever and whenever. Declaration of a variable type is not required because Twiggery is a loosely-typed language, if you want to use one, just code it down.

Numeric Calculation

The main purpose of a programming language is data processing, and the main purpose of data processing is numerical calculation.

There are five Numeric calculation operations. Nothing is easier than this, so more explanation will make you bored. You can use +, -, *, /, % as add, minus, multiply, divide and mod like below:

 s = v0 * t + (1 / 2) * 9.8 * t * t;
 m = 10 % 3; ' m is 1 

Numeric Comparison

These operations compare two numbers and return Boolean values, they give out “true” or “false” depending on whether or not the comparison formulas are equal. Any of the comparisons could only give one of “true” or “false”. See below for Twiggery numeric comparisons.

Comparison Sample Description (result as true)
< ex1 < ex2 ex1 is less than ex2
> ex1 > ex2 ex1 is greater than ex2
<= ex1 <= ex2 ex1 is less than or equal to ex2
>= ex1 >= ex2 ex1 is greater than or equal to ex2
== ex1 == ex2 ex1 is equal to ex2
~= ex1 ~= ex2 ex1 is not equal to ex2

Boolean Operation

Boolean is a special type expressing way of numeric, so Boolean and numeric comparisons are supported. “true” is dealt as nonzero and “false” as zero.

An execution controlling Twig uses a boolean value as its condition. More details will be shown later.

String

Twiggery is designed as a JavaME embedded scripting language at first, just for easy logical controlling and numeric processing. So String operation is not a strong point of it.

String type values are only allowed to pass as a remote function argument in some usage. For example, pass a String “Hello” to the standard output function “output”, and the String will be shown on standard console.

Function

As you see, there is only one function in a script source file in current version of Twiggery. Unlike other complex programming languages, Twiggery is a tiny and easy embedded script, so the designing philosophy is “Do more in less”.

Each Twiggery script source contains only one function without arguments. The execution flow starts from the first line of the function. Multi function calling and function arguments supporting at enter point may be optional in later versions.

Execution Structures

We call Twiggery a scripting language but not a formula processor, because there are three types of execution structures like other programming languages, that is serial, conditional and loop flows. In this part, you will learn how to use them.

Similar to C/C++/Java/C#, etc. Twiggery scope is determined by the placement of curly braces {}, and a statement is ended by a semicolon;. Braces must be used in pair. It is allowed but not suggested to write several statements in a single line.

Serial Flow

Serial flow statements are written one by one, and they are executed according to the sequence you write. For example, test some code like below.

function main() {
 ' Now let's do some calculating.
  pi = 3.1415926; ' Step 1: Assign p to variable pi
  r = input(); ' Step 2: Input a value to variable r
  s = pi * r * r; ' Step 3: Calculate area of a circle
  output( s); ' Step 4: Output the result
} 

As you see, each Twiggery script source contains only one “function”. In Step 1, a float type value 3.1415926 is assigned to a variable named pi; in Step 2, we call a standard remote function “input” to get a value from user input(console or input box…) and set it to variable r; in Step 3, we do a calculation as you know: S =pR2; Finally, the result area “s” is shown in the last Step 4.

It is so easy to get start with Twiggery, isn’t it?

if-elseif-else

Standard “if” twig follows the syntax as below:

if( expression) {
   twig_body;
}

If the result of the formula expression is “true” or nonzero, the sub twig “twig_body” will be executed; otherwise it will turn to the next twig followed after this “if” block.

A twig body contains one or several sub twigs. For example:

n =  input();
if(<a name="OLE_LINK14"> n </a>% 400 == 0 or ( n % 4 == 0 and  n % 100 ~= 0)) {
   output("leap year");
}

There is no “optimal path” in Twiggery. That means the formula after “or” will be calculated every time. So, even “ n % 400 == 0” is true in this sample; and “n % 100 ~= 0” will be processed in any case.

It is allowed to append at most one “else” twig after “if” twig directly. Furthermore “if-elseifelse” structure is very useful in complex conditional twig. “elseif” and “else” are both optional in an “if-elseifelse” structure. See below:

c = input(); ' Input a variable.
if( c == 1) { ' If the variable "c" equals to "1"...
  output("Uno"); ' Call a system function to output something.
} elseif(c == 2) {
  output("Dos");
} elseif(c == 3) {
  output("Tres");
} else {
  output(c);
} 

In this sample, the second condition ”c == 2” is determinate only if “c” is not 1, the third is similar to that. The last “output(c)” is executed only if “c” is not 1, 2 and 3.

for, while and do-while loop

if-elseifelse” twig could only provide skip ability to Twiggery. In this section, you will learn some useful twig with repeating ability.

There are three types of repeating twig: “for-to-step”, “while” and “do-while”.

The “for” twig is deemed as fixed step loop. See below:

 n = 1; ' Initialize "n" with value "1".
 e = 10;
for( i = 1 to e step 1) { ' A loop.
   n  = n * i;
 }
 output ( n );  ' Output n!

You see in this sample, variable “i" is counted from 1 to e(as 10) and the loop step is 1. That means the twig body “n = n * I” is dealt with 10 times. The default value of loop step is 1, so this twig head can be written like “for(i = 1 to e)” as well.

We do not know how many steps the loop should be, sometimes. For this purpose, dynamic variable loops are necessary. There are two kinds of unfixed loops in Twiggery, “while” and “do-while” loop.

while” and “do-while” twigs are conditional loops in fact. It will head to a twig body execution once the condition is true in an “if” twig; and the twig body will be executed again and again until the loop condition is not true anymore in “while” and “do-while”; the difference between these two loops is, if the condition is false then the “while” twig body would not be treated, but whatever the condition value is, the twig body would run at least once in “do-while” twig, that is because of a loop condition is judged before twig body in a “while” but after twig body in a “do-while”. For example:

 a = 0;
while( a <= 5) {
  ' Execute inside if loop condition is true
   output ( a );
   a = a + 1;
 }
 b  = 0;
do  {
  ' Execute inside at least once whether loop condition is true or false
  output(b);
  b = b + 1;
} while(b <= 5)

break, continue and return

break” in Twiggery is used to interrupt current loop and continue to execute the program after it. It is the same as C programming language. It always breaks off current loop by external condition trigger (usually tested by an “if” twig). “break” can be used in “for”, “while” and “do-while” twigs.

 num =  input();
 count =  num / 2;
while( count > 0) {
  if( num %  count == 0) {
     output( count, " is the largest factor of ",  num);
    break;
  }
   count =  count - 1;
}

This script will find out the largest factor of the given number “num”. We iterate all possible numbers, and use “count” as a loop variable, reject all numbers that cannot be divided exactly by “num” in descending order. Then the first number which can be divided exactly by “num” is the one we are looking for, and there is no need to do more loop execution if we find it, we just use “break” to exit the loop.

There is no difference between “continue” in Twiggery and other programming languages. It can be used in “for”, “while” and “do-while”, like “break”. “while” and “do-while” are conditional loops and “for” is a iterative loop. Whether or not the next circle of a loop will be executed when it meets a “continue” also depends on the demand of a loop type; a loop will be terminated normally when it is not satisfied. See below:

 valid = false;
 count = 3;
while( count > 0) {
  it = input();
  if(it == 123) {
    valid = true;
    break;
  }
  if(not valid) {
    output("Invalid");
    count = count - 1;
    continue;
  } else {
    break;
  }
}

Sometimes we want to break deeply out of a whole function and exit an execution of a script, “return” is for this; “return” is only used to do such thing but cannot return a value to outer caller. See below:

for( i = 0 to 10) {
   n =  input();
  if( i %  n ~= 0) {
    return;
  }
}

The program will be terminated directly if “i % n ~= 0” is true with no doubt.

Input and Output

We can do nothing using a programming language without input and output but only internal processing. In Twiggery, there is one standard input function and output function. The input” function gets no arguments and returns a numeric value and the “output” function gets at least one argument in numeric or string format and outputs it to standard stream (a message box on Windows, a line printing on console, etc.).

History

  • Aug. 12, 2010 - Ver: 0.5.2.44
    • Add try-catch for C# TVM to load and run bytecode directly
    • Add drag drop support for script text box
    • Bytecode loading bugfix in Java TVM
  • July. 28, 2010 - Ver: 0.5.1.43
    • Audio plugin bugfix
    • Add array support to the Core plugin
    • Add dynamic multi arguments support to all TVMs
    • Accept function call in a common formula
    • Negative symbol bugfix
  • July. 3, 2010 - Ver: 0.4.2.38
    • Script internal exception bugfix
  • June. 24, 2010 - Ver: 0.4.1.36
    • Add a plugin loading process window
    • Set '.twg' and '.tad' file related
    • Add a new Core plugin
    • Add auto-compleate tip to CodeLeaf
    • Condition expression parsing bugfix
    • Add some new interface in the Graphics plugin
  • June. 18, 2010 - Ver: 0.4.0.30
    • Modify the Graphics plugin: put canvas image in a PictureBox instead of right in the form
    • Add keyword 'do' and 'do-while' twig support
    • Add negative symbol surpport
    • Reconfigurate the Graphics plugin
  • June. 16, 2010 - Ver: 0.3.5.28
    • Show heap unit usage in RAM box
    • Accept multi arguments in standard function 'input' and 'output'
    • Swap two operands if their addressing mode are all AM_STK
    • TASM show box items count bugfix
    • Add string type plugin function argument support
    • Modify the Graphics plugin: create Canvas, draw Sprites, get KeyDown, etc.
    • Modify the Audio plugin: C# source code format plugin, play *.wav file
    • Modify the IO plugin: open, close, write, read a file
    • Push arguments back into stack if get operand failed
    • 'if-elseif-else' block compiling bugfix
    • Set default 'for' loop step argument value as 1
    • Get returned value as format 'a = input();'
    • Reconfigurate exception messages
    • Add new example scripts using plugins
    • Escape 'true', 'false' into '1', '0' in function arguments.
  • June. 12, 2010 - Ver: 0.2.3.25
    • Add compiled assembly DLL and C# source code plugin surpport
    • Use 'v is t' instead of 'v.GetType() == typeof(t)' in TVM execution.
  • June. 9, 2010 - Ver: 0.1.2.24
    • 'if-elseif-else' jump instruction compiling bugfix
  • Feb. 24, 2010 - Ver: 0.1.0.20
    • First released edition. Full compiler and VM

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)

About the Author

paladin_t
Technical Lead
China China
Member
Video game player & creator.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionThe Best! New Version?memberMember 45586618 Dec '12 - 3:42 
My vote of 5
Rand

GeneralMy vote of 5mvpCPallini26 Apr '12 - 9:56 
Very good job.
GeneralRe: My vote of 5memberpaladin_t26 Apr '12 - 13:59 
Thank you!
GeneralThis is goodmemberRick York12 Aug '10 - 10:51 
This is a good effort but I think there are two things I would do differently. One is having only the float type for data is very constraining for a few reasons. The first is you can't do comparisons of equality reliably. The second is the limited dynamic range of floats can quickly result in a loss of accuracy for extensive calculations. I think that integers, doubles, and bytes are necessary for a scripting language along with the ability to have arrays. The second thing is your functions seem to be of void type. I would make functions return an integer at least.
 
I know these issues may be beyond the scope of what you needed to accomplish with your language but you have shared this and I suspect many people would find this kind of functionality to be very useful if they were to use your language.
 
BTW - I know a little about what I am refering to. I wrote an embeddable scripting language for my company's product and we use it extensively. Actually, we now write entire applications using it and that's because it was made to be very versatile. It supports all of the standard data types (except for 64-bit ints) and arrays, functions return an integer, functions can be mapped in from any DLL, and functions imported from DLLs can be either _stdcall or _cdecl types. There is also an associated source code debugger that supports single-stepping, breakpoints, and data watching. The funnest part of the development effort was when I converted from a virtual machine with a bytecode interpreter to generating native machine code on the fly. That raised the performance level a lot.
 
I don't mean to brag about this. I am merely pointing that I have done similar things to what you have and I think you need to fill out your language's feature list just a little bit to enhance its usability. Smile | :)
GeneralRe: This is goodmemberTony's Toy12 Aug '10 - 14:48 
Thanks a lot! It's very kind of you and your advice is pertinent indeed. It was my first time to do such a job. I've done it all in my spare time after work. More or less it's for fun. I got some awareness similar as yours after it's done. One of my dream is to create a wonderful game scripting language, your encourage is my motive force. Big Grin | :-D
GeneralMy vote of 5memberenan12 Aug '10 - 3:29 
very good and very useful. thanks
GeneralRe: My vote of 5memberTony's Toy12 Aug '10 - 14:28 
Thank you very much!
GeneralJSR 223 compliancememberSumit Pandya2 Aug '10 - 21:02 
Hi Dear,
      Warm encouragement for this wonderful work. I'd like to draw your attention on Java standards as your Twiggery supports JVM.
      Please look for similar standards for .NET etc.
 
Sumit Pandya
GeneralRe: JSR 223 compliancememberTony's Toy12 Aug '10 - 3:03 
Thank you very much! I consider Twiggery to be run in an environment which does not support that particularly a JavaME cell phone. Smile | :)
GeneralSo amazing!!! So good....memberAntonom2 Aug '10 - 18:21 
Thank you for your helpfull sample. I learn many thinks in your technichal codes.
GeneralRe: So amazing!!! So good....memberTony's Toy12 Aug '10 - 2:59 
Thanks a lot!
GeneralGreat WorkmemberTL Wallace1 Aug '10 - 11:11 
Very nice indeed. Smile | :)
"If you think it's expensive to hire a professional to do the job, wait until you hire an amateur." - Red Adair

GeneralRe: Great WorkmemberTony's Toy12 Aug '10 - 2:58 
Thank you!
GeneralMy vote of 5memberTL Wallace1 Aug '10 - 11:11 
Oh now that is nice my man. Great work.
GeneralRe: My vote of 5memberTony's Toy12 Aug '10 - 2:57 
Thanks a lot!
GeneralQuestions [modified]mvpPIEBALDconsult31 Jul '10 - 6:36 
Looks good... way more than I would take on. Thumbs Up | :thumbsup:
 

Are the braces required for if statements and such? If so, why require the parentheses? If not, then what benefit is there to elseif over else if?
 
Why use keywords for booleans rather than symbols?
 
Are you working on library functions (SQRT, POW, etc.)?
 

 
P.S. Twig[^]

modified on Saturday, July 31, 2010 12:42 PM

GeneralRe: QuestionsmemberTony's Toy31 Jul '10 - 18:24 
Well, braces are required there indeed if an 'if' (elseif, else) statement contains more than one inner statements, but they are optional if it contains only one. Just like bellow.
  c = input();
  if(c == 1) {
    output("Uno");
    output("Oops");
  }
  elseif(c == 2)
    output("Dos");
  elseif(c == 3)
    output("Tres");
  else
    output(c);
 
I define most of the syntax reference from the C language and also a little from BASIC (elseif, for-to-step) as my favourites; my code editor supplied in the package supports auto-tip for a single lexical element, just hit Enter after typing 'el' then an elseif is out, it is more or less short for typing. Blush | :O
 
'true' and 'false' are keywords that they can not be used as variables. Execuse me, I've no idea what does symbol mean here. Maybe it is different from keyword in some other programming languages, but similar.
 
For the C++ based and the Java based virtual machine, there is nothing more than standard 'input' and 'output' functions. But there are some extended plugins for the C# one, like Math, IO, Graphics, Audio, etc. Examples in the package maybe helpful.
 
BTW: I'm a new here, and how to color some text in a message, should I put tags?
GeneralRe: QuestionsmvpPIEBALDconsult1 Aug '10 - 4:09 
Tony's Toy wrote:
'true' and 'false' are keywords

 
Yes, but I meant or and and.
GeneralRe: QuestionsmemberTony's Toy1 Aug '10 - 4:29 
Oh, I get it now. They are operators like < > ==, on the other hand they are syntax keywords. Smile | :)
GeneralRe: Questions [modified]mvpCPallini26 Apr '12 - 9:55 
I suppose elseif (instead of else if) simplify noticeably the parsing.
Veni, vidi, vici.

GeneralRe: Questions [modified]memberPIEBALDconsult26 Apr '12 - 12:52 
I disagree; it's something else the parser needs to look for.
GeneralRe: Questions [modified]mvpCPallini26 Apr '12 - 21:25 
You may disagree but, as matter of fact other languages (notably Lua) have it.
Veni, vidi, vici.

GeneralRe: Questions [modified]memberPIEBALDconsult27 Apr '12 - 3:08 
That's no reason to muddy up a language. The simpler the better. I choose C and C# partly because it has fewer keywords than BASIC and VB.
 

"Simplify. Simplify." -- Thoreau
GeneralRe: Questions [modified]mvpCPallini27 Apr '12 - 3:17 
There's a reason: with elseif you (the parser) have not to resolve an ambiguity.
I recognize that C approach is 'the simpler the better'. However C does have redundant keywords (e.g. if/switch, for/while, ...).
Veni, vidi, vici.

GeneralLooks nice...mentorSandeep Mewara31 Jul '10 - 3:38 
Everything else looks fine, can you just put the code parts in the PRE tags such that they are more readable? Otherwise, nicely compiled and explained. Thumbs Up | :thumbsup:

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130523.1 | Last Updated 12 Aug 2010
Article Copyright 2010 by paladin_t
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid