Tag Archives: oberon

I don’t write here most of the time. It is an effort to translate each time my Armenian blog entries. I hardly can maintain two (0 1 ) diaspora profiles.

Whatever, I like Peter Matthias’s Oberon/Linux Revival project.

Today I have added a patch to OLR’s XCompiler, which I before have added to voc.

If there is CASE statement sequence, and no ELSE, and neither of possibilities is true, then trap happens. This caused me a lot of headache to figure out why this or that code crashes. Thus I have added a warning to Vishap, in order to find such cases.

This is how crash happens under oberon system.

And this is how it works now.

und so weiter. (:

story about left shift

I was tinkering with Ofront, making changes here and there in order to run it on x86_64.
By doing this I met a strange warning issued by gcc when it was compiling Console.c file.

Console.c: In function ‘Console_Int’:
Console.c:57:2: warning: left shift count >= width of type [enabled by default]

So, Console.c is generated from Console.Mod. And the Int function of Console module writes integer to the console.
This is how it looks:

  PROCEDURE Int*(i, n: LONGINT);
    VAR s: ARRAY 32 OF CHAR; i1, k: LONGINT;
  BEGIN
    IF i = SYSTEM.LSH(LONG(LONG(1)), SIZE(LONGINT)*8 - 1) THEN
      IF SIZE(LONGINT) = 8 THEN s := "8085774586302733229"; k := 19
      ELSE s := "8463847412"; k := 10
      END
    ELSE
      i1 := ABS(i);
      s[0] := CHR(i1 MOD 10 + ORD("0")); i1 := i1 DIV 10; k := 1;
      WHILE i1 > 0 DO s[k] := CHR(i1 MOD 10 + ORD("0")); i1 := i1 DIV 10; INC(k) END
    END ;
    IF i < 0 THEN s[k] := "-"; INC(k) END ;
    WHILE n > k DO Char(" "); DEC(n) END ;
    WHILE k > 0 DO  DEC(k); Char(s[k]) END
  END Int;

The error is issued in the line:

    IF i = SYSTEM.LSH(LONG(LONG(1)), SIZE(LONGINT)*8 - 1) THEN

which is translated as following in case of x86_64:

if (i == __LSHL(1, 63, LONGINT)) {

On x86 it gets translated as:

if (i == __LSHL(1, 31, LONGINT)) {

Okay, and it does not issue an error on 32 bit platform, Why?

Probably, need to look into how the _LSHL macro is written. That’s in SYSTEM.h

#define __LSHL(x, n, t) ((t)((unsigned)(x)<<(n)))

Okay, what do we see. It casts the number as unsigned, then shifts it. Obviously, the cast is necessary in order to use the sign bit.

Now let's swerve to the question why do they to do this?
And what special in this "8085774586302733229" number? Or in this: "8463847412"? If you fed this number to the Worlfram alpha saas, it does not give a clue.
The clue gives the lower part of the script, it writes the number from right to left.

WHILE k > 0 DO  DEC(k); Char(s[k]) END

Let's reverse this number and look at it as binary.

noch@SAL9000 ~ $ echo 'obase=2; 2147483648' | bc
10000000000000000000000000000000

wow. This is it. We would get it by shifting 1 to the left.
But why do they shift it?
What is LONGINT on 32 bit platform? It is a number in range from -2^31 .. 2^31 -1.
And the number 2147483648 is 2^31.
So they do it in order to be able to print the number 2^31! Only for that!
Obviously, in case of x86_64 that's the number 9,223,372,036,854,775,808

Okay, let's tinker further. We want to be able to print it, why not?

So why C compiler (I use gcc) does not issue
the warning in case of 32 bits but issues in case of 64?

Because of the macro, probably. Let's write a simple C text to check.

#include "stdio.h"
#define __LSHL(x, n, t) ((t)((unsigned)(x)<<(n)))

int main()
{
   long i;
   printf("%lu\n",sizeof(long));

   i=__LSHL(1, sizeof(long)*8-1, long);

   printf ("%lu\n",i);
return 0;

}

Then,

$ gcc -o test0 test0.c
test0.c: In function ‘main’:
test0.c:9:4: warning: left shift count >= width of type [enabled by default]

The problem is in the cast. If we do (unsigned) then it casts it to unsigned int, not unsigned long.
Let's change the macro to

#define __LSHL(x, n, t) ((t)((unsigned t)(x)<<(n)))

Now it compiles without warnings and run.

$ gcc -o test0 test0.c
$ ./test0
8
9223372036854775808

However, compiler fails to compile it when we make the same change in SYSTEM.h

Console.c: In function ‘Console_Int’:
Console.c:56:11: error: expected ‘)’ before ‘LONGINT’

Why?
Let's emulate the case exactly. We need to add LONGINT typedef

#include "stdio.h"
typedef long LONGINT;
#define __LSHL(x, n, t) ((t)((unsigned t)(x)<<(n)))

int main()
{
   long i;
   printf("%lu\n",sizeof(LONGINT));

   i=__LSHL(1, sizeof(LONGINT)*8-1, LONGINT);

   printf ("%lu\n",i);
return 0;

}

It does not compile!

noch@SAL9000 /tmp $ gcc -o test1 test1.c
test1.c: In function ‘main’:
test1.c:10:6: error: expected ‘)’ before ‘LONGINT’

We clearly see that in the macro there are three arguments which _LSHL expects but for some strange reason gcc expects the closing parentheses after the second argument.
However we can compile it with g++ - it understands this typedef issue

noch@SAL9000 /tmp $ cp test1.c test1.cpp
noch@SAL9000 /tmp $ g++ -o test1 test1.cpp
noch@SAL9000 /tmp $ ./test1
8
9223372036854775808
noch@SAL9000 /tmp $

Okay. What can be done here?
We can do

typedef unsigned long ULONGINT;

and then change macro like this:

#define __LSHL(x, n, t) ((t)((ULONGINT)(x)<<(n)))

So the file looks like

#include "stdio.h"
typedef long LONGINT;
typedef unsigned long ULONGINT;
#define __LSHL(x, n, t) ((t)((ULONGINT)(x)<<(n)))
//#define __LSHL(x, n, t) ((t)((unsigned t)(x)<<(n)))

int main()
{
   long i;
   printf("%lu\n",sizeof(LONGINT));

   i=__LSHL(1, sizeof(LONGINT)*8-1, LONGINT);

   printf ("%lu\n",i);
return 0;

}

now, and it compiles

$ gcc -o test test.c
$ ./test
8
9223372036854775808

But this is not what we want.
The good solution would be to replace a macro with a function, which can be debugged, and which won't give such an error. But it is not possible to pass a type as an argument in plain C without a macro. It may be possible by using templates, in C++, but we use C.
May be there is a need to change Ofront in a way it would generate a different function call.
Another solution is to use define instead of typedef.

#include "stdio.h"
//typedef long LONGINT;
#define LONGINT long

//typedef unsigned long ULONGINT;
//#define __LSHL(x, n, t) ((t)((ULONGINT)(x)<<(n)))
#define __LSHL(x, n, t) ((t)((unsigned t)(x)<<(n)))

int main()
{
   long i;
   printf("%lu\n",sizeof(LONGINT));

   i=__LSHL(1, sizeof(LONGINT)*8-1, LONGINT);

   printf ("%lu\n",i);
return 0;

}

Test runs

$ gcc -o test test.c
$ ./test
8
9223372036854775808

For now the solution is to replace typedef with define in SYSTEM.h and use (unsigned t) cast in the macro.

und so weiter

story about pencil marks

I have eventually found this book, second hand, obviously.

I have learned about it first because Creenshaw in his compiler book advised it as one of the best compiler books ever.

POINTER TO syntax appeared first in Modula.
Apparently the former owner of the book tried to translate the text from Pascal to Modula, or may be to Oberon.


There is no BEGIN in WHILE loops since Modula.
Modula and Oberon also don’t have the FUNCTION keyword, they have only PROCEDUREs (:

und so weiter

quote about debugging

from Wirth’s interview

well, of course, if the world was ideal I would gladly recommend learn the basic concepts properly and then do programming with Oberon. But I’m fully aware that the world is not that simple. Programmers nowadays are faced with very difficult task and they cannot afford to build system from scratch. They have to use many tools that exist already and interface their new programs with them, and that’s where the problem is. This interface is not even properly and fully specified. Any many work comes with that. It is quite well known that if 5% percent going to programming is much, the rest is going to debugging. And that’s precular, it’s not science, not even engineering, it’s just trying.

und so weiter

story about linking Pascal and Oberon.

I prefer to write programs in Oberon when it does not require too many extra efforts. It requires too many extra efforts simply because it is not widely used, and this often leads to the community is fragmented and small. This explains why we don’t have the huge code base of Oberon sources, and the regular Oberon developer always has challenges, regular Python programmer does not have. Oberon developer needs to change existing libraries in order to compile them with different compilers, or may be prepare wrappers in order to compile those libraries. It is often necessary to prepare bindings to C code, or just translate some code by hand, just because no one before have dote it.

I don’t have yet good skills in programming graphical interfaces in Oberon, however you can find an example of GTK program at my github page.

I was using Lazarus/FreePascal to develop graphical applications, and it has one clear and important advantage for me – interface does not depend on the backend widget suite. For instance, I have recompiled the same program so that it would draw itself by using Qt, or GTK, or even native WinAPI on Windows.

That lead me to the idea to combine some Pascal and Oberon code together, and to call Oberon code handlers from the LCL application. Oberon compiler I used, ooc, has a C backend, so the stary begins.

Let’s write a minimal module with one exported function in Oberon:

MODULE m; PROCEDURE add*(a, b : INTEGER): INTEGER; BEGIN RETURN a + b; END add; END m.

We even can compile it now with oo2c

$ oo2c m.Mod

and get directories obj and sym.
We may now compile obj/m.c
and get an object m.o

gcc -Iobj -I/local/oo2c/lib/oo2c/src -I/local/oo2c/lib/oo2c/obj -c obj/m.c

Now we need a pascal wrapper to bind it.

Let’s call it mbind.pas

unit mbind; {$link m.o} (*oo2c objs to link*) {$link RT0.o} {$link Object.o} {$link Exception.o} {$link HashCode.o} {$linklib c} interface uses CTypes; function m__add(a, b : ctypes.cint16) : ctypes.cint16; cdecl; external; (* /local/oo2c/lib/oo2c/obj/C.oh typedef OOC_INT16 C__shortint; *) implementation end.

We need to tell compiler explicitly which object files to link.
m.o is the object file we get by compiling obj/m.c
Other files are the minimal oo2c rtl which needs to be linked.
We also need to link to libc, because oo2c works by compiling via C.
Function name is m__add because oo2c translates m.add to C as m__add
Note, that implementation section is empty, and fpc does not issue an error because the function marked as external.

Eventually, let’s write a main module to call the Oberon function.

program m0; uses mbind; var i : integer; begin i := m__add(20, 3); writeln (i); end.

Neither fpc nor oo2c do not need a make file.
FreePascal compiler, as well as Oberon can itself resolve module dependencies.
For example, I do not need to write a makefile where I compile first mbind.pas and get mbind.o and link it during the next step.

However, in this case I’d like to write a make file.

IPATH = -Iobj -I/local/oo2c/lib/oo2c/src -I/local/oo2c/lib/oo2c/obj LPATH = /local/oo2c/lib/oo2c/obj GCC = /usr/bin/gcc OO2C = /local/oo2c/bin/oo2c FPC = /local/fpc/bin/fpc all: $(OO2C) m.Mod $(GCC) $(IPATH) -c obj/m.c $(FPC) -Fo$(LPATH) -Fo. m0.pas clean: rm *.o rm *.ppu

I usually use custom fpc I compiled from subversion, and I prefer to keep my software in /local
LPATH is the path where oo2c main rtl objects are located, so fpc can find and link RT0.o, Exceptions.o, Object.o and HashCode.o.

So, first oo2c compiles the m module to c.
Then gcc compiles it to object file.
Then fpc compiles the main module.

And now enjoy:

$ ./m0 23

und so weiter