0% found this document useful (0 votes)
4 views31 pages

Uploads Seng206 Week3

The document discusses the concept of programming languages, focusing on the Chomsky Hierarchy, which categorizes languages based on complexity into four types. It also explains Backus-Naur Form (BNF) used for defining programming languages, along with examples of recursive functions and binary trees, including their components and traversal methods. Additionally, it provides examples of BNF for various programming constructs and challenges the reader to implement an inorder tree search algorithm.

Uploaded by

gbw2vqttv9
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)
4 views31 pages

Uploads Seng206 Week3

The document discusses the concept of programming languages, focusing on the Chomsky Hierarchy, which categorizes languages based on complexity into four types. It also explains Backus-Naur Form (BNF) used for defining programming languages, along with examples of recursive functions and binary trees, including their components and traversal methods. Additionally, it provides examples of BNF for various programming constructs and challenges the reader to implement an inorder tree search algorithm.

Uploaded by

gbw2vqttv9
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
You are on page 1/ 31

Concept of Programmin Languages

(SENG206)

Dr. Yenal ARSLAN

@yenalarslan1
https://www.linkedin.com/in/yenalarslan
[email protected]
Chomsky Hierarchy

The Chomsky Hierarchy, developed by linguist


Noam Chomsky, is a system used to categorize
languages based on their complexity. It classifies
languages into four groups:

Noam Chomsky (1928)


Chomsky Hierarchy
Type 0 - Unrestricted Grammars: This group includes languages with no
limitations. Any grammar rule can be used.

Type 1 - Context-Free Grammars: In this group, each rule defines how a


symbol can be replaced with other symbols, regardless of the surrounding
symbols. The order of the rules doesn't matter.

Type 2 - Context-Sensitive Grammars: Here, each rule defines how a symbol


can be replaced with other symbols, but the order of the rules becomes
important.

Type 3 - Regular Grammars: In this group, each rule defines how a symbol
can be replaced with other symbols, but the rules are very simple and can
only involve a finite number of symbols.
Chomsky Hierarchy

A homework suggestion: A student can explain the Chomsky


hierarchy in detail, giving examples
BNF- Backus Naur Form
Backus-Naur Form (BNF) is widely used to define
programming languages. Many popular
languages like C, Java, and Python are defined
using BNF.

BNF is a notation system used to define


languages. It consists of symbols and production
rules that describe all possible syntactic
structures within a language. BNF is a powerful
tool for formally defining languages and is used John Backus (1924-2007)
by programming language tools like compilers
and interpreters.
BNF- Backus Naur Form

It's named after John Backus and


Peter Naur, who introduced it in the
1960s. BNF provides a formal way to
express grammatical structures,
making it easier to understand and
implement the rules of a language.

Peter Naur (1928-2016)


Basic Concepts of BNF
Symbols: There are two types of symbols in BNF:

Non-terminal symbols: Represented within angle


brackets (e.g., <expression>), these symbols can be
expanded into one or more sequences of non-terminal and
terminal symbols.

Terminal symbols: Represented as themselves or within


quotes (e.g., +, "while"), these are the basic elements that
cannot be further expanded. They often correspond to
literal strings or characters in the language.
Basic Concepts of BNF
Production Rules: A BNF specification consists of a series
of production rules. Each rule expresses how a non-
terminal symbol can be expanded into a sequence of
terminal and/or non-terminal symbols. The symbol on the
left side of the rule is the symbol being defined, and the
sequence on the right side is what it can be replaced with in
the language.

Choices: The pipe symbol (|) is used to separate


alternatives in a rule, indicating that any one of the
alternatives may be used.
Example of BNF:
To define a simple arithmetic expression language (may be an exam question)

<expression> ::= <term> | <expression> "+" <term> | <expression> "-"


<term>
<term> ::= <factor> | <term> "*" <factor> | <term> "/" <factor>
<factor> ::= <number> | "(" <expression> ")"
<number> ::= <digit> | <number> <digit>
<digit> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9«

An <expression> can be a <term>, or an <expression> followed by a plus or minus sign and another
<term>.
A <term> can be a <factor>, or a <term> followed by a multiplication or division sign and another
<factor>.
A <factor> can be a <number>, or an <expression> enclosed in parentheses.
A <number> consists of one or more <digit>s.
Recursive
The term "recursive" in programming refers to the
technique where a function calls itself directly or indirectly
to solve a problem. Recursive functions break down a
problem into smaller, more manageable sub-problems,
each of which is solved by a call to the same function.

Recursion is a fundamental concept in computer science,


used in sorting algorithms (like quicksort and mergesort),
navigating data structures (like trees and graphs), and
many other applications where a problem can naturally be
divided into similar sub-problems.
Recursive
Factorial Function in Python:

def factorial(n):
# Base case: factorial of 0 or 1 is 1
if n == 0 or n == 1:
return 1
# Recursive case: n! = n * (n-1)!
else:
return n * factorial(n-1)

# Example usage
print(factorial(5)) # Output: 120
Recursive
Factorial Function in C#:
using System;

class Program
{
// Recursive Function to calculate Factorial of a number
static int Factorial(int n)
{
// Base case
if (n == 0)
{
return 1;
}

// Recursive case
return n * Factorial(n - 1);
}

// Driver Code
static void Main()
{
int n = 4;

Console.WriteLine("Factorial of " + n + " is: " + Factorial(n));


}
}
Recursive
Fibonacci Sequence in JavaScript:

function fibonacci(n) {
// Base cases
if (n === 0) return 0;
if (n === 1) return 1;
// Recursive case
return fibonacci(n-1) + fibonacci(n-2);
}

// Example usage
console.log(fibonacci(10)); // Output: 55
Example of BNF:

Write down a BNF that describes an email address format.


Example of BNF:
Recursive

<email> ::= <local-part> "@" <domain>


<local-part> ::= <alpha> | <local-part> <alpha> | <local-part> "."
<domain> ::= <subdomain> "." <tld>
<subdomain> ::= <alpha> | <subdomain> <alpha> | <subdomain> <digit>
<tld> ::= "com" | "org" | "net" | "edu"
<alpha> ::= "a" | "b" | "c" | ... | "z" | "A" | "B" | "C" | ... | "Z"
<digit> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
Example of BNF:

Write down simple programming language BNF to include


if-else statements, while loops, and simple arithmetic
operations within expressions
Example of BNF:
<program> ::= <statement> | <program> <statement>

<statement> ::= <var-declaration> | <assignment> | <print-statement> | <if-statement> | <while-statement>

<var-declaration> ::= "var" <identifier> ";"

<assignment> ::= <identifier> "=" <expression> ";"

<print-statement> ::= "print" "(" <expression> ")" ";"

<if-statement> ::= "if" "(" <condition> ")" "{" <program> "}" | "if" "(" <condition> ")" "{" <program> "}" "else" "{" <program> "}"

<while-statement> ::= "while" "(" <condition> ")" "{" <program> "}"

<expression> ::= <term> | <expression> "+" <term> | <expression> "-" <term>

<term> ::= <factor> | <term> "*" <factor> | <term> "/" <factor>

<factor> ::= <number> | <identifier> | "(" <expression> ")"

<condition> ::= <expression> "<" <expression> | <expression> ">" <expression> | <expression> "==" <expression>

<identifier> ::= <alpha> | <identifier> <alpha> | <identifier> <digit>

<number> ::= <digit> | <number> <digit>

<alpha> ::= "a" | "b" | "c" | ... | "z" | "A" | "B" | "C" | ... | "Z"

<digit> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
Example of BNF:
Variable Declarations (<var-declaration>): Starting with the keyword "var", followed by an identifier, and
terminated with a semicolon.

Assignments (<assignment>): Specifying a variable name, an equals sign, an expression representing the
new value, and ending with a semicolon.

Print Statements (<print-statement>): Outputting the value of an expression.

If Statements (<if-statement>): Conditional execution based on the evaluation of a condition. An optional else
branch can execute an alternative program.

While Statements (<while-statement>): Repeatedly executing a program as long as a condition evaluates to


true.

Expressions (<expression>, <term>, <factor>): Allowing arithmetic operations within expressions. Terms and
factors break down the expression into parts that can be evaluated according to the rules of arithmetic
precedence.

Conditions (<condition>): Comparing two expressions using less than, greater than, or equals operators.
Binary Trees

Binary trees are a fundamental data structure in computer


science, used in various applications such as sorting
algorithms, search algorithms, and making hierarchical
decisions. A binary tree is a tree data structure in which
each node has at most two children, referred to as the left
child and the right child.
Binary Tree Components
Node: The basic unit of a binary tree, containing data and
references to the left and right children.
Root: The topmost node of the tree, from which all other
nodes descend.
Left Child: The node referenced as the left child of a
parent node.
Right Child: The node referenced as the right child of a
parent node.
Leaf: A node with no children.
Depth: The number of edges from the root to the node.
Binary Tree Types
Full Binary Tree: Every node other than the leaves has
two children.
Complete Binary Tree: All levels are fully filled except
possibly the last level, which is filled from left to right.
Balanced Binary Tree: The height of the two subtrees of
any node differ by no more than one.
Binary Search Tree (BST): A special kind of binary tree
where the left child of a node contains only nodes with
values less than the parent node, and the right child only
contains nodes with values greater than or equal to the
parent.
Tree traversal
Tree traversal is the process of visiting each node
in the tree exactly once in some order. There are
three common depth-first search (DFS) traversal
strategies: preorder, inorder, and postorder.

Preorder Traversal (Root, Left, Right):


Visit the root.
Traverse the left subtree in preorder.
Traverse the right subtree in preorder.
Preorder Traversal: A, B, D, C, E, F

Preorder traversal is used to create a copy of the


tree or to print a structured representation of the
tree.
Tree traversal
Inorder Traversal (Left, Root, Right):
Traverse the left subtree in inorder.
Visit the root.
Traverse the right subtree in inorder.

Inorder traversal is mainly used in binary


search trees because it returns values in
non-decreasing order.

Inorder Traversal: D, B, A, E, C, F
Tree traversal
Postorder Traversal (Left, Right, Root):

Traverse the left subtree in postorder.


Traverse the right subtree in postorder.
Visit the root.

Postorder traversal is useful for deleting


the tree or evaluating postfix expression
trees.
Postorder Traversal: D, B, E, F, C, A
Tree traversal

Examine with Inorder Traversal Method


(Like an exam question)
Tree traversal
1. Go to the leftmost node of the tree (1) and visit it.
2. Go back to its parent (2) and visit it.
3. Proceed to the parent of 2, which is 3, but before
visiting 3, visit its right subtree (4).
4. After visiting 4, visit 3 (the root of this subtree).
5. Go back to the root of the entire tree (5) and visit
it.
6. Move to the right subtree, visiting the left child of 7
if it exists (it doesn't in this case), then visit 7.
7. Finally, visit the right child of 7, which is 8.

Inorder Traversal Result: 1, 2, 3, 4, 5, 7, 8


Tree traversal

Examine with Inorder Traversal Method


1. Start with the leftmost node (2) in the left
subtree and visit it.
2. Move up to its parent (3) and visit it.
3. Visit the right child of 3, which is 5.
4. Visit the root of the tree (6).
5. Move to the left child of 8, which is 7,
and visit it.
6. Visit 8 (the root of the right subtree).
7. Visit the right child of 8, which is 9.

Inorder Traversal Result: 2, 3, 5, 6, 7, 8, 9


Tree traversal

Examine with Postorder Traversal


Method
Tree traversal
To perform a postorder traversal on this tree, we follow the Left, Right,
Root order recursively:

1. Start with the left subtree of the root (1), which is the subtree rooted
at 2.
2. Go to the left subtree of 2, which is the subtree rooted at 4.
3. Visit 8 (left of 4), which is a leaf node. So, visit it first.
4. Then, visit 9 (right of 4), another leaf node.
5. Having visited both children of 4, now visit 4 itself.
6. With the left subtree of 2 processed, move to the right subtree of 2,
which is 5, a leaf node. Visit 5.
7. Having visited both children of 2 (the subtrees rooted at 4 and 5), now
visit 2.
8. With the entire left subtree of the root processed, move to the right
subtree of the root (1), which is the subtree rooted at 3.
9. Visit 6 (left of 3), a leaf node, so visit it.
10. Then, visit 7 (right of 3), another leaf node.
Postorder Traversal: 8, 9, 4, 5, 2, 6, 7, 3, 1.
11. Having visited both children of 3, now visit 3 itself.
12. Having visited both the left and right subtrees of the root, finally visit
the root node, 1.
Challenge

What if I say write an inorder tree search algorithm using


the recursive method in python? Think about it

You might also like