• Please review our updated Terms and Rules here

1983 - coming ready or not

I think everyone is a little confused by the purpose of this "challenge". However, two things stand out me: something about 16 bit MS-DOS compatibility and a requirement to use SubC.

So I downloaded SubC to see what it's all about. Aside from being public domain, it appears to be woefully substandard. Nowhere near C90 as claimed. From the README:

Code:
    The current version of the SubC compiler adds support for
    the following parts of C language to the version described
    in "Practical Compiler Construction":

    o  There is some support for structs and unions.

    o  There is some support for typedefs.

    o  &array is now valid syntax (you no longer have to write
       &array[0]).

    o  the auto, register, and volatile keywords are recognized
       (as no-ops). Yes, volatile is safe, because SubC does not
       have register variables.

    o  enums may now be local.

    o  extern identifiers may now be declared locally.

    o  Prototypes may have the static storage class.

    o  FILEs are now structs and can no longer be mistaken for
       ints by the type checker.

    o  The #error, #line, and #pragma commands have been added.

    o  There is a (non-standard) kprintf() function, which is
       like fprintf(), but uses a file descriptor.

    o  There is now a (slightly incompatible) varargs mechanism.
       Here is how it works:

        #include <varargs.h>

        void p(int a, int b, ...) {
            int    first;
            void    *ap;

            ap = _va_start(&b);
            first = (int) _va_arg(&ap);
            vprintf("other args: %d %d %d\n", ap);
            _va_end(&ap);
        }

    o  The vprintf(), vfprintf(), and vsprintf() functions have
       been added to the runtime library.

    o  A broader subset of C expression syntax is accepted
       in constant expression contexts. For example, pointer
       variables can be initialized with NULL.


    DIFFERENCES BETWEEN SUBC (THIS VERSION) AND FULL C89

    o  The following keywords are not recognized:
       const, double, float, goto, long, short, signed,
       unsigned.

    o  There are only two primitive data types: the signed int and
       the unsigned char; there are also void pointers, and there
       is limited support for int(*)() (pointers to functions
       of type int).

    o  No more than two levels of indirection are supported, and
       arrays are limited to one dimension, i.e. valid declarators
       are limited to x, x[], *x, *x[], **x (and (*x)()).

    o  K&R-style function declarations (with parameter declarations
       between the parameter list and function body) are not
       accepted.

    o  There are no ``const'' variables.

    o  There are no unsigned integers, long integers, or signed
       chars.

    o  Struct/union declarations must be global (struct and union
       objects may be declared locally, though).

    o  There is no support for bit fields.

    o  Only ints, chars, and arrays of int and char can be
       initialized in their declarations; pointers can be
       initialized with 0 or NULL.

    o  Local arrays cannot have initializers.

    o  Local declarations are limited to the beginnings of function
       bodies (they do not work in other compound statements).

    o  Arguments of prototypes must be named.

    o  There is no goto.

    o  There are no parameterized macros.

    o  The #if and #elif preprocessor commands are not recognized.

    o  The preprocessor does not accept multi-line commands.

    o  The preprocessor does not accept comments in (some) commands.

    o  The preprocessor does not recognize the # and ## operators.

    o  There may not be any blanks between the # that introduces
       a preprocessor command and the subsequent command (e.g.:
       "# define" would not be recognized as a valid command).

    o  The sizeof operator requires parentheses.

    o  Subscripting an integer with a pointer (e.g. 1["foo"]) is
       not supported.

    o  Function pointers are limited to one single type, int(*)(),
       and they have no argument types. Note that this declaration
       will in fact generate a pointer to int(*)(void).

    o  There is no assert() due to the lack of parameterized macros.

    o  The atexit() mechanism is limited to one function (this may
       even be covered by TCPL2).

    o  The signal() function returns int due to the lack of a more
       sophisticated type system; the return value must be casted to
       int(*)() manually.

    o  Most of the time-related functions are missing, in particular:
       asctime(), gmtime(), localtime(), mktime(), and strftime().

    o  The clock() function is missing, because CLOCKS_PER_SEC
       varies among systems.

    o  The ctime() function ignores the time zone.

    o  The varargs mechanism is slightly incompatible.

    o  The SubC compiler accepts // comments in addition to /* */
       (but not in macros).

The code generation is also quite simplistic. It really only understands a flat memory model, wether that be 32 bits or 16 bits (not particularly good for MS-DOS > 64K). So I would suggest your challenge should be to fix the tools.

Since you're looking at 1983, one approach would be to create a higher level 32 bit virtual machine as your compile target and write an interpreter/JIT compiler that would present a flat memory model to the application. I took this approach with PLASMA on the 6502 (albeit a 16 bit VM on an 8 bit CPU): https://github.com/dschmenk/PLASMA

There is a long precedent for this approach going back to DigiTek's compilers in the early '60s: https://en.wikipedia.org/wiki/Digitek using POPS (Programmed Operators) and brought to the IBM PC in the early '80s by my good friend Tom Lahey.

Edit: and of course UCSD Pascal for the IBM PC (although just a 16 bit VM, IIRC): https://williambader.com/museum/at/pascal.html
 
Last edited:
When I was writing code for MSDOS in 1983, I used Lattice C, as recommended by Microsoft. Still have the two 360K disk set.

Don't know what this is about subC--never heard of it until now.
 
Of course, I deeply respect this project and the big task of building an operating system from scratch. I hope my words aren't interpreted as an attack to this project, as they are not. I understand that one of the goals of this project is making a fully public domain operating system, in contrast with MS-DOS up to 2.0, which is now open source, but the copyright still belongs to Microsoft.

But, like resman, I also don't fully get what this challenge is about. I mean, I highly doubt a written in C operating system can match (not even talking about outperform) an operating system written in pure assembler.

Even the best C optimizing compilers use to make executable code quite larger than their pure assembly equivalents. And the C standard lib is quite large too, so just using something as common as printf alone can make the code a few kilobytes larger, while a custom print function based on BIOS INT 10h take just a few bytes. If there's something the 1983 IBMs are not plenty of, it is RAM. Here, the smaller the binary, the better. That's maybe one of the many reasons why MS-DOS is written with pure assembler instead of C, like UNIX. Also, what a C compiler can do in terms of speed is miles behind of what a well programmed and optimized piece of assembly code can do. So, in my opinion 1983 was already (almost) as good as it could be in terms of operating systems. Nevertheless, I think that better games and applications can be done with the resources available in 1983.
 
Last edited:
The code generation is also quite simplistic. It really only understands a flat memory model, wether that be 32 bits or 16 bits (not particularly good for MS-DOS > 64K). So I would suggest your challenge should be to fix the tools.
I agree that that should be the first thing done - bring SubC closer to C90. But rather than a VM, I was planning on getting it to generate huge memory model code. Isn't that a better option?
 
Of course, I deeply respect this project and the big task of building an operating system from scratch. I hope my words aren't interpreted as an attack to this project, as they are not. I understand that one of the goals of this project is making a fully public domain operating system, in contrast with MS-DOS up to 2.0, which is now open source, but the copyright still belongs to Microsoft.

But, like resman, I also don't fully get what this challenge is about. I mean, I highly doubt a written in C operating system can match (not even talking about outperform) an operating system written in pure assembler.

Even the best C optimizing compilers use to make executable code quite larger than their pure assembly equivalents. And the C standard lib is quite large too, so just using something as common as printf alone can make the code a few kilobytes larger, while a custom print function based on BIOS INT 10h take just a few bytes. If there's something the 1983 IBMs are not plenty of, it is RAM. Here, the smaller the binary, the better. That's maybe one of the many reasons why MS-DOS is written with pure assembler instead of C, like UNIX. Also, what a C compiler can do in terms of speed is miles behind of what a well programmed and optimized piece of assembly code can do. So, in my opinion 1983 was already (almost) as good as it could be in terms of operating systems. Nevertheless, I think that better games and applications can be done with the resources available in 1983.
I am not claiming that the C version would be better than the assembler version. But maybe the C version would still be adequate, depending on your needs. A normal price/performance tradeoff.

However, the 640k RAM limitation will be lifted in 1984 with the PC AT, where it becomes 16 MB (and note that the 80286 existed in 1982). If you write your 16:16 OS and programs in a way that prepares for this, perhaps being MSDOS-inspired rather than truly compatible, maybe you shouldn't throw C away.

And you can solve the problem with the C library being large (about 32k), by having just one copy in the OS and have all the applications use that. Similar to a DLL, but not necessarily exactly that.
 
wow. subc.. I havnt thought about this since I bought the book in 2012 off lulu? Are we talking the same SubC?
Yep. After 50 years of C, that is the most advanced C compiler that the public owns. It *may* be *just* good enough that you can program in it instead of needing to resort to machine code, if you are restricted to a pure public domain environment.
 
I'm not sure what's meant by "the public owns it". DJGPP goes back a bit more than 30 years and has a generous license.
DJGPP is copyrighted (owned by the authors, not the public), and will only be owned by the public (ie be public domain) 70 years after the death of the authors.

SubC was released to the public domain by the author, so we don't need to wait for him to die, and then wait another 70 years.
 
In this case does it matter? DeLorie has stated that he makes no claims on the product of compilation.
Yes, it matters, because I may wish to enhance it and produce a commercial product. Or someone else might.

A better question is does it matter if DJGPP is released to the public domain?
 
Yes, it matters, because I may wish to enhance it and produce a commercial product. Or someone else might.

A better question is does it matter if DJGPP is released to the public domain?

djgpp is open source, so I dont see the point of this reasoning. you can enhance and produce a commercial product from it. so can anyone else.
 
djgpp is open source, so I dont see the point of this reasoning. you can enhance and produce a commercial product from it. so can anyone else.
Not if I want to protect my changes/work by making it closed source.

Or if I wish to violate any of the other 573 conditions of the GPL. Or even if my team of lawyers thinks I'm not violating any of them, but the copyright holder disagrees and then it comes down the whim of a random judge in a random country.

Public domain is totally unrestricted.

Again - a better question is - why wasn't it made public domain instead of copyrighted with a long list of conditions? Whatever they don't want you to do - I want to be able to do. There are no restrictions on the use of Shakespeare's "Hamlet". It's as free as sunlight. Same with SubC.
 
Not if I want to protect my changes/work by making it closed source.

aaah I get it, you want free public domain so you can work off the backs of others, but keep any changes you make closed and not share.. got it. otherwise opensource would fit the bill.

you must have some amazing compiler optimisation changes nobody has ever thought off you want to fearfully protect. 🤣


Again - a better question is - why wasn't it made public domain instead of copyrighted with a long list of conditions?

So everyone can benefit from changes, rather than, say, unscrupulous people hoarding their changes?

Anyway, I think this is a pointless argument. If you want public domain, your options are limited, so have fun with subc or bdsc!
 
aaah I get it, you want free public domain so you can work off the backs of others, but keep any changes you make closed and not share.. got it. otherwise opensource would fit the bill.
Feel free to work off the back of my public domain work. That's why it exists. So you don't have to start your project from scratch and pass those costs on to the consumer.

you must have some amazing compiler optimisation changes nobody has ever thought off you want to fearfully protect. 🤣
I don't currently, but someone else might. Or I might in the future.

So everyone can benefit from changes, rather than, say, unscrupulous people hoarding their changes?
I don't consider people using my public domain code as a base for a commercial venture to be "unscrupulous". Some people think that anyone who supports capitalism itself are unscrupulous. I disagree with them too.

Anyway, I think this is a pointless argument. If you want public domain, your options are limited, so have fun with subc or bdsc!
What is bdsc?
 
I agree that that should be the first thing done - bring SubC closer to C90. But rather than a VM, I was planning on getting it to generate huge memory model code. Isn't that a better option?
Maybe or maybe not. Since SubC has no concept of segmented memory the approach could be to modify the compiler enough to support a pseudo 32 bit target machine. The result could either be interpreted as byte code or simply transformed into underlying 16 bit 8086 code. Either way you will have a lot of work ahead of you. Definitely a learning experience.
 
Maybe or maybe not. Since SubC has no concept of segmented memory the approach could be to modify the compiler enough to support a pseudo 32 bit target machine. The result could either be interpreted as byte code or simply transformed into underlying 16 bit 8086 code. Either way you will have a lot of work ahead of you. Definitely a learning experience.
Are you sure it is a lot of work? Each SubC target is about 300 lines of code. And it's not necessarily "pseudo 32-bit". Memory access already uses two 16-bit registers (that's the 8086 design) and 32-bit ints would be a different register pair (dx + ax or whatever).

Having said that, I may well be missing something. Generating 32-bit code for the 8086 hasn't come up as priority yet. Priority (for me) is to get PDOS-generic built with SubC.
 
Back
Top