X#

X Sharp documentation

X# is a low-level programming developed for the processor architecture as a part of Cosmos to make operating system development easier. X# is designed to bring some C-like language syntax to assembly. At the beginning, X# was an aid for debugging services of Cosmos. The X# compiler is an open-source command-line interface program with an atypical architecture. It parses lines of code into tokens and compares them with patterns. Finally, matched X# code patterns are translated to Intel x86 assembly, usually for the NASM Netwide compiler. In first versions, X# operation was mostly 1:1 with assembly code, but hasn’t been the reason why the X# compiler was written.

Syntax

The syntax of X# is simple. Despite being similar to C, X# syntax differs and is stricter.

Comments

X# supports only one kind of comment, the C-style single line comment, started with a double forward slash – //.

Constants

X# supports the definition of named constants which are declared outside of functions. Defining a numeric constant is similar to C++ for instance,
const i = 0
Referencing the constant elsewhere requires a # before the name – "#i", for instance.

  • To define a string constant, single quotes ('') are used. To use a single quote in a string constant, it must be escaped by placing a backslash before it, as 'I\'m so happy'. X# strings are null terminated.
  • Hexadecimal constants are prefixed with a dollar sign ($), followed by the constant. ($B8000).
  • Decimal constants are not decorated but may not start with 0.
  • Binary and octal constants aren’t supported yet.

Labels

Labels in X# are mostly equivalent to labels in other assembly languages. The instruction to jump to a label uses the goto mnemonic, as opposed to the conventional jump or jmp mnemonic.

Namespaces

X# program files must begin with a namespace directive. X# lacks a namespace hierarchy, so any directive will change the current namespace until it’s changed again or the file ends. Variables or constants in different namespaces may have the same name as the namespace is prefixed to the member’s name on assembly output. Namespaces cannot reference each other except through “cheats” using native-assembly-level operations.

Functions

All X# executive code should be placed in functions defined by the ‘function’ keyword. Unlike C, X# does not support any formal parameter declaration in the header of the functions, so the conventional parentheses after the function name are omitted. Because line-fixed patterns are specified in syntax implemented in code parser, the opening curly bracket can’t be placed on the next line, unlike in many other C-style languages.

Because X# is a low-level language, there are no stack frames inserted, so by default, there should be the return EIP address on the top of the stack.
X# function calls do contain arguments enclosed in parentheses, unlike in function headers. Arguments passed to functions can be registers, addresses, or constants. These arguments are pushed onto the stack in reverse order. Note that the stack on x86 platforms cannot push or pop one-byte registers.

The return keyword returns execution to the return EIP address saved in the stack.

Arithmetic and bitwise operations

X# can work with three low-level data structures: the registers, the stack and the memory, on different ports. The registers are the base of all normal operations for X#. A register can be copied to another by writing DST = SRC as opposed to mov or load/store instructions. Registers can be incremented or decremented just as easily. Arithmetic operations (add, subtract, multiply, divide) are written as dest op src where src is a constant, variable, or register, and dest is both an operand and the location where the result is stored.

Examples of assignment and arithmetic operations are shown below.

Register shifting and rolling is similar to C.

Other bitwise operations are similar to arithmetic operations.

Stack

Stack manipulation in X# is performed using + and - prefixes, where + pushes a register, value, constant or all registers onto the stack and - pops a value to some register. All constants are pushed on stack as double words, unless stated otherwise (pushing single bytes is not supported).

Variables

Variables are defined within namespaces (as there are no stack frames, local variables aren’t supported) using the var keyword. Arrays can be defined by adding the array’s type and size on the end of the declaration. Variables and arrays are zeroed by default. To reference a variable’s value, it must be prefixed with a dot. Prefixing that with an @ will reference the variable’s address.

X# can access an address with a specified offset using square brackets:

Comparison

There are two ways of comparing values: pure comparison and if-comparison.
*Pure comparison leaves the result in FLAGS so it can be used in native assembly or using the if keyword without specifying comparison members.
*If comparison compares two members directly after an if keyword.
Here are two ways of writing a (slow) X# string length (strlen)function:

There are six available comparison operators: < > = <= >= !=. These operators can be used in both comparisons and loops. Note that there’s also a bitwise AND operator which tests bits: