On Github zzag / slides
At the University of Manchester, Alick Glennie developed Autocode in the early 1950s. The first code and compiler was developed in 1952 for the Mark 1 computer at the University of Manchester and is considered to be the first compiled high-level programming language.
The origin of C is closely tied to the development of the Unix operating system, originally implemented in assembly language on a PDP-7 by Ritchie and Thompson, incorporating several ideas from colleagues. Eventually, they decided to port the operating system to a PDP-11. The original PDP-11 version of Unix was developed in assembly language. The developers were considering rewriting the system using the B language, Thompson's simplified version of BCPL. However B's inability to take advantage of some of the PDP-11's features, notably byte addressability, led to C.
Unix was one of the first operating system kernels implemented in a language other than assembly. (Earlier instances include the Multics system (written in PL/I), and MCP (Master Control Program)
The 1980s were years of relative consolidation in imperative languages. Rather than inventing new paradigms, all of these movements elaborated upon the ideas invented in the previous decade. C++ combined object-oriented and systems programming. The United States government standardized Ada, a systems programming language intended for use by defense contractors. In Japan and elsewhere, vast sums were spent investigating so-called fifth-generation programming languages that incorporated logic programming constructs. The functional languages community moved to standardize ML and Lisp. Research in Miranda, a functional language with lazy evaluation, began to take hold in this decade.
One important new trend in language design was an increased focus on programming for large-scale systems through the use of modules, or large-scale organizational units of code. Modula, Ada, and ML all developed notable module systems in the 1980s. Module systems were often wedded to generic programming constructs---generics being, in essence, parametrized modules (see also polymorphism in object-oriented programming).
The 1980s also brought advances in programming language implementation. The RISC movement in computer architecture postulated that hardware should be designed for compilers rather than for human assembly programmers. Aided by processor speed improvements that enabled increasingly aggressive compilation techniques, the RISC movement sparked greater interest in compilation technology for high-level languages.
This era began the spread of functional languages
typeOf(<e1, '+', e2>) = t1 = typeof(e1) t2 = typeOf(e2) if t1 != t2 && t1 != <no-type> && t2 != <no-type> { error("type mismatch") return <no-type> } return t1Use Visitor pattern to traverse AST!!!
codegen(<e1, '+', e2>) = codegen(e1) print("push r0") codegen(e2) print("push r0") print("pop r2") # value of e2 print("pop r1") # value of e1 print("add r0, r1, r2")
class Band { var name: String var members: List<Dude> fn getName(): String { return name; } fn getMembers(): List<Dude> { return members; } fn addMember(dude: Dude) { members.add(dude); } }
struct Band { name: String, members: List<Dude> } fn Band__getName(self: Band): String { return self.name; } fn Band__getMembers(self: Band): List<Dude> { return self.members; } fn Band__addMember(self: Band, dude: Dude) { List_Dude__add(self.members, dude); }
Defined by backend
Close enough to assembly
Target independent
SSA
%4 = load i32, i32* %j, align 4 %5 = sitofp i32 %4 to float %6 = load float, float* %delta_x, align 4 %7 = fmul float %6, %5 %8 = load float, float* %x_min, align 4 %9 = fadd float %8, %7 store float %9, float* %re, align 4 %10 = load i32, i32* %i, align 4 %11 = sitofp i32 %10 to float
collection of modular and reusable compiler and toolchain technologies
var name: type = initValue; var name = initValue; var pi: f32 = 3.1415; var goldenRatio = 1.618; // => f32 var rustIsTheBest = true; // => bool
func name(args): return-type { ... } func add(a: i32, b: i32): i32 { return a + b; }
binary: +, -, *, /, %, <<, >>, &, |, ^ unary: -, prefix -- and ++, postfix -- and ++ comparison: <, >, <=, >=, ==, !=, &&, || x++; // postfix inc ++x; // prefix inc x = 3 + 4; x -= y; // x = x - y x += 3.6 as i32;
if <cond> { ... } else if <cond> { ... } else if <cond> { ... } else { ... } <stmt> if <cond> <stmt> unless <cond>
while <cond> { ... } unless <cond> { ... } loop { ... } for <init>, <cond>, <step> { ... }
// break statement is encountered inside a loop, // the loop is immediately terminated and the program // control resumes at the next statement following the loop break // continue statement forces the next iteration // of the loop to take place continue return <expr>
// Hello world // compile: bin/emit-elf hello.txt func main(): i32 { puts("Hello, world!"); return 0; }
// Get sum of numbers in range [1, 10] var acc = 0; for var i = 1, i <= 10, ++i { acc += i; }