- DCPU must provide a self sufficient environment for developing and running software - Capability is more important than capacity - Users shouldn't be bothered with details that the machine can handle - A bug in the user’s Admiral-code should not be allowed to lead to undefined behavior of the interpreter (except poke() and call()) - Should there be no limit on the range of numbers, the length of strings, or the size of collections (other than the total memory available) - "First make it work. Then make it right. Then make it fast." - Memory allocation targets: - 70% for heap - 5% for stack - 25% for admiral core (including static memory buffers) - Memory is conserved by using direct one-pass interpreter - It is quite slow, but could be boosted with AST compiler - memory-speed trade-off - Pratt’s algorithm for efficient expression parsing - Mark and sweep garbage collector for memory conservation and detecting trash even with reference loops - Floppy load/save uses object graph serialization e.g. - save("big.obj", big_obj) - big_obj = load("big.obj")
Classic Hello World in Admiral.
>print 'Hello World' Hello World
..or as a function call:
>hello="print 'Hello World'" # assign function string to 'hello' >hello() # call 'hello' as function Hello World # output
In Admiral - ANY and ALL strings can be called as functions! You could even write:
>'print argv[0]'('Hello World') # crazy way to call constant string as function
Hello World # function output
Here is another example of Admiral code. A function that calculates square Root for integers and floats:
>sqrt=edit() # start integrated editor
p=0 # define variable x=argv[0] # assign first unnamed function argument to x while not x==p: # loop to calculate sqrt p=x x=(x**2+argv[0])/(2*x) return x # return value
>print sqrt(81.0) # function call with float argument 9.00000000 >print sqrt(81) # function call with integer argument 9
Example: variable swap
>a=1 >b=2 >a,b=b,a
Example: dictionary printing
>d={'a':1,'b':2}
>for k,v in d:print k, v
a 1
b 2
--
- Pure interpreted language - Python inspired grammar - Garbage collection - Dynamic typing - Prototype based inheritance - Data types - Variable length integers (only limited by available heap space) - Floats with compile time precision selection (1+ words for mantissa) - Booleans, strings, lists, tuples and dicts - Integrated code editor with gap buffer - Object serialization for floppy - Dict implementation with binary search - Nice starting set of built-in functions - Interactive command prompt with line editing - Functions: poke(), peek() and call() for low level access - Functions: hwn(), hwq() and hwi() for low level hardware access - Functions: HIC select, status, read and transmit functions for TechCompliant HIC hardware - Github issue tracker contains a list of development items - Support for other TechCompliant hardware--
Following sources were proven to be invaluable sources for information:
- Let's Build a Compiler, by Jack Crenshaw: http://compilers.iecc.com/crenshaw/
- Top Down Operator Precedence, by Douglas Crockford: http://javascript.crockford.com/tdop/tdop.html
- Simple Top-Down Parsing in Python, by Fredrik Lundh: http://effbot.org/zone/simple-top-down-parsing.html
- The Art of Assembly Language Programming, by Randall Hyde: http://cs.smith.edu/~thiebaut/ArtOfAssembly/artofasm.html
- Data Structures and Algorithms with Object-Oriented Design Patterns in Java, by Bruno R. Preiss: http://www.brpreiss.com/books/opus5/html/book.html
--
There are dozens of advanced compilers that compile DCPU assembler from multitude of different source languages e.g. java, c, c++, ...
However, these compilers run IRL and emit outside processing power to in-game universe :) That is agains the Admiral´s philosophy and I present here only the projects that interpret or compile some higher level language inside DCPU.
- umbibium´s CBM64 Basic: https://github.com/unbibium/dcpu-cbmbasic
- Amazing port of Commodore 64 BASIC and KERNAL to the DCPU-16
- hellige´s goforth: https://github.com/hellige/dcpu
- I know nothing about forth, so the DCPU role in this project is a mystery for me :)
--
The latest version of Admiral release is available from github:
The admiral.bin is the precompiled binary file that should run in emulators.
However, if you only want a quick peek at the Admiral, the easies way to try it is with Admiral Emulator:
Note that Admiral Emulator contains older version of Admiral and is not maintained at the moment.
--
All source code is available in Github:
https://github.com/orlof/dcpu-admiral
Since the collapse of 0x10c, most of the DCPU development tools have been abandoned. Admiral used to work with all the major tools e.g. DevCPU, DCPU toolchain, Organic & Lettuce, F1DE...
Today I use my self-made assembler and debugger:
- https://github.com/orlof/dcpu-compiler
- Python 2.7, Notchian syntax
- https://github.com/orlof/dcpu-debugger
- Java 1.8, graphical ui
Those are pretty sophisticated and field proven tools, but will lack proper releases and packaging until someone other than me starts using them ;)
--
NOTE: Latest Admiral interpreter does not output return value automatically to screen. Instead 'print' statement must be used.
When Admiral starts, it will show an interactive prompt '>' and wait for input. It can evaluate one line statements.
>print 1+2**32 4294967297 >for a in range(5): print a 0 1 2 3 4
Admiral also has a built-in text editor to facilitate software development in deep space colonies. It is started by calling edit(). edit() returns the edited text as string that can be assigned to a variable. To exit the editor hold down CTRL and then press x (CTRL-x). If you want to discard your editing, use CTRL-c, which will return the original string instead of the edited version.
result=edit()
If you need to edit an existing text, you can give a string argument for edit():
result=edit(result)
Since Admiral is pure interpreter all strings are callable (i.e. can be used as functions):
>'print msg'(msg='Hello World again!') Hello World again!
Function calls can have positional and keyword arguments in any order.
Example: only keyword arguments (type='Monster", size='XXXL')
get_danger_level(type='Monster", size='XXXL')
Example: only positional arguments (argv[0]='Monster' and argv[1]='XXXL')
get_danger_level('Monster', 'XXXL')
Example: mixed keyword and positional arguments (type='Monster' and argv[0]='XXXL')
get_danger_level(type='Monster', 'XXXL')
Positional arguments are automatically assigned to argv[] array from left to right order.
You can set default value for keyword argument with the following one line idiom in the beginning of the function:
if "type" not in locals(): type='Gigalosaurus'
Dicts with prototype creation provide "poor mans" objects :-)
>ship={} # create prototype object (i.e. dict)
>ship.spd=0 # assign value to prototype
>ship.accelerate=edit() # define function in prototype
--------------------------
me.spd+=me.acceleration # function modifies object field
--------------------------
>shuttle=ship.create() # create new object from prototype
>shuttle.acceleration=8 # set value in new object
>shuttle.accelerate() # call new object's method (that is defined in prototype)
>print shuttle.spd
8 # new objects field has changed...
>print ship.spd
0 # and prototype's fields are intact
Dict created with dict.create() inherits its properties from prototype. Prototype dict is used to read values if property is not defined in dict itself. Note that prototype values are not just copied at creation time, but also changes in prototype values are reflected to the created dict unless it has already defined the value itself. However, writing values to created dict never modify the prototype dict.
Admiral has three different types of built-in functionalities: statements, global functions and class functions. E.g. print and run are stetements, len() and mem() are global functions, and str.encrypt() is a class functions.
Admiral programmer can write global functions and dict class functions. New statements or functions to other class types cannot be added. Global functions are variables that have string value and class functions can be defined for dicts by adding function with str key.
Example: global function
>out="print argv[0]"
>out("Hello")
Hello
Example: class function
>a={}
>a.out="print argv[0]"
>a.out("Hello")
Hello
--
Admiral provides some built-in data types i.e. dict, list, tuple, str, int, float and boolean.
The Admiral interpreter acts as a simple calculator: you can type 'print' and an expression at it and it will write the value. Expression syntax is straightforward: the operators +, -, * and / work just like in most other languages (for example, Pascal or C); parentheses can be used for grouping. For example:
>print 2+2 4 ># This is a comment >print 2+2 # and a comment on the same line as code 4 >print (50-5*6)/4 5 ># Integer division returns the number closer to 0: >print 7/3 2 >print 7/-3 -2
The equal sign ('=') is used to assign a value to a variable.
>width=20 >height=5*9 >width*height
Admiral treats an assignment as both an expression and as a statement. As an expression, its value is the value assigned to the variable. This is done to allow multiple assignments in a single statement, such as
>x=y=z=0 # Zero x, y and z >print x,y,z 0 0 0
Variables must be “defined” (assigned a value) before they can be used, or an error will occur:
>n # try to access an undefined variable ERROR:2846 n ^
Error codes are not yet documented and will change in every release.
There is full support for floating point; operators with mixed type operands convert the integer operand to floating point:
>print 3 * 3.75 / 1.5 7.5 >print 7.0 / 2 3.5
Floating point precision can be set during compilation time in defs.dasm16 file:
#define FLOAT_MANTISSA_WORDS 2
Recommended values are in range 1-4. NOTE currently only value 2 has been tested.
Besides numbers, Admiral can also manipulate strings, which can be expressed in several ways. They can be enclosed in single quotes or double quotes:
>'spam eggs' >"doesn't" >'"Yes," he said.'
repr() function generates strings in single quotes.
String literals cannot span multiple lines.
The str class can be used to handle 16-bit binary data and DCPU 7-bit text. Some str functions such as replace or split will not work with binary data. (That will be addressed in later releases)
Strings can be concatenated (glued together) with the + operator, and repeated with *:
>word = 'Help' + 'A' >print word HelpA >print '*' + word*5 + '*' *HelpAHelpAHelpAHelpAHelpA*
Strings can be subscripted (indexed); like in C, the first character of a string has subscript (index) 0. There is no separate character type; a character is simply a string of size one. Like in Python, substrings can be specified with the slice notation: two indices separated by a colon.
>print word[4] A >print word[0:2] He >print word[2:4] lp
Slice indices have useful defaults; an omitted first index defaults to zero, an omitted second index defaults to the size of the string being sliced.
>print word[:2] # The first two characters He >print word[2:] # Everything except the first two characters lpA
Unlike a C string, Admiral strings cannot be changed. Assigning to an indexed position in the string results in an error.
However, creating a new string with the combined content is easy:
>print 'x' + word[1:] xelpA >print 'Splat' + word[4] SplatA
Here’s a useful invariant of slice operations: s[:i] + s[i:] equals s.
>print word[:2] + word[2:] HelpA >print word[:3] + word[3:] HelpA
Degenerate slice indices are handled gracefully: an index that is too large is replaced by the string size, an upper bound smaller than the lower bound returns an empty string.
>print word[1:100] elpA >print repr(word[10:]) '' >print repr(word[2:1]) ''
Indices may be negative numbers, to start counting from the right. For example:
>print word[-1] # The last character A >print word[-2] # The last-but-one character p >print word[-2:] # The last two characters pA >print word[:-2] # Everything except the last two characters Hel
But note that -0 is really the same as 0, so it does not count from the right!
Out-of-range negative slice indices are truncated, but don’t try this for single-element (non-slice) indices:
The built-in function len() returns the length of a string:
>s = 'supercalifragilisticexpialidocious' >len(s) 34
Current strings do not support escape characters or output formatting. That will be fixed to future releases.
- str.encrypt(key)
-
Encrypts the string with given key using hummingbird2 codec.
- str.decrypt(key)
-
Decrypts encrypted string with given key and hummingbird2 codec.
- str.lower()
-
Return a copy of the string with all the cased characters converted to lowercase.
- str.upper()
-
Return a copy of the string with all the cased characters converted to uppercase.
- str.find(sub[, start[, end]])
-
Return the lowest index in the string where substring sub is found, such that sub is contained in the slice s[start:end]. Optional arguments start and end are interpreted as in slice notation. Return -1 if sub is not found.
The find() method should be used only if you need to know the position of sub. To check if sub is a substring or not, use the in operator:
>"mi" in "Admiral" True
- str.replace(old, new)
-
Return a copy of the string with all occurrences of substring old replaced by new.
- str.split([sep])
-
Return a list of the words in the string, using sep as the delimiter string. Consecutive delimiters are not grouped together and are deemed to delimit empty strings:
>'1,,2'.split(',') ['1','','2'])The sep argument may consist of multiple characters>'1<>2<>3'.split('<>') ['1','2','3']).Splitting an empty string with a specified separator returns [''].If sep is not specified, a different splitting algorithm is applied: runs of consecutive whitespace are regarded as a single separator, and the result will contain no empty strings at the start or end if the string has leading or trailing whitespace. Consequently, splitting an empty string or a string consisting of just whitespace with a None separator returns [].
>' 1 2 3 '.split() ['1','2','3']
- str.endswith(suffix)
-
Return True if the string ends with the specified suffix, otherwise return False. suffix can also be a tuple of suffixes to look for.
- str.startswith(prefix)
-
Return True if string starts with the prefix, otherwise return False. prefix can also be a tuple of prefixes to look for.
- str.isalpha()
-
Return true if all characters in the string are alphabetic and there is at least one character, false otherwise.
- str.isdigit()
-
Return true if all characters in the string are digits and there is at least one character, false otherwise.
Another useful data type built into Admiral is the dictionary. Dictionaries are sometimes found in other languages as “associative memories” or “associative arrays”. Unlike sequences, which are indexed by a range of numbers, dictionaries are indexed by keys, which can be strings or numbers. Tuples can not be used as keys as they can contain other mutable types.
It is best to think of a dictionary as an unordered set of key: value pairs, with the requirement that the keys are unique (within one dictionary). A pair of braces creates an empty dictionary: {}.
>d = {}
Placing a comma-separated list of key:value pairs within the braces adds initial key:value pairs to the dictionary;
>d = {1: 2, 'Hi': [5,4,3,2,1]}
this is also the way dictionaries are written on output.
>print d
{1: 2, 'Hi': [5,4,3,2,1]}
The main operations on a dictionary are storing a value with some key and extracting the value given the key. Admiral supports multiple formats to store key-value pair:
>d={}
>d[1]=3
>d.one=1
>d["two"]=2
>print d
{1: 3, 'one':1, 'two': 2}
It is also possible to delete a key:value pair with del. If you store using a key that is already in use, the old value associated with that key is forgotten. It is an error to extract a value using a non-existent key.
>del d[1]
>print d
>{'one':1, 'two': 2}
- dict.create()
-
Return a new dict object that has the existing dict set as prototype.
- dict.me
-
If function is called via dict reference e.g. dict.hello() then "me" keyword can be used to access the properties of the referenced dict inside that function.
>d={'hello': 'print me.value', 'value':10} >d.hello() 10
The list is a versatile datatype which can be written as a list of comma-separated values (items) between square brackets. Important thing about a list is that items in a list need not be of the same type.
Creating a list is as simple as putting different comma-separated values between square brackets. For example −
>l1=['Sun','Alpha Centauri',2085,16.7] >l2=[1,2,3,4,5] >l3=["a","b","c","d"]
Similar to string indices, list indices start at 0, and lists can be sliced, concatenated and so on.
To access values in lists, use the square brackets for slicing along with the index or indices to obtain value available at that index. For example −
>print l1[0] Sun >print l2[1:5] [2,3,4,5]
You can update single or multiple elements of lists by giving the index on the left-hand side of the assignment operator, and you can add to elements in a list with the append() method. For example −
>l2[2]=2001 >print l[2] 2001
To remove a list element, you can use the del statement, but you must know the index of the element which you are deleting. For example −
>del l1[1]; >print l1 ['Sun',2085,16.7]
Lists respond to the + and * operators much like strings; they mean concatenation and repetition here too, except that the result is a new list, not a string.
| Expression | Results | Description |
|---|---|---|
| len([1, 2, 3]) | 3 | Length |
| [1, 2, 3] + [4, 5, 6] | [1, 2, 3, 4, 5, 6] | Concatenation |
| ['Hi!'] * 4 | ['Hi!', 'Hi!', 'Hi!', 'Hi!'] | Repetition |
| 3 in [1, 2, 3] | true | Membership |
| for x in [1, 2, 3]: print x | 1 2 3 | Iteration |
- list.append(x)
-
Add an item to the end of the list.
- list.insert(int, obj)
-
Insert an item at a given position. The first argument is the index of the element before which to insert, so a.insert(0, x) inserts at the front of the list, and a.insert(len(a), x) is equivalent to a.append(x).
TODO
Admiral uses boolean variables to evaluate conditions. The boolean values true and false are returned when an expression is compared or evaluated.
None is frequently used to represent the absence of a value, as when default arguments are not passed to a function.
--
Here is a complete list of all the Admiral's statements.
Simple statements are comprised within a single line.
pass_stmt ::= "pass"
pass is a null operation — when it is executed, nothing happens. It is useful as a placeholder when a statement is required syntactically, but no code needs to be executed, for example:
while not getchar()=='y': pass
return_stmt ::= "return" [expression]
return may only occur in a function. If an expression is present, it is evaluated, else None is substituted. return leaves the current function call with the expression (or None) as return value.
break_stmt ::= "break"
break may only occur syntactically nested in a for or while loop. break terminates the nearest enclosing loop.
continue_stmt ::= "continue"
continue may only occur syntactically nested in a for or while loop. It continues with the next cycle of the nearest enclosing loop.
print_stmt ::= "print" [expression ([","] expression)* ]
print evaluates each expression in turn and writes the resulting object to LEM screen. If an object is not a string, it is first converted to a string using the rules for string conversions. A space is written between each object separated by comma. You can also leave out the comma, but then items are written without separator.
e.g.
>print "Hello", "World" Hello World >print "Hello" "World" HelloWorld >name="Orlof" 'Orlof' >print "My name is " name "." My name is Orlof.
Usage of plus operator to concatenate string in print statement is not recommended as it is much slower than using comma or implicit concatenation.
>print "This", "is", "good" This is good >print "This" + " " + "is" + " " + "BAD!" This is BAD!
del_stmt ::= "del" target_list
Deletion removes the binding of that name from the local or global namespace. If the name is unbound, an error will be raised.
Deletion of attribute reference removes the attribute from the primary object involved
cls_stmt ::= "cls"
cls (for clear screen) is a command used by the command line interpreter to clear the LEM1802 screen and restore cursor to top left -corner position.
reset_stmt ::= "reset"
routine that resets the Admiral interpreter and peripheral devices (as if it were turned off and then on again). This command retains the data that is stored into global scope!
run_stmt ::= "run" [filename [args] ] filename ::= expression args ::= expression*
routine that loads Admiral object serialization graph from file and executes it with given arguments. if filename is omitted, "MAIN" is used. Object serialization graph can be either dict or string. String object is executed directly and in dict object execution start point is value associated with key "main".
Compound statements contain other statements; they affect or control the execution of those other statements in some way. In general, compound statements span multiple lines, although in simple incarnations a whole compound statement may be contained in one line.
The if, while and for statements implement traditional control flow constructs.
Compound statements consist of one or more ‘clauses.’ A clause consists of a header and a ‘suite.’ Each clause header begins with a uniquely identifying keyword and ends with a colon. A suite is a group of statements controlled by a clause. A suite can be one simple statements on the same line as the header, following the header’s colon, or it can be one or more indented statements on subsequent lines. Only the latter form of suite can contain nested compound statements, mostly because it wouldn’t be clear to which if clause else clause would belong.
All compound statements are executed in a block scope. Compound statements can use the enclosing scope (i.e. read and assign values to variables that are alrady defined in the enclosing scope) but all variables that are defined in the compound statement are discarded when control exits the compound statement's block scope.
NOTE: To help fitting source code into LEM 32x12 screen, INDENT and DEDENT MUST always BE a SINGLE SPACE!
The if statement is used for conditional execution:
if_stmt ::= "if" expression ":" suite
( "elif" expression ":" suite )*
["else" ":" suite]
It selects exactly one of the suites by evaluating the expressions one by one until one is found to be true (see section Boolean operations for the definition of true and false); then that suite is executed (and no other part of the if statement is executed or evaluated). If all expressions are false, the suite of the else clause, if present, is executed.
The while statement is used for repeated execution as long as an expression is true:
while_stmt ::= "while" expression ":" suite
This repeatedly tests the expression and, if it is true, executes the suite; if the expression is false (which may be the first time it is tested) the loop terminates.
A break statement executed in the suite terminates the loop. A continue statement executed in the suite skips the rest of the suite and goes back to testing the expression.
The for statement is used to iterate over the elements of a string, tuple, list or dict.
for_stmt ::= "for" target_list "in" expression_list ":" suite
The expression list is evaluated once. The suite is then executed once for each item provided by the expression list in the order of ascending indices. Each item in turn is assigned to the target list using the standard rules for assignments, and then the suite is executed. When the items are exhausted the loop terminates.
A break statement executed in the suite terminates the loop. A continue statement executed in the suite skips the rest of the suite and continues with the next item, or terminates if there was no next item.
The suite may assign to the variable(s) in the target list; this does not affect the next item assigned to it.
Hint: the built-in function range() returns a sequence of integers suitable to emulate the effect of Pascal’s for i := a to b do; e.g., range(3) returns the list [0, 1, 2].
--
- Generic functions
- Numeric functions
- Character functions
- User input / output functions
- Memory functions
- Type conversion functions
- Floppy functions
- HIC functions
- Hardware functions
- cmp(x, y)
-
Compare the two objects x and y and return an integer according to the outcome. The return value is negative if x < y, zero if x == y and strictly positive if x > y.
<ul> <li>Numbers are compared arithmetically</li> <li>Strings are compared lexicographically using the numeric equivalents (the result of the built-in function ord()) of their characters.</li> <li>Tuples and lists are compared lexicographically using comparison of corresponding elements. This means that to compare equal, each element must compare equal and the two sequences must be of the same type and have the same length.</li> <li>If not equal, the sequences are ordered the same as their first differing elements. For example, cmp([1,2,x], [1,2,y]) returns the same as cmp(x,y). If the corresponding element does not exist, the shorter sequence is ordered first (for example, [1,2] < [1,2,3]).</li> <li>Other objects of built-in types compare unequal unless they are the same object; the choice whether one object is considered smaller or larger than another one is made arbitrarily but consistently within one execution of a program.</li> </ul>
- len(S)
-
Return the length (the number of items) of an object. The argument may be a sequence (string, tuple or list) or a mapping (dictionary).
- range(end)
- range(start, end[, step])
-
This is a versatile function to create lists containing arithmetic progressions. It is most often used in for loops. The arguments must be plain integers. If the step argument is omitted, it defaults to 1. If the start argument is omitted, it defaults to 0. The full form returns a list of plain integers [start, start + step, start + 2 * step, ...]. If step is positive, the last element is the largest start + i * step less than stop; if step is negative, the last element is the smallest start + i * step greater than stop. step must not be zero.
- sort(S[, reverse])
-
Return a sorted version from the items in iterable. Strings and tuples are sorted by creating a new sorted iterable and lists are sorted in place. Reverse is a boolean value. If set to True, then the list elements are sorted as if each comparison were reversed.
- type(obj)
-
Return the type of an object. The return value is an integer specifiying the type.
Type Value none 0x0080 float 0x0040 int 0x0020 bool 0x0010 str 0x0008 tuple 0x0004 list 0x0002 dict 0x0001
- abs(x)
-
Return the absolute value of a number. The argument may be a plain integer or a floating point number.
- rnd([start[, end]])
-
Return the next pseudorandom number. TODO
- ord(char)
-
Given a string of length one, return the value of the byte. For example, ord('a') returns the integer 97. This is the inverse of chr().
- chr(i)
-
Return a string of one character whose ASCII code is the integer i. For example, chr(97) returns the string 'a'. This is the inverse of ord().
- getc()
-
Blocks until user types a key and return the key typed as a string of one character.
- key([int])
-
Without argument return immediately the next key typed from keyboard buffer, or 0 if the buffer is empty. If int is specified return true if the specified key is down or false otherwise.
- input([str])
-
If str argument is present, it is written to standard output without a trailing newline. The function then reads a line from input, converts it to a string (stripping a trailing newline), and returns that.
- edit([str])
-
Opens interactive text editor. If the input argument is present, editor is initialized with input string. Editor can be used to modify the contents. Editing can be canceled by typing (press and release) CTRL followed by typing 'c', or confirmed by typing CTRL and 'x'. The function then converts editor contents (confirm) or the original input string (cancel) to a string, and returns that.
- repr(obj)
-
Return a string containing a printable representation of an object. This is similar to str funtion, but surrounds string type values in quotes.
- hex(int)
-
Convert an integer number (of any size) to a lowercase hexadecimal string prefixed with “0x”.
- wget(int x, int y)
-
Return character (string of length 1) containing the character at screen coordinates x, y.
- wset(int x, int y, char c)
-
Draw character (string of length 1) to screen coordinates x, y.
- cursor(int x, int y)
-
Move cursor to screen coordinates x, y. Next print statement will start from the cursor coordinates.
- scroll(int dx, int dy)
-
Scroll screen dx, dy characters. Areas that scroll in are filled with zero and appear empty on screen.
- id(x)
-
Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.
- mem()
-
Runs the garbage collector and returns the amount of free heap space in words.
Calling the gc method makes Admiral expend effort to recycling unused objects in order to make the memory they currently occupy available for quick reuse. When control returns from the method call, the Admiral has made a best effort to reclaim space from all discarded objects. </p>
- locals()
-
Return a dictionary representing the current local symbol table.
- globals()
-
Return a dictionary representing the current global symbol table.
- bool(x)
-
Convert a value to a Boolean, using the standard truth testing procedure.
The following values are interpreted as false: false, numeric zero of all types, and empty strings and containers (including tuples, lists and dictionaries). All other values are interpreted as true.
- int(x)
-
Convert a number or string x to an integer. If x is a number, it can be a boolean, a plain integer, or a floating point number. If x is floating point, the conversion truncates towards zero.
- float(x)
-
Convert a string or a number to floating point. If the argument is a string, it must contain a possibly signed decimal or floating point number. The argument may also be [+|-]nan or [+|-]inf. Otherwise, the argument may be a plain integer or a floating point number, and a floating point number with the same value is returned.
- str(x)
-
Return a string containing an object representation of obj. For strings, this returns the string itself.
- format()
-
Format is used to initialize a DCPU M35FD floppy for use. It erases all information off the floppy.
- dir()
-
The dir command returns a dictionary containing the available files in DCPU M35FD floppy.
- load(str)
-
The load command returns the object stored in DCPU M35FD floppy with filename str.
- save(str, obj)
-
The save command serializes the defined obj with filename str to DCPU M35FD floppy.
- rm(str)
-
Removes serialized object with filename str from DCPU M35FD floppy and frees the reserved disk space.
HIC is a bi-directional multipurpose data port. Transmissions in either direction are independent of each other and can operate asynchronously of one another.
- int hsel()
- bool hsel(int port)
-
Returns the lowest port which has data available or -1 if no data is available. If port number is specified hsel returns true if data is available in the port, false otherwise.
- str hinfo(int port)
-
Returns name for given port or None if port is invalid.
- int hread(int port)
-
Returns an integer containing a word of data received from given port or none if no data is available.
- void hsend(int port, int data)
-
Transmits a word of data to specified port.
- call(addr)
-
Hands the CPU over to a the machine language subroutine at a specific address. If address is not specified then start of the floppy drive buffer is used as a default. Floppy drive buffer provides 512 words of space that is used only when Admiral executes floppy commands. Floppy commands will overwrite the buffer area completely.
Given address should be in the range 0 thru 65535, or 0x0000 thru 0xFFFF. If the given address is outside these limits, Admiral will use LSW as address.
Parameters can be passed between Admiral and subroutine via registers. Before calling the specified address Admiral “loads” a, b, c, x, y, z, i and j registers with the words stored at storage addresses (see table below).
If or when the routine at the specified address returns control to Admiral (via an RTS instruction), Admiral immediately saves the contents of the registers back into the storage addresses memory range: This can be used to transfer results from the machine language routine to Admiral for further processing.
Storage addresses: <pre> a: [0xffff] b: [0xffff] + 1 c: [0xffff] + 2 x: [0xffff] + 3 y: [0xffff] + 4 z: [0xffff] + 5 i: [0xffff] + 6 j: [0xffff] + 7 </pre> Subroutine can pollute registers a-j, but must return with rts. </p>
- peek(addr[, len])
-
Returns the memory contents of the specified address, which must be in the range 0x0000 through 0xffff. The int value returned will be in the range from 0x0000 thru 0xffff. If the address given exceeds the limits of the memory map, Admiral will use the LSW of the address.
The second form with 'length' argument returns a string that contains 'length' words copied from the memory area that starts from the given address.
- poke(addr, val)
-
Changes the content of the memory. New value can be specified either as an integer or string. Integer form stores LSW to given addr and str form copies the str starting from the given addr.
Caution: A misplaced POKE may cause the DCPU to lock up, or garble or delete the program currently in memory. To restore a locked-up DCPU one has to reboot the DCPU, thereby losing any program or data in RAM!
- hwn()
-
Returns the number of connected hardware devices.
- hwq(int)
-
Returns tuple containing three integers (hardware_id, hardware_version, manufacturer).
for n in range(hwn()): hw=hwq(n) print hex(hw[0]), hex(hw[1]), hex(hw[2])
- hwi(int)
-
Sends the interrupt to hardware n.
Parameters can be passed between Admiral and interrupt via registers. Before interrupt Admiral “loads” a, b, c, x, y, z, i and j registers with the words stored at storage addresses (see call()).
If or when the interrupt returns control, Admiral immediately saves the contents of the registers back into the storage addresses memory range: This can be used to transfer results from the interrupt to Admiral for further processing.
- read(int)
-
Reads a single sector from floppy and stores it to floppy buffer (0xd980 - 0xdb7f in current build). This method is provided for integrating with non-Admiral floppy formats.
- write(int)
-
Writes a single sector to floppy from floppy buffer (0xd980 - 0xdb7f in current build). This method is provided for integrating with non-Admiral floppy formats.
| OPERATOR | DESCRIPTION | ASSOCIATIVITY |
|---|---|---|
| =, +=, -=, *=, /=, %=, **=, >>=, <<=, &=, ^=, %= | Assignment, augmented assignments | Right |
| , | Comma | Left |
| or | Boolean OR | Left |
| and | Boolean AND | Left |
| not x | Boolean NOT (unary) | - |
| in, not in | Membership test | Left |
| is, is not | Identity tests | Left |
| <, <=, >, >=, <>, !=, == | Comparisons | Left |
| | | Bitwise OR | Left |
| ^ | Bitwise XOR | Left |
| & | Bitwise AND | Left |
| <<, >> | Shifts | Left |
| +, - | Addition and subtraction | Left |
| *, /, % | Multiplication, division, remainder | Left |
| +x, -x | Positive, negative (unary) | - |
| ~x | Bitwise NOT | - |
| ** | Exponentiation | Right |
| x[index] | Subscription | Left |
| x[start:end] | Slicing | Left |
| x(arguments...) | Call | Left |
| x.attribute | Reference | Left |
| (expression...) | Binding or tuple display (unary) | - |
| [expressions...] | List display (unary) | - |
| {key:datum...} | Dictionary display (unary) | - |
NOTES
- Admiral provides optimized integer division algorithm. Based on the divident and divisor size it select one of the three different division strategies
- 16b / 16b -> DCPU hardware supported DIV operation
- n bit / 8 bit -> Optimized proprietary division algorithm that divides with DIV in 8 bit chunks
- n bit / n bit -> Standard long division is used
- Assignment is an expression, not statement
- yelds the assigned value
- e.g. "a = (b += 1)" is a valid command
- Assignment right side is alway evaluated before left side
- e.g. "for n in range(3): a += b += 1"
- round 1: a=1, b=1
- round 2: a=3, b=2
- round 3: a=6, b=3
- e.g. "for n in range(3): a += b += 1"
- Slicing is not supported as assignment left side
- e.g. "a[1:2] = 1,2" is NOT working!
- Boolean operators both sides are always evaluated
- e.g. "if true or (a+=1):" will increment a with every evaluation
- INDENT and DEDENT must be exactly one space
ADMIRAL MEMORY LAYOUT
Admiral reserves the whole DCPU memory for its use. Memory is divided into segments:
| Segment | Default size | Default location | Description |
|---|---|---|---|
| Stack | 4.096 | 0xf000 - 0xffff | Admiral call stack to store registers and arguments |
| Video Memory | 1.152 | 0xeb80 - 0xefff | Video memory for LEM |
| Floppy Buffer | 512 | 0xe980 - 0xeb7f | Memory buffer used by floppy operations, default memory area for machine language subroutine calls |
| Heap | 46.207 | 0x3500 - 0xe97f | Admiral heap for variables and objects |
| System | 13.568 | 0x0000 - 0x34ff | Admiral interpreter, data and subroutines |
The exact location and size of each segment depends on the Admiral build.
SOME EXTRA BITS
ASSIGNMENTS
>a = b = 0 >a += b += 1 1 >a += b += 1 3
Currently Admiral does not support assigning to slices: i.e. a[1:3]=(1,2,3) is not working. If that REALLY is a language feature that anyone would use, I will consider adding it :-)
UNKNOWN IDENTS IN FUNCTIONS
Currently Admiral does not produce error if unknown variable name is present in function body, but it is not evaluated. E.g.
>f=edit() 'print "Hello" foobar print "The End"
foobar would not yeld error, as it is not used for anything. However,
>f=edit() 'print "Hello" foobar+1 print "The End"
will yeld error, as unknown IDENT (foobar) cannot be evaluated for addition operator.
PYTHON FEATURES MISSING (INCOMPLETE LIST)
- 'def' function definitions
- 'class' class definitions
- 'lambda' functions
- generators
- list comprehension e.g. [x**2 for x in range(10)]
- '*args' and '*kwargs'
- % string operator
- 'yield'
- 'try' - 'except' exception handling
- lot of built-in functions