COSC 327 Compiler Construction Exam
COSC 327 Compiler Construction Exam
The optimization rule of replacing '0 * e' with '0' simplifies computations by eliminating unnecessary operations, potentially improving execution time. However, it may be problematic in cases where 'e' has side effects or is a function call, as eliminating 'e' also removes any associated side effects or evaluations, which could alter the program's behavior. Hence, this optimization requires careful consideration of the context in which expressions are evaluated .
A compiler translates an entire program into machine code before the program is executed, which means it processes the source code all at once, generating an executable that can be run independently. In contrast, an interpreter translates and executes the program one line at a time, meaning it processes the source code line-by-line or statement-by-statement without producing an intermediate machine code file .
Creating intermediate code serves multiple purposes: it improves portability by allowing the intermediate code to run on different machine architectures; it simplifies optimization by providing a platform-independent representation; and it eases the translation of high-level source code by decoupling the process into manageable stages. Moreover, it reduces complexity by separating concerns between front-end and back-end compilation processes .
Syntax analysis, or parsing, involves checking the source code against grammatical structure defined by the language's syntax rules. It ensures that constructs are syntactically correct, generating a parse tree or abstract syntax tree. Semantic analysis uses the parse tree output to check for semantic correctness, such as type-checking, and ensures that operations conform to the language's semantics. While syntax analysis is concerned with form, semantic analysis is concerned with meaning, and together they validate the input program before code generation .
A grammar is ambiguous when there exists at least one string that can be generated by the grammar in more than one parse tree or derivation sequence. For example, consider a grammar with the production rules: E -> E + E | E * E | id. The expression 'id + id * id' can result in two different parse trees, representing (id + id) * id and id + (id * id), making the grammar ambiguous because the parse trees can represent different computations .
Stacks are used to store procedure calls primarily because they naturally support the last-in, first-out (LIFO) order of function invocations in programming languages. They facilitate the management of function calls and returns, allowing the compiler to maintain the state and local variables of each function invocation effectively and efficiently. This also allows for straightforward implementation of recursive function calls and backtracking .
The three fundamental rules of code optimization are: (1) Eliminate common subexpressions to avoid redundant calculations. (2) Perform loop transformations to improve the performance of iterative structures. (3) Apply inlining and other transformations to reduce function call overhead. These rules are essential as they enhance the efficiency and execution speed of the compiled code, contributing to overall performance improvements without altering functionality .
Garbage is defined as data in memory that is no longer accessible in any part of the program. It is typically identified using garbage collection algorithms that track references to objects. When an object has no remaining references, it is considered unreachable and thus identifies as garbage. Algorithms like mark-and-sweep and reference counting are used to locate such objects and clean them up to free memory .
Formal parameters are the variables defined in the function declaration or definition that specify the inputs required by the function. They act as placeholders for the input values, which are actual parameters passed during the function call. For instance, in a C function defined as `int add(int x, int y)`, `x` and `y` are formal parameters. In a call like `add(5, 10)`, the numbers `5` and `10` are the actual parameters given to the function .
Symbol tables function as a data structure that a compiler uses to store and manage information about the various identifiers (such as variable and function names) encountered in the source program. The two major operations they support are 'insert', to add new identifiers and associated information, and 'lookup', to retrieve stored information for existing identifiers. These operations are crucial for semantic analysis, allowing for type checking and scope management .