0% found this document useful (0 votes)
26 views97 pages

Programming Language Syntax Principles

The document discusses the principles of programming languages, focusing on abstract syntax, lexical analysis, and parsing. It outlines the components of programming languages, including alphabets, tokens, and grammars, and provides examples of valid sentences and lexical rules. Additionally, it introduces concepts like parse trees, abstract syntax trees, and Backus-Naur Form (BNF) for defining language syntax.

Uploaded by

Tudor Romaniuc
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
26 views97 pages

Programming Language Syntax Principles

The document discusses the principles of programming languages, focusing on abstract syntax, lexical analysis, and parsing. It outlines the components of programming languages, including alphabets, tokens, and grammars, and provides examples of valid sentences and lexical rules. Additionally, it introduces concepts like parse trees, abstract syntax trees, and Backus-Naur Form (BNF) for defining language syntax.

Uploaded by

Tudor Romaniuc
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

Principles of Programming Languages

Abstract Syntax

Andrei Arusoaie1
1 Department of Computer Science
Outline

Alphabet. Lexical analysis. Parsing.

Parse Trees

Abstract syntax trees

Abstract syntax in Lean

IMP Language Demo


Sentences in a programming language

Which phrases are correct?

▶ int x; x = x + 2
▶ int x; x = x + 2;
▶ if (a > 0) then x = 1; else x = -1;
▶ (a > 0) ? x = 1 : x = -1;
Sentences in a programming language

Which phrases are correct?

▶ int x; x = x + 2
▶ int x; x = x + 2;
▶ if (a > 0) then x = 1; else x = -1;
▶ (a > 0) ? x = 1 : x = -1;
Sentences in a programming language

Which phrases are correct?

▶ int x; x = x + 2
▶ int x; x = x + 2;
▶ if (a > 0) then x = 1; else x = -1;
▶ (a > 0) ? x = 1 : x = -1;
Overview: alphabet, lexical analysis, syntax

▶ Alphabet: set of (allowed) symbols


▶ Lexical analysis: identify the sequence of symbols
constituting the words (or tokens)
▶ Lexical rules
▶ Syntax: describes which sequences of words constitute
“legal” phrases
▶ Grammars
Overview: alphabet, lexical analysis, syntax

▶ Alphabet: set of (allowed) symbols


▶ Lexical analysis: identify the sequence of symbols
constituting the words (or tokens)
▶ Lexical rules
▶ Syntax: describes which sequences of words constitute
“legal” phrases
▶ Grammars
Overview: alphabet, lexical analysis, syntax

▶ Alphabet: set of (allowed) symbols


▶ Lexical analysis: identify the sequence of symbols
constituting the words (or tokens)
▶ Lexical rules
▶ Syntax: describes which sequences of words constitute
“legal” phrases
▶ Grammars
Alphabet

The Alphabet of C from the Standard has 96 symbols:


▶ a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,
u,v,w,x,z
▶ A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,
U,V,W,X,Y,Z
▶ 0,1,2,3,4,5,6,7,8,9
▶ ! " # % & ’ ( ) * + , - . /
▶ : ; < = > ? [ \ ] ^ _ { | } ~
▶ Separators: space, horizontal and vertical tab, form feed,
newline
Lexical analysis

Problem: Given a sequence of characters, find the pieces with


assigned meaning from that sequence: words or tokens

Example:
▶ Input: if (a > 0) then x = 1; else x = -1;
▶ Output: if, (, a, >, 0,), then, x, =, 1,;, else, x, =, -1,;
▶ Tokens = pieces with assigned/identified meaning
Lexical analyzer (lexer) = a program that implements an
algorithm that solves the problem above
Lexical analysis

Problem: Given a sequence of characters, find the pieces with


assigned meaning from that sequence: words or tokens

Example:
▶ Input: if (a > 0) then x = 1; else x = -1;
▶ Output: if, (, a, >, 0,), then, x, =, 1,;, else, x, =, -1,;
▶ Tokens = pieces with assigned/identified meaning
Lexical analyzer (lexer) = a program that implements an
algorithm that solves the problem above
Lexical analysis

Problem: Given a sequence of characters, find the pieces with


assigned meaning from that sequence: words or tokens

Example:
▶ Input: if (a > 0) then x = 1; else x = -1;
▶ Output: if, (, a, >, 0,), then, x, =, 1,;, else, x, =, -1,;
▶ Tokens = pieces with assigned/identified meaning
Lexical analyzer (lexer) = a program that implements an
algorithm that solves the problem above
Lexical analysis

Problem: Given a sequence of characters, find the pieces with


assigned meaning from that sequence: words or tokens

Example:
▶ Input: if (a > 0) then x = 1; else x = -1;
▶ Output: if, (, a, >, 0,), then, x, =, 1,;, else, x, =, -1,;
▶ Tokens = pieces with assigned/identified meaning
Lexical analyzer (lexer) = a program that implements an
algorithm that solves the problem above
Example I - Lexical rules

▶ Integers: 6, 0, −2, +3
▶ The alphabet A = {+, −} ∪ N
▶ Lexical rules: used to describe atomic language
constructions: numbers, identifiers, . . .
▶ Lexical rules are expressed using regular grammars (see
Formal Languages, Compilers and Automata course)
▶ Regular expressions, a.k.a regex
▶ Regex for integers: [\+-]?\d+
Example I - Lexical rules

▶ Integers: 6, 0, −2, +3
▶ The alphabet A = {+, −} ∪ N
▶ Lexical rules: used to describe atomic language
constructions: numbers, identifiers, . . .
▶ Lexical rules are expressed using regular grammars (see
Formal Languages, Compilers and Automata course)
▶ Regular expressions, a.k.a regex
▶ Regex for integers: [\+-]?\d+
Example I - Lexical rules

▶ Integers: 6, 0, −2, +3
▶ The alphabet A = {+, −} ∪ N
▶ Lexical rules: used to describe atomic language
constructions: numbers, identifiers, . . .
▶ Lexical rules are expressed using regular grammars (see
Formal Languages, Compilers and Automata course)
▶ Regular expressions, a.k.a regex
▶ Regex for integers: [\+-]?\d+
Example I - Lexical rules

▶ Integers: 6, 0, −2, +3
▶ The alphabet A = {+, −} ∪ N
▶ Lexical rules: used to describe atomic language
constructions: numbers, identifiers, . . .
▶ Lexical rules are expressed using regular grammars (see
Formal Languages, Compilers and Automata course)
▶ Regular expressions, a.k.a regex
▶ Regex for integers: [\+-]?\d+
Example I - Lexical rules

▶ Integers: 6, 0, −2, +3
▶ The alphabet A = {+, −} ∪ N
▶ Lexical rules: used to describe atomic language
constructions: numbers, identifiers, . . .
▶ Lexical rules are expressed using regular grammars (see
Formal Languages, Compilers and Automata course)
▶ Regular expressions, a.k.a regex
▶ Regex for integers: [\+-]?\d+
Parsing

Problem: how to combine the tokens in (valid) sentences?


▶ Answer: we define the grammar of the language
▶ Noam Chomsky: generative grammar
▶ Grammars allow us to transform a program given as a
sequence of characters into a syntax tree
▶ Parser = program which attempts to do this transformation
▶ Only valid programs can be parsed!
Parsing

Problem: how to combine the tokens in (valid) sentences?


▶ Answer: we define the grammar of the language
▶ Noam Chomsky: generative grammar
▶ Grammars allow us to transform a program given as a
sequence of characters into a syntax tree
▶ Parser = program which attempts to do this transformation
▶ Only valid programs can be parsed!
Parsing

Problem: how to combine the tokens in (valid) sentences?


▶ Answer: we define the grammar of the language
▶ Noam Chomsky: generative grammar
▶ Grammars allow us to transform a program given as a
sequence of characters into a syntax tree
▶ Parser = program which attempts to do this transformation
▶ Only valid programs can be parsed!
Parsing

Problem: how to combine the tokens in (valid) sentences?


▶ Answer: we define the grammar of the language
▶ Noam Chomsky: generative grammar
▶ Grammars allow us to transform a program given as a
sequence of characters into a syntax tree
▶ Parser = program which attempts to do this transformation
▶ Only valid programs can be parsed!
Parsing

Problem: how to combine the tokens in (valid) sentences?


▶ Answer: we define the grammar of the language
▶ Noam Chomsky: generative grammar
▶ Grammars allow us to transform a program given as a
sequence of characters into a syntax tree
▶ Parser = program which attempts to do this transformation
▶ Only valid programs can be parsed!
Example II - Grammar

▶ Language of palindromic strings using symbols a and b


▶ The alphabet A = {a, b}
▶ Can we describe palindromes using regex?
Example II - Grammar

▶ Language of palindromic strings using symbols a and b


▶ The alphabet A = {a, b}
▶ Can we describe palindromes using regex?
Example II - Grammar

▶ Language of palindromic strings using symbols a and b


▶ The alphabet A = {a, b}
▶ Can we describe palindromes using regex?
Example II - Grammar

▶ How do we “formally” describe palindromic strings?


▶ Note that there is a simple recursion in a palindromic string
▶ Base: a and b are palindromic strings
▶ Recursion: if s is a palindromic string then so are asa and
bsb
▶ Examples: “aba”, “aabaa”, “bab”, etc.
▶ Problem? Yes: “aa”, “abba”.
▶ Fix: add the empty string to base, hereafter denoted by ϵ
Example II - Grammar

▶ How do we “formally” describe palindromic strings?


▶ Note that there is a simple recursion in a palindromic string
▶ Base: a and b are palindromic strings
▶ Recursion: if s is a palindromic string then so are asa and
bsb
▶ Examples: “aba”, “aabaa”, “bab”, etc.
▶ Problem? Yes: “aa”, “abba”.
▶ Fix: add the empty string to base, hereafter denoted by ϵ
Example II - Grammar

▶ How do we “formally” describe palindromic strings?


▶ Note that there is a simple recursion in a palindromic string
▶ Base: a and b are palindromic strings
▶ Recursion: if s is a palindromic string then so are asa and
bsb
▶ Examples: “aba”, “aabaa”, “bab”, etc.
▶ Problem? Yes: “aa”, “abba”.
▶ Fix: add the empty string to base, hereafter denoted by ϵ
Example II - Grammar

▶ How do we “formally” describe palindromic strings?


▶ Note that there is a simple recursion in a palindromic string
▶ Base: a and b are palindromic strings
▶ Recursion: if s is a palindromic string then so are asa and
bsb
▶ Examples: “aba”, “aabaa”, “bab”, etc.
▶ Problem? Yes: “aa”, “abba”.
▶ Fix: add the empty string to base, hereafter denoted by ϵ
Example II - Grammar

▶ How do we “formally” describe palindromic strings?


▶ Note that there is a simple recursion in a palindromic string
▶ Base: a and b are palindromic strings
▶ Recursion: if s is a palindromic string then so are asa and
bsb
▶ Examples: “aba”, “aabaa”, “bab”, etc.
▶ Problem? Yes: “aa”, “abba”.
▶ Fix: add the empty string to base, hereafter denoted by ϵ
Example II - Grammar

▶ How do we “formally” describe palindromic strings?


▶ Note that there is a simple recursion in a palindromic string
▶ Base: a and b are palindromic strings
▶ Recursion: if s is a palindromic string then so are asa and
bsb
▶ Examples: “aba”, “aabaa”, “bab”, etc.
▶ Problem? Yes: “aa”, “abba”.
▶ Fix: add the empty string to base, hereafter denoted by ϵ
Example II - Grammar

▶ How do we “formally” describe palindromic strings?


▶ Note that there is a simple recursion in a palindromic string
▶ Base: a and b are palindromic strings
▶ Recursion: if s is a palindromic string then so are asa and
bsb
▶ Examples: “aba”, “aabaa”, “bab”, etc.
▶ Problem? Yes: “aa”, “abba”.
▶ Fix: add the empty string to base, hereafter denoted by ϵ
Example II - Grammar

▶ Base case:
▶ P→ϵ
▶ P→a
▶ P→b
▶ Recursion:
▶ P → aPa
▶ P → bPb
▶ Context-free grammar (you study this in your compiler
course!)
Example II - Grammar

▶ Base case:
▶ P→ϵ
▶ P→a
▶ P→b
▶ Recursion:
▶ P → aPa
▶ P → bPb
▶ Context-free grammar (you study this in your compiler
course!)
Example II - Grammar

▶ Base case:
▶ P→ϵ
▶ P→a
▶ P→b
▶ Recursion:
▶ P → aPa
▶ P → bPb
▶ Context-free grammar (you study this in your compiler
course!)
Example II - Grammar

▶ Base case:
▶ P→ϵ
▶ P→a
▶ P→b
▶ Recursion:
▶ P → aPa
▶ P → bPb
▶ Context-free grammar (you study this in your compiler
course!)
Example II - Grammar

▶ Base case:
▶ P→ϵ
▶ P→a
▶ P→b
▶ Recursion:
▶ P → aPa
▶ P → bPb
▶ Context-free grammar (you study this in your compiler
course!)
Example II - Grammar

▶ Base case:
▶ P→ϵ
▶ P→a
▶ P→b
▶ Recursion:
▶ P → aPa
▶ P → bPb
▶ Context-free grammar (you study this in your compiler
course!)
Example II - Grammar

▶ Base case:
▶ P→ϵ
▶ P→a
▶ P→b
▶ Recursion:
▶ P → aPa
▶ P → bPb
▶ Context-free grammar (you study this in your compiler
course!)
Example II - Grammar

▶ Base case:
▶ P→ϵ
▶ P→a
▶ P→b
▶ Recursion:
▶ P → aPa
▶ P → bPb
▶ Context-free grammar (you study this in your compiler
course!)
Backus-Naur Form (BNF)

▶ Meta-language introduced by Backus and Naur to define


ALGOL60
▶ Vocabulary:
▶ Terminals: simple language strings; typically: tokens or
symbols
▶ Non-terminals: complex language constructions
Backus-Naur Form (BNF)

▶ Meta-language introduced by Backus and Naur to define


ALGOL60
▶ Vocabulary:
▶ Terminals: simple language strings; typically: tokens or
symbols
▶ Non-terminals: complex language constructions
Backus-Naur Form (BNF)

▶ Meta-language introduced by Backus and Naur to define


ALGOL60
▶ Vocabulary:
▶ Terminals: simple language strings; typically: tokens or
symbols
▶ Non-terminals: complex language constructions
BNF - example I

▶ Palindromic strings:
P ::= ϵ (1)
| a (2)
| b (3)
| a P a (4)
| b P b (5)
Derivations

▶ How to obtain a derivation: read the production as rewrite


rules and find a finite sequence of rewrite steps

▶ Example: derivation for abba


P →4 aPa →5 abPba →1 abba
Parse trees

▶ Derivation: P →4 aPa →5 abPba →1 abba


▶ Parse tree:
▶ contains nodes labeled with terminals, nonterminals, and ϵ

P
/|\
/ | \
a P a
/|\
/ | \
b P b
|
|
e
Parse trees

▶ Derivation: P →4 aPa →5 abPba →1 abba


▶ Parse tree:
▶ contains nodes labeled with terminals, nonterminals, and ϵ

P
/|\
/ | \
a P a
/|\
/ | \
b P b
|
|
e
BNF - example II

▶ Simple expressions language:


Int ::= [\+-]?[0-9]+
Exp ::= Int
| Exp "+" Exp
| Exp "*" Exp
| Exp "/" Exp
| "(" Exp ")"
Multiple parses available

Possible parse trees for 2 + 4 + 6:


Exp Exp

Exp + Exp Exp + Exp

Int Exp + Exp Exp + Exp Int

2 Int Int Int Int 6

4 6 2 4
Multiple parses available

Possible parse trees for 2 + 4 + 6:


Exp Exp

Exp + Exp Exp + Exp

Int Exp + Exp Exp + Exp Int

2 Int Int Int Int 6

4 6 2 4
Ambiguities

Possible parse trees for 2 + 4 + 6:


Exp Exp
Exp + Exp Exp + Exp
Int Exp + Exp Exp + Exp Int
2 Int Int Int Int 6
4 6 2 4

▶ Solutions?
▶ Use the parentheses defined in the syntax: ‘(’ and ‘)’
▶ Encode some kind of associativity: left or right
Ambiguities

Possible parse trees for 2 + 4 + 6:


Exp Exp
Exp + Exp Exp + Exp
Int Exp + Exp Exp + Exp Int
2 Int Int Int Int 6
4 6 2 4

▶ Solutions?
▶ Use the parentheses defined in the syntax: ‘(’ and ‘)’
▶ Encode some kind of associativity: left or right
Ambiguities

Possible parse trees for 2 + 4 + 6:


Exp Exp
Exp + Exp Exp + Exp
Int Exp + Exp Exp + Exp Int
2 Int Int Int Int 6
4 6 2 4

▶ Solutions?
▶ Use the parentheses defined in the syntax: ‘(’ and ‘)’
▶ Encode some kind of associativity: left or right
Priorities

Possible parse trees for 4 / 2 + 6:


Exp Exp
Exp / Exp Exp + Exp
Int Exp + Exp Exp / Exp Int
4 Int Int Int Int 6
2 6 4 2

▶ Which parse tree is correct in this case?


Priorities

Possible parse trees for 4 / 2 + 6:


Exp Exp
Exp / Exp Exp + Exp
Int Exp + Exp Exp / Exp Int
4 Int Int Int Int 6
2 6 4 2

▶ Which parse tree is correct in this case?


Priorities

Possible parse trees for 4 / 2 + 6:


Exp Exp
Exp / Exp Exp + Exp
Int Exp + Exp Exp / Exp Int
4 Int Int Int Int 6
2 6 4 2

▶ Which parse tree is correct in this case?


Priorities

NO YES
Exp Exp
Exp / Exp Exp + Exp
Int Exp + Exp Exp / Exp Int
4 Int Int Int Int 6
2 6 4 2
Solutions:
▶ Establish priorities between various constructs
▶ Filtering vs. modifying the grammar
Abstract Syntax Trees

▶ Grammars define concrete syntax


▶ Arithmetic expressions:

▶ 1 + 2 – infix notation
▶ (+ 1 2) – prefix notation
▶ (1 2 +) – postfix notation
▶ Each variant has a particular grammar production:
▶ E → E + E // infix
▶ E → + E E // prefix
▶ E → E E + // postfix
Abstract Syntax Trees

▶ Grammars define concrete syntax


▶ Arithmetic expressions:

▶ 1 + 2 – infix notation
▶ (+ 1 2) – prefix notation
▶ (1 2 +) – postfix notation
▶ Each variant has a particular grammar production:
▶ E → E + E // infix
▶ E → + E E // prefix
▶ E → E E + // postfix
Abstract Syntax Trees

▶ Grammars define concrete syntax


▶ Arithmetic expressions:

▶ 1 + 2 – infix notation
▶ (+ 1 2) – prefix notation
▶ (1 2 +) – postfix notation
▶ Each variant has a particular grammar production:
▶ E → E + E // infix
▶ E → + E E // prefix
▶ E → E E + // postfix
Abstract syntax trees

▶ Variants:
▶ 1 + 2 – infix notation
▶ (+ 1 2) – prefix notation
▶ (1 2 +) – postfix notation
▶ Parse trees:

infix prefix postfix

E E E
/|\ /|\ /|\
/ | \ / | \ / | \
1 + 2 + 1 2 1 2 +
Abstract syntax trees

▶ Variants:
▶ 1 + 2 – infix notation
▶ (+ 1 2) – prefix notation
▶ (1 2 +) – postfix notation
▶ Parse trees:

infix prefix postfix

E E E
/|\ /|\ /|\
/ | \ / | \ / | \
1 + 2 + 1 2 1 2 +
Abstract syntax trees

▶ Parse trees:

infix prefix postfix

E E E
/|\ /|\ /|\
/ | \ / | \ / | \
1 + 2 + 1 2 1 2 +
▶ Abstract representation of all the above trees:

add
/ \
/ \
1 2
Abstract syntax trees

▶ Parse trees:

infix prefix postfix

E E E
/|\ /|\ /|\
/ | \ / | \ / | \
1 + 2 + 1 2 1 2 +
▶ Abstract representation of all the above trees:

add
/ \
/ \
1 2
Abstract Syntax Trees

▶ Grammars define concrete syntax


▶ An AST is a tree representation of the structure of a
program where syntactical details are abstracted away
▶ For instance, addition has the same abstract tree even if
the concrete syntax differs across languages (e.g., C vs.
Haskell)
▶ Compilers use ASTs as the main data structure
Example: arithmetic expressions

AST for 2 + (4 + 6):


plus inductive Exp where
| number : Nat → Exp
| plus : Exp → Exp → Exp

2 plus instance : Coe Nat Exp where


coe := [Link]

#check ([Link] 2 ([Link] 4 6))


4 6 -- [Link] 2 ([Link] 4 6) : Exp
Abstract Syntax in Lean

The BNF grammar of arithmetic expressions:

▶ E ::= nat | E + E | E * E
The corresponding Lean encoding is:
inductive Exp : Type where
| num : Nat → Exp
| plus : Exp → Exp → Exp
| mul : Exp → Exp → Exp
Abstract Syntax in Lean

The BNF grammar of arithmetic expressions:

▶ E ::= nat | E + E | E * E
The corresponding Lean encoding is:
inductive Exp : Type where
| num : Nat → Exp
| plus : Exp → Exp → Exp
| mul : Exp → Exp → Exp
Instances

Complicated:

#check ([Link] ([Link] 1) ([Link] 2))

open Exp
#check plus (num 1) (num 2)

Less complicated:

instance : OfNat Exp n where


ofNat := [Link] n

#check (plus 1 2)
Instances

Complicated:

#check ([Link] ([Link] 1) ([Link] 2))

open Exp
#check plus (num 1) (num 2)

Less complicated:

instance : OfNat Exp n where


ofNat := [Link] n

#check (plus 1 2)
Notations
inductive Exp : Type where
| num : Nat → Exp
| var : String -> Exp
| plus : Exp → Exp → Exp
| mul : Exp → Exp → Exp
open Exp

instance : OfNat Exp n where


ofNat := [Link] n
#check (plus 1 2)

instance : Coe String Exp where


coe := var

#check (plus "x" 2)

infixl:50 " +' " => plus


infixl:40 " *' " => mul

#check 1 +' "x"


IMP

Demo
▶ Arithmetic expressions
▶ Boolean expressions
▶ Statements
IMP: BNF Syntax
▶ Arithmetic Expressions:
AExp ::= n | v | AExp "+" AExp | AExp "*" AExp
...

▶ Boolean Expressions:
BExp ::= "true" | "false"
| AExp "<=" AExp
| "!" BExp
| BExp "&&" BExp
| BExp "||" BExp
▶ Statements:
Stmt ::= "skip"
| String ":=" AExp
| Stmt ";" Stmt
| "if" BExp "then" Stmt "else" Stmt
| "while" BExp "do" Stmt
IMP: BNF Syntax
▶ Arithmetic Expressions:
AExp ::= n | v | AExp "+" AExp | AExp "*" AExp
...

▶ Boolean Expressions:
BExp ::= "true" | "false"
| AExp "<=" AExp
| "!" BExp
| BExp "&&" BExp
| BExp "||" BExp
▶ Statements:
Stmt ::= "skip"
| String ":=" AExp
| Stmt ";" Stmt
| "if" BExp "then" Stmt "else" Stmt
| "while" BExp "do" Stmt
IMP: BNF Syntax
▶ Arithmetic Expressions:
AExp ::= n | v | AExp "+" AExp | AExp "*" AExp
...

▶ Boolean Expressions:
BExp ::= "true" | "false"
| AExp "<=" AExp
| "!" BExp
| BExp "&&" BExp
| BExp "||" BExp
▶ Statements:
Stmt ::= "skip"
| String ":=" AExp
| Stmt ";" Stmt
| "if" BExp "then" Stmt "else" Stmt
| "while" BExp "do" Stmt
IMP: Arithmetic Expressions

inductive AExp : Type where


| num : Nat → AExp
| var : String → AExp
| plus : AExp → AExp → AExp
| mul : AExp → AExp → AExp

open AExp
#check plus (num 3) (mul (var "x") (num 4))
-- (num 3).plus ((var "x").mul (num 4)) : AExp
Coercions

inductive AExp : Type where


| num : Nat → AExp
| var : String → AExp
| plus : AExp → AExp → AExp
| mul : AExp → AExp → AExp

open AExp
#check plus (num 3) (mul (var "x") (num 4))

instance : OfNat AExp n where


ofNat := num n
instance : Coe String AExp where
coe := var

#check plus 3 (mul "x" 4)


-- plus 3 ((var "x").mul 4) : AExp
Why Use Custom Notations?

Custom notations make code more readable and closer to


mathematical notation:

Without notation:
plus (plus (num 1) (num 2)) (num 3)

Notations:
infixl:65 " +' " => plus
infixl:65 " -' " => minus
infixl:70 " *' " => mul
infixl:70 " /' " => div

With notation:
1 +' 2 +' 3
Basic Infix Notation Syntax

Lean 4 provides three types of infix operators:


▶ infixl – left associative
▶ infixr – right associative
▶ infix – non-associative

General syntax:
infixl:precedence "operator" => function
Example: Arithmetic Expressions
inductive AExp : Type where
| num : Nat → AExp
| var : String → AExp
| plus : AExp → AExp → AExp
| mul : AExp → AExp → AExp
open AExp

instance : OfNat AExp n where


ofNat := num n
instance : Coe String AExp where
coe := var

infixl:65 " +' " => plus


infixl:65 " -' " => minus
infixl:70 " *' " => mul
infixl:70 " /' " => div

#check 1 +' 2 +' 3 -- plus (plus 1 2) : AExp → AExp


#check 2 *' 3 +' 4 -- plus (mul 2 3) : AExp → AExp
Precedence Levels

Higher numbers = tighter binding

▶ Multiplication at 70: binds tighter


▶ Addition at 65: binds looser

Example:
2 *' 3 +' 4
-- Parses as: (2 *' 3) +' 4
-- NOT as: 2 *' (3 +' 4)
Docs

Metaprogramming – declare and operate with syntax in Lean 4:


[Link]
lean4-metaprogramming-book/main/05_syntax.html
Associativity: Left vs Right

Left associative (infixl):


a +' b +' c -- means (a +' b) +' c

Right associative (infixr):


infixr:60 " ^' " => power

a ^' b ^' c -- means a ^' (b ^' c)

Non-associative (infix):
infix:50 " == " => equal

a == b == c -- ERROR: requires parentheses


Spaces in Notation

Spaces in the notation string matter!

-- Recommended: spaces around operator


infixl:65 " +' " => plus

-- Also works: no spaces


infixl:65 "+'" => plus

-- The spaces affect parsing!


1+' 2 -- works with no spaces
1 +' 2 -- works with spaces

Best practice: Include spaces for readability.


Prefix and Postfix Notations

Lean 4 also supports prefix and postfix notation:

Prefix:
prefix:75 "-' " => neg

#check -' x -- means (neg x)

Postfix:
postfix:80 "!" => factorial

#check n! -- means (factorial n)


More Complex Notations

For more complex syntax, use the notation command:

notation:65 a " + " b " + " c =>


plus (plus a b) c

notation:max "|" e "|" => abs e

notation "if" c "then" t "else" e =>


ite c t e

notation "let" x " := " v " in " body =>


(fun x => body) v
Summary

▶ Use infixl, infixr, or infix for operators


▶ Higher precedence numbers = tighter binding
▶ Choose precedence levels that match mathematical
intuition
▶ Include spaces in notation strings for clarity
▶ Use notation for complex syntax patterns
IMP: Boolean Expressions

inductive BExp : Type where


| btrue : BExp
| bfalse : BExp
| beq : AExp → AExp → BExp -- equality
| ble : AExp → AExp → BExp -- less or equal
| bnot : BExp → BExp -- negation
| band : BExp → BExp → BExp -- conjunction
| bor : BExp → BExp → BExp -- disjunction

open BExp

notation:70 a:70 " =' " b:71 => beq a b


notation:70 a:70 " <=' " b:71 => ble a b
prefix:75 "!' " => bnot
infixr:60 " &&' " => band
infixr:55 " ||' " => bor
IMP: Boolean Examples

-- Example: x = 5
#check "x" =' 5

-- Example: x <= y
#check "x" <=' "y"

-- Example: !(x = 0)
#check !' ("x" =' 0)

-- Example: (x <= 10) && (y = 5)


#check ("x" <=' 10) &&' ("y" =' 5)

-- Example: (x = 0) || (y > 0)
-- Note: y > 0 encoded as !(y <= 0)
#check ("x" =' 0) ||' (!' ("y" <=' 0))
IMP: Statements
inductive Stmt : Type where
| skip : Stmt
| assign : String → AExp → Stmt
| seq : Stmt → Stmt → Stmt
| ifthenelse : BExp → Stmt → Stmt → Stmt
| while : BExp → Stmt → Stmt

open Stmt

notation:2 var:2 " ::= " a:3 => assign var a


infixr:1 " ;; " => seq

▶ notation:2: the precedence of the entire notation


▶ var:2: minimum precedence for parsing var; accept operators
with precedence greater than 2 as part of var
▶ a:3: The minimum precedence for parsing a. Since 3 > 2, this
means a binds slightly tighter than var.
IMP: Statement Examples

-- Example: x := 5
#check "x" ::= 5

-- Example: x := x + 1
#check "x" ::= ("x" +' 1)

-- Example: x := 0 ;; y := 1
#check ("x" ::= 0) ;; ("y" ::= 1)

-- Example: if (x = 0) then y := 1 else y := 2


#check ifthenelse ("x" =' 0)
("y" ::= 1)
("y" ::= 2)
IMP: Program

The following program parses now in Lean:


def factorial : Stmt :=
("result" ::= 1) ;;
("counter" ::= "n") ;;
[Link] (!' ("counter" <=' 0)) (
("result" ::= ("result" *' "counter")) ;;
("counter" ::= ("counter" -' 1))
)

#check factorial
-- factorial : Stmt
Summary: IMP Language

▶ Arithmetic expressions: variables, numbers, operations


(+, -, *, /)
▶ Boolean expressions: comparisons (=, <=), logical
operations (¬, ∧, ∨)
▶ Statements:
▶ Assignment: x := e
▶ Sequence: s1 ;; s2
▶ Conditional: if b then s1 else s2
▶ Loop: while b do s
▶ All defined as inductive types in Lean
▶ Lean’s notation system makes code readable
▶ Will be used for defining semantics and proving properties!
Summary: IMP Language

▶ Arithmetic expressions: variables, numbers, operations


(+, -, *, /)
▶ Boolean expressions: comparisons (=, <=), logical
operations (¬, ∧, ∨)
▶ Statements:
▶ Assignment: x := e
▶ Sequence: s1 ;; s2
▶ Conditional: if b then s1 else s2
▶ Loop: while b do s
▶ All defined as inductive types in Lean
▶ Lean’s notation system makes code readable
▶ Will be used for defining semantics and proving properties!
Summary: IMP Language

▶ Arithmetic expressions: variables, numbers, operations


(+, -, *, /)
▶ Boolean expressions: comparisons (=, <=), logical
operations (¬, ∧, ∨)
▶ Statements:
▶ Assignment: x := e
▶ Sequence: s1 ;; s2
▶ Conditional: if b then s1 else s2
▶ Loop: while b do s
▶ All defined as inductive types in Lean
▶ Lean’s notation system makes code readable
▶ Will be used for defining semantics and proving properties!
Summary: IMP Language

▶ Arithmetic expressions: variables, numbers, operations


(+, -, *, /)
▶ Boolean expressions: comparisons (=, <=), logical
operations (¬, ∧, ∨)
▶ Statements:
▶ Assignment: x := e
▶ Sequence: s1 ;; s2
▶ Conditional: if b then s1 else s2
▶ Loop: while b do s
▶ All defined as inductive types in Lean
▶ Lean’s notation system makes code readable
▶ Will be used for defining semantics and proving properties!

You might also like