Download presentation
Presentation is loading. Please wait.
Published byDestiny Cornett Modified over 10 years ago
1
Case Study: A Recursive Descent Interpreter Implementation in C++ (Source Code Courtesy of Dr. Adam Drozdek) Payap University ICS220 - Data Structures and Algorithm Analysis Instructor: Dr. Ken Cosh Analysis and Presentation by Rob Agle
2
First, let’s clear up some terminology…
3
Interpreter Examples of “Interpreted” Languages
In general, a compiler is a program that converts an entire program from high level source code into some lower level representation (assembly or machine code for example). An interpreter on the other hand, traditionally translates high level instructions and executes them on the fly (at runtime). The lines between these two concepts are blurring however… Examples of “Interpreted” Languages Python Ruby Pearl Smalltalk JavaScript Java
4
Interpreter For our purposes – we can simply say that our interpreter will be used to translate and execute one instruction statement at a time.
5
Interpreter For our purposes – we can simply say that our interpreter will be used to translate and execute one instruction statement at a time.
6
Interpreter For our purposes – we can simply say that our interpreter will be used to translate and execute one instruction statement at a time.
7
Interpreter Things our interpreter understands:
Variable Names: Any alphanumeric string Operators: + - / * = Commands: Print, Status, End
8
Recursive Descent A process that allows us to descend – or “go down” to lower and lower levels of complexity via recursion, and then work “backwards” towards a solution once all the pieces are in place.
9
Recursive Descent A process that allows us to descend – or “go down” to lower and lower levels of complexity via recursion, and then work “backwards” towards a solution once all the pieces are in place.
10
Recursive Descent For Example: var = 2*(3+5);
11
Recursive Descent For Example: var = 2*(3+5);
12
Recursive Descent For Example:
The statement: var = 2*(3+5); can be parsed and broken down into its individual pieces using recursion.
13
Recursive Descent For Example:
The statement: var = 2*(3+5); can be parsed and broken down into its individual pieces using recursion.
14
Recursive Descent var = 2*(3+5);
Don’t worry about how, just imagine we magically use some combination of direct and indirect recursion to break down the above statement into the following…
15
Recursive Descent var = 2*(3+5);
Don’t worry about how, just imagine we magically use some combination of direct and indirect recursion to break down the above statement into the following…
16
var = 2 * ( ) ;
17
var = 2 * ( ) ; ID
18
var = 2 * ( ) ; ID Operator Operator Operator
19
var = 2 * ( 3 + 5 ) ; ID Factor Factor Factor Operator Operator
20
var = 2 * ( 3 + 5 ) ; ID Term Term Factor Factor Factor Operator
21
var = 2 * ( 3 + 5 ) ; ID Expression Expression Term Term Factor Factor
Operator Operator Operator
22
var = 2 * ( 3 + 5 ) ; ID Expression Expression Term Term Factor Factor
Operator Operator Operator
23
What do we need (object wise) to accomplish this?
Data: a list of all ID’s (variables) An array of characters to store an input statement Functionality: A way to get the input statement from the user A way to parse the input, get values for expressions (if any) and its composite parts (terms, factors – if any) and perform indicated operations. A few “black boxes”…
24
Data
25
What do we need (object wise) to accomplish this?
Data: a list of all ID’s (variables) An array of characters to store an input statement Functionality: A way to get the input statement from the user A way to parse the input, get values for expressions (if any) and its composite parts (terms, factors – if any) and perform indicated operations. A few “black boxes”…
26
Functionality
27
So – let’s go back to our concrete example and trace the program…
28
Trace: Input -> var = 2*(3+5);
29
Trace: Input -> var = 2*(3+5);
30
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch =
31
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = Runtime Stack getStatement() e = id = command =
32
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = var Runtime Stack getStatement() e = id = command = var VAR
33
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = = var Runtime Stack R expression() getStatement() e = id = command = ? var VAR
34
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = = Runtime Stack R term() R expression() t = ? getStatement() e = id = command = ? var VAR
35
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = = Runtime Stack R factor() R term() f = ? R expression() t = ? getStatement() e = id = command = ? var VAR
36
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = = Runtime Stack R factor() var = 1.0 minus = 1.0 id = R term() f = ? R expression() t = ? getStatement() e = id = command = ? var VAR
37
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = 2 = Runtime Stack R factor() var = 1.0 minus = 1.0 id = R term() f = ? R expression() t = ? getStatement() e = id = command = ? var VAR
38
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = 2 Runtime Stack R factor() var = 1.0 minus = 1.0 id = R term() f = ? R expression() t = ? getStatement() e = id = command = ? var VAR
39
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = 2 Runtime Stack R factor() var = 1.0 minus = 1.0 id = R term() f = ? R expression() t = ? getStatement() e = id = command = ? var VAR
40
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = 2 * Runtime Stack R factor() var = 1.0 2.0 minus = 1.0 id = R term() f = ? R expression() t = ? getStatement() e = id = command = ? var VAR
41
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = * Runtime Stack R factor() var = 2.0 minus = 1.0 id = R term() f = 2 ? R expression() t = ? getStatement() e = id = command = ? var VAR
42
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = * Runtime Stack R factor() R term() f = 2 * ? R expression() t = ? getStatement() e = id = command = ? var VAR
43
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = * Runtime Stack R factor() var = 1.0 minus = 1.0 id = R term() f = 2 * ? R expression() t = ? getStatement() e = id = command = ? var VAR
44
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = * ( Runtime Stack R factor() var = 1.0 minus = 1.0 id = R term() f = 2 * ? R expression() t = ? getStatement() e = id = command = ? var VAR
45
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = ( Runtime Stack R factor() var = 1.0 minus = 1.0 id = R term() f = 2 * ? R expression() t = ? getStatement() e = id = command = ? var VAR
46
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = ( R expression() Runtime Stack R factor() var = ? 1.0 minus = 1.0 id = R term() f = 2 * ? R expression() t = ? getStatement() e = id = command = ? var VAR
47
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = ( R expression() Runtime Stack R factor() var = ? Here, we have our first recursive function call… minus = 1.0 id = R term() f = 2 * ? R expression() t = ? getStatement() e = id = command = ? var VAR
48
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = ( R expression() Runtime Stack R factor() var = ? This conveniently allows us to naturally follow mathematical precedence … minus = 1.0 id = R term() f = 2 * ? R expression() t = ? getStatement() e = id = command = ? var VAR
49
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = ( R term() R expression() Runtime Stack R factor() var = ? A series of additional indirect recursive calls will determine the value of (3+5)… minus = 1.0 id = R term() f = 2 * ? R expression() t = ? getStatement() e = id = command = ? var VAR
50
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = R factor() ( R term() R expression() Runtime Stack R factor() var = ? A series of additional indirect recursive calls will determine the value of (3+5)… minus = 1.0 id = R term() f = 2 * ? R expression() t = ? getStatement() e = id = command = ? var VAR
51
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = R factor() ( 3 R term() R expression() Runtime Stack R factor() var = ? A series of additional indirect recursive calls will determine the value of (3+5)… minus = 1.0 id = R term() f = 2 * ? R expression() t = ? getStatement() e = id = command = ? var VAR
52
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = R factor() 3 + R term() R expression() Runtime Stack R factor() var = ? A series of additional indirect recursive calls will determine the value of (3+5)… minus = 1.0 id = R term() f = 2 * ? R expression() t = ? getStatement() e = id = command = ? var VAR
53
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = + R expression() Runtime Stack R factor() var = ? minus = 1.0 id = R term() f = 2 * ? R expression() t = ? getStatement() e = id = command = ? var VAR
54
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = + ) R expression() Runtime Stack R factor() var = ? 8 minus = 1.0 id = R term() f = 2 * ? We now see the same chain of recursive calls to term and factor… Which eventually sets t = 8 in expression(). This value will be returned to factor… R expression() t = ? getStatement() e = id = command = ? var VAR
55
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = ; ) Runtime Stack R factor() factor() can now return 8 to term() var = 8 minus = 1.0 id = R term() f = 2 * ? * 8 R expression() t = ? getStatement() e = id = command = ? var VAR
56
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = ; Runtime Stack factor() can now return 8 to term() term() can return 2*8 =16 to expression() R term() f = 2 * 8 R expression() t = ? 16 getStatement() e = id = command = ? var VAR
57
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = ; Runtime Stack factor() can now return 8 to term() term() can return 2*8 =16 to expression() expression() also returns 16 to getStatement… R expression() t = 16 getStatement() e = id = command = ? 16 var VAR
58
Trace: Input -> var = 2*(3+5);
statement.idList = Statement.ch = var => 16 ; Runtime Stack getStatement() e = id = command = 16 var VAR
59
Control is returned to the main function, where once again getStatement will be called…
60
Final Thoughts For the sake of time – a lot of the non-recursive functions were overlooked and treated as black boxes. Tracing your own input through the functions carefully will leave you with a solid understanding of recursion. Recursive descent was once a popular way to build a parser. These days more complex parsers can be built by parser generators. For more information (and a solid headache), google: LR parsers.
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.