Negative integer literals in Oberon
While developing the compiler[1], we got a question whether it is possible to write the following: PROCEDURE DWord(n: INTEGER); ... DWord (90909090H) (where INTEGER is 32-bit). Some compilers give an error (i.e. VOC), while this works in the Project Oberon (2013) compiler. This would turn out to be quite convenient, because the purpose of DWord in our code was to write 4 bytes to the file given as INTEGER (using little-endian byte order). DWord has the following implementation (module Generator[2]): PROCEDURE DWord (n: INTEGER); BEGIN Files.Write (r, CHR (n MOD 100H)); Files.Write (r, CHR (n DIV 100H MOD 100H)); Files.Write (r, CHR (n DIV 10000H MOD 100H)); Files.Write (r, CHR (n DIV 1000000H)) END DWord; The Oberon language report does not indicate that literal 90909090H should be considered an error if INTEGER has 32 bits. In this experiment, an online RISC emulator[3] was used. References: [1] https://github.com/kekcleader/oberon [2] https://github.com/kekcleader/oberon/blob/master/Mod/Generator.Mod [3] http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768
I have a clear opinion on this: it is allowed. But we had a kind of similar case a few days back when I was attacked to allow b := -1; Strictly speaking negative numbers do not exist in Oberon-07. -1 is syntactically not a negative number but a SimpleExpression. You can see this as a kind of shortcut for 0 - 1. Another proof of this view is, you can‘t write CASE i OF -2: END; as case labels can only be numbers, no (const) expression. You can think of decimal values as signed and hex values as unsigned. If you look at Texts.WriteHex(W, -1) you‘ll see what I mean. So, I see 9090909090H as a kind of (low level) way to fill up 32 bit. No notion of sign. However, if you do calculations with these 32 bit you have to be aware that the calculation is done signed. And the comparisons are signed as well. A side topic: this signed comparison thingy is the reason why a timer should better be coded like start := Kernel.Time(); WHILE Kernel.Time() - start < delay DO END; instead of the often found end := Kernel.Time() + delay; WHILE Kernel.Time() < end DO END; br Jörg
Am 25.04.2020 um 17:09 schrieb Arthur Yefimov <artur.efimov@gmail.com>:
While developing the compiler[1], we got a question whether it is possible to write the following:
PROCEDURE DWord(n: INTEGER); ... DWord (90909090H)
(where INTEGER is 32-bit).
Some compilers give an error (i.e. VOC), while this works in the Project Oberon (2013) compiler. This would turn out to be quite convenient, because the purpose of DWord in our code was to write 4 bytes to the file given as INTEGER (using little-endian byte order).
DWord has the following implementation (module Generator[2]):
PROCEDURE DWord (n: INTEGER); BEGIN Files.Write (r, CHR (n MOD 100H)); Files.Write (r, CHR (n DIV 100H MOD 100H)); Files.Write (r, CHR (n DIV 10000H MOD 100H)); Files.Write (r, CHR (n DIV 1000000H)) END DWord;
The Oberon language report does not indicate that literal 90909090H should be considered an error if INTEGER has 32 bits.
In this experiment, an online RISC emulator[3] was used.
References: [1] https://github.com/kekcleader/oberon [2] https://github.com/kekcleader/oberon/blob/master/Mod/Generator.Mod [3] http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768 -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
On 2020-04-25 18:56, Joerg wrote:
I have a clear opinion on this: it is allowed. But we had a kind of similar case a few days back when I was attacked to allow b := -1;
The language report doesn't say anything about the range of the basic types with the exception of BYTE which is defined as the integers between 0 and 255. Therefor it is implementation-dependent whether or not an integer can be assigned 90909090H. On the other hand it seems reasonable to reject the statement b := -1. -- August
Assume INTEGER i (* 32 bit *) i := 7FFFFFFFH; i := i + 1; The report does not say that you have to do a range check. i = 80000000H. if this bit combination is signed or unsigned depends on your output procedure: WriteInt vs WriteHex Assume BYTE b 1) b := 0; b := b - 1; 2) i := -1; b := i; The report does not say that you have to do a range check. If the compiler does not generate a runtime range check, I propse to not do a compile time range check and allow b := -1; After 1) and 2) b = 255; br Jörg
Am 26.04.2020 um 00:17 schrieb August Karlstrom <fusionfile@gmail.com>:
On 2020-04-25 18:56, Joerg wrote: I have a clear opinion on this: it is allowed. But we had a kind of similar case a few days back when I was attacked to allow b := -1;
The language report doesn't say anything about the range of the basic types with the exception of BYTE which is defined as the integers between 0 and 255. Therefor it is implementation-dependent whether or not an integer can be assigned 90909090H. On the other hand it seems reasonable to reject the statement b := -1.
-- August -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
I'm sorry - You have lost me there. How can b, a BYTE, ever validly assume the value of -1 when BYTE is clearly defined in section 6.2 of 'The Programming Language Oberon, Revision 1.10.2013 / 3.5.2016 as: BYTE the integers between 0 and 255 Unlike INTEGER, BYTE is always an unsigned quantity. 1) Are you perhaps suggesting that the language should be changed? 2) Am I misunderstanding what you are trying to say? 3) Something else? Regards, Chris Burrows CFB Software https://www.astrobe.com
-----Original Message----- From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of Joerg Sent: Sunday, 26 April 2020 10:35 AM To: ETH Oberon and related systems Subject: Re: [Oberon] Negative integer literals in Oberon
Assume INTEGER i (* 32 bit *) i := 7FFFFFFFH; i := i + 1;
The report does not say that you have to do a range check. i = 80000000H. if this bit combination is signed or unsigned depends on your output procedure: WriteInt vs WriteHex
Assume BYTE b 1) b := 0; b := b - 1; 2) i := -1; b := i;
The report does not say that you have to do a range check. If the compiler does not generate a runtime range check, I propse to not do a compile time range check and allow b := -1; After 1) and 2) b = 255;
br J rg
Am 26.04.2020 um 00:17 schrieb August Karlstrom <fusionfile@gmail.com>:
?On 2020-04-25 18:56, Joerg wrote: I have a clear opinion on this: it is allowed. But we had a kind of similar case a few days back when I was attacked to allow b := -1;
The language report doesn't say anything about the range of the basic types with the exception of BYTE which is defined as the integers between 0 and 255. Therefor it is implementation-dependent whether or not an integer can be assigned 90909090H. On the other hand it seems reasonable to reject the statement b := -1.
-- August -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
It all depends on what size (i.e. number of bits) INTEGER is defined as on the system you are using as to what range of numbers are valid INTEGERs. Since 2011, the range of INTEGER values is no longer defined in the Language Report; it is implementation-dependent. In the Project Oberon (2013) RISC5 compiler, INTEGER is 32 bit so 90909090H is a valid INTEGER. Maybe you used the default (-O2) option in VOC? If so, INTEGER is 16 bit so 90909090H would be too large. Make sure you are compiling with the VOC –OC option instead if you want INTEGER to be treated as a 32 bit quantity. Note that 9090H would be a negative number on a 16-bit INTEGER system but a positive number on a 32-bit INTEGER system. Regards, Chris Burrows CFB Software https://www.astrobe.com From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of Arthur Yefimov Sent: Sunday, 26 April 2020 12:38 AM To: oberon@lists.inf.ethz.ch Subject: [Oberon] Negative integer literals in Oberon While developing the compiler[1], we got a question whether it is possible to write the following: PROCEDURE DWord(n: INTEGER); ... DWord (90909090H) (where INTEGER is 32-bit). Some compilers give an error (i.e. VOC), while this works in the Project Oberon (2013) compiler. This would turn out to be quite convenient, because the purpose of DWord in our code was to write 4 bytes to the file given as INTEGER (using little-endian byte order). DWord has the following implementation (module Generator[2]): PROCEDURE DWord (n: INTEGER); BEGIN Files.Write (r, CHR (n MOD 100H)); Files.Write (r, CHR (n DIV 100H MOD 100H)); Files.Write (r, CHR (n DIV 10000H MOD 100H)); Files.Write (r, CHR (n DIV 1000000H)) END DWord; The Oberon language report does not indicate that literal 90909090H should be considered an error if INTEGER has 32 bits. In this experiment, an online RISC emulator[3] was used. References: [1] https://github.com/kekcleader/oberon [2] https://github.com/kekcleader/oberon/blob/master/Mod/Generator.Mod [3] http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage <http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768> &width=1024&height=768
((Lapsed) VOC maintainer here.) In both VOC and Oberon 2013, integer literals are parsed in the symbol parser (VOC :OPS.Mod or 2013:ORS.MOD) and stored in the symbol table as signed integer values. Later, during expression compilation, their size is determined by the magnitude of their signed integer value. The difference between Oberon 2013 and VOC is the largest integer type, which is 32 bit on Oberon 2013 and 64 bit in VOC. The special handling that allows a hex literal with top bit set to be treated as a signed value happens at the time the literal is parsed as a symbol independent of what context it is being used in. (Consider e.g. 'CONST mask = 90909090H' - CONST parsing does not know whether this constant will be used in a 64 bit, 32 bit, 16bit or other context.) VOC and Oberon 2013 do both allow the hex special case top bit set parsing behaviour, the difference being the integer literal size. Thus VOC accepts myint64 := 9090909090909090H because 9090909090909090H is parsed as a negative 64 bit signed integer. But VOC does not accept myint32 := 90909090H because 90909090H is parsed as a positive 64 bit signed integer. VOC has no way to parse 90909090H as a negative 32 bit signed integer. - I did wonder about adding a further suffix letter to indicate the intended size, but I couldn't satisfy myself that any solution was simple enough to be easy to understand. - Note that this is independent of VOC's -Ox compatibility setting: that sets the default INTEGER size, not integer literal size - integer literals always support the largest available integer size which is SYSTEM.INT64 aka HUGEINT.) -- Dave On 2020-04-25 22:52, Chris Burrows wrote:
It all depends on what size (i.e. number of bits) INTEGER is defined as on the system you are using as to what range of numbers are valid INTEGERs. Since 2011, the range of INTEGER values is no longer defined in the Language Report; it is implementation-dependent.
In the Project Oberon (2013) RISC5 compiler, INTEGER is 32 bit so 90909090H is a valid INTEGER. Maybe you used the default (-O2) option in VOC? If so, INTEGER is 16 bit so 90909090H would be too large. Make sure you are compiling with the VOC -OC option instead if you want INTEGER to be treated as a 32 bit quantity.
Note that 9090H would be a negative number on a 16-bit INTEGER system but a positive number on a 32-bit INTEGER system.
Regards,
Chris Burrows
CFB Software
FROM: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] ON BEHALF OF Arthur Yefimov SENT: Sunday, 26 April 2020 12:38 AM TO: oberon@lists.inf.ethz.ch SUBJECT: [Oberon] Negative integer literals in Oberon
While developing the compiler[1], we got a question
whether it is possible to write the following:
PROCEDURE DWord(n: INTEGER); ... DWord (90909090H)
(where INTEGER is 32-bit).
Some compilers give an error (i.e. VOC), while this works in the
Project Oberon (2013) compiler. This would turn out to be quite convenient,
because the purpose of DWord in our code was to write 4 bytes to the file
given as INTEGER (using little-endian byte order).
DWord has the following implementation (module Generator[2]):
PROCEDURE DWord (n: INTEGER); BEGIN Files.Write (r, CHR (n MOD 100H)); Files.Write (r, CHR (n DIV 100H MOD 100H)); Files.Write (r, CHR (n DIV 10000H MOD 100H)); Files.Write (r, CHR (n DIV 1000000H)) END DWord;
The Oberon language report does not indicate that literal 90909090H
should be considered an error if INTEGER has 32 bits.
In this experiment, an online RISC emulator[3] was used.
References:
[1] https://github.com/kekcleader/oberon
[2] https://github.com/kekcleader/oberon/blob/master/Mod/Generator.Mod
[3] http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768 -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Chris 1) b := i; is allowed, right? 2) b := i; does not generate a range check, right? 3) i := 511; b := i; If 3) doesn’t generate a range check, but you want to be compliant to the report, you implement the assignment as b := i MOD 256; as any value MOD 256 is between 0..255. br Jörg
Am 26.04.2020 um 09:28 schrieb dave@brownsmeet.com:
((Lapsed) VOC maintainer here.)
In both VOC and Oberon 2013, integer literals are parsed in the symbol parser (VOC :OPS.Mod or 2013:ORS.MOD) and stored in the symbol table as signed integer values.
Later, during expression compilation, their size is determined by the magnitude of their signed integer value.
The difference between Oberon 2013 and VOC is the largest integer type, which is 32 bit on Oberon 2013 and 64 bit in VOC.
The special handling that allows a hex literal with top bit set to be treated as a signed value happens at the time the literal is parsed as a symbol independent of what context it is being used in. (Consider e.g. 'CONST mask = 90909090H' - CONST parsing does not know whether this constant will be used in a 64 bit, 32 bit, 16bit or other context.)
VOC and Oberon 2013 do both allow the hex special case top bit set parsing behaviour, the difference being the integer literal size.
Thus VOC accepts myint64 := 9090909090909090H because 9090909090909090H is parsed as a negative 64 bit signed integer.
But VOC does not accept myint32 := 90909090H because 90909090H is parsed as a positive 64 bit signed integer.
VOC has no way to parse 90909090H as a negative 32 bit signed integer.
- I did wonder about adding a further suffix letter to indicate the intended size, but I couldn't satisfy myself that any solution was simple enough to be easy to understand.
- Note that this is independent of VOC's -Ox compatibility setting: that sets the default INTEGER size, not integer literal size - integer literals always support the largest available integer size which is SYSTEM.INT64 aka HUGEINT.)
-- Dave
On 2020-04-25 22:52, Chris Burrows wrote:
It all depends on what size (i.e. number of bits) INTEGER is defined as on the system you are using as to what range of numbers are valid INTEGERs. Since 2011, the range of INTEGER values is no longer defined in the Language Report; it is implementation-dependent.
In the Project Oberon (2013) RISC5 compiler, INTEGER is 32 bit so 90909090H is a valid INTEGER. Maybe you used the default (-O2) option in VOC? If so, INTEGER is 16 bit so 90909090H would be too large. Make sure you are compiling with the VOC –OC option instead if you want INTEGER to be treated as a 32 bit quantity.
Note that 9090H would be a negative number on a 16-bit INTEGER system but a positive number on a 32-bit INTEGER system.
Regards,
Chris Burrows
CFB Software
From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of Arthur Yefimov Sent: Sunday, 26 April 2020 12:38 AM To: oberon@lists.inf.ethz.ch Subject: [Oberon] Negative integer literals in Oberon
While developing the compiler[1], we got a question
whether it is possible to write the following:
PROCEDURE DWord(n: INTEGER); ... DWord (90909090H)
(where INTEGER is 32-bit).
Some compilers give an error (i.e. VOC), while this works in the
Project Oberon (2013) compiler. This would turn out to be quite convenient,
because the purpose of DWord in our code was to write 4 bytes to the file
given as INTEGER (using little-endian byte order).
DWord has the following implementation (module Generator[2]):
PROCEDURE DWord (n: INTEGER); BEGIN Files.Write (r, CHR (n MOD 100H)); Files.Write (r, CHR (n DIV 100H MOD 100H)); Files.Write (r, CHR (n DIV 10000H MOD 100H)); Files.Write (r, CHR (n DIV 1000000H)) END DWord;
The Oberon language report does not indicate that literal 90909090H
should be considered an error if INTEGER has 32 bits.
In this experiment, an online RISC emulator[3] was used.
References:
[1] https://github.com/kekcleader/oberon
[2] https://github.com/kekcleader/oberon/blob/master/Mod/Generator.Mod
[3] http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
In earlier Oberon versions, variable integer size was supported: INTEGER and LONGINT. LONGINT is not officially supported in Oberon-07 but the compiler internally declares TYPE LONGINT = INTEGER. The concept of variable integer size is not supported in Oberon-07 anymore. Every INTEGER has one (implementation dependent) size, be it 16 or 32 or 64 or ... Syntactically and conceptionally, negative literals do not exist. Only results of calculations can be negative as they are done signed per report. CONST neg = -1; is conceptionally the result of subtracting the literal 1 from 0, and NOT the literal -1. If you use the hex suffix H to fill up the bits of the underlying INTEGER, you need to know the INTEGER size and are per definition in the grey, non-portable, implementation-dependent area of coding If you use the hex suffix H to specify a (unsigned) 32 bit value for low level modules that work with 32 bits (on disc or memory or so) the size of the INTEGER does not matter (as long as it’s 32 bits or larger of course) as your low level module have to treat the passed values MOD 100000000H anyhow. br Jörg
Am 26.04.2020 um 10:25 schrieb Joerg <joerg.straube@iaeth.ch>:
Chris
1) b := i; is allowed, right? 2) b := i; does not generate a range check, right? 3) i := 511; b := i;
If 3) doesn’t generate a range check, but you want to be compliant to the report, you implement the assignment as b := i MOD 256; as any value MOD 256 is between 0..255.
br Jörg
Am 26.04.2020 um 09:28 schrieb dave@brownsmeet.com:
((Lapsed) VOC maintainer here.)
In both VOC and Oberon 2013, integer literals are parsed in the symbol parser (VOC :OPS.Mod or 2013:ORS.MOD) and stored in the symbol table as signed integer values.
Later, during expression compilation, their size is determined by the magnitude of their signed integer value.
The difference between Oberon 2013 and VOC is the largest integer type, which is 32 bit on Oberon 2013 and 64 bit in VOC.
The special handling that allows a hex literal with top bit set to be treated as a signed value happens at the time the literal is parsed as a symbol independent of what context it is being used in. (Consider e.g. 'CONST mask = 90909090H' - CONST parsing does not know whether this constant will be used in a 64 bit, 32 bit, 16bit or other context.)
VOC and Oberon 2013 do both allow the hex special case top bit set parsing behaviour, the difference being the integer literal size.
Thus VOC accepts myint64 := 9090909090909090H because 9090909090909090H is parsed as a negative 64 bit signed integer.
But VOC does not accept myint32 := 90909090H because 90909090H is parsed as a positive 64 bit signed integer.
VOC has no way to parse 90909090H as a negative 32 bit signed integer.
- I did wonder about adding a further suffix letter to indicate the intended size, but I couldn't satisfy myself that any solution was simple enough to be easy to understand.
- Note that this is independent of VOC's -Ox compatibility setting: that sets the default INTEGER size, not integer literal size - integer literals always support the largest available integer size which is SYSTEM.INT64 aka HUGEINT.)
-- Dave
On 2020-04-25 22:52, Chris Burrows wrote:
It all depends on what size (i.e. number of bits) INTEGER is defined as on the system you are using as to what range of numbers are valid INTEGERs. Since 2011, the range of INTEGER values is no longer defined in the Language Report; it is implementation-dependent.
In the Project Oberon (2013) RISC5 compiler, INTEGER is 32 bit so 90909090H is a valid INTEGER. Maybe you used the default (-O2) option in VOC? If so, INTEGER is 16 bit so 90909090H would be too large. Make sure you are compiling with the VOC –OC option instead if you want INTEGER to be treated as a 32 bit quantity.
Note that 9090H would be a negative number on a 16-bit INTEGER system but a positive number on a 32-bit INTEGER system.
Regards,
Chris Burrows
CFB Software
From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of Arthur Yefimov Sent: Sunday, 26 April 2020 12:38 AM To: oberon@lists.inf.ethz.ch Subject: [Oberon] Negative integer literals in Oberon
While developing the compiler[1], we got a question
whether it is possible to write the following:
PROCEDURE DWord(n: INTEGER); ... DWord (90909090H)
(where INTEGER is 32-bit).
Some compilers give an error (i.e. VOC), while this works in the
Project Oberon (2013) compiler. This would turn out to be quite convenient,
because the purpose of DWord in our code was to write 4 bytes to the file
given as INTEGER (using little-endian byte order).
DWord has the following implementation (module Generator[2]):
PROCEDURE DWord (n: INTEGER); BEGIN Files.Write (r, CHR (n MOD 100H)); Files.Write (r, CHR (n DIV 100H MOD 100H)); Files.Write (r, CHR (n DIV 10000H MOD 100H)); Files.Write (r, CHR (n DIV 1000000H)) END DWord;
The Oberon language report does not indicate that literal 90909090H
should be considered an error if INTEGER has 32 bits.
In this experiment, an online RISC emulator[3] was used.
References:
[1] https://github.com/kekcleader/oberon
[2] https://github.com/kekcleader/oberon/blob/master/Mod/Generator.Mod
[3] http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
or in other words: specifying 90909090H just initializes 32 bits and sets the possibly existing MSBs of your INTEGER to 0. On a system where INTEGERs happen to be implemented with 32 bits, the hex value above does - just by coincidence - represent a negative integer. But the literal per se is not negative, just 32 bits. If you want to initialize the 32 LSBs to 909090H and wish to fill the MSBs of your INTEGER with 1 (for whatever reason you want to do that) use -6F6F6F70H br Jörg
Am 26.04.2020 um 11:16 schrieb Joerg <joerg.straube@iaeth.ch>:
In earlier Oberon versions, variable integer size was supported: INTEGER and LONGINT. LONGINT is not officially supported in Oberon-07 but the compiler internally declares TYPE LONGINT = INTEGER. The concept of variable integer size is not supported in Oberon-07 anymore. Every INTEGER has one (implementation dependent) size, be it 16 or 32 or 64 or ...
Syntactically and conceptionally, negative literals do not exist. Only results of calculations can be negative as they are done signed per report. CONST neg = -1; is conceptionally the result of subtracting the literal 1 from 0, and NOT the literal -1.
If you use the hex suffix H to fill up the bits of the underlying INTEGER, you need to know the INTEGER size and are per definition in the grey, non-portable, implementation-dependent area of coding
If you use the hex suffix H to specify a (unsigned) 32 bit value for low level modules that work with 32 bits (on disc or memory or so) the size of the INTEGER does not matter (as long as it’s 32 bits or larger of course) as your low level module have to treat the passed values MOD 100000000H anyhow.
br Jörg
Am 26.04.2020 um 10:25 schrieb Joerg <joerg.straube@iaeth.ch>:
Chris
1) b := i; is allowed, right? 2) b := i; does not generate a range check, right? 3) i := 511; b := i;
If 3) doesn’t generate a range check, but you want to be compliant to the report, you implement the assignment as b := i MOD 256; as any value MOD 256 is between 0..255.
br Jörg
Am 26.04.2020 um 09:28 schrieb dave@brownsmeet.com:
((Lapsed) VOC maintainer here.)
In both VOC and Oberon 2013, integer literals are parsed in the symbol parser (VOC :OPS.Mod or 2013:ORS.MOD) and stored in the symbol table as signed integer values.
Later, during expression compilation, their size is determined by the magnitude of their signed integer value.
The difference between Oberon 2013 and VOC is the largest integer type, which is 32 bit on Oberon 2013 and 64 bit in VOC.
The special handling that allows a hex literal with top bit set to be treated as a signed value happens at the time the literal is parsed as a symbol independent of what context it is being used in. (Consider e.g. 'CONST mask = 90909090H' - CONST parsing does not know whether this constant will be used in a 64 bit, 32 bit, 16bit or other context.)
VOC and Oberon 2013 do both allow the hex special case top bit set parsing behaviour, the difference being the integer literal size.
Thus VOC accepts myint64 := 9090909090909090H because 9090909090909090H is parsed as a negative 64 bit signed integer.
But VOC does not accept myint32 := 90909090H because 90909090H is parsed as a positive 64 bit signed integer.
VOC has no way to parse 90909090H as a negative 32 bit signed integer.
- I did wonder about adding a further suffix letter to indicate the intended size, but I couldn't satisfy myself that any solution was simple enough to be easy to understand.
- Note that this is independent of VOC's -Ox compatibility setting: that sets the default INTEGER size, not integer literal size - integer literals always support the largest available integer size which is SYSTEM.INT64 aka HUGEINT.)
-- Dave
On 2020-04-25 22:52, Chris Burrows wrote:
It all depends on what size (i.e. number of bits) INTEGER is defined as on the system you are using as to what range of numbers are valid INTEGERs. Since 2011, the range of INTEGER values is no longer defined in the Language Report; it is implementation-dependent.
In the Project Oberon (2013) RISC5 compiler, INTEGER is 32 bit so 90909090H is a valid INTEGER. Maybe you used the default (-O2) option in VOC? If so, INTEGER is 16 bit so 90909090H would be too large. Make sure you are compiling with the VOC –OC option instead if you want INTEGER to be treated as a 32 bit quantity.
Note that 9090H would be a negative number on a 16-bit INTEGER system but a positive number on a 32-bit INTEGER system.
Regards,
Chris Burrows
CFB Software
From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of Arthur Yefimov Sent: Sunday, 26 April 2020 12:38 AM To: oberon@lists.inf.ethz.ch Subject: [Oberon] Negative integer literals in Oberon
While developing the compiler[1], we got a question
whether it is possible to write the following:
PROCEDURE DWord(n: INTEGER); ... DWord (90909090H)
(where INTEGER is 32-bit).
Some compilers give an error (i.e. VOC), while this works in the
Project Oberon (2013) compiler. This would turn out to be quite convenient,
because the purpose of DWord in our code was to write 4 bytes to the file
given as INTEGER (using little-endian byte order).
DWord has the following implementation (module Generator[2]):
PROCEDURE DWord (n: INTEGER); BEGIN Files.Write (r, CHR (n MOD 100H)); Files.Write (r, CHR (n DIV 100H MOD 100H)); Files.Write (r, CHR (n DIV 10000H MOD 100H)); Files.Write (r, CHR (n DIV 1000000H)) END DWord;
The Oberon language report does not indicate that literal 90909090H
should be considered an error if INTEGER has 32 bits.
In this experiment, an online RISC emulator[3] was used.
References:
[1] https://github.com/kekcleader/oberon
[2] https://github.com/kekcleader/oberon/blob/master/Mod/Generator.Mod
[3] http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
To be clear - I would like VOC to allow myint32 := 90909090H, but VOC's support of 64 bit literals gets in the way. My advice therefore is that if you never plan to support integers of more than 32 bits, go ahead and allow myint := 90909090H. If you plan to add support for 64 bit integers later, you will need to work around the problems I described below. I cannot see how to do that, but I would love a solution. -- Dave. On 2020-04-26 10:14, Joerg wrote:
In earlier Oberon versions, variable integer size was supported: INTEGER and LONGINT. LONGINT is not officially supported in Oberon-07 but the compiler internally declares TYPE LONGINT = INTEGER. The concept of variable integer size is not supported in Oberon-07 anymore. Every INTEGER has one (implementation dependent) size, be it 16 or 32 or 64 or ...
Syntactically and conceptionally, negative literals do not exist. Only results of calculations can be negative as they are done signed per report. CONST neg = -1; is conceptionally the result of subtracting the literal 1 from 0, and NOT the literal -1.
If you use the hex suffix H to fill up the bits of the underlying INTEGER, you need to know the INTEGER size and are per definition in the grey, non-portable, implementation-dependent area of coding
If you use the hex suffix H to specify a (unsigned) 32 bit value for low level modules that work with 32 bits (on disc or memory or so) the size of the INTEGER does not matter (as long as it's 32 bits or larger of course) as your low level module have to treat the passed values MOD 100000000H anyhow.
br Jörg
Am 26.04.2020 um 10:25 schrieb Joerg <joerg.straube@iaeth.ch>:
Chris
1) b := i; is allowed, right? 2) b := i; does not generate a range check, right? 3) i := 511; b := i;
If 3) doesn't generate a range check, but you want to be compliant to the report, you implement the assignment as b := i MOD 256; as any value MOD 256 is between 0..255.
br
Jörg
Am 26.04.2020 um 09:28 schrieb dave@brownsmeet.com:
((Lapsed) VOC maintainer here.)
In both VOC and Oberon 2013, integer literals are parsed in the symbol parser (VOC :OPS.Mod or 2013:ORS.MOD) and stored in the symbol table as signed integer values.
Later, during expression compilation, their size is determined by the magnitude of their signed integer value.
The difference between Oberon 2013 and VOC is the largest integer type, which is 32 bit on Oberon 2013 and 64 bit in VOC.
The special handling that allows a hex literal with top bit set to be treated as a signed value happens at the time the literal is parsed as a symbol independent of what context it is being used in. (Consider e.g. 'CONST mask = 90909090H' - CONST parsing does not know whether this constant will be used in a 64 bit, 32 bit, 16bit or other context.)
VOC and Oberon 2013 do both allow the hex special case top bit set parsing behaviour, the difference being the integer literal size.
Thus VOC accepts myint64 := 9090909090909090H because 9090909090909090H is parsed as a negative 64 bit signed integer.
But VOC does not accept myint32 := 90909090H because 90909090H is parsed as a positive 64 bit signed integer.
VOC has no way to parse 90909090H as a negative 32 bit signed integer.
- I did wonder about adding a further suffix letter to indicate the intended size, but I couldn't satisfy myself that any solution was simple enough to be easy to understand.
- Note that this is independent of VOC's -Ox compatibility setting: that sets the default INTEGER size, not integer literal size - integer literals always support the largest available integer size which is SYSTEM.INT64 aka HUGEINT.)
-- Dave
On 2020-04-25 22:52, Chris Burrows wrote:
It all depends on what size (i.e. number of bits) INTEGER is defined as on the system you are using as to what range of numbers are valid INTEGERs. Since 2011, the range of INTEGER values is no longer defined in the Language Report; it is implementation-dependent.
In the Project Oberon (2013) RISC5 compiler, INTEGER is 32 bit so 90909090H is a valid INTEGER. Maybe you used the default (-O2) option in VOC? If so, INTEGER is 16 bit so 90909090H would be too large. Make sure you are compiling with the VOC -OC option instead if you want INTEGER to be treated as a 32 bit quantity.
Note that 9090H would be a negative number on a 16-bit INTEGER system but a positive number on a 32-bit INTEGER system.
Regards,
Chris Burrows
CFB Software
FROM: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] ON BEHALF OF Arthur Yefimov SENT: Sunday, 26 April 2020 12:38 AM TO: oberon@lists.inf.ethz.ch SUBJECT: [Oberon] Negative integer literals in Oberon
While developing the compiler[1], we got a question
whether it is possible to write the following:
PROCEDURE DWord(n: INTEGER); ... DWord (90909090H)
(where INTEGER is 32-bit).
Some compilers give an error (i.e. VOC), while this works in the
Project Oberon (2013) compiler. This would turn out to be quite convenient,
because the purpose of DWord in our code was to write 4 bytes to the file
given as INTEGER (using little-endian byte order).
DWord has the following implementation (module Generator[2]):
PROCEDURE DWord (n: INTEGER); BEGIN Files.Write (r, CHR (n MOD 100H)); Files.Write (r, CHR (n DIV 100H MOD 100H)); Files.Write (r, CHR (n DIV 10000H MOD 100H)); Files.Write (r, CHR (n DIV 1000000H)) END DWord;
The Oberon language report does not indicate that literal 90909090H
should be considered an error if INTEGER has 32 bits.
In this experiment, an online RISC emulator[3] was used.
References:
[1] https://github.com/kekcleader/oberon
[2] https://github.com/kekcleader/oberon/blob/master/Mod/Generator.Mod
[3] http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768 -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Dave
VOC has no way to parse 90909090H as a negative 32 bit signed integer.
Why do you want to do that?
as I tried to explain: When you as programmer use the hex notation, you most probably have unsigned byte, word, longword .. usage in mind. Else why not using the decimal notation in the first place? If your intention of 90909090H is just 32 bits, neither the size of the underlying INTEGER nor the sign bit do matter. When implementing a protocol (eg TCP/IP or NTP) you sooner or later have to implement its presentation layer (ISO layer 6). There you most probably have to program Put8, Put16, Put32 ... The parameter in Oberon-07 will always be an INTEGER (of implementation dependent size) but the name of the procedure will tell you, how many bits are used by the protocol’s presentation layer. The procedure has to take the endianness into account as well. Put8 treats the INTEGER parameter MOD 10H, Put16 works MOD 1000H and so on. All presentation layer things are not defined in Oberon-07 and left to the implementation. (Size of INTEGER, endianness of INTEGER and SET, CHAR size, char set...) br Jörg
Am 26.04.2020 um 12:42 schrieb dave@brownsmeet.com:
To be clear - I would like VOC to allow myint32 := 90909090H, but VOC's support of 64 bit literals gets in the way.
My advice therefore is that if you never plan to support integers of more than 32 bits, go ahead and allow myint := 90909090H.
If you plan to add support for 64 bit integers later, you will need to work around the problems I described below. I cannot see how to do that, but I would love a solution.
-- Dave.
On 2020-04-26 10:14, Joerg wrote:
In earlier Oberon versions, variable integer size was supported: INTEGER and LONGINT. LONGINT is not officially supported in Oberon-07 but the compiler internally declares TYPE LONGINT = INTEGER. The concept of variable integer size is not supported in Oberon-07 anymore. Every INTEGER has one (implementation dependent) size, be it 16 or 32 or 64 or ...
Syntactically and conceptionally, negative literals do not exist. Only results of calculations can be negative as they are done signed per report. CONST neg = -1; is conceptionally the result of subtracting the literal 1 from 0, and NOT the literal -1.
If you use the hex suffix H to fill up the bits of the underlying INTEGER, you need to know the INTEGER size and are per definition in the grey, non-portable, implementation-dependent area of coding
If you use the hex suffix H to specify a (unsigned) 32 bit value for low level modules that work with 32 bits (on disc or memory or so) the size of the INTEGER does not matter (as long as it's 32 bits or larger of course) as your low level module have to treat the passed values MOD 100000000H anyhow.
br Jörg
Am 26.04.2020 um 10:25 schrieb Joerg <joerg.straube@iaeth.ch>:
Chris
1) b := i; is allowed, right? 2) b := i; does not generate a range check, right? 3) i := 511; b := i;
If 3) doesn't generate a range check, but you want to be compliant to the report, you implement the assignment as b := i MOD 256; as any value MOD 256 is between 0..255.
br Jörg
Am 26.04.2020 um 09:28 schrieb dave@brownsmeet.com:
((Lapsed) VOC maintainer here.)
In both VOC and Oberon 2013, integer literals are parsed in the symbol parser (VOC :OPS.Mod or 2013:ORS.MOD) and stored in the symbol table as signed integer values.
Later, during expression compilation, their size is determined by the magnitude of their signed integer value.
The difference between Oberon 2013 and VOC is the largest integer type, which is 32 bit on Oberon 2013 and 64 bit in VOC.
The special handling that allows a hex literal with top bit set to be treated as a signed value happens at the time the literal is parsed as a symbol independent of what context it is being used in. (Consider e.g. 'CONST mask = 90909090H' - CONST parsing does not know whether this constant will be used in a 64 bit, 32 bit, 16bit or other context.)
VOC and Oberon 2013 do both allow the hex special case top bit set parsing behaviour, the difference being the integer literal size.
Thus VOC accepts myint64 := 9090909090909090H because 9090909090909090H is parsed as a negative 64 bit signed integer.
But VOC does not accept myint32 := 90909090H because 90909090H is parsed as a positive 64 bit signed integer.
VOC has no way to parse 90909090H as a negative 32 bit signed integer.
- I did wonder about adding a further suffix letter to indicate the intended size, but I couldn't satisfy myself that any solution was simple enough to be easy to understand.
- Note that this is independent of VOC's -Ox compatibility setting: that sets the default INTEGER size, not integer literal size - integer literals always support the largest available integer size which is SYSTEM.INT64 aka HUGEINT.)
-- Dave
On 2020-04-25 22:52, Chris Burrows wrote:
It all depends on what size (i.e. number of bits) INTEGER is defined as on the system you are using as to what range of numbers are valid INTEGERs. Since 2011, the range of INTEGER values is no longer defined in the Language Report; it is implementation-dependent.
In the Project Oberon (2013) RISC5 compiler, INTEGER is 32 bit so 90909090H is a valid INTEGER. Maybe you used the default (-O2) option in VOC? If so, INTEGER is 16 bit so 90909090H would be too large. Make sure you are compiling with the VOC –OC option instead if you want INTEGER to be treated as a 32 bit quantity.
Note that 9090H would be a negative number on a 16-bit INTEGER system but a positive number on a 32-bit INTEGER system.
Regards,
Chris Burrows
CFB Software
From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of Arthur Yefimov Sent: Sunday, 26 April 2020 12:38 AM To: oberon@lists.inf.ethz.ch Subject: [Oberon] Negative integer literals in Oberon
While developing the compiler[1], we got a question
whether it is possible to write the following:
PROCEDURE DWord(n: INTEGER); ... DWord (90909090H)
(where INTEGER is 32-bit).
Some compilers give an error (i.e. VOC), while this works in the
Project Oberon (2013) compiler. This would turn out to be quite convenient,
because the purpose of DWord in our code was to write 4 bytes to the file
given as INTEGER (using little-endian byte order).
DWord has the following implementation (module Generator[2]):
PROCEDURE DWord (n: INTEGER); BEGIN Files.Write (r, CHR (n MOD 100H)); Files.Write (r, CHR (n DIV 100H MOD 100H)); Files.Write (r, CHR (n DIV 10000H MOD 100H)); Files.Write (r, CHR (n DIV 1000000H)) END DWord;
The Oberon language report does not indicate that literal 90909090H
should be considered an error if INTEGER has 32 bits.
In this experiment, an online RISC emulator[3] was used.
References:
[1] https://github.com/kekcleader/oberon
[2] https://github.com/kekcleader/oberon/blob/master/Mod/Generator.Mod
[3] http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Joerg [joerg.straube@iaeth.ch] wrote:
as I tried to explain: When you as programmer use the hex notation, you most probably have unsigned byte, word, longword .. usage in mind. Else why not using the decimal notation in the first place?
Really? Then why do I see all these negative decimal peripheral addresses in the FPGA Oberon Project? A while ago I put together the SysDef.Mod to bring some order into this mess. I had to decipher the hex bit patterns "by hand" and find the correspondence with the negative decimal numbers in the documentation. The copy is attached. It somehow seems to me that the discussion and the actual practice in the FPGA Oberon Project live in two disjoint spaces. On one hand you have all these hex constants plus the theories exposed in this thread, but when you take the actual practice, it looks very different from the theory. W.
Wojtek The 64 IO addresses are the last 256 bytes at the top end of memory. If you have 1MB of memory they are at absolute address 0FFF00H to 0FFFFFH. If you have 16 MB of memory the IO addresses are at 0FFFF00H to 0FFFFFFH. You could either write 0FFFFFFFFFFFFFC0H to be prepared for all possible memory sizes, or just simpler -64; br Jörg
Am 26.04.2020 um 22:20 schrieb Skulski, Wojciech <skulski@pas.rochester.edu>:
Joerg [joerg.straube@iaeth.ch] wrote:
as I tried to explain: When you as programmer use the hex notation, you most probably have unsigned byte, word, longword .. usage in mind. Else why not using the decimal notation in the first place?
Really? Then why do I see all these negative decimal peripheral addresses in the FPGA Oberon Project? A while ago I put together the SysDef.Mod to bring some order into this mess. I had to decipher the hex bit patterns "by hand" and find the correspondence with the negative decimal numbers in the documentation. The copy is attached.
It somehow seems to me that the discussion and the actual practice in the FPGA Oberon Project live in two disjoint spaces. On one hand you have all these hex constants plus the theories exposed in this thread, but when you take the actual practice, it looks very different from the theory.
W.
<SysDef_Feb_11_2020c.Mod.odc.pdf>
FYI Oberon microsystems tackled this problem in the following way when 64-bit integers were introduced in their Component Pascal language: “Hexadecimal integer constants now can be specified either as 4 byte (e.g., 0FFFFFFFFH) or 8 byte constants (e.g., 0FFFFFFFFFFFFFFFFL). This allows to distinguish negative INTEGER hex constants from positive LONGINT hex constants. For example, 0FFFFFFFF denotes -1 when interpreted as INTEGER, but 4294967295 when interpreted as a LONGINT. Integer constants are always INTEGER (4 byte) values. Assignment of an integer constant to a smaller type (e.g., BYTE) is legal if the constant lies within the range of the target type. Integer constants of other types can only be constructed using SHORT or LONG, except that sufficiently large constants automatically have type LONGINT.” Ref: What’s New in Component Pascal, Cuno Pfister, Oberon microsystems, Inc. March 2001 Regards, Chris Burrows https://www.astrobe.com From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of dave@brownsmeet.com Sent: Sunday, 26 April 2020 8:12 PM To: ETH Oberon and related systems Subject: Re: [Oberon] Negative integer literals in Oberon To be clear - I would like VOC to allow myint32 := 90909090H, but VOC's support of 64 bit literals gets in the way. My advice therefore is that if you never plan to support integers of more than 32 bits, go ahead and allow myint := 90909090H. If you plan to add support for 64 bit integers later, you will need to work around the problems I described below. I cannot see how to do that, but I would love a solution. -- Dave. On 2020-04-26 10:14, Joerg wrote: In earlier Oberon versions, variable integer size was supported: INTEGER and LONGINT. LONGINT is not officially supported in Oberon-07 but the compiler internally declares TYPE LONGINT = INTEGER. The concept of variable integer size is not supported in Oberon-07 anymore. Every INTEGER has one (implementation dependent) size, be it 16 or 32 or 64 or ... Syntactically and conceptionally, negative literals do not exist. Only results of calculations can be negative as they are done signed per report. CONST neg = -1; is conceptionally the result of subtracting the literal 1 from 0, and NOT the literal -1. If you use the hex suffix H to fill up the bits of the underlying INTEGER, you need to know the INTEGER size and are per definition in the grey, non-portable, implementation-dependent area of coding If you use the hex suffix H to specify a (unsigned) 32 bit value for low level modules that work with 32 bits (on disc or memory or so) the size of the INTEGER does not matter (as long as it's 32 bits or larger of course) as your low level module have to treat the passed values MOD 100000000H anyhow. br Jörg Am 26.04.2020 um 10:25 schrieb Joerg <joerg.straube@iaeth.ch <mailto:joerg.straube@iaeth.ch> >: Chris 1) b := i; is allowed, right? 2) b := i; does not generate a range check, right? 3) i := 511; b := i; If 3) doesn't generate a range check, but you want to be compliant to the report, you implement the assignment as b := i MOD 256; as any value MOD 256 is between 0..255. br Jörg Am 26.04.2020 um 09:28 schrieb dave@brownsmeet.com <mailto:dave@brownsmeet.com> : ((Lapsed) VOC maintainer here.) In both VOC and Oberon 2013, integer literals are parsed in the symbol parser (VOC :OPS.Mod or 2013:ORS.MOD) and stored in the symbol table as signed integer values. Later, during expression compilation, their size is determined by the magnitude of their signed integer value. The difference between Oberon 2013 and VOC is the largest integer type, which is 32 bit on Oberon 2013 and 64 bit in VOC. The special handling that allows a hex literal with top bit set to be treated as a signed value happens at the time the literal is parsed as a symbol independent of what context it is being used in. (Consider e.g. 'CONST mask = 90909090H' - CONST parsing does not know whether this constant will be used in a 64 bit, 32 bit, 16bit or other context.) VOC and Oberon 2013 do both allow the hex special case top bit set parsing behaviour, the difference being the integer literal size. Thus VOC accepts myint64 := 9090909090909090H because 9090909090909090H is parsed as a negative 64 bit signed integer. But VOC does not accept myint32 := 90909090H because 90909090H is parsed as a positive 64 bit signed integer. VOC has no way to parse 90909090H as a negative 32 bit signed integer. - I did wonder about adding a further suffix letter to indicate the intended size, but I couldn't satisfy myself that any solution was simple enough to be easy to understand. - Note that this is independent of VOC's -Ox compatibility setting: that sets the default INTEGER size, not integer literal size - integer literals always support the largest available integer size which is SYSTEM.INT64 aka HUGEINT.) -- Dave On 2020-04-25 22:52, Chris Burrows wrote: It all depends on what size (i.e. number of bits) INTEGER is defined as on the system you are using as to what range of numbers are valid INTEGERs. Since 2011, the range of INTEGER values is no longer defined in the Language Report; it is implementation-dependent. In the Project Oberon (2013) RISC5 compiler, INTEGER is 32 bit so 90909090H is a valid INTEGER. Maybe you used the default (-O2) option in VOC? If so, INTEGER is 16 bit so 90909090H would be too large. Make sure you are compiling with the VOC –OC option instead if you want INTEGER to be treated as a 32 bit quantity. Note that 9090H would be a negative number on a 16-bit INTEGER system but a positive number on a 32-bit INTEGER system. Regards, Chris Burrows CFB Software https://www.astrobe.com From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of Arthur Yefimov Sent: Sunday, 26 April 2020 12:38 AM To: oberon@lists.inf.ethz.ch <mailto:oberon@lists.inf.ethz.ch> Subject: [Oberon] Negative integer literals in Oberon While developing the compiler[1], we got a question whether it is possible to write the following: PROCEDURE DWord(n: INTEGER); ... DWord (90909090H) (where INTEGER is 32-bit). Some compilers give an error (i.e. VOC), while this works in the Project Oberon (2013) compiler. This would turn out to be quite convenient, because the purpose of DWord in our code was to write 4 bytes to the file given as INTEGER (using little-endian byte order). DWord has the following implementation (module Generator[2]): PROCEDURE DWord (n: INTEGER); BEGIN Files.Write (r, CHR (n MOD 100H)); Files.Write (r, CHR (n DIV 100H MOD 100H)); Files.Write (r, CHR (n DIV 10000H MOD 100H)); Files.Write (r, CHR (n DIV 1000000H)) END DWord; The Oberon language report does not indicate that literal 90909090H should be considered an error if INTEGER has 32 bits. In this experiment, an online RISC emulator[3] was used. References: [1] https://github.com/kekcleader/oberon [2] https://github.com/kekcleader/oberon/blob/master/Mod/Generator.Mod [3] http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage <http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768> &width=1024&height=768 -- Oberon@lists.inf.ethz.ch <mailto:Oberon@lists.inf.ethz.ch> mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch <mailto:Oberon@lists.inf.ethz.ch> mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch <mailto:Oberon@lists.inf.ethz.ch> mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
This propsal is based on the assumption that negative literals do exist. I don‘t think so. If you write 0FFFFH you define 16 bits, not -1. if you want to define -1 write -1 or -1H. br Jörg
Am 26.04.2020 um 13:34 schrieb Chris Burrows <chris@cfbsoftware.com>:
FYI Oberon microsystems tackled this problem in the following way when 64-bit integers were introduced in their Component Pascal language:
“Hexadecimal integer constants now can be specified either as 4 byte (e.g., 0FFFFFFFFH) or 8 byte constants (e.g., 0FFFFFFFFFFFFFFFFL). This allows to distinguish negative INTEGER hex constants from positive LONGINT hex constants. For example, 0FFFFFFFF denotes -1 when interpreted as INTEGER, but 4294967295 when interpreted as a LONGINT. Integer constants are always INTEGER (4 byte) values. Assignment of an integer constant to a smaller type (e.g., BYTE) is legal if the constant lies within the range of the target type. Integer constants of other types can only be constructed using SHORT or LONG, except that sufficiently large constants automatically have type LONGINT.”
Ref: What’s New in Component Pascal, Cuno Pfister, Oberon microsystems, Inc. March 2001
Regards, Chris Burrows https://www.astrobe.com
From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of dave@brownsmeet.com Sent: Sunday, 26 April 2020 8:12 PM To: ETH Oberon and related systems Subject: Re: [Oberon] Negative integer literals in Oberon
To be clear - I would like VOC to allow myint32 := 90909090H, but VOC's support of 64 bit literals gets in the way.
My advice therefore is that if you never plan to support integers of more than 32 bits, go ahead and allow myint := 90909090H.
If you plan to add support for 64 bit integers later, you will need to work around the problems I described below. I cannot see how to do that, but I would love a solution.
-- Dave.
On 2020-04-26 10:14, Joerg wrote:
In earlier Oberon versions, variable integer size was supported: INTEGER and LONGINT. LONGINT is not officially supported in Oberon-07 but the compiler internally declares TYPE LONGINT = INTEGER. The concept of variable integer size is not supported in Oberon-07 anymore. Every INTEGER has one (implementation dependent) size, be it 16 or 32 or 64 or ...
Syntactically and conceptionally, negative literals do not exist. Only results of calculations can be negative as they are done signed per report. CONST neg = -1; is conceptionally the result of subtracting the literal 1 from 0, and NOT the literal -1.
If you use the hex suffix H to fill up the bits of the underlying INTEGER, you need to know the INTEGER size and are per definition in the grey, non-portable, implementation-dependent area of coding
If you use the hex suffix H to specify a (unsigned) 32 bit value for low level modules that work with 32 bits (on disc or memory or so) the size of the INTEGER does not matter (as long as it's 32 bits or larger of course) as your low level module have to treat the passed values MOD 100000000H anyhow.
br Jörg
Am 26.04.2020 um 10:25 schrieb Joerg <joerg.straube@iaeth.ch>:
Chris
1) b := i; is allowed, right? 2) b := i; does not generate a range check, right? 3) i := 511; b := i;
If 3) doesn't generate a range check, but you want to be compliant to the report, you implement the assignment as b := i MOD 256; as any value MOD 256 is between 0..255.
br Jörg
Am 26.04.2020 um 09:28 schrieb dave@brownsmeet.com:
((Lapsed) VOC maintainer here.)
In both VOC and Oberon 2013, integer literals are parsed in the symbol parser (VOC :OPS.Mod or 2013:ORS.MOD) and stored in the symbol table as signed integer values.
Later, during expression compilation, their size is determined by the magnitude of their signed integer value.
The difference between Oberon 2013 and VOC is the largest integer type, which is 32 bit on Oberon 2013 and 64 bit in VOC.
The special handling that allows a hex literal with top bit set to be treated as a signed value happens at the time the literal is parsed as a symbol independent of what context it is being used in. (Consider e.g. 'CONST mask = 90909090H' - CONST parsing does not know whether this constant will be used in a 64 bit, 32 bit, 16bit or other context.)
VOC and Oberon 2013 do both allow the hex special case top bit set parsing behaviour, the difference being the integer literal size.
Thus VOC accepts myint64 := 9090909090909090H because 9090909090909090H is parsed as a negative 64 bit signed integer.
But VOC does not accept myint32 := 90909090H because 90909090H is parsed as a positive 64 bit signed integer.
VOC has no way to parse 90909090H as a negative 32 bit signed integer.
- I did wonder about adding a further suffix letter to indicate the intended size, but I couldn't satisfy myself that any solution was simple enough to be easy to understand.
- Note that this is independent of VOC's -Ox compatibility setting: that sets the default INTEGER size, not integer literal size - integer literals always support the largest available integer size which is SYSTEM.INT64 aka HUGEINT.)
-- Dave
On 2020-04-25 22:52, Chris Burrows wrote:
It all depends on what size (i.e. number of bits) INTEGER is defined as on the system you are using as to what range of numbers are valid INTEGERs. Since 2011, the range of INTEGER values is no longer defined in the Language Report; it is implementation-dependent.
In the Project Oberon (2013) RISC5 compiler, INTEGER is 32 bit so 90909090H is a valid INTEGER. Maybe you used the default (-O2) option in VOC? If so, INTEGER is 16 bit so 90909090H would be too large. Make sure you are compiling with the VOC –OC option instead if you want INTEGER to be treated as a 32 bit quantity.
Note that 9090H would be a negative number on a 16-bit INTEGER system but a positive number on a 32-bit INTEGER system.
Regards, Chris Burrows CFB Software https://www.astrobe.com
From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of Arthur Yefimov Sent: Sunday, 26 April 2020 12:38 AM To: oberon@lists.inf.ethz.ch Subject: [Oberon] Negative integer literals in Oberon
While developing the compiler[1], we got a question whether it is possible to write the following:
PROCEDURE DWord(n: INTEGER); ... DWord (90909090H)
(where INTEGER is 32-bit).
Some compilers give an error (i.e. VOC), while this works in the Project Oberon (2013) compiler. This would turn out to be quite convenient, because the purpose of DWord in our code was to write 4 bytes to the file given as INTEGER (using little-endian byte order).
DWord has the following implementation (module Generator[2]):
PROCEDURE DWord (n: INTEGER); BEGIN Files.Write (r, CHR (n MOD 100H)); Files.Write (r, CHR (n DIV 100H MOD 100H)); Files.Write (r, CHR (n DIV 10000H MOD 100H)); Files.Write (r, CHR (n DIV 1000000H)) END DWord;
The Oberon language report does not indicate that literal 90909090H should be considered an error if INTEGER has 32 bits.
In this experiment, an online RISC emulator[3] was used.
References: [1] https://github.com/kekcleader/oberon [2] https://github.com/kekcleader/oberon/blob/master/Mod/Generator.Mod [3] http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
The subtle semantical refinement that hex values do not follow the „normal“ INTEGER rules is unfortunately not written in the report but his intention can be found in NW‘s compiler: not compared to „maxint“ and if you wrote more than 8 hex digits, only the 32 LSB are stored. IF ch = "H" THEN (*hex*) REPEAT h := d[i]; IF h >= 10 THEN h := h-7 END; (* assumes ASCII coding *) k := k*10H + h; INC(i) (*no overflow check*) UNTIL i = n; ELSE (*decimal integer*) REPEAT IF d[i] < 10 THEN IF k <= (maxint - d[i]) DIV 10 THEN k := k*10 + d[i] ELSE Mark("too large"); k := 0 END ELSE Mark("bad integer") END ; INC(i) UNTIL i = n; END; sym := int; ival := k Gruss, Jörg
Am 26.04.2020 um 14:47 schrieb Jörg <joerg.straube@iaeth.ch>:
This propsal is based on the assumption that negative literals do exist. I don‘t think so.
If you write 0FFFFH you define 16 bits, not -1. if you want to define -1 write -1 or -1H.
br Jörg
Am 26.04.2020 um 13:34 schrieb Chris Burrows <chris@cfbsoftware.com>:
FYI Oberon microsystems tackled this problem in the following way when 64-bit integers were introduced in their Component Pascal language:
“Hexadecimal integer constants now can be specified either as 4 byte (e.g., 0FFFFFFFFH) or 8 byte constants (e.g., 0FFFFFFFFFFFFFFFFL). This allows to distinguish negative INTEGER hex constants from positive LONGINT hex constants. For example, 0FFFFFFFF denotes -1 when interpreted as INTEGER, but 4294967295 when interpreted as a LONGINT. Integer constants are always INTEGER (4 byte) values. Assignment of an integer constant to a smaller type (e.g., BYTE) is legal if the constant lies within the range of the target type. Integer constants of other types can only be constructed using SHORT or LONG, except that sufficiently large constants automatically have type LONGINT.”
Ref: What’s New in Component Pascal, Cuno Pfister, Oberon microsystems, Inc. March 2001
Regards, Chris Burrows https://www.astrobe.com
From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of dave@brownsmeet.com Sent: Sunday, 26 April 2020 8:12 PM To: ETH Oberon and related systems Subject: Re: [Oberon] Negative integer literals in Oberon
To be clear - I would like VOC to allow myint32 := 90909090H, but VOC's support of 64 bit literals gets in the way.
My advice therefore is that if you never plan to support integers of more than 32 bits, go ahead and allow myint := 90909090H.
If you plan to add support for 64 bit integers later, you will need to work around the problems I described below. I cannot see how to do that, but I would love a solution.
-- Dave.
On 2020-04-26 10:14, Joerg wrote:
In earlier Oberon versions, variable integer size was supported: INTEGER and LONGINT. LONGINT is not officially supported in Oberon-07 but the compiler internally declares TYPE LONGINT = INTEGER. The concept of variable integer size is not supported in Oberon-07 anymore. Every INTEGER has one (implementation dependent) size, be it 16 or 32 or 64 or ...
Syntactically and conceptionally, negative literals do not exist. Only results of calculations can be negative as they are done signed per report. CONST neg = -1; is conceptionally the result of subtracting the literal 1 from 0, and NOT the literal -1.
If you use the hex suffix H to fill up the bits of the underlying INTEGER, you need to know the INTEGER size and are per definition in the grey, non-portable, implementation-dependent area of coding
If you use the hex suffix H to specify a (unsigned) 32 bit value for low level modules that work with 32 bits (on disc or memory or so) the size of the INTEGER does not matter (as long as it's 32 bits or larger of course) as your low level module have to treat the passed values MOD 100000000H anyhow.
br Jörg
Am 26.04.2020 um 10:25 schrieb Joerg <joerg.straube@iaeth.ch>:
Chris
1) b := i; is allowed, right? 2) b := i; does not generate a range check, right? 3) i := 511; b := i;
If 3) doesn't generate a range check, but you want to be compliant to the report, you implement the assignment as b := i MOD 256; as any value MOD 256 is between 0..255.
br Jörg
Am 26.04.2020 um 09:28 schrieb dave@brownsmeet.com:
((Lapsed) VOC maintainer here.)
In both VOC and Oberon 2013, integer literals are parsed in the symbol parser (VOC :OPS.Mod or 2013:ORS.MOD) and stored in the symbol table as signed integer values.
Later, during expression compilation, their size is determined by the magnitude of their signed integer value.
The difference between Oberon 2013 and VOC is the largest integer type, which is 32 bit on Oberon 2013 and 64 bit in VOC.
The special handling that allows a hex literal with top bit set to be treated as a signed value happens at the time the literal is parsed as a symbol independent of what context it is being used in. (Consider e.g. 'CONST mask = 90909090H' - CONST parsing does not know whether this constant will be used in a 64 bit, 32 bit, 16bit or other context.)
VOC and Oberon 2013 do both allow the hex special case top bit set parsing behaviour, the difference being the integer literal size.
Thus VOC accepts myint64 := 9090909090909090H because 9090909090909090H is parsed as a negative 64 bit signed integer.
But VOC does not accept myint32 := 90909090H because 90909090H is parsed as a positive 64 bit signed integer.
VOC has no way to parse 90909090H as a negative 32 bit signed integer.
- I did wonder about adding a further suffix letter to indicate the intended size, but I couldn't satisfy myself that any solution was simple enough to be easy to understand.
- Note that this is independent of VOC's -Ox compatibility setting: that sets the default INTEGER size, not integer literal size - integer literals always support the largest available integer size which is SYSTEM.INT64 aka HUGEINT.)
-- Dave
On 2020-04-25 22:52, Chris Burrows wrote:
It all depends on what size (i.e. number of bits) INTEGER is defined as on the system you are using as to what range of numbers are valid INTEGERs. Since 2011, the range of INTEGER values is no longer defined in the Language Report; it is implementation-dependent.
In the Project Oberon (2013) RISC5 compiler, INTEGER is 32 bit so 90909090H is a valid INTEGER. Maybe you used the default (-O2) option in VOC? If so, INTEGER is 16 bit so 90909090H would be too large. Make sure you are compiling with the VOC –OC option instead if you want INTEGER to be treated as a 32 bit quantity.
Note that 9090H would be a negative number on a 16-bit INTEGER system but a positive number on a 32-bit INTEGER system.
Regards, Chris Burrows CFB Software https://www.astrobe.com
From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of Arthur Yefimov Sent: Sunday, 26 April 2020 12:38 AM To: oberon@lists.inf.ethz.ch Subject: [Oberon] Negative integer literals in Oberon
While developing the compiler[1], we got a question whether it is possible to write the following:
PROCEDURE DWord(n: INTEGER); ... DWord (90909090H)
(where INTEGER is 32-bit).
Some compilers give an error (i.e. VOC), while this works in the Project Oberon (2013) compiler. This would turn out to be quite convenient, because the purpose of DWord in our code was to write 4 bytes to the file given as INTEGER (using little-endian byte order).
DWord has the following implementation (module Generator[2]):
PROCEDURE DWord (n: INTEGER); BEGIN Files.Write (r, CHR (n MOD 100H)); Files.Write (r, CHR (n DIV 100H MOD 100H)); Files.Write (r, CHR (n DIV 10000H MOD 100H)); Files.Write (r, CHR (n DIV 1000000H)) END DWord;
The Oberon language report does not indicate that literal 90909090H should be considered an error if INTEGER has 32 bits.
In this experiment, an online RISC emulator[3] was used.
References: [1] https://github.com/kekcleader/oberon [2] https://github.com/kekcleader/oberon/blob/master/Mod/Generator.Mod [3] http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Hi Joerg,
... his intention can be found in NW‘s compiler: not compared to „maxint“ and if you wrote more than 8 hex digits, only the 32 LSB are stored.
I wouldn't read too much into this. In general it looks to me as if he will try to find the least complicated way to show the principle; and checking, if too distracting or hitting (a rather vintage view of) performance, will be elided (eg no PC checks when compilers are laying down code). And that decision is likely to be on a case-by-case basis. If he can do a better job, he usually does. :) ...
k := k*10H + h; INC(i) (*no overflow check*)
Indeed. But pragmatic. Cheers, Paul
Thanks Chris, that's interesting. I explored some combinations in blackbox: MODULE Test; IMPORT Out; PROCEDURE Do*; VAR b: BYTE; s: SHORTINT; i: INTEGER; l: LONGINT; BEGIN i := 0FFFFFFFFH; Out.String("i := 0FFFFFFFFH: "); Out.Int(i,1); Out.Ln; l := 0FFFFFFFFH; Out.String("l := 0FFFFFFFFH: "); Out.Int(l,1); Out.Ln; l := 0FFFFFFFFL; Out.String("l := 0FFFFFFFFL: "); Out.Int(l,1); Out.Ln; l := 0FFFFFFFFFFFFFFFFL; Out.String("l := 0FFFFFFFFFFFFFFFFL: "); Out.Int(l,1); Out.Ln; (* The following all fail to compile with 'number too large': b := 0FFH; s := 0FFFFH; i := 0FFFFFFFFL; l := 0FFFFFFFFFFFFFFFFH; *) END Do; END Test. With results: i := 0FFFFFFFFH: -1 l := 0FFFFFFFFH: -1 l := 0FFFFFFFFL: 4294967295 l := 0FFFFFFFFFFFFFFFFL: -1 So I understand the H/L suffix enables the use of hex bit patterns for 32 and 64 bit integers, but does not address the issue for 8 or 16 bit integers. Do you know if there is any way to enable e.g. FF for bytes, or FFFF for shortints? Or whether this was considered? Thanks -- Dave. On 2020-04-26 12:32, Chris Burrows wrote:
FYI Oberon microsystems tackled this problem in the following way when 64-bit integers were introduced in their Component Pascal language:
"Hexadecimal integer constants now can be specified either as 4 byte (e.g., 0FFFFFFFFH) or 8 byte
constants (e.g., 0FFFFFFFFFFFFFFFFL). This allows to distinguish negative _INTEGER _hex
constants from positive _LONGINT _hex constants. For example, 0FFFFFFFF denotes -1 when
interpreted as _INTEGER_, but 4294967295 when interpreted as a _LONGINT_.
Integer constants are always _INTEGER _(4 byte) values. Assignment of an integer constant to a
smaller type (e.g., _BYTE_) is legal if the constant lies within the range of the target type. Integer
constants of other types can only be constructed using _SHORT _or _LONG_, except that sufficiently
large constants automatically have type _LONGINT_."
Ref: What's New in Component Pascal, Cuno Pfister, Oberon microsystems, Inc. March 2001
Regards,
Chris Burrows
FROM: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] ON BEHALF OF dave@brownsmeet.com SENT: Sunday, 26 April 2020 8:12 PM TO: ETH Oberon and related systems SUBJECT: Re: [Oberon] Negative integer literals in Oberon
To be clear - I would like VOC to allow myint32 := 90909090H, but VOC's support of 64 bit literals gets in the way.
My advice therefore is that if you never plan to support integers of more than 32 bits, go ahead and allow myint := 90909090H.
If you plan to add support for 64 bit integers later, you will need to work around the problems I described below. I cannot see how to do that, but I would love a solution.
-- Dave.
On 2020-04-26 10:14, Joerg wrote:
In earlier Oberon versions, variable integer size was supported: INTEGER and LONGINT. LONGINT is not officially supported in Oberon-07 but the compiler internally declares TYPE LONGINT = INTEGER.
The concept of variable integer size is not supported in Oberon-07 anymore. Every INTEGER has one (implementation dependent) size, be it 16 or 32 or 64 or ...
Syntactically and conceptionally, negative literals do not exist. Only results of calculations can be negative as they are done signed per report.
CONST neg = -1; is conceptionally the result of subtracting the literal 1 from 0, and NOT the literal -1.
If you use the hex suffix H to fill up the bits of the underlying INTEGER, you need to know the INTEGER size and are per definition in the grey, non-portable, implementation-dependent area of coding
If you use the hex suffix H to specify a (unsigned) 32 bit value for low level modules that work with 32 bits (on disc or memory or so) the size of the INTEGER does not matter (as long as it's 32 bits or larger of course) as your low level module have to treat the passed values MOD 100000000H anyhow.
br
Jörg
Am 26.04.2020 um 10:25 schrieb Joerg <joerg.straube@iaeth.ch>:
Chris
1) b := i; is allowed, right?
2) b := i; does not generate a range check, right?
3) i := 511; b := i;
If 3) doesn't generate a range check, but you want to be compliant to the report, you implement the assignment as b := i MOD 256;
as any value MOD 256 is between 0..255.
br
Jörg
Am 26.04.2020 um 09:28 schrieb dave@brownsmeet.com:
((Lapsed) VOC maintainer here.)
In both VOC and Oberon 2013, integer literals are parsed in the symbol parser (VOC :OPS.Mod or 2013:ORS.MOD) and stored in the symbol table as signed integer values.
Later, during expression compilation, their size is determined by the magnitude of their signed integer value.
The difference between Oberon 2013 and VOC is the largest integer type, which is 32 bit on Oberon 2013 and 64 bit in VOC.
The special handling that allows a hex literal with top bit set to be treated as a signed value happens at the time the literal is parsed as a symbol independent of what context it is being used in. (Consider e.g. 'CONST mask = 90909090H' - CONST parsing does not know whether this constant will be used in a 64 bit, 32 bit, 16bit or other context.)
VOC and Oberon 2013 do both allow the hex special case top bit set parsing behaviour, the difference being the integer literal size.
Thus VOC accepts myint64 := 9090909090909090H because 9090909090909090H is parsed as a negative 64 bit signed integer.
But VOC does not accept myint32 := 90909090H because 90909090H is parsed as a positive 64 bit signed integer.
VOC has no way to parse 90909090H as a negative 32 bit signed integer.
- I did wonder about adding a further suffix letter to indicate the intended size, but I couldn't satisfy myself that any solution was simple enough to be easy to understand.
- Note that this is independent of VOC's -Ox compatibility setting: that sets the default INTEGER size, not integer literal size - integer literals always support the largest available integer size which is SYSTEM.INT64 aka HUGEINT.)
-- Dave
On 2020-04-25 22:52, Chris Burrows wrote:
It all depends on what size (i.e. number of bits) INTEGER is defined as on the system you are using as to what range of numbers are valid INTEGERs. Since 2011, the range of INTEGER values is no longer defined in the Language Report; it is implementation-dependent.
In the Project Oberon (2013) RISC5 compiler, INTEGER is 32 bit so 90909090H is a valid INTEGER. Maybe you used the default (-O2) option in VOC? If so, INTEGER is 16 bit so 90909090H would be too large. Make sure you are compiling with the VOC -OC option instead if you want INTEGER to be treated as a 32 bit quantity.
Note that 9090H would be a negative number on a 16-bit INTEGER system but a positive number on a 32-bit INTEGER system.
Regards,
Chris Burrows
CFB Software
FROM: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] ON BEHALF OF Arthur Yefimov SENT: Sunday, 26 April 2020 12:38 AM TO: oberon@lists.inf.ethz.ch SUBJECT: [Oberon] Negative integer literals in Oberon
While developing the compiler[1], we got a question
whether it is possible to write the following:
PROCEDURE DWord(n: INTEGER); ... DWord (90909090H)
(where INTEGER is 32-bit).
Some compilers give an error (i.e. VOC), while this works in the
Project Oberon (2013) compiler. This would turn out to be quite convenient,
because the purpose of DWord in our code was to write 4 bytes to the file
given as INTEGER (using little-endian byte order).
DWord has the following implementation (module Generator[2]):
PROCEDURE DWord (n: INTEGER); BEGIN Files.Write (r, CHR (n MOD 100H)); Files.Write (r, CHR (n DIV 100H MOD 100H)); Files.Write (r, CHR (n DIV 10000H MOD 100H)); Files.Write (r, CHR (n DIV 1000000H)) END DWord;
The Oberon language report does not indicate that literal 90909090H
should be considered an error if INTEGER has 32 bits.
In this experiment, an online RISC emulator[3] was used.
References:
[1] https://github.com/kekcleader/oberon
[2] https://github.com/kekcleader/oberon/blob/master/Mod/Generator.Mod
[3] http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Dave I was only refering to Oberon-07. The semantic in previous Oberons (and Oberon dialects) was different than Oberon-07. I find the implemented semantic of hex values in the Oberon-07 compiler cleaner. In Oberon-07, you can write b := 0FFFFFFFFFFFFH; i := 0FFFFFFFFFFFFH; the results are: b = 255 and i = -1. Jörg
MODULE Test; IMPORT Out;
PROCEDURE Do*; VAR b: BYTE; s: SHORTINT; i: INTEGER; l: LONGINT; BEGIN i := 0FFFFFFFFH; Out.String("i := 0FFFFFFFFH: "); Out.Int(i,1); Out.Ln; l := 0FFFFFFFFH; Out.String("l := 0FFFFFFFFH: "); Out.Int(l,1); Out.Ln; l := 0FFFFFFFFL; Out.String("l := 0FFFFFFFFL: "); Out.Int(l,1); Out.Ln; l := 0FFFFFFFFFFFFFFFFL; Out.String("l := 0FFFFFFFFFFFFFFFFL: "); Out.Int(l,1); Out.Ln; (* The following all fail to compile with 'number too large': b := 0FFH; s := 0FFFFH; i := 0FFFFFFFFL; l := 0FFFFFFFFFFFFFFFFH; *) END Do;
END Test.
With results:
i := 0FFFFFFFFH: -1 l := 0FFFFFFFFH: -1 l := 0FFFFFFFFL: 4294967295 l := 0FFFFFFFFFFFFFFFFL: -1
So I understand the H/L suffix enables the use of hex bit patterns for 32 and 64 bit integers, but does not address the issue for 8 or 16 bit integers.
Do you know if there is any way to enable e.g. FF for bytes, or FFFF for shortints? Or whether this was considered?
Thanks --
Yes.😊 As I wrote in an earlier email, if something is not clearly defined in the report I look at the compiler source to see what NW had in mind when he invented and/or refined an idea. Even if its not documented in the report. I mean: the idea that hex values are treated as unsigned values is more inline with the programmer’s expectation than a compiler issueing „too big“ for the value 0E0000000H. Jörg
Am 26.04.2020 um 18:27 schrieb August Karlstrom <fusionfile@gmail.com>:
On 2020-04-26 16:24, Jörg wrote:
In Oberon-07, you can write b := 0FFFFFFFFFFFFH; i := 0FFFFFFFFFFFFH; the results are: b = 255 and i = -1. I think you mean "The compiler in Project Oberon accepts..."
-- August -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
The only unsigned data in the 2016 definition of Oberon are BYTE values. Ask yourself the following questions: 1. Should the following assertion be successful? ASSERT(ABS(0FFFFFFFFH) = 0FFFFFFFFH); If 0FFFFFFFFH is an unsigned value I would have expected the answer to be 'yes'. 2. Should the compiler accept the following statement? i := i DIV 0FFFFFFFFH; Regards, Chris Burrows CFB Software https://wwww.astrobe.com
-----Original Message----- From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of Joerg Sent: Monday, 27 April 2020 5:00 AM To: ETH Oberon and related systems Subject: Re: [Oberon] Negative integer literals in Oberon
Yes.?? As I wrote in an earlier email, if something is not clearly defined in the report I look at the compiler source to see what NW had in mind when he invented and/or refined an idea. Even if its not documented in the report.
I mean: the idea that hex values are treated as unsigned values is more inline with the programmer s expectation than a compiler issueing too big for the value 0E0000000H.
J rg
Am 26.04.2020 um 18:27 schrieb August Karlstrom <fusionfile@gmail.com>:
?On 2020-04-26 16:24, J rg wrote:
In Oberon-07, you can write b := 0FFFFFFFFFFFFH; i := 0FFFFFFFFFFFFH; the results are: b = 255 and i = -1. I think you mean "The compiler in Project Oberon accepts..."
-- August -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
How the sign bit for INTEGER values have to be stored is NOT defined in the report. This is part of the presentation layer that is deliberately left to the implementation. 1. Should the following assertion be successful? ASSERT(ABS(0FFFFFFFFH) = 0FFFFFFFFH); No, on a 32 bit machine with simple presentation layer implementation Yes, on a 32 bit machine with clever presentation layer implementation. Yes, on a 64 bit machine. 2. Should the compiler accept the following statement? i := i DIV 0FFFFFFFFH; Yes, why not? Just look at the case where INTEGER is 8 bytes. But be aware: as I said H has two different flavors: one H usage is used in INTEGER arithmetic (just use decimal notation and hexadecimal notions for the same INTEGER values, there I wonder why you would do that anyway). And the second H usage (and this is in my experience the usage most have in mind when they use H: low-level programming where you need bit patterns and don't care about the internal presentation layer of INTEGERs that is - as we know - not defined in the Oberon report. Jörg
The whole discussion is based on the assumption that the MSB of a 32 bit value is the sign of an INTEGER. That is not defined in the report. This is left to the implementation. The only means in the Oberon-07 language to influence the sign bit is by using calculations involving "-". 0FFFFFFFFH has no sign operation, so can't be negative. -6AB3H has a "-", so is negative br Jörg Am 27.04.20, 10:04 schrieb "Oberon im Auftrag von Jörg" <oberon-bounces@lists.inf.ethz.ch im Auftrag von joerg.straube@iaeth.ch>: How the sign bit for INTEGER values have to be stored is NOT defined in the report. This is part of the presentation layer that is deliberately left to the implementation. 1. Should the following assertion be successful? ASSERT(ABS(0FFFFFFFFH) = 0FFFFFFFFH); No, on a 32 bit machine with simple presentation layer implementation Yes, on a 32 bit machine with clever presentation layer implementation. Yes, on a 64 bit machine. 2. Should the compiler accept the following statement? i := i DIV 0FFFFFFFFH; Yes, why not? Just look at the case where INTEGER is 8 bytes. But be aware: as I said H has two different flavors: one H usage is used in INTEGER arithmetic (just use decimal notation and hexadecimal notions for the same INTEGER values, there I wonder why you would do that anyway). And the second H usage (and this is in my experience the usage most have in mind when they use H: low-level programming where you need bit patterns and don't care about the internal presentation layer of INTEGERs that is - as we know - not defined in the Oberon report. Jörg -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Hi INTEGER is a black box; Oberon does not state, how to implement this: You are free to implement it as 32 bit value, as 64 bit value, as linked list, as array, as record with separate sign field... INTEGERs - where you don't have any idea, how they are implemented - are normally written in decimal notation. You can calculate with them, compare them etc. Oberon-07 allows to enter INTEGER literals in hex form. This kind of hex digits should obey the same rule as INTEGERs. I mean: if the implementation choses to represent INTEGERs as 31 bit and the MSB builds the sign, only values upto 2'147'483'647 or 7FFFFFFFH should be allowed. A totally other use case is, when a (low level) programmer wants to use 32 bits, independent on the way how the underlying CPU happens to implement INTEGERs. Often programmers have this in mind, when they use the hex notation. These two different use cases where suffix H is used clash obviously. Puristically speaking, Oberon can't be used for low level programming as too much things are left to the implementation. An abstraction like "BITFIELD" or "BIT32" or so is missing. This new base type is not identical to INTEGER as it does not leave the implementation open, but defines exactly how bits are numbered, and how many bits there are. If you use the base type INTEGER where you basically want to manipulate bits, these two concepts clash. On this bit type you can use bitwise AND, OR, XOR, can shift etc. When I talked to NW about this, he said, the only abstraction he came up with for this type of low level bit usage was SETs. SET is almost there but SET has the same "issue" as INTEGER: the presentation layer of SET is left to the implementation!! In my point of view Oberon report should slightly redefine SETs by defining its internal presentation: define its bit numbering (= define its endianness) allow hex notation only for SETs (as alternative notation to { } ), drop hex notation for INTEGERs as I don't see a real use case for hex notation on INTEGERs yet. br Jörg Am 27.04.20, 10:18 schrieb "Oberon im Auftrag von Jörg" <oberon-bounces@lists.inf.ethz.ch im Auftrag von joerg.straube@iaeth.ch>: The whole discussion is based on the assumption that the MSB of a 32 bit value is the sign of an INTEGER. That is not defined in the report. This is left to the implementation. The only means in the Oberon-07 language to influence the sign bit is by using calculations involving "-". 0FFFFFFFFH has no sign operation, so can't be negative. -6AB3H has a "-", so is negative br Jörg Am 27.04.20, 10:04 schrieb "Oberon im Auftrag von Jörg" <oberon-bounces@lists.inf.ethz.ch im Auftrag von joerg.straube@iaeth.ch>: How the sign bit for INTEGER values have to be stored is NOT defined in the report. This is part of the presentation layer that is deliberately left to the implementation. 1. Should the following assertion be successful? ASSERT(ABS(0FFFFFFFFH) = 0FFFFFFFFH); No, on a 32 bit machine with simple presentation layer implementation Yes, on a 32 bit machine with clever presentation layer implementation. Yes, on a 64 bit machine. 2. Should the compiler accept the following statement? i := i DIV 0FFFFFFFFH; Yes, why not? Just look at the case where INTEGER is 8 bytes. But be aware: as I said H has two different flavors: one H usage is used in INTEGER arithmetic (just use decimal notation and hexadecimal notions for the same INTEGER values, there I wonder why you would do that anyway). And the second H usage (and this is in my experience the usage most have in mind when they use H: low-level programming where you need bit patterns and don't care about the internal presentation layer of INTEGERs that is - as we know - not defined in the Oberon report. Jörg -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Joerg:
In my point of view Oberon report should slightly redefine SETs by defining its internal presentation: define its bit numbering (= define its endianness) allow hex notation only for SETs (as alternative notation to { } ), drop hex notation for INTEGERs as I don't see a real use case for hex notation on INTEGERs yet.
How about all these MOD and DIV used for bit manipulations in Oberon System? They are everywhere. Are you saying that someone (==NW?) should redefine both the SETs and the INTEGERs and then modify most of the low level Oberon modules to eradicate bit manipulations with MOD and DIV? This kind of redesign may be worth it, but who is going to do it? You? NW? Paul? Somebody else? How about the adoption by the community? The story of SysDef.Mod is telling me that the entrenched coding practice is not going to change any easily. And now you are implying changing lots of low level bit manipulation code across the entire System. Is it a realistic proposition? Wojtek
You are not forced to use DIV, you have the freedom to use LSR() if you like it more. Programming is a little bit like writing a novel: every author has its style. You either like it or you don‘t😊 br Jörg
Am 27.04.2020 um 18:11 schrieb Skulski, Wojciech <skulski@pas.rochester.edu>:
Joerg:
In my point of view Oberon report should slightly redefine SETs by defining its internal presentation: define its bit numbering (= define its endianness) allow hex notation only for SETs (as alternative notation to { } ), drop hex notation for INTEGERs as I don't see a real use case for hex notation on INTEGERs yet.
How about all these MOD and DIV used for bit manipulations in Oberon System? They are everywhere. Are you saying that someone (==NW?) should redefine both the SETs and the INTEGERs and then modify most of the low level Oberon modules to eradicate bit manipulations with MOD and DIV?
This kind of redesign may be worth it, but who is going to do it? You? NW? Paul? Somebody else? How about the adoption by the community? The story of SysDef.Mod is telling me that the entrenched coding practice is not going to change any easily. And now you are implying changing lots of low level bit manipulation code across the entire System. Is it a realistic proposition?
Wojtek -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
You can enrich the current Oberon system with new HW, but compatibility and flexibility is a little bit missing in the current form. A modular driver architecture is missing. I’m looking into this, how this could be done. By introducing this new driver architecture responsible for one piece of HW, the idea of SysDef.Mod is taken one step further to split it in smaller modular parts. Having all constants at one place like SysDef.Mod is good and bad. Good is that you see all relevant HW related constant definition at one place. But if you want to change one part of it, you have to recompile the whole system, even modules not influenced by the change at all. br Jörg
Am 27.04.2020 um 18:11 schrieb Skulski, Wojciech <skulski@pas.rochester.edu>:
Joerg:
In my point of view Oberon report should slightly redefine SETs by defining its internal presentation: define its bit numbering (= define its endianness) allow hex notation only for SETs (as alternative notation to { } ), drop hex notation for INTEGERs as I don't see a real use case for hex notation on INTEGERs yet.
How about all these MOD and DIV used for bit manipulations in Oberon System? They are everywhere. Are you saying that someone (==NW?) should redefine both the SETs and the INTEGERs and then modify most of the low level Oberon modules to eradicate bit manipulations with MOD and DIV?
This kind of redesign may be worth it, but who is going to do it? You? NW? Paul? Somebody else? How about the adoption by the community? The story of SysDef.Mod is telling me that the entrenched coding practice is not going to change any easily. And now you are implying changing lots of low level bit manipulation code across the entire System. Is it a realistic proposition?
Wojtek -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
On 2020-04-27 15:12, Jörg wrote:
Puristically speaking, Oberon can't be used for low level programming as too much things are left to the implementation.
I don't think I agree. As mentioned by Chris, in a low-level module you can assert that the type INTEGER has the desired properties and then assume that the requirements are met in the rest of the code: ASSERT(SYSTEM.SIZE(INTEGER) = 4); ASSERT(0FFFFFFFFH = -1) (*require two's complement*) ...
An abstraction like "BITFIELD" or "BIT32" or so is missing. This new base type is not identical to INTEGER as it does not leave the implementation open, but defines exactly how bits are numbered, and how many bits there are. If you use the base type INTEGER where you basically want to manipulate bits, these two concepts clash. On this bit type you can use bitwise AND, OR, XOR, can shift etc.
The basic philosophy of the Oberon language report is to describe an abstract language which does contain references to a computer or computing mechanism. This makes the language timeless. In the future 32-bit computing will probably be completely outdated. -- August
August Karlstrom [fusionfile@gmail.com] wrote
In the future 32-bit computing will probably be completely outdated.
I bet 32 bit will remain in the embedded electronics for the foreseeable future. Note that the 8-bit 8051 is still one of the most popular controller cores. I heard it is the most popular cores out there even now. There is no need to advance to 64 bit computing for many embedded applications. Computer vision, probably yes. Simple control most likely not. I happen to believe that RISC5 has a lot of potential which we are slow to realize. Wojtek
August Did you ever write a display driver in Oberon? It can obviously be done but the code is full of strange code (SYSTEM.VALs, Strange SETs and INTEGER constants that have nothing to do with neither INTEGERs nor SETs..) The whole code is heavily compiler dependent not Oberon dependent. ASSERT (0FFFFFFFF = -1) should never be true. as per report left side is positive, right side is negative. Thus is heavily compiler dependent. Jörg
Am 27.04.2020 um 20:22 schrieb August Karlstrom <fusionfile@gmail.com>:
On 2020-04-27 15:12, Jörg wrote:
Puristically speaking, Oberon can't be used for low level programming as too much things are left to the implementation.
I don't think I agree. As mentioned by Chris, in a low-level module you can assert that the type INTEGER has the desired properties and then assume that the requirements are met in the rest of the code:
ASSERT(SYSTEM.SIZE(INTEGER) = 4); ASSERT(0FFFFFFFFH = -1) (*require two's complement*) ...
An abstraction like "BITFIELD" or "BIT32" or so is missing. This new base type is not identical to INTEGER as it does not leave the implementation open, but defines exactly how bits are numbered, and how many bits there are. If you use the base type INTEGER where you basically want to manipulate bits, these two concepts clash. On this bit type you can use bitwise AND, OR, XOR, can shift etc.
The basic philosophy of the Oberon language report is to describe an abstract language which does contain references to a computer or computing mechanism. This makes the language timeless. In the future 32-bit computing will probably be completely outdated.
-- August -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
ASSERT(SYSTEM.SIZE(INTEGER) = 4); Here, the code uses SYSTEM and I know its not portable by definition, or at least I must be careful when porting.
32 bit literals seem useful in low level programming. If you have a strict compiler, like VOC, it’s far from obvious how to do what you want to do. If you want to pass 9090909090H and your machine has 63 bit INTEGERs 9090909090H - 100000000H does the trick If your machine has 31 bit INTEGERs -6F6F6F70H does the trick. Both methods are there to just overcome the compiler restrictions. That’s not what I call a programming language suitable to low level programming. As said everything can be done in Oberon and I‘m fan of Oberon, but a really good high level abstraction (=language construct) for bit programming is unfortunately missing. Br Jörg
Am 27.04.2020 um 20:22 schrieb August Karlstrom <fusionfile@gmail.com>:
On 2020-04-27 15:12, Jörg wrote:
Puristically speaking, Oberon can't be used for low level programming as too much things are left to the implementation.
I don't think I agree. As mentioned by Chris, in a low-level module you can assert that the type INTEGER has the desired properties and then assume that the requirements are met in the rest of the code:
ASSERT(SYSTEM.SIZE(INTEGER) = 4); ASSERT(0FFFFFFFFH = -1) (*require two's complement*) ...
An abstraction like "BITFIELD" or "BIT32" or so is missing. This new base type is not identical to INTEGER as it does not leave the implementation open, but defines exactly how bits are numbered, and how many bits there are. If you use the base type INTEGER where you basically want to manipulate bits, these two concepts clash. On this bit type you can use bitwise AND, OR, XOR, can shift etc.
The basic philosophy of the Oberon language report is to describe an abstract language which does contain references to a computer or computing mechanism. This makes the language timeless. In the future 32-bit computing will probably be completely outdated.
-- August -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
On 2020-04-27 22:10, Jörg wrote:
ASSERT(0FFFFFFFFH = -1) (*require two's complement *)
On strict compilers this statement does not even compile as 0FFFFFFFFH is not a valid INTEGER.
Other compilers, like OBNC (32-bit version), accepts 0FFFFFFFFH for pragmatic reasons. I agree that it's not ideal though.
Could somebody give me a good example, where INTEGERs need a hex notation?
Good question! -- August
Joerg:
Could somebody give me a good example, where INTEGERs need a hex notation?
How about this? These INTEGERS represent addresses. Are addresses integers? I believe they are. The memory is a collection of addresses with consecutive numbers expressed with integers. So it is a relevant example. (* Memory map; PO.System page 104 *) STACKSIZE* = 8000H; (* 32 kB. Was hardwired in Kernel.Init *) STACKORG* = 80000H; (* stackOrg = 524,288; half a megabyte. *) HEAPORG* = STACKORG; (* heapOrg = stackOrg *) FSoffset* = STACKORG; (* Not clear what it is *) MEMLIM* = 0E7EF0H; (* 1 MB minus 98,575 bytes of VRAM at the end*) VRAMORG* = 0E7F00H; (* start of memory-mapped display frame*) VRAMSIZE* = 1024*768 DIV 8; (* 1024 x 768 pixel, monocolor display frame*)
Wojtek It‘s a good point but a little bit a corner case. Principally, Oberon does not know addresses, as addresses are abstracted away by the type construct POINTER TO br, Jörg
Am 27.04.2020 um 22:40 schrieb Skulski, Wojciech <skulski@pas.rochester.edu>:
Joerg:
Could somebody give me a good example, where INTEGERs need a hex notation?
How about this? These INTEGERS represent addresses. Are addresses integers? I believe they are. The memory is a collection of addresses with consecutive numbers expressed with integers. So it is a relevant example.
(* Memory map; PO.System page 104 *) STACKSIZE* = 8000H; (* 32 kB. Was hardwired in Kernel.Init *) STACKORG* = 80000H; (* stackOrg = 524,288; half a megabyte. *) HEAPORG* = STACKORG; (* heapOrg = stackOrg *) FSoffset* = STACKORG; (* Not clear what it is *) MEMLIM* = 0E7EF0H; (* 1 MB minus 98,575 bytes of VRAM at the end*) VRAMORG* = 0E7F00H; (* start of memory-mapped display frame*) VRAMSIZE* = 1024*768 DIV 8; (* 1024 x 768 pixel, monocolor display frame*) -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Joerg:
It‘s a good point but a little bit a corner case. Principally, Oberon does not know addresses, as addresses are abstracted away by the type construct POINTER TO
Yes, POINTER TO needs to be used eventually. But we are facing the question how to assign the hard coded address to the POINTER. The VRAMORG is the case in point. This address is connected to the firmware video controller. The value has to be used as provided below, or there will be no video. VRAMORG does not have to be coded in hex in Oberon. The FW developer can use 0E7F00H, while the Oberon programmer can write 950016 in decimal. But it is much easier and less error prone if both developers can use the same notation. So we need the hex in this case because firmware developers are likely to use hex. Another example is perhaps all these protocols like Ethernet where the documentation will provide hex constants. Imagine the Oberon developer not being able to use these, but rather using a Windows calculator to translate to decimal because hex notation was removed from the language. Wojtek br, Jörg
Am 27.04.2020 um 22:40 schrieb Skulski, Wojciech <skulski@pas.rochester.edu>:
Joerg:
Could somebody give me a good example, where INTEGERs need a hex notation?
How about this? These INTEGERS represent addresses. Are addresses integers? I believe they are. The memory is a collection of addresses with consecutive numbers expressed with integers. So it is a relevant example.
(* Memory map; PO.System page 104 *) STACKSIZE* = 8000H; (* 32 kB. Was hardwired in Kernel.Init *) STACKORG* = 80000H; (* stackOrg = 524,288; half a megabyte. *) HEAPORG* = STACKORG; (* heapOrg = stackOrg *) FSoffset* = STACKORG; (* Not clear what it is *) MEMLIM* = 0E7EF0H; (* 1 MB minus 98,575 bytes of VRAM at the end*) VRAMORG* = 0E7F00H; (* start of memory-mapped display frame*) VRAMSIZE* = 1024*768 DIV 8; (* 1024 x 768 pixel, monocolor display frame*) --
Wojtek There is no question, that hex notation is convenient and needed. But are we really talking about INTEGERs here? Whenever I saw hex notation in my career, it had something to do with HW registers and silly register constants for low level programming. - INTEGERs and REALs are abstractions to do calculations with undefined precision. - POINTER is an abstraction to address memory - SET is an abstraction for bit operations. To what Oberon type should the hex notation apply? In my point of view to INTEGERs the least. SET the most, but this is not foreseen today. And POINTERs have no explicit value at all, as all is abstracted away (hidden) by NEW() br Jörg Am 28.04.20, 06:51 schrieb "Oberon im Auftrag von Skulski, Wojciech" <oberon-bounces@lists.inf.ethz.ch im Auftrag von skulski@pas.rochester.edu>: Joerg: >It‘s a good point but a little bit a corner case. Principally, > Oberon does not know addresses, as addresses are abstracted > away by the type construct POINTER TO Yes, POINTER TO needs to be used eventually. But we are facing the question how to assign the hard coded address to the POINTER. The VRAMORG is the case in point. This address is connected to the firmware video controller. The value has to be used as provided below, or there will be no video. VRAMORG does not have to be coded in hex in Oberon. The FW developer can use 0E7F00H, while the Oberon programmer can write 950016 in decimal. But it is much easier and less error prone if both developers can use the same notation. So we need the hex in this case because firmware developers are likely to use hex. Another example is perhaps all these protocols like Ethernet where the documentation will provide hex constants. Imagine the Oberon developer not being able to use these, but rather using a Windows calculator to translate to decimal because hex notation was removed from the language. Wojtek br, Jörg > Am 27.04.2020 um 22:40 schrieb Skulski, Wojciech <skulski@pas.rochester.edu>: > > Joerg: > >> Could somebody give me a good example, where INTEGERs need a hex notation? > > How about this? These INTEGERS represent addresses. Are addresses integers? I believe they are. The memory is a collection of addresses with consecutive numbers expressed with integers. So it is a relevant example. > > (* Memory map; PO.System page 104 *) > STACKSIZE* = 8000H; (* 32 kB. Was hardwired in Kernel.Init *) > STACKORG* = 80000H; (* stackOrg = 524,288; half a megabyte. *) > HEAPORG* = STACKORG; (* heapOrg = stackOrg *) > FSoffset* = STACKORG; (* Not clear what it is *) > MEMLIM* = 0E7EF0H; (* 1 MB minus 98,575 bytes of VRAM at the end*) > VRAMORG* = 0E7F00H; (* start of memory-mapped display frame*) > VRAMSIZE* = 1024*768 DIV 8; (* 1024 x 768 pixel, monocolor display frame*) > -- -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Just one example I can think of is that I've stored a HEX value representing an absolute start address into an INTEGER and then incremented it to initialise a block of memory at that address. Something like this: VAR startAdr, nWords, data: INTEGER; ... FOR startAdr := 0ABCDEFH TO (startAdr + nWords) BY 4 DO ReadInput(data); SYSTEM.PUT(startAdr, data) END Regards, Chris Burrows CFB Software https://www.astrobe.com
-----Original Message----- From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of Jörg Sent: Tuesday, 28 April 2020 6:42 PM To: ETH Oberon and related systems Subject: Re: [Oberon] Negative integer literals in Oberon
Wojtek
There is no question, that hex notation is convenient and needed. But are we really talking about INTEGERs here? Whenever I saw hex notation in my career, it had something to do with HW registers and silly register constants for low level programming. - INTEGERs and REALs are abstractions to do calculations with undefined precision. - POINTER is an abstraction to address memory - SET is an abstraction for bit operations.
To what Oberon type should the hex notation apply? In my point of view to INTEGERs the least. SET the most, but this is not foreseen today. And POINTERs have no explicit value at all, as all is abstracted away (hidden) by NEW()
br J rg
?Am 28.04.20, 06:51 schrieb "Oberon im Auftrag von Skulski, Wojciech" <oberon-bounces@lists.inf.ethz.ch im Auftrag von skulski@pas.rochester.edu>:
Joerg:
>It s a good point but a little bit a corner case. Principally, > Oberon does not know addresses, as addresses are abstracted > away by the type construct POINTER TO
Yes, POINTER TO needs to be used eventually. But we are facing the question how to assign the hard coded address to the POINTER. The VRAMORG is the case in point. This address is connected to the firmware video controller. The value has to be used as provided below, or there will be no video.
VRAMORG does not have to be coded in hex in Oberon. The FW developer can use 0E7F00H, while the Oberon programmer can write 950016 in decimal. But it is much easier and less error prone if both developers can use the same notation. So we need the hex in this case because firmware developers are likely to use hex.
Another example is perhaps all these protocols like Ethernet where the documentation will provide hex constants. Imagine the Oberon developer not being able to use these, but rather using a Windows calculator to translate to decimal because hex notation was removed from the language.
Wojtek
br, J rg
> Am 27.04.2020 um 22:40 schrieb Skulski, Wojciech <skulski@pas.rochester.edu>: > > ?Joerg: > >> Could somebody give me a good example, where INTEGERs need a hex notation? > > How about this? These INTEGERS represent addresses. Are addresses integers? I believe they are. The memory is a collection of addresses with consecutive numbers expressed with integers. So it is a relevant example. > > (* Memory map; PO.System page 104 *) > STACKSIZE* = 8000H; (* 32 kB. Was hardwired in Kernel.Init *) > STACKORG* = 80000H; (* stackOrg = 524,288; half a megabyte. *) > HEAPORG* = STACKORG; (* heapOrg = stackOrg *) > FSoffset* = STACKORG; (* Not clear what it is *) > MEMLIM* = 0E7EF0H; (* 1 MB minus 98,575 bytes of VRAM at the end*) > VRAMORG* = 0E7F00H; (* start of memory-mapped display frame*) > VRAMSIZE* = 1024*768 DIV 8; (* 1024 x 768 pixel, monocolor display frame*) > -- -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
yes, yes. As replied to Wojtek, addresses are INTEGERs and you might use hex notation if you feel more comfortable. In your example I see more of an issue with „data“ than with „startAdr“.... your code moves 32 bit entities around and not INTEGERs... The input ReadInput works on might be a text or whatever. So in this case INTEGER is kind of misused as you know from the compiler that it by coincidence can hold 32 bits. br Jörg
Am 28.04.2020 um 13:43 schrieb Chris Burrows <chris@cfbsoftware.com>:
Just one example I can think of is that I've stored a HEX value representing an absolute start address into an INTEGER and then incremented it to initialise a block of memory at that address.
Something like this:
VAR startAdr, nWords, data: INTEGER;
... FOR startAdr := 0ABCDEFH TO (startAdr + nWords) BY 4 DO ReadInput(data); SYSTEM.PUT(startAdr, data) END
Regards, Chris Burrows CFB Software https://www.astrobe.com
-----Original Message----- From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of Jörg Sent: Tuesday, 28 April 2020 6:42 PM To: ETH Oberon and related systems Subject: Re: [Oberon] Negative integer literals in Oberon
Wojtek
There is no question, that hex notation is convenient and needed. But are we really talking about INTEGERs here? Whenever I saw hex notation in my career, it had something to do with HW registers and silly register constants for low level programming. - INTEGERs and REALs are abstractions to do calculations with undefined precision. - POINTER is an abstraction to address memory - SET is an abstraction for bit operations.
To what Oberon type should the hex notation apply? In my point of view to INTEGERs the least. SET the most, but this is not foreseen today. And POINTERs have no explicit value at all, as all is abstracted away (hidden) by NEW()
br J rg
?Am 28.04.20, 06:51 schrieb "Oberon im Auftrag von Skulski, Wojciech" <oberon-bounces@lists.inf.ethz.ch im Auftrag von skulski@pas.rochester.edu>:
Joerg:
It s a good point but a little bit a corner case. Principally, Oberon does not know addresses, as addresses are abstracted away by the type construct POINTER TO
Yes, POINTER TO needs to be used eventually. But we are facing the question how to assign the hard coded address to the POINTER. The VRAMORG is the case in point. This address is connected to the firmware video controller. The value has to be used as provided below, or there will be no video.
VRAMORG does not have to be coded in hex in Oberon. The FW developer can use 0E7F00H, while the Oberon programmer can write 950016 in decimal. But it is much easier and less error prone if both developers can use the same notation. So we need the hex in this case because firmware developers are likely to use hex.
Another example is perhaps all these protocols like Ethernet where the documentation will provide hex constants. Imagine the Oberon developer not being able to use these, but rather using a Windows calculator to translate to decimal because hex notation was removed from the language.
Wojtek
br, J rg
Am 27.04.2020 um 22:40 schrieb Skulski, Wojciech <skulski@pas.rochester.edu>:
?Joerg:
Could somebody give me a good example, where INTEGERs need a hex notation?
How about this? These INTEGERS represent addresses. Are addresses integers? I believe they are. The memory is a collection of addresses with consecutive numbers expressed with integers. So it is a relevant example.
(* Memory map; PO.System page 104 *) STACKSIZE* = 8000H; (* 32 kB. Was hardwired in Kernel.Init *) STACKORG* = 80000H; (* stackOrg = 524,288; half a megabyte. *) HEAPORG* = STACKORG; (* heapOrg = stackOrg *) FSoffset* = STACKORG; (* Not clear what it is *) MEMLIM* = 0E7EF0H; (* 1 MB minus 98,575 bytes of VRAM at the end*) VRAMORG* = 0E7F00H; (* start of memory-mapped display frame*) VRAMSIZE* = 1024*768 DIV 8; (* 1024 x 768 pixel, monocolor display frame*) -- -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
How could that possibly be? If ReadInput was reading text input, it would need a CHAR or ARRAY OF CHAR parameter, in which case ReadInput(data) would fail to compile. If I had been reviewing the code myself I would have complained about the use of the identifier name startAdr. Maybe this would be more acceptable? VAR address, nWords, data: INTEGER; FOR address := 0ABCDEFH TO (address + nWords) BY 4 DO ReadIntegerInput(data); SYSTEM.PUT(address, data) END Regards, Chris Burrows CFB Software https://www.cfbsoftware.com
-----Original Message----- From: Joerg [mailto:joerg.straube@iaeth.ch] Sent: Wednesday, 29 April 2020 12:39 AM To: chris@cfbsoftware.com; ETH Oberon and related systems Subject: Re: [Oberon] Negative integer literals in Oberon
yes, yes. As replied to Wojtek, addresses are INTEGERs and you might use hex notation if you feel more comfortable.
In your example I see more of an issue with data than with startAdr ....
your code moves 32 bit entities around and not INTEGERs... The input ReadInput works on might be a text or whatever. So in this case INTEGER is kind of misused as you know from the compiler that it by coincidence can hold 32 bits.
br J rg
Am 28.04.2020 um 13:43 schrieb Chris Burrows <chris@cfbsoftware.com>:
?Just one example I can think of is that I've stored a HEX value representing an absolute start address into an INTEGER and then incremented it to initialise a block of memory at that address.
Something like this:
VAR startAdr, nWords, data: INTEGER;
... FOR startAdr := 0ABCDEFH TO (startAdr + nWords) BY 4 DO ReadInput(data); SYSTEM.PUT(startAdr, data) END
Regards, Chris Burrows CFB Software https://www.astrobe.com
-----Original Message----- From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of J rg Sent: Tuesday, 28 April 2020 6:42 PM To: ETH Oberon and related systems Subject: Re: [Oberon] Negative integer literals in Oberon
Wojtek
There is no question, that hex notation is convenient and needed. But are we really talking about INTEGERs here? Whenever I saw hex notation in my career, it had something to do with HW registers and silly register constants for low level programming. - INTEGERs and REALs are abstractions to do calculations with undefined precision. - POINTER is an abstraction to address memory - SET is an abstraction for bit operations.
To what Oberon type should the hex notation apply? In my point of view to INTEGERs the least. SET the most, but this is not foreseen today. And POINTERs have no explicit value at all, as all is abstracted away (hidden) by NEW()
br J rg
?Am 28.04.20, 06:51 schrieb "Oberon im Auftrag von Skulski, Wojciech" <oberon-bounces@lists.inf.ethz.ch im Auftrag von skulski@pas.rochester.edu>:
Joerg:
It s a good point but a little bit a corner case. Principally, Oberon does not know addresses, as addresses are abstracted away by the type construct POINTER TO
Yes, POINTER TO needs to be used eventually. But we are facing the question how to assign the hard coded address to the POINTER. The VRAMORG is the case in point. This address is connected to the firmware video controller. The value has to be used as provided below, or there will be no video.
VRAMORG does not have to be coded in hex in Oberon. The FW developer can use 0E7F00H, while the Oberon programmer can write 950016 in decimal. But it is much easier and less error prone if both developers can use the same notation. So we need the hex in this case because firmware developers are likely to use hex.
Another example is perhaps all these protocols like Ethernet where the documentation will provide hex constants. Imagine the Oberon developer not being able to use these, but rather using a Windows calculator to translate to decimal because hex notation was removed from the language.
Wojtek
br, J rg
Am 27.04.2020 um 22:40 schrieb Skulski, Wojciech <skulski@pas.rochester.edu>:
?Joerg:
Could somebody give me a good example, where INTEGERs need a hex notation?
How about this? These INTEGERS represent addresses. Are addresses integers? I believe they are. The memory is a collection of addresses with consecutive numbers expressed with integers. So it is a relevant example.
(* Memory map; PO.System page 104 *) STACKSIZE* = 8000H; (* 32 kB. Was hardwired in Kernel.Init *) STACKORG* = 80000H; (* stackOrg = 524,288; half a megabyte. *) HEAPORG* = STACKORG; (* heapOrg = stackOrg *) FSoffset* = STACKORG; (* Not clear what it is *) MEMLIM* = 0E7EF0H; (* 1 MB minus 98,575 bytes of VRAM at the end*) VRAMORG* = 0E7F00H; (* start of memory-mapped display frame*) VRAMSIZE* = 1024*768 DIV 8; (* 1024 x 768 pixel, monocolor display frame*) -- -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Chris Right. In this case I accept it: ReadInteger (data) reads an INTEGER (perhaps reading several digits as ASCII characters and converting them using INTEGER arithmetic to an INTEGER), and SYSTEM.PUT transparently puts the unknown internal presentation of INTEGER to memory. The other way around, it's more tricky: SYSTEM.GET(address, data); WriteInput (data). You have no clue whether the "data" got from memory does really represent an INTEGER. When it was generated like in the previous example, then it's okay. But it could for example be a REAL. So here the use of INTEGER is misleading, as basically it can be an INTEGER but it could be something completely different. If you want to compare the "data" with something, you can't use INTEGER literals, as only the compiler knows how INTEGERs are represented. (Eg is it big endian or little endian?) br Jörg Am 28.04.20, 23:22 schrieb "Oberon im Auftrag von Chris Burrows" <oberon-bounces@lists.inf.ethz.ch im Auftrag von chris@cfbsoftware.com>: How could that possibly be? If ReadInput was reading text input, it would need a CHAR or ARRAY OF CHAR parameter, in which case ReadInput(data) would fail to compile. If I had been reviewing the code myself I would have complained about the use of the identifier name startAdr. Maybe this would be more acceptable? VAR address, nWords, data: INTEGER; FOR address := 0ABCDEFH TO (address + nWords) BY 4 DO ReadIntegerInput(data); SYSTEM.PUT(address, data) END Regards, Chris Burrows CFB Software https://www.cfbsoftware.com > -----Original Message----- > From: Joerg [mailto:joerg.straube@iaeth.ch] > Sent: Wednesday, 29 April 2020 12:39 AM > To: chris@cfbsoftware.com; ETH Oberon and related systems > Subject: Re: [Oberon] Negative integer literals in Oberon > > yes, yes. As replied to Wojtek, addresses are INTEGERs and you might use > hex notation if you feel more comfortable. > > In your example I see more of an issue with data than with startAdr > .... > > your code moves 32 bit entities around and not INTEGERs... The input > ReadInput works on might be a text or whatever. So in this case INTEGER > is kind of misused as you know from the compiler that it by coincidence > can hold 32 bits. > > br > J rg > > > Am 28.04.2020 um 13:43 schrieb Chris Burrows <chris@cfbsoftware.com>: > > > > ?Just one example I can think of is that I've stored a HEX value > representing an absolute start address into an INTEGER and then > incremented it to initialise a block of memory at that address. > > > > Something like this: > > > > VAR > > startAdr, nWords, data: INTEGER; > > > > ... > > FOR startAdr := 0ABCDEFH TO (startAdr + nWords) BY 4 DO > > ReadInput(data); SYSTEM.PUT(startAdr, data) END > > > > Regards, > > Chris Burrows > > CFB Software > > https://www.astrobe.com > > > > > >> -----Original Message----- > >> From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of > >> J rg > >> Sent: Tuesday, 28 April 2020 6:42 PM > >> To: ETH Oberon and related systems > >> Subject: Re: [Oberon] Negative integer literals in Oberon > >> > >> Wojtek > >> > >> There is no question, that hex notation is convenient and needed. > >> But are we really talking about INTEGERs here? Whenever I saw hex > >> notation in my career, it had something to do with HW registers and > >> silly register constants for low level programming. > >> - INTEGERs and REALs are abstractions to do calculations with > >> undefined precision. > >> - POINTER is an abstraction to address memory > >> - SET is an abstraction for bit operations. > >> > >> To what Oberon type should the hex notation apply? > >> In my point of view to INTEGERs the least. SET the most, but this is > >> not foreseen today. > >> And POINTERs have no explicit value at all, as all is abstracted away > >> (hidden) by NEW() > >> > >> br > >> J rg > >> > >> ?Am 28.04.20, 06:51 schrieb "Oberon im Auftrag von Skulski, Wojciech" > >> <oberon-bounces@lists.inf.ethz.ch im Auftrag von > >> skulski@pas.rochester.edu>: > >> > >> Joerg: > >> > >>> It s a good point but a little bit a corner case. Principally, > >>> Oberon does not know addresses, as addresses are abstracted away by > >>> the type construct POINTER TO > >> > >> Yes, POINTER TO needs to be used eventually. But we are facing the > >> question > >> how to assign the hard coded address to the POINTER. The VRAMORG is > >> the case in point. This address is connected to the firmware video > >> controller. > >> The value has to be used as provided below, or there will be no > >> video. > >> > >> VRAMORG does not have to be coded in hex in Oberon. The FW > >> developer can use > >> 0E7F00H, while the Oberon programmer can write 950016 in decimal. > >> But it is > >> much easier and less error prone if both developers can use the > >> same notation. > >> So we need the hex in this case because firmware developers are > >> likely to use hex. > >> > >> Another example is perhaps all these protocols like Ethernet where > >> the documentation > >> will provide hex constants. Imagine the Oberon developer not being > >> able to use these, > >> but rather using a Windows calculator to translate to decimal > >> because hex notation > >> was removed from the language. > >> > >> Wojtek > >> > >> br, J rg > >> > >>> Am 27.04.2020 um 22:40 schrieb Skulski, Wojciech > >> <skulski@pas.rochester.edu>: > >>> > >>> ?Joerg: > >>> > >>>> Could somebody give me a good example, where INTEGERs need a hex > >> notation? > >>> > >>> How about this? These INTEGERS represent addresses. Are addresses > >> integers? I believe they are. The memory is a collection of addresses > >> with consecutive numbers expressed with integers. So it is a relevant > >> example. > >>> > >>> (* Memory map; PO.System page 104 *) > >>> STACKSIZE* = 8000H; (* 32 kB. Was hardwired in Kernel.Init *) > >>> STACKORG* = 80000H; (* stackOrg = 524,288; half a megabyte. *) > >>> HEAPORG* = STACKORG; (* heapOrg = stackOrg *) > >>> FSoffset* = STACKORG; (* Not clear what it is *) > >>> MEMLIM* = 0E7EF0H; (* 1 MB minus 98,575 bytes of VRAM at the > >> end*) > >>> VRAMORG* = 0E7F00H; (* start of memory-mapped display frame*) > >>> VRAMSIZE* = 1024*768 DIV 8; (* 1024 x 768 pixel, monocolor > >> display frame*) > >>> -- > >> -- > >> Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related > >> systems > >> https://lists.inf.ethz.ch/mailman/listinfo/oberon > >> > >> > >> > >> -- > >> Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related > >> systems https://lists.inf.ethz.ch/mailman/listinfo/oberon > > > > -- > > Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related > > systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Joerg:
There is no question, that hex notation is convenient and needed.
I am glad that you are retracting your suggestion that hex could be removed ;-)
But are we really talking about INTEGERs here? Whenever I saw hex notation in my career, it had something to do with HW registers and silly register constants for low level programming.
There are a few use cases. Case 1. We are talking of memory locations. The RAM memory chip is organized as an array. An array starts at 0 and goes on with consecutive numbers, which are integers. Moreover, addresses are often calculated. Therefore, an address is not only an integer, but it is also an integer with math. So yes, an address is a first class integer. Case 2. We can dig further and note that the DRAM is organized as a vector composed on the row, column, and bank. So DRAM address is a triple. But practical DRAM memory controllers strive to map the triple to an ascending array of integers. So there is no reason to deny the integer status in case of DRAM. Case 3. Hardware registers and special purpose memories: arrays of registers, video memories, or network chip buffers (e.g., Wiznet W5300 or ASIX AX8180). These are as good memory arrays as any memory, and their addresses are as good addresses as any. So these addresses are good integers. Case 3. The content of these special registers or video memories. We already know that the addresses are registers, but how about the content? Here we can recall that the colors can be calculated using integer math. Another example: imagine that the memory buffer contains an arbitrary signal to be synthesized, which is often the case with signal processing. This also needs calculation. The conclusion: the register content is a good integer and it needs math.
- INTEGERs and REALs are abstractions to do calculations with undefined precision.
Yes, if you are implementing an abstract algorithm. Not quite so if you are serving some hardware.
- POINTER is an abstraction to address memory
Ditto. A POINTER is allocated by the run time at any memory location. Good for algorithms. Not good for serving hardware. In the latter case I would advocate a minor language extension, or something equivalent. Presently the same is somehow achieved with SYSTEM syntax. myReg := NEW (INTEGER32 at 01234H); (* 32-bit register *)
- SET is an abstraction for bit operations.
Good for abstract algorithms, but in practice we also need hardware mapped bits. How about the following: myBits := NEW (SET27 at 01234H); (* 27-bit register *)
To what Oberon type should the hex notation apply?
Integers and sets.
In my point of view to INTEGERs the least. SET the most, but this is not foreseen today.
And POINTERs have no explicit value at all, as all is abstracted away (hidden) by NEW()
Not sufficient for serving hardware. If the pointer is used to reach a concrete register or video memory, then its target location must be provided by the programmer rather than the run time. Wojtek ------------------------------------ br Jörg Am 28.04.20, 06:51 schrieb "Oberon im Auftrag von Skulski, Wojciech" <oberon-bounces@lists.inf.ethz.ch im Auftrag von skulski@pas.rochester.edu>: Joerg: >It‘s a good point but a little bit a corner case. Principally, > Oberon does not know addresses, as addresses are abstracted > away by the type construct POINTER TO Yes, POINTER TO needs to be used eventually. But we are facing the question how to assign the hard coded address to the POINTER. The VRAMORG is the case in point. This address is connected to the firmware video controller. The value has to be used as provided below, or there will be no video. VRAMORG does not have to be coded in hex in Oberon. The FW developer can use 0E7F00H, while the Oberon programmer can write 950016 in decimal. But it is much easier and less error prone if both developers can use the same notation. So we need the hex in this case because firmware developers are likely to use hex. Another example is perhaps all these protocols like Ethernet where the documentation will provide hex constants. Imagine the Oberon developer not being able to use these, but rather using a Windows calculator to translate to decimal because hex notation was removed from the language. Wojtek br, Jörg > Am 27.04.2020 um 22:40 schrieb Skulski, Wojciech <skulski@pas.rochester.edu>: > > Joerg: > >> Could somebody give me a good example, where INTEGERs need a hex notation? > > How about this? These INTEGERS represent addresses. Are addresses integers? I believe they are. The memory is a collection of addresses with consecutive numbers expressed with integers. So it is a relevant example. > > (* Memory map; PO.System page 104 *) > STACKSIZE* = 8000H; (* 32 kB. Was hardwired in Kernel.Init *) > STACKORG* = 80000H; (* stackOrg = 524,288; half a megabyte. *) > HEAPORG* = STACKORG; (* heapOrg = stackOrg *) > FSoffset* = STACKORG; (* Not clear what it is *) > MEMLIM* = 0E7EF0H; (* 1 MB minus 98,575 bytes of VRAM at the end*) > VRAMORG* = 0E7F00H; (* start of memory-mapped display frame*) > VRAMSIZE* = 1024*768 DIV 8; (* 1024 x 768 pixel, monocolor display frame*) > -- --
I agree that addresses are INTEGERs. They start at 0 and increment up to max memory. Low level function SYSTEM.GET(a, v) defines address “a“ as INTEGER. Whether you have to work with hex notation though is another story. But be it. br Jörg
Am 28.04.2020 um 16:04 schrieb Skulski, Wojciech <skulski@pas.rochester.edu>:
Joerg:
There is no question, that hex notation is convenient and needed.
I am glad that you are retracting your suggestion that hex could be removed ;-)
But are we really talking about INTEGERs here? Whenever I saw hex notation in my career, it had something to do with HW registers and silly register constants for low level programming.
There are a few use cases.
Case 1. We are talking of memory locations. The RAM memory chip is organized as an array. An array starts at 0 and goes on with consecutive numbers, which are integers. Moreover, addresses are often calculated. Therefore, an address is not only an integer, but it is also an integer with math. So yes, an address is a first class integer.
Case 2. We can dig further and note that the DRAM is organized as a vector composed on the row, column, and bank. So DRAM address is a triple. But practical DRAM memory controllers strive to map the triple to an ascending array of integers. So there is no reason to deny the integer status in case of DRAM.
Case 3. Hardware registers and special purpose memories: arrays of registers, video memories, or network chip buffers (e.g., Wiznet W5300 or ASIX AX8180). These are as good memory arrays as any memory, and their addresses are as good addresses as any. So these addresses are good integers.
Case 3. The content of these special registers or video memories. We already know that the addresses are registers, but how about the content? Here we can recall that the colors can be calculated using integer math. Another example: imagine that the memory buffer contains an arbitrary signal to be synthesized, which is often the case with signal processing. This also needs calculation. The conclusion: the register content is a good integer and it needs math.
- INTEGERs and REALs are abstractions to do calculations with undefined precision.
Yes, if you are implementing an abstract algorithm. Not quite so if you are serving some hardware.
- POINTER is an abstraction to address memory
Ditto. A POINTER is allocated by the run time at any memory location. Good for algorithms. Not good for serving hardware. In the latter case I would advocate a minor language extension, or something equivalent. Presently the same is somehow achieved with SYSTEM syntax.
myReg := NEW (INTEGER32 at 01234H); (* 32-bit register *)
- SET is an abstraction for bit operations.
Good for abstract algorithms, but in practice we also need hardware mapped bits. How about the following:
myBits := NEW (SET27 at 01234H); (* 27-bit register *)
To what Oberon type should the hex notation apply?
Integers and sets.
In my point of view to INTEGERs the least. SET the most, but this is not foreseen today.
And POINTERs have no explicit value at all, as all is abstracted away (hidden) by NEW()
Not sufficient for serving hardware. If the pointer is used to reach a concrete register or video memory, then its target location must be provided by the programmer rather than the run time.
Wojtek ------------------------------------
br Jörg
Am 28.04.20, 06:51 schrieb "Oberon im Auftrag von Skulski, Wojciech" <oberon-bounces@lists.inf.ethz.ch im Auftrag von skulski@pas.rochester.edu>:
Joerg:
It‘s a good point but a little bit a corner case. Principally, Oberon does not know addresses, as addresses are abstracted away by the type construct POINTER TO
Yes, POINTER TO needs to be used eventually. But we are facing the question how to assign the hard coded address to the POINTER. The VRAMORG is the case in point. This address is connected to the firmware video controller. The value has to be used as provided below, or there will be no video.
VRAMORG does not have to be coded in hex in Oberon. The FW developer can use 0E7F00H, while the Oberon programmer can write 950016 in decimal. But it is much easier and less error prone if both developers can use the same notation. So we need the hex in this case because firmware developers are likely to use hex.
Another example is perhaps all these protocols like Ethernet where the documentation will provide hex constants. Imagine the Oberon developer not being able to use these, but rather using a Windows calculator to translate to decimal because hex notation was removed from the language.
Wojtek
br, Jörg
Am 27.04.2020 um 22:40 schrieb Skulski, Wojciech <skulski@pas.rochester.edu>:
Joerg:
Could somebody give me a good example, where INTEGERs need a hex notation?
How about this? These INTEGERS represent addresses. Are addresses integers? I believe they are. The memory is a collection of addresses with consecutive numbers expressed with integers. So it is a relevant example.
(* Memory map; PO.System page 104 *) STACKSIZE* = 8000H; (* 32 kB. Was hardwired in Kernel.Init *) STACKORG* = 80000H; (* stackOrg = 524,288; half a megabyte. *) HEAPORG* = STACKORG; (* heapOrg = stackOrg *) FSoffset* = STACKORG; (* Not clear what it is *) MEMLIM* = 0E7EF0H; (* 1 MB minus 98,575 bytes of VRAM at the end*) VRAMORG* = 0E7F00H; (* start of memory-mapped display frame*) VRAMSIZE* = 1024*768 DIV 8; (* 1024 x 768 pixel, monocolor display frame*) -- -- -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Dear Joerg, If we talk about addresses, addresses are usually positive numbers. And working in Oberon, we have an inconvenient moment when the maximum positive number denoting the address goes to the minimum negative: 7FFFFFFFH+1. Therefore, strictly speaking, integers do not map well on the address type. This is bad when addresses are compared and so on. It's just a compromise. Joerg пишет:
I agree that addresses are INTEGERs. They start at 0 and increment up to max memory. Low level function SYSTEM.GET(a, v) defines address “a“ as INTEGER. Whether you have to work with hex notation though is another story. But be it.
br Jörg
Am 28.04.2020 um 16:04 schrieb Skulski, Wojciech <skulski@pas.rochester.edu>:
Joerg:
There is no question, that hex notation is convenient and needed. I am glad that you are retracting your suggestion that hex could be removed ;-)
But are we really talking about INTEGERs here? Whenever I saw hex notation in my career, it had something to do with HW registers and silly register constants for low level programming. There are a few use cases.
Case 1. We are talking of memory locations. The RAM memory chip is organized as an array. An array starts at 0 and goes on with consecutive numbers, which are integers. Moreover, addresses are often calculated. Therefore, an address is not only an integer, but it is also an integer with math. So yes, an address is a first class integer.
Case 2. We can dig further and note that the DRAM is organized as a vector composed on the row, column, and bank. So DRAM address is a triple. But practical DRAM memory controllers strive to map the triple to an ascending array of integers. So there is no reason to deny the integer status in case of DRAM.
Case 3. Hardware registers and special purpose memories: arrays of registers, video memories, or network chip buffers (e.g., Wiznet W5300 or ASIX AX8180). These are as good memory arrays as any memory, and their addresses are as good addresses as any. So these addresses are good integers.
Case 3. The content of these special registers or video memories. We already know that the addresses are registers, but how about the content? Here we can recall that the colors can be calculated using integer math. Another example: imagine that the memory buffer contains an arbitrary signal to be synthesized, which is often the case with signal processing. This also needs calculation. The conclusion: the register content is a good integer and it needs math.
- INTEGERs and REALs are abstractions to do calculations with undefined precision. Yes, if you are implementing an abstract algorithm. Not quite so if you are serving some hardware.
- POINTER is an abstraction to address memory Ditto. A POINTER is allocated by the run time at any memory location. Good for algorithms. Not good for serving hardware. In the latter case I would advocate a minor language extension, or something equivalent. Presently the same is somehow achieved with SYSTEM syntax.
myReg := NEW (INTEGER32 at 01234H); (* 32-bit register *)
- SET is an abstraction for bit operations. Good for abstract algorithms, but in practice we also need hardware mapped bits. How about the following:
myBits := NEW (SET27 at 01234H); (* 27-bit register *)
To what Oberon type should the hex notation apply? Integers and sets.
In my point of view to INTEGERs the least. SET the most, but this is not foreseen today. And POINTERs have no explicit value at all, as all is abstracted away (hidden) by NEW() Not sufficient for serving hardware. If the pointer is used to reach a concrete register or video memory, then its target location must be provided by the programmer rather than the run time.
Wojtek ------------------------------------
br Jörg
Am 28.04.20, 06:51 schrieb "Oberon im Auftrag von Skulski, Wojciech" <oberon-bounces@lists.inf.ethz.ch im Auftrag von skulski@pas.rochester.edu>:
Joerg:
It‘s a good point but a little bit a corner case. Principally, Oberon does not know addresses, as addresses are abstracted away by the type construct POINTER TO Yes, POINTER TO needs to be used eventually. But we are facing the question how to assign the hard coded address to the POINTER. The VRAMORG is the case in point. This address is connected to the firmware video controller. The value has to be used as provided below, or there will be no video.
VRAMORG does not have to be coded in hex in Oberon. The FW developer can use 0E7F00H, while the Oberon programmer can write 950016 in decimal. But it is much easier and less error prone if both developers can use the same notation. So we need the hex in this case because firmware developers are likely to use hex.
Another example is perhaps all these protocols like Ethernet where the documentation will provide hex constants. Imagine the Oberon developer not being able to use these, but rather using a Windows calculator to translate to decimal because hex notation was removed from the language.
Wojtek
br, Jörg
Am 27.04.2020 um 22:40 schrieb Skulski, Wojciech <skulski@pas.rochester.edu>:
Joerg:
Could somebody give me a good example, where INTEGERs need a hex notation? How about this? These INTEGERS represent addresses. Are addresses integers? I believe they are. The memory is a collection of addresses with consecutive numbers expressed with integers. So it is a relevant example.
(* Memory map; PO.System page 104 *) STACKSIZE* = 8000H; (* 32 kB. Was hardwired in Kernel.Init *) STACKORG* = 80000H; (* stackOrg = 524,288; half a megabyte. *) HEAPORG* = STACKORG; (* heapOrg = stackOrg *) FSoffset* = STACKORG; (* Not clear what it is *) MEMLIM* = 0E7EF0H; (* 1 MB minus 98,575 bytes of VRAM at the end*) VRAMORG* = 0E7F00H; (* start of memory-mapped display frame*) VRAMSIZE* = 1024*768 DIV 8; (* 1024 x 768 pixel, monocolor display frame*) -- -- -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Yes and no. Addresses (as integers) do not exist in Oberon. Oberon uses POINTER. You can‘t do arithmetic on pointers. only = and # are allowed on pointers/adresses, no < or > If you use SYSTEM.GET/PUT/VAL you hopefully know what you are doing. With 32bit INTEGERs and max 24bit address bus of the RISC5 (max 16 MB) you don‘t run into this overflow problem. SYSTEM.GET/PUT can handle „negative“ values (=large positive values) correctly. br Jörg
Am 01.05.2020 um 20:22 schrieb Oleg N. Cher <allot@bk.ru>:
Dear Joerg,
If we talk about addresses, addresses are usually positive numbers. And working in Oberon, we have an inconvenient moment when the maximum positive number denoting the address goes to the minimum negative: 7FFFFFFFH+1. Therefore, strictly speaking, integers do not map well on the address type. This is bad when addresses are compared and so on. It's just a compromise.
Joerg пишет:
I agree that addresses are INTEGERs. They start at 0 and increment up to max memory. Low level function SYSTEM.GET(a, v) defines address “a“ as INTEGER. Whether you have to work with hex notation though is another story. But be it. br Jörg
Am 28.04.2020 um 16:04 schrieb Skulski, Wojciech <skulski@pas.rochester.edu>:
Joerg:
There is no question, that hex notation is convenient and needed. I am glad that you are retracting your suggestion that hex could be removed ;-)
But are we really talking about INTEGERs here? Whenever I saw hex notation in my career, it had something to do with HW registers and silly register constants for low level programming. There are a few use cases. Case 1. We are talking of memory locations. The RAM memory chip is organized as an array. An array starts at 0 and goes on with consecutive numbers, which are integers. Moreover, addresses are often calculated. Therefore, an address is not only an integer, but it is also an integer with math. So yes, an address is a first class integer.
Case 2. We can dig further and note that the DRAM is organized as a vector composed on the row, column, and bank. So DRAM address is a triple. But practical DRAM memory controllers strive to map the triple to an ascending array of integers. So there is no reason to deny the integer status in case of DRAM.
Case 3. Hardware registers and special purpose memories: arrays of registers, video memories, or network chip buffers (e.g., Wiznet W5300 or ASIX AX8180). These are as good memory arrays as any memory, and their addresses are as good addresses as any. So these addresses are good integers.
Case 3. The content of these special registers or video memories. We already know that the addresses are registers, but how about the content? Here we can recall that the colors can be calculated using integer math. Another example: imagine that the memory buffer contains an arbitrary signal to be synthesized, which is often the case with signal processing. This also needs calculation. The conclusion: the register content is a good integer and it needs math.
- INTEGERs and REALs are abstractions to do calculations with undefined precision. Yes, if you are implementing an abstract algorithm. Not quite so if you are serving some hardware.
- POINTER is an abstraction to address memory Ditto. A POINTER is allocated by the run time at any memory location. Good for algorithms. Not good for serving hardware. In the latter case I would advocate a minor language extension, or something equivalent. Presently the same is somehow achieved with SYSTEM syntax. myReg := NEW (INTEGER32 at 01234H); (* 32-bit register *)
- SET is an abstraction for bit operations. Good for abstract algorithms, but in practice we also need hardware mapped bits. How about the following:
myBits := NEW (SET27 at 01234H); (* 27-bit register *)
To what Oberon type should the hex notation apply? Integers and sets.
In my point of view to INTEGERs the least. SET the most, but this is not foreseen today. And POINTERs have no explicit value at all, as all is abstracted away (hidden) by NEW() Not sufficient for serving hardware. If the pointer is used to reach a concrete register or video memory, then its target location must be provided by the programmer rather than the run time.
Wojtek ------------------------------------
br Jörg
Am 28.04.20, 06:51 schrieb "Oberon im Auftrag von Skulski, Wojciech" <oberon-bounces@lists.inf.ethz.ch im Auftrag von skulski@pas.rochester.edu>:
Joerg:
It‘s a good point but a little bit a corner case. Principally, Oberon does not know addresses, as addresses are abstracted away by the type construct POINTER TO Yes, POINTER TO needs to be used eventually. But we are facing the question how to assign the hard coded address to the POINTER. The VRAMORG is the case in point. This address is connected to the firmware video controller. The value has to be used as provided below, or there will be no video.
VRAMORG does not have to be coded in hex in Oberon. The FW developer can use 0E7F00H, while the Oberon programmer can write 950016 in decimal. But it is much easier and less error prone if both developers can use the same notation. So we need the hex in this case because firmware developers are likely to use hex.
Another example is perhaps all these protocols like Ethernet where the documentation will provide hex constants. Imagine the Oberon developer not being able to use these, but rather using a Windows calculator to translate to decimal because hex notation was removed from the language.
Wojtek
br, Jörg
Am 27.04.2020 um 22:40 schrieb Skulski, Wojciech <skulski@pas.rochester.edu>:
Joerg:
Could somebody give me a good example, where INTEGERs need a hex notation? How about this? These INTEGERS represent addresses. Are addresses integers? I believe they are. The memory is a collection of addresses with consecutive numbers expressed with integers. So it is a relevant example.
(* Memory map; PO.System page 104 *) STACKSIZE* = 8000H; (* 32 kB. Was hardwired in Kernel.Init *) STACKORG* = 80000H; (* stackOrg = 524,288; half a megabyte. *) HEAPORG* = STACKORG; (* heapOrg = stackOrg *) FSoffset* = STACKORG; (* Not clear what it is *) MEMLIM* = 0E7EF0H; (* 1 MB minus 98,575 bytes of VRAM at the end*) VRAMORG* = 0E7F00H; (* start of memory-mapped display frame*) VRAMSIZE* = 1024*768 DIV 8; (* 1024 x 768 pixel, monocolor display frame*) -- -- -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-----Original Message----- From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of Joerg Sent: Saturday, 2 May 2020 8:54 PM To: ETH Oberon and related systems Subject: Re: [Oberon] Negative integer literals in Oberon
Yes and no. Addresses (as integers) do not exist in Oberon.
That is not true. Refer to Section 11.1 The Module System of the Oberon Language Report: Function procedures: Name: ADR(v) Argument types: any Result type: INTEGER Function: address of variable v Regards, Chris Burrows CFB Software https://www.astrobe.com
Read my last mail to Jan. Firstly, ADR is a low level function. All low level functions are a little bit stetching the strong typing rule Oberon normally has. So, if ADR reports back the INTEGER -1000, what does this mean? Does negative memory exist? No. Basically, ADR is defined as returning an INTEGER but in reality it passes back a value (ignoring its type) you can use for SYSTEM.GET/PUT. These low level functions ignore the sign and treat negative values as positive. Strictly speaking, those low level functions misuse the INTEGER construct to transport unsigned 32bit values, ignoring the sign bit. Very puristically speaking Jan is right: You should introduce a new base type eg BIT32 (not to use the word CARDINAL) where low level programmers can transport and manipulate 32 bits without having to worry about the sign bit. Another very radical aproach could be to use the type SET to play the role of this low level transport of unsigned 32 bit. Obviously, one would have to allow ROR and LSL on SETs and forget about this functionality on INTEGERs. I mean: if you think of it: rotating INTEGERs is pretty weird where the the INTEGER is negative and then positive again from bit rotation to bit rotation... makes no sense at all. br Jörg
Am 02.05.2020 um 14:28 schrieb Chris Burrows <chris@cfbsoftware.com>:
-----Original Message----- From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of Joerg Sent: Saturday, 2 May 2020 8:54 PM To: ETH Oberon and related systems Subject: Re: [Oberon] Negative integer literals in Oberon
Yes and no. Addresses (as integers) do not exist in Oberon.
That is not true. Refer to Section 11.1 The Module System of the Oberon Language Report:
Function procedures:
Name: ADR(v) Argument types: any Result type: INTEGER Function: address of variable v
Regards, Chris Burrows CFB Software https://www.astrobe.com
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Joerg:
With 32bit INTEGERs and max 24bit address bus of the RISC5 (max 16 MB) you don‘t run into this overflow problem. SYSTEM.GET/PUT can handle „negative“ values (=large positive values) correctly.
The 24 bit address bus is an artifact of this particular Verilog implementation file. The full address bus is 32 bit and it can easily be routed to the rest of the design and to the FPGA pins as well. If someone wanted to use an FPGA board with a large DRAM, then one can route all the bits. It would make sense after adding a cache to the CPU, which is a separate issue. Wojtek
On 04/28/20 10:03, Skulski, Wojciech wrote (in part):
Not quite so if you are serving some hardware.
Speaking of h/w and f/w, was the model helicopter flight control ever ported to Oberon-07? In Niklaus Wirth, "A Computer System for Model Helicopter Flight Control", Technical Memo Nr. 6: The Oberon Compiler for the Strong-ARM Processor, 1999, we find the following in the conclusion. An important advantage of designing one's own compiler is that specific, perhaps machine−dependent facilities can easily be incorporated. Such facilities are required if, for example, specific resources must be accessible, such as processor status register, memory management registers, or device interfaces. This is typically the case for embedded applications, which also require a predictable performance for real−time sensing and control. N.
Another proof that Oberon can be used for low level programming IF the compiler support is good enough. In case it is not sufficiently convenient, invent a special “Oberon” dialect. Creating dialects has pros and cons. Jörg Von: Oberon <oberon-bounces@lists.inf.ethz.ch> im Auftrag von Nemo Nusquam <cym224@gmail.com> Antworten an: ETH Oberon and related systems <oberon@lists.inf.ethz.ch> Datum: Dienstag, 28. April 2020 um 17:13 An: <oberon@lists.inf.ethz.ch> Betreff: Re: [Oberon] Negative integer literals in Oberon On 04/28/20 10:03, Skulski, Wojciech wrote (in part):
Not quite so if you are serving some hardware.
Speaking of h/w and f/w, was the model helicopter flight control ever ported to Oberon-07? In Niklaus Wirth, "A Computer System for Model Helicopter Flight Control", Technical Memo Nr. 6: The Oberon Compiler for the Strong-ARM Processor, 1999, we find the following in the conclusion. An important advantage of designing one's own compiler is that specific, perhaps machine−dependent facilities can easily be incorporated. Such facilities are required if, for example, specific resources must be accessible, such as processor status register, memory management registers, or device interfaces. This is typically the case for embedded applications, which also require a predictable performance for real−time sensing and control. N. -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
One of the new features in Oberon-SA was the base type RIDER, a special case of POINTER TO ARRAY RIDERs are useful, if the CPU offers special pre/post increment/decrement. In e.g. Oberon-07 you write something like VAR s, x, y: REAL; ra, rb, limit: POINTER TO REAL; BEGIN s := 0.0; ra := SYSTEM.ADR(a); rb:= SYSTEM.ADR(b); limit := ra + n*4; WHILE ra < limit DO SYSTEM.GET(ra, x); SYSTEM.GET(rb, y); s := x * y + s; INC(ra, 4) INC(rb, 4) END With RIDERS it looks like this: VAR s: REAL; ra, rb, limit: RIDER REAL; BEGIN s := 0.0; SET(ra, a, 0); SET(rb, b, 0); SET(limit, a, n); WHILE ra < limit DO s := ra^ * rb^ + s END; This is not existing in Oberon-07 as the RISC5 CPU does not offer the autoincrement feature. br Jörg Von: Oberon <oberon-bounces@lists.inf.ethz.ch> im Auftrag von Nemo Nusquam <cym224@gmail.com> Antworten an: ETH Oberon and related systems <oberon@lists.inf.ethz.ch> Datum: Dienstag, 28. April 2020 um 17:13 An: <oberon@lists.inf.ethz.ch> Betreff: Re: [Oberon] Negative integer literals in Oberon On 04/28/20 10:03, Skulski, Wojciech wrote (in part):
Not quite so if you are serving some hardware.
Speaking of h/w and f/w, was the model helicopter flight control ever ported to Oberon-07? In Niklaus Wirth, "A Computer System for Model Helicopter Flight Control", Technical Memo Nr. 6: The Oberon Compiler for the Strong-ARM Processor, 1999, we find the following in the conclusion. An important advantage of designing one's own compiler is that specific, perhaps machine−dependent facilities can easily be incorporated. Such facilities are required if, for example, specific resources must be accessible, such as processor status register, memory management registers, or device interfaces. This is typically the case for embedded applications, which also require a predictable performance for real−time sensing and control. N. -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Am 27.04.2020 um 22:10 schrieb Jörg:
ASSERT(0FFFFFFFFH = -1) (*require two's complement *)
On strict compilers this statement does not even compile as 0FFFFFFFFH is not a valid INTEGER.
Could somebody give me a good example, where INTEGERs need a hex notation?
Depends how exactly you define "INTEGERs" for. If I understand you correctly, in your opinion INTEGERs are the data type that is used for arithmetic operations without caring of the memory layout. In that case, it is quite common to give cryptographic parameters (e.g. RSA modulus or ECC curve parameters) in hexadecimal. Most of them (except the infamous 0x010001) will not fit into a 32-bit INTEGER, but still they are defined in Hex and you do arithmetic (multiplication, addition, exponentiation, modulus, modInverse) with them and hope that no overflow happens. AES keys or checksums are also often given in hex, but in this case the size and representation of the values is also fixed, so probably a purist would use a different data type than (BIG)INTEGER for it. Regards, Michael
Yes, one might see cryptographic as one case, where hex and calculation might fit. The first sentence in RFC1321 MD5 hash states: This document describes the MD5 message-digest algorithm. The algorithm takes as input a message of arbitrary length and produces as output a 128-bit "fingerprint" or "message digest" of the input. 128 bit output is very concrete presentation layer, and when mapping that to a program, most algorithms use deep implementation knowhow to optimally organize these bits in memory. What the algorithms are basically doing, they simulate calculations on a 128 bit bitfield, knowing that the useful entity they can work with on their machine is a 32 bitfield. So, principally they define BIT128 and they write a MODULE to make some fancy stuff on this type. With the help of the compiler SYSTEM.SIZE(INTEGER) you know the nbr of bytes, but you can only guess that the MSB is the sign. It's up to the compiler and the CPU to decide. If you look at the reference implementation in C you find context->state[0] = 0x67452301; context->state[1] = 0xefcdab89; The 0xefcdab89 has for sure nothing to do with an INTEGER. Even if you know that the compiler fits the sign bit into the MSB, the MSB of the expression 0xefcdab89 is not a sign. br Jörg Am 28.04.20, 14:51 schrieb "Oberon im Auftrag von Michael Schierl" <oberon-bounces@lists.inf.ethz.ch im Auftrag von schierlm@gmx.de>: Am 27.04.2020 um 22:10 schrieb Jörg: > >> ASSERT(0FFFFFFFFH = -1) (*require two's complement *) > > On strict compilers this statement does not even compile as 0FFFFFFFFH is not a valid INTEGER. > > Could somebody give me a good example, where INTEGERs need a hex notation? Depends how exactly you define "INTEGERs" for. If I understand you correctly, in your opinion INTEGERs are the data type that is used for arithmetic operations without caring of the memory layout. In that case, it is quite common to give cryptographic parameters (e.g. RSA modulus or ECC curve parameters) in hexadecimal. Most of them (except the infamous 0x010001) will not fit into a 32-bit INTEGER, but still they are defined in Hex and you do arithmetic (multiplication, addition, exponentiation, modulus, modInverse) with them and hope that no overflow happens. AES keys or checksums are also often given in hex, but in this case the size and representation of the values is also fixed, so probably a purist would use a different data type than (BIG)INTEGER for it. Regards, Michael -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Jörg пишет:
In Oberon-07, you can write b := 0FFFFFFFFFFFFH; i := 0FFFFFFFFFFFFH;
the results are: b = 255 and i = -1.
This is some kind of trash and ugliness. Why is overflow not detected? The fact that overflow is allowed and it is not caught in any way, generates carelessness and lack of accuracy. This was much better done in Oberon/Oberon-2. IMHO.
So I understand the H/L suffix enables the use of hex bit patterns for 32 and 64 bit integers, but does not address the issue for 8 or 16 bit integers.
Do you know if there is any way to enable e.g. FF for bytes, or FFFF for shortints? Or whether this was considered?
Thanks --
------------------------------------------------------------------------
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
This is exactly my point: to allow low level programming the compiler should ignore INTEGER overflow with hex notation. If you don’t, 90909090H will generate an error on 32bit machine what is NOT the expectation of a low level programmer. But you‘re right. Perhaps I overloaded the example to make my point with another one: I overdid it a little bit with the amount of Fs. What I wanted to say was i := 0FFFFFFFFH; should be allowed (but already this overflows normal two’s complement INTEGER arithmetic on a 32bit CPU) This case is not covered in the Oberon report as the semantic of the H operator is not well defined. Now, even if you ignored overflow, the compiler could still detect whether the hex string has more than 8 digits (ignoring leading 0s in the digit counting) Whether b := i; should generate a range check or not, is not defined in the Oberon report. If the compiler does not generate a runtime range check for b := i, then b := 300; should not generate a compile time error neither. br Jörg
Am 01.05.2020 um 19:17 schrieb Oleg N. Cher <allot@bk.ru>:
Jörg пишет:
In Oberon-07, you can write b := 0FFFFFFFFFFFFH; i := 0FFFFFFFFFFFFH; the results are: b = 255 and i = -1.
This is some kind of trash and ugliness. Why is overflow not detected?
The fact that overflow is allowed and it is not caught in any way, generates carelessness and lack of accuracy. This was much better done in Oberon/Oberon-2. IMHO.
So I understand the H/L suffix enables the use of hex bit patterns for 32 and 64 bit integers, but does not address the issue for 8 or 16 bit integers.
Do you know if there is any way to enable e.g. FF for bytes, or FFFF for shortints? Or whether this was considered?
Thanks --
------------------------------------------------------------------------ -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
On 2020-05-02 13:43, Joerg wrote:
If the compiler does not generate a runtime range check for b := i, then b := 300; should not generate a compile time error neither. Why not? For a byte variable b, the statement b := 300 is invalid according to the language report, so I think the compiler should reject it.
-- August
August In my point of view a compiler should be consistent. If he inserts code for runtime checks, I'm happy he checks also at compile time. If he doesn't generate code for runtime checks, there is no point to check at compile time as I could write i := 300; b := i; Typically, the code generated for b := i; is "store byte i -> b", no runtime check. br Jörg Am 02.05.20, 18:55 schrieb "Oberon im Auftrag von August Karlstrom" <oberon-bounces@lists.inf.ethz.ch im Auftrag von fusionfile@gmail.com>: On 2020-05-02 13:43, Joerg wrote: > If the compiler does not generate a runtime range check for b := i, > then b := 300; should not generate a compile time error neither. Why not? For a byte variable b, the statement b := 300 is invalid according to the language report, so I think the compiler should reject it. -- August -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
It is useful that Blackbox reports those compilation errors; it is less forgiving than many Oberon compilers. By not making assumptions it forces the programmer to really think about what he is trying to achieve. As far as I know there are no specific literal constants defined in Component Pascal for BYTE or SHORTINT values. If I were you I would implement two completely separate compilers. One that implements 32-bit INTEGERs and another that implements 64-bit INTEGERs and avoid mixing the two. In that way you can still conform to the Oberon Language report and not have to introduce any extensions. If you are concerned that a programmer might want to write code using the 64-bit compiler and then try to run it on the 32-bit compiler that is a problem for the programmer not you. If the programmer is writing code that he wants to run on both systems then he should separate any parts that are sensitive to the size of INTEGER and include assertions in those parts such as: ASSERT(SYSTEM.SIZE(INTEGER) = 8) to prevent it from accidentally being compiled for, and run on, the wrong platform. Regards, Chris Burrows CFB Software https://www.astrobe.com From: dave@brownsmeet.com [mailto:dave@brownsmeet.com] Sent: Sunday, 26 April 2020 11:23 PM To: chris@cfbsoftware.com; ETH Oberon and related systems Subject: Re: [Oberon] Negative integer literals in Oberon Thanks Chris, that's interesting. I explored some combinations in blackbox: MODULE Test; IMPORT Out; PROCEDURE Do*; VAR b: BYTE; s: SHORTINT; i: INTEGER; l: LONGINT; BEGIN i := 0FFFFFFFFH; Out.String("i := 0FFFFFFFFH: "); Out.Int(i,1); Out.Ln; l := 0FFFFFFFFH; Out.String("l := 0FFFFFFFFH: "); Out.Int(l,1); Out.Ln; l := 0FFFFFFFFL; Out.String("l := 0FFFFFFFFL: "); Out.Int(l,1); Out.Ln; l := 0FFFFFFFFFFFFFFFFL; Out.String("l := 0FFFFFFFFFFFFFFFFL: "); Out.Int(l,1); Out.Ln; (* The following all fail to compile with 'number too large': b := 0FFH; s := 0FFFFH; i := 0FFFFFFFFL; l := 0FFFFFFFFFFFFFFFFH; *) END Do; END Test. With results: i := 0FFFFFFFFH: -1 l := 0FFFFFFFFH: -1 l := 0FFFFFFFFL: 4294967295 l := 0FFFFFFFFFFFFFFFFL: -1 So I understand the H/L suffix enables the use of hex bit patterns for 32 and 64 bit integers, but does not address the issue for 8 or 16 bit integers. Do you know if there is any way to enable e.g. FF for bytes, or FFFF for shortints? Or whether this was considered? Thanks -- Dave.
I think there are a couple of conversations going on here, I'm trying to get straight what's being discussed. Arthur's original question was about passing 90909090H as a literal to a 32 bit INTEGER parameter, he found that Oberon 2013 supported it and VOC didn't. I chimed in because I had tried to support this in VOC but had not been able to. My response was an attempt to explain why VOC could not support it but I suspect I just confused the matter. VOC is an Oberon 2 compiler including support for SHORTINT, INTEGER and LONGINT, and for size conversions SHORT() and LONG(), and applies type compatibility rules as per the OBERON 2 language report. This is in contrast to the Oberon 2007/2013/2016 language which has a single integer size. (While it also has BYTE, it does not have the size compatibility rules of Oberon 2, nor does it have SHORT() and LONG(). This makes it a lot simpler.) I think I am seeing some level of consensus that having a single INTEGER size has benefits. (Aside - I worked a lot with the original CDC 6000 Pascal which had a single integer size of 60 bits. It worked vary well, I miss it. All arithmetic was done on 60 bit values. Additionally Pascal supported subrange types - these did not affect arithmetic, but they did 1) support compile time range and run time value checking 2) affect storage size - only when used in packed records. ) I think the answer to Arthur's original question depends on whether his goal is a single integer size compiler, or whether there is an intent to add support for e.g. Oberon 2's SHORTINT and LONGINT. The crux of the issue from my point of view is that supporting 90909090H as a 32 bit integer parameter is easy for a compiler like Oberon 2013 that supports a single INTEGER size, and not easy, or not possible for a compiler that supports OBERON 2's multiple integer sizes. (Component Pascal has the H vs L suffix workaround for 64 bit and 32 bit integers, but does not provide similar solutions for 16 or 8 bit integers.) -- Dave. On 2020-04-27 00:55, Chris Burrows wrote:
It is useful that Blackbox reports those compilation errors; it is less forgiving than many Oberon compilers. By not making assumptions it forces the programmer to really think about what he is trying to achieve.
As far as I know there are no specific literal constants defined in Component Pascal for BYTE or SHORTINT values.
If I were you I would implement two completely separate compilers. One that implements 32-bit INTEGERs and another that implements 64-bit INTEGERs and avoid mixing the two. In that way you can still conform to the Oberon Language report and not have to introduce any extensions. If you are concerned that a programmer might want to write code using the 64-bit compiler and then try to run it on the 32-bit compiler that is a problem for the programmer not you.
If the programmer is writing code that he wants to run on both systems then he should separate any parts that are sensitive to the size of INTEGER and include assertions in those parts such as:
ASSERT(SYSTEM.SIZE(INTEGER) = 8)
to prevent it from accidentally being compiled for, and run on, the wrong platform.
Regards,
Chris Burrows
CFB Software
/lists.inf.ethz.ch/mailman/listinfo/oberon [1]
Links: ------ [1] https://lists.inf.ethz.ch/mailman/listinfo/oberon
The main question is: why does somebody want to hand over 90909090H to an INTEGER value? What does 90909090H mean? Does the author mean 2’425’393’296 in decimal or does he mean -1’869‘574‘000 (assuming he knows how INTEGERs are implemented) If it is 2 billion, it will not fit in an 31bit INTEGER. If it is -1 billion, it will fit in an 31bit INTEGER. In short: if the compiler generates an error try -6F6F6F70H. It’s the same as 90909090H on a machine that implements INTEGERs with 31 bits and MSB as sign. br Jörg
Am 27.04.2020 um 18:50 schrieb dave@brownsmeet.com:
I think there are a couple of conversations going on here, I'm trying to get straight what's being discussed.
Arthur's original question was about passing 90909090H as a literal to a 32 bit INTEGER parameter, he found that Oberon 2013 supported it and VOC didn't.
I chimed in because I had tried to support this in VOC but had not been able to. My response was an attempt to explain why VOC could not support it but I suspect I just confused the matter.
VOC is an Oberon 2 compiler including support for SHORTINT, INTEGER and LONGINT, and for size conversions SHORT() and LONG(), and applies type compatibility rules as per the OBERON 2 language report.
This is in contrast to the Oberon 2007/2013/2016 language which has a single integer size. (While it also has BYTE, it does not have the size compatibility rules of Oberon 2, nor does it have SHORT() and LONG(). This makes it a lot simpler.)
I think I am seeing some level of consensus that having a single INTEGER size has benefits.
(Aside - I worked a lot with the original CDC 6000 Pascal which had a single integer size of 60 bits. It worked vary well, I miss it. All arithmetic was done on 60 bit values. Additionally Pascal supported subrange types - these did not affect arithmetic, but they did 1) support compile time range and run time value checking 2) affect storage size - only when used in packed records. )
I think the answer to Arthur's original question depends on whether his goal is a single integer size compiler, or whether there is an intent to add support for e.g. Oberon 2's SHORTINT and LONGINT.
The crux of the issue from my point of view is that supporting 90909090H as a 32 bit integer parameter is easy for a compiler like Oberon 2013 that supports a single INTEGER size, and not easy, or not possible for a compiler that supports OBERON 2's multiple integer sizes. (Component Pascal has the H vs L suffix workaround for 64 bit and 32 bit integers, but does not provide similar solutions for 16 or 8 bit integers.)
-- Dave.
On 2020-04-27 00:55, Chris Burrows wrote:
It is useful that Blackbox reports those compilation errors; it is less forgiving than many Oberon compilers. By not making assumptions it forces the programmer to really think about what he is trying to achieve.
As far as I know there are no specific literal constants defined in Component Pascal for BYTE or SHORTINT values.
If I were you I would implement two completely separate compilers. One that implements 32-bit INTEGERs and another that implements 64-bit INTEGERs and avoid mixing the two. In that way you can still conform to the Oberon Language report and not have to introduce any extensions. If you are concerned that a programmer might want to write code using the 64-bit compiler and then try to run it on the 32-bit compiler that is a problem for the programmer not you.
If the programmer is writing code that he wants to run on both systems then he should separate any parts that are sensitive to the size of INTEGER and include assertions in those parts such as:
ASSERT(SYSTEM.SIZE(INTEGER) = 8)
to prevent it from accidentally being compiled for, and run on, the wrong platform.
Regards,
Chris Burrows
CFB Software
/lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Dear Dave, After all, the question: is the literal 90909090H considered 64-bit unsigned or 32-bit signed? We have four solutions: 1. Consider it as a 64-bit literal, by context. And if we need to declare it as a 32-bit literal, we'll write it like this: myint := 90909090H - 100000000H; If we don't like writing code this way, we'll write it differently: myint := SYSTEM.VAL(INTEGER, 90909090H); , quite in the spirit of the Oberon paradigm. So, Artur, this is what I suggest you do in your compiler. 2. Consider it as a 32-bit literal. And for 64-bit use the postfix modifier like 0FFFFFFFFL, as in Component Pascal. Ofront+ also implements this option (in -C mode). 3. Pretend that we have all integer literals of the same size. In this case, all the hexadecimal digits allowed as a bitfield value of the literal. This way is implemented in most Oberon-07 compilers, which is justified by the lack of integer arithmetic of different bits in them. (BYTE is a non-arithmeric type in Oberon-07, and its size does not used in operations, always casted to INTEGER). 4. Explicitly specifying the constant type, as there was in Turbo Pascal: CONST MyConst = INTEGER(90909090H); As in Active Oberon, Delphi and Turbo Pascal. But then it is necessary to allow the same (note, non-system) casting in expressions - and rushed. I would suggest two ways. The non-system way: CONST MyConst = 90909090H - 100000000H; This will be our payment for the fact that there are no unsigned types in Oberon. This is a simplification that I think is very useful, but has a cost. So now we have all integer constants as signed numbers. And the system way. Ofront+ supports: myint := SYSTEM.VAL(INTEGER, 90909090H); And in constants too: CONST MyConst = SYSTEM.VAL(INTEGER, 90909090H); The disadvantage here is the compatibility problem, because old sources may contain literals that rely on the size of 32 bits. But this is mitigated by the fact that Ofront+ supports 5 Oberon dialects, and we can choose any of it at our discretion. dave@brownsmeet.com пишет:
To be clear - I would like VOC to allow myint32 := 90909090H, but VOC's support of 64 bit literals gets in the way.
My advice therefore is that if you never plan to support integers of more than 32 bits, go ahead and allow myint := 90909090H.
If you plan to add support for 64 bit integers later, you will need to work around the problems I described below. I cannot see how to do that, but I would love a solution.
-- Dave.
On 2020-04-26 10:14, Joerg wrote:
In earlier Oberon versions, variable integer size was supported: INTEGER and LONGINT. LONGINT is not officially supported in Oberon-07 but the compiler internally declares TYPE LONGINT = INTEGER. The concept of variable integer size is not supported in Oberon-07 anymore. Every INTEGER has one (implementation dependent) size, be it 16 or 32 or 64 or ...
Syntactically and conceptionally, negative literals do not exist. Only results of calculations can be negative as they are done signed per report. CONST neg = -1; is conceptionally the result of subtracting the literal 1 from 0, and NOT the literal -1.
If you use the hex suffix H to fill up the bits of the underlying INTEGER, you need to know the INTEGER size and are per definition in the grey, non-portable, implementation-dependent area of coding
If you use the hex suffix H to specify a (unsigned) 32 bit value for low level modules that work with 32 bits (on disc or memory or so) the size of the INTEGER does not matter (as long as it's 32 bits or larger of course) as your low level module have to treat the passed values MOD 100000000H anyhow.
br Jörg
Am 26.04.2020 um 10:25 schrieb Joerg <joerg.straube@iaeth.ch>:
Chris
1) b := i; is allowed, right? 2) b := i; does not generate a range check, right? 3) i := 511; b := i;
If 3) doesn't generate a range check, but you want to be compliant to the report, you implement the assignment as b := i MOD 256; as any value MOD 256 is between 0..255.
br Jörg
Am 26.04.2020 um 09:28 schrieb dave@brownsmeet.com:
((Lapsed) VOC maintainer here.)
In both VOC and Oberon 2013, integer literals are parsed in the symbol parser (VOC :OPS.Mod or 2013:ORS.MOD) and stored in the symbol table as signed integer values.
Later, during expression compilation, their size is determined by the magnitude of their signed integer value.
The difference between Oberon 2013 and VOC is the largest integer type, which is 32 bit on Oberon 2013 and 64 bit in VOC.
The special handling that allows a hex literal with top bit set to be treated as a signed value happens at the time the literal is parsed as a symbol independent of what context it is being used in. (Consider e.g. 'CONST mask = 90909090H' - CONST parsing does not know whether this constant will be used in a 64 bit, 32 bit, 16bit or other context.)
VOC and Oberon 2013 do both allow the hex special case top bit set parsing behaviour, the difference being the integer literal size.
Thus VOC accepts myint64 := 9090909090909090H because 9090909090909090H is parsed as a negative 64 bit signed integer.
But VOC does not accept myint32 := 90909090H because 90909090H is parsed as a positive 64 bit signed integer.
VOC has no way to parse 90909090H as a negative 32 bit signed integer.
- I did wonder about adding a further suffix letter to indicate the intended size, but I couldn't satisfy myself that any solution was simple enough to be easy to understand.
- Note that this is independent of VOC's -Ox compatibility setting: that sets the default INTEGER size, not integer literal size - integer literals always support the largest available integer size which is SYSTEM.INT64 aka HUGEINT.)
-- Dave
On 2020-04-25 22:52, Chris Burrows wrote:
It all depends on what size (i.e. number of bits) INTEGER is defined as on the system you are using as to what range of numbers are valid INTEGERs. Since 2011, the range of INTEGER values is no longer defined in the Language Report; it is implementation-dependent.
In the Project Oberon (2013) RISC5 compiler, INTEGER is 32 bit so 90909090H is a valid INTEGER. Maybe you used the default (-O2) option in VOC? If so, INTEGER is 16 bit so 90909090H would be too large. Make sure you are compiling with the VOC –OC option instead if you want INTEGER to be treated as a 32 bit quantity.
Note that 9090H would be a negative number on a 16-bit INTEGER system but a positive number on a 32-bit INTEGER system.
Regards,
Chris Burrows
CFB Software
*From:* Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] *On Behalf Of *Arthur Yefimov *Sent:* Sunday, 26 April 2020 12:38 AM *To:* oberon@lists.inf.ethz.ch *Subject:* [Oberon] Negative integer literals in Oberon
While developing the compiler[1], we got a question
whether it is possible to write the following:
PROCEDURE DWord(n: INTEGER); ... DWord (90909090H)
(where INTEGER is 32-bit).
Some compilers give an error (i.e. VOC), while this works in the
Project Oberon (2013) compiler. This would turn out to be quite convenient,
because the purpose of DWord in our code was to write 4 bytes to the file
given as INTEGER (using little-endian byte order).
DWord has the following implementation (module Generator[2]):
PROCEDURE DWord (n: INTEGER); BEGIN Files.Write (r, CHR (n MOD 100H)); Files.Write (r, CHR (n DIV 100H MOD 100H)); Files.Write (r, CHR (n DIV 10000H MOD 100H)); Files.Write (r, CHR (n DIV 1000000H)) END DWord;
The Oberon language report does not indicate that literal 90909090H
should be considered an error if INTEGER has 32 bits.
In this experiment, an online RISC emulator[3] was used.
References:
[1] https://github.com/kekcleader/oberon
[2] https://github.com/kekcleader/oberon/blob/master/Mod/Generator.Mod
[3] http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768 <http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768>
-- Oberon@lists.inf.ethz.ch <mailto:Oberon@lists.inf.ethz.ch> mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch <mailto:Oberon@lists.inf.ethz.ch> mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
------------------------------------------------------------------------
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
A crux with all these solution is: you have to know the register size of the underlying system, else your code will not even compile. ASSERTs to find the register size does not help, as 100000000H will not compile on a strict Oberon compiler on a 32bit machine. You need either an Oberon language clarification for hex nitation, or a compiler that ignores overflows when parsing hex notation. br Jörg
Am 01.05.2020 um 12:26 schrieb Oleg N. Cher <allot@bk.ru>:
Dear Dave,
After all, the question: is the literal 90909090H considered 64-bit unsigned or 32-bit signed? We have four solutions:
1. Consider it as a 64-bit literal, by context. And if we need to declare it as a 32-bit literal, we'll write it like this:
myint := 90909090H - 100000000H;
If we don't like writing code this way, we'll write it differently:
myint := SYSTEM.VAL(INTEGER, 90909090H);
, quite in the spirit of the Oberon paradigm. So, Artur, this is what I suggest you do in your compiler.
2. Consider it as a 32-bit literal. And for 64-bit use the postfix modifier like 0FFFFFFFFL, as in Component Pascal. Ofront+ also implements this option (in -C mode).
3. Pretend that we have all integer literals of the same size. In this case, all the hexadecimal digits allowed as a bitfield value of the literal. This way is implemented in most Oberon-07 compilers, which is justified by the lack of integer arithmetic of different bits in them. (BYTE is a non-arithmeric type in Oberon-07, and its size does not used in operations, always casted to INTEGER).
4. Explicitly specifying the constant type, as there was in Turbo Pascal:
CONST MyConst = INTEGER(90909090H);
As in Active Oberon, Delphi and Turbo Pascal. But then it is necessary to allow the same (note, non-system) casting in expressions - and rushed.
I would suggest two ways. The non-system way:
CONST MyConst = 90909090H - 100000000H;
This will be our payment for the fact that there are no unsigned types in Oberon. This is a simplification that I think is very useful, but has a cost. So now we have all integer constants as signed numbers.
And the system way. Ofront+ supports:
myint := SYSTEM.VAL(INTEGER, 90909090H);
And in constants too:
CONST MyConst = SYSTEM.VAL(INTEGER, 90909090H);
The disadvantage here is the compatibility problem, because old sources may contain literals that rely on the size of 32 bits. But this is mitigated by the fact that Ofront+ supports 5 Oberon dialects, and we can choose any of it at our discretion.
dave@brownsmeet.com пишет:
To be clear - I would like VOC to allow myint32 := 90909090H, but VOC's support of 64 bit literals gets in the way. My advice therefore is that if you never plan to support integers of more than 32 bits, go ahead and allow myint := 90909090H. If you plan to add support for 64 bit integers later, you will need to work around the problems I described below. I cannot see how to do that, but I would love a solution. -- Dave.
On 2020-04-26 10:14, Joerg wrote: In earlier Oberon versions, variable integer size was supported: INTEGER and LONGINT. LONGINT is not officially supported in Oberon-07 but the compiler internally declares TYPE LONGINT = INTEGER. The concept of variable integer size is not supported in Oberon-07 anymore. Every INTEGER has one (implementation dependent) size, be it 16 or 32 or 64 or ... Syntactically and conceptionally, negative literals do not exist. Only results of calculations can be negative as they are done signed per report. CONST neg = -1; is conceptionally the result of subtracting the literal 1 from 0, and NOT the literal -1. If you use the hex suffix H to fill up the bits of the underlying INTEGER, you need to know the INTEGER size and are per definition in the grey, non-portable, implementation-dependent area of coding If you use the hex suffix H to specify a (unsigned) 32 bit value for low level modules that work with 32 bits (on disc or memory or so) the size of the INTEGER does not matter (as long as it's 32 bits or larger of course) as your low level module have to treat the passed values MOD 100000000H anyhow.
br Jörg
Am 26.04.2020 um 10:25 schrieb Joerg <joerg.straube@iaeth.ch>:
Chris 1) b := i; is allowed, right? 2) b := i; does not generate a range check, right? 3) i := 511; b := i; If 3) doesn't generate a range check, but you want to be compliant to the report, you implement the assignment as b := i MOD 256; as any value MOD 256 is between 0..255. br Jörg
Am 26.04.2020 um 09:28 schrieb dave@brownsmeet.com:
((Lapsed) VOC maintainer here.)
In both VOC and Oberon 2013, integer literals are parsed in the symbol parser (VOC :OPS.Mod or 2013:ORS.MOD) and stored in the symbol table as signed integer values.
Later, during expression compilation, their size is determined by the magnitude of their signed integer value.
The difference between Oberon 2013 and VOC is the largest integer type, which is 32 bit on Oberon 2013 and 64 bit in VOC.
The special handling that allows a hex literal with top bit set to be treated as a signed value happens at the time the literal is parsed as a symbol independent of what context it is being used in. (Consider e.g. 'CONST mask = 90909090H' - CONST parsing does not know whether this constant will be used in a 64 bit, 32 bit, 16bit or other context.)
VOC and Oberon 2013 do both allow the hex special case top bit set parsing behaviour, the difference being the integer literal size.
Thus VOC accepts myint64 := 9090909090909090H because 9090909090909090H is parsed as a negative 64 bit signed integer.
But VOC does not accept myint32 := 90909090H because 90909090H is parsed as a positive 64 bit signed integer. VOC has no way to parse 90909090H as a negative 32 bit signed integer.
- I did wonder about adding a further suffix letter to indicate the intended size, but I couldn't satisfy myself that any solution was simple enough to be easy to understand.
- Note that this is independent of VOC's -Ox compatibility setting: that sets the default INTEGER size, not integer literal size - integer literals always support the largest available integer size which is SYSTEM.INT64 aka HUGEINT.)
-- Dave
On 2020-04-25 22:52, Chris Burrows wrote:
It all depends on what size (i.e. number of bits) INTEGER is defined as on the system you are using as to what range of numbers are valid INTEGERs. Since 2011, the range of INTEGER values is no longer defined in the Language Report; it is implementation-dependent.
In the Project Oberon (2013) RISC5 compiler, INTEGER is 32 bit so 90909090H is a valid INTEGER. Maybe you used the default (-O2) option in VOC? If so, INTEGER is 16 bit so 90909090H would be too large. Make sure you are compiling with the VOC –OC option instead if you want INTEGER to be treated as a 32 bit quantity.
Note that 9090H would be a negative number on a 16-bit INTEGER system but a positive number on a 32-bit INTEGER system.
Regards,
Chris Burrows
CFB Software
*From:* Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] *On Behalf Of *Arthur Yefimov *Sent:* Sunday, 26 April 2020 12:38 AM *To:* oberon@lists.inf.ethz.ch *Subject:* [Oberon] Negative integer literals in Oberon
While developing the compiler[1], we got a question
whether it is possible to write the following:
PROCEDURE DWord(n: INTEGER); ... DWord (90909090H)
(where INTEGER is 32-bit).
Some compilers give an error (i.e. VOC), while this works in the
Project Oberon (2013) compiler. This would turn out to be quite convenient,
because the purpose of DWord in our code was to write 4 bytes to the file
given as INTEGER (using little-endian byte order).
DWord has the following implementation (module Generator[2]):
PROCEDURE DWord (n: INTEGER); BEGIN Files.Write (r, CHR (n MOD 100H)); Files.Write (r, CHR (n DIV 100H MOD 100H)); Files.Write (r, CHR (n DIV 10000H MOD 100H)); Files.Write (r, CHR (n DIV 1000000H)) END DWord;
The Oberon language report does not indicate that literal 90909090H
should be considered an error if INTEGER has 32 bits.
In this experiment, an online RISC emulator[3] was used.
References:
[1] https://github.com/kekcleader/oberon
[2] https://github.com/kekcleader/oberon/blob/master/Mod/Generator.Mod
[3] http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768 <http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768>
-- Oberon@lists.inf.ethz.ch <mailto:Oberon@lists.inf.ethz.ch> mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch <mailto:Oberon@lists.inf.ethz.ch> mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Hi Oleg, Re 1 - Personally I really dislike '90909090H - 100000000H' because it is more confusing to read than the alternatives. Instead of SYSTEM.VAL(INTEGER, 90909090H) you may prefer SHORT(90909090H). It's a bit more concise, avoids the dependency on SYSTEM, and works whatever the 32 bit integer type is called (i.e. INTEGER or LONGINT). (If you are adding support for LONGINT then you will almost certainly be adding support for SHORT() and LONG()). --- Re 2 - Yes, this fixes 32 bit hex literals. But it doesn't fix 16 or 8 bit hex literals. I think these should be considered too. It's also difficult to explain the use of the H vs L suffix - the description in the component pascal documentation is correct but very confusing. --- Re 3 - Yes, in this case (assuming you have added support for 64 bit integers) all arithmetic is 64 bit, and assignments to smaller int variables are simply clipped at the time they are stored. You don't need SHORT() or LONG(). If you do this I'd like to see a compilation option to do range checking at run time on every store to < 64 bits. --- Re 4 - Oberon already has casting under another name (type guard) for extended types - with the type name in brackets following the variable name. Maybe keep the syntax similar. -- Dave. On 2020-05-01 11:26, Oleg N. Cher wrote:
Dear Dave,
After all, the question: is the literal 90909090H considered 64-bit unsigned or 32-bit signed? We have four solutions:
1. Consider it as a 64-bit literal, by context. And if we need to declare it as a 32-bit literal, we'll write it like this:
myint := 90909090H - 100000000H;
If we don't like writing code this way, we'll write it differently:
myint := SYSTEM.VAL(INTEGER, 90909090H);
, quite in the spirit of the Oberon paradigm. So, Artur, this is what I suggest you do in your compiler.
2. Consider it as a 32-bit literal. And for 64-bit use the postfix modifier like 0FFFFFFFFL, as in Component Pascal. Ofront+ also implements this option (in -C mode).
3. Pretend that we have all integer literals of the same size. In this case, all the hexadecimal digits allowed as a bitfield value of the literal. This way is implemented in most Oberon-07 compilers, which is justified by the lack of integer arithmetic of different bits in them. (BYTE is a non-arithmeric type in Oberon-07, and its size does not used in operations, always casted to INTEGER).
4. Explicitly specifying the constant type, as there was in Turbo Pascal:
CONST MyConst = INTEGER(90909090H);
As in Active Oberon, Delphi and Turbo Pascal. But then it is necessary to allow the same (note, non-system) casting in expressions - and rushed.
I would suggest two ways. The non-system way:
CONST MyConst = 90909090H - 100000000H;
This will be our payment for the fact that there are no unsigned types in Oberon. This is a simplification that I think is very useful, but has a cost. So now we have all integer constants as signed numbers.
And the system way. Ofront+ supports:
myint := SYSTEM.VAL(INTEGER, 90909090H);
And in constants too:
CONST MyConst = SYSTEM.VAL(INTEGER, 90909090H);
The disadvantage here is the compatibility problem, because old sources may contain literals that rely on the size of 32 bits. But this is mitigated by the fact that Ofront+ supports 5 Oberon dialects, and we can choose any of it at our discretion.
SHORT(90909090H) should generate an error, as 2.4 billion is big for a 32 bit integer. Jörg
Am 01.05.2020 um 18:46 schrieb dave@brownsmeet.com:
Hi Oleg,
Re 1 - Personally I really dislike '90909090H - 100000000H' because it is more confusing to read than the alternatives.
Instead of SYSTEM.VAL(INTEGER, 90909090H) you may prefer SHORT(90909090H). It's a bit more concise, avoids the dependency on SYSTEM, and works whatever the 32 bit integer type is called (i.e. INTEGER or LONGINT).
(If you are adding support for LONGINT then you will almost certainly be adding support for SHORT() and LONG()).
---
Re 2 - Yes, this fixes 32 bit hex literals. But it doesn't fix 16 or 8 bit hex literals. I think these should be considered too. It's also difficult to explain the use of the H vs L suffix - the description in the component pascal documentation is correct but very confusing.
---
Re 3 - Yes, in this case (assuming you have added support for 64 bit integers) all arithmetic is 64 bit, and assignments to smaller int variables are simply clipped at the time they are stored. You don't need SHORT() or LONG().
If you do this I'd like to see a compilation option to do range checking at run time on every store to < 64 bits.
---
Re 4 - Oberon already has casting under another name (type guard) for extended types - with the type name in brackets following the variable name. Maybe keep the syntax similar.
-- Dave.
On 2020-05-01 11:26, Oleg N. Cher wrote: Dear Dave, After all, the question: is the literal 90909090H considered 64-bit unsigned or 32-bit signed? We have four solutions: 1. Consider it as a 64-bit literal, by context. And if we need to declare it as a 32-bit literal, we'll write it like this: myint := 90909090H - 100000000H; If we don't like writing code this way, we'll write it differently: myint := SYSTEM.VAL(INTEGER, 90909090H); , quite in the spirit of the Oberon paradigm. So, Artur, this is what I suggest you do in your compiler. 2. Consider it as a 32-bit literal. And for 64-bit use the postfix modifier like 0FFFFFFFFL, as in Component Pascal. Ofront+ also implements this option (in -C mode). 3. Pretend that we have all integer literals of the same size. In this case, all the hexadecimal digits allowed as a bitfield value of the literal. This way is implemented in most Oberon-07 compilers, which is justified by the lack of integer arithmetic of different bits in them. (BYTE is a non-arithmeric type in Oberon-07, and its size does not used in operations, always casted to INTEGER). 4. Explicitly specifying the constant type, as there was in Turbo Pascal: CONST MyConst = INTEGER(90909090H); As in Active Oberon, Delphi and Turbo Pascal. But then it is necessary to allow the same (note, non-system) casting in expressions - and rushed. I would suggest two ways. The non-system way: CONST MyConst = 90909090H - 100000000H; This will be our payment for the fact that there are no unsigned types in Oberon. This is a simplification that I think is very useful, but has a cost. So now we have all integer constants as signed numbers. And the system way. Ofront+ supports: myint := SYSTEM.VAL(INTEGER, 90909090H); And in constants too: CONST MyConst = SYSTEM.VAL(INTEGER, 90909090H); The disadvantage here is the compatibility problem, because old sources may contain literals that rely on the size of 32 bits. But this is mitigated by the fact that Ofront+ supports 5 Oberon dialects, and we can choose any of it at our discretion. -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
I think the root cause of this discussion is that the Oberon language does not clearly define the semantic of the H suffix. Let me try to explain what I mean. In my point of view we have to differentiate two conceptionally different layers. Let me call it the red Oberon layer, as defined by the Oberon report. the blue implementation layer, as defined by the target CPU and the Oberon compiler. In the red Oberon layer you might write CONST Int = -1869574000; Real = -5.702072E-29; Let’s assume the compiler has a 32bit CPU as target. The CPU represents INTEGERs as two’s complement (that’s quite common but not a given) then the red Oberon value -1869574000 is represented by the blue 32bit pattern 90909090. If the floating point unit chooses to represent REALs as IEEE754 (that’s quite common but not a given) the red Oberon value -5.702072E-29 is represented by the blue 32 bit pattern 90909090. With these two layers in mind, the H suffix can have two totally different semantics is H purely working in the red Oberon layer and just be another notation to define an INTEGER? Then, the decimal notation 2425393296 and hex notation 90909090H are absolutely identical. Or does H do a type cast of the blue 32bit pattern 90909090 into a red INTEGER value -1869574000? Looking at the Oberon-07 report the semantic of H looks more like a). NW’s Oberon-07 compiler behaves like b). Another hint that NW most probably had semantic b) in mind is the fact that a suffix R exists. 90909090R type casts the 32 bit pattern 90909090 into a REAL. The semantic of H should be better described in the Oberon report. br Jörg Am 01.05.20, 20:00 schrieb "Jörg" <joerg.straube@iaeth.ch>: SHORT(90909090H) should generate an error, as 2.4 billion is big for a 32 bit integer. Jörg > Am 01.05.2020 um 18:46 schrieb dave@brownsmeet.com: > > Hi Oleg, > > Re 1 - Personally I really dislike '90909090H - 100000000H' because it is more confusing to read than the alternatives. > > Instead of SYSTEM.VAL(INTEGER, 90909090H) you may prefer SHORT(90909090H). It's a bit more concise, avoids the dependency on SYSTEM, and works whatever the 32 bit integer type is called (i.e. INTEGER or LONGINT). > > (If you are adding support for LONGINT then you will almost certainly be adding support for SHORT() and LONG()). > > --- > > Re 2 - Yes, this fixes 32 bit hex literals. But it doesn't fix 16 or 8 bit hex literals. I think these should be considered too. It's also difficult to explain the use of the H vs L suffix - the description in the component pascal documentation is correct but very confusing. > > --- > > Re 3 - Yes, in this case (assuming you have added support for 64 bit integers) all arithmetic is 64 bit, and assignments to smaller int variables are simply clipped at the time they are stored. You don't need SHORT() or LONG(). > > If you do this I'd like to see a compilation option to do range checking at run time on every store to < 64 bits. > > --- > > Re 4 - Oberon already has casting under another name (type guard) for extended types - with the type name in brackets following the variable name. Maybe keep the syntax similar. > > > -- Dave. > > >> On 2020-05-01 11:26, Oleg N. Cher wrote: >> Dear Dave, >> After all, the question: is the literal 90909090H considered 64-bit >> unsigned or 32-bit signed? We have four solutions: >> 1. Consider it as a 64-bit literal, by context. And if we need to >> declare it as a 32-bit literal, we'll write it like this: >> myint := 90909090H - 100000000H; >> If we don't like writing code this way, we'll write it differently: >> myint := SYSTEM.VAL(INTEGER, 90909090H); >> , quite in the spirit of the Oberon paradigm. So, Artur, this is what >> I suggest you do in your compiler. >> 2. Consider it as a 32-bit literal. And for 64-bit use the postfix >> modifier like 0FFFFFFFFL, as in Component Pascal. Ofront+ also >> implements this option (in -C mode). >> 3. Pretend that we have all integer literals of the same size. In this >> case, all the hexadecimal digits allowed as a bitfield value of the >> literal. This way is implemented in most Oberon-07 compilers, which is >> justified by the lack of integer arithmetic of different bits in them. >> (BYTE is a non-arithmeric type in Oberon-07, and its size does not >> used in operations, always casted to INTEGER). >> 4. Explicitly specifying the constant type, as there was in Turbo Pascal: >> CONST MyConst = INTEGER(90909090H); >> As in Active Oberon, Delphi and Turbo Pascal. But then it is necessary >> to allow the same (note, non-system) casting in expressions - and >> rushed. >> I would suggest two ways. The non-system way: >> CONST MyConst = 90909090H - 100000000H; >> This will be our payment for the fact that there are no unsigned types >> in Oberon. This is a simplification that I think is very useful, but >> has a cost. So now we have all integer constants as signed numbers. >> And the system way. Ofront+ supports: >> myint := SYSTEM.VAL(INTEGER, 90909090H); >> And in constants too: >> CONST MyConst = SYSTEM.VAL(INTEGER, 90909090H); >> The disadvantage here is the compatibility problem, because old >> sources may contain literals that rely on the size of 32 bits. But >> this is mitigated by the fact that Ofront+ supports 5 Oberon dialects, >> and we can choose any of it at our discretion. > -- > Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems > https://lists.inf.ethz.ch/mailman/listinfo/oberon
So the thought experiment whether we can live without unsigned integers must be answered with a resounding "No". q. e. d. J. On Sat, 2 May 2020, 08:23 Jörg, <joerg.straube@iaeth.ch> wrote:
I think the root cause of this discussion is that the Oberon language does not clearly define the semantic of the H suffix.
Let me try to explain what I mean. In my point of view we have to differentiate two conceptionally different layers. Let me call it
- the red Oberon layer, as defined by the Oberon report. - the blue implementation layer, as defined by the target CPU and the Oberon compiler.
In the red Oberon layer you might write
CONST
Int = -1869574000;
Real = -5.702072E-29;
Let’s assume the compiler has a 32bit CPU as target. The CPU represents INTEGERs as two’s complement (that’s quite common but not a given) then the red Oberon value -1869574000 is represented by the blue 32bit pattern 90909090.
If the floating point unit chooses to represent REALs as IEEE754 (that’s quite common but not a given) the red Oberon value -5.702072E-29 is represented by the blue 32 bit pattern 90909090.
With these two layers in mind, the *H* suffix can have two totally different semantics
1. is H purely working in the red Oberon layer and just be another notation to define an INTEGER? Then, the decimal notation 2425393296 and hex notation 90909090H are absolutely identical. 2. Or does H do a type cast of the blue 32bit pattern 90909090 into a red INTEGER value -1869574000?
Looking at the Oberon-07 report the semantic of H looks more like a).
NW’s Oberon-07 compiler behaves like b). Another hint that NW most probably had semantic b) in mind is the fact that a suffix R exists. 90909090R type casts the 32 bit pattern 90909090 into a REAL.
The semantic of H should be better described in the Oberon report.
br
Jörg
Am 01.05.20, 20:00 schrieb "Jörg" <joerg.straube@iaeth.ch>:
SHORT(90909090H) should generate an error, as 2.4 billion is big for a 32 bit integer.
Jörg
> Am 01.05.2020 um 18:46 schrieb dave@brownsmeet.com:
>
> Hi Oleg,
>
> Re 1 - Personally I really dislike '90909090H - 100000000H' because it is more confusing to read than the alternatives.
>
> Instead of SYSTEM.VAL(INTEGER, 90909090H) you may prefer SHORT(90909090H). It's a bit more concise, avoids the dependency on SYSTEM, and works whatever the 32 bit integer type is called (i.e. INTEGER or LONGINT).
>
> (If you are adding support for LONGINT then you will almost certainly be adding support for SHORT() and LONG()).
>
> ---
>
> Re 2 - Yes, this fixes 32 bit hex literals. But it doesn't fix 16 or 8 bit hex literals. I think these should be considered too. It's also difficult to explain the use of the H vs L suffix - the description in the component pascal documentation is correct but very confusing.
>
> ---
>
> Re 3 - Yes, in this case (assuming you have added support for 64 bit integers) all arithmetic is 64 bit, and assignments to smaller int variables are simply clipped at the time they are stored. You don't need SHORT() or LONG().
>
> If you do this I'd like to see a compilation option to do range checking at run time on every store to < 64 bits.
>
> ---
>
> Re 4 - Oberon already has casting under another name (type guard) for extended types - with the type name in brackets following the variable name. Maybe keep the syntax similar.
>
>
> -- Dave.
>
>
>> On 2020-05-01 11:26, Oleg N. Cher wrote:
>> Dear Dave,
>> After all, the question: is the literal 90909090H considered 64-bit
>> unsigned or 32-bit signed? We have four solutions:
>> 1. Consider it as a 64-bit literal, by context. And if we need to
>> declare it as a 32-bit literal, we'll write it like this:
>> myint := 90909090H - 100000000H;
>> If we don't like writing code this way, we'll write it differently:
>> myint := SYSTEM.VAL(INTEGER, 90909090H);
>> , quite in the spirit of the Oberon paradigm. So, Artur, this is what
>> I suggest you do in your compiler.
>> 2. Consider it as a 32-bit literal. And for 64-bit use the postfix
>> modifier like 0FFFFFFFFL, as in Component Pascal. Ofront+ also
>> implements this option (in -C mode).
>> 3. Pretend that we have all integer literals of the same size. In this
>> case, all the hexadecimal digits allowed as a bitfield value of the
>> literal. This way is implemented in most Oberon-07 compilers, which is
>> justified by the lack of integer arithmetic of different bits in them.
>> (BYTE is a non-arithmeric type in Oberon-07, and its size does not
>> used in operations, always casted to INTEGER).
>> 4. Explicitly specifying the constant type, as there was in Turbo Pascal:
>> CONST MyConst = INTEGER(90909090H);
>> As in Active Oberon, Delphi and Turbo Pascal. But then it is necessary
>> to allow the same (note, non-system) casting in expressions - and
>> rushed.
>> I would suggest two ways. The non-system way:
>> CONST MyConst = 90909090H - 100000000H;
>> This will be our payment for the fact that there are no unsigned types
>> in Oberon. This is a simplification that I think is very useful, but
>> has a cost. So now we have all integer constants as signed numbers.
>> And the system way. Ofront+ supports:
>> myint := SYSTEM.VAL(INTEGER, 90909090H);
>> And in constants too:
>> CONST MyConst = SYSTEM.VAL(INTEGER, 90909090H);
>> The disadvantage here is the compatibility problem, because old
>> sources may contain literals that rely on the size of 32 bits. But
>> this is mitigated by the fact that Ofront+ supports 5 Oberon dialects,
>> and we can choose any of it at our discretion.
> --
> Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems
> https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Jan I first thought so as well. But re-introducing CARDINALs is not one of my favorites (and Chris‘ neither😊) The question arises: where do we need those „CARDINALs“? In my point only in low level programming, HW drivers and cryptography. Oberon declares quite some SYSTEM functions with INTEGER as parameters. Looking at the carefully, the semantic is not really INTEGERs in the pure sense. These low level functions know they are handling low level things and can interprete internally INTEGERs as CARDINALs. Eg the famous SYSTEM.GET(-64) knows that the INTEGER address -64 has to be taken at the top end of memory. So, from the point on where you have a value in your register/variable, you can well live with INTEGER as type for it. Let‘s look at the problem how to get a value into a register. Setting a variable is the result of an arithmetic expression, a type conversion or a literal. So the only point where you really need the „CARDINAL“ behaviour, is when stating constant literals in your code. So instead of defining a whole new type (with all pros and cons) don’t you think the clarification of the value cast operator H is enough? Jörg
Am 02.05.2020 um 11:32 schrieb Jan de Kruyf <jan.de.kruyf@gmail.com>:
So the thought experiment whether we can live without unsigned integers must be answered with a resounding "No".
q. e. d.
J.
On Sat, 2 May 2020, 08:23 Jörg, <joerg.straube@iaeth.ch> wrote: I think the root cause of this discussion is that the Oberon language does not clearly define the semantic of the H suffix.
Let me try to explain what I mean. In my point of view we have to differentiate two conceptionally different layers. Let me call it
the red Oberon layer, as defined by the Oberon report. the blue implementation layer, as defined by the target CPU and the Oberon compiler.
In the red Oberon layer you might write
CONST
Int = -1869574000;
Real = -5.702072E-29;
Let’s assume the compiler has a 32bit CPU as target. The CPU represents INTEGERs as two’s complement (that’s quite common but not a given) then the red Oberon value -1869574000 is represented by the blue 32bit pattern 90909090.
If the floating point unit chooses to represent REALs as IEEE754 (that’s quite common but not a given) the red Oberon value -5.702072E-29 is represented by the blue 32 bit pattern 90909090.
With these two layers in mind, the H suffix can have two totally different semantics
is H purely working in the red Oberon layer and just be another notation to define an INTEGER? Then, the decimal notation 2425393296 and hex notation 90909090H are absolutely identical. Or does H do a type cast of the blue 32bit pattern 90909090 into a red INTEGER value -1869574000?
Looking at the Oberon-07 report the semantic of H looks more like a).
NW’s Oberon-07 compiler behaves like b). Another hint that NW most probably had semantic b) in mind is the fact that a suffix R exists. 90909090R type casts the 32 bit pattern 90909090 into a REAL.
The semantic of H should be better described in the Oberon report.
br
Jörg
Am 01.05.20, 20:00 schrieb "Jörg" <joerg.straube@iaeth.ch>:
SHORT(90909090H) should generate an error, as 2.4 billion is big for a 32 bit integer.
Jörg
> Am 01.05.2020 um 18:46 schrieb dave@brownsmeet.com:
>
> Hi Oleg,
>
> Re 1 - Personally I really dislike '90909090H - 100000000H' because it is more confusing to read than the alternatives.
>
> Instead of SYSTEM.VAL(INTEGER, 90909090H) you may prefer SHORT(90909090H). It's a bit more concise, avoids the dependency on SYSTEM, and works whatever the 32 bit integer type is called (i.e. INTEGER or LONGINT).
>
> (If you are adding support for LONGINT then you will almost certainly be adding support for SHORT() and LONG()).
>
> ---
>
> Re 2 - Yes, this fixes 32 bit hex literals. But it doesn't fix 16 or 8 bit hex literals. I think these should be considered too. It's also difficult to explain the use of the H vs L suffix - the description in the component pascal documentation is correct but very confusing.
>
> ---
>
> Re 3 - Yes, in this case (assuming you have added support for 64 bit integers) all arithmetic is 64 bit, and assignments to smaller int variables are simply clipped at the time they are stored. You don't need SHORT() or LONG().
>
> If you do this I'd like to see a compilation option to do range checking at run time on every store to < 64 bits.
>
> ---
>
> Re 4 - Oberon already has casting under another name (type guard) for extended types - with the type name in brackets following the variable name. Maybe keep the syntax similar.
>
>
> -- Dave.
>
>
>> On 2020-05-01 11:26, Oleg N. Cher wrote:
>> Dear Dave,
>> After all, the question: is the literal 90909090H considered 64-bit
>> unsigned or 32-bit signed? We have four solutions:
>> 1. Consider it as a 64-bit literal, by context. And if we need to
>> declare it as a 32-bit literal, we'll write it like this:
>> myint := 90909090H - 100000000H;
>> If we don't like writing code this way, we'll write it differently:
>> myint := SYSTEM.VAL(INTEGER, 90909090H);
>> , quite in the spirit of the Oberon paradigm. So, Artur, this is what
>> I suggest you do in your compiler.
>> 2. Consider it as a 32-bit literal. And for 64-bit use the postfix
>> modifier like 0FFFFFFFFL, as in Component Pascal. Ofront+ also
>> implements this option (in -C mode).
>> 3. Pretend that we have all integer literals of the same size. In this
>> case, all the hexadecimal digits allowed as a bitfield value of the
>> literal. This way is implemented in most Oberon-07 compilers, which is
>> justified by the lack of integer arithmetic of different bits in them.
>> (BYTE is a non-arithmeric type in Oberon-07, and its size does not
>> used in operations, always casted to INTEGER).
>> 4. Explicitly specifying the constant type, as there was in Turbo Pascal:
>> CONST MyConst = INTEGER(90909090H);
>> As in Active Oberon, Delphi and Turbo Pascal. But then it is necessary
>> to allow the same (note, non-system) casting in expressions - and
>> rushed.
>> I would suggest two ways. The non-system way:
>> CONST MyConst = 90909090H - 100000000H;
>> This will be our payment for the fact that there are no unsigned types
>> in Oberon. This is a simplification that I think is very useful, but
>> has a cost. So now we have all integer constants as signed numbers.
>> And the system way. Ofront+ supports:
>> myint := SYSTEM.VAL(INTEGER, 90909090H);
>> And in constants too:
>> CONST MyConst = SYSTEM.VAL(INTEGER, 90909090H);
>> The disadvantage here is the compatibility problem, because old
>> sources may contain literals that rely on the size of 32 bits. But
>> this is mitigated by the fact that Ofront+ supports 5 Oberon dialects,
>> and we can choose any of it at our discretion.
> --
> Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems
> https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
in other words you are saying that that integer constant then takes on a specific property, which is "cardinal". Or to say it another way "it has a specific aspect". In the same way Guy's C interface declarations have a specific aspect not found in regular procedure declarations. And by the way on thinking about that issue : he might be right and I might have been wrong, but that is a discussion for another day. There is another place where one needs to assign a specific aspect: in the case of immutable addresses of hardware, so the optimizer does not optimize them into oblivion. Then there is a passed variable from the hw-interface layer, out of our control, that should be read only because the hardware changes it all the time. All this then makes me think that we should be able to clearly assign an abnormal aspect to certain entities as is done in Ada. CONST jim = 9999 WITH CARDINAL; PROCEDURE Jerry (....) WITH "C"; VAR Jock : INTEGER WITH READONLY; In this way It is clear that it does not belong to the regular language and you could compile with it or without it. In any case this whole discussion points to a much deeper cultural problem in the Oberon community. Let me do some more thinking about that before I shoot off my mouth. But for sure the present situation is very debilitating. j. On Sat, May 2, 2020 at 2:27 PM Joerg <joerg.straube@iaeth.ch> wrote:
Jan
I first thought so as well. But re-introducing CARDINALs is not one of my favorites (and Chris‘ neither😊)
The question arises: where do we need those „CARDINALs“? In my point only in low level programming, HW drivers and cryptography. Oberon declares quite some SYSTEM functions with INTEGER as parameters. Looking at the carefully, the semantic is not really INTEGERs in the pure sense. These low level functions know they are handling low level things and can interprete internally INTEGERs as CARDINALs. Eg the famous SYSTEM.GET(-64) knows that the INTEGER address -64 has to be taken at the top end of memory.
So, from the point on where you have a value in your register/variable, you can well live with INTEGER as type for it. Let‘s look at the problem how to get a value into a register. Setting a variable is the result of an arithmetic expression, a type conversion or a literal. So the only point where you really need the „CARDINAL“ behaviour, is when stating constant literals in your code.
So instead of defining a whole new type (with all pros and cons) don’t you think the clarification of the value cast operator H is enough?
Jörg
Am 02.05.2020 um 11:32 schrieb Jan de Kruyf <jan.de.kruyf@gmail.com>:
So the thought experiment whether we can live without unsigned integers must be answered with a resounding "No".
q. e. d.
J.
On Sat, 2 May 2020, 08:23 Jörg, <joerg.straube@iaeth.ch> wrote:
I think the root cause of this discussion is that the Oberon language does not clearly define the semantic of the H suffix.
Let me try to explain what I mean. In my point of view we have to differentiate two conceptionally different layers. Let me call it
- the red Oberon layer, as defined by the Oberon report. - the blue implementation layer, as defined by the target CPU and the Oberon compiler.
In the red Oberon layer you might write
CONST
Int = -1869574000;
Real = -5.702072E-29;
Let’s assume the compiler has a 32bit CPU as target. The CPU represents INTEGERs as two’s complement (that’s quite common but not a given) then the red Oberon value -1869574000 is represented by the blue 32bit pattern 90909090.
If the floating point unit chooses to represent REALs as IEEE754 (that’s quite common but not a given) the red Oberon value -5.702072E-29 is represented by the blue 32 bit pattern 90909090.
With these two layers in mind, the *H* suffix can have two totally different semantics
1. is H purely working in the red Oberon layer and just be another notation to define an INTEGER? Then, the decimal notation 2425393296 and hex notation 90909090H are absolutely identical. 2. Or does H do a type cast of the blue 32bit pattern 90909090 into a red INTEGER value -1869574000?
Looking at the Oberon-07 report the semantic of H looks more like a).
NW’s Oberon-07 compiler behaves like b). Another hint that NW most probably had semantic b) in mind is the fact that a suffix R exists. 90909090R type casts the 32 bit pattern 90909090 into a REAL.
The semantic of H should be better described in the Oberon report.
br
Jörg
Am 01.05.20, 20:00 schrieb "Jörg" <joerg.straube@iaeth.ch>:
SHORT(90909090H) should generate an error, as 2.4 billion is big for a 32 bit integer.
Jörg
> Am 01.05.2020 um 18:46 schrieb dave@brownsmeet.com:
>
> Hi Oleg,
>
> Re 1 - Personally I really dislike '90909090H - 100000000H' because it is more confusing to read than the alternatives.
>
> Instead of SYSTEM.VAL(INTEGER, 90909090H) you may prefer SHORT(90909090H). It's a bit more concise, avoids the dependency on SYSTEM, and works whatever the 32 bit integer type is called (i.e. INTEGER or LONGINT).
>
> (If you are adding support for LONGINT then you will almost certainly be adding support for SHORT() and LONG()).
>
> ---
>
> Re 2 - Yes, this fixes 32 bit hex literals. But it doesn't fix 16 or 8 bit hex literals. I think these should be considered too. It's also difficult to explain the use of the H vs L suffix - the description in the component pascal documentation is correct but very confusing.
>
> ---
>
> Re 3 - Yes, in this case (assuming you have added support for 64 bit integers) all arithmetic is 64 bit, and assignments to smaller int variables are simply clipped at the time they are stored. You don't need SHORT() or LONG().
>
> If you do this I'd like to see a compilation option to do range checking at run time on every store to < 64 bits.
>
> ---
>
> Re 4 - Oberon already has casting under another name (type guard) for extended types - with the type name in brackets following the variable name. Maybe keep the syntax similar.
>
>
> -- Dave.
>
>
>> On 2020-05-01 11:26, Oleg N. Cher wrote:
>> Dear Dave,
>> After all, the question: is the literal 90909090H considered 64-bit
>> unsigned or 32-bit signed? We have four solutions:
>> 1. Consider it as a 64-bit literal, by context. And if we need to
>> declare it as a 32-bit literal, we'll write it like this:
>> myint := 90909090H - 100000000H;
>> If we don't like writing code this way, we'll write it differently:
>> myint := SYSTEM.VAL(INTEGER, 90909090H);
>> , quite in the spirit of the Oberon paradigm. So, Artur, this is what
>> I suggest you do in your compiler.
>> 2. Consider it as a 32-bit literal. And for 64-bit use the postfix
>> modifier like 0FFFFFFFFL, as in Component Pascal. Ofront+ also
>> implements this option (in -C mode).
>> 3. Pretend that we have all integer literals of the same size. In this
>> case, all the hexadecimal digits allowed as a bitfield value of the
>> literal. This way is implemented in most Oberon-07 compilers, which is
>> justified by the lack of integer arithmetic of different bits in them.
>> (BYTE is a non-arithmeric type in Oberon-07, and its size does not
>> used in operations, always casted to INTEGER).
>> 4. Explicitly specifying the constant type, as there was in Turbo Pascal:
>> CONST MyConst = INTEGER(90909090H);
>> As in Active Oberon, Delphi and Turbo Pascal. But then it is necessary
>> to allow the same (note, non-system) casting in expressions - and
>> rushed.
>> I would suggest two ways. The non-system way:
>> CONST MyConst = 90909090H - 100000000H;
>> This will be our payment for the fact that there are no unsigned types
>> in Oberon. This is a simplification that I think is very useful, but
>> has a cost. So now we have all integer constants as signed numbers.
>> And the system way. Ofront+ supports:
>> myint := SYSTEM.VAL(INTEGER, 90909090H);
>> And in constants too:
>> CONST MyConst = SYSTEM.VAL(INTEGER, 90909090H);
>> The disadvantage here is the compatibility problem, because old
>> sources may contain literals that rely on the size of 32 bits. But
>> this is mitigated by the fact that Ofront+ supports 5 Oberon dialects,
>> and we can choose any of it at our discretion.
> --
> Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems
> https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Dave Let’s assume we are on a 64bit CPU and we have two integer types: INTEGER (32bit) and LONGINT (64bit) In my point of view, you would need two value cast operators H and L to cover those cases. But in additiion to the H and L thingy, the compiler might make a difference between SHORT(long) and SYSTEM.VAL(INTEGER, long) SHORT could generate a runtime error. SYSTEM.VAL most probably not as it is low level and most compilers implement this just as long MOD 100000000L br Jörg
Am 01.05.2020 um 18:46 schrieb dave@brownsmeet.com:
Hi Oleg,
Re 1 - Personally I really dislike '90909090H - 100000000H' because it is more confusing to read than the alternatives.
Instead of SYSTEM.VAL(INTEGER, 90909090H) you may prefer SHORT(90909090H). It's a bit more concise, avoids the dependency on SYSTEM, and works whatever the 32 bit integer type is called (i.e. INTEGER or LONGINT).
(If you are adding support for LONGINT then you will almost certainly be adding support for SHORT() and LONG()).
---
Re 2 - Yes, this fixes 32 bit hex literals. But it doesn't fix 16 or 8 bit hex literals. I think these should be considered too. It's also difficult to explain the use of the H vs L suffix - the description in the component pascal documentation is correct but very confusing.
---
Re 3 - Yes, in this case (assuming you have added support for 64 bit integers) all arithmetic is 64 bit, and assignments to smaller int variables are simply clipped at the time they are stored. You don't need SHORT() or LONG().
If you do this I'd like to see a compilation option to do range checking at run time on every store to < 64 bits.
---
Re 4 - Oberon already has casting under another name (type guard) for extended types - with the type name in brackets following the variable name. Maybe keep the syntax similar.
-- Dave.
On 2020-05-01 11:26, Oleg N. Cher wrote: Dear Dave, After all, the question: is the literal 90909090H considered 64-bit unsigned or 32-bit signed? We have four solutions: 1. Consider it as a 64-bit literal, by context. And if we need to declare it as a 32-bit literal, we'll write it like this: myint := 90909090H - 100000000H; If we don't like writing code this way, we'll write it differently: myint := SYSTEM.VAL(INTEGER, 90909090H); , quite in the spirit of the Oberon paradigm. So, Artur, this is what I suggest you do in your compiler. 2. Consider it as a 32-bit literal. And for 64-bit use the postfix modifier like 0FFFFFFFFL, as in Component Pascal. Ofront+ also implements this option (in -C mode). 3. Pretend that we have all integer literals of the same size. In this case, all the hexadecimal digits allowed as a bitfield value of the literal. This way is implemented in most Oberon-07 compilers, which is justified by the lack of integer arithmetic of different bits in them. (BYTE is a non-arithmeric type in Oberon-07, and its size does not used in operations, always casted to INTEGER). 4. Explicitly specifying the constant type, as there was in Turbo Pascal: CONST MyConst = INTEGER(90909090H); As in Active Oberon, Delphi and Turbo Pascal. But then it is necessary to allow the same (note, non-system) casting in expressions - and rushed. I would suggest two ways. The non-system way: CONST MyConst = 90909090H - 100000000H; This will be our payment for the fact that there are no unsigned types in Oberon. This is a simplification that I think is very useful, but has a cost. So now we have all integer constants as signed numbers. And the system way. Ofront+ supports: myint := SYSTEM.VAL(INTEGER, 90909090H); And in constants too: CONST MyConst = SYSTEM.VAL(INTEGER, 90909090H); The disadvantage here is the compatibility problem, because old sources may contain literals that rely on the size of 32 bits. But this is mitigated by the fact that Ofront+ supports 5 Oberon dialects, and we can choose any of it at our discretion. -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Yes, that seems good. Personally I am surprised there is not more support in compilers (of all languages) for generating run time integer overflow checking code. In my Pascal days I got into the habit of using subranges rather than INTEGER pretty much everywhere, and caught quite a few mistakes. It seems highly likely that I have not stopped making such mistakes since using languages without integer range checking :-(. Re suffix characters and the number of integer types - it seems to me that we should solve for more sizes - there is a lot of data that is composed of sequences of 8 bits, and 16 bit data exists too. If our solution involves suffices at all, then I would like to see HEX suffixes available for all 4 sizes. Cheers -- Dave. On 2020-05-02 12:59, Joerg wrote:
Dave
Let’s assume we are on a 64bit CPU and we have two integer types: INTEGER (32bit) and LONGINT (64bit)
In my point of view, you would need two value cast operators H and L to cover those cases.
But in additiion to the H and L thingy, the compiler might make a difference between SHORT(long) and SYSTEM.VAL(INTEGER, long)
SHORT could generate a runtime error. SYSTEM.VAL most probably not as it is low level and most compilers implement this just as long MOD 100000000L
br Jörg /oberon
Dave For smaller values than the size of your CPU register it‘s not needed, as you always can enfoce what you want by using normal INTEGER arithmetic. b := FFH; word16 := 0CAFEH; or to be absolutely sure (although not needed) b := FFH MOD 100H; word16 := 0CAFEH MOD 10000H; All those literals are legal INTEGERs on a 32 CPU. But you can‘t use the same for values completely filling yor register that are no valid INTEGERs anymore. i := 0CAFEBABEH; is not going to work, as CAFEBABE needs more than 31 bit to be represented as positive INTEGER. br Jörg
Am 02.05.2020 um 16:19 schrieb dave@brownsmeet.com:
Yes, that seems good.
Personally I am surprised there is not more support in compilers (of all languages) for generating run time integer overflow checking code.
In my Pascal days I got into the habit of using subranges rather than INTEGER pretty much everywhere, and caught quite a few mistakes. It seems highly likely that I have not stopped making such mistakes since using languages without integer range checking :-(.
Re suffix characters and the number of integer types - it seems to me that we should solve for more sizes - there is a lot of data that is composed of sequences of 8 bits, and 16 bit data exists too. If our solution involves suffices at all, then I would like to see HEX suffixes available for all 4 sizes.
Cheers -- Dave.
On 2020-05-02 12:59, Joerg wrote: Dave Let’s assume we are on a 64bit CPU and we have two integer types: INTEGER (32bit) and LONGINT (64bit) In my point of view, you would need two value cast operators H and L to cover those cases. But in additiion to the H and L thingy, the compiler might make a difference between SHORT(long) and SYSTEM.VAL(INTEGER, long) SHORT could generate a runtime error. SYSTEM.VAL most probably not as it is low level and most compilers implement this just as long MOD 100000000L br Jörg /oberon
While I agree on Oberon 2007+, this is not sufficient for original Oberon2 systems with SHORTINTs and (signed) BYTES. It's not an issue on Oberon2007+ because of the freer integer type compatibility rules. e.g. myshort := 0FFFFH doesn't work on multi-size oberon2 compilers because 65535 is bigger than MAX(SHORTINT) which is 32767. And using MOD to restrict the size doesn't work on such compilers because the size of the result of an arithmetic operation such as MOD that has a INTEGER parameters is INTEGER. There is no special case handling for MOD: the compiler doesn't look at the right hand argument, see if it is a constant, and work out how many bits that constant would require. (It could, but I don't know of any that do, and it's not covered in the language report, or in system specific documents that I have seen.) The more we discuss this the more I'm convinced that the compiler needs to be more sophisticated: rather than hex constants being rapidly treated as signed integers, they need a distinct intermediate representation that can be taken through the expression evaluation handling to the point where we can make a valid decision on whether they are an acceptable size. But - this is quite a lot of special case code for compilers that support multiple sizes of integer. And actually it is the support of multiple sizes of integer that is the real can of worms here, hex literal issues are just one issue. So to put the cat amongst the pigeons again :-), I have seen no better solution to multiple integer sizes than Wirth and Knudsen's original Pascal 6000 compiler (circa 1975) and its support for integer subranges. The BYTE/SHORTINT/INTEGER/LONGINT approach is for me the worst solution, it has neither the simplicity of a single INTEGER size, nor does it avoid the complexities of subranges, while at the same time introducing more special cases and limitations. Hey ho -- Dave. On 2020-05-02 16:12, Joerg wrote:
Dave
For smaller values than the size of your CPU register it‘s not needed, as you always can enfoce what you want by using normal INTEGER arithmetic.
b := FFH; word16 := 0CAFEH;
or to be absolutely sure (although not needed)
b := FFH MOD 100H; word16 := 0CAFEH MOD 10000H;
All those literals are legal INTEGERs on a 32 CPU.
But you can‘t use the same for values completely filling yor register that are no valid INTEGERs anymore.
i := 0CAFEBABEH; is not going to work, as CAFEBABE needs more than 31 bit to be represented as positive INTEGER.
br Jörg
So to put the cat amongst the pigeons again :-)...
Yes very well said.😇 And all the birds are long ago in the highest tree they could find. And the cat sits licking itself in the sun: "It didn't happen anyway!" So do I understand then that, to solve the multiple type size issue (which is basically a hardware issue) you propose sub-ranges (which are an aid to software development)?? I would not like to teach that to a 14 year old, Dave. My oldest son did very well with the Wirth and Reiser book at the time. It taught him reading and clear thinking. But this would have been a bridge too far because the primary concepts are fudged On Sat, May 2, 2020 at 6:06 PM <dave@brownsmeet.com> wrote:
While I agree on Oberon 2007+, this is not sufficient for original Oberon2 systems with SHORTINTs and (signed) BYTES. It's not an issue on Oberon2007+ because of the freer integer type compatibility rules.
e.g. myshort := 0FFFFH
doesn't work on multi-size oberon2 compilers because 65535 is bigger than MAX(SHORTINT) which is 32767.
And using MOD to restrict the size doesn't work on such compilers because the size of the result of an arithmetic operation such as MOD that has a INTEGER parameters is INTEGER. There is no special case handling for MOD: the compiler doesn't look at the right hand argument, see if it is a constant, and work out how many bits that constant would require.
(It could, but I don't know of any that do, and it's not covered in the language report, or in system specific documents that I have seen.)
The more we discuss this the more I'm convinced that the compiler needs to be more sophisticated: rather than hex constants being rapidly treated as signed integers, they need a distinct intermediate representation that can be taken through the expression evaluation handling to the point where we can make a valid decision on whether they are an acceptable size.
But - this is quite a lot of special case code for compilers that support multiple sizes of integer.
And actually it is the support of multiple sizes of integer that is the real can of worms here, hex literal issues are just one issue.
So to put the cat amongst the pigeons again :-), I have seen no better solution to multiple integer sizes than Wirth and Knudsen's original Pascal 6000 compiler (circa 1975) and its support for integer subranges.
The BYTE/SHORTINT/INTEGER/LONGINT approach is for me the worst solution, it has neither the simplicity of a single INTEGER size, nor does it avoid the complexities of subranges, while at the same time introducing more special cases and limitations.
Hey ho -- Dave.
On 2020-05-02 16:12, Joerg wrote:
Dave
For smaller values than the size of your CPU register it‘s not needed, as you always can enfoce what you want by using normal INTEGER arithmetic.
b := FFH; word16 := 0CAFEH;
or to be absolutely sure (although not needed)
b := FFH MOD 100H; word16 := 0CAFEH MOD 10000H;
All those literals are legal INTEGERs on a 32 CPU.
But you can‘t use the same for values completely filling yor register that are no valid INTEGERs anymore.
i := 0CAFEBABEH; is not going to work, as CAFEBABE needs more than 31 bit to be represented as positive INTEGER.
br Jörg -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
This theme and others that are particularly amenable to right-first-time software are at the core of Ada. The effort up front is higher, but there's a body of evidence that suggests this up front effort is not wasted. Adding it to Oberon-X would certainly defeat the purpose of a small language. Whether teaching the precepts of right-first-time software is suitable for teenagers is one question, but teenagers as a rule have no comprehension of the risks of leaky software. Arnim On Sat, 2 May 2020 21:40:52 +0200 Jan de Kruyf <jan.de.kruyf@gmail.com> wrote:
So to put the cat amongst the pigeons again :-)...
Yes very well said.😇 And all the birds are long ago in the highest tree they could find. And the cat sits licking itself in the sun: "It didn't happen anyway!"
So do I understand then that, to solve the multiple type size issue (which is basically a hardware issue) you propose sub-ranges (which are an aid to software development)??
I would not like to teach that to a 14 year old, Dave. My oldest son did very well with the Wirth and Reiser book at the time. It taught him reading and clear thinking. But this would have been a bridge too far because the primary concepts are fudged
On Sat, May 2, 2020 at 6:06 PM <dave@brownsmeet.com> wrote:
While I agree on Oberon 2007+, this is not sufficient for original Oberon2 systems with SHORTINTs and (signed) BYTES. It's not an issue on Oberon2007+ because of the freer integer type compatibility rules.
e.g. myshort := 0FFFFH
doesn't work on multi-size oberon2 compilers because 65535 is bigger than MAX(SHORTINT) which is 32767.
And using MOD to restrict the size doesn't work on such compilers because the size of the result of an arithmetic operation such as MOD that has a INTEGER parameters is INTEGER. There is no special case handling for MOD: the compiler doesn't look at the right hand argument, see if it is a constant, and work out how many bits that constant would require.
(It could, but I don't know of any that do, and it's not covered in the language report, or in system specific documents that I have seen.)
The more we discuss this the more I'm convinced that the compiler needs to be more sophisticated: rather than hex constants being rapidly treated as signed integers, they need a distinct intermediate representation that can be taken through the expression evaluation handling to the point where we can make a valid decision on whether they are an acceptable size.
But - this is quite a lot of special case code for compilers that support multiple sizes of integer.
And actually it is the support of multiple sizes of integer that is the real can of worms here, hex literal issues are just one issue.
So to put the cat amongst the pigeons again :-), I have seen no better solution to multiple integer sizes than Wirth and Knudsen's original Pascal 6000 compiler (circa 1975) and its support for integer subranges.
The BYTE/SHORTINT/INTEGER/LONGINT approach is for me the worst solution, it has neither the simplicity of a single INTEGER size, nor does it avoid the complexities of subranges, while at the same time introducing more special cases and limitations.
Hey ho -- Dave.
On 2020-05-02 16:12, Joerg wrote:
Dave
For smaller values than the size of your CPU register it‘s not needed, as you always can enfoce what you want by using normal INTEGER arithmetic.
b := FFH; word16 := 0CAFEH;
or to be absolutely sure (although not needed)
b := FFH MOD 100H; word16 := 0CAFEH MOD 10000H;
All those literals are legal INTEGERs on a 32 CPU.
But you can‘t use the same for values completely filling yor register that are no valid INTEGERs anymore.
i := 0CAFEBABEH; is not going to work, as CAFEBABE needs more than 31 bit to be represented as positive INTEGER.
br Jörg -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
-- Arnim Littek <arnim@actrix.gen.nz>
On 2020-04-26 11:14, Joerg wrote:
In earlier Oberon versions, variable integer size was supported: INTEGER and LONGINT. LONGINT is not officially supported in Oberon-07 but the compiler internally declares TYPE LONGINT = INTEGER. The concept of variable integer size is not supported in Oberon-07 anymore. Every INTEGER has one (implementation dependent) size, be it 16 or 32 or 64 or ...
In principle a compiler could use arbitrary-precision arithmetic for the numeric types.
If you use the hex suffix H to fill up the bits of the underlying INTEGER, you need to know the INTEGER size and are per definition in the grey, non-portable, implementation-dependent area of coding
As far as I understand, the large hexadecimal literals we are discussing here are typically used for addresses in low-level modules, and when implementing such a module you need to assume a few things about the implementation and the system, so general portability is not to be expected anyway. -- August
Am 26.04.2020 um 13:52 schrieb August Karlstrom <fusionfile@gmail.com>:
On 2020-04-26 11:14, Joerg wrote:
In earlier Oberon versions, variable integer size was supported: INTEGER and LONGINT. LONGINT is not officially supported in Oberon-07 but the compiler internally declares TYPE LONGINT = INTEGER. The concept of variable integer size is not supported in Oberon-07 anymore. Every INTEGER has one (implementation dependent) size, be it 16 or 32 or 64 or ...
In principle a compiler could use arbitrary-precision arithmetic for the numeric types.
Right. My main topic is that the literal 90909090H is not negative, it defines the lowest 32 bits of a value. It happens to be interpreted as negative integer, if the implementation uses a presentation layer to represent INTEGERs with 32 bit and uses the MSB to mark negative integers. That’s - as you pointed out - not a given.
If you use the hex suffix H to fill up the bits of the underlying INTEGER, you need to know the INTEGER size and are per definition in the grey, non-portable, implementation-dependent area of coding
As far as I understand, the large hexadecimal literals we are discussing here are typically used for addresses in low-level modules, and when implementing such a module you need to assume a few things about the implementation and the system, so general portability is not to be expected anyway.
The crux of the H suffix is, that it has semantically two flavours: one that just represents an INTEGER in a hexadecimal notation; instead of 30, write 1EH for whatever reason this might be needed. So its usage is linked to INTEGERs. The other flavours is rather for low level programming where you need certain bit mask, filters, bit constellation. Has nothing to do with INTEGERs, just a collection of bits. Sometimes SETs could be used here. Puristically, this H usage should be in SYSTEM to clearly mark its non-portablility Jörg
From: Joerg [mailto:joerg.straube@iaeth.ch] Sent: Sunday, 26 April 2020 5:55 PM To: ETH Oberon and related systems Cc: chris@cfbsoftware.com Subject: Re: [Oberon] Negative integer literals in Oberon Chris 1) b := i; is allowed, right? Yes – but the value of i must be in the range 0..255 for the result to be predictable. 2) b := i; does not generate a range check, right? Not necessarily. An implementer is not required to generate a range check, but equally they are not prohibited from generating a range check either. 3) i := 511; b := i; If 3) doesn’t generate a range check, but you want to be compliant to the report, you implement the assignment as b := i MOD 256; as any value MOD 256 is between 0..255. The behaviour is not specified in the report so there is no question of compliance or non-compliance. Hence, the resulting value of b is undefined / unpredictable. Any programmer who assumes a particular result in that case is making a mistake. However, the implementer of the compiler is not required by the report to alert him to that mistake - but he can do if he wants to. If the programmer is competent there is no problem because he can write his code in such a way that he gets the answer that he want. If he expects values of i to be outside the range 0..255 and he wants b to be equal to i MOD 256 then he should explicitly code it as: b := i MOD 256 then there is no doubt about what the result will be no matter what the compiler implementer has decided to do.. br Jörg Am 26.04.2020 um 09:28 schrieb dave@brownsmeet.com <mailto:dave@brownsmeet.com> : ((Lapsed) VOC maintainer here.) In both VOC and Oberon 2013, integer literals are parsed in the symbol parser (VOC :OPS.Mod or 2013:ORS.MOD) and stored in the symbol table as signed integer values. Later, during expression compilation, their size is determined by the magnitude of their signed integer value. The difference between Oberon 2013 and VOC is the largest integer type, which is 32 bit on Oberon 2013 and 64 bit in VOC. The special handling that allows a hex literal with top bit set to be treated as a signed value happens at the time the literal is parsed as a symbol independent of what context it is being used in. (Consider e.g. 'CONST mask = 90909090H' - CONST parsing does not know whether this constant will be used in a 64 bit, 32 bit, 16bit or other context.) VOC and Oberon 2013 do both allow the hex special case top bit set parsing behaviour, the difference being the integer literal size. Thus VOC accepts myint64 := 9090909090909090H because 9090909090909090H is parsed as a negative 64 bit signed integer. But VOC does not accept myint32 := 90909090H because 90909090H is parsed as a positive 64 bit signed integer. VOC has no way to parse 90909090H as a negative 32 bit signed integer. - I did wonder about adding a further suffix letter to indicate the intended size, but I couldn't satisfy myself that any solution was simple enough to be easy to understand. - Note that this is independent of VOC's -Ox compatibility setting: that sets the default INTEGER size, not integer literal size - integer literals always support the largest available integer size which is SYSTEM.INT64 aka HUGEINT.) -- Dave On 2020-04-25 22:52, Chris Burrows wrote: It all depends on what size (i.e. number of bits) INTEGER is defined as on the system you are using as to what range of numbers are valid INTEGERs. Since 2011, the range of INTEGER values is no longer defined in the Language Report; it is implementation-dependent. In the Project Oberon (2013) RISC5 compiler, INTEGER is 32 bit so 90909090H is a valid INTEGER. Maybe you used the default (-O2) option in VOC? If so, INTEGER is 16 bit so 90909090H would be too large. Make sure you are compiling with the VOC –OC option instead if you want INTEGER to be treated as a 32 bit quantity. Note that 9090H would be a negative number on a 16-bit INTEGER system but a positive number on a 32-bit INTEGER system. Regards, Chris Burrows CFB Software https://www.astrobe.com From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of Arthur Yefimov Sent: Sunday, 26 April 2020 12:38 AM To: oberon@lists.inf.ethz.ch <mailto:oberon@lists.inf.ethz.ch> Subject: [Oberon] Negative integer literals in Oberon While developing the compiler[1], we got a question whether it is possible to write the following: PROCEDURE DWord(n: INTEGER); ... DWord (90909090H) (where INTEGER is 32-bit). Some compilers give an error (i.e. VOC), while this works in the Project Oberon (2013) compiler. This would turn out to be quite convenient, because the purpose of DWord in our code was to write 4 bytes to the file given as INTEGER (using little-endian byte order). DWord has the following implementation (module Generator[2]): PROCEDURE DWord (n: INTEGER); BEGIN Files.Write (r, CHR (n MOD 100H)); Files.Write (r, CHR (n DIV 100H MOD 100H)); Files.Write (r, CHR (n DIV 10000H MOD 100H)); Files.Write (r, CHR (n DIV 1000000H)) END DWord; The Oberon language report does not indicate that literal 90909090H should be considered an error if INTEGER has 32 bits. In this experiment, an online RISC emulator[3] was used. References: [1] https://github.com/kekcleader/oberon [2] https://github.com/kekcleader/oberon/blob/master/Mod/Generator.Mod [3] http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage <http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768> &width=1024&height=768 -- Oberon@lists.inf.ethz.ch <mailto:Oberon@lists.inf.ethz.ch> mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch <mailto:Oberon@lists.inf.ethz.ch> mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
Agreed The report is not always 100% clear. If this happens, I try to find other sources to get the intention of the construct. My preferred sources are other NW publications, like his compiler source and his RISC architecture. Looking at these facts a) NW introduced byte addressing mode in RISC-3 b) BYTE are the integers between 0 and 255 c) The type BYTE is compatible with the type INTEGER, and vice-versa. Led to the (perhaps wrong) conclusion that assignments to BYTE are mapped to the byte addressing mode of the processor. The byte addressing mode works MOD 256 by definition. There are basically two cases you have to consider Firstly: b := expression; (* store*) The expression on the righthand side can be any integer value. c) tells us that I can store any value into b. And b) tells us that the as a result of this assignment to byte b, b is between 0..255. The compiler source tells us, that the intention of this assigment case was, to just map the assignment to the „store byte“ instruction, that works MOD 256 by definition Secondly: i := f(b) (* load *) Whenever we use a byte value on the righthand side as part of an expression, b) tells us that the value to be taken shall be interpreted as 0..255. And c) tells us that a byte value is allowed to be assigned to an integer variable. br Jörg
Am 26.04.2020 um 12:53 schrieb Chris Burrows <chris@cfbsoftware.com>:
From: Joerg [mailto:joerg.straube@iaeth.ch] Sent: Sunday, 26 April 2020 5:55 PM To: ETH Oberon and related systems Cc: chris@cfbsoftware.com Subject: Re: [Oberon] Negative integer literals in Oberon
Chris
1) b := i; is allowed, right?
Yes – but the value of i must be in the range 0..255 for the result to be predictable.
2) b := i; does not generate a range check, right?
Not necessarily. An implementer is not required to generate a range check, but equally they are not prohibited from generating a range check either.
3) i := 511; b := i;
If 3) doesn’t generate a range check, but you want to be compliant to the report, you implement the assignment as b := i MOD 256; as any value MOD 256 is between 0..255.
The behaviour is not specified in the report so there is no question of compliance or non-compliance. Hence, the resulting value of b is undefined / unpredictable. Any programmer who assumes a particular result in that case is making a mistake. However, the implementer of the compiler is not required by the report to alert him to that mistake - but he can do if he wants to.
If the programmer is competent there is no problem because he can write his code in such a way that he gets the answer that he want. If he expects values of i to be outside the range 0..255 and he wants b to be equal to i MOD 256 then he should explicitly code it as:
b := i MOD 256
then there is no doubt about what the result will be no matter what the compiler implementer has decided to do..
br Jörg
Am 26.04.2020 um 09:28 schrieb dave@brownsmeet.com:
((Lapsed) VOC maintainer here.)
In both VOC and Oberon 2013, integer literals are parsed in the symbol parser (VOC :OPS.Mod or 2013:ORS.MOD) and stored in the symbol table as signed integer values.
Later, during expression compilation, their size is determined by the magnitude of their signed integer value.
The difference between Oberon 2013 and VOC is the largest integer type, which is 32 bit on Oberon 2013 and 64 bit in VOC.
The special handling that allows a hex literal with top bit set to be treated as a signed value happens at the time the literal is parsed as a symbol independent of what context it is being used in. (Consider e.g. 'CONST mask = 90909090H' - CONST parsing does not know whether this constant will be used in a 64 bit, 32 bit, 16bit or other context.)
VOC and Oberon 2013 do both allow the hex special case top bit set parsing behaviour, the difference being the integer literal size.
Thus VOC accepts myint64 := 9090909090909090H because 9090909090909090H is parsed as a negative 64 bit signed integer.
But VOC does not accept myint32 := 90909090H because 90909090H is parsed as a positive 64 bit signed integer.
VOC has no way to parse 90909090H as a negative 32 bit signed integer.
- I did wonder about adding a further suffix letter to indicate the intended size, but I couldn't satisfy myself that any solution was simple enough to be easy to understand.
- Note that this is independent of VOC's -Ox compatibility setting: that sets the default INTEGER size, not integer literal size - integer literals always support the largest available integer size which is SYSTEM.INT64 aka HUGEINT.)
-- Dave
On 2020-04-25 22:52, Chris Burrows wrote:
It all depends on what size (i.e. number of bits) INTEGER is defined as on the system you are using as to what range of numbers are valid INTEGERs. Since 2011, the range of INTEGER values is no longer defined in the Language Report; it is implementation-dependent.
In the Project Oberon (2013) RISC5 compiler, INTEGER is 32 bit so 90909090H is a valid INTEGER. Maybe you used the default (-O2) option in VOC? If so, INTEGER is 16 bit so 90909090H would be too large. Make sure you are compiling with the VOC –OC option instead if you want INTEGER to be treated as a 32 bit quantity.
Note that 9090H would be a negative number on a 16-bit INTEGER system but a positive number on a 32-bit INTEGER system.
Regards, Chris Burrows CFB Software https://www.astrobe.com
From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of Arthur Yefimov Sent: Sunday, 26 April 2020 12:38 AM To: oberon@lists.inf.ethz.ch Subject: [Oberon] Negative integer literals in Oberon
While developing the compiler[1], we got a question whether it is possible to write the following:
PROCEDURE DWord(n: INTEGER); ... DWord (90909090H)
(where INTEGER is 32-bit).
Some compilers give an error (i.e. VOC), while this works in the Project Oberon (2013) compiler. This would turn out to be quite convenient, because the purpose of DWord in our code was to write 4 bytes to the file given as INTEGER (using little-endian byte order).
DWord has the following implementation (module Generator[2]):
PROCEDURE DWord (n: INTEGER); BEGIN Files.Write (r, CHR (n MOD 100H)); Files.Write (r, CHR (n DIV 100H MOD 100H)); Files.Write (r, CHR (n DIV 10000H MOD 100H)); Files.Write (r, CHR (n DIV 1000000H)) END DWord;
The Oberon language report does not indicate that literal 90909090H should be considered an error if INTEGER has 32 bits.
In this experiment, an online RISC emulator[3] was used.
References: [1] https://github.com/kekcleader/oberon [2] https://github.com/kekcleader/oberon/blob/master/Mod/Generator.Mod [3] http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768
-- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
A few years ago I was included in a private email discussion. I take the liberty of reproducing part of it here as I believe the concepts are crucial to this discussion. The following statement had been made: “I like this new version of Oberon's type rules. They are simpler to understand and if the audience wants more details, he can always read the source code of ORP.Mod.” Wirth’s response was as follows (verbatim apart from a couple of spelling typos that I corrected): ------------------------------------------------------------------------ NO, NO! He should look only at the Oberon-Report. This is the definitive document. But never the compiler! Oberon-Users do not have access to the compiler source. The very idea of a high-level language was that it must not be defined with reference to a computer (or compiler), but be clearly defined as an abstract machine, the language report. I am afraid that this notion got lost over the past decades, where in case of doubt one does not analyze the situation, but simply, due to interactive usage, try and try again. Also, the "open source" is a terrible promoter of deserting this most useful idea. Another consequence is that "everyone" creates his own compiler (language?) version, compromising the very idea of a common language serving communication. Please do not consider my compiler as the definition of Oberon, and in case of doubt read the Report. It is the privilege of a report to leave certain constructs undefined. In this case a user should simply avoid using the (undefined) feature. ------------------------------------------------------------------------ Regards, Chris Burrows CFB Software https://www.astrobe.com From: Jörg [mailto:joerg.straube@iaeth.ch] Sent: Sunday, 26 April 2020 9:42 PM To: chris@cfbsoftware.com; ETH Oberon and related systems Subject: Re: [Oberon] Negative integer literals in Oberon Agreed The report is not always 100% clear. If this happens, I try to find other sources to get the intention of the construct. My preferred sources are other NW publications, like his compiler source and his RISC architecture. Looking at these facts a) NW introduced byte addressing mode in RISC-3 b) BYTE are the integers between 0 and 255 c) The type BYTE is compatible with the type INTEGER, and vice-versa. Led to the (perhaps wrong) conclusion that assignments to BYTE are mapped to the byte addressing mode of the processor. The byte addressing mode works MOD 256 by definition. There are basically two cases you have to consider Firstly: b := expression; (* store*) The expression on the righthand side can be any integer value. c) tells us that I can store any value into b. And b) tells us that the as a result of this assignment to byte b, b is between 0..255. The compiler source tells us, that the intention of this assigment case was, to just map the assignment to the „store byte“ instruction, that works MOD 256 by definition Secondly: i := f(b) (* load *) Whenever we use a byte value on the righthand side as part of an expression, b) tells us that the value to be taken shall be interpreted as 0..255. And c) tells us that a byte value is allowed to be assigned to an integer variable. br Jörg Am 26.04.2020 um 12:53 schrieb Chris Burrows <chris@cfbsoftware.com <mailto:chris@cfbsoftware.com> >: From: Joerg [mailto:joerg.straube@iaeth.ch] Sent: Sunday, 26 April 2020 5:55 PM To: ETH Oberon and related systems Cc: chris@cfbsoftware.com <mailto:chris@cfbsoftware.com> Subject: Re: [Oberon] Negative integer literals in Oberon Chris 1) b := i; is allowed, right? Yes – but the value of i must be in the range 0..255 for the result to be predictable. 2) b := i; does not generate a range check, right? Not necessarily. An implementer is not required to generate a range check, but equally they are not prohibited from generating a range check either. 3) i := 511; b := i; If 3) doesn’t generate a range check, but you want to be compliant to the report, you implement the assignment as b := i MOD 256; as any value MOD 256 is between 0..255. The behaviour is not specified in the report so there is no question of compliance or non-compliance. Hence, the resulting value of b is undefined / unpredictable. Any programmer who assumes a particular result in that case is making a mistake. However, the implementer of the compiler is not required by the report to alert him to that mistake - but he can do if he wants to. If the programmer is competent there is no problem because he can write his code in such a way that he gets the answer that he want. If he expects values of i to be outside the range 0..255 and he wants b to be equal to i MOD 256 then he should explicitly code it as: b := i MOD 256 then there is no doubt about what the result will be no matter what the compiler implementer has decided to do.. br Jörg Am 26.04.2020 um 09:28 schrieb dave@brownsmeet.com <mailto:dave@brownsmeet.com> : ((Lapsed) VOC maintainer here.) In both VOC and Oberon 2013, integer literals are parsed in the symbol parser (VOC :OPS.Mod or 2013:ORS.MOD) and stored in the symbol table as signed integer values. Later, during expression compilation, their size is determined by the magnitude of their signed integer value. The difference between Oberon 2013 and VOC is the largest integer type, which is 32 bit on Oberon 2013 and 64 bit in VOC. The special handling that allows a hex literal with top bit set to be treated as a signed value happens at the time the literal is parsed as a symbol independent of what context it is being used in. (Consider e.g. 'CONST mask = 90909090H' - CONST parsing does not know whether this constant will be used in a 64 bit, 32 bit, 16bit or other context.) VOC and Oberon 2013 do both allow the hex special case top bit set parsing behaviour, the difference being the integer literal size. Thus VOC accepts myint64 := 9090909090909090H because 9090909090909090H is parsed as a negative 64 bit signed integer. But VOC does not accept myint32 := 90909090H because 90909090H is parsed as a positive 64 bit signed integer. VOC has no way to parse 90909090H as a negative 32 bit signed integer. - I did wonder about adding a further suffix letter to indicate the intended size, but I couldn't satisfy myself that any solution was simple enough to be easy to understand. - Note that this is independent of VOC's -Ox compatibility setting: that sets the default INTEGER size, not integer literal size - integer literals always support the largest available integer size which is SYSTEM.INT64 aka HUGEINT.) -- Dave On 2020-04-25 22:52, Chris Burrows wrote: It all depends on what size (i.e. number of bits) INTEGER is defined as on the system you are using as to what range of numbers are valid INTEGERs. Since 2011, the range of INTEGER values is no longer defined in the Language Report; it is implementation-dependent. In the Project Oberon (2013) RISC5 compiler, INTEGER is 32 bit so 90909090H is a valid INTEGER. Maybe you used the default (-O2) option in VOC? If so, INTEGER is 16 bit so 90909090H would be too large. Make sure you are compiling with the VOC –OC option instead if you want INTEGER to be treated as a 32 bit quantity. Note that 9090H would be a negative number on a 16-bit INTEGER system but a positive number on a 32-bit INTEGER system. Regards, Chris Burrows CFB Software https://www.astrobe.com From: Oberon [mailto:oberon-bounces@lists.inf.ethz.ch] On Behalf Of Arthur Yefimov Sent: Sunday, 26 April 2020 12:38 AM To: oberon@lists.inf.ethz.ch <mailto:oberon@lists.inf.ethz.ch> Subject: [Oberon] Negative integer literals in Oberon While developing the compiler[1], we got a question whether it is possible to write the following: PROCEDURE DWord(n: INTEGER); ... DWord (90909090H) (where INTEGER is 32-bit). Some compilers give an error (i.e. VOC), while this works in the Project Oberon (2013) compiler. This would turn out to be quite convenient, because the purpose of DWord in our code was to write 4 bytes to the file given as INTEGER (using little-endian byte order). DWord has the following implementation (module Generator[2]): PROCEDURE DWord (n: INTEGER); BEGIN Files.Write (r, CHR (n MOD 100H)); Files.Write (r, CHR (n DIV 100H MOD 100H)); Files.Write (r, CHR (n DIV 10000H MOD 100H)); Files.Write (r, CHR (n DIV 1000000H)) END DWord; The Oberon language report does not indicate that literal 90909090H should be considered an error if INTEGER has 32 bits. In this experiment, an online RISC emulator[3] was used. References: [1] https://github.com/kekcleader/oberon [2] https://github.com/kekcleader/oberon/blob/master/Mod/Generator.Mod [3] http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage <http://schierlm.github.io/OberonEmulator/emu-wasm.html?image=FullDiskImage&width=1024&height=768> &width=1024&height=768 -- Oberon@lists.inf.ethz.ch <mailto:Oberon@lists.inf.ethz.ch> mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch <mailto:Oberon@lists.inf.ethz.ch> mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon -- Oberon@lists.inf.ethz.ch <mailto:Oberon@lists.inf.ethz.ch> mailing list for ETH Oberon and related systems https://lists.inf.ethz.ch/mailman/listinfo/oberon
participants (13)
-
Arnim Littek -
Arthur Yefimov -
August Karlstrom -
Chris Burrows -
dave@brownsmeet.com -
Jan de Kruyf -
Joerg -
Jörg -
Michael Schierl -
Nemo Nusquam -
Oleg N. Cher -
Paul Reed -
Skulski, Wojciech