[HN Gopher] The earliest versions of the first C compiler known ...
___________________________________________________________________
The earliest versions of the first C compiler known to exist
Author : diginova
Score : 279 points
Date : 2025-03-21 08:17 UTC (3 days ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| diginova wrote:
| Also read how a compiler can be written in the same language -
| https://en.wikipedia.org/wiki/Bootstrapping_%28compilers%29
|
| https://stackoverflow.com/a/18247926/15566831
| Joker_vD wrote:
| Funnily enough, it is emphatically _not_ a single-pass compiler.
| dbrower wrote:
| I don't think anybody thinks or thought it was.
| aap_ wrote:
| Probably one of my favorite pieces of software of all times.
| Learned so much from this!
| gus_massa wrote:
| Do you remember any interesting anecdote you can share?
| aap_ wrote:
| Anecdote probably not. But i learned how a compiler works
| from it and reconstructed the B compiler based on it (found
| here: https://github.com/aap/b, warning: repo is messy, will
| clean up more soon hopefully).
| bluetomcat wrote:
| Interesting usage of "extern" and "auto". Quite different from
| contemporary C: tree() { extern
| symbol, block, csym[], ctyp, isn, peeksym, opdope[],
| build, error, cp[], cmst[], space, ospace, cval,
| ossiz, exit, errflush, cmsiz; auto op[],
| opst[20], pp[], prst[20], andflg, o, p, ps, os; ...
|
| Looks like "extern" is used to bring global symbols into function
| scope. Everything looks to be "int" by default. Some array
| declarations are specifying a size, others are not. Are the
| "sizeless" arrays meant to be used as pointers only?
| Joker_vD wrote:
| Yes, pretty much. To be fair, C at this point was basically
| BCPL with slightly different syntax (and better char/string
| support). The introduction of structs (and then longs) changed
| it forever.
| netbsdusers wrote:
| You can do the same with a modren C compiler - the extern and
| auto mean the same and int is still the default type.
| tialaramex wrote:
| In C23, auto doesn't have a default type, if you write auto
| without a type then you get the C++ style "type deduction"
| instead. This is part of the trend (regretted by some WG14
| members) of WG14 increasingly serving as a way to fix the
| core of C++ by instead mutating the C language it's
| ostensibly based on.
|
| You can think of deduction as crap type inference.
| pjmlp wrote:
| Design by committee, the outcome is usually not what the
| people on the trenches would like to get.
| uecker wrote:
| Nobody in the trenches seemed to use old-style auto in
| the last decades.
|
| BTW: The right place to complain if you disagree would be
| the compiler vendors. In particular the Clang side pushes
| very much for keeping C and C++ aligned, because they
| have a shared C/C++ FE. So if you want something else,
| please file or comment on bugs in their bug tracker.
| Similar for other compilers.
| Y_Y wrote:
| > Nobody in the trenches seemed to use old-style auto in
| the last decades.
|
| To the beat of my knowledge, there was no case where
| "auto" wasn't redundant. See e.g.
| https://stackoverflow.com/a/2192761
|
| This makes me feel better about repurposing it, but I
| still hate the shitty use it's been put to.
| pjmlp wrote:
| Indeed, however many in the treches would like a more
| serious take on security, complaining has not served
| anything in the last 50 years until goverment agencies
| finally decided to step in.
| uecker wrote:
| This is again a problem compilers could have addressed,
| but didn't. Mostly because the users in the trenches did
| not care. Instead they flocked in droves to the compiler
| optimizing in the most aggressive way and rejecting
| everything costing performance. So I do not have the
| feeling that users were really pushing for safety. They
| are very good at complaining though.
| ndiddy wrote:
| GCC and Clang support asan/ubsan, which lets you trade
| performance for nicer behavior related to memory access
| and undefined behavior. Whenever I do C development for a
| platform that supports asan/ubsan, I always develop and
| test with them enabled just because of how much debugging
| time they save.
| jeltz wrote:
| Isn't the original inclusion of the auto keyword more in
| line with what you expect from design by committee?
| Including a keyword which serves no purpose other than
| theretical completeness?
| pjmlp wrote:
| I was talking more in general, not specific regarding
| auto.
|
| Actually I did use C compilers, with K&R C subset for
| home computers, where auto mattered.
|
| Naturally they are long gone, this was in the early
| 1990's.
| windward wrote:
| It doesn't matter. The people in the trenches don't
| update their standard versions.
| mhh__ wrote:
| An interesting secondary meaning of "design by
| committee", the reason why what you mention happens, is
| "design _in_ committee ".
|
| People can skip the usual lifecycle and feedback for an
| idea by presenting jumping directly to committee stage./
| fsckboy wrote:
| > _Looks like "extern" is used to bring global symbols into
| function scope._
|
| a better way to think of extern is, "this symbol is not
| declared/defined/allocated here, it is
| declared/defined/allocated someplace else"
|
| "this is its type so your code can reference it properly, and
| the linker will match up your references with the
| declared/defined/allocated storage later"
|
| (i'm using reference in the generic english sense, not pointer
| or anything. it's "that which can give you not only an r-value
| but an l-value")
| dfawcus wrote:
| As to "sizeless" arrays - yes.
|
| Have a look at the early history of C document on DMR's site,
| it mentions that the initial syntax for pointers was that form.
| xenadu02 wrote:
| "auto" used to mean _automatic memory management_ because if
| you are coming from assembly or even some other older higher-
| level languages you can 't just declare a local variable and
| use it as you please. You must declare somewhere to store it
| and manage its lifetime (even if that means everything is
| global).
|
| C and its contemporaries introduced automatic or in modern
| terms local or stack allocated values, often with lexically-
| scoped lifetimes. extern meaning something outside this file
| declares the storage for it and register meaning the compiler
| should keep the value in a register.
|
| However auto has always been the default and thus redundant and
| style-wise almost no one ever had the style of explicitly
| specifying auto so it was little-used in the wild. So the C23
| committee adopted auto to mean the same as C++: automatically
| infer the type of the declaration.
|
| You can see some of B's legacy in the design of C. Making
| everything int by default harkens back to B's lack of types
| because everything was a machine word you could interpret
| however you wanted.
|
| Also with original C's function declarations which don't really
| make sense. The prototype only declares the name and the local
| function definition then defines (between the closing paren and
| the opening brace) the list of parameters and their types.
| There was no attempt whatsoever to have the compiler verify you
| passed the correct number or types of parameters.
| tanelpoder wrote:
| The first publicly available version of Oracle Database (v2
| released in 1979) was written in assembly for PDP-11. Then Oracle
| rewrote v3 in C (1983) for portability across platforms. The
| mainframes at the time didn't have C compilers, so instead of
| writing a mainframe-specific database product in a different
| language (COBOL?), they just wrote a C compiler for mainframes
| too.
| chasil wrote:
| UNIX was ported to the System/370 in 1980, but it ran on top of
| TSS, which I understand was an obscure product.
|
| "Most of the design for implementing the UNIX system for
| System/370 was done in 1979, and coding was completed in 1980.
| The first production system, an IBM 3033AP, was installed at
| the Bell Laboratories facility at Indian Hill in early 1981."
|
| https://web.archive.org/web/20240930232326/https://www.bell-...
| dboreham wrote:
| Writing something that large in assembly is pretty crazy, even
| in 1979!
| acchow wrote:
| Keep in mind, Oracle was designed to run with 128KB of RAM
| (no swapping). So it was really tens of thousands of lines,
| not millions.
| dark-star wrote:
| My favorite function, which some might say even made it into
| Windows ;-) 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)); }
| retSava wrote:
| But why? Waste (compiled) binary space? Or source code space,
| perhaps for early employee metrics gaming purposes?
|
| And don't answer "to waste space of course" please. :)
| ajb wrote:
| There's nothing in that repo that says, but at a guess: old
| machines often had non-uniform ways to access memory, so it
| may have been to test that the compiler would still work if
| the binary grew over some threshold.
|
| Even today's machines often have a limit as to the offset
| that can be included in an instruction, so a compiler will
| have to use different machine instructions if a branch or
| load/store needs a larger offset. That would be another thing
| that this function might be useful to test. Actually that
| seems more likely.
|
| It might be instructive to compare the binary size of this
| function to the offset length allowed in various PDP-11
| machine instructions
| bustling-noose wrote:
| Yes it seems like this is something to do with hardware
| testing. Maybe memory or registers or something that needed
| just X bytes etc for overflows or something. It's really
| random and the only person who would know it is the one who
| wrote it :)
| bluetomcat wrote:
| Wild guess: it was a way to offset the location of the "main"
| function by an arbitrary amount of bytes. In the a.out binary
| format, this translates to an entry point which is not zero.
| aap_ wrote:
| See my other comment.
| jeltz wrote:
| One possible reason is to allocate a static global area.
| Without read-only protection of memory you could write to
| that area.
| unclad5968 wrote:
| There is a variable declared right before the waste space
| function. The 'wasted' space is statically allocated memory
| for the variable 'ospace' just before it.
| dfawcus wrote:
| http://cm.bell-labs.co/who/dmr/primevalC.html
|
| " A 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. "
| ape4 wrote:
| The comment is a waste too. It could have explained why the
| function is doing what it does.
| ChrisMarshallNY wrote:
| This is my favorite function :):
| https://github.com/mortdeus/legacy-cc/blob/936e12cfc756773cb...
| johnisgood wrote:
| What is the point of it?
| rasjani wrote:
| Without actually knowing, i'd guess that would generate
| bytecode's that could be modified later by patching the
| resulting binary ?
|
| I remember few buddies using similar pattern in ASM that just
| added n NOP's into code to allow patching and thus
| eliminating possible recompilation..
| ChrisMarshallNY wrote:
| I suspect that's it.
|
| There was a lot of self-modification, going on, in those
| days. Old machine language stuff had _very_ limited
| resources, so we often modified code, or reused code space.
| agumonkey wrote:
| warm up the stack ? (no idea to be honest)
| tanelpoder wrote:
| The C alternative for the hardware "halt and catch fire"
| instruction?
| kps wrote:
| The C alternative for the Fortran COMMON block.
| aap_ wrote:
| It's an awkward way to reserve memory. The important detail
| here is that both compiler phases do this, and the way the
| programs are linked guarantees that the reserved region has
| the same address in both phases. Therefore an expression tree
| involving pointers can be passed to the second phase very
| succinctly. Not pretty, no, but hardware limitations force
| you to do come up with strange solutions sometimes.
| johnisgood wrote:
| Thank you! Is it relevant today at all, or is there an use-
| case for it today?
| aap_ wrote:
| No, if you need fixed addresses i suppose a linker script
| would be the way to go? Or in this case you'd just
| serialize the data such that it doesn't contain any
| pointers in the first place.
| ddulaney wrote:
| If you even can with ASLR. Most modern boxes would
| disable stuff like this.
| mananaysiempre wrote:
| There are better tools to do this these days--with the
| GNU toolchain, for example, you'd use a linker script and
| make sure you're building a non-position-independent
| static executable. Alternatively, you could use self-
| relative pointers: instead of having foo_t *foo and
| putting p there, have ptrdiff_t foo and put ((char *)p -
| (char *)&foo) there.
| colejohnson66 wrote:
| Here's the actual code that references the 'ospace' from
| before 'waste': https://github.com/mortdeus/legacy-
| cc/blob/936e12cfc756773cb...
| fxtentacle wrote:
| It's an obscure way to statically allocate memory for the
| ospace pointer.
| Amlal wrote:
| Ah, yes, was that because of a lack of inline assembly? I feel
| like these could be replaced by 'nop' operations.
| arp242 wrote:
| Gotta love the user-friendliness of these old Unix tools:
| if (argc<4) { error("Arg count"); exit(1);
| }
| FeistySkink wrote:
| Missed opportunity not calling it LegaC.
| smackay wrote:
| 1972 is the answer to the question on the lips of everybody too
| busy to look at the source files.
| ModernMech wrote:
| I thought the first C compiler was written in B.
| indoordin0saur wrote:
| Yes. I'm not an expert in compilers, but how is the first c
| compiler also written in C? How did they compile the compiler?
| ModernMech wrote:
| There's a thread here which talked about it:
| https://news.ycombinator.com/item?id=26721305
| 9rx wrote:
| If we had the full change history you would see that it is
| written in B. New features were added and changes were
| iteratively made along the way, but it is the same codebase.
| Nowadays we'd pick some change point and call it B v2, but back
| then they named that point C.
| xenadu02 wrote:
| That's not quite correct. See my comment here:
| https://news.ycombinator.com/item?id=43465698
|
| B was bootstrapped in BCPL, then rewritten in B to be self-
| hosting. But the transition from B to NB (New B) to C was
| continuous evolution. Thompson or Richie would add a feature
| to the compiler, compile a new compiler, then change the
| compiler source to use the new feature. If you did not have a
| sufficiently new enough B/NB/C compiler you could not compile
| the compiler and there was no path maintained to deal with
| that. You went down the hall and asked someone else to give
| you the newer compiler.
|
| There also wasn't a definitive point where NB became C...
| they just decided it had changed enough and called it C.
| 90s_dev wrote:
| The thing I always loved about C was its simplicity, but in
| practice it's actually very complex with tons of nuance. Are
| there any low level languages like C that actually _are_ simple,
| through and through? I looked into Zig and it seems to approach
| that simplicity, but I have reservations that I can 't quite put
| my finger on...
| bewo001 wrote:
| forth would come to mind, some people have build surprising
| stuff with it though I find it too low-level.
| ChrisRR wrote:
| It depends what you mean by simple. C still is simple, but it
| doesn't include a lot of features that other languages do, and
| to implement them in C is not simple.
|
| C is simple for some use cases, and not for others.
| 90s_dev wrote:
| The appeal of C is that you're just operating on raw memory,
| with some slight conveniences like structs and arrays. That's
| the beauty of its simplicity. That's why casting a struct to
| its first argument works, why everything has an address, or
| why pointer arithmetic is so natural. Higher level langs like
| C++ and Go try to retain the usefulness of these features
| while abstracting away the actuality of them, which is
| simultaneously sad and helpful.
| colejohnson66 wrote:
| > That's why casting a struct to its first argument works
|
| Until WG14 makes everything you love about C "undefined
| behavior" in the name of performance.
| worik wrote:
| > Until WG14 makes everything you love about C "undefined
| behavior" in the name of performance.
|
| What do you mean?
|
| I just looked up WG14 and I cannot see what you mean
|
| A link perhaps? Am I going to have to "pin" my C compiler
| version?
| tialaramex wrote:
| Some people have this idea that when they write utter
| nonsense it _should_ do what they meant because - ie they
| 're missing out the whole discipline of programming and
| going straight from "I want it to work" to "It should
| work" and don't understand what they're doing wrong.
|
| For some of these people WG14 (the C language sub-
| committee of SC22, the programming language sub-committee
| of JTC1, the Joint Technical Commitee between ISO and the
| IEC) is the problem because somehow they've taken this
| wonderful language where you just write stuff and it
| definitely works and does what you meant and turned into
| something awful.
|
| This doesn't make a whole lot of sense, but hey, they
| wrote nonsense and they're angry that it didn't work, do
| we expect high quality arguments from people who mumble
| nonsense and make wild gestures on the street because
| they've imagined they are wizards? We do not.
|
| There are others who blame the compiler vendors, this at
| least makes a little more sense, the people who write
| Clang are literally responsible for how your nonsense C
| is translated into machine code which does... something.
| They probably couldn't have read your mind and ensured
| the machine code did what you wanted, especially because
| your nonsense doesn't mean that, but you can make an
| argument that they might do a better job of communicating
| the problem (C is pretty hostile to this, and C
| programmers no less so)
|
| For a long time I thought the best idea was to give these
| people what they ostensibly "want" a language where it
| does something very specific, as a result it's slow and
| clunky and maybe after you've spent so much effort to
| produce a bigger, slower version of the software a friend
| wrote in Python so easily these C programmers will snap
| out of it.
|
| But then I read some essays by C programmers who had
| genuinely set out on this path and realised to their
| horror that their fellow C programmers don't actually
| agree what their C programs mean, the ambiguity isn't
| some conspiracy by WG14 or the compiler vendors, it's
| their reality, they are bad at writing software. The
| whole point of software is that we need to explain
| exactly what the machine is supposed to do, when we write
| ambiguous programs we are doing a bad job of that.
| windward wrote:
| A typical C program of useful length typically includes a
| spattering of implicit type conversions that the programmer
| never intended or considered. It's the consequence of a
| feature that abstracts away how the type system and memory
| really[1] acts.
|
| [1]for certain definitions of 'really'
| acuozzo wrote:
| > C still is simple
|
| Syntactically, yes. Semantically, no.
|
| There are languages with tons of "features" with far, far
| less semantic overhead than C.
|
| https://blog.regehr.org/archives/767
|
| FWIW, writing programs in C has been my day job for a long
| time.
| drob518 wrote:
| Exactly. There is a lot happening implicitly in a C program
| that the programmer has to be aware of and keep in mind.
| And it's made worse by valid compile implementation
| choices. I remember chasing a bug for a day that was based
| on me forgetting that the particular implementation I was
| working with had signed characters and was sign extending
| something at an inopportune time.
| kstrauser wrote:
| C is simple like SMTP.
| acuozzo wrote:
| EXACTLY!
| groos wrote:
| As someone who has had to parse C syntax for a living, I'd
| argue that it's not syntactically simple either.
| (Declarators are particularly nasty in C and even more so
| in C++).
| SAI_Peregrinus wrote:
| I've said before that C is small, but not simple.
|
| Turing Tarpits like Brainfuck or the Binary Lambda Calculus
| are a more extreme demonstration of the distinction, they can
| be very tiny languages but are extremely difficult to
| actually use for anything non-trivial.
|
| I think difficulty follows a "bathtub" curve when plotted
| against language size. The smallest languages are really hard
| to use, as more features get added to a language it gets
| easier to use, up to a point where it becomes difficult to
| keep track of all the things the language does and it starts
| getting more difficult again.
| LPisGood wrote:
| It's not really clear to me how you could have a simple low
| level language without tons of nuance. Something like Go is
| certainly simple without tons of nuance, but it's not low
| level, and I think extending it to be low level might add a lot
| of nuance.
| bluetomcat wrote:
| The perceived complexity from a semantic standpoint comes from
| the weakly-typed nature of the language. When the operands of
| an expression have different types, implicit promotions and
| conversions take place. This can be avoided by using the
| appropriate types in the first place. Modern compilers have
| warning flags that can spot such dodgy conversions.
|
| The rest of the complexity stems from the language being a thin
| layer over a von Neumann abstract machine. You can mess up your
| memory freely, and the language doesn't guarantee anything.
| drob518 wrote:
| Exactly. C started off as high level assembly language. That
| was both a strength, at first, and a weakness, later on.
| grandempire wrote:
| C is simple.
|
| Representing computation as words of a fixed bit length, in
| random access memory, is not (See The Art of Computer
| Programming). And the extent to which other languages simplify
| is creating simpler memory models.
| mort96 wrote:
| What about C is simple? Its syntax is certainly not simple,
| it's hard to grok and hard to implement parsers for, and
| parsing depends on semantic analysis. Its macro system is
| certainly not simple; implementing a C preprocessor is a huge
| job in itself, it's much more complex than what appears to be
| necessary for a macro system or even general text processor.
| Its semantics are not simple, with complex aliasing rules
| which just exist as a hacky trade-off between programming
| flexibility and optimizer implementer freedom.
|
| C forces programs to be simple, because C doesn't offer ways
| to build powerful abstractions. And as an occasional C
| programmer, I enjoy that about it. But I don't think it's
| simple, certainly not from an implementer's perspective.
| pjc50 wrote:
| Parsing isn't too bad compared to, say, Perl.
|
| The preprocessor is a classic example of simplicity in the
| wrong direction: it's simple to _implement_ , and pretty
| simple to describe, but when actually using it you have to
| deal with complexity like argument multiple evaluations.
|
| The semantics are a disaster ("undefined behavior").
| mort96 wrote:
| I would probably describe Perl as really complex to parse
| as well if I knew enough about it. Both are difficult to
| parse compared to languages with more "modern
| sensibilities" like Go and Rust, with their nice mostly
| context free grammars which can be parsed without
| terrible lexer hacks and separately from semantic
| analysis.
|
| Walter Bright (who, among other things, has been employed
| to work on a C preprocessor) seems to disagree that the C
| preprocessor is simple to implement:
| https://news.ycombinator.com/item?id=20890749
|
| > The preprocessor is fiendishly tricky to write. [...] I
| had to scrap mine and reimplement it 3 times.
|
| I have seen other people in the general "C
| implementer/standards community" complain about it as
| well.
| pjc50 wrote:
| I wonder if we can dig out the original K&R preprocessor
| implementation?
| dbrower wrote:
| it was a lot simpler in capabilities. much of the
| complexity is because of feature creep.
| kibwen wrote:
| _> Parsing isn 't too bad compared to, say, Perl._
|
| This is damning with faint praise. Perl is _undecidable_
| to parse! Even if C isn 't as bad as Perl, it's still bad
| enough that there's an entire Wikipedia article devoted
| to how bad it is:
| https://en.wikipedia.org/wiki/Lexer_hack
| grandempire wrote:
| Each of these elements is even worse in every other
| language I can think of. What language do you think is
| simple in comparison?
| mort96 wrote:
| Go, Rust, Zig?
|
| I'm curious, what language do you know of with a more
| complex macro system than the whole C preprocessor?
|
| EDIT: To be clear to prospective downvoters, I'm not just
| throwing these languages out because they're hype or
| whatever. They all have a grammar that's much simpler to
| parse. Notably, you can construct a parse tree without a
| semantic analyser which is capable of running in lockstep
| with the parser to provide semantic information to the
| parser. You can just write a parser which makes a parse
| tree.
| unclad5968 wrote:
| I've never written a parser for any of those languages
| but my intuition is that Go is easier to parse than C.
| The others are debatable. Rust macros are definitely not
| simpler than C macros. I'm not sure what could be simpler
| than text substition. Zig doesn't have macros and
| comptime is implemented as a language VM that runs as a
| compilation step(last I knew), so that's definitely not
| simpler. I don't use go often, but I don't think it has
| macros at all so that's definitely simpler.
|
| When people say that C is a simple language, my
| interpretation is that they mean it is easy to interpret
| what a C program does at a low level, not that it is
| simple to write.
| mort96 wrote:
| The other languages can be written by a parser. A parser
| for C needs a semantic analyzer working in tandem.
|
| The C preprocessor is not text substitution.
|
| It is not easy to describe what C does at a low level.
| There are simple, easy to describe _and wrong_ models of
| what C does "at a low level". C's semantics are defined
| by a very difficult to understand standards document, and
| if you use one of those simple and enticing mental
| models, you will end up with incorrect C code which works
| until you try a different compiler or enable
| optimisations.
| ioma8 wrote:
| I would say rust. When you learn the basics, rust is very
| simple and will point to you any errors you have, so you get
| basically no runtime errors. Also the type system is extremely
| clean, making the code very readable.
|
| But also C itself is very simple language. I do not mean C++,
| but pure C. I would probably start with this. Yes, you will
| crash at runtime errors, but besides that its very very simple
| language, which will give you good understanding of memory
| allocation, pointers etc.
| ForOldHack wrote:
| Got through C and K&R with no runtime errors, on four
| platforms, but the first platform... Someone asked the
| teacher why a struct would not work on Lattice C. The
| instructor looked at the code, sat down at the students
| computer, typed in a small program compiled it, and camly put
| the disks in the box with the manual and threw it in the
| garbage. "We will have a new compiler next week." We switched
| to Manx C, which is what we had on the Amiga. Structs worked
| on MS C, which I thought was the lettuce compiler. (
| Apparently a different fork of the portable C compiler, but
| later they admitted that it was still bigendian years later )
|
| Best programming joke. Teacher said when your code becomes
| "recalcitrent", we had no idea what he meant. This was in the
| bottom floor of the library, so on break, we went upstairs
| and used the dictionary. Recalcitrant means not obeying
| authority. We laughed out loud, and then went silent. Opps.
|
| The instructor was a commentator on the cryptic-C challenges,
| and would often say... "That will not do what you think it
| will do" and then go on and explain why. Wow. We learned a
| _lot_ about the pre-processor, and more about how to write
| clean and useful code.
| steveklabnik wrote:
| The reality is, the only languages that are truly simple are
| Turing tarpits, like Brainfuck.
|
| Reality is not simple. Every language that's used for real work
| has to deal with reality. It's about how the language helps you
| manage complexity, not how complex the language is.
|
| Maybe Forth gets a pass but there's good reason why it's
| effectively used in very limited circumstances.
| 1wd wrote:
| Oberon?
| 90s_dev wrote:
| I did not realize how intrinsically I also meant simple in
| syntax until you suggested that.
| timewizard wrote:
| > but in practice it's actually very complex with tons of
| nuance
|
| That's because computers are very complex with tons of nuance.
| fads_go wrote:
| Lisp is build from a few simple axioms. Would that make it
| simple?
| dwattttt wrote:
| So are entire branches of mathematics, and I feel safe in
| saying they are not "simple"
| tempodox wrote:
| Highly interesting! main(argc, argv) int
| argv[];
|
| This is a culture shock. Did the PDP-11 not distinguish between
| `char` and `int`?
| spijdar wrote:
| Of course it did -- this was one of the distinguishing features
| (byte addressing) of the PDP-11 vs the original machine that
| ran UNIX, the PDP-7, after all ;-)
|
| In "ancient"/K&R C, types weren't specified with the
| parameters, but on the following lines afterwards. GCC would
| still compile code like this, if passed the -traditional flag,
| until ... some point in the last decade or so. Still, this
| style was deprecated with ANSI C/C89, so it had a good run.
| jecel wrote:
| Here the `int` is being used in place of `char *`, not `char`.
|
| And yes, the PDP-11 did have byte addressing while the PDP-7 on
| which Unix was originally created was a word addressed machine.
| tempodox wrote:
| I see, now it makes sense.
| ZhiqiangWang wrote:
| Can't stop thinking about Ken Thompson Hack. This should be a
| clean one ...
| ricardo81 wrote:
| Reminds me of the humility every programmer should have,
| basically we're standing on the shoulders of giants and
| abstraction for the most part. 80+ years of computer science.
|
| Cool kids may talk about memory safety but ultimately someone had
| to take care of it, either in their code or abstracted out of it.
| wang_li wrote:
| Big non sequitur, but your comment triggered a peeve of mine
| that I find it ironic when people talk like oldsters can't
| understand technology.
| ricardo81 wrote:
| Your comment sounds like a riddle. I've programmed for 25
| years but appreciate there's a lot more going on than what I
| know.
| wang_li wrote:
| Upon my own rereading, it is unclear. My point is that the
| languages most of us use and the fundamental technologies
| in the oses we use were designed/invented by people who are
| in their 80s now, many of the Linux core team are 50-60.
| worik wrote:
| > ...people talk like oldsters can't understand technology
|
| IMO it is young people that have trouble understanding.
|
| The same mistakes are made over and over, lessons learned
| long ago are ignored in the present
|
| It easier to write than read, easier to talk than listen,
| build new than expand the old
| bigstrat2003 wrote:
| This is the way of young people in every domain, not just
| technology. Much like teenagers think they're the first
| ones to ever have sex before, young people tend to think
| they are the first ones to notice "hey this status quo
| really sucks" and try to solve it.
|
| This can be a strength, to be fair - the human mind really
| _does_ tend to get stuck in a rut based on familiarity, and
| someone new to the domain can spot solutions that others
| haven 't because of that. But more often, it turns into
| futile attempts to solve problems while forgetting the
| lessons of the past.
| phito wrote:
| Understanding one level of abstraction doesn't mean you
| understand the levels of abstraction built on top of it. And
| vice versa.
| estebank wrote:
| The "cool kids talking about memory safety" are indeed standing
| on the shoulders of giants, to allow for others to stand even
| taller.
| deweywsu wrote:
| Am I interpreting this repo correctly? The first C compiler was
| written in...C?
| schindlabua wrote:
| It would have been bootstrapped in assembly (or B/BCPL?) and
| then once you can compile enough C to write a C compiler you
| rewrite your compiler in C.
|
| I remember a Computerphile video where prof. Brailsford said
| something along the lines of "nobody knew who wrote the first C
| compiler, everybody just kinda had it and passed it around the
| office" which I think is funny. There's some sort of analogy to
| life and things emerging from the primordial soup there, if you
| squint hard enough.
| froh wrote:
| yes. the Q you're asking is: "how was this bootstrapped?"
|
| the page that's referenced from GitHub doesn't describe that
|
| http://cm.bell-labs.co/who/dmr/primevalC.html
|
| however there probably was a running c compiler (written in
| assembly) and an assembler and a linker available, hand
| bootstrapped from machine code, then assembler, linker, then B,
| NB and then C...
|
| We can't tell but that would make sense...
| xenadu02 wrote:
| The first B compiler was written in BCPL on the GE 635
| mainframe. Thompson wrote a B compiler in BCPL which they used
| to cross-compile for PDP-7. Then Thompson rewrote B in B, using
| the BCPL compiler to bootstrap. AFAIK this is the only clean
| "bootstrap" step involved in the birth of C (BCPL -> B -> self-
| compiled B)
|
| Then they tweaked the compiler and called it NB (New B), then
| eventually tweaked it enough they decided to call it C.
|
| The compiler continuously evolved by compiling new versions of
| itself through the B -> New B -> C transition. There was no
| clean cutoff to say "ah this was the first C compiler written
| in New B".
|
| You can see evidence of this in the "pre-struct" version of the
| compiler after Ritchie had added structure support but before
| the compiler itself actually used structs. They compiled that
| version of the compiler then modified the compiler source to
| use structs, thus all older versions of the compiler could no
| longer compile the compiler:
| https://web.archive.org/web/20140708222735/http://thechangel...
|
| Primeval C:
| https://web.archive.org/web/20140910102704/http://cm.bell-la...
|
| A modern bootstrapping compiler usually keeps around one or
| more "simplified" versions of the compiler's source. The
| simplest one either starts with C or assembly. Phase 0 is
| compiled or assembled then is used to compile Phase 1, which is
| used to compile Phase 2.
|
| (Technically if you parsed through all the backup tapes and
| restored the right versions of old compilers and compiler
| source you'd have the bootstrap chain for C but no one bothered
| to do that until decades later).
| ramon156 wrote:
| Love how unserious some of the code comments are. Makes you feel
| less noob for a second :')
| robertkoss wrote:
| As someone who has no touchpoints with lower languages at all,
| can you explain to me why those files are called c01, c02 etc.?
| higgins wrote:
| disappointed this didn't link to some analysis of clay tablets
| sbassi wrote:
| which compiler is used to compile the first compiler?
| sc68cal wrote:
| With BCPL
|
| https://web.archive.org/web/20250130134200/https://www.bell-...
|
| See also this comment
| https://news.ycombinator.com/item?id=43462794
| canucker2016 wrote:
| Can people who have used/were around at this time (early 1970s)
| give a description of the typical dev environment?
|
| Also helpful: C history
| https://en.wikipedia.org/wiki/C_language#History
|
| From wikipedia, early Unix was developed on PDP/11 (16-bit).
|
| signed 16-bit ints, 8-bit chars, arrays of those previous types.
|
| identifiers were limited in length? (I'm seeing 8 chars,
| lowercase, as the longest)
|
| octal numeric constants, was hexadecimal used?
|
| there was only a line editor available (vi was 1976)
|
| did the file system support directories at that point?
|
| no C preprocessor, no header files. (1973)
|
| no make/makefiles (1976)
|
| was there a std library used with the linker or an archive of
| object files that was the 'standard' library?
|
| Bourne shell wasn't around (1979), so wikipedia seems to point to
| the Thompson shell - https://en.wikipedia.org/wiki/Thompson_shell
|
| was there a debugger or was printf the only tool?
___________________________________________________________________
(page generated 2025-03-24 23:00 UTC)