Syntax and Grammar

Syntax Specification

Syntax in a programming language is specificied using a mathematical device called a Grammar.

Relevant Notes: CS3310 (Formal Languages and Automata

Example: A really simple language’s syntax

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…

Variables and Binding

Variables

Variable: Store data and associate it with a name.

Variables have two values associated with them.

Example: A variable
int x = 42

Symbol table:

SymbolL-ValueR-Value
xi42
Example: A pointer
int x = 42;
int *p = &x;

Symbol table:

SymbolL-ValueR-Value
xi42
pji

Notice how *p and x become aliases for the same memory location, which can lead to potential problems.

Binding

Binding: Association of a name to a particular property.

\begin{matrix} &\text{Symbol} & & &\text{Property} \\ &x &\to& &p \end{matrix}

Types of Binding:

Binding Time: When the binding happens

  1. Dynamic Binding: If the binding happens while the program is running.
  2. Static Binding: If the binding happens outside program execution.

More on Static Binding: Two types

  1. Compiler does it
  2. Lexer does it.

Note: This has nothing to do with the static keyword in Java.

Memory Binding (Memory Allocation)

Static Allocation: Allocation happens before execution (typically the compiler)

Process Memory Heap:

TODO plantuml

Refresher: Frames store the local variables and parameters of a function call.

Dynamic Allocation: Allocation happens during execution.

Example: Static and dynamic allocation in C.
// Statically allocate n=3
x = int[3];

// Dynamically allocate n=3
y = malloc(sizeof(int) * 3);

In dynamic languages (e.g., Python, Ruby, Perl), all arrays are dynamic, because there is no static allocation in an interpreted language.

Type Checking

Typing: Assigning a type to every symbol in a program, and checking the type assignment makes sense.

Static Typing

Static Typing: Happens before execution, typically during compilation

Example: Explicit and implicit typing in Rust
// 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.

Dynamic Typing

Dynamic Typing: Happens during execution

Strict Typing: When the type is allowed to change.

Example: Strict typing

Suppose:

x := 42
// ...
x := "Apple"

If this is disallowed, the typing is said to be strict.

Scope Binding

Scope: The region of a program where a symbol is visible.

Remember: This is about visibility, not permanence!

Example: Scope

Typical example:

fn f() {
  let x = 42;
}

fn g() {
  let y = 42;
}

Wacky example:

// We can statically define variables in c
f() {
  static x = 0;
  x++;
}

Static Scoping (Lexical Scoping)

Scoping happens while writing the program.

Dynamic Scoping

Whatever is in the stack exists everywhere.

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
}

For most dynamic languages, this is an optional thing you have to turn on.