Introduction to M2000

Installation tips
sudo apt-get install wine1.8 winetricks
wine wineboot
winetricks winecfg
in dialog:
1. choose windows 7 or 8.1
2. library override oleaut32 (native)
In console:
winetricks vb6run art2kmin mdac28

From Menu choose Wine -> Explore C
Place M20000language.exe and execute it

Need MS Access Runtime at least. Download it from Micorsoft.
Then get setup executable and run it.
Check help file: Write in M2000 console Help All

For both OS, at the first execution of M2000 environment.
Write Settings, then press enter to open settings dialog (or Ctrl+U)
Write Monitor to see the state of M2000 environment
Write Help to get first help.
Write End to exit from console.

Interactive Mode

We can start m2000.exe at interactive mode, without providing a gsb file to execute. At a prompt > we give so called manual commands, and we can define global entities like variables, functions and modules.

>Print “Hello”

All commands are in English and Greek words, and we can use either language per command. So we can use a module using English commands, in a module using Greek commands.



Internal terminal for manual commands. Use Linespace to insert spaces between lines.

  • Commands to show directories, files, search text in files.
  • Used mostly in full screen, but can be change in size, position and transparency. Also we can create path to exclude unwanted parts, and create a form of irregular shape.
  • Graphics/Text can be mixed. Also there is a Background layer, and 32 layer above console as sprites/layers.
  • Editor for modules/functions with automatically color coding. 
  • Help pop up window.
  • Can change character resolution in any time. Form 80, 40 
  • We can execute a gsb without GUI or Terminal. We need to insert a Show command or use Input to open Terminal. 
  • We can use M2000's Windows instead of terminal, or in front of terminal. 
  • We can execute Os commands, or execute applications using Win command using filenames and command.
  • Save name (without quotes) save all modules/functions in that name. Ctrl+A save to same file after the first save.
  • Statements: NEW, START, FLUSH, CLEAR (see Help, write Help New)
  • Code executed on a "global" runnable object. When we call a named block of code (say a Module or a Function) then a new runnable object created for code execution.


Lexical Scope 


  • Global Named Block Scope (Module, Function, Nested Module, Nested Function, Group, Group Module, Group Function, Nested Group)
  • Local Named Block Scope (Module, Function, Nested Module, Nested Function, Group, Group Module, Group Function, Nested Group)
  • Unnamed Block Scope (Lambda Function, Lambda Closure, Group Operator Function, Group Value, Group Set, Events Functions)
  • Static variables per runnable Object
  • Standard calling for modules and functions prevents merging of scope from outer or inner scope. A module can't read parent variables, and can't read variables from inner module.(Although for modules we can use a higher level module name as name prefix and a dot to read/write simple variables, but we can't get references from these, this included for compatibility with  older versions, as last revision for version 9.0)
  • Special calling can pass in a new runnable object the same lexical scope from already running object. This used for event handlers, and for user call back (we can call the calling object, by running a new object using same lexical scope).
  • We can change static variables (or add new static variables) in a threat from other thread, using thread id and executing a command (basically we execute a statement which is not part of thread, but in thread's runnable object, which certain is in idle state)


Runnable Objects 


  • A runnable object uses lexical scope from module or function which executed.
  • Modules, functions and Threads executed on separate runnable objects. Threads are in same lexical scope with a thread generator (a Module or a Function).
  • Subroutines executed on runnable object from calling module/function, inherit lexical scope from runnable object. We have to specify Local for making local variables and arrays, in a subroutine.
  • Modules, Functions,Subroutines and For object { }, always erased any new definitions that take place in their code. Threads can't erased other than own static variables definitions (and any other static variables from what ever called by them). For Modules and Functions, static variables, preserved by caller. So for a global module maybe there are more than one set of static variables. The same hold for a module which called from a thread, module's static variables stored to specific thread.
  • There are simple routines, calling with Gosub and a label or line number (line numbers are optional). These routines are just lines of code in same scope.
  • There are specific objects like event and lambda object which make own runnable objects when used. Event object used for raising events, store functions handlers, and for control. When we raise an event by code, a new runnable object filled with code from event object, from each stored function, passing arguments (by value or and by reference) to each (multicast). A lambda object has a list of closures and a source code for own function, and act as a value and as a function, so when used as function, make own runnable object.

  • A runnable object always is connected with an output object, so Print command always use that object.


Stack for Values


  • A stack of values is an object special collection of values. Calling modules, functions, subroutines we pass arguments to a stack of values. This isn't used as return/process stack. 
  • M2000 environment start with one stack for values, the global stack. Stack for values can hold any object/value. We READ from top (say position 1) and we put to top using PUSH, or at the end using DATA. So we can use it as LIFO or FIFO
  • We can read any value/object from stack without popping, using index number (1 is the top). We can't change value using single statement (this can be done for user stack objects, not the current one, using RETURN statement), but we can move fast to top, then drop it, and place a new value and move back to specific position (Statements SHIFT, DROP, PUSH, SHIFTBACK)
  • Any module call any other module passing current stack values
  • Normally any function start with new stack for values 
  • Using CALL we can call a function as Module (passing current stack of values) 
  • We can open a temporary stack for values hiding current stack
  • Event Handler always use new stack for values 
  • Passing by reference can be done, with a copy of a weak pointer.
  • We can pass by reference values/groups/functions but no modules/subroutines 


A BASIC like Language 


  • No case sensitive for names, except Labels
  • Use of $ and % at the end of names for strings and integers 
  • Numeric computations always done in double floating point. 
  • Strings as UTF16LE, 2 byte character, can be big to 2Gbyte

  • DATA push to end of stack, so DATA 1,2 push 1 to end, then push 2 to end, so if we start with empty stack (using FlUSH) then READ work as in BASIC. There isn't a Restore to first DATA, but we can place DATA in a Module or in a Sub, because stack is the same, so calling again a module with DATA only commands we fill the stack for readings.
  • Subroutines SUB/END SUB
  • Let has specific use. Let A=10 has the same effect as Push 10 : Read A.
    Pushing result to stack and reading from stack.
    A statement A=10 first find or define A, then examine if expression is compatible as number (or object, can't know), without evaluation (so for this reason we have to put $ for variables and functions names which return strings), and then if is ok then evaluate it.
  • Random Access files one field only (we can split field using commands)
  • Optional Numbers in lines (can be used as labels too)
  • Labels (this is a label Label:). Labels with letters need a separate line, optionally comments after in same line.
  • Colon : split commands in line. 

  • Semi colon ; used for Print command to suppress the moving of cursor to next column, and when we call modules and we wish to decorate them. Decoration is a way to pass temporary module definitions as final inner definitions in a module which we call. These decorated definitions can't altered from inside, and used only for the decorated call.
  • There is no Run command, we use module name instead. We can make a Module as Run, and we can place code inside this module. Then we can write Run (as module name) to execute this code. We can write some more "programs" and each one can be called by name. 


Basic Types 


  • Number (it is a Double in VB6). 
  • Integer (it is a Double in VB6, double with no decimals in M2000) (use % at the end of name) 
  • String (it is a BSTR as in VB6 and a string data type that is used by COM) (use $ at the end of name)
We can make from Basic Types:
  • Local Constants 
  • Global Constants 
  • Local Variables 
  • Global Variables 
  • Static variables (per runnable object) 
  • Global Arrays 
  • Local Arrays
  Also we can make final variables (which can take once a value, and second time return error) in groups (we have no constant there). We can make final arrays, so each item in array can take once a value and second time return also error. Internal a final variable and a final array item are constants.


Special Objects/Values 

example: json library

  • Document (linked list of paragraphs)
  • Long value (32bit) 
  • Event (Internal list of functions) 
  • Lambda Function with closures 
  • Auto Array, a nameless array, where (,) is an empty auto array. 
  • Stack (for Values). We can move items from top to any position, and vis versa. 
  • Arrays using () or without (as pointers to arrays) 
  • Inventory, a list of keys, or keys and values. Unique Keys, can be string or numbers (internal strings). Inventory use hash table. Has quicksort for sorting. Delete statement can't retain order, we have to sort again.
  • Inventory queue, as Inventory but can take same keys. Has a "stable" type for sorting, so same keys retain order of input. We can't use Delete statement. We have Drop statement to drop from the end, a number of keys, or to drop all keys after a number of keys. 
  • Buffer (memory chunk), we can make Structures for Buffers, and Structures may have unions. We can use unsigned numbers, 8, 16 and 32 bit, and doubles (64bit). We can store/read strings one or two bytes per character. We can obtain addresses and use them when calling external functions (from dll).
  • Com Objects (we can use WithEvents to make event sink and root events to M2000 functienons) 
  • Forms/Controls (are com objects too, but are internal to environment) 
  • Com Properties, as identifiers bind once to an object, as properties 

Inventories, Arrays and Stacks are data containers, and may contain anything, including other containers.
Also there are Layers for graphic commands. Console has 36 layers, one for background, one as "console", 32 as players/layers (we can define positions and priority, and can used as sprites, with magnification and rotation plus transparency color). There are two more layers, the printer page layer, and the transparency guard, a special form in low level, to block transparency to act as window to desktop. Console also can change form, to an irregular surface.

User Forms (M2000 GUI) also have one layer for graphics/console commands, except Input command (we use controls for input). Forms may have transparency too. Also we can use modal forms in many levels. Control Form (for showing code as executed, and open with Test command, or by using ctrl  plus G - and some other letters which do nothing else) is never modal, and can be used to watch variables too. Forms are produced from M2000, with commands, and they have same M2000 style for any operating system (Windows/Linux).




  • M2000 script file type is gsb as text in UTF8. Gsb files can be read in any of these encodings UTF8,UTF16LE, UTF16BE, ANSI, and with crlf, lf, lflf as line ending.
  • In scripts tab converted to 6 spaces at loading stage.
  • Open file in ANSI or UTF16LE format (using For Wide, in OPEN)
  • Can load/Save text in/from a Document object using UTF8,UTF16LE, UTF16BE, ANSI.
  • Can open/make databases using ADO and SQL Because early versions have DAO, old commands for databases use ADO as DAO. There is a cache for queries and we can close some in advance, using query string in close command.
  • Can read/write bmp and jpg files. Bitmap can be saved in strings.
  • Can read ico, wmf, emf files.




  • Video player. We can move back or in any position by time. We can set size of displayed video, and position. Video are played in terminal (console)
  • Music player. We can play wav and mid files. Also there is a Background statement with variation to play music in a background task.
  • Music Score Player. We can provide strings with a specific language for music score, for each voice (16 voices, the number 10 used for drum machine), assign an organ for each - except number 10. Scores played using internal task manager.(problematic in Wine, in Linux)
  • Html Browsing. We can play radio, video, show images using Browser, and make some HTML5 works too. (there are problems in Wine, in Linux, mainly with VB control, used internal)
  • Graphics 2D using polar (absolute angle, relative distance) or Cartesian coordinates (relative or absolute), using Draw, Circle, Polygon, Curve, Color and Path to manipulate the graphic output, using pen functions, line styles, regions.
  • Bitmap 2D, scaling, rotating, transparency using color, mask and per cent for all pixels. We can make software sprites to move them by fast redrawing captured background (without using layers - layers are hardware sprites, because are Gdi objects used from graphic card as sprites, and redrawing by hardware). We can mix these two types of "sprites" (software sprites may use paths in console or other layer, but hardware sprites are independent, and leave in background layer above console). User forms can have software sprites but no hardware sprites, by design (maybe in version 10, who knows...)


 Advanced topics 


  • Block of code in curly brackets { }. Any block of code can be used for loop, using Loop command. Statements LOOP, CONTINUE, EXIT, RESTART and BREAK for exit from multiple blocks.
  • Multi line strings using curly brackets { }. Editor can know if content in curly brackets has commands or is a string.
  • Modules, Functions, Subroutines. May have Subroutines/Modules/Functions
  • There is no static modules/functions except for those Global modules/functions which first loaded. We can make temporary globals also.
  • Modules and Functions run on runnable objects. Subroutines are light parts of Modules and functions, without own runnable object (use the parent object)
  • A runnable object may have threads, other runnable objects, with parts of code to run in regular period of time, and we can handle them with a number (thread handler)
  • Modules/ Functions may have Static simple variables (not arrays with Brackets). Static list stay in parents runnable object, so a Module may have two or more set of static variables, if can be called from different runnable objects. A thread can see modules variables, but has own static variables, because it is a runnable object.
  • A runnable object, not a thread, may have functions as event handlers for forms and controls and for events from COM objects.
  • Lambda functions as first citizens
  • Groups as prototyped objects. Class produced a factory function for groups. SuperClass as a common entity for common entities. Groups may have variables, properties, modules,functions, events, arrays, groups in groups. Properties are groups also. Groups can get value, can return value, but by default return a copy of it, and merge a copy of any other. There are no Group Pointers.
  • Arrays with parenthesis, like A(), can be copied
  • Auto Arrays like ((1,2),(3,4)) is an array with two items, and each item is an array with two items.
  • Containers: Stacks, Arrays without parenthesis like A, Inventories (map type list),used by pointers to them. We can assign a group, or other value, or other container, in any position/index/key to those containers.
  • User Structures to define memory blocks, Buffers. We can place/read in/from buffers unsigned numbers (byte, word, long), double (8 byte), and strings (one or two bytes per char). We can make structures in structures and unions. Structures used to make Buffers, memory with specific start and size, as arrays of structures. 
  • We can declare objects as COM objects, using registered free objects (we can't make com objects). Also we can declare forms/controls (they are com objects too, but they are internal M2000 environment's objects). We can declare OS functions and other functions from DLLs using C calls.From com objects we can get events
  • We can use Javascript/VbScript from M2000, exporting M2000 object to them.


Special Behavior 


  • We can change later a local function or a module definition with a new one. 
  • Decoration: We can change a module B inside a local module A before a calling of A with a module defined in the current module.
  • Groups (objects in M2000) may have modules/functions that can be changed later.  We can make, in groups, final modules and functions to not changed during execution. Groups may have other groups inside in any level, and each one may have a SuperClass link, to access unique members to Superclass. So we may have a group with more than one superclass, each one in separate group inside (including top one). There is no need for pointers to groups, because we use containers, so we use indexes or keys or positions as pointers to groups. Containers have pointers, and can exist as group members. Coping a group is a default behavior, but pointers to containers copied as pointers. Arrays with parenthesis inside group are special containers which have shallow copy (copy all items except those containers which copy pointers only). We can make operators for groups also, as a special form of function.
  • A Superclass is a group in a state of "float" group (like an nameless group in a container), which all members are closed, encapsulated and excluded form variables/modules lists. We can't access Super class members outside from a group which is linked to it. We use Superclass prefix to use those members. A superclass can't have link to another superclass. A group created from a superclass (by assign it), get only the public and private members of superclass, and not the unique members, but get a link to superclass for later use through Superclass prefix.
  • We can open a "float" group (as those in containers) using For statement (like with in visual basic), but here we can place more than one, and use more than one dot to reference to each. (For object [,object] {} and For {} are different commands). "Unfloating" a group means that we place a name (automatic in a for statement) for it and for that time we can access any public member, or we can pass reference to it, or to members of it.
  • Calling a module, interpreter never check the argument list, just send arguments using stack for values, so the calling module is responsible to leave stack in a normal condition (this is not a return stack). Maybe we want to return values. This hold for function called as modules using Call statement.
  • Calling a user function in an expression can get any argument list and function's code is responsible to read values. If some values left in stack for values isn't problem, because stack destroyed at the exit.
  • In any case above two paragraphs, there are ways to inspect stack before read values. This means that a module or function can read passing argument to parameters in stages, and not at the beginning of execution of their code.
  • Modules can't called recursive except we call them using Call statement.
  • Functions has recursion at a limit of 3233 calls, a Call to function or to Module use less the return stack so we get recurtion >5000 calls. Check Monitor statement.
  • Subroutines if never use block of codes can have big number of recursion, and this can be set to 100000 or more, using a special statement Recursion.Limit.
  • Block of codes, using curled brackets { } have an internal flag to repeat execution, and can be set for one time with Loop command.
  • We can load modules, or edit modules (we can rerwrite code) at execution time. Loading from running modules performed once. So next time we use Load for same file, we get the stored one. We can load modules/functions only skipping other commands, or we can load from disk (bypassing the store one) with a New tag (Load New)
  • There is Eval() and Inline statement to parse expressions and 
    and pass in line code at run time.
  • We can call vbscript or javascript passing special object to execute back commands from these script languages and execute vbscripts or javascript scripts with call back to module which call them.
  • We can declare functions from a dll with c calls, or stdcalls.
  • We can use COM objects, with WithEvents to obtain sink object, and we can define functions with event names using names object underscore event-name. These functions use parent scope, so we use LOCAL for local variables.
  • We can declare GUI forms and controls and get events in functions using object dot event-name and parent scope too.  
  • Functional Programming (we can make lambda functions and pass them as closures to newer lambda functions, so we get a program as one lambda function) (example)


Sources of Values


Each piece of code has six sources for values:
  • Literal values (written in code)
  • From List of variables/arrays (this is a global list)
  • From List of Static variables (per runnable object)
  • From Current Stack of values (can be altered, in some ways)
  • Environment State. From internal read only variables (environment variables)
  • Files/Databases. Statements which work with files/databases.

Pointers to containers can be in List of variables, and in List of Static variables. We can't get reference from static variables (only List of variables can produce references). Arrays with parenthesis (e.g. A()) are objects, so we can't get reference to item of array. We can use weak references for such items, which places name of array and indexes in a string, used as weak reference. When we use this string, interpreter check if exist, and then it use the value.

Groups are objects with members (values, code as modules, functions, operators, value part, set part, and can have inner groups in any level) in one of two mode: As named group, each value member is as separate entity in list of variables, so we can get a reference from a member of a group. As in a position in a container, a "float" state, there is no member in list of variables, and all members are inside a private container in group. Interpreter has no way to read members in from a group in a container. To manipulate group, interpreter has to attach it to variable list, and deploy all modules/functions in a global Modules/Functions list, using a copy in - copy out procedure, so the group has to take name. Members of group which are containers copied just by pointer.

Groups are "Values", and symbol "=" return  a float group (except group has a value defined, so return this value, or we can use Group() to get from a named group - no float- a copy from that ). The returning float group can be merged to another named group (we get new superclass by this operation if float group has a superclass), or can be just drop a group in a container and take a place on it. So a A(3)=GroupA place in A(3) a copy of GroupA, but GroupB=GroupA merge a copy of GroupA tp GroupB. And A(3)=A(4) make a copy of A(4) group to A(3). (no pointers for Groups, but there are pointers inside only for interpreter, because a group is a Com object Group). We can pass a group by reference using &, so Alfa &GroupA call Alfa passing GroupA by reference, make references for all members but not for group. So a group made by reference may get more members, but these members didn't included in referenced group. And this is the way to add temporary members to groups.

A special container for groups is an array with parenthesis, which can be initialized as holding a same kind of groups, so there is only one place for modules/functions and local to group variables (a special form that is constant for this use and can't passed by reference). We can use arrays for mixed kind of groups, as in other type of containers.

Sources of Code


There are eight places for source in M2000: 

  • Command line in M2000 terminal (or console)
  • List of Modules/Functions
  • In list of variables/arrays, in groups, events and or lambda functions in containers.
  • In list of variables/arrays, in events and in lambda functions.
  • In list of variables/arrays, in arrays when an array initialized with a group for all items.
  • In current stack as a reference for function, or in any container in stack, or in lambda function in stack, or an event object in stack.
  • In a string. We can use it with Inline command, or for expression with Eval() and Eval$(), also we can define groups providing code in a string (old fashion, for groups)
  • In Disk in files.

A group which have a name, has all code in List of Modules/Functions. A group module in that place can be decorated (altered inner modules from calling statement), like other modules in list of modules/functions

A function can be passed by reference, and this isn't the same as a reference in a value in list of values. A function pass code as reference, and if is a member of group, then pass after code the weak reference of group which belong. So when a new function created as a reference, get same code and same group name, so act as it is in group;

Event is a special object with a signature for parameters and a list of functions (as handlers of event), which can be passed any time. Event objects may be member of a Group.

Lambda functions

Lambda function is a special object, with one list of closures (variables), and a nameless function. A Closure is a private variable for lambda, which can be used in function, and hold value after the end of function execution. We make closures by using an existing variable, or a new one. Closures can be other lambda functions.

When a lambda get a name in list of variables, say A, then a name A() created in list of modules/variables. Actual lambda object is pointed in var() at an index pointed in the pair ("A", index1). In Function A() is a call to an extern function in var index same as index1. Because passing arguments are stay in stack of values, when we use the call to extern function we pass the same stack of values, so it is the same as we call the function in lambda, but code of lambda function is always in list of variables/arrays.

We can't get a second pointer for a lambda object. We get a new object, with a copy of closures (at the current state) and the code of function. We can use recursion using Lambda() or Lambda$() as name to call it, and closures get a a reference in every call, so closures stay there in any level of recursion.

A lambda in a group has access to group variables. We can assign a new lambda in a group member which is lambda, and in code of new lambda we can use group members. In recursion, at each call lambda function has same access to group variables.

Unicode Support

Variable names can have any Unicode letter plus symbols dot, underscore, and non breaking space (nbsp), except symbols used for operators or other purposes. Internal editor colored properly variables when names follow the rules. So a variable may have space as nbsp and we can insert it using internal editor Shift Ctrl Space. (there is another space for numbers Shift Alt Space).

Unicode supported for filenames, for files (using Open with Wide tag), in forms, controls, terminal. Not supported right to left Unicode (we can displayed it only with Report statement and in editor, but not in Print statement).


We can alter the interpreter using switches (in command line, or by using Switches from M2000 terminal, or using Set Switches from code inside modules/funcitons. Use command Monitor to check switches. See Help Switches to see more info.


-TXT compare strings as binary (> < >= >= <> =) **by default**

+TXT compare strings as text (> < >= >= <> =)

With any TXT state we can use Order("a", "b") to get values 1, 0, -1 (-1 means the right one is bigger) with any state of this switch. This function use Locale and numeric evaluation for comparing, so "alfa12" is bigger to "alfa8", and "alfa8" is less than "alfa008", but "alfa9" is bigger than "alfa008". Comparing work as equal parts found, so we can use strings with letters and numbers. Numbers can be as any double value, but decimal point is always a "." for evaluation.


-DEC use decimal point as dot

+DEC use decimal point as local (for code is always dot) ***by default***


-DIV like VB6 with integers.
Not the same for Double (mod return fractions too) ***by default***

Print 10 mod 2.3*2 is Print 10 mod (2.3*2)

+DIV like Python
Print 10 mod 2.3*2 is Print (10 mod 2.3)*2
There are euclidean Div and Mod using #. Div# and Mod#


-PRI ***by default***
Print True Or False And False
Print (True Or False) And False

And has priority over Or

Print True Or False And False
Print True Or (False And False)



not used for Version 9. In this version there is a control for return stack usage, measuring the use.


Not used for Version 9. In this version there is a control for return stack usage, measuring the use. Calling modules by name we get more calling depth, from calling modules/function using call, or calling functions in expressions. Subs not using return stack. Blocks {} also use return stack. Calling subs without using blocks we get the best calling depth. We can define a "stop" using Recursion.Limit command only for safety reasons upon the logic of program.


\\ only for current running interpreter


using For loop as normal in M2000, always execution of block, using from step the absolute value, if starting and ending number are different, or using normal value if starting and ending number are equal (to compute the final value for control variable)


using normal sign step, and if sign of (ending point- starting point) isn't equal to step sign then we get no execution of for loop.


\\ only for current running interpreter

normal a Dim A(4) has 4 items (0 to 3 or 1 to 4 depends of Base, by default is 0 to 3)


if base 0 then we get for dimension items>0 one more, so a Dim A(4) has items from 0 to 4, so Len(A())=5

Also these arrays expands from last dimension (right one, but normal is from left one, or using Dim Ole make it from right one).

Old interpreter mode
New "Secure" interpreter mode
In the example bellow k from inner module z is not a new one, because exist as z.k, if we use mode -sec.

When we change to "+sec" then we get 10, because z.k isn't visible (has other prefix, which interpreter choose), so outer z.k and inner z.k have alias names, as keys to list of variables.

Code coloring are passed to clipboard, from internal editor, as html text. If we use Windows then we can just paste to browser, but in Linux we have to paste to Libreoffice and then copy and past to browser).

\\ we use set inside module to execute CLI command
set switches "-sec"
\\ print 100
module z { k=10 : module m {module z { k=100}: z } : m : Print k} : z
set switches "+sec"
\\ print 10
module z { k=10 : module m {module z { k=100}: z } : m : Print k} : z