Computer Language Processing (Compiler Construction) Staff: • Viktor Kuncak – Lectures • Etienne Kneuss – Labs • Ravichandhran Kandhadai Madhavan – Exercises http://lara.epfl.ch/cc Drawing Hands M.C. Escher, 1948
Jan 12, 2016
Computer Language Processing(Compiler Construction)
Staff:• Viktor Kuncak – Lectures• Etienne Kneuss – Labs• Ravichandhran Kandhadai Madhavan – Exercises
http://lara.epfl.ch/ccDrawing Hands
M.C. Escher, 1948
Computer Language ProcessingLanguage can be
– Natural language (French, English, …)– computer language (Java, Scala, C, SQL, …)– Mathematical language: a set of strings
• Can represent both of the above
We can process the language: do something with strings in the language
– manually: mathematical proof, literary criticism– using computers: algorithms that work on strings
Computer language processing in this course: processing computer languages using computers
Compilers
A typical compiler processes a general-purpose, Turing-complete, language and translates it into the form where it can be efficiently executed
– gcc and clang: map C into machine instructions– Java compiler: Java source code into bytecodes
(.class files)– Just-in-time (JIT) compiler inside the Java Virtual
Machine (JVM): translate .class files into machine instructions (while running the program)
This is the focus of this class and the class project.
Example: javac
while (i < 10) { System.out.println(j); i = i + 1; j = j + 2*i+1; }
4: iload_1 5: bipush 10 7: if_icmpge 32 10: getstatic #2; //System.out 13: iload_2 14: invokevirtual #3; //println 17: iload_1 18: iconst_1 19: iadd 20: istore_1 21: iload_2 22: iconst_2 23: iload_1 24: imul 25: iadd 26: iconst_1 27: iadd 28: istore_2 29: goto 4 32: return
javac Test.java Test.class javap –c Test
You will build a compiler thatgenerates such code
- from Java to Bytecode
…
…
Example: gcc
#include <stdio.h> int main(void) { int i = 0; int j = 0; while (i < 10) { printf("%d\n", j); i = i + 1; j = j + 2*i+1; } }
jmp .L2 .L3: movl -8(%ebp), %eax
movl %eax, 4(%esp)movl $.LC0, (%esp) call printf addl $1, -12(%ebp) movl -12(%ebp), %eaxaddl %eax, %eax addl -8(%ebp), %eaxaddl $1, %eax movl %eax, -8(%ebp)
.L2:cmpl $9, -12(%ebp) jle .L3
gcc test.c –S test.s
- from C to Intel x86
Compiler (scalac, gcc)
machine code(e.g. x86, ARM, JVM)efficient to execute
i=0while (i < 10) { a[i] = 7*i+3 i = i + 1 }
source code(e.g. Scala, Java,C)easy to write
mov R1,#0mov R2,#40mov R3,#3jmp +12mov (a+R1),R3add R1, R1, #4add R3, R3, #7cmp R1, R2blt -16
CompilerConstruction
i=0LFwhile
i=0
while(i<
10)
lexer
characters words trees
data-flowgraphs
parser
assign
while
i 0
+
* 37 i
assigna[i]
<i 10
code gen
optimizer
type check
Compilers are Important
Source code (e.g. Scala, Java, C, C++, Python) – designed to be easy for programmers to use
– should correspond to way programmers think– help them be productive: avoid errors, write at a
higher level, use abstractions, interfaces
Target code (e.g. x86, arm, JVM, .NET) – designed to efficiently run on hardware / VM
– fast, low-power, compact, low-level
Compilers bridge these two worlds, they are essential for building complex software
A pioneering compiler: FORTRAN(FORmula
TRANslator)
Turing Award1977
Backus-NaurForm - BNF
Challenges for Future
Can source code programs be wishes:specification languages, math,natural language phrases, diagrams, other forms of communication closerto engineers and users?
Can target code commands include not only execution of commands on standard microprocessors processors, but also automatic design of new hardware devices, and control of physical devices?
Can compilers bridge the gap betweenwishes and commands, and help humans make the right decisions?
Some of Topics You Learn in Course• Develop a compiler for a Java-like language
– Write a compiler from start to end– Generates Java Virtual Machine (JVM) code (We provide you code stubs, libraries in Scala)
• Compiler generators – using and making them• Analyze complex text
– Automata, regular expressions, grammars, parsing• Automatically detecting errors in code
– name resolution, type checking, data-flow analysis• Machine-like code generation
Potential Uses of Knowledge Gained– understand how compilers work, use them better– gain experience with building complex software– build compiler for your next great language– extend language with a new construct you need– adapt existing compiler to new target platform
(e.g. embedded CPU or graphics processor)– regular expression handling in editors, grep – build an XML parsing library– process complex input box in an application
(e.g. expression evaluator)– parse simple natural language fragments
Schedule and Activities (6 credits)• All activities take place in INM 202
– Mondays 10:15-12:00, – Wednesday 8:15-10:00 and continuing to:– Wednesday 10:15-12:00
• Lectures, Labs, Exercises• At home
– Continue with programming the compiler– Practice solving problems to prepare for quizzes
• If you need more help, email us:– we will arrange additional meetings
How We Compute Your Grade
The grade is based on a weighted average of:– 50% : project (submit, explain if requested)
• submit through our wonderful online system• do them in groups of 2, exceptionally 1 or 3
– 25% : quiz for the first part of the course– 25% : quiz for the second part of the course
• will be on the last Wednesday of classes
Collaboration and Its Boundaries• For clarification questions, discuss them in the
mailing list, which we monitor• Work in groups of 2 for project
– everyone should know every part of code– we may ask you to explain specific parts of code
• Do not copy lab solutions from other groups!– we use code plagiarism detection tools– we will check if you fully understand your code
• Do the quizzes individually– You wouldn’t steal a handbag. – You wouldn’t steal a car. – You wouldn’t steal a compiler!
Your Compiler
JVMCode
i=0while (i < 10) { a[i] = 7*i+3 i = i + 1 }
source codesimplified Java-likelanguage
21: iload_2 22: iconst_2 23: iload_1 24: imul 25: iadd 26: iconst_1 27: iadd 28: istore_2
Your Compiler
Construction
i=0LFwhile
i=0
while(i<
10)
lexer
characters words trees
parser
assign
while
i 0
+
* 37 i
assigna[i]
<i 10
code gentype check
Each two weeks you will add next phase - keep same groups - it is essential to not get behind schedule - final addition to compiler is your choice!
EPFL Course Dependencies• Theoretical Computer Science (CS-251)
– If have not taken it, check the book “Introduction to the Theory of Computation” by Michael Sipser
• Knowledge of the Scala language (see web)• Helpful general background
– Discrete structures (CS-150), Algorithms (CS-250)• This course provides background for MSc:
– Advanced Compilers– Synthesis Analysis & Verification– Foundations of Software
Course Materials
Official Textbook:Andrew W. Appel, Jens Palsberg:Modern Compiler Implementation in Java (2nd Edition). Cambridge University Press, 2002We do not strictly follow it–understand, not copy
– program in Scala instead of Java– use pattern matching instead of visitors– hand-written parsers in the project
(instead of using a parser generator)
Lectures in course wiki: http://lara.epfl.ch/w/cc
Additional Materials• Compilers: Principles, Techniques, and Tools (2nd Edition) by
Alfred V. Aho, Monica S. Lam, Ravi Sethi, Jeffrey D. Ullman– comprehensive
• Compiler Construction by Niklaus Wirth– concise, has main ideas
“Niklaus Emil Wirth (born February 15, 1934) is a Swiss computer scientist, best known for designing several programming languages, including Pascal, and for pioneering several classic topics in software engineering. In 1984 he won the Turing Award for developing a sequence of innovative computer languages.”
• Additional recent books (2011-2012):– Aarne Ranta: Implementing Programming Languages– H.Seidl, R.Wilhelm, S.Haack: Compiler Design (3 vols, Springer)
Describing the Syntax of Languages
Syntax (from Wikipedia)
...In linguistics, syntax (from Ancient Greek σύνταξις "arrangement" from σύν - syn, "together", and τάξις - táxis, "an ordering") is the study of the principles and rules for constructing phrases and sentences in natural languages.
...In computer science, the syntax of a programming language is the set of rules that define the combinations of symbols that are considered to be correctly structured programs in that language.
Describing Syntax: Why
• Goal: document precisely (a superset of) meaningful programs (for users, implementors)– Programs outside the superset: meaningless– We say programs inside make syntactic sense
(They may still be ‘wrong’ in a deeper sense)• Describing syntactically valid programs
– There exist arbitrarily long valid programs, we cannot list all of them explicitly!
– Informal English descriptions are imprecise, cannot use them as language reference
Describing Syntax: How
• Use theory of formal languages (from TCS)– regular expressions & finite automata– context-free grammars
• We can use such precise descriptions to– document what each compiler should support– manually derive compiler phases (lexer, parser)– automatically construct these phases using
compiler generating tools• We illustrate this through an example
While Language – Idea
• Small language used to illustrate key concepts• Simpler than the language for which you
implement your compiler• ‘while’ and ‘if’ are the control statements
– no procedures, no exceptions• the only variables are of ‘int’ type
– no variable declarations, they are initially zero– no objects, pointers, arrays
While Language – Example Programsx = 13; while (x > 1) { println("x=", x); if (x % 2 == 0) { x = x / 2; } else { x = 3 * x + 1; } }
Does the program terminate for every initial value of x? (Collatz conjecture - open)
while (i < 100) { j = i + 1; while (j < 100) { println(“ “,i); println(“,”,j); j = j + 1; } i = i + 1;}
Nested loop
Even though it is simple, while is Turing-complete.
Reasons for Unbounded Program Length
while (i < 100) { j = i + 5*(j + 2*(k + 7*(j+k) + i)); while (293847329 > j) { while (k < 100) { someName42a = someName42a + k; k = k + i + j; println(“Nice number”, k) } }}
constants of any length
variable names of any length
nesting of expressions
nesting of statements
(words - tokens)
String constantsof any length
Tokens (Words) of the While LanguageIdent ::=
letter (letter | digit)*integerConst ::=
digit digit*stringConst ::=
“ AnySymbolExceptQuote* “keywords
if else while printlnspecial symbols
( ) && < == + - * / % ! - { } ; , letter ::= a | b | c | … | z | A | B | C | … | Zdigit ::= 0 | 1 | … | 8 | 9
regularexpressions
Double Floating Point Constants
Different rules in different languages1) digit digit* [ . ] [ digit digit* ]
2) digit digit* [ . digit digit * ]
3) digit* . digit digit*
4) digit digit* . digit digit*
while (i < 100) { j = i + 5*(j + 2*(k + 7*(j+k) + i)); while (293847329 > j) { while (k < 100) { someName42a = someName42a + k; k = k + i + j; println(“Nice number”, k) } }}
letter (letter | digit)*
Identifiers
Id3 = 0while (id3 < 10) { println(“”,id3); id3 = id3 + 1 }
source codeCompiler
Construction
id3
=
0LFw
id3=0
while(
id3<
10)
lexer
characters words(tokens)
trees
parser
assign
while
i 0
+
* 37 i
assigna[i]
<i 10
Lexer is specified using regular expressions.Groups characters into tokens and classifies them into token classes.
More Reasons for Unbounded Length
while (i < 100) { j = i + 5*(j + 2*(k + 7*(j+k) + i)); while (293847329847 > j) { while (k < 100) { someName42a = someName42a + k; k = k + i + j; println(“Nice number”, k) } }}
constants of any length
variable names of any length
nesting of expressions
nesting of statements
(words - tokens) (sentences)
String constantsof any length
Sentences of the While Language
We describe sentences using context-free grammar (Backus-Naur form). Terminal symbols are tokens (words)
program ::= statmt* statmt ::= println( stringConst , ident ) | ident = expr | if ( expr ) statmt (else statmt)?
| while ( expr ) statmt | { statmt* } expr ::= intLiteral | ident | expr (&& | < | == | + | - | * | / | % ) expr | ! expr | - expr
nesting of statements
nesting of expressions
While Language without Nested Loops
statmt ::= println( stringConst , ident ) | ident = expr | if ( expr ) statmt (else statmt)?
| while ( expr ) statmtww | { statmt* } statmtww ::= println( stringConst , ident ) | ident = expr | if ( expr ) statmtww (else statmtww)?
| { statmtww* }
Id3 = 0while (id3 < 10) { println(“”,id3); id3 = id3 + 1 }
source codeCompiler
Construction
id3
=
0LFw
id3=0
while(
id3<
10)
lexer
characters words(tokens)
trees
parser
assign
while
i 0
+
* 37 i
assigna[i]
<i 10
regular expressionsfor tokens
context-freegrammar
Abstract Syntax - TreesTo get abstract syntax (trees, cases classes), start from context-free grammar for tokens, then
– remove punctuation characters– interpret rules as tree descriptions, not string descriptions
statmt ::= println( stringConst , ident ) PRINT(String,ident)
| ident = expr ASSIGN(ident,expr)
| if ( expr ) statmt (else statmt)? IF(expr,stmt,Option[statmt])
| while ( expr ) statmt WHILE(expr,statmt) | { statmt* } BLOCK(List[statmt])
abstract class statmtcase class PRINT(id:ident) extends statmtcase class ASSIGN(id:ident, e:expr) extends statmtcase class IF(e:expr, s1:statmt, s2:Option[statmt]) extends statmt ...
concrete syntax abstract syntax
Scala trees for this abstract syntax
ocaml vs Haskell vs Scala
ocaml: type tree = Leaf | Node of tree * int * treeHaskell: data Tree = Leaf | Branch Tree Int TreeScala: abstract class Tree case object Leaf extends Tree case class Node(left:Tree,x:Int,right:Tree) extends Tree
Example of Parsingres = 14 + arg * 3
Lexer:
res = 14 + arg * 3
Parser:
ASSIGN(res, PLUS(CONST(14), TIMES(VAR(arg),CONST(3))))
Code generator then “prints” this tree into instructions.
:=
+
*
res
arg 3
14
Interpreters
What is an interpreter?
• Interpreter is a simpler way to implement a language
• Usually it is easier to build than a compiler• It can be used as one way to define the meaning
of programs: programs should compute whatever the interpreter returns
• Your first lab: build an interpreter– the front end (lexer and parser) will be given to you
as a class file
Your Compiler
JVMCode
i=0while (i < 10) { a[i] = 7*i+3 i = i + 1 }
source codesimplified Java-likelanguage
result of executing the program
InterpreterConstruction
(first lab)
i=0LFwhile
i=0
while(i<
10)
lexer
characters words trees
parser
assign
while
i 0
+
* 37 i
assigna[i]
<i 10
Differences with the compiler• does not generate code• waits for program input, evaluates
program tree, computes the result
interpreter
program inputs
Reminder about Formal Languages
Languages Formally
• A word is a finite, possibly empty, sequence of elements from some set ΣΣ – alphabet, Σ* - set of all words over Σ
• For lexer: characters; for parser: token classes• uv denotes concatenation of words u and v• By a language we mean a subset of Σ*
– union, intersection, complement wrt. Σ*
L1 L2 = { u1 u2 | u1 in L1 , u2 in L2 }L0 = {ε} Lk+1 = L Lk
L* = Uk Lk (Kleene star)
Are there finitely many tokens?• There are finitely many token classes
– identifier– string– {– }– ( ... (many, but finitely many)
There is unbounded number of instances of token classes identifier and stringWhen we discuss grammars, we work with token classes.
Examples of Languages
Σ = {a,b}Σ* = {ε, a, b, aa, ab, ba, bb, aaa, aab, aba, ... }
Examples of two languages, subsets of Σ* :L1 = {a, bb, ab} (finite language, three words)
L2 = {ab, abab, ababab, ... } = { (ab)n | n ≥ 0 } (infinite language)
Examples of Operations
L = {a,ab}L L = { aa, aab, aba, abab }L* = { a, ab, aa, aab, aba, abab, aaa, ... }(is bb inside L* ?) = { w | immediately before each b there is a }