Click here to Skip to main content
15,867,453 members
Articles / Containers / Virtual Machine

Twiggery Scripting Language

Rate me:
Please Sign up or sign in to vote.
4.82/5 (14 votes)
12 Aug 2010LGPL313 min read 62.6K   1.1K   36   29
Twiggery Scripting Language

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.

<chsdate year="1899" month="12" day="30" islunardate="False" isrocdate="False" w:st="on">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.

<chsdate year="1899" month="12" day="30" islunardate="False" isrocdate="False" w:st="on">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

<chsdate year="1899" month="12" day="30" islunardate="False" isrocdate="False" w:st="on">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.

<chsdate year="1899" month="12" day="30" islunardate="False" isrocdate="False" w:st="on">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

<chsdate year="1899" month="12" day="30" islunardate="False" isrocdate="False" w:st="on">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

<chsdate year="1899" month="12" day="30" islunardate="False" isrocdate="False" w:st="on">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.

<chsdate year="1899" month="12" day="30" islunardate="False" isrocdate="False" w:st="on">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.

<chsdate year="1899" month="12" day="30" islunardate="False" isrocdate="False" w:st="on">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 <chmetcnv w:st="on" unitname="a" sourcevalue="1" hasspace="True" negative="False" numbertype="1" tcsc="0">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?

<chsdate year="1899" month="12" day="30" islunardate="False" isrocdate="False" w:st="on">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 == <chmetcnv w:st="on" unitname="”" sourcevalue="0" hasspace="False" negative="False" numbertype="1" tcsc="0">0” is true in this sample; and “n % 100 ~= <chmetcnv w:st="on" unitname="”" sourcevalue="0" hasspace="False" negative="False" numbertype="1" tcsc="0" />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.

<chsdate year="1899" month="12" day="30" islunardate="False" isrocdate="False" w:st="on">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)

<chsdate year="1899" month="12" day="30" islunardate="False" isrocdate="False" w:st="on">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)


Written By
Architect
China China
Video game player & creator; Hardware geek & maker.

Comments and Discussions

 
Questionnice, but...example not work :) Pin
SergeyAB6-Mar-15 5:30
SergeyAB6-Mar-15 5:30 
AnswerRe: nice, but...example not work :) Pin
Member 139774062-Jan-19 6:41
Member 139774062-Jan-19 6:41 
QuestionThe Best! New Version? Pin
RAND 45586618-Dec-12 3:42
RAND 45586618-Dec-12 3:42 
GeneralMy vote of 5 Pin
CPallini26-Apr-12 9:56
mveCPallini26-Apr-12 9:56 
GeneralRe: My vote of 5 Pin
paladin_t26-Apr-12 13:59
paladin_t26-Apr-12 13:59 
GeneralThis is good Pin
Rick York12-Aug-10 10:51
mveRick 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 good Pin
paladin_t12-Aug-10 14:48
paladin_t12-Aug-10 14:48 
GeneralMy vote of 5 Pin
enan12-Aug-10 3:29
enan12-Aug-10 3:29 
GeneralRe: My vote of 5 Pin
paladin_t12-Aug-10 14:28
paladin_t12-Aug-10 14:28 
GeneralJSR 223 compliance Pin
User 267402-Aug-10 21:02
professionalUser 267402-Aug-10 21:02 
GeneralRe: JSR 223 compliance Pin
paladin_t12-Aug-10 3:03
paladin_t12-Aug-10 3:03 
GeneralRe: JSR 223 compliance Pin
Member 139774062-Jan-19 6:45
Member 139774062-Jan-19 6:45 
GeneralSo amazing!!! So good.... Pin
Antonom2-Aug-10 18:21
Antonom2-Aug-10 18:21 
GeneralRe: So amazing!!! So good.... Pin
paladin_t12-Aug-10 2:59
paladin_t12-Aug-10 2:59 
GeneralGreat Work Pin
Terence Wallace1-Aug-10 11:11
Terence Wallace1-Aug-10 11:11 
GeneralRe: Great Work Pin
paladin_t12-Aug-10 2:58
paladin_t12-Aug-10 2:58 
GeneralMy vote of 5 Pin
Terence Wallace1-Aug-10 11:11
Terence Wallace1-Aug-10 11:11 
GeneralRe: My vote of 5 Pin
paladin_t12-Aug-10 2:57
paladin_t12-Aug-10 2:57 
GeneralQuestions [modified] Pin
PIEBALDconsult31-Jul-10 6:36
mvePIEBALDconsult31-Jul-10 6:36 
GeneralRe: Questions Pin
paladin_t31-Jul-10 18:24
paladin_t31-Jul-10 18:24 
GeneralRe: Questions Pin
PIEBALDconsult1-Aug-10 4:09
mvePIEBALDconsult1-Aug-10 4:09 
GeneralRe: Questions Pin
paladin_t1-Aug-10 4:29
paladin_t1-Aug-10 4:29 
GeneralRe: Questions [modified] Pin
CPallini26-Apr-12 9:55
mveCPallini26-Apr-12 9:55 
GeneralRe: Questions [modified] Pin
PIEBALDconsult26-Apr-12 12:52
mvePIEBALDconsult26-Apr-12 12:52 
GeneralRe: Questions [modified] Pin
CPallini26-Apr-12 21:25
mveCPallini26-Apr-12 21:25 

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

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.