158

Today, you need a real C compiler to be an optimizing compiler, notably because C is no longer a language close to the hardware, because current processors are incredibly complex (out-of-order, pipelined, superscalar, with complex caches & TLB, hence needing instruction scheduling, etc...). Today's x86 processors are not like i386 processors of the ...


145

As explained by Brian Goetz (Java Language Architect at Oracle) in this video: in jdk classes [...] there are a number of security sensitive methods that rely on counting stack frames between jdk library code and calling code to figure out who's calling them. Anything that changed the number of frames on the stack would break this and would cause an ...


122

Does the compiler store a copy of some garbage collection program and paste it into each executable it generates? It sounds unelegant and weird, but yes. The compiler has an entire utility library, containing a whole lot more than just garbage collection code, and calls to this library will be inserted into each executable it creates. This is called the ...


109

No. In general, the performance of a language implementation is primarily dependent on the amount of money, resources, manpower, research, engineering, and development spent on it. And specifically, the performance of a particular program is primarily dependent on the amount of thought put into its algorithms. There are some very fast interpreters out ...


104

You can't be certain, but you just assume they are, until you discover they are not. There have been plenty of bugs in compilers and hardware over the years. The way these are tested, for example a compiler, is that they are very narrowly and rigidly defined, carefully written, then tested with an enormous test suite to verify correctness. Add to that the ...


99

Writing a compiler seems like a much harder problem than an interpreter. That might be true today, but I would argue that it was not the case some 60 years ago. A few reasons why: With an interpreter, you have to keep both it and the program in memory. In an age where 1kb of memory was a massive luxury, keeping the running memory footprint low was key. And ...


95

I think you are approaching this problem from the wrong angle. Better let the generator place a clear and visible comment at the beginning of the C header file like // This file is autogenerated, don't change it manually, // any manual changes will get lost after next regeneration. then make generating the C file from the CSV file part of the build ...


81

You mention on how if the code is specific to a CPU, why must it be specific also to an OS. This is actually more of an interesting question that many of the answers here have assumed. CPU Security Model The first program run on most CPU architectures runs inside what is called the inner ring or ring 0. How a specific CPU arch implements rings varies, but ...


81

The terms "interpreter" and "compiler" are much more fuzzy than they used to be. Many years ago it was more common for compilers to produce machine code to be executed later, while interpreters more or less "executed" the source code directly. So those two terms were well understood back then. But today there are many variations on the use of "compiler" ...


80

Generalizations and specific scenarios are literally opposites. You seem to be contradicting yourself. On the one hand, you want to make a general statement about interpreted vs compiled languages. But on the other hand, you want to apply that general statement to a concrete scenario involving Technology A and Technology B. Once you apply something to a ...


79

I wouldn't go so far as to call it "bad practice" per se, but neither am I convinced it's really the right solution to your problem. If all you want is four separate functions to do your four data types, why do not what C programmers have done since time immemorial: void transmit_uchar_buffer(unsigned char *buffer); void transmit_char_buffer(char *buffer); ...


75

This is called "inlining" and many compilers do this as an optimization strategy in cases where it makes sense. In your particular example, this optimization would save both space and execution time. But if the function was called in multiple places in the program (not uncommon!), it would increase code size, so the strategy becomes more dubious. (And of ...


73

I would like to contest your underlying assumption that there are only a small number of C implementations. I don't even know C, I don't use C, I am not a member of the C community, and yet, even I know far more than the few compilers you mentioned. First and foremost, there is the compiler which probably completely dwarfs both GCC and Clang on the desktop:...


67

Because the standard writers don't want to actually assert an implementation. They want to define what it does, but not necessarily how it does it. So, for example, if you look at the GNU C++ version of find_if, you will see that the implementation is slightly different from what you give, which is based on the C++ standard: template<typename ...


64

Tranlating to C code is a very well established habit. The original C with classes (and the early C++ implementations, then called Cfront) did that successfully. Several implementations of Lisp or Scheme are doing that, e.g. Chicken Scheme, Scheme48, Bigloo. Some people translated Prolog to C. And so did some versions of Mozart (and there have been attempts ...


62

It means all of its production rules have a single non-terminal on their left hand side. For example, this grammar which recognizes strings of matched parentheses ("()", "()()", "(())()", ...) is context-free: S → SS S → (S) S → () The left-hand side of every rule consists of a single non-terminal (in this case it's always S, but there could be more.) ...


62

The general problem is that it’s very easy to encode undocumented assumptions in a program, and very hard to find places where those assumptions were made. High-level languages tend to insulate us from these concerns somewhat, but in lower-level languages used for implementing platforms and services, it’s easy to do things that are not necessarily portable ...


58

Or does the compiler include some minimal garbage collector in the compiled program's code. That’s an odd way of saying “the compiler links the program with a library that performs garbage collection”. But yes, that’s what’s happening. This is nothing special: compilers usually link tons of libraries into the programs they compile; otherwise compiled ...


56

Using only some features of C++ while otherwise treating it as C is not exactly common, but also not exactly unheard of either. In fact, some people even use no features at all of C++, except the stricter and more powerful type checking. They simply write C (taking care to write only in the common intersection of C++ and C), then compile with a C++ compiler ...


55

Garbage collection in a compiled language works the same way as in an interpreted language. Languages like Go use tracing garbage collectors even though their code is usually compiled to machine code ahead-of-time. (Tracing) garbage collection usually starts by walking the call stacks of all threads that are currently running. Objects on those stacks are ...


54

Asuming expensive_calc_one and expensive_calc_two are pure functions Unfortunately, determining whether a function is pure is equivalent to solving the Halting Problem in the general case. So, you cannot have an Ahead-of-Time compiler which can in the general case decide whether a function is pure or not. You have to help the compiler by explicitly ...


52

The short answer is that you use stacks. This is a good example, but I'll apply it to an AST. FYI, this is Edsger Dijkstra's Shunting-Yard Algorithm. In this case, I will use an operator stack and an expression stack. Since numbers are considered expressions in most languages, I'll use the expression stack to store them. class ExprNode: char c ...


49

As you can see, APIs are not indicated as a part of the operating system. I think you are reading too much into the diagram. Yes, an OS will specify a binary interface for how operating system functions are called, and it will also define a file format for executables, but it will also provide an API, in the sense of providing a catalog of functions that ...


47

The short answer is that JIT has longer initialization times, but is a lot faster in the long run, and JavaScript wasn't originally intended for the long run. In the 90s, typical JavaScript on a web site would amount to one or two functions in the header, and a handful of code embedded directly in onclick properties and the like. It would typically get run ...


46

In layman's terms: You cannot. Compilers and interpreters are unit-tested as any other (professional) software. A sucessful test doesn't mean a program is bug-free, it only means no bugs were detected. A wide user base using the compiler during a long time is a pretty indicator of it having very few bugs, because users usually test cases the designers didn'...


44

What is the usually method used when a compiler is type checking expressions with many operators and operands. Read wikipages on type system and type inference and on Hindley-Milner type system, which uses unification. Read also about denotational semantics and operational semantics. Type checking can be simpler if: all your variables like a are ...


42

The fundamental point is that the computing hardware environment of the 1950s made it such that only a compiler was feasible given the batch-oriented processing of computers back then. At the time the better user interfaces were primarily limited to punch cards and teletype printers. In 1961 the SAGE system became the first Cathode-Ray Tube (CRT) display on ...


41

At every step of compilation you lose information that is irrecoverable. The more information you lose from the original source, the harder it is to decompile. You can create a useful de-compiler for byte-code because a lot more information is preserved from the original source than is preserved when producing the final target machine code. The first step ...


41

Don't commit the generated C header file at all. In fact, delete the current file (thanks @user1936), change the script to call the header file .g.h (thanks @davidbak), and add it to .gitignore, so it doesn't get committed accidentally (thanks @cmaster). Instead, commit the csv and python script, and add some custom step to generate the C header file at ...


Only top voted, non community-wiki answers of a minimum length are eligible