Presentation is loading. Please wait.

Presentation is loading. Please wait.

Case Study: A Recursive Descent Interpreter Implementation in C++ (Source Code Courtesy of Dr. Adam Drozdek) Payap University ICS220 - Data Structures.

Similar presentations


Presentation on theme: "Case Study: A Recursive Descent Interpreter Implementation in C++ (Source Code Courtesy of Dr. Adam Drozdek) Payap University ICS220 - Data Structures."— Presentation transcript:

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.


Download ppt "Case Study: A Recursive Descent Interpreter Implementation in C++ (Source Code Courtesy of Dr. Adam Drozdek) Payap University ICS220 - Data Structures."

Similar presentations


Ads by Google