Discussion:
Compiler issues from an Oberon learner/newbie
(too old to reply)
Xcriber51
2007-03-20 23:20:00 UTC
Permalink
Hi

I need a bit of advice on using Oberon for programming (on Windows XP).

After spotting Wirth's book on compilers, I've taken an interest in it.
Then I spotted the OS, and I downloaded and installed it. I've started
exploring it the last few days. But you see, I first want to explore
Oberon the programming language, and then study Wirth's compiler book.

Unfortunately - it seems -, as regards compilation, unless one is in the
OS environment, one is not able to utilize the Oberon compiler - at least
not on XP.

I found a third party's compiler: XDS by Excelsior. The trouble is, that
tool, being "free," leaves a few things to be desired. Its own environment
is not very enticing, and, worst, none of the "standard" libraries/modules
Wirth refers to are there. They have their own libraries, which makes it
programming certain things (especially IO interaction) pretty awkward.

Now, is there a way I can use the native Oberon OS compiler and its
libraries in XP without having to work in the OS?

--

Another question, which is a bit more language-specific. I'd like to be
able to write small programs -- while exploring Oberon -- that don't cost
an arm and a leg to interact with. For instance, take this example from
Wirth's "Programming in Oberon:"

PROCEDURE Gcd*;
VAR x, y: INTEGER; S: Texts.Scanner;
BEGIN
Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos);
Texts.Scan(S); x := S.i; Texts.WriteString(W, " x =");
Texts.WriteInt(W, x, 6);
Texts.Scan(S); y := S.i; Texts.WriteString(W, " y =");
Texts.WriteInt(W, y, 6);
WHILE x # y DO...
etc.

Now, my problem is this style of IO interaction is tortuous. Being used to
languages like C or LISP (e.g. as I'm sure you know, C's "agv[arg-#]"
facility makes life so easy), I find myself looking for a simple way of
passing command-line arguments to the compiler executable without all this
thrashing about with

Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos);

-or-

Texts.Scan(S); x := S.i; Texts.WriteString(W, " x =");
Texts.WriteInt(W, x, 6);

etc. Is there a way of doing this - i.e. any standard libraries for that?
Another reason for this is, I'd like to write multiple test/sample
functions in the same module, and then be able to call them by just using
(i.e. parsing)command line options.

(I learned in great joy, for instance, that the Oberon OS allows you to
access the exported functions in module directly, so theoretically you
should be able to call, say, "Math.Sqrt" directly from the command line,
but my trials only resulted in error. Is there a way to achieve this
quickly?)

Thanks in advance.


-- Ken
Stewart Greenhill
2007-03-21 00:21:28 UTC
Permalink
Hi Ken,

[...]
Post by Xcriber51
I found a third party's compiler: XDS by Excelsior. The trouble is, that
tool, being "free," leaves a few things to be desired. Its own environment
is not very enticing, and, worst, none of the "standard" libraries/modules
Wirth refers to are there. They have their own libraries, which makes it
programming certain things (especially IO interaction) pretty awkward.
Another option is OOC:
http://ooc.sf.net
The libraries are not standard Oberon libraries and follow more of a
unix-centric model like XDS. Its fine for text processing, but there are
also numerous libraries for doing XML, GUI, database, and network
programming. Its also possible to use native API like OpenGL, Win32,
ffmpeg, libsdl, etc.
Post by Xcriber51
Now, is there a way I can use the native Oberon OS compiler and its
libraries in XP without having to work in the OS?
A great alternative for Windows is Blackbox Component Builder:
http://www.oberon.ch/blackbox.html
This commercial product was produced by a spin-off company from the
original Oberon group at ETH. It is a little different in some areas,
but follows the same philosophy and is well documented. The current
version also comes with complete source code. It uses the same basic
Texts model, but adds a HMVC (hierarchical model-view-controller) model
that allows views to be nested in models, etc. You can use this to build
nifty GUI dialogs by embedding *native* GUI controls inside text
documents. With the built-in meta-programming facilities, these controls
can be attached directly to variables and procedures in your modules.
This makes it very easy to rapidly prototype simple GUI apps.
Post by Xcriber51
Another question, which is a bit more language-specific. I'd like to be
able to write small programs -- while exploring Oberon -- that don't cost
an arm and a leg to interact with. For instance, take this example from
Wirth's "Programming in Oberon:"
PROCEDURE Gcd*;
VAR x, y: INTEGER; S: Texts.Scanner;
BEGIN
Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos);
Texts.Scan(S); x := S.i; Texts.WriteString(W, " x =");
Texts.WriteInt(W, x, 6);
Texts.Scan(S); y := S.i; Texts.WriteString(W, " y =");
Texts.WriteInt(W, y, 6);
WHILE x # y DO...
etc.
Now, my problem is this style of IO interaction is tortuous. Being used to
languages like C or LISP (e.g. as I'm sure you know, C's "agv[arg-#]"
facility makes life so easy), I find myself looking for a simple way of
passing command-line arguments to the compiler executable without all this
thrashing about with
Texts.OpenScanner(S, Oberon.Par.text, Oberon.Par.pos);
-or-
Texts.Scan(S); x := S.i; Texts.WriteString(W, " x =");
Texts.WriteInt(W, x, 6);
etc. Is there a way of doing this - i.e. any standard libraries for that?
Another reason for this is, I'd like to write multiple test/sample
functions in the same module, and then be able to call them by just using
(i.e. parsing)command line options.
OOC has a rider-style interface to texts, but texts can include files,
I/O streams (eg. standard input) as well as command-line arguments. The
variable ProgramArgs.args is a text stream which can be read just like a
file. So for example, you can do something like this:

VAR
r : TextRider.Reader;
x, y : INTEGER
...
r := TextRider.ConnectReader(ProgramArgs.args);

r.ReadInt(x); r.ReadLn;
r.ReadInt(y); r.ReadLn;
Out.WriteString("x + y = ");
Out.WriteInt(x + y, 0, 0);
Out.Ln;

Alternatively, you can access the arguments directly via RT0.argc and
RT0.argv, though at some stage you still have to parse the arguments so
you'd probably end up with something like the above code anyway.
Post by Xcriber51
(I learned in great joy, for instance, that the Oberon OS allows you to
access the exported functions in module directly, so theoretically you
should be able to call, say, "Math.Sqrt" directly from the command line,
but my trials only resulted in error. Is there a way to achieve this
quickly?)
Not sure about the Oberon system, but grab Blackbox and read Chapter 8
(Forms). You can write procedures that work on module variables. Then
you can bind form elements *directly* to these variables and procedures.
In your example, you might have three variables "x", "y" and "result"
and a procedure ComputeGCD which computes "result := GCD(x, y)". You
bind x, y and result to text fields, and ComputeGCD to a command button
and you're done. For simple programs this is probably the "purest"
interaction model since you don't have to code I/O at all - your
procedures just operate on module variables. You still have to build the
forms, although Blackbox can auto-generate forms from module variables.

Also, checkout Blackbox StdInterpreter module, and the procedure
Dialog.Call. This allows procedures with particular forms of parameter
lists to be interpreted directly from string commands. So, for example
you can do:
Dialog.Call("MyModule.MyFunc(123,234)", "", res)
Its up to you how you derive the command string - it could be read from
a text, or bound to a dialog control, etc.

Hope this helps.

Cheers,
Stewart
August Karlstrom
2007-03-22 20:10:15 UTC
Permalink
Some minor corrections.

Stewart Greenhill skrev:
[...]
Post by Stewart Greenhill
VAR
r : TextRider.Reader;
x, y : INTEGER
x, y: INTEGER;
Post by Stewart Greenhill
...
r := TextRider.ConnectReader(ProgramArgs.args);
r.ReadInt(x); r.ReadLn;
r.ReadInt(y); r.ReadLn;
Out.WriteString("x + y = ");
Out.String("x + y = ");
Post by Stewart Greenhill
Out.WriteInt(x + y, 0, 0);
Out.Int(x + y, 0);
Post by Stewart Greenhill
Out.Ln;
[...]


August
August Karlstrom
2007-03-22 23:01:12 UTC
Permalink
Stewart Greenhill skrev:
[...]
Post by Stewart Greenhill
VAR
r : TextRider.Reader;
x, y : INTEGER
...
r := TextRider.ConnectReader(ProgramArgs.args);
r.ReadInt(x); r.ReadLn;
r.ReadInt(y); r.ReadLn;
Out.WriteString("x + y = ");
Out.WriteInt(x + y, 0, 0);
Out.Ln;
Tried an example based on the above fragment but I can't get it to work.

$ cat src/Test.Mod
MODULE Test;

IMPORT Out, ProgramArgs, TextRider;

PROCEDURE Run;
VAR r: TextRider.Reader;
x, y: INTEGER;
BEGIN
r := TextRider.ConnectReader(ProgramArgs.args);
r.ReadInt(x); r.ReadLn;
r.ReadInt(y); r.ReadLn;
Out.String("x + y = ");
Out.Int(x + y, 0);
Out.Ln;
END Run;

BEGIN
Run
END Test.

$ bin/Test 1 1
x + y = -13063

Any clues?


August
Taylor Hutt
2007-03-23 04:25:30 UTC
Permalink
Post by August Karlstrom
[...]
Post by Stewart Greenhill
VAR
r : TextRider.Reader;
x, y : INTEGER
...
r := TextRider.ConnectReader(ProgramArgs.args);
r.ReadInt(x); r.ReadLn;
r.ReadInt(y); r.ReadLn;
Out.WriteString("x + y = ");
Out.WriteInt(x + y, 0, 0);
Out.Ln;
Tried an example based on the above fragment but I can't get it to work.
$ cat src/Test.Mod
MODULE Test;
IMPORT Out, ProgramArgs, TextRider;
PROCEDURE Run;
VAR r: TextRider.Reader;
x, y: INTEGER;
BEGIN
r := TextRider.ConnectReader(ProgramArgs.args);
r.ReadInt(x); r.ReadLn;
r.ReadInt(y); r.ReadLn;
Out.String("x + y = ");
Out.Int(x + y, 0);
Out.Ln;
END Run;
BEGIN
Run
END Test.
$ bin/Test 1 1
x + y = -13063
Any clues?
Historically, ReadInt() was for reading binary values from files.

thutt
Lurking, always lurking.
Stewart Greenhill
2007-03-26 15:58:37 UTC
Permalink
Hi Taylor,
Post by Taylor Hutt
Historically, ReadInt() was for reading binary values from files.
OOC tries to provide a consistent interface for reading from both binary
and text files. Obviously the two are not identical, so some features
are available in one and not the other. For example, ReadLn only makes
sense on text files, so this method is available for TextRider.Reader
and not for BinaryRider.Reader.

Cheers,
Stewart
Post by Taylor Hutt
thutt
Lurking, always lurking.
Wow! You're still here ;-) Long time, no see...
Taylor Hutt
2007-04-03 04:08:42 UTC
Permalink
Post by Stewart Greenhill
Hi Taylor,
Post by Taylor Hutt
Historically, ReadInt() was for reading binary values from files.
OOC tries to provide a consistent interface for reading from both
binary and text files. Obviously the two are not identical, so some
features are available in one and not the other. For example, ReadLn
only makes sense on text files, so this method is available for
TextRider.Reader and not for BinaryRider.Reader.
Cheers,
Stewart
Post by Taylor Hutt
thutt
Lurking, always lurking.
Wow! You're still here ;-) Long time, no see...
Well, ok, I haven't really been lurking in a long, long time. But,
since I needed to visit comp.arch.fpga, I thought I would drop by
again.

Stewart Greenhill
2007-03-26 15:47:33 UTC
Permalink
Hi August,

Sorry about that. I did not test the code - it was just intended to be
an outline. The working version is below.

Here are the errors in the outline version:
- I omitted to read the first argument, which is always the name of the
program.
- I omitted error checking, so the program only read one argument but
did not report an error.

The following code checks the result of reading each argument. If you
like you can factor the reading and checking into one (local) procedure,
like this:
PROCEDURE ReadInteger(VAR x : INTEGER);
BEGIN
r.ReadInt(x); r.ReadLn; CheckResult(r);
END ReadInteger;
and then just do:
ReadInteger(x);
ReadInteger(y);

You can retrieve a description for the result of a rider operation using
GetText. In this case, if you don't provide enough arguments, you get:
$ bin/TestArgs 1
Error: Trying to read past the end of the file

Hope this helps.

Cheers,
Stewart

MODULE TestArgs;

IMPORT Out, ProgramArgs, TextRider, Err;

PROCEDURE CheckResult(r : TextRider.Reader);
VAR
message : ARRAY 256 OF CHAR;
BEGIN
IF r.res # TextRider.done THEN
r.res.GetText(message);
Err.String("Error: "); Err.String(message); Err.Ln;
HALT(0);
END;
END CheckResult;

PROCEDURE Run;
VAR
r: TextRider.Reader;
x, y: INTEGER;
BEGIN
r := TextRider.ConnectReader(ProgramArgs.args);
r.ReadLn;
r.ReadInt(x); r.ReadLn; CheckResult(r);
r.ReadInt(y); r.ReadLn; CheckResult(r);
Out.String("x + y = ");
Out.Int(x + y, 0);
Out.Ln;
END Run;

BEGIN
Run
END TestArgs.
Post by August Karlstrom
[...]
Tried an example based on the above fragment but I can't get it to work.
$ cat src/Test.Mod
MODULE Test;
IMPORT Out, ProgramArgs, TextRider;
PROCEDURE Run;
VAR r: TextRider.Reader;
x, y: INTEGER;
BEGIN
r := TextRider.ConnectReader(ProgramArgs.args);
r.ReadInt(x); r.ReadLn;
r.ReadInt(y); r.ReadLn;
Out.String("x + y = ");
Out.Int(x + y, 0);
Out.Ln;
END Run;
BEGIN
Run
END Test.
$ bin/Test 1 1
x + y = -13063
Any clues?
August
Loading...