The O language use constants, variables, pointers that are octal/decimal/hexadecimal numbers.
Elf object/executable files for Linux-based systems and Exe files for Windows and can be created. And C files with otoc.
Object files that have elf relocatable format can be created.
The language commands are case INsensitive.
At the beginning data can be declared with diverse methods.
The language has basic, arithmetic, bitwise operations.
The pointer mechanism is used to handle the variables more easily.
Functions can be declared and called.
External libraries can be imported.
Code conditions are if-elseif-else.
Files can be included to form complex programs.
There are 2 scopes: the global scope and the function scope.
The commands are from i386 with extension for x86-64 (but with the HEX macro anything can be wrote to code section).
4 bytes variables are sign extended to 8 by default(must add unsigned notation to zero extend). 1 byte variables are zero extended to 4/8 bytes when needed(otherwise must add signed notation).
o[.exe] filename [options]
#key value options. more at configuration file.
The language has 7 names for data declaration (1 for constants and 6 for variables).
1. Constants
Language command: Const ConstIf
Is a 32 bit value. It's content is declared into the memory(variables are declared into the file) therefore it is used at header files.
Constants have a separate declaration scope.
Constants(like ordinary integers) can be used at operations, but to avoid same names these are introduced with parenthesis (); without parenthesis only one integer can be used
ConstIf will define the constant only if is not defined.
Example:
Const TRUE=1
if 20=(ConstantValue+11)
set x 20
endif
Const x=3$2
#is 3 pow 2 = 9
2. Data
Language command: Data
Is a 32 bit value. It is used for operations, pointer operations.
Example:
Data variable=100
3. Strings
Language command: Str
Is a 32 bit value. It is used for pointer operations.
Example:
#for compatibility, on 64 reloc_64 pref is 1, if was 0 must use vstr mostly
Char chardata="Text"
Str string^chardata
Str text="Text data"
4. Characters
Language command: Char
Is a 8 bit value. It is used for operations.
Example:
Char value={1}
Char value=1
Char value="Add text here"
5 - 7. Stack variables
Language command: SD = Stack Data
Language command: SS = Stack String
Language command: SV = Stack Value
At 64bit code all stack variables are 8 bytes. 4 bytes at 32.
Stack Value differentiates at 64bit code. It will point at 8 bytes ('sv#').
At 32bit code sd and sv are the same.
Sd is pointing at 4 and ss at 1.
These variables are located on the stack. The methods for declaring SD/SS/SV are the same as for Data/String.
Stack variables can be declared without a sign. The implicit method in this case is '#1' (reserve one unit).
Example:
Char chardata="Text"
function recursive(sd stackdata)
endfunction
ss string="Text"
sd reserve
sd another_reserve#1
8 - 10. Value variables
Language command: VDATA
Language command: VSTR
Language command: VALUE
They will declare 8 bytes for a unit on 64 bit format file.
The pointer is like for stack variables; vdata 4, vstr 1, value 4/8.
11 - 16. Virtual variables
Language command: DATAX
Language command: STRX
Language command: CHARX
Language command: VDATAX
Language command: VSTRX
Language command: VALUEX
These will be in a nobits section at object. Set nobits_virtual preference to 0 for old behavior:
these will be physically placed after the counterparts and the starting offset will be logged
so ostrip can remove them after ld linked the objects.
For otoc, adding U at the end, excepting constants, will make them unsigned in C, and excepting chars where adding S will make them signed.
Data can be declared using the following methods:
1. Equal sign ('=')
First method.
Example:
Const fruits=20
Data value=-70
Char text="The quick brown fox jumps over the laxy dog."
vStr stringASM=0x401000
Second method is with '{}' signs.
Example:
Data values={1,3,900}
Char bytes={1,4,100}
vStr pointers={0x401010,0x401020}
2. Reservation sign ('#')
Example:
Data reserveDATA#10
#the data section will have 40 bytes reserved
Char reserveCHAR#10
#the data section will have 10 bytes reserved
vStr reservePointers#10
#the data section will have 40 bytes reserved
3. Pointer sign ('^')
Right side can have variables and at object format, when left side is not constant, can have functions.
Variables (value and sv) that point to a function can be called like a function. At the executables format (ex: not elfobj), when pointing to an import function the supported manner is with double pointer(^^); all cases, except this one, use the normal pointer(^).
Example:
Data value=1
Data pointervalue^value
Char bytes="Raw text data declaration."
vStr text^bytes
4. Relocation sign ('%')
Used at the object format. It acts like equal sign and then the offset is added to the REL section.
At executables it translated to '='. At Str and quotations declaration the equal sign adds at object to Rel and this sign cannot be used here. At Char the sign cannot be used.
Add another '%' sign to point to .dtnb section instead of .data if applicable.
Example:
Format ElfObj
Data global=100
Const ptrglobal^global
Function test()
Data local=200
Data reference%ptrglobal
Add local reference#
#200+100
Return local
EndFunction
Entry main()
Data item#1
SetCall item test()
Data addmore=300
Data apointer^addmore
Add item apointer#
#300+300
Return item
Operations can be performed at declarations with arithmetic (+,-,*,/,//,%,%%,$), bitwise (&,|,^,~,<<,>>,>>>) and logical (=,!=,<,>,<=,>=,&&,||,<^,>^,<=^,>=^,!,!!) signs. - and ~ can prefix a number/constant.
Example:
| const a=1 | ||||||||||||||||||||||||||||||
| # | add | sub | mul | div | divu | rem | remu | pow | and | or | xor | not | shl1 | sar1 | shr1 | equal | inequal | less | greater | lessEqual | greaterEqual | logicalAnd | logicalOr | unsignedLess | unsignedGreater | unsignedLessEqual | unsignedGreaterEqual | parity | odd | neg |
| char *examples={ | 3+2, | 6-4, | 5*5, | 32/10, | -1//0x10000000, | 32%10, | -1%%0x10, | 3$2, | 7&2, | 5|2, | 7^2, | ~0, | 2<<2, | 8>>3, | -1>>>25, | 7=7, | 7!=7, | 2<3, | 2>3, | 9<=9, | 9>=9, | 1&&0, | 0||1, | 1<^0xffFFffFF, | 1>^0xffFFffFF, | -1<=^-2, | -1>=^0, | 4!1, | 2!!1, | -a} |
| #hex: | 5 | 2 | 19 | 3 | f | 2 | f | 9 | 2 | 7 | 5 | ff | 8 | 1 | 7f | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 1 | ff |
If a variable is not used at code operations a warning will be displayed for that variable name.
To create unreferenced values use the * sign.
Example:
Data struct=3
Data *structValue=1000
vData structures^struct
#the "structures" variable can be used in the program as a pointer
Entry event(data *widget,data signal)
return signal
#only the signal value is checked for unreferences
To disable the unreferenced warning or to set options at symbols see 'ocompiler.conf' file.
The data declarations can be made in the global scope or in the function scope.
All the constants are in the global scope.
When a function is declared all the variables declared in the function can not be used outside that function because they are in the function scope.
The "\" character represents the data section cursor and can be used in place of a number. "\\" represents the nobits data section cursor if applicable.
"\function" will retrieve the data section size of that entry and "\\function" the virtual size. "\function\" will retrieve both.
"\scope.variable" will get the size of the entity.
"\scope.variable\" is the offset of the variable in the scope.
The ":" character represents the size of a long and can be used in the place of a number. Returns 4B on 32-bits, 8B on 64-bits.
"?" and a string is the value of the preference (example: ?x_file is x_file preference value).
The AfterCall set a value to be tested with zero at the every call and to return if it is not zero.
AfterCallImport is used in objects to import an extern defined AfterCall.
AfterCallEnable/AfterCallDisable automation commands (name is not used; if not imported, aftercall can be defined with unrefsign(*)).
& sign will create throwless variables.
function pre_test()
return 3
endfunction
aftercall interrupt
function test()
return 3
endfunction
entry main()
set interrupt 1
call pre_test()
#it is still going on
value &throwless^test
call throwless()
#it is still going on
call test()
#here is the end, the program last return was 3
return 5
1. Return
Language command: Return Ret Exit
The return command is used to terminate the program or a function.
The asm value termination is ret (0xc3). To return int 0x80(0xcd,0x80;linux sys_exit;eax=1,ebx=return value) use Exit.
To return without a value use Ret.
To return like Exit at main scope but using returns set exit_end preference to 1.
Example:
Data true=1
Return true
#the program exit code will be 1
2. Set
Language command: Set
The set command is used to set one value to another.
Example:
Data valueA=20
Data valueB=30
Set valueA valueB
#the valueA will be 30
sd string
set string "text test"
#string will point to "text test"
3. Base/Leave
Language command: Base Leave
Base is setting the Base Pointer and Leave is restoring the base pointer and is leaving.
Example:
format elfobj64
value z#1
function a()
leave main.z
end
entry main()
hex 144
base z
call a()
i3
1. Addition
Language command: Add
Example:
Data valueA=20
Data valueB=30
Add valueA valueB
#the valueA will be 50
2. Subtraction
Language command: Sub
Example:
Data valueA=20
Data valueB=30
Sub valueA valueB
#the valueA will be -10
3. Multiplication
Language command: Mult MultS
Example:
Data valueA=20
Data valueB=30
Mult valueA valueB
#the valueA will be 600
#imul at mults
4. Division
Language command: Div Rem DivU RemU
Example:
Data valueA=465
Data valueB=20
Div valueA valueB
#the valueA will be 23
Rem valueA valueB
#the valueA will be 3
#unsigned division (divu) and unsigned reminder (remu) is similar with constant operations presented at declaring data
5. Incrementation
Language command: Inc IncSt
The incrementation command adds one to the value.
Example:
Data value=30
Inc value
#the value will be 31
IncSt adds 4 bytes to the argument or 8 bytes when building for 64-bit application.
Example:
sd x#2;sd z^x
set z# 1;incst z;set z# 2
add z# x
#at z# will be 3
6. Decrementation
Language command: Dec DecSt
The decrementation command subtracts one from the value.
Example:
Data value=30
Dec value
#the value will be 29
DecSt subtracts 4 bytes from the argument or 8 bytes when building for 64-bit application.
7. Negation
Language command: Neg
Subtract the operand from 0.
Example:
Data value=30
Neg value
#the value will be -30
1. And
Example:
Data valueA=0x0101
Data valueB=0x0001
And valueA valueB
#the valueA will be 0x0001
2. Or
Example:
Data valueA=0x0101
Data valueB=0x0011
Or valueA valueB
#the valueA will be 0x0111
3. Xor
Example:
Data valueA=0x0101
Data valueB=0x0011
Xor valueA valueB
#the valueA will be 0x0110
4. Not
Example:
Data valueA=0x0f0F0f0F
Not valueA
#the valueA will be 0xF0f0F0f0
5. ShL1
Example:
sd shift_left_once=2
shl1 shift_left_once
#the value will be 4
6. ShR1 SaR1
Example:
sd shift_right_once=0x10
SHR1 shift_right_once
#the value will be 8
sd shift_right_signed_once=-2
SaR1 shift_right_signed_once
#the value will be -1
Pointers can be used for manipulating the data. The pointer sign at code operations is '#'.
Data valueA=1
Char data="ABC"
Inc string
function test()
Example:
Data valueB=2
Data pointerA^valueA
Data pointerB^valueB
Add pointerA# pointerB#
#the valueA will be 3
vStr string^data
Char c1#1
Set c1 string#
#the c1 will be A
Set c2 string#
#the c2 will be B
data bits_per_sample=16
return #bits_per_sample
endfunction
#the function call will return the pointer, and the variable can be modified
sd a
setcall a test()
set a# 8
| format elfobj64 | |
| sd a | |
| ss b | |
| hex 144;set a a#s^ | #cast data to string |
| Hex 144;set a a#v^ | #cast data to value |
| hEx 144;set b b#D^ | #cast string to data |
| heX 144;inc b#V^ | #and a one arg cast |
Function can be declared and called later in the program. Functions must be closed with EndFunction(or End) command.
To call a function use the Call command. To call a function and store the return value into a variable use the SetCall comand.
The functions must be declared before the main scope.
For example, at the first operation within the main scope (ex. basic Set command, or arithmetic Add command) the Entry Point is placed there and the Function statement it is no longer available.
The Entry command acts like a Function command but with some differences: 1. the scope is not changed to a local scope; 2. the function is not added to the unreferences list; 3. the endfunction command is not used at this function.
EntryRaw is an Entry command which is acting like it does not have a value for Ret at the top of the stack and without a calling convention.
FunctionX is described at objects. FunctionXV and EntryV will handle the input arguments as if they don't know how many there are (varargs). Varargs are also at other function definitions for otoc.
All functions can be used in combinations like AddCall, OrCall, XorCall, etc (set a b() is same as setcall a b()).
CallEx is for prepared calls. This is a 3 argument operation. The first argument is the function name, the second argument is the arguments pointer and the third argument is the number of arguments. The arguments are passed forward respecting the size of the integer(4 bytes on 32-bits app, 8 on 64). One usage can be when there is a call with a number of arguments detected at run-time and want to pass them all to another call.
CallX, ...XCall, CallExX will call like a FunctionX/ImportX.
Call[X]G, ...[X]G, CallEx[X]G will skip aftercall.
Call[Ex][X]Ret can return from a function. Note that "G" is useless when "RET" is coming.
The functions can be imported from an extern library and used like in the previous chapter. To declare a library use the Library and to import a function use the Import command and provide the program function name.
The language has if-elseif-else conditions that must by closed with endif-endelseif-endelse(or end) commands.
The condition operators are:
Equal: =
Not Equal: !=
Less: <
Greater: >
Less or Equal: <=
Greater or Equal:>=
Unsigned Less: <^
Unsigned Greater: >^
Unsigned Less or Equal: <=^
Unsigned Greater or Equal:>=^
Parity: !
Not Parity: !!
Can point at compile time structures or at runtime structures with ':' sign.
format elf
entry main()
sd a
sd b=3
sd c^a
sd d
set d c#:b
add d a:b
exit d ##3+3
The program can be formed with multiple files using the Include command.
If wanting to switch between two files (one use can be at multiple OSes) add a second path at the command:
the preference include_sec 0 will take the first path, 1 will take the second path.
EInclude will turn unreferenced warning off (one use can be when including a header between multiple projects).
Example:
Include "files\\headers.oh"
Include "files\\headers_win.oh" "files\\headers_lin.oh"
eInclude "/usr/include/ocompiler/logs.oh"
Exe files for windows will be created by default. Executable and Linking Format (ELF) files can be created for Unix - System V, operable on linux platforms. format elf will override the default format exe.
Append SO at format to inform the log parser (ounused) to skip input/output functions and constants.
This is a debugging option.
Example: Format elfobj64so
Black = 1 byte. Blue = 4 bytes = data. Red = string = data[+byte(s)]. Green = replacement.
There are at least two options at the '*' wildcard from there. '{}' is an enumeration.
First long(4 bytes) is null or offset of entry which will be at the end.
Xfile_noignore at ocompiler is '^' sign before the command, and at otoc will noignore a tagIgnore argument. Xfile_yesignore at compiler is '!' sign before the command and at otoc will ignore the command. Xfile_variadic at ocompiler is '%' sign at start, followed by '<argument' for va_start at otoc, '&variable' for va_copy, '|variable' for va_arg, '>' for va_end. va_copy will also replace 'the_va_list' with variable until va_end.
Another option specific to otoc is Xfile_c_volatile, to use stack variables at o for recursion but not pointers at c (example: sdu ?attr). And Xfile_c_variadic to work with va_list arguments.
| Xfile_proto | Xfile_function_t_* | name | nr_of_args | {DA} | Xfile_proto_* |
| Xfile_import | Xfile_import_* | S | intern | Xfile_function_va_* | nr_of_args |
| Xfile_comment* | comment |
| Xfile_format | Xfile_format_* |
| Xfile_include | Xfile_include_normal Xfile_include_extern | S | Xfile_include_alternative_no | |
| Xfile_include_alternative_yes | S | |||
| Xfile_functiondef | Xfile_function_t* | Xfile_function_va_* | name | Xfile_function_t_* | nr_of_args | {D} |
| Xfile_function_e* |
| Xfile_declare | D | Xfile_declsign_pointer | Xfile_declsign_pointer_* | var/fn |
| Xfile_declsign_reserve | N | |||
| Xfile_declsign_e* | Xfile_declmode_value | N | ||
| Xfile_declmode_group | nr_of_args | {N} | ||
| Xfile_declmode_string | S | Xfile_declmode_string_pop_* |
| Xfile_action | Xfile_action_a* | A |
| Xfile_action_t* | VF |
| Xfile_action2 | VF | Xfile_action2_* | A |
| Xfile_call | Xfile_call_* | CL | |
| Xfile_callex | C | VF | A |
| Xfile_if | CD | |||||||||
| Xfile_elseif | CD | |||||||||
| Xfile_else | ||||||||||
| Xfile_while | CD | |||||||||
| Xfile_whiletrue | ||||||||||
| Xfile_break | ||||||||||
| Xfile_continue | ||||||||||
| Xfile_end | Xfile_end_* |
| Xfile_ret |
| Xfile_library | S |
| Xfile_import_name | name |
| Xfile_aftercall | Xfile_aftercall_declare | Xfile_declfeature_normal Xfile_declfeature_unref | var |
| Xfile_aftercall_import | var | ||
| Xfile_aftercall_enable | |||
| Xfile_aftercall_disable |
| Xfile_hex | nr_of_args | {N} |
| Xfile_override | name | N |
| Xfile_orphan | Xfile_orphan_* |
| Xfile_interrupt |
| Xfile_line |
| Xfile_iend |
| Xfile_variadic | Xfile_variadic_begin | var |
| Xfile_variadic_copy | ||
| Xfile_variadic_get | ||
| Xfile_variadic_end |
| Xfile_noignore |
| Xfile_yesignore |
| Xfile_arg_number | N |
| Xfile_arg_string | S |
| Xfile_arg_varfn | VF |
| Xfile_arg_call | CL |
| Xfile_arg_call_* | var/fn |
| C | nr_of_args | {A} |
| A | Xfile_cond_* | A |
| Xfile_declfield_const | Xfile_declfield_const_* | name |
| DA | Xfile_declfeature_* |
| Xfile_declfield_stack | Xfile_declext_* | Xfile_decltype_* | Xfile_c_* | |
| Xfile_declfield_data | Xfile_declfield_data_* | |||
| Xfile_declfield_varargs | ||||
| func | V |
| [Xfile_numbers_parenthesis_open] | Xfile_numbers_prefix_* | Xfile_numbers_type_i* | [Xfile_numbers_parenthesis_close] | [Xfile_numbers_operation_*] | {...} | Xfile_numbers_done | |
| Xfile_numbers_type_t* | text | ||||||
| Xfile_numbers_type_f* | func | ||||||
| Xfile_numbers_type_v* | DT | ||||||
| Xfile_string_multiline_* | string |
| var/fn | Xfile_suffix_false |
| Xfile_suffix_true | Xfile_suffix_cast_* |
| Xfile_suffix_notasuffix |
| Xfile_arg_varfn_prefix_* | Xfile_arg_varfn_colon_no |
| ||||||||
| Xfile_arg_varfn_colon_yes | Xfile_arg_varfn_dot_no | var | Xfile_suffix_* | |||||||
| Xfile_arg_varfn_dot_yes | func | |||||||||
Other commands that comes with the language.
1. Comments
To comment the code use the sign # before any text.
Multiline comments are using #! ... ! syntax.
format elf
sd a=2; #! 1111
2222
3333
! ; inc a
exit a ##will be 3
2. Interrupts
To place software breakpoints use the I3 command.
3. Hex
Write bytes in the code section.
4. Orphan
Turn on or off the orphan warnings.
5. Override
Override preference. Note that preference order is default < preference_file < command_line_argument < override.
When the option function_name from the ocompiler.conf file is set to Yes(1), the name is wrote in the code section above the function, for debugging asm code.
The preferences file can be placed in HOME folder on linux.
Lines are ended with new line(0xa),carriage return and new line(0xd,0xa) or semicolon(0x3B).
The command line options are detailed at some point on the linux console std. On windows there some dialogs instead of console std.
has_debug option will add a .debug section at objects that acts like the log file for files hierarchy and another log, log_line, A,B format, where A is the line number and B is the code section offset where it starts.
To see the content, for example, run
objcopy -O binary --only-section=.debug --set-section-flags .debug=alloc file.o file.txt