Compiler Construction Flashcards

1
Q

Left recursion

A

Top-down parsers cannot handle left-recursion in a grammar

-> transform the grammar to fix this cf sl. 40/41

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Context-free grammars

A

s
syntax is context-free
semantics is context-sensitive

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

intermediate representation

A

aka parse tree
-> a notation that is not tied to any particular source language or target machine

Choosing the “right” IR is not an easy task: source code is too
high level for performing many analyses, and machine code is
too low level. Sometimes an AST is used (i.e., closer to source
code), and sometimes a special kind of abstract instruction set
(i.e., closer to machine code).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

derivation

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

left-recursion

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Bytecode

A

The “machine-code” of the virtual machine

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

What is the difference between a compiler and an

interpreter?

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

What are important qualities of compilers?

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Why are compilers commonly split into multiple passes?

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

What are the typical responsibilities of the different parts of a modern compiler?

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

How are context-free grammars specified?

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

What is “abstract” about an abstract syntax tree?

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

What is intermediate representation and what is it for?

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Why is optimization a separate activity?

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Is Java compiled or interpreted? What about Smalltalk?

Ruby? PHP? Are you sure?

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

What are the key differences between modern compilers and compilers written in the 1970s?

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

Why is it hard for compilers to generate good error

messages?

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

What is “context-free” about a context-free grammar?

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q

Traditional two pass compiler

A

A classical compiler consists of a front end that parses the source
code into an intermediate representation, and a back end that
generates executable code.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

front end

A

parses the source code into an intermediate representation

  • the front end should deal with all things to do with the language and source code
  • consists of scanner (tokens) and parser (IR)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q

back end

A

generates executable code
- the back end should deal with all things to do with the
target architecture
- translate IR into target machine code

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q

scanner

A

is responsible for converting the source code into a stream of tokens of the source language

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q

parser

A
is responsible for recognizing structure in the stream of tokens
- job of the parser is to recognize structure in the stream of tokens produced by the scanner
- Typically it builds a parse tree representing this structure, but it may also produce another kind
of IR (intermediate representation) more suitable for the backend
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q

IR

A

e.g. parse tree

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
Q

context-free?

A

“context-free” because rules for nonterminals
can be written without regard for the context in which
they appear

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
26
Q

context-sensitive

A

context sensitive: you need the context of a code to validate it
context free: you do not need the context of a code to validate it

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
27
Q

unambiguous grammar

A

it always produces a unique parse for a given valid input.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
28
Q

the parse and the parse tree

A

The parse is the sequence of productions needed to parse the input.
The parse tree is a structure representing this derivation

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
29
Q

LL(1), LR(1)

A

“sweet spots”: allow interesting languages to be specified, but can also be parsed efficiently

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
30
Q

syntax analysis

A

An AST is usually the result of the syntax analysis phase of a compiler

lexical analysis -> syntax analysis

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
31
Q

Leftmost vs rightmost derivation

A

replace the leftmost non-terminal at each step
vs
replace the rightmost non-terminal at each step

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
32
Q

table-driven parser

A
  • Our recursive descent parser encodes state information in its call stack.
  • Using recursive procedure calls to implement a stack
    abstraction may not be particularly efficient
  • This suggests other implementation methods:
    —explicit stack, hand-coded parser
    —stack-based, table-driven parser
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
33
Q

constant expression propagation and folding

A

evaluate and propagate constant expressions at compile time

Constant propagation entails recognizing that certain “variables” actually have constant values, and then propagating these constants to expressions where they are used. Later we will see SSA is ideal to analyze this.

constant folding:
> Evaluate constant expressions at compile time
> Only possible when side-effect freeness guaranteed

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
34
Q

ambiguous grammar

A

If a grammar has more than one derivation for a single

sentential form

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
35
Q

Top-down parser (LL)

A
  • starts at the root of derivation tree and fills in
  • picks a production and tries to match the input
  • may require backtracking
  • some grammars are backtrack-free (predictive)
  • uses leftmost derivation
  • can be either hand-written or generated
  • cannot handle left-recursion in a grammar

-> Since a parser does not just parse, but must also produce a suitable IR, we must decorate the grammar with additional actions that the generated parser will take

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
36
Q

Bottom-up parser (LR)

A
  • starts at the leaves and fills in
  • starts in a state valid for legal first tokens
  • as input is consumed, changes state to encode possibilities (recognize valid prefixes)
  • uses a stack to store both state and sentential forms
  • uses rightmost derivation
  • are normally built by parser generators

Reading in reverse, we have a rightmost derivation, first replacing
S, then B, A and A again. 9

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
37
Q

parser generators

A
  • build bottom-up parsers
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
38
Q

dead code elimination

A

eliminate code that can never be

executed

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
39
Q

left-recursion

A
If the parser makes the wrong choices, expansion doesn’t terminate!
-> solve using right recursion:
E -> E + T
E -> T
rewrite as:
E -> T E'
E' -> + T E'
E' ->
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
40
Q

look-ahead

A

top-down parsers may need to backtrack when they select the wrong production
- large subclasses of CFGs can be parsed with limited lookahead
- Among the interesting subclasses are:
LL(1): Left to right scan, Left-most derivation, 1-token look-ahead
LR(1): Left to right scan, Right-most derivation, 1-token look-ahead

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
41
Q

recursive descent / predictive parsing

A

basic idea: For any two productions A → α | β, we would like a distinct way of choosing the
correct production to expand.
Whenever two productions A → α and A → β both appear in the grammar, we would like:
FIRST(α) ∩ FIRST(β) = ∅
This would allow the parser to make a correct choice with a look-ahead of only one symbol!
=> this type of parsing works only on grammars where the first terminal symbol of each subexpression provides enough information to choose which production to use (iff FIRST property can be established!).
What if a grammar does not have this property?
-> left factoring

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
42
Q

left factoring

A

sometimes we can transform a grammar in order to have this property (FIRST(α) ∩ FIRST(β) = ∅):
- For each non-terminal A find the longest prefix α common to two or more of its alternatives
- if α ≠ ε then replace all of the A productions
A → αβ1 | αβ2 | … | αβn
with
A → α A´
A´ → β1 | β2 | … | βn
where A´ is fresh
- Repeat until no two alternatives for a single non-terminal have a common prefix.

-> we do this so that the token lookahead will be unambiguous! i.e. that selection requires only a single token look-ahead

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
43
Q

lexical analyzer

A

The lexical analyzer breaks these syntaxes into a series of tokens, by removing any whitespace or comments in the source code. If the lexical analyzer finds a token invalid, it generates an error. The lexical analyzer works closely with the syntax analyzer. It reads character streams from the source code, checks for legal tokens, and passes the data to the syntax analyzer when it demands.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
44
Q

FIRST(a)

A

FIRST(a) is the set of all terminal symbols that can begin any string derived from a
-> if two different productions have the same left-hand-side symbol X and their right-hand sides have overlapping FIRST sets, then the grammar cannot be parsed using predictive parsing.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
45
Q

construct a predictive / recursive-descent parser

A

p. 50/51
- create predictive parsing table with one production per entry (if > 1 production, predictive parsing will not work -> is ambiguous)
- > an ambiguous grammar will always lead to duplicate entries in a predictive parsing table
- > need to find an unambiguous grammar
- > grammars whose predictive parsing tables contain no duplicate entries are called LL(1) = left-to-right prase, leftmost-derivation, 1-symbol lookahead
- > a recursive-descent parser does its job just by looking at the next token of the input, never looking more than one token ahead

… FIRST property

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
46
Q

LL(k)

A

generalize the notion of FIRST sets to describe the first k tokens of a string, and make an LL(k) parsing table whose rows are the nonterminals and columns are every sequence of k terminals (rarely done -> tables get large!)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
47
Q

NFA -> DFA

A

Any NFA can be converted into a DFA, by simulating sets of simultaneous states.
Since a DFA must always be in a unique state, the states of the DFA must be all possible subsets of the NFA states.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
48
Q

NFA to DFA using the subset construction

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
49
Q

Non-recursive predictive parsing

A
  • use parse table

-

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
50
Q

DFA Minimization algorithm

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
51
Q

LL(1) parse table

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
52
Q

Properties of LL(1) grammars

A
  • No left-recursive grammar is LL(1)
  • No ambiguous grammar is LL(1)
  • Some languages have no LL(1) grammar
  • An ε–free grammar where each alternative expansion for A begins with a distinct terminal is a simple LL(1) grammar
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
53
Q

What are the key responsibilities of a scanner?

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
54
Q

Bottom-up parsing

A

Goal:

  • Given an input string w and a grammar G, construct a parse tree by starting at the leaves and working to the root.
  • We parse bottom-up, replacing terms by non-terminals!

the question is always whether to shift or reduce!

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
55
Q

What is a regular language?

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
56
Q

handle

A

A handle of a right-sentential form γ is a production A → β and a position in γ where β may be found and replaced by A to produce the previous right-sentential form in a rightmost derivation of γ

—Suppose: S ⇒* αAw ⇒ αβw
—Then A → β in the position following α is a handle of αβw

-> NB: Because γ is a right-sentential form, the substring to the right of a handle contains only terminal symbols.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
57
Q

How can you generate a DFA recognizer from a regular

expression?

A

by a scanner generator

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
58
Q

Why aren’t regular languages expressive enough for

parsing?

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
59
Q

handle-pruning, bottom-up parser

shift-reduce parser

A

Shift-reduce parsers use a stack and an input buffer

  1. initialize stack with $
  2. Repeat until the top of the stack is the goal symbol and the input token is $:
    a) Find the handle.
    If we don’t have a handle on top of the stack, shift (push) an input symbol onto the stack
    b) Prune the handle.
    If we have a handle A → β on the stack, reduce
    I. Pop |β| symbols off the stack
    II. Push A onto the stack

A shift-reduce parser has just four canonical actions:
shift, reduce, accept, error

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
60
Q

left-to-right-scan?

right-to-left-scan?

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
61
Q

Scanning vs. parsing

A

CFGs are used to impose structure!!!

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
62
Q

lexical analysis

A
  1. Maps sequences of characters to tokens
  2. Eliminates white space (tabs, blanks, comments etc.)
    - > happens within the scanner
    - > The string value of a token is a lexeme
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
63
Q

CFG / parsing

A

CFGs are used to impose structure!!!
- For practical purposes it is important that a grammar
be unambiguous, i.e., that it always produces a unique parse for a given valid input
- Although parsers read their input Left to Right (the first “L” in most of these categories), they may work either top-down — producing a leftmost derivation — or bottom-up — producing a rightmost derivation.

  • The process of discovering a derivation is called parsing.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
64
Q

left recursion vs right recursion

A

pro-contra?

Rule of thumb:
—right recursion for top-down parsers
—left recursion for bottom-up parsers

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
65
Q

Leftmost derivation

A

replace the leftmost non-terminal at each step

- corresponds to top-down parsing, and is especially well-suited to recursive descent parsers

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
66
Q

Rightmost derivation

A

replace the rightmost non-terminal at each
step
- is produced bottom-up, and is better-suited to table-driven parsing

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
67
Q

review: LR(k):

A

must be able to recognize the occurrence of the right hand side of a production after having seen all that is derived from that right hand side with k symbols of look-ahead.

LR dilemma: pick A → b or B → b ? (how to reduce?)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
68
Q

Resolving ambiguity

A

eliminate by rearranging the grammar

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
69
Q

Visitor Pattern

A

Intent: Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

  • > A visitor gathers related operations
  • > Visitor makes adding new operations easy (write new visitor)
  • > Visitor can break encapsulation
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
70
Q

Java Tree Builder (JTB)

A
  • front-end for javacc
  • supports the building of syntax trees that can be traversed using visitors.
  • transforms a bare JavaCC grammar into three
    components:
    1) a JavaCC grammar with embedded Java code for building a syntax tree
    2) one class for every form of syntax tree node
    3) a default visitor which can do a depth-first traversal of a syntax tree
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
71
Q

Why use intermediate representations?

A

—break compiler into manageable pieces
—isolates back end from front end
—different languages can share IR and back end
- Enables machine-independent optimization -> general techniques, multiple passes

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
72
Q

IR types

A
  • Abstract syntax trees (AST)
  • Linear operator form of tree (e.g., postfix notation)
  • Directed acyclic graphs (DAG)
  • Control flow graphs (CFG)
  • Program dependence graphs (PDG)
  • Static single assignment form (SSA)
  • 3-address code
  • Hybrid combinations
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
73
Q

lookahead

A

to decide which production rule to apply at any point without backtracking

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
74
Q

Abstract syntax tree

A

An AST is a parse tree with nodes for most non-terminals removed.
-> Since the program is already parsed, non-terminals needed to establish precedence and associativity can be collapsed!

Remember: Concrete syntax trees, or parse trees, show all of the intermediate non-terminals needed to produce an unambiguous grammar. An abstract syntax tree collapses these to offer a much simpler version of the parse tree.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
75
Q

parsing

A

the process of discovering a derivation

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
76
Q

Leftmost vs rightmost derivation

A

replace the leftmost non-terminal at each step
vs
replace the rightmost non-terminal at each step

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
77
Q

3-address code

A

Statements take the form: x = y op z

Advantages:
—compact form
—names for intermediate values

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
78
Q

Static Single Assignment Form (SSA)

A

Goal: simplify procedure-global optimizations

Program is in SSA form if every variable is only assigned once
- is only used for static analysis and optimization. It will
disappear when we generate the final executable code
- SSA is normally used for control-flow graphs (CFG)c

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
79
Q

The Φ-Function

A
  • Φ-functions are always at the beginning of a basic block

- Selects between values depending on control-flow

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
80
Q

Minimal SSA

A

Two steps:
—Place Φ-functions
—Rename Variables

We want minimal amount of needed Φ
—Save memory
—Algorithms will work faster

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
81
Q

Dominance Property of SSA

A

Dominance: node D dominates node N if every path from the
start node to N goes through D

(“strictly dominates”: D ≠ N)
-Definition dominates use

-> Dominance can be used to efficiently build SSA

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
82
Q

Dominance Frontier

A

DF(D) = the set of all nodes N such that D dominates an immediate predecessor of N but does not strictly
dominate N.

application of DF: Φ-Functions are placed in all basic blocks of the
Dominance Frontier

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
83
Q

parser generators

A

s

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
84
Q

top-down parsing

A

A top-down parser starts with the root of the parse tree, labeled with the start or goal symbol of the grammar.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
85
Q

SSA and Register Allocation

A
  • Idea: remove Φ as late as possible
  • Variables in Φ-function never live at the same time!
  • > Can be stored in the same register
  • > Do register allocation on SSA!

So, don’t remove Φ functions before register allocation

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
86
Q

look-ahead

A

top-down parsers may need to backtrack when they select the wrong production
- large subclasses of CFGs can be parsed with limited lookahead
- Among the interesting subclasses are:
LL(1): Left to right scan, Left-most derivation, 1-token look-ahead
LR(1): Left to right scan, Right-most derivation, 1-token look-ahead

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
87
Q

predictive parsing

A

basic idea: For any two productions A → α | β, we would like a distinct way of choosing the
correct production to expand.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
88
Q

Lattices

A

A lattice is a partially ordered set with meet and join.

A partially ordered set is a set S and a binary relation ≤ such that
a ≤ a (reflexivity)
if a ≤ b and b ≤ a, then a = b (antisymmetry)
if a ≤ b and b ≤ c, then a ≤ c (transitivity)

A complete lattice is a lattice where every subset has a supremum and infimum

-> For static analysis, abstract interpretation is mostly performed over finite lattices

89
Q

Dataflow analysis

A

Flow based analysis is a particular instance of abstract interpretation

90
Q

Optimization

A

Performance: faster execution
Size: smaller executable, smaller memory footprint

Tradeoffs:

1) Performance vs. Size
2) Compilation speed and memory

Optimizations both in the optimizer and back-end!
- Back-end optimizations may focus on how the machine code is optimally generated

91
Q

Optimizations in the Backend

A

> Register Allocation
Instruction Selection
Peep-hole Optimization

92
Q

LL(k)

A

generalize the notion of FIRST sets to describe the first k tokens of a string, and make an LL(k) parsing table whose rows are the nonterminals and columns are every sequence of k terminals (rarely done -> tables get large!)

93
Q

sentential form

A

is any string derivable from the start symbol

94
Q

left-recursion elimination (after left factoring)

A

cf. 03 sl 56

95
Q

Examples for Optimizations

A
> Constant Folding / Propagation
> Copy Propagation
> Algebraic Simplifications
> Strength Reduction
> Dead Code Elimination (Structure Simplifications)
> Loop Optimizations
> Partial Redundancy Elimination
> Code Inlining
96
Q

FOLLOW(X)

A

is the set of terminals that can immediately follow X

i. e. t e FOLLOW(X) if there is any derivation containing Xt. This can occur if the derivation contains XYZt where Y and Z both derive epsilon
- > I.e., a non-terminal’s FOLLOW set specifies the tokens that can legally appear after it
- A terminal symbol has no FOLLOW set.

97
Q

LL(1) parse table

A

s

98
Q

Properties of LL(1) grammars

A
  • No left-recursive grammar is LL(1)
  • No ambiguous grammar is LL(1)
  • Some languages have no LL(1) grammar
  • An ε–free grammar where each alternative expansion for A begins with a distinct terminal is a simple LL(1) grammar
99
Q

derivation vs parse

A

s

100
Q

Bottom-up parsing

A

Goal:

  • Given an input string w and a grammar G, construct a parse tree by starting at the leaves and working to the root.
  • We parse bottom-up, replacing terms by non-terminals!
101
Q

right-sentential form

A

s

102
Q

handle

A

A handle of a right-sentential form γ is a production A → β and a position in γ where β may be found and replaced by A to produce the previous right-sentential form in a rightmost derivation of γ

—Suppose: S ⇒* αAw ⇒ αβw
—Then A → β in the position following α is a handle of αβw

-> NB: Because γ is a right-sentential form, the substring to the right of a handle contains only terminal symbols.

103
Q

Common Subexpression Elimination (CSE)

A

Common Subexpression:
—There is another occurrence of the expression whose evaluation always precedes this one
—operands remain unchanged

104
Q

Loop Optimizations

A

Optimizing code in loops is important
—often executed, large payoff!

e.g.
—fission/fusion: split/combine loops to improve locality or reduce overhead
—scheduling: run parts in multiple processors
—unrolling: duplicate body several times in order to decrease the number of times the loop condition is tested
—loop-invariant code motion: move invariant code out of loop

105
Q

handle-pruning, bottom-up parser

shift-reduce parser

A

Shift-reduce parsers use a stack and an input buffer

  1. initialize stack with $
  2. Repeat until the top of the stack is the goal symbol and the input token is $
106
Q

Induction Variable Optimizations

A

Values of variables form an arithmetic progression

sl. 38

107
Q

LR(k)

A

A grammar is LR(k) if k tokens of lookahead are enough to determine a unique parse:

108
Q

Why study LR grammars?

A
  • LR(1) grammars are used to construct LR(1) parsers
  • everyone’s favorite parser
  • virtually all context-free programming language constructs can be expressed in an LR(1) form
  • LR grammars are the most general grammars parsable by a deterministic, bottom-up parser
  • efficient parsers can be implemented for LR(1) grammars
  • LR parsers detect an error as soon as possible in a left-to-right scan of the input
  • LR grammars describe a proper superset of the languages recognized by predictive (i.e., LL) parsers
109
Q

Optimization on SSA

A

e.g. three simple ones:
—Constant Propagation
-> SSA: Variables are assigned once
-> We know that we can replace all uses by the constant!

—Copy Propagation
-> SSA: for a statement x1 := y1
-> replace later uses of x1 with y1
-> as a “clean up” optimization after
other optimizations have been performed

—Simple Dead Code Elimination

  • > SSA: Variable is live if the list of uses is not empty
  • > Dead definitions can be deleted
110
Q

Profile-guided optimization

A

Approach:
—Generate code,
—profile it in a typical scenario,
—then use that information to optimize it

Problem:
—usage scenarios can change in deployment, there is no way to react to that as profile is generated at compile time.

111
Q

review: Recursive descent

A

A hand coded recursive descent parser directly encodes a grammar (typically an LL(1) grammar) into a series of mutually recursive procedures. It has most of the linguistic limitations of LL(1).

112
Q

review: LL(k):

A

must be able to recognize the use of a production after seeing only the first k symbols of its right hand side.

LL dilemma: pick A → b or A → c ? (which rule to apply?)

113
Q

Optimization: Iterative Process

A
  • There is no general “right” order of optimizations
  • One optimization generates new opportunities for a preceding one.
    => Optimization is an iterative process

Compile Time vs. Code Quality

114
Q

JavaCC

A
  • based on LL(k)
  • Grammars are written in EBNF
  • Transforms an EBNF grammar into an LL(k) parser
  • ## Top-down parsing (recursive descent) with variable lookahead
115
Q

Visitor Pattern

A

Intent: Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

116
Q

Runtime storage organization

A

study slides again + chap. 6

117
Q

Procedure call conventions

A

s

118
Q

Calls: Saving and restoring registers

A

CC-08 sl 24

usual approach:
caller’s registers: callee saves
Call includes bitmap of caller’s registers to be saved/restored. Best: saves fewer registers, compact call sequences

119
Q

parse tree

A

the syntactic structure of the program

120
Q

Abstract syntax tree

A

An AST is a parse tree with nodes for most non-terminals removed.
-> Since the program is already parsed, non-terminals needed to establish precedence and associativity can be collapsed!

121
Q

Directed acyclic graph

A

A DAG is an AST with
unique, shared nodes
for each value.

122
Q

Control flow graph

A

A CFG models transfer of control in a program

123
Q

3-address code

A

Statements take the form: x = y op z

Advantages:
—compact form
—names for intermediate values

124
Q

Static Single Assignment Form (SSA)

A

Goal: simplify procedure-global optimizations

Program is in SSA form if every variable is only assigned once
- is only used for static analysis and optimization. It will
disappear when we generate the final executable code

125
Q

The Φ-Function

A
  • Φ-functions are always at the beginning of a basic block

- Selects between values depending on control-flow

126
Q

Optimum tiling

A

s

127
Q

Dominance Property of SSA

A

Dominance: node D dominates node N if every path from the
start node to N goes through D

  • Definition dominates use
  • > Dominance can be used to efficiently build SSA
128
Q

Main Components of a VM

A

s

Virtual machine provides a virtual processor

The VM provides a virtual processor
that interprets bytecode instructions

129
Q

Applications of SSA

A

Simplifies many optimizations:

  • Every variable has only one definition
  • Every use knows its definition, every definition knows its uses
  • Unrelated variables get different names
Examples:
—Constant propagation
—Value numbering
—Invariant code motion and removal
—Strength reduction
—Partial redundancy elimination
130
Q

Pharo Bytecode

A
256 Bytecodes, four groups:
Stack Bytecodes
Send Bytecodes
Return Bytecodes
Jump Bytecodes
131
Q

SSA and Register Allocation

A
  • Idea: remove Φ as late as possible
  • Variables in Φ-function never live at the same time!
  • > Can be stored in the same register
  • > Do register allocation on SSA!
132
Q

Program Analysis

A

Types:

  • static vs dynamically checked
  • soundness
  • type checking
  • > Typing rules are usually written as natural deductions
  • Abstract Interpretation:
  • > One of the most generic and fundamental ways of approximating the behavior of a program
133
Q

Method Contexts

A

sl 38 cc-09

A method context is an object that represents an activation record (stack frame) for a method invocation. Each method context points to the context of its caller, thus constituting a stack of contexts.

134
Q

Lattices

A

A lattice is a partially ordered set with meet and join.

A partially ordered set is a set S and a binary relation ≤ such that
a ≤ a (reflexivity)
if a ≤ b and b ≤ a, then a = b (antisymmetry)
if a ≤ b and b ≤ c, then a ≤ c (transitivity)

A complete lattice is a lattice where every subset has a supremum and infimum

-> For static analysis, abstract interpretation is mostly performed over finite lattices

135
Q

Dataflow analysis

A

Flow based analysis is a particular instance of abstract interpretation

136
Q

Optimization

A

Performance: faster execution
Size: smaller executable, smaller memory footprint

Tradeoffs:

1) Performance vs. Size
2) Compilation speed and memory

Optimizations both in the optimizer and back-end!
- Back-end optimizations may focus on how the machine code is optimally generated

137
Q

Optimizations in the Backend

A

> Register Allocation
Instruction Selection
Peep-hole Optimization

138
Q

GC Remembered Set

A

Write barrier: remember objects with old-young pointers in “Remembered Set”:

When marking young generation, use objects in remembered set as additional roots

139
Q

Instruction Selection

A

For every expression, there are many ways to realize
them for a processor
Example: Multiplication*2 can be done by bit-shift

Instruction selection is a form of optimization

-> Group IR-tree nodes into clumps that correspond to actions of targetmachine instructions

140
Q

Pharo GC

A

mark and sweep compacting collector with two
generations

> Cooperative, i.e., not concurrent
Single threaded

141
Q

Examples for Optimizations

A
> Constant Folding / Propagation
> Copy Propagation
> Algebraic Simplifications
> Strength Reduction
> Dead Code Elimination (Structure Simplifications)
> Loop Optimizations
> Partial Redundancy Elimination
> Code Inlining
142
Q

Threading System

A

Multithreading is the ability to create concurrently
running “processes”

Non-native threads (green threads):
– Only one native thread used by the VM
– Simpler to implement and easier to port

Native threads
– Using the native thread system provided by the OS
– Potentially higher performance

143
Q

Constant Propagation

A

y

144
Q

Optimization: JIT

A

Idea: Just In Time Compilation
> Translate unit (method, loop, …) into native machine code at runtime
> Store native code in a buffer on the heap

Challenges
> Run-time overhead of compilation
> Machine code takes a lot of space (4-8x compared to bytecode)
> Deoptimization (for debugging) is very tricky

Adaptive compilation: gather statistics to compile only units that are heavily used (hot spots)

145
Q

Algebraic Simplifications

A

s

146
Q

Strength Reduction

A

s
Replace expensive operations with simpler ones
-> Peephole optimizations are often strength reductions

147
Q

Dead Code

A

a

148
Q

Simplify Structure

A

Similar to dead code: Simplify CFG Structure

e. g.
- Delete Empty Basic Blocks
- Fuse Basic Blocks (e.g. “conditional” jumps between basic blocks where conditions are always true)

-> Optimizations will degenerate CFG:
— Needs to be cleaned to simplify further optimization!

149
Q

Common Subexpression Elimination (CSE)

A

s

150
Q

Loop Optimizations

A

Optimizing code in loops is important
—often executed, large payoff!

e.g.
—fission/fusion: split/combine loops to improve locality or reduce overhead
—scheduling: run parts in multiple processors
—unrolling: duplicate body several times in order to decrease the number of times the loop condition is tested
—loop-invariant code motion: move invariant code out of loop

151
Q

What can’t PEGs express directly?

A

> Ambiguous languages
—That’s what CFGs are for!

152
Q

Induction Variable Optimizations

A

Values of variables form an arithmetic progression

sl. 38

153
Q

Scannerless parsers

A

> Traditional linear-time parsers have fixed lookahead
—With unlimited lookahead, don’t need separate lexical analysis!

  • especially useful when mixing languages
    with different terminals
154
Q

Memoized parsing: Packrat Parsers

A

By memoizing parsing results, we avoid having to recalculate partially successful parses.

=> A “packrat parser” is a PEG that memoizes (i.e., caches) intermediate parsing results so they do not have to be recomputed while backtracking.

155
Q

Optimization on SSA

A

e.g. hree simple ones:
—Constant Propagation
—Copy Propagation
—Simple Dead Code Elimination

156
Q

What is Packrat Parsing not good for?

A

> General CFG parsing (ambiguous grammars)
—produces at most one result
Parsing highly “stateful” syntax (C, C++)
—memoization depends on statelessness
Parsing in minimal space
—LL/LR parsers grow with stack depth, not input size

157
Q

Parser Combinators

A

> Parser combinators in functional languages are higher order functions used to build parsers
—e.g., Parsec, Haskell

> In an OO language, a combinator is a (functional) object
—To build a parser, you simply compose the combinators

158
Q

JIT compilation

A

Dynamic Translation: Compilation done during execution of a program – at run time – rather than prior to execution

Improve time and space efficiency of programs using:
> portable and space-efficient byte-code
> run-time information → feedback directed optimizations
> speculative optimization

159
Q

Optimization: Iterative Process

A
  • There is no general “right” order of optimizations
  • One optimization generates new opportunities for a preceding one.
    => Optimization is an iterative process

Compile Time vs. Code Quality

160
Q

Stratego

A

—A language for specifying program transformations

XT:
A collection of transformation tools

161
Q

Registers

A

s

162
Q

Runtime storage organization

A

study slides again + chap. 6

163
Q

Stratego vs TXL

A

Scannerless GLR parsing vs Agile parsing (top-down + bottom-up)
Reusable, generic traversal strategies vs Fixed traversals
Separates rewrite rules from traversal strategies vs Traversals part of rewrite rules

164
Q

Instruction selection

A

s

165
Q

maximal munch

A

The “maximal munch” principle is the rule that as much of the input as possible should be processed when creating some construct.

166
Q

Register allocation (Code generation)

A

Choose registers for variables and temporary values; variables not
simultaneously live can share same register

167
Q

Liveness analysis

A

Liveness analysis:
Problem:
—IR has unbounded # temporaries
—Machines has bounded # registers

Approach:
—Temporaries with disjoint live ranges can map to same register
—If not enough registers, then spill some temporaries (i.e., keep in memory)

The compiler must perform liveness analysis for each
temporary
—It is live if it holds a value that may still be needed

Liveness information is a form of data flow
analysis over the control flow graph
-> liveness analysis calculates places where each variable holds a still-needed (live) value

168
Q

downward exposure

A

s

169
Q

upward exposure

A

s

170
Q

optimal tiling

A

s

171
Q

Optimum tiling

A

s

172
Q

virtual machine

A

an abstract computing
architecture supporting a programming language
in a hardware-independent fashion

173
Q

Main Components of a VM

A

s

Virtual machine provides a virtual processor

174
Q

Bytecode:

A

The “machine-code” of the virtual machine

Bytecode is analogous to assembler, except it targets a virtual machine rather than a physical one. Many VMs are stack machines: the generated bytecode pushes values onto a stack, and executes operations that consume one or more values on the top of the stack, replacing them with results

Different forms of bytecodes:
Single bytecodes
Groups of similar bytecodes
Multibyte bytecodes

175
Q

Pharo Bytecode

A
256 Bytecodes, four groups:
Stack Bytecodes
Send Bytecodes
Return Bytecodes
Jump Bytecodes
176
Q

Stack vs. Register VMs

A

Stack machines
• Smalltalk, Java and most other VMs
• Simple to implement for different hardware architectures
• Very compact code

Register machines
• Potentially faster than stack machines
• Only a few register VMs exist, e.g., Parrot VM (Perl6

177
Q

Interpreter State and Loop

A

s

178
Q

Method Contexts

A

sl 38 cc-09

A method context is an object that represents an activation record (stack frame) for a method invocation. Each method context points to the context of its caller, thus constituting a stack of contexts.

179
Q

Automatic Memory Management

A

Tell when an object is no longer used and then recycle the memory

Challenges
– Fast allocation
– Fast program execution
– Small predictable pauses
– Scalable to large heaps
– Minimal space usage

Main Approaches:

  1. Reference Counting (cool idea but fragile)
  2. Mark and Sweep
180
Q

Reference Counting GC

A

Idea
> For each store operation increment count field in header of newly stored object
> Decrement if object is overwritten
> If count is 0, collect object and decrement the counter o each object it pointed to

Problems
> Run-time overhead of counting (particularly on stack)
> Inability to detect cycles (need additional GC technique)

181
Q

Mark and Sweep GC

A

Idea
> Suspend current process
> Mark phase: trace each accessible object leaving a mark in the object header (start at known root objects)
> Sweep phase: all objects with no mark are collected
> Remove all marks and resume current process

Problems
> Need to “stop the world”
> Slow for large heaps generational collectors
> Fragmentation compacting collectors

182
Q

Generational Collectors

A

“Most new objects live very short lives;
most older objects live forever”

Idea
> Partition objects into generations
> Create objects in young generation
> Tenuring: move live objects from young to old generation
> Incremental GC: frequently collect young generation (very fast)
> Full GC: infrequently collect young+old generation (slow)

Difficulty
> Need to track pointers from old to new space

183
Q

GC Remembered Set

A

Write barrier: remember objects with old-young pointers in “Remembered Set”:

When marking young generation, use objects in remembered set as additional roots

184
Q

GC Compacting Collectors

A

Idea
> During the sweep phase all live objects are packed to the beginning of the heap
> Simplifies allocation since free space is in one contiguous block

Challenge
> Adjust all pointers of moved objects
– object references on the heap
– pointer variables of the interpreter!

185
Q

Pharo GC

A

mark and sweep compacting collector with two
generations

> Cooperative, i.e., not concurrent
Single threaded

186
Q

When Does the GC Run?

A

– Incremental GC on allocation count or memory needs
– Full GC on memory needs
– Tenure objects if survivor threshold exceeded

187
Q

Threading System

A

Multithreading is the ability to create concurrently
running “processes”

Non-native threads (green threads):
– Only one native thread used by the VM
– Simpler to implement and easier to port

Native threads
– Using the native thread system provided by the OS
– Potentially higher performance

188
Q

VM Optimizations

A
  • Method cache for faster lookup: receiver’s class + method selector
  • Method context cache (as much as 80% of objects created are context objects!)
  • Interpreter loop: 256 way case statement to dispatch bytecodes
  • Quick returns: methods that simply return a variable or known constant are compiled as a primitive method
  • Small integers are tagged pointers: value is directly encoded in field references
189
Q

Optimization: JIT

A

Idea: Just In Time Compilation
> Translate unit (method, loop, …) into native machine code at runtime
> Store native code in a buffer on the heap

Challenges
> Run-time overhead of compilation
> Machine code takes a lot of space (4-8x compared to bytecode)
> Deoptimization (for debugging) is very tricky

190
Q

Process Scheduler

A

> Cooperative between processes of the same priority

> Preemptive between processes of different priorities

191
Q

Designing a Language Syntax

A

Textbook Method

  1. Formalize syntax via a context-free grammar
  2. Write a parser generator (.*CC) specification
  3. Hack on grammar until “nearly LALR(1)”
  4. Use generated parser
192
Q

What exactly does a CFG describe?

A

a rule system to generate language strings

but we really want: a rule system to recognize language strings

193
Q

Parsing Expression Grammars (PEGs)

A

model recursive descent parsing best practice

PEG specifies rules to recognize sentences in a topdown fashion.

CFG:
S → aaS
S → ε

PEG:
S ← aaS / ε

PEG specifies rules to recognize sentences in a topdown fashion

CFG: a rule system to generate language strings
PEG: a rule system to recognize language strings

194
Q

Key benefits of PEGs

A

> Simplicity, formalism of CFGs
Closer match to syntax practices
—More expressive than deterministic CFGs (LL/LR)
—Unlimited lookahead, backtracking
Linear time parsing for any PEG (!)
-> linear parse time can be achieved with the help
of memoization using a “packrat parser”.

195
Q

Formal properties of PEGs

A

> Expresses all deterministic languages — LR(k)
Closed under union, intersection, complement
Can express some non-context free languages
—e.g., a^nb^nc^n
Undecidable whether L(G) = ∅

196
Q

What can’t PEGs express directly?

A

> Ambiguous languages
—That’s what CFGs are for!

197
Q

Top-down parsing techniques

A

Predictive parsers
• use lookahead to decide which rule to trigger
• fast, linear time

Backtracking parsers
• try alternatives in order; backtrack on failure
• simpler, more expressive (possibly exponential time!)

198
Q

Scannerless parsers

A
  • especially useful when mixing languages

with different terminals

199
Q

Memoized parsing: Packrat Parsers

A

By memoizing parsing results, we avoid having to recalculate partially successful parses

200
Q

What is Packrat Parsing good for?

A

> Linear cost
—bounded by size(input) × #(parser rules)
Recognizes strictly larger class of languages than
deterministic parsing algorithms (LL(k), LR(k))
Good for scannerless parsing
—fine-grained tokens, unlimited lookahead
Scannerless parsing enables unified grammar for entire
language
—Can express grammars for mixed languages with different lexemes!

201
Q

What is Packrat Parsing not good for?

A

> General CFG parsing (ambiguous grammars)
—produces at most one result
Parsing highly “stateful” syntax (C, C++)
—memoization depends on statelessness
Parsing in minimal space
—LL/LR parsers grow with stack depth, not input size

202
Q

Parser Combinators

A

> Parser combinators in functional languages are higher order functions used to build parsers
—e.g., Parsec, Haskell

> In an OO language, a combinator is a (functional) object
—To build a parser, you simply compose the combinators

203
Q

Program Transformation

A

Translation:

  • Compilation
  • migration from procedural to OO

Rephrasing:

  • desugaring regular expressions
  • partial evaluation
204
Q

Program Transformation pipeline

A

program -> parse -> (tree) -> transform -> (tree) -> transform -> (tree) -> pretty-print -> program

205
Q

Stratego

A

—A language for specifying program transformations

XT:
A collection of transformation tools

206
Q

Stratego Parsing

A

Stratego parses any
context-free language
using Scannerless
Generalized LR Parsing

207
Q

TXL

A

general-purpose source to source transformation language

-> original designed as a desugaring tool for syntactic
extensions to the teaching language Turing

208
Q

Stratego vs TXL

A

Scannerless GLR parsing vs Agile parsing (top-down + bottom-up)
Reusable, generic traversal strategies vs Fixed traversals
Separates rewrite rules from traversal strategies vs Traversals part of rewrite rules

209
Q

Refactoring

A

The process of changing a software system in such a
way that it does not alter the external behaviour of the
code, yet improves its internal structure

210
Q

AOP

A

cross-cutting concerns:
Certain features (like logging, persistence and security), cannot usually be encapsulated as classes. They cross-cut code of the system.
AOP improves modularity by supporting the
separation of cross-cutting concerns.

An aspect packages cross-cutting concerns.
A pointcut specifies a set of join points in the target system to be affected.
Weaving is the process of applying the aspect to
the target system

211
Q

Program transformation: rewrite rules?

A

s

212
Q

symbol table

A

aka environment

symbol table map variable names to information about the variables (e.g. type, location)

213
Q

virtual machine primitive

A
  • > Primitive methods trigger a VM routine and are executed without a new method context unless they fail
  • Do work that can only be done in VM (new object creation, process manipulation, become, …)
  • Improve performance
214
Q

regular expressions

A

—Simpler and more concise for tokens than a grammar
—More efficient scanners can be built from REs

  • > CFGs are used to impose structure
  • > lexical analysis: Lexical analysis is the first phase of a compiler. The lexical analyzer breaks these syntaxes into a series of tokens, by removing any whitespace or comments in the source code.
215
Q

token / lexeme

A

Lexemes are said to be a sequence of characters (alphanumeric) in a token. There are some predefined rules for every lexeme to be identified as a valid token. These rules are defined by grammar rules, by means of a pattern. A pattern explains what can be a token, and these patterns are defined by means of regular expressions.

216
Q

interpreter

A

a program that reads an executable
program and produces the results
of running that program

The job of an interpreter is to execute source code, possibly consuming input, and producing output. An interpreter typically will translate the source code to some intermediate representation along the way, but this intermediate form will not necessarily be
stored as an artifact. In contrast to a compiler, an interpreter does execute the source
program.

217
Q

LALR

A

LookAhead LR (uses “lookahead sets”)

218
Q

derivation

A

a proof that shows a sentence is in the language of a grammar.

  • > start with the start symbol, then repeatedly replace any nonterminal by one of its right-hand sides
  • there are many different derivations of the same sentence
  • a parse tree is made by connecting each symbol in a derivation to the one from which it was derived

We can view the productions of a CFG as rewriting rules.
The process of discovering a derivation is called parsing

219
Q

Scanner generators

A
automatically construct code from
regular expression-like descriptions
—construct a DFA
—use state minimization techniques
—emit code for the scanner (table driven or direct code )