Home > CS4080: Programming Languages > Syntax and GrammarSyntax and Grammar
Syntax in a programming language is specificied using a mathematical device called a Grammar.
Relevant Notes: CS3310 (Formal Languages and Automata
Arithmetic Expression
AExp \to IntBit | AExp + AExp | ...
Boolean Expression
BExp \to BLit | BExp < BExp | ...
BLit: Boolean Literal
Statements:
\text{Stmnt} \to \text{Assgment} | \text{IFThen | \text{while}
et cetera…
Variable: Store data and associate it with a name.
Variables have two values associated with them.
int x = 42
Symbol table:
Symbol | L-Value | R-Value |
---|---|---|
x | i | 42 |
… | … | … |
- Static type checking is an uncomputable problem. There is no algorithm that can, for all possible instances, solve that problem.
int x = 42;
int *p = &x;
Symbol table:
Symbol | L-Value | R-Value |
---|---|---|
x | i | 42 |
p | j | i |
… | … | … |
Notice how
*p
andx
become aliases for the same memory location, which can lead to potential problems.
Binding: Association of a name to a particular property.
\begin{matrix} &\text{Symbol} & & &\text{Property} \\ &x &\to& &p \end{matrix}
Types of Binding:
- Memory Allocation: Memory binding
- Typing: Type binding
- Scoping: Scope binding
Binding Time: When the binding happens
More on Static Binding: Two types
- Compiler does it
- Lexer does it.
Note: This has nothing to do with the
static
keyword in Java.
Static Allocation: Allocation happens before execution (typically the compiler)
Process Memory Heap:
TODO plantuml
- stack (stack frames)
- heap (dynamically allocated data)
- data (statically allocated data).
- text
Refresher: Frames store the local variables and parameters of a function call.
Dynamic Allocation: Allocation happens during execution.
// Statically allocate n=3
= int[3];
x
// Dynamically allocate n=3
= malloc(sizeof(int) * 3); y
In dynamic languages (e.g., Python, Ruby, Perl), all arrays are dynamic, because there is no static allocation in an interpreted language.
Typing: Assigning a type to every symbol in a program, and checking the type assignment makes sense.
Static Typing: Happens before execution, typically during compilation
// Explicit Typing
let x : f64 = 1.0;
// Implicit Typing (type inference)
let y = 1.0;
On Overhead:
Typing adds a lot of overhead, which is why there’s a gap in performance between compiled and dynamic languages.
- In the modern day, with JIT and other optimizations, this gap is shortening.
Dynamic Typing: Happens during execution
Strict Typing: When the type is allowed to change. Suppose: If this is disallowed, the typing is said to be strict.Example: Strict typing
x := 42
// ...
x := "Apple"
Scope: The region of a program where a symbol is visible.
Remember: This is about visibility, not permanence!
Typical example:
fn f() {
let x = 42;
}
fn g() {
let y = 42;
}
Wacky example:
// We can statically define variables in c
() {
fstatic x = 0;
++;
x}
Scoping happens while writing the program.
Whatever is in the stack exists everywhere. For most dynamic languages, this is an optional thing you have to turn on.Example: Dynamic scoping
z := 0
x := 0
call g
call f
function f() {
// Shadows the x outside
x := 42
call g
}
function g() {
// Uses the x in the function that called me
y := x \text{$+$} 7
}