Turns out, this Github-repo is just a mirror/copy of his work, but with attribution [2]. Still worth reading through there, tuhs also stores some extremely old UNIX versions.
[1] www.tuhs.org
[2] http://cm.bell-labs.com/cm/cs/who/dmr/primevalC.html
Edit: Warren has written a paper on restoring ancient UNIX versions and C-compilers, you might like it [3]
[3] http://epublications.bond.edu.au/infotech_pubs/146/
Edit2: Now that I've thought a little bit about it, I'm not happy that the sources are on GitHub in this form. This is Warren's work - he did a lot of work in getting these tapes to work again, and "mortdeus" just copied the work and didn't even change the folder-names - "last1120c" is the first tape, "prestruct" the second. And you still need Warren's Apout emulator to get these files to work.
If one releases code under an open license and people use/copy/fork it, why should you or the original author be unhappy. (As long as the license terms are not being broken.)
If we had to worry about this each time we forked/cloned someone's work, it would make code reuse very hard.
[Edit]
I am working on some Python charting. I found Pychart, which I found interesting: http://home.gna.org/pychart/ . Because it is in bzr which I don't work with, I put it on github. Should I be worried that someone will feel offended with it?
In the case of the C compiler, I think the modifications are under the same license as the original, but I'm not totally certain. If they aren't it would be cause for concern.
What happens when you have more then 9 substitutions specified in the string? :D
edit: decided the code was a bit long to have pasted into my post. Can find it at the bottom of http://cm.bell-labs.com/cm/cs/who/dmr/last1120c/c03.c
"Dennis MacAlistair Ritchie (born September 9, 1941; found dead October 12, 2011) was an American computer scientist who "helped shape the digital era." He created the C programming language and, with long-time colleague Ken Thompson, the Unix operating system"
(All three events were in October 2011 - Jobs, then Ritchie, then McCarthy)
if(foo) {
omitting the space after control statements' names, which is almost never done - except in very early C code. (It's not just this: V7 Unix often omits the space as well.). I should probably settle on a less idiosyncratic personal style, but I can't help but take a little heart from seeing "my" style in such a famous codebase. :)"no white space after the keywords if, for, while, etc."
if(foo)
I avoid doing this because it looks like a function call.Everyone must support the space character, it cannot be banned. But a simple commit hook to ban tabs can make indentation and alignment not get messed up over time with many collaborators with default-configured editors (that mess up and use tabs for alignment).
The tab character is a nice idea, but they do not seem to have worked out at all. I'd much rather have syntax-aware indenting in the editor, now that available compiler technology and CPU power make it practical.
init(s, t)
char s[]; {
would be equivalent to: int init(char s[], int t) {
This still works with modern compilers.I'd be interested if anyone has any more info about this:
waste() /* waste space */
{
waste(waste(waste),waste(waste),waste(waste));
waste(waste(waste),waste(waste),waste(waste));
waste(waste(waste),waste(waste),waste(waste));
waste(waste(waste),waste(waste),waste(waste));
waste(waste(waste),waste(waste),waste(waste));
waste(waste(waste),waste(waste),waste(waste));
waste(waste(waste),waste(waste),waste(waste));
waste(waste(waste),waste(waste),waste(waste));
}
Found in last1120c/c10.cA second, less noticeable, but astonishing peculiarity is the space allocation: temporary storage is allocated that deliberately overwrites the beginning of the program, smashing its initialization code to save space. The two compilers differ in the details in how they cope with this. In the earlier one, the start is found by naming a function; in the later, the start is simply taken to be 0. This indicates that the first compiler was written before we had a machine with memory mapping, so the origin of the program was not at location 0, whereas by the time of the second, we had a PDP-11 that did provide mapping. (See the Unix History paper). In one of the files (prestruct-c/c10.c) the kludgery is especially evident.
It looks beautiful, almost like a scripting language. No monster type signatures like
const std::foo_bar<boost::blah_ptr<const xyz::bar::Bar&, baz::Baz>>&http://cm.bell-labs.com/cm/cs/who/dmr/primevalC.html
Which led me to here:
http://cm.bell-labs.com/cm/cs/who/dmr/chist.html
Where, if you take the time, you will find a wonderful story, upon completing, you will probably know more about the early embryonic history of C then 95% of your peers.
(Spoiler - We start with BCPL, then Move to B - it's left as an exercise to determine how we originally compiled BCPL)
To compile a C compiler, you don't need a full-blown C compiler. For instance, I bet floats and doubles are not used. Therefore, you can write a barebones proto-C compiler in whatever language you have available and use it to bootstrap your compiler. Rinse and repeat.
The later is a c compiler in about 1kb of source code! It's quite functional and can compile itself.
The first link is what came out of it: A compiler so fast, that it can boot Linux from source code in a few seconds: http://bellard.org/tcc/tccboot.html
Does anyone know what hardware the assembly language files are for?
Maybe you could produce a modified version with the archaic features removed, compile it with a modern compiler, then use the binary produced to compile an unmodified version. Or maybe there are still binaries of really old compilers that can understand this code floating around out there.
Any ideas?
main(argc, argv)
int argv[]; {
Is that still valid today?The standard now known as C89/C90 had been in committee for many years before being 'released'. This didn't stop the tool vendors (like Borland) from supporting the 'proposed' standard much earlier than 1989.
Unfortunately, commercial UNIX vendors (like HP, in my case), were very slow to adopt the standard and update the cc compiler in their distribution. This forced us to work in K&R for a good time after 1990, all the while grumbling that $150 MS-DOS compilers already 'had ANSI'.
int foo(int i, int j) {...}
in Fortran you would do (! is comment) function foo(i, j)
integer :: foo !return type
integer :: i
integer :: j
!body goes here
Early C stuck to that style, so you would just put the names of the variables in the declaration, and then before the body give them types. The reason only argv is mentioned in that example is that C assumes a variable is an int if not declared otherwise, so there's no reason to put "int argc" like "int argv[]".To explain further:
main(argc, argv)
int argv[]; {
is equivalent to: int main(int argc, int argv[]) {
The old style definition works because C had a default type of int, so the type specifications for the function main and the parameter argc could be omitted.As for int argv[]? What that actually represents is an array of memory addresses that hold the command line arguments given. Obviously this becomes a problem if you're on a 64-bit system, where int and (void * ) are two different sizes. However, I checked this out on my 64-bit machine and it works just fine:
int main(int argc, unsigned long long argv[]) {
char *firstarg = (void *)(argv[1]);
printf("%s", firstarg);
}
which, given "./a.out pickles" will print "pickles" (argv[0] gives the memory address of the cstring "./a.out"). I'm guessing that, in the case of a compiler, the memory addresses of arguments are more relevant to have than the arguments themselves.All modern C compilers still accept this style for backwards compatibility. I'm not sure about C++ compilers.
The int argv[]; is where the declaration for argv is happening and is being declared as an pointer for ints.
You can also see elsewhere in the code where they are passing pointer addresses (as int params) into functions and then using the address to build pointers referencing that data.