#Baffled by Benchmark
39 messages in this thread
I keep the Benchmark manuals next to my bed, read them on the subway, etc. but
so much is so wierd!
Why do I pass strings as Addresses? Is 'Address' another name for 'String'?
Can't be! I can go Write("Hello"), Write() is looking for a string, but
AddMenu() expects the menu name to be an Address. This is in SimpleMenus, yet!
I had exactly the same sorts of trouble with TDI's M2 manuals; I'd read the
definition modules and find only declarations, record structures, etc. but no
verbs! It is beginning to dawn on me that in a multitasking universe, I should
only be passing messages back and forth, and never actually command anything,
and that's why there are no verbs, right?
I came to Forth, Snobol4, and Modula-2 from what I thought was a strong
background in UCSD Pascal. The first two supposedly exotic languages were a
cakewalk compared to the supposedly derivative M2. I think Wirth blew it.
When you are asked to supply an adress, this address is used
as a pointer to the string. You then put your string at that
Address. In your AddMenu() instruction you give it an address
also. This address id is used as a pointer to the Menu Structure
that you have to create in order to give the system a description
of your new menu. In multitasking one has to be a "Very nice
programmer" and do everything with CALLS so that the system nknows
whats going on. I found this idea of Structure's to be
a great idea and make things easier to do.
Hoped I helped. BRW……(-.-)
Thank you for your help, Brian. How do I put a String at an Address? Isn't it
already in my executable? If I have in my source code
foo := "ABCD";
then somewhere in my object exists the hex sequence 41$ 42$ 43$ 44$ 00$ (null
terminated string). Am I supposed to know where that piece of object got
loaded? Or can I pass the Address of foo, and have this interpreted as the
address of the string to which foo points?
Strings are rogue elements in strongly typed languages. I guess passing
Addresses instead of the strings themselves allows a routine to deal properly
with strings regardless of length, without having to declare ARRAY [0 … 255]
OF CHAR for all strings, even short one.
My problem with answering that question is that I do not
program in Modula 2, I am more or less an assembly language
programmer. I don't n [D I don't know anything about M2. Your example
looks some how
familiar, do you know if , say in the Wt write() routine if
you could do something like " Write (foo) " or are you saying
that IS EQUAL to ABCD. Actually I'm kind of stumbling along
here because as I said I know nothing about M2.
You are correct about address passing being easier than ARRAY's
By passing the pointr you can randomely change your string,
and as long as it ends in NULL it will get printed, in most
cases.
Sorry I could not help you more, I'm sure someone who is
an M@ M2 er will respond to your message. Pi~{
m{
BRW……….<*_*>
But Thomas, you put 'foo' in the program, so you know where it is. Well, maybe
not in real numbers that you can pick up, squeeze, pinch, and rub, but at least
that there is a variable named 'foo', and that it MUST be at some address. You
tell the compiler where it is by passing 'ADDRESS(foo)'. You can, of course use
'here_is_where_my_string_is := (ADDRESS)foo', and then pass it as
'here_is_where_my_string_is'.
Hmm… hope I have the right operator there, ADDRESS vs. ADR, that is.
Regards, Larry.
Larry,
I *think* you ment ADR.
An example would be how you use the "Execute" command imported from
AmigaDOS.
error := Execute(ADR("dir"),0,0);
This passes the ADDRESS of the string "dir" to Execute – which just
happens to be looking for a first parameter of TYPE ADDRESS.
Lloyd
ADR() will give me the address of an inline literal? So I don't need dummy
variables?
Hooray!
Thomas,
Yep. Kind of a round-about way of doing it, but it works just like the
sample code I left.
Lloyd
Seems to me like I can do
Foo := 'ABCD'
DoSomethingWith(ADDR(Foo))
but it is not permitted to
DoSomethingWith('ABCD')
so if I want to pass a string to a procedure, I _must_ assign it to a
variable, a dummy variable, and the variable's address. No 'Inline' constant
strings.
Thomas,
That's essentially correct. The thing is (as you pointed out), strrings are a
bit of a kludge in many high level compiled languages, and even in C.
Take a look at the way you define strings as arrays of characters, and also at
the way you can pass open arrays (no implicit bounds) to procedures.
Regards, Larry.
Maybe it's a kludge, but waht Thol described works perfectly in C.
Steve,
Yes it does, and it will bite you occasionally too.
Regards, Larry.
It may bite you but in 3-4 years of using C (Lattice on the PC, MegaMax, Mark
Williams, and Alycon on the ST, Lattice and Aztec on the Amiga) it's behaved
exactly as expected.
[Icy tone]
The goal in language design is not to come up with something that _works_ since
any common assembler can do that, but with an intuitive structure that requires
zero learning.
Human languages (so-called Natural Languages) 'work fine' yet contain gross
redundancy and inconsistency. De l'Go demonstrated that any properly designed
computer language can, in principle, be both complete and consistent. This was
in a codicil to his essential work 'The Largest Integer(s).'
Ah, Tom..the critical phrase is "in principal". There are many problems
solvable "in principal", but when the real world interferes the solution is
less than obious. For example, Newton had "in principal" solved the problem of
navigation form Earth to the Moon. But it took engineers few hundred years to
work out the details….Richie 🙂
I suppose I am jumping to C's defense…but, how are strings a kludge in C? I
have programmed in many HOLs, and when I came to C, I remember saying to myself
"At last, a language with a decent concept of strings." (This was after COBOL,
Pascal, a little FORTRAN, and ALGOL). From previous messages in this thread,
it looks like Modula-2 is not quite as comfortable doing all kinds of things
with strings as C. A C programmer is quite comfortable with the fact that the
address of a string is the same as the address of the string's first character,
since strings are just "array of char" or "pointer to char", these being
interchangeable in C. In C:
char *mystring; /* or char mystring[]; */
mystring = "Hello World";
myfunc(mystring); means:
Assign the address of the start of the string "Hello World" to mystring
Call myfunc with mystring (the address of aforementioned string) and
myfunc("Hello World") means call myfunc with the address of "Hello World"
Perhaps in Modula-2:
mystring := "Hello World";
myfunc(/*whatever the appropriate stuff is*/ mystring); means call myfunc
with the address of "Hello World", while myfunc("Hello World") means:
Call myfunc, pushing 12 characters in "Hello World" onto the stack for
processing by myfunc? Am I way off here? It should be obvious by now that
I don't know Modula-2 from JOVIAL. 🙂
I no qualms about passing the address of a variable. Variables are fine things
that the compiler knows about from the VAR section and has set up a lovely
table of names and addresses to lookup at that time, long before they are
encountered in any Procedure.
The program fragment
DoSomething(ADR('D. J. Bauch loves C but is not going to marry it'))
shows me passing the address of an inline constant, and since that address
seems to be dependent on the state of the machine at load time, it makes me
feel a little queezy.
Thomas,
It's the same for your VARs… there is no fixed position for them in memory
and they will be plunked in there at an address dependent upon the state of the
machine at load time as well. Queasy/ Naw… just the fun of relocating
loaders.
Regards, Larry.
Why get queezy? On a relocating loader machine nothing is ever the same. None
of your code, variables or even constant is guaranteed to load in the same
place. But what's the big deal? It's the same on most "sufficiently advanced"
computers? Still feel queezy? Take Drammamine!
– Steve –
What makes me queasy is passing the address of an un-declared constant. In a
language which supports Declaration sections, I expect the compiler to be
making up its address tables _there_. When I hit it with an undeclared in-line
constant, I expect it to compile the constant into the code. I expect
foo := 2 + 3
to be compile to machine instructions loading the immediate value 2 into one
register and immediate value 3 into the other, summing them, and punching them
into the address denoted 'foo.' I do _not_ expect the compiler to make up two
dummy variables, store 2 and 3 in them, and then generate instructions to
retrieve the contents of dummy1 and dummy2.
Whoops! See message #97136. It's meant for you, not Richie. — Art
In many high level languages, a string is an array of characters for which
library routines are written to handle them in special ways. Sounds like a
kludge to me. Look at other languages where strings are a specific data type,
and you'l see what i mean.
Regards, Larry.
<Funny look on face> Why would you want a specific data type? Seems to me as
if the ultimate language would treat all the data the same way; I.E., a
character string is a single dimensioned array is a group of type BYTE with a
pointer is…
This isn't a poke to start an argument. I'm wondering what I'm overlooking.
Rick
Rick,
I did not mention untyped languages, but the principle is the same. A string
is a data type in an untyped language just as much as it is in say, BASIC or
COMAL. It's just that it's a string when you treat it as a string, and
something elsewhen you don't.
Why would _I_ want a specific data type? Well, it beats the heck out of
having to treat it as another data type and write rotuines to handle it as if
it were really the type I wanted in the first place.
Regards, Larry.
Some are more kludgy than others. In fact, built-in strings are often as bad
as character arrays, as they share many of the failings. There are, in my
experience, two basic types of string implementations; counted strings and
terminated strings. C uses terminated strings; a string is a character pointer
or array, it's composed of all characters up to the terminating NUL character.
It can be any length, but can't contain the NUL character. The other kind is
usually implemented in PASCAL and is the counted string, of which BCPL strings
are a type. The counted string can contain all characters, and is basically a
structure with a count and string field, the string field being an array of
characters.
Typically, Pascal string implementations are weak in that Pascal doesn't easily
support variable sized arrays. So you allocate a string, and it takes up the
maximum string length, no matter it's length. It also means that it's easy to
find the length, but it probably takes longer to do any manipulation. Some
BASICs have this problem. The BCPL problem is that the count field is a BYTE,
so strings can't be over 255 characters long.
C type strings can be any length, though the length has to be computed. They
can very easily be dynamically created by program or statically allocated by
compiler, as char * is a much more standard type than a thing like RECORD len :
BYTE; str [1..magiclen] : ARRAY OF CHAR; END;.
Of course, languages like BASIC tend to have everything built-in, as opposed to
C, which has very little built in. BASIC strings, and to a greater degree ICON
and SNOBOL strings, are dynamically allocated and transparent to the user.
They also tend to be slow, and require some kind of garbage collection. C type
strings with the standard C string library aren't dynamic, but it's rather
simple to make them so, without changing any existing functions, with the
addition of a few allocation, reallocation, and garbage collection functions.
I've even seen this done in PASCAL, though not so cleanly.
-Dave
There's the whole problem! C does not differentiate between an array and a
pointer. This is certainly untyped and "messy" (not to mention dangerous).
Modula-2, in my opinion, has a better approach, but if you really want to, it
can behave just like C.
– Steve – s
That's how the non-C person looks at it. My personal viewpoint is that there
really aren't any arrays in C. There is, however, this operator, "[x]", which
will index and dereference a memory element given a proper pointer to that
block of memory.
-Dave
Dave,
exactly like the ! operator in BCPL
Come on Tom! I'm surprised by you!
The requirements to pass some parameters as addresses has nothing to do
with Modula-2 or any high level language (HLL for short), but it has to do with
what the ROM Kernel routines want to see. In numerous instances these routines
want to get a pointer (same as address) to a string or some other data
structure.
In Modula-2 you can find the address of any variable using the ADR
function. So ADR(foo) gives you the address of 'foo'. According to the strict
M2 language definition, if you want to pass a string to a RK routine by address
you would have to do the following:
foo := 'Hello There';
SomeRKroutine(ADR(foo)); But Benchmark relaxes that a bit and lets you
do
SomeRKroutine(ADR('Hello There')) (which is really kind of weird, but
save you the trouble of creating
another variable).
One thing to watch out for is because of this relaxation of the
language definition, you can pass the address of a constant to some routine
which might think that this is a string that it can change, and you end up
changing a constant(!!!!!). Watch out for this!!
Anyway, Wirth did NOT blow it, and string handling is not so bad in
Modula-2 (although it could have been better).
One last thing: The manuals for TDI and Benchmark are mostly there to
document the interface to the RK routines, and nothing else. They are certainly
no substitute for the RKM and Intuition manuals or some good M2 books.
Hope this helped
– Steve – (Wheww)
Ok, I've spent some more time with Volume One of the documentation/manuals, and
sure enough, there's the ADR function in full glory ADR("Hello World") so Shame
On Me. Still pretty counterintuitive. I mean, what is the compiler _doing_
there? [Enter reading the compiler's mind mode ]
DoSomething(ADR("Hi Pal"))
hmm that means I do a little inline constant here ok where am I STAB Hi Pal now
put that in the register and Jump to Do Something.
You're on the right track. In the pure language definition, constants are NOT
variables. Therefore they cannot be modified and they do not (theoretically)
take space and therefore don't have an address. Hovewever, reality IS
different, and those string constant must be stored somewhere in the code (so
you'r right about the in-line code bit). Therefore, Benchmark gives you the
unorthodox ability to find the address of this constant and use that. By the
way, passing parameters to procedure does NOT mean thos parameters must reside
in registers; they can also (and usually are) passed on the stack.
– Steve –
Tom, the problems you are running into are due to the fact that Intuition was
written in C. To a "C" program strings are accessed via pointers (loosely
speaking) and Modula-2 must conform to C standard. An ADDRESS in Modula-2 is
just like an ADDRESS in assembler. You know, the number assigned to each memory
location. There is one more thing here…when you pass a string to a procedure
that sets up a menu the string must exist after the procedure is done. So the
string must be passed as VAR parameter. Now a you can't pass a constant (!) as
a variable (!). So the way to get around this dilema is to pass the address of
the constant…..
…I don't think I'm explaining it to well…if you really have more questions,
give me a call I'll be happy to tell you all you want to know….Richie
Ahh, some light is dawning. When I pass a string to a menu, AmigaDOS sez "gee,
the guy's already got that doggone thing somewhere in memory since it's living
in his program, so why should I make another copy just to splatter onto the
screen? I'll just use his original. A byte saved is a byte earned."
Now here I was, a diskette full of menu titles, all set to begin a loop which
would read the first title into a little buffer, set up a menu, read the next
title into the buffer, set up another menu, until EOF; and _now_ I learn that
this important application is _impossible._ Oh woe is me.
What is impossible? You can read menu labels from a disk file and use
them "on the fly." Passing constants is not mandatory.
…
VAR
foo : SomeStringType;
BEGIN
MyMenuFileRead(foo); (* where foo is a string read from a file *)
AddMenuItem(ADR(foo)); (* any other params. needed for this? *)
(*etc.*)
…
That oughta be just groovy. — Art
But, if I'm passing the _address_ of foo, and foo changes the next time I go
through the loop and read in another name from disk, won't my menu change, too?
Thomas,
Of course. The data for menus must be in chip ram whenever the menu can be
activated. You cannot share buffer space for the text.
So that means the loop:
LoopTop
Foo := NextMenuName(MenuFileName)
SetupMenu(ADR(Foo))
GOTO LoopTop
builds an infinite number of menues with the same, changing name.
Sheesh!! The turnaround here is so fast that I've missed the beginning of this
thread, and I was only away for 3 days!!! So I can't be sure what exactly
you're talking about, but from the code fragment you posted it looks dangerous
to me. The 'SetupMenu' and 'NextMenuName' calls don't look familiar to me.
What do they do? Depending on how SetupMenu works, your code may or may not
work properly.
– Steve –
I don't think that data for menus have to be in CHIP RAM. As far as I know
only IMAGE data must reside there.
– Steve –