-
Notifications
You must be signed in to change notification settings - Fork 9
Detailed Documentation
Reason for introducing: For calling external procedures of Win32 API and other languages.
Note: Their formal parameters are as follow:
PROCEDURE LoadLibraryW(VAR result: INTEGER; lpFileName: ARRAY OF CHAR);
PROCEDURE GetProcAddress(VAR result: INTEGER or any procedure type; hModule, lpProcName: INTEGER);Example usage:
PROCEDURE ImportProc;
VAR user32, i: INTEGER;
ansiStr: ARRAY 256 OF BYTE;
str: ARRAY 256 OF CHAR;
MessageBoxW: PROCEDURE(hWnd, lpText, lpCaption, uType: INTEGER);
BEGIN
SYSTEM.LoadLibraryW(user32, "USER32.DLL");
ASSERT(user32 # 0); str := "MessageBoxW"; i := 0;
WHILE str[i] # 0X DO ansiStr[i] := ORD(str[i]); INC(i) END; ansiStr[i] := 0;
SYSTEM.GetProcAddress(MessageBoxW, user32, SYSTEM.ADR(ansiStr));
MessageBoxW(0, SYSTEM.ADR("Text"), SYSTEM.ADR("Caption"), 0)
END ImportProc;Reason for introducing: It doesn't have an additional length descriptor and therefore, is compatible with C array parameter.
Note: Restricted, cannot do array assignment or string comparison on this kind of parameter.
Example:
MessageBoxW: PROCEDURE(hWnd: INTEGER; lpText, lpCaption: ARRAY [untagged] OF CHAR; uType: INTEGER);Here is the list of compiler pragma:
| Pragma | Meaning |
|---|---|
(*$MAIN*) |
Generate .EXE file instead of .DLL |
(*$CONSOLE*) |
Same as MAIN but for console applications |
(*$RTL-*) |
This module don't need Run Time Library (low level modules) |
All pragma should stay at the beginning of module for easy visibility.
The Run Time Library can be written in any language (not necessary Oberon). It must export two following procedures:
PROCEDURE New(VAR ptr: INTEGER; tdAdr: INTEGER); (* dynamic memory allocator *)
PROCEDURE Register(modAdr: INTEGER); (* Oberon modules will call this function during initialization *)
PROCEDURE Halt(exitCode: INTEGER);See module Rtl.mod for example implementation. Type desc structure is same as in Project Oberon, with each word be 64-bit, instead of 32-bit, and the max level of extension is 7, instead of 3.
Garbage Collector is as same as in Project Oberon 2013, without stack scanning. Instead of writing program as a single continuous thread of execution, now the program should be written as multiple phases process, with garbage collection possibly happen between each phase.
The Run Time Library won't do GC automatically, instead, the programmer must explicitly call Rtl.Collect procedure.
In the tradition of most Oberon compilers, the code outputted by this compiler is accompanied by runtime error checking guard. There is no way to remove runtime error checking, so if you want to bypass them, use SYSTEM module or external assembly module. In my opinion, running the code without runtime guard is similar to driving car without seatbelt.
Additionally, there is SYSTEM.INT3 statement (x86 INT3 interrupt) in order to hook in your favourite assembly code debugger. Sadly, there is no debugging information for external symbolic debugger.
The image below is an example of Oberon array index guard in action:

The source pos is the byte position in source code, if you are using Notepad++, you can quickly identify the offending error location by Ctrl+G and find by offset. Combines with write to console, that is how I develop the compiler without symbolic debugger (and thanks to the powerful ASSERT statement too). If you had used GPCP or BlackBox, then this feature would be familiar.
Another example of run-time guard, this time, is the ability to verify the interface of imported module:

Arithmetic overflow is not checked, as same as in Project Oberon 2013.
| Type | Size (in bytes) | Note |
|---|---|---|
| BOOLEAN | 1 | |
| CHAR | 2 | |
| INTEGER | 8 | |
| REAL | 8 | Windows x64 standard floating point type |
| BYTE | 1 | Same as in Project Oberon 2013, BYTE = SYSTEM.BYTE |
| SET | 8 | With 64 elements, SET is powerful now |
| SYSTEM.CARD32 | 4 | For interfacing with external modules |
| SYSTEM.CARD16 | 2 | For interfacing with external modules |