Professor Craton
Anything you want to know?
In Babbage’s world his engines were bound by number…what Ada Byron saw—was that number could represent entities other than quantity. So once you had a machine for manipulating numbers, if those numbers represented other things, letters, musical notes, then the machine could manipulate symbols of which number was one instance
objdump -d hello
hello: file format elf64-x86-64
Disassembly of section .text:
00000000004000d4 <.text>:
4000d4: 48 c7 c0 01 00 00 00 mov $0x1,%rax
4000db: 48 c7 c7 01 00 00 00 mov $0x1,%rdi
4000e2: 48 c7 c6 02 01 40 00 mov $0x400102,%rsi
4000e9: 48 c7 c2 0e 00 00 00 mov $0xe,%rdx
4000f0: 0f 05 syscall
4000f2: 48 c7 c0 3c 00 00 00 mov $0x3c,%rax
4000f9: 48 c7 c7 00 00 00 00 mov $0x0,%rdi
400100: 0f 05 syscallCode is converted to machine code or another executable form
hello.i is plain text C code and can be inspected.
hello.s is plain text Assembly and can be inspected
hexedit hello.oobjdump -d hello.ohello is x64 machine codehexedit helloobjdump -d hellomake is a build automation tool
Contain a set of directives that instruct make how to create a target.
In computer science, lexical analysis, lexing or tokenization is the process of converting a sequence of characters (such as in a computer program or web page) into a sequence of tokens
Commonly stored as (name, value) tuples. Example:
Becomes:
(identifier, "my_variable")
(operator, "=")
(integer, 17)
1 + 24 - 22 * 38 / 4Grammar Automaton (Computer)
A string used as a search pattern for a member of a regular language.
? - zero or one occurrences of preceding element* - zero or more occurrences of preceding element+ - one or more occurrences of preceding element{n} - exactly n occurrences of preceding element[] may be used to match a single character
against a set of charactersSeveral special character classes are provided:
\w - alphanumeric characters\d - digits\s - whitespace characters. - anythingimport sys
import re
def lex_one(value):
if re.match('\d+', value):
return ('number', value)
elif re.match('[\+\-\*\/]', value):
return ('operator', value)
else:
raise ValueError(f'Invalid token: {value}')
def lex(text):
return [lex_one(v) for v in text.split()]Lexing lab questions?
Parsing or syntax analysis is the process of analyzing a string of symbols conforming to the rules of a formal grammar.
1 + 24 - 22 * 38 / 4Grammar Automaton (Computer)
Unrestricted Turing Machines Context Free Pushdown Automata Regular Finite State Automata
Parsing “1 + 2”
Shift: 1
Reduce: (expr 1)
Shift: +
Shift: 2
Reduce: (expr 2)
Reduce: (expr (expr 1) + (expr 2))
Result: (expr (expr 1) + (expr 2))
Section 3.1
Section 3.2
staticmalloc returns a pointer to allocated heap memoryfree frees the memorychar* ptr;
// Allocate 100 bytes
ptr = (char*) malloc(100 * sizeof(char));
// Do some things using the memory
// ...
// Free the memory
free(ptr);Exam in lab, Thursday, March 5th
(Section 3.3)
The textual region of a program where a binding is active
Can also be used to refer to a region of a program where no bindings are changing
The set of active bindings
import inspect
def main():
a = 1
def sub(b):
c = 3
print('Locals:', inspect.currentframe().f_locals)
print('Parent:', inspect.currentframe().f_back.f_locals)
sub(2)
main()Locals: {'c': 3, 'b': 2}
Parent: {'sub': <function main.<locals>.sub at 0x7f89903ce268>, 'a': 1}
Binding can be determined at compile time
10 FOR X = 1 TO 10
20 PRINT "HELLO, WORLD"
30 NEXT X
integer if name begins with I-N or real
otherwise)save in Fortran, own in AlgolSection 3.5
Some names can refer to multiple objects at a given time
Allows a subroutine to perform differently based on the types involved
Section 3.6
Chapter 6
Dictates the order of program execution
if, then,
else and forif or switchfor loopfor loops must often be more complex,
as loop count can’t be easily predictedTail-recursive version:
__iter__ method that returns an
iterator__next__ method that returns the next
itemyield successive valuesChapters 7 & 8
Strictly enforces valid types and operations
Type rules are enforced at compile time
#include <iostream>
#include <cstring>
template <typename Type>
Type get_min(Type a, Type b) {
return a < b ? a : b;
}
template <>
const char* get_min<const char*>(const char* a, const char* b) {
return std::strcmp(a, b) < 0 ? a : b;
}
int main() {
std::cout << get_min(2, 1) << std::endl;
std::cout << get_min("hello", "world") << std::endl;
}null is one option, but it can be used differently in
different contextsType Option represents an optional value: every Option is either Some and contains a value, or None, and does not. Option types are very common in Rust code
Introduced in Pascal:
Also introduced in Pascal:
. notation.On most systems, the layout of items in a struct can change the storage space requirements due to alignment constraints.
Have you ever needed to write code to remove duplicate elements from a list?
The difference between a bad programmer and a good one is whether they consider their code or their data structures more important. Bad programmers worry about the code. Good programmers worry about data structures and their relationships.
- Linus Torvalds
void in C, Object in
Java, and object in C#Let’s revisit our previous C container example to use void.
#include <stdio.h>
typedef struct {
int inner;
} ContainerA;
typedef struct {
int inner;
} ContainerB;
// Use void to accept any pointer
void increment(void* container) {
// Cast pointer to ContainerB type
((ContainerB*)container)->inner += 1;
}
int main() {
ContainerA container = {0};
increment(&container);
printf("Number %d\n", container.inner);
}C++ provides the auto keyword to infer types
Some languages are statically typed while providing type inference such that explicit types are rarely required. Examples are ML, Haskell, and Rust.
fn main() {
let elem = 5u8;
// The compiler knows that `elem` has type u8
let mut vec = Vec::new();
// The compiler doesn't yet know the exact type of `vec`
// It just knows that it's a vector (`Vec<_>`)
vec.push(elem);
// Aha! Now the compiler knows that
// `vec` is a vector of `u8`s (`Vec<u8>`)
println!("{:?}", vec);
}#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void main(void) {
char * a = malloc(6);
char * b = malloc(4);
strcpy(a, "Alice");
strcpy(b, "Bob");
// Shallow compare
printf("%d\n", a == b); // False
printf("%d\n", a == a); // True
// Undefined behavior, typical results provided
printf("%d\n", a == "Alice"); // False
printf("%d\n", a != "Bob"); // True
// Deep compare
printf("%d\n", strcmp(a, a) == 0); // True
printf("%d\n", strcmp(a, b) == 0); // False
printf("%d\n", strcmp(a, "Alice") == 0); // True
}Enum lab questions?
It is a great vaccine. It is a safe vaccine, and it is something that works.
Chapter 9
If we allow C++, we can use a proper pass by reference mode.
Callers will be able to see modifications to mutable objects
Callers will still hold a reference to the exact same object
Immutable objects (such as tuples or strings) can’t be modified for the caller
Python allows us to annotate optional parameters by providing default values
All parameters are optional in Javascript
printf in Cimport urllib.request
import json
junk_foods = [
'Pizza',
'Popcorn',
'Hamburger',
'Pepsi',
'Potato_chip',
'Cake',
]
url = 'https://en.wikipedia.org/w/api.php?action=parse&format=json&page='
for food in junk_foods:
contents = urllib.request.urlopen(f'{url}{food}').read()
print(f"{food}: {json.loads(contents)['parse']['properties'][0]['*']}")const https = require('https')
junk_foods = ['Pizza', 'Popcorn', 'Hamburger', 'Pepsi', 'Potato_chip', 'Cake']
url = 'https://en.wikipedia.org/w/api.php?action=parse&format=json&page='
junk_foods.forEach(food => {
https.get(
{
host: 'en.wikipedia.org',
path: '/w/api.php?action=parse&format=json&page=' + food,
},
function (res) {
let body = ''
res.on('data', function (d) {
body += d
})
res.on('end', function () {
console.log(`${food}: ${JSON.parse(body).parse.properties[0]['*']}`)
})
},
)
})Chapter 10
fields or propertiesmethodsthis and selfObjects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.
class Asset:
"""
Represents some asset and provides methods to operate on it
>>> bitcoin = Asset(1, appreciation=1)
>>> int(bitcoin.future_value(years=10))
1024
>>> int(bitcoin.change_in_value(years=10))
1023
"""
def __init__(self, value, appreciation):
self.value = value
self.appreciation = appreciation
def future_value(self, years):
return self.value * (1 + self.appreciation) ** years
def change_in_value(self, years):
return self.future_value(years) - self.value
class House(Asset):
""" Represents a real estate asset
>>> house = House(100000, appreciation=.01, maintenance=.02, tax=.03, utilities=100)
>>> int(house.operating_cost(10))
53311
>>> int(house.tco(10))
42848
"""
def __init__(self, value, appreciation=0.02, maintenance=0.02, tax=0.01, utilities=200):
super().__init__(value, appreciation)
self.maintenance = maintenance
self.tax = tax
self.utilities = utilities
def operating_cost(self, years):
maintenance = sum(self.future_value(y) * self.maintenance for y in range(years))
tax = sum(self.future_value(y) * self.tax for y in range(years))
return maintenance + tax + self.utilities * years
def tco(self, years):
return -self.change_in_value(years) + self.operating_cost(years)
class Vehicle(Asset):
"""
Represents a vehicle of some type
>>> car = Vehicle(16000, appreciation=-.2, maintenance=500, mpg=22)
>>> int(car.tco(years=5))
20075
>>> car = Vehicle(16000, appreciation=-.2, maintenance=500, mpg=38)
>>> int(car.tco(years=5))
17204
"""
def __init__(self, value=16000, appreciation=-0.25, maintenance=300, mpg=25):
super().__init__(value, appreciation)
self.maintenance = maintenance
self.mpg = mpg
def operating_cost(self, years, miles_per_year=10000, gas_price=3.0):
return self.maintenance * years + miles_per_year / self.mpg * gas_price * years
def tco(self, years):
return -self.change_in_value(years) + self.operating_cost(years)
if __name__ == '__main__':
house = House(100000, appreciation=0.04, tax=.01, maintenance=.02)
print("House", house.tco(10))
car = Vehicle(35000, appreciation=-0.20, mpg=22)
print("Car", car.tco(10))
car = Vehicle(8000, appreciation=-0.10, mpg=35)
print("Budget car", car.tco(10))Favor composition over inheritance
Chapter 11
In modern languages, the lines between language families and often have a lot of overlap.
Functions that accept functions as parameters
We express the logic of our program without specifying its control flow
/* Create users */
create table users (
userid integer primary key,
name text
);
insert into users values
(1,'Alice'),
(2,'Bob'),
(3,'Carol'),
(4,'Dan'),
(5,'Eve'),
(6,'Frank');
/* Create chat message */
create table messages (
userid integer,
content text
);
insert into messages values
(2,'Does anyone know how modify a record in a SQL DB?'),
(6,'Everyone knows how to do this'),
(3,'Have you tried `UPDATE`?'),
(2,'Nope. What does that do?'),
(3,'It updates a record in a SQL DB...'),
(2,'Oh cool. I will try that.'),
(3,'Good luck!'),
(5,'wat up, nerds!'),
(4,'Is there any way to link records between two tables?'),
(6,'Of course there is'),
(1,'I think that you are looking for a `JOIN`'),
(4,'Ah. Thanks!'),
(1,'No problem.');
select "
Display messages in order";
select userid, content
from messages;
select "
Display messages with usernames";
select name, content
from messages
natural join users;
select "
Display messages with usernames in reverse order";
select name, content
from messages
natural join users
order by messages.rowid desc;
select "
Show Dan's messages using a `where` clause";
select name, content
from messages
natural join users
where name='Dan';
select "
Show query plan (imperative program to complete query)";
explain query plan
select name, content
from messages
natural join users
where name='Dan';
select "
Create indexes to improve query plan";
create index messages_userid_idx on messages(userid);
create index users_name_idx on users(name);
select "
Show new query plan";
explain query plan
select name, content
from messages
natural join users
where name='Dan';
select "
Change Dan's name to Dave";
update users
set name = 'Dave'
where name = 'Dan';
select name, content
from messages
natural join users;
select "
Delete Eve's messages";
delete from messages
where userid = (
select userid
from users
where name = 'Eve'
);
select name, content
from messages
natural join users;
/*
Lab Excercises
You should be able to complete these using the same techniqes
as above, but you if need a place to start to refresh you SQL
knowledge, you may want to start with an overview like this:
https://en.wikipedia.org/wiki/SQL_syntax#Queries
*/
select "
Display messages with usernames sorted by username";
select "
Change Alice's name to Abby";
select "
Add a new message";
select "
Delete Frank's messages";
/*
You have nothing to do after this point
We just show all messages here so you can easily see your changes
*/
select "
Final message list";
select name, content
from messages
natural join users;all: main
main: main.c
gcc main.c -o main
Language used to describe the behavior of electronic circuits.