JavaScript seems to be disabled in your browser. For the best experience on our site, be sure to turn on Javascript in your browser.
Exclusive access to over 200,000 completely editable slides.
(4 Editable Slides)
Download Now
Gain access to over 200,000 slides with pro plan..
Upgrade Now
Already a Pro customer? Login
(15 Editable Slides)
(13 Editable Slides)
(14 Editable Slides)
(12 Editable Slides)
(7 Editable Slides)
Download our Compiler Design PPT template to describe the structure and principles that guide a compiler's translation and optimization process. Programmers can use this entirely customizable deck to explain how compilers help implement high-level programming languages and make the end code efficient. You can also use this set to discuss the features and applications of compiler technology.
We have ensured that the graphics embedded in this PowerPoint template are easy on the eyes and not overwhelming to help your viewers actively engage and interact with you on the topic. Just download this set right away!
Download the PPT now for an excellent slideshow!
Course info.
Computation structures, 11 compilers.
ContinueAnnotated Slides
11.1 Annotated Slides
11.2 Topic Videos
11.3 Worksheet
11.3.1 Compilation Worksheet
Content of the following slides is described in the surrounding text.
Today we’re going to talk about how to translate high-level languages into code that computers can execute.
So far we’ve seen the Beta ISA, which includes instructions that control the datapath operations performed on 32-bit data stored in the registers. There are also instructions for accessing main memory and changing the program counter. The instructions are formatted as opcode, source, and destination fields that form 32-bit values in main memory.
To make our lives easier, we developed assembly language as a way of specifying sequences of instructions. Each assembly language statement corresponds to a single instruction. As assembly language programmers, we’re responsible for managing which values are in registers and which are in main memory, and we need to figure out how to break down complicated operations, e.g. , accessing an element of an array, into the right sequence of Beta operations.
We can go one step further and use high-level languages to describe the computations we want to perform. These languages use variables and other data structures to abstract away the details of storage allocation and the movement of data to and from main memory. We can just refer to a data object by name and let the language processor handle the details. Similarly, we’ll write expressions and other operators such as assignment (=) to efficiently describe what would require many statements in assembly language.
Today we’re going to dive into how to translate high-level language programs into code that will run on the Beta.
Here we see Euclid’s algorithm for determining the greatest common divisor of two numbers, in this case the algorithm is written in the C programming language. We’ll be using a simple subset of C as our example high-level language. Please see the brief overview of C in the Handouts section if you’d like an introduction to C syntax and semantics. C was developed by Dennis Ritchie at AT&T Bell Labs in the late 60’s and early 70’s to use when implementing the Unix operating system. Since that time many new high-level languages have been introduced providing modern abstractions like object-oriented programming along with useful new data and control structures.
Using C allows us describe a computation without referring to any of the details of the Beta ISA like registers, specific Beta instructions, and so on. The absence of such details means there is less work required to create the program and makes it easier for others to read and understand the algorithm implemented by the program.
There are many advantages to using a high-level language. They enable programmers to be very productive since the programs are concise and readable. These attributes also make it easy to maintain the code. Often it is harder to make certain types of mistakes since the language allows us to check for silly errors like storing a string value into a numeric variable. And more complicated tasks like dynamically allocating and deallocating storage can be completely automated. The result is that it can take much less time to create a correct program in a high-level language than it would it when writing in assembly language.
Since the high-level language has abstracted away the details of a particular ISA, the programs are portable in the sense that we can expect to run the same code on different ISAs without having to rewrite the code.
What do we lose by using a high-level language? Should we worry that we’ll pay a price in terms of the efficiency and performance we might get by crafting each instruction by hand? The answer depends on how we choose to run high-level language programs. The two basic execution strategies are “interpretation” and “compilation”.
To interpret a high-level language program, we’ll write a special program called an “interpreter” that runs on the actual computer, M1. The interpreter mimics the behavior of some abstract easy-to-program machine M2 and for each M2 operation executes sequences of M1 instructions to achieve the desired result. We can think of the interpreter along with M1 as an implementation of M2, i.e. , given a program written for M2, the interpreter will, step-by-step, emulate the effect of M2 instructions.
We often use several layers of interpretation when tackling computation tasks. For example, an engineer may use her laptop with an Intel CPU to run the Python interpreter. In Python, she loads the SciPy toolkit, which provides a calculator-like interface for numerical analysis for matrices of data. For each SciPy command, e.g. , “find the maximum value of a dataset”, the SciPy tool kit executes many Python statements, e.g. , to loop over each element of the array, remembering the largest value. For each Python statement, the Python interpreter executes many x86 instructions, e.g. , to increment the loop index and check for loop termination. Executing a single SciPy command may require executing of tens of Python statements, which in turn each may require executing hundreds of x86 instructions. The engineer is very happy she didn’t have to write each of those instructions herself!
Interpretation is an effective implementation strategy when performing a computation once, or when exploring which computational approach is most effective before making a more substantial investment in creating a more efficient implementation.
We’ll use a compilation implementation strategy when we have computational tasks that we need to execute repeatedly and hence we are willing to invest more time up-front for more efficiency in the long-term.
In compilation, we also start with our actual computer M1. Then we’ll take our high-level language program P2 and translate it statement-by-statement into a program for M1. Note that we’re not actually running the P2 program. Instead we’re using it as a template to create an equivalent P1 program that can execute directly on M1. The translation process is called “compilation” and the program that does the translation is called a “compiler”.
We compile the P2 program once to get the translation P1, and then we’ll run P1 on M1 whenever we want to execute P2. Running P1 avoids the overhead of having to process the P2 source and the costs of executing any intervening layers of interpretation. Instead of dynamically figuring out the necessary machine instructions for each P2 statement as it’s encountered, in effect we’ve arranged to capture that stream of machine instructions and save them as a P1 program for later execution. If we’re willing to pay the up-front costs of compilation, we’ll get more efficient execution.
And, with different compilers, we can arrange to run P2 on many different machines — M2, M3, etc. — without having rewrite P2.
So we now have two ways to execute a high-level language program: interpretation and compilation. Both allow us to change the original source program. Both allow us to abstract away the details of the actual computer we’ll use to run the program. And both strategies are widely used in modern computer systems!
Let’s summarize the differences between interpretation and compilation.
Suppose the statement “x+2” appears in the high-level program. When the interpreter processes this statement it immediately fetches the value of the variable x and adds 2 to it. On the other hand, the compiler would generate Beta instructions that would LD the variable x into a register and then ADD 2 to that value.
The interpreter is executing each statement as it’s processed and, in fact, may process and execute the same statement many times if, e.g. , it was in a loop. The compiler is just generating instructions to be executed at some later time.
Interpreters have the overhead of processing the high-level source code during execution and that overhead may be incurred many times in loops. Compilers incur the processing overhead once, making the eventual execution more efficient. But during development, the programmer may have to compile and run the program many times, often incurring the cost of compilation for only a single execution of the program. So the compile-run-debug loop can take more time.
The interpreter is making decisions about the data type of x and the type of operations necessary at run time, i.e. , while the program is running. The compiler is making those decisions during the compilation process.
Which is the better approach? In general, executing compiled code is much faster than running the code interpretively. But since the interpreter is making decisions at run time, it can change its behavior depending, say, on the type of the data in the variable X, offering considerable flexibility in handling different types of data with the same algorithm. Compilers take away that flexibility in exchange for fast execution.
A compiler is a program that translates a high-level language program into a functionally equivalent sequence of machine instructions, i.e. , an assembly language program.
A compiler first checks that the high-level program is correct, i.e. , that the statements are well formed, the programmer isn’t asking for nonsensical computations — e.g. , adding a string value and an integer — or attempting to use the value of a variable before it has been properly initialized. The compiler may also provide warnings when operations may not produce the expected results, e.g. , when converting from a floating-point number to an integer, where the floating-point value may be too large to fit in the number of bits provided by the integer.
If the program passes scrutiny, the compiler then proceeds to generate efficient sequences of instructions, often finding ways to rearrange the computation so that the resulting sequences are shorter and faster. It’s hard to beat a modern optimizing compiler at producing assembly language, since the compiler will patiently explore alternatives and deduce properties of the program that may not be apparent to even diligent assembly language programmers.
In this section, we’ll look at a simple technique for compiling C programs into assembly. Then, in the next section, we’ll dive more deeply into how a modern compiler works.
There are two main routines in our simple compiler: compile_statement and compile_expr. The job of compile_statement is to compile a single statement from the source program. Since the source program is a sequence of statements, we’ll be calling compile_statement repeatedly.
We’ll focus on the compilation technique for four types of statements. An unconditional statement is simply an expression that’s evaluated once. A compound statement is simply a sequence of statements to be executed in turn. Conditional statements, sometimes called “if statements”, compute the value of an test expression, e.g. , a comparison such as “A < B”. If the test is true then statement 1
The other main routine is compile_expr whose job it is to generate code to compute the value of an expression, leaving the result in some register. Expressions take many forms:
simple constant values,
values from scalar or array variables,
assignment expressions that compute a value and then store the result in some variable,
unary or binary operations that combine the values of their operands with the specified operator. Complex arithmetic expressions can be decomposed into sequences of unary and binary operations.
And, finally, procedure calls, where a named sequence of statements will be executed with the values of the supplied arguments assigned as the values for the formal parameters of the procedure. Compiling procedures and procedure calls is a topic that we’ll tackle next lecture since there are some complications to understand and deal with.
Happily, compiling the other types of expressions and statements is straightforward, so let’s get started.
What code do we need to put the value of a constant into a register? If the constant will fit into the 16-bit constant field of an instruction, we can use CMOVE to load the sign-extended constant into a register. This approach works for constants between -32768 and +32767. If the constant is too large, it’s stored in a main memory location and we use a LD instruction to get the value into a register.
Loading the value of a variable is much the same as loading the value of a large constant: we use a LD instruction to access the memory location that holds the value of the variable.
Performing an array access is slightly more complicated: arrays are stored as consecutive locations in main memory, starting with index 0. Each array element occupies some fixed number of bytes. So we need code to convert the array index into the actual main memory address for the specified array element.
We first invoke compile_expr to generate code that evaluates the index expression and leaves the result in Rx. That will be a value between 0 and the size of the array minus 1. We’ll use a LD instruction to access the appropriate array entry, but that means we need to convert the index into a byte offset, which we do by multiplying the index by bsize, the number of bytes in one element. If b was an array of integers, bsize would be 4. Now that we have the byte offset in a register, we can use LD to add the offset to the base address of the array computing the address of the desired array element, then load the memory value at that address into a register.
Assignment expressions are easy: invoke compile_expr to generate code that loads the value of the expression into a register, then generate a ST instruction to store the value into the specified variable.
Arithmetic operations are pretty easy too: use compile_expr to generate code for each of the operand expressions, leaving the results in registers. Then generate the appropriate ALU instruction to combine the operands and leave the answer in a register.
Let’s look at example to see how all this works. Here we have an assignment expression that requires a subtract, a multiply, and an addition to compute the required value.
Let’s follow the compilation process from start to finish as we invoke compile_expr to generate the necessary code.
Following the template for assignment expressions from the previous page, we recursively call compile_expr to compute value of the right-hand-side of the assignment.
That’s a multiply operation, so, following the Operations template, we need to compile the left-hand operand of the multiply.
That’s a subtract operation, so, we call compile_expr again to compile the left-hand operand of the subtract.
Aha, we know how to get the value of a variable into a register. So we generate a LD instruction to load the value of x into r1.
The process we’re following is called “recursive descent”. We’ve used recursive calls to compile_expr to process each level of the expression tree. At each recursive call the expressions get simpler, until we reach a variable or constant, where we can generate the appropriate instruction without descending further. At this point we’ve reached a leaf of the expression tree and we’re done with this branch of the recursion.
We now need to get the value of the right-hand operand of the subtract into a register. In case it’s a small constant, so we generate a CMOVE instruction.
Now that both operand values are in registers, we return to the subtract template and generate a SUB instruction to do the subtraction. We now have the value for the left-hand operand of the multiply in r1.
We follow the same process for the right-hand operand of the multiply, recursively calling compile_expr to process each level of the expression until we reach a variable or constant. Then we return up the expression tree, generating the appropriate instructions as we go, following the dictates of the appropriate template from the previous slide.
The generated code is shown on the left of the slide. The recursive-descent technique makes short work of generating code for even the most complicated of expressions.
There’s even opportunity to find some simple optimizations by looking at adjacent instructions. For example, a CMOVE followed by an arithmetic operation can often be shortened to a single arithmetic instruction with the constant as its second operand. These local transformations are called “peephole optimizations” since we’re only considering just one or two instructions at a time.
Now let’s turn our attention to compile_statement.
The first two statement types are pretty easy to handle. Unconditional statements are usually assignment expressions or procedure calls. We’ll simply ask compile_expr to generate the appropriate code.
Compound statements are equally easy. We’ll recursively call compile_statement to generate code for each statement in turn. The code for statement_2 will immediately follow the code generated for statement_1. Execution will proceed sequentially through the code for each statement.
Here we see the simplest form of the conditional statement, where we need to generate code to evaluate the test expression and then, if the value in the register is FALSE, skip over the code that executes the statement in the THEN clause. The simple assembly-language template uses recursive calls to compile_expr and compile_statement to generate code for the various parts of the IF statement.
The full-blown conditional statement includes an ELSE clause, which should be executed if the value of the test expression is FALSE. The template uses some branches and labels to ensure the course of execution is as intended.
You can see that the compilation process is really just the application of many small templates that break the code generation task down step-by-step into smaller and smaller tasks, generating the necessary code to glue all the pieces together in the appropriate fashion.
And here’s the template for the WHILE statement, which looks a lot like the template for the IF statement with a branch at the end that causes the generated code to be re-executed until the value of the test expression is FALSE.
With a bit of thought, we can improve on this template slightly. We’ve reorganized the code so that only a single branch instruction (BT) is executed each iteration, instead of the two branches (BF, BR) per iteration in the original template. Not a big deal, but little optimizations to code inside a loop can add up to big savings in a long-running program.
Just a quick comment about another common iteration statement, the FOR loop. The FOR loop is a shorthand way of expressing iterations where the loop index (“i” in the example shown) is run through a sequence of values and the body of the FOR loop is executed once for each value of the loop index.
The FOR loop can be transformed into the WHILE statement shown here, which can then be compiled using the templates shown above.
In this example, we’ve applied our templates to generate code for the iterative implementation of the factorial function that we’ve seen before. Look through the generated code and you’ll be able to match code fragments with the templates from last couple of slides. It’s not the most efficient code, but not bad given the simplicity of the recursive-descent approach for compiling high-level programs.
It’s a simple matter to modify the recursive-descent process to accommodate variable values that are stored in dedicated registers rather than in main memory. Optimizing compilers are quite good at identifying opportunities to keep values in registers and hence avoid the LD and ST operations needed to access values in main memory. Using this simple optimization, the number of instructions in the loop has gone from 10 down to 4. Now the generated code is looking pretty good!
But rather than keep tweaking the recursive-descent approach, let’s stop here. In the next segment, we’ll see how modern compilers take a more general approach to generating code. Still though, the first time I learned about recursive descent, I ran home to write a simple implementation and marveled at having authored my own compiler in an afternoon!
A modern compiler starts by analyzing the source program text to produce an equivalent sequence of operations expressed in a language — and machine-independent intermediate representation (IR). The analysis, or frontend, phase checks that the program is well-formed, i.e. , that the syntax of each high-level language statement is correct. It understands the meaning (semantics) of each statement. Many high-level languages include declarations of the type — e.g. , integer, floating point, string, etc. — of each variable, and the frontend verifies that all operations are correctly applied, ensuring that numeric operations have numeric-type operands, string operations have string-type operands, and so on. Basically the analysis phase converts the text of the source program into an internal data structure that specifies the sequence and type of operations to be performed.
Often there are families of frontend programs that translate a variety of high-level languages (e.g, C, C++, Java) into a common IR.
The synthesis, or backend, phase then optimizes the IR to reduce the number of operations that will be executed when the final code is run. For example, it might find operations inside of a loop that are independent of the loop index and can moved outside the loop, where they are performed once instead of repeatedly inside the loop. Once the IR is in its final optimized form, the backend generates code sequences for the target ISA and looks for further optimizations that take advantage of particular features of the ISA. For example, for the Beta ISA we saw how a CMOVE followed by an arithmetic operation can be shorted to a single operation with a constant operand.
The analysis phase starts by scanning the source text and generating a sequence of token objects that identify the type of each piece of the source text. While spaces, tabs, newlines, and so on were needed to separate tokens in the source text, they’ve all been removed during the scanning process. To enable useful error reporting, token objects also include information about where in the source text each token was found, e.g. , the file name, line number, and column number. The scanning phase reports illegal tokens, e.g. , the token “3x” would cause an error since in C it would not be a legal number or a legal variable name.
The parsing phase processes the sequence of tokens to build the syntax tree, which captures the structure of the original program in a convenient data structure. The operands have been organized for each unary and binary operation. The components of each statement have been found and labeled. The role of each source token has been determined and the information captured in the syntax tree.
Compare the labels of the nodes in the tree to the templates we discussed in the previous segment. We can see that it would be easy to write a program that did a depth-first tree walk, using the label of each tree node to select the appropriate code generation template. We won’t do that quite yet since there’s still some work to be done analyzing and transforming the tree.
The syntax tree makes it easy to verify that the program is semantically correct, e.g. , to check that the types of the operands are compatible with the requested operation.
For example, consider the statement x = “bananas”. The syntax of the assignment operation is correct: there’s a variable on the left-hand side and an expression on the right-hand side. But the semantics is not correct, at least in the C language! By looking in its symbol table to check the declared type for the variable x (int) and comparing it to the type of the expression (string), the semantic checker for the “op =” tree node will detect that the types are not compatible, i.e. , that we can’t store a string value into an integer variable.
When the semantic analysis is complete, we know that the syntax tree represents a syntactically correct program with valid semantics, and we’ve finished converting the source program into an equivalent, language-independent sequence of operations.
The syntax tree is a useful intermediate representation (IR) that is independent of both the source language and the target ISA. It contains information about the sequencing and grouping of operations that isn’t apparent in individual machine language instructions. And it allows frontends for different source languages to share a common backend targeting a specific ISA. As we’ll see, the backend processing can be split into two sub-phases. The first performs machine-independent optimizations on the IR. The optimized IR is then translated by the code generation phase into sequences of instructions for the target ISA.
A common IR is to reorganize the syntax tree into what’s called a control flow graph (CFG). Each node in the graph is a sequence of assignment and expression evaluations that ends with a branch. The nodes are called “basic blocks” and represent sequences of operations that are executed as a unit: once the first operation in a basic block is performed, the remaining operations will also be performed without any other intervening operations. This knowledge lets us consider many optimizations, e.g. , temporarily storing variable values in registers, that would be complicated if there was the possibility that other operations outside the block might also need to access the variable values while we were in the middle of this block.
The edges of the graph indicate the branches that take us to another basic block.
For example, here’s the CFG for GCD.
If a basic block ends with a conditional branch, there are two edges, labeled “T” and “F” leaving the block that indicate the next block to execute depending on the outcome of the test. Other blocks have only a single departing arrow, indicating that the block always transfers control to the block indicated by the arrow.
Note that if we can arrive at a block from only a single predecessor block, then any knowledge we have about operations and variables from the predecessor block can be carried over to the destination block. For example, if the “if (x > y)” block has generated code to load the values of x and y into registers, both destination blocks can use that information and use the appropriate registers without having to generate their own LDs.
But if a block has multiple predecessors, such optimizations are more constrained: we can only use knowledge that is common to *all* the predecessor blocks.
The CFG looks a lot like the state transition diagram for a high-level FSM!
We’ll optimize the IR by performing multiple passes over the CFG. Each pass performs a specific, simple optimization. We’ll repeatedly apply the simple optimizations in multiple passes, until the we can’t find any further optimizations to perform. Collectively, the simple optimizations can combine to achieve very complex optimizations.
Here are some example optimizations:
We can eliminate assignments to variables that are never used and basic blocks that are never reached. This is called “dead code elimination”.
In constant propagation, we identify variables that have a constant value and substitute that constant in place of references to the variable.
We can compute the value of expressions that have constant operands. This is called “constant folding”.
To illustrate how these optimizations work, consider this slightly silly source program and its CFG. Note that we’ve broken down complicated expressions into simple binary operations, using temporary variable names (e.g, “_t1”) to name the intermediate results.
Let’s get started!
The dead code elimination pass can remove the assignment to Z in the first basic block since Z is reassigned in subsequent blocks and the intervening code makes no reference to Z.
Next we look for variables with constant values. Here we find that X is assigned the value of 3 and is never re-assigned, so we can replace all references to X with the constant 3.
Now perform constant folding, evaluating any constant expressions.
Here’s the updated CFG, ready for another round of optimizations.
First dead code elimination.
Then constant propagation.
And, finally, constant folding.
So after two rounds of these simple operations, we’ve thinned out a number of assignments. On to round three!
Dead code elimination. And here we can determine the outcome of a conditional branch, eliminating entire basic blocks from the IR, either because they’re now empty or because they can no longer be reached.
Wow, the IR is now considerably smaller.
Next is another application of constant propagation.
And then constant folding.
Followed by more dead code elimination.
The passes continue until we discover there are no further optimizations to perform, so we’re done!
Repeated applications of these simple transformations have transformed the original program into an equivalent program that computes the same final value for Z.
We can do more optimizations by adding passes: eliminating redundant computation of common subexpressions, moving loop-independent calculations out of loops, unrolling short loops to perform the effect of, say, two iterations in a single loop execution, saving some of the cost of increment and test instructions. Optimizing compilers have a sophisticated set of optimizations they employ to make smaller and more efficient code.
Okay, we’re done with optimizations. Now it’s time to generate instructions for the target ISA.
First the code generator assigns each variable a dedicated register. If we have more variables than registers, some variables are stored in memory and we’ll use LD and ST to access them as needed. But frequently-used variables will almost certainly live as much as possible in registers.
Use our templates from before to translate each assignment and operation into one or more instructions.
Then emit the code for each block, adding the appropriate labels and branches.
Reorder the basic block code to eliminate unconditional branches wherever possible.
And finally perform any target-specific peephole optimizations.
Here’s the original CFG for the GCD code, along with the slightly optimized CFG. GCD isn’t as trivial as the previous example, so we’ve only been able to do a bit of constant propagation and constant folding.
Note that we can’t propagate knowledge about variable values from the top basic block to the following “if” block since the “if” block has multiple predecessors.
Here’s how the code generator will process the optimized CFG.
First, it dedicates registers to hold the values for x and y.
Then, it emits the code for each of the basic blocks.
Next, reorganize the order of the basic blocks to eliminate unconditional branches wherever possible.
The resulting code is pretty good. There are no obvious changes that a human programmer might make to make the code faster or smaller. Good job, compiler!
Here are all the compilation steps shown in order, along with their input and output data structures. Collectively they transform the original source code into high-quality assembly code. The patient application of optimization passes often produces code that’s more efficient than writing assembly language by hand.
Nowadays, programmers are able to focus on getting the source code to achieve the desired functionality and leave the details of translation to instructions in the hands of the compiler.
This worksheet contains exercises for the lecture, selected from old quiz problems. If you can successfully answer the questions on the worksheet, you’ve mastered the material for the lecture! We’ve also included a link to the answers, but you’ll get the most out of the worksheet if you work on the exercises before reading the answers.
Click here to open worksheet PDF in a new window.
Click here to open answer PDF in a new window.
JavaScript seems to be disabled in your browser. For the best experience on our site, be sure to turn on Javascript in your browser.
You must be logged in to download this file*
item details (4 Editable Slides)
(4 Editable Slides)
Grab our Compiler Design presentation template for MS PowerPoint and Google Slides and effectively showcase information on the structure and guidelines that facilitate a compiler's translation, analysis, and optimization process. Deliver a memorable presentation in a hassle-free manner using our fully customizable deck!
This visual aid is ideal for programmers to showcase their ideas and information related to this topic. Use the intriguing PPT to demonstrate the major phases of compiler design and explain the significance and objective of each phase. You can also highlight this process's challenges and architectural design in a visually appealing manner. Moreover, you can illustrate the bottom-up and top-down parsing process in compiler design that analyzes the structure of a program's code and determines if it conforms to the syntax rules of the programming language.
Size | XS | S | S | M | M | L |
---|---|---|---|---|---|---|
EU | 32 | 34 | 36 | 38 | 40 | 42 |
UK | 4 | 6 | 8 | 10 | 12 | 14 |
US | 0 | 2 | 4 | 6 | 8 | 10 |
Bust | 79.5cm / 31" | 82cm / 32" | 84.5cm / 33" | 89.5cm / 35" | 94.5cm / 37" | 99.5cm / 39" |
Waist | 61.5cm / 24" | 64cm / 25" | 66.5cm / 26" | 71.5cm / 28" | 76.5cm / 30" | 81.5cm / 32" |
Hip | 86.5cm / 34" | 89cm / 35" | 91.5cm / 36" | 96.5cm / 38" | 101.5cm / 40" | 106.5cm / 42" |
Size | XS | S | M | L | XL | XXL |
---|---|---|---|---|---|---|
UK/US | 34 | 36 | 38 | 40 | 42 | 44 |
Neck | 37cm / 14.5" | 38cm /15" | 39.5cm / 15.5" | 41cm / 16" | 42cm / 16.5" | 43cm / 17" |
Chest | 86.5cm / 34" | 91.5cm / 36" | 96.5cm / 38" | 101.5cm / 40" | 106.5cm / 42" | 111.5cm / 44" |
Waist | 71.5cm / 28" | 76.5cm / 30" | 81.5cm / 32" | 86.5cm / 34" | 91.5cm / 36" | 96.5cm / 38" |
Seat | 90cm / 35.4" | 95cm / 37.4" | 100cm / 39.4" | 105cm / 41.3" | 110cm / 43.3" | 115cm / 45.3" |
The First edition of Innovations In Compiler Technology (IICT) Workshop will be held at Dayananda Sagar College of Engineering, Bangalore, India ( compilertech.org ). The two-day workshop will be in-person. Submission GuidelinesThe IICT (Innovations In Compiler Technology) workshop aims to bring together researchers, practitioners, and enthusiasts in the field of compiler technologies. This year's theme focuses on the cutting-edge advancements in compiler design, implementation, and optimization, and their impact on emerging software and hardware platforms. We invite presentation proposals for our upcoming workshop. List of TopicsWe invite speakers from academia and industry to present their work in one of the following tracks.
We are looking for:
Proposals should provide sufficient information for the review committee to be able to judge the quality of the submission. Proposals can be submitted under the form of an extended abstract, full paper, or slides. Accepted presentations must be presented in-person. The presentations and recordings may be publicly available in future. In case of any queries please reach out to the workshop organizers: What types of people attend?
Program Committee
Organizing committee
Dayananda Sagar College of Engineering, Bangalore, India In case of any queries please reach out to the workshop organizers: [email protected], Aditya Kumar ([email protected]) CS343 - Advanced Topics in CompilersSpring 2010, class abstract. Compiler research for a long time was moribund, stuck on narrow topics such as register allocation and instruction scheduling. In contrast, the last decade has seen an explosion of interesting work using compilers to accomplish something cool. This class will cover a selection of such research papers, ranging across static and dynamic bug finding, binary analysis, reverse engineering, programming via sketching, and other topics that seem worth knowing. The class is discussion oriented. You will read (typically) one paper before each class thoroughly, which will be dissected during the class period. By the end of the course you will be able to read a technical paper and extract its essence as well as noticing when the authors have sinned by omission in their experiments or wording. Papers will be somewhat bimodal. We will often start with an older one to set the stage (since they are simpler), and then a later one so you can see what the current thinking is. In addition, students will form groups of 1-3 and do a final project of their design which they will present. Staff | Logistics | Schedule
|
| Suhabe Bugrara | Office | Gates 324 | Office hours | TBD |
Lectures | Tues, Thurs 2:15 to 3:30 in 380-380C |
Prerequisites | cs243 or permission from instructor |
Staff mailing list |
|
Midterm | May 11th |
Project Presentations | June 9th |
Final exam | June 1st |
Topic | Lecture notes | |
Mar 30 (Tue) | ||
April 1 (Thu) | ||
April 6 (Tue) | | |
April 8 (Thu) | Guest Lecture: Overflow Checking in Firefox, Brian Hackett, Mozilla | |
April 13 (Tue) | ||
April 15 (Thu) | | |
April 20 (Tue) | ||
April 22 (Thu) | ||
April 27 (Tue) | Guest Lecture: Failure Oblivious Computing, Martin Rinard, MIT | |
April 29 (Thu) | | |
May 4 (Tue) | ||
May 6 (Thu) | Guest Lecture: , Russ Cox, Google | |
May 11 (Tue) | Midterm | |
May 13 (Thu) | Guest Lecture: , Kayvon Fatahalian, Stanford | |
May 18 (Tue) | | |
May 20 (Thu) | Guest Lecture: , Alex Aiken, Stanford | |
May 25 (Tue) | ||
May 27 (Thu) | ||
June 1 (Tue) |
Hardcopies of the course material and graded assignments will be distributed during class. Extras and assignments that are not picked up will be placed in the handout bin on the 3rd floor of Gates. Turn left as you come off the elevator and head across the hall to the nook between the two wings. There is a file cabinet with a drawer for CS243.
SCPD students: Please download the lecture notes before the lecture; the material will be available by the morning of the lecture. Your assignments will be returned via the SCPD courier. Since all the material for the assignments will be available on the web, you have to give your assignemnts to the SPCD courier (or hand it in electronically) on the same day as everybody else.
Group Work: Homework will consist of both written and programming assignments. You are encouraged to work on the programming assignments in groups of two, but you must do the written assignments by yourself.
Late Policy: In general, no late assignments are accepted. However, you have two grace days for the entire quarter. That means you can be late by one day for two assignments, or use the two days up for one assignment.
Submission: Homework should be submitted in class only. If you do not come to class it should be handed to Darlene Hadding in Gates 408 who will write the date and time of the submission. Late homeworks should also be directed to Darlene. We do not check the file cabinet for homework! SCPD students may submit their homework by e-mail via [email protected] .
Apr 29, 2012
170 likes | 665 Views
Principles of Compiler Design. Sanjeev K Aggarwal Department of Computer Science and Engineering, IIT Kanpur [email protected]. Motivation for doing this course. Language processing is an important component of programming
Principles of Compiler Design Sanjeev K Aggarwal Department of Computer Science and Engineering, IIT Kanpur [email protected]
Motivation for doing this course • Language processing is an important component of programming • A large number of systems software and application programs require structured input • Operating Systems (command line processing) • Databases (Query language processing) • Type setting systems like Latex, Nroff, Troff, Equation editors, M4 • VLSI design and testing, • Software quality assurance and software testing
XML, html based systems, Awk, Sed, Emacs, vi …. • Form processing, extracting information automatically from forms • Compilers, assemblers and linkers • High level language to language translators • Natural language processing • Where ever input has a structure one can think of language processing • Why study compilers? Compilers use the whole spectrum of language processing technology
Many common applications require structured input during development phase (design of banner programme of Unix) 9x 9x 9x 3b 3x 3b 3x 3b 3x 3b 3x 3b 3x 3b 3x 9x 9x 9x xxxxxxxxx xxxxxxxxx xxxxxxxxx xxx xxx xxx xxx xxx xxx xxxxxxxxx xxxxxxxxx xxxxxxxxx 3 9x 6 3b 3x 3 9x
What will we learn in the course? • How high level languages are implemented to generate machine code. Complete structure of compilers and how various parts are composed together to get a compiler • Course has theoretical and practical components. Both are needed in implementing programming languages. The focus will be on practical application of the theory. • Emphasis will be on algorithms and data structures rather than proofs of correctness of algorithms. • Theory of lexical analysis, parsing, type checking, runtime system, code generation, optimization (without going too deep into the proofs etc.) • Techniques for developing lexical analyzers, parsers, type checkers, run time systems, code generator, optimization. Use of tools and specifications for developing various parts of compilers
What do we expect to achieve by the end of the course? • Students are confident that they can use language processing technology for various software developments • Students are confident that they can design, develop, understand, modify/enhance, and maintain compilers for (even complex!) programming languages
Organization of the course • Approximately 40 lectures of one hour each • One large programming project to be done in group of four students. The project will have 4-5 parts and will be evaluated every 2-3 weeks during the semester. It is important to start early. (25% credit) • Copying old code is cheating. Do not Cheat. • Late submissions will be increasingly penalized. • Submissions must happen by noon on the due day • Some small programming assignments and home work (10% credit) • Do not copy. However, you are free to discuss • Late submissions will be increasingly penalized. • Submissions must happen by noon on the due day • Two mid semester examinations (15% + 15% credit) • One end semester examination (30% credit) • Participation in the discussions in the class + class notes (5% credit)
Class Notes • Groups of three students to be formed by the instructor in round robin fashion • Each group will be responsible for preparing notes (both writing and editing) for two consecutive lectures • Notes should be related to slides or a group of slides • Notes should be added to the power point slides of the lectures • Slides and notes will be made available to the students • Deadline for notes: Seven days from the second lecture
Required Background and self reading • This is a 5 unit course and, therefore, will have about 25% more load than other professional courses. You should be prepared for more work and long hours of programming • Courses in data structures, computer organization, operating systems • Proficiency in C/C++/Java programming languages • Knowledge of at least one assembly language, assembler, linker & loader, symbolic debugger • You are expected to read the complete book (except the chapter on code optimization) on Compiler Design by Aho, Sethi and Ullman. All the material will not be covered in the lectures
Things to do immediately • Form groups of 4 students • Inform the instructor • Send an email with subject line “CS335 group” • Give roll number, name and email ids of all the group members in the message • Deadline Dec 31, 2004 • Give feed back through out the semester; either personally or through email or anonymous. PLEASE HELP ME IMPROVING THE SLIDES (both presentation style and the material), AND THE NOTES!! • First assignment: Write a simulator for the stack machine described in the text book by Aho, Sethi and Ullman in section 2.8. Submission date: Jan 10, 2005
Bit of History • How are programming languages implemented? Two major strategies: • Interpreters (old and much less studied) • Compilers (very well understood with mathematical foundations) • Some environments provide both interpreter and compiler. Lisp, scheme etc. provide • Interpreter for development • Compiler for deployment • Java • Java compiler: Java to interpretable bytecode • Java JIT: bytecode to executable image
Some early machines and implementations • IBM developed 704 in 1954. All programming was done in assembly language. Cost of software development far exceeded cost of hardware. Low productivity. • Speedcoding interpreter: programs ran about 10 times slower than hand written assembly code • John Backus (in 1954): Proposed a program that translated high level expressions into native machine code. Skeptism all around. Most people thought it was impossible • Fortran I project (1954-1957): The first compiler was released
Fortran I • The first compiler had a huge impact on the programming languages and computer science. The whole new field of compiler design was started • More than half the programmers were using Fortran by 1958 • The development time was cut down to half • Led to enormous amount of theoretical work (lexical analysis, parsing, optimization, structured programming, code generation, error recovery etc.) • Modern compilers preserve the basic structure of the Fortran I compiler !!!
References • Compilers: Principles, Tools and Techniques by Aho, Sethi and Ullman soon to be replaced by “21st Century Compilers” by Aho, Sethi, Ullman, and Lam • Crafting a Compiler in C by Fischer and LeBlanc soon to be replaced by “Crafting a Compiler” by Fischer • Compiler Design in C by Holub • Programming Language Pragmatics by Scott • Engineering a Compiler by Cooper and Torczon • Modern Compiler Implementation (in C and in Java) by Appel • Writing Compilers and Interpreters by Mak
Compiler Design by Wilhelm and Maurer • A Retargetable Compiler: Design and Implementation by Fraser and Hanson • Compiler Construction by Wirth • The Theory of Parsing, Translation and Compiling (vol 1 & 2) by Aho and Ullman (old classic) • Introduction to Compiler Construction with Unix by Schreiner and Friedman • Compiler Design and Construction: Tools and Techniques by Pyster • Engineering a Compiler by Anklam and Cutler • Object Oriented Compiler Construction by Holmes • The Compiler Design Handbook edited by Srikant and Shankar
Compiler Design. Preliminaries Required. Basic knowledge of programming languages. Basic knowledge of FSA and CFG. Knowledge of a high programming language for the programming assignments. Textbook: Alfred V. Aho, Ravi Sethi, and Jeffrey D. Ullman,
727 views • 16 slides
Compiler Design. Hongwei Xi Comp. Sci. Dept. Boston University. Welcome!. Compiler Design Introduction to some basics in the compiler design and implementation The theory behind various components of a compiler The programming techniques involved to put the theory into practice
633 views • 15 slides
Compiler Design. Lexical Analysis Syntactical Analysis Semantic Analysis Optimization Code Generation. Compilation Process. Start with source code Perform analysis Generate object code Execute code from start to finish on hardware or software interpreter
809 views • 19 slides
Compiler Design. PROJECT PRESENTATION : COMPILER FOR OBJECTIVE C Harshal Waghmare Jeet Kumar Nandan Kumar Vishal A grawal. Objective C: An Introduction.
327 views • 10 slides
Compiler Design. PROJECT PRESENTATION : COMPILER FOR OBJECTIVE C Harshal Waghmare Jeet Kumar Nandan Kumar Vishal Agrawal. Objective C: An Introduction.
290 views • 10 slides
532 views • 15 slides
Compiler Design. INTRODUCTION TO CODE OPTIMIZATION. Code Optimization. Code produced by compilation algorithms can often be improved (ideally optimized) in terms of run-time speed and the amount of memory they consume
705 views • 20 slides
BANHA UNIVERSITY FACULTY OF COMPUTERS AND INFORMATIC. Fourth Year (First Semester). ___________________________________________ COMPILER DESIGN ___________________________________________. Lecture 1. Dr. Hamdy M. Mousa. 1. INTRODUCTION to COMPILER DESIGN.
1.24k views • 38 slides
Compiler design. Overview. Compiler Front-End What is a compiler? Lexical Analysis Syntax Analysis Parsing. Compiler Back-End Code Generation Register Allocation Optimization. Specific Examples lex yacc lcc. What is a Compiler?. Example of tasks of compiler.
1.06k views • 29 slides
Compiler Design. Introduction. Course Outline. Introduction to Compiling Lexical Analysis Syntax Analysis Context Free Grammars Top-Down Parsing Bottom-Up Parsing Semantic Analysis Intermediate Code Generation. Machine Language. The only language that is “understood” by a computer
538 views • 16 slides
Compiler design. Lecture 2: lexical analysis Lecturer :Batool Almasri. Lexical Analysis. -It’s the first phase of compiler is also known as Scanner -Lexical breaks the input in to smallest meaningful sequences called TOKENS which Parser uses for syntax analyzer .
371 views • 23 slides
Compiler design. Generating an Abstract Syntax Tree using Syntax-Directed Translation. Abstract Syntax Tree: Definition. An abstract syntax tree (AST) is a tree representation of the abstract syntactic structure of source code.
411 views • 35 slides
Compiler design. Bottom-up parsing: Canonical LR and LALR Error recovery in LR parsing Parsing: concluding comments. S if E then S | if E then S else S. State 3 : S id FOLLOW(S) = {$} V[ id ] E id FOLLOW(E) = {$,+,=}. Z S S E = E S id E E + id
317 views • 19 slides
Compiler design. Code generation. x dw 0. Variable declarations and access. Integer variable declaration: where x is the addresses of x, which is a label generated during the parse and stored in the symbol table. To load or change the content of an integer variable:
307 views • 28 slides
Compiler design. Code generation. x dw 0. Variable declarations and access. Integer variable declaration: where x is the address of x, which is a (unique) label generated during the parse and stored in the symbol table. To load or change the content of an integer variable:
420 views • 30 slides
Compiler design. Lexical analysis. Lexical analysis. Lexical analysis is the process of converting a sequence of characters into a sequence of tokens . A program or function which performs lexical analysis is called a lexical analyzer , lexer or scanner .
500 views • 43 slides
Compiler design. Table-driven syntax-directed translation. Top-down table-driven syntax-directed translation. Top-down table-driven syntax-directed translation. Augment the parser algorithm to implement attribute migration.
311 views • 23 slides
IMAGES
COMMENTS
This compiler design tutorial includes all the basic to advanced topics like lexical analysis, code generation, syntax analysis, semantic analysis, and optimization techniques. Each section is crafted to provide clarity and depth, ensuring you grasp the complexities of transforming source code into executable programs.
Compiler Design and Programming Language Design (1) • An interesting aspect is how programming language design and compiler design influence one another. • Programming languages that are easy to compile have many advantages. Compiler Design and Programming Language Design (2) • Languages such as Snobol and APL are usually considered ...
The number of architecture register available to the compiler can vary from processor to processors. The rst phase of code generation usually assumes an unlimited numbers of registers (virtual registers).
3 Objectives * To introduce principles, techniques, and tools for compiler construction * To obtaining the knowledge what a compiler does and how to build one. 4 Course Outline 1.
Description: compiler design. Computer Science. Rensselaer Polytechnic. Lecture 1. 66.648 Lecture ... Compiler is a program (written in a high-level language) that converts ... - PowerPoint PPT presentation. Number of Views: 1434. Avg rating:3.0/5.0.
A Good Compiler Infrastructure Needed - A modern View Front end Interprocedural Analysis and Optimization Good IR Loop Nest Optimization and Parallelization Global (Scalar) Optimization Middle-End Backend Code Generation \course\cpeg421-08s\Topic-1a.ppt
Compiler Design This course is an introduction to the full pipeline of modern compilers it covers all aspects of the compiler pipeline for modern languages (C, Java, Python, etc.); touches on advanced topics related to optimization will present how realworld compilers are built
Compiler Design. Hongwei Xi Comp. Sci. Dept. Boston University. Welcome!. Compiler Design Introduction to some basics in the compiler design and implementation The theory behind various components of a compiler The programming techniques involved to put the theory into practice Download Presentation final letter grade calculation instruction selection office hours precolored nodes solely own ...
Download our Compiler Design PPT template to discuss the features and applications of compilers. The deck is feature-rich. - https://www.sketchbubble.com/en/...
Download Compiler Design Notes, PDF [2021] syllabus, books for B Tech, M Tech, BCA. Get complete Lecture Notes, course, interview questions paper, ppt, tutorials.
Download our Compiler Design PPT template to describe the structure and principles that guide a compiler's translation and optimization process. Programmers can use this entirely customizable deck to explain how compilers help implement high-level programming languages and make the end code efficient. You can also use this set to discuss the features and applications of compiler technology.
Compilers take away that flexibility in exchange for fast execution. A compiler is a program that translates a high-level language program into a functionally equivalent sequence of machine instructions, i.e., an assembly language program.
Compiler design. Text Book: Compilers: principles, theory, and techniques by Aho, Sethi, and Ullman. Topics: Compiler phases Lexical analysis Syntax analysis Code generation Home work: there will be two major programming assignments. They must be done independently.
Download the premade presentation template for MS PowerPoint and Google Slides and showcase the phases, architecture, and parsing techniques of the Compiler Design.
This year's theme focuses on the cutting-edge advancements in compiler design, implementation, and optimization, and their impact on emerging software and hardware platforms. We invite presentation proposals for our upcoming workshop. List of Topics. We invite speakers from academia and industry to present their work in one of the following tracks.
Compiler Design - 10CS43. REFERENCE TEXTS. Programming Languages - Concepts and Constructs . By Ravi Sethi, 2nd Edition. Pearson Education Asia. Modern Compiler Implementation in C. By Andrew Appel. Cambridge University Press. Compilers - Principles, Techniques and Tools
Class Abstract Compiler research for a long time was moribund, stuck on narrow topics such as register allocation and instruction scheduling. In contrast, the last decade has seen an explosion of interesting work using compilers to accomplish something cool. This class will cover a selection of such research papers, ranging across static and dynamic bug finding, binary analysis, reverse ...
Principles of Compiler Design. Sanjeev K Aggarwal Department of Computer Science and Engineering, IIT Kanpur [email protected]. Motivation for doing this course. Language processing is an important component of programming Download Presentation text book k aggarwal department application programs fortran high level expressions complete book veta ...