Consider a basic block made up of the instructions
t = b * c u = t - a d = d + u b = c c = c + 1 if c > n goto L4
where t and u are temporaries, local to the block, and b, c, and d are live at exit from the block. Generate
code, for the simple processor architecture posited in the textbook, for
this block and prepare a diagram similar to Figure 8.16 showing the
contents of the register and address descriptors each each step.
Exercise 8.4.2 from the textbook (page 532). (Use param and call instructions for the invocation of the sqrt
function, and treat call as a branch instruction.)
Suppose that, on an AVR microcontroller, the value of x is stored at memory locations 256 and 257 (hex $0100 and $0101), with the low byte at the lesser address; y at memory locations 258 and 259 (hex $0102 and $0103), a at memory location 264 and 265 (hex $0108 and $0109), b at memory locations 266 and 267 (hex $010A and $010B), and c at memory locations 268 and 269 (hex $010C and $010D). Generate code for the following sequence of three-address instructions, assuming that none of the registers currently contains any of these values or any other value that must be preserved.
x = c - a * b y = x * 16 + 1
Choose a programming language with which you are familiar (excluding Scheme, C, and Java) and describe its facilities for invoking functions, providing functions as arguments to other functions, and constructing function values dynamically. Would access links be useful components of activation records in the language you chose? Justify your answer.
In some programming languages, it is possible to use the same storage locations within an activation record for the values of the function's actual parameters as it is invoked and for return values when it finishes execution. Assess the advantages and disadvantages of this strategy.
I mentioned in class that the oldest high-level programming language that is still in general use, FORTRAN, originally had a completely static storage model, supporting neither a heap nor a run-time stack; instead, the compiler assigned, at compile time, a fixed storage location to every identifier, whether it was declared locally within a procedure or globally. What common design patterns does this storage model obstruct? How might a programmer who is obliged to work in a language that has this storage model get around such obstructions?
In many languages, the expression at the top of a switch-statement
can be of an enumerated type. Which of the strategies described in section
6.8.1 of the text would you want the compiler to use in such a case?
Justify your answer.
float is eight bytes, the size of an int is four bytes, and the size of a pointer is four bytes, what is the
size of a record of the following type? Assume that no padding for
alignment is needed.
record {
float[3] coordinates;
int serialNumber;
float remoteness;
int[256][30] grayLevel;
}
images is an array of 24 such records, indexed from 0 to 23
(inclusive), how far from the base address of images would one find
images[11].grayLevel[13][17]?Complete the lab on bison and submit the final versions of lc.l and lc.y and the files containing your test cases.
On page 283, the textbook mentions that "if we are unable to use an ambiguous grammar to specify conditional statements, then we would have to use a bulkier grammar" to resolve the dangling-else problem. The "bulkier grammar," in augmented form, would be
S' -> S S -> M | P M -> i M e M | a P -> i S | i M P
Draw up the SLR parsing table for this grammar and compare its size and complexity to the one shown in Figure 4.51.
for-statements, the loop control mechanism is
sometimes the initializer/entry-test/updater structure borrowed from C,
sometimes a selection-from-iterator structure. Why does the coexistence of
these two variants pose a small problem for top-down parsers?
Exercise 4.2.2d) (page 207) proposes a context-free grammar for regular
expressions on the alphabet {a}. Confirm that this grammar is
ambiguous by finding a single string that has two or more leftmost
derivations in that grammar. Devise an unambiguous grammar for the same
language.
A flex program can contain translation rules for different
patterns that match different strings that start out the same way. For
instance, the patterns ab*cd and a*bce match the strings
abcd and abce respectively, but flex won't know
which pattern should be applied until it sees the fourth character of
either string. How does flex avoid having to backtrack and
start over again at the beginning of the token in such cases?
Complete the lab on flex and submit the final versions of upper-to-mixed.l and conditionals.l.
(a*b|c)* on the alphabet {a, b, c}.Write a regular expression for names in ABC (see exercise 4).
A positive integer n is a lesser twin prime if both n and n + 2 are prime. Write a Dijkstra program that finds and outputs the first hundred lesser twin primes, beginning with 3.
Write a Dijkstra program that finds and prints the smallest odd natural number that is less than the sum of its exact proper divisors. (So, for instance, the sum of the exact proper divisors of 45 is 1 + 3 + 5 + 9 + 15, or 33; so it does not qualify. 1 has no exact proper divisors, so it doesn't qualify either.)
Do the git lab. When you are finished, submit a copy of the log for each remaining branch of each repository you created.
Write a schema showing how a C-style for-statement, with the syntax
for ( expr_1 ; expr_2 ; expr_3 ) stmt
would be rendered in the three-address code presented in section 2.8 of the
textbook. In other words, show what the three-address code would be, but
elide the part that executes the body of the loop, and replace the parts
that would compute the values of expr_1, expr_2, and expr_3 with indications of the temporary variables in which those values
are placed.
#, and ends with the next following newline. Adapt
the lexical analyzer in /home/stone/courses/compilers/code/arithmetic-expression-scanner so that
it discards such comments without generating any tokens.// as the beginning-of-comment marker.
Explain why that exercise would be substantially more difficult.Do the make lab and submit the Makefile that you construct for the last exercise in the lab.
In section 2.5 of the textbook, the authors implement, in Java, an infix-to-postfix translator for simple arithmetic expressions. Implement a version of the same translator in C.
^, to the
grammar of arithmetic expressions in example 2.6 (page 49). It should have
higher precedence (i.e., bind its operands more tightly) than * and
/.