Case Study: A Recursive Descent Interpreter Implementation in C++ (Source Code Courtesy of Dr. Adam...

Post on 28-Mar-2015

222 views 4 download

Tags:

Transcript of Case Study: A Recursive Descent Interpreter Implementation in C++ (Source Code Courtesy of Dr. Adam...

Case Study:A Recursive Descent Interpreter

Implementation in C++(Source Code Courtesy of Dr. Adam Drozdek)

Payap UniversityICS220 - Data Structures and Algorithm AnalysisInstructor: Dr. Ken CoshAnalysis and Presentation by Rob Agle

First, let’s clear up some terminology…

Interpreter

Examples of “Interpreted” Languages

PythonPearl

JavaScript

RubySmalltalk

Java

• 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…

Interpreter

For our purposes – we can simply say that our interpreter will be used to translate and execute

one instruction statement at a time.

Interpreter

For our purposes – we can simply say that our interpreter will be used to translate and execute

one instruction statement at a time.

Interpreter

For our purposes – we can simply say that our interpreter will be used to translate and execute

one instruction statement at a time.

Interpreter

Things our interpreter understands:Variable Names: Any alphanumeric string

Operators: + - / * =Commands: Print, Status, End

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.

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.

Recursive Descent

For Example:

var = 2*(3+5);

Recursive Descent

For Example:

var = 2*(3+5);

Recursive Descent

For Example:The statement: var = 2*(3+5); can be parsed and broken

down into its individual pieces using recursion.

Recursive Descent

For Example:The statement: var = 2*(3+5); can be parsed and broken

down into its individual pieces using recursion.

Recursive Descentvar = 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…

Recursive Descentvar = 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…

var = 2 * ( 3 + 5 ) ;

var = 2 * ( 3 + 5 ) ;ID

var = 2 * ( 3 + 5 ) ;ID

Operator Operator Operator

var = 2 * ( 3 + 5 ) ;ID

Operator

Factor

Operator Operator

Factor Factor

var = 2 * ( 3 + 5 ) ;ID

Operator

Factor

Operator Operator

Factor Factor

Term Term

var = 2 * ( 3 + 5 ) ;ID

Operator

Factor

Operator Operator

Factor Factor

Term Term

Expression

Expression

var = 2 * ( 3 + 5 ) ;ID

Operator

Factor

Operator Operator

Factor Factor

Term Term

Expression

Expression

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”…

Data

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”…

What do we need (object wise) to accomplish this?

Functionality

So – let’s go back to our concrete example and trace the program…

Trace: Input -> var = 2*(3+5);

Trace: Input -> var = 2*(3+5);

Trace: Input -> var = 2*(3+5);

statement.idList =

Statement.ch =

Trace: Input -> var = 2*(3+5);

statement.idList =

Statement.ch =

Runti

me

Stac

ke =id =command =

getStatement()

Trace: Input -> var = 2*(3+5);

statement.idList =

Statement.ch =

Runti

me

Stac

ke =id =command =

getStatement()

varVAR

var

R expression()

Trace: Input -> var = 2*(3+5);

statement.idList =

Statement.ch =

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

=var

R expression()

Trace: Input -> var = 2*(3+5);

statement.idList =

Statement.ch =

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

=

t =

R term()

?

R expression()

Trace: Input -> var = 2*(3+5);

statement.idList =

Statement.ch =

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

=

t =

R term()

?

R factor()

f = ?

R expression()

Trace: Input -> var = 2*(3+5);

statement.idList =

Statement.ch =

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

=

t =

R term()

?

R factor()

f = ?

var = minus = id =

1.0 1.0

statement.idList =

Statement.ch = =2

R expression()

Trace: Input -> var = 2*(3+5);

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t =

R term()

?

R factor()

f = ?

var = minus = id =

1.0 1.0

2

R expression()

Trace: Input -> var = 2*(3+5);

statement.idList =

Statement.ch =

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t =

R term()

?

R factor()

f = ?

var = minus = id =

1.0 1.0

2

R expression()

Trace: Input -> var = 2*(3+5);

statement.idList =

Statement.ch =

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t =

R term()

?

R factor()

f = ?

var = minus = id =

1.0 1.0

*

statement.idList =

Statement.ch =

1.0 2.0

2

R expression()

Trace: Input -> var = 2*(3+5);

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t =

R term()

?

R factor()

f = ?

var = minus = id =

1.0

statement.idList =

Statement.ch =

2

2.0

*

R expression()

Trace: Input -> var = 2*(3+5);

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t =

R term()

?

R factor()

f = ?

var = minus = id =

1.0

statement.idList =

Statement.ch =

2

R expression()

Trace: Input -> var = 2*(3+5);

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t =

R term()

?

f =

*

R factor()

* ?

R expression()

Trace: Input -> var = 2*(3+5);

statement.idList =

Statement.ch =

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

*

t =

R term()

?

R factor()

f = 2

var = minus = id =

1.0 1.0

* ?

(

R expression()

Trace: Input -> var = 2*(3+5);

statement.idList =

Statement.ch =

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

*

t =

R term()

?

R factor()

f = 2

var = minus = id =

1.0 1.0

* ?

(

R expression()

Trace: Input -> var = 2*(3+5);

statement.idList =

Statement.ch =

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t =

R term()

?

R factor()

f = 2

var = minus = id =

1.0 1.0

* ?

?

R expression()

(

R expression()

Trace: Input -> var = 2*(3+5);

statement.idList =

Statement.ch =

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t =

R term()

?

R factor()

f = 2

var = minus = id =

1.0 1.0

* ?

?

R expression()

(

R expression()

Trace: Input -> var = 2*(3+5);

statement.idList =

Statement.ch =

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t =

R term()

?

R factor()

f = 2

var = minus = id =

1.0

* ?

Here, we have our first recursive function call…

?

R expression()

(

R expression()

Trace: Input -> var = 2*(3+5);

statement.idList =

Statement.ch =

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t =

R term()

?

R factor()

f = 2

var = minus = id =

1.0

* ?

This conveniently allows us to naturally follow mathematical

precedence …

?

R expression()

(

R expression()

Trace: Input -> var = 2*(3+5);

statement.idList =

Statement.ch =

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t =

R term()

?

R factor()

f = 2

var = minus = id =

1.0

* ?

A series of additional indirect recursive

calls will determine the value of (3+5)…

R term()

?

R expression()

(

R expression()

Trace: Input -> var = 2*(3+5);

statement.idList =

Statement.ch =

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t =

R term()

?

R factor()

f = 2

var = minus = id =

1.0

* ?

A series of additional indirect recursive

calls will determine the value of (3+5)…

R term()R factor()

3

statement.idList =

Statement.ch =

?

R expression()

(

R expression()

Trace: Input -> var = 2*(3+5);

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t =

R term()

?

R factor()

f = 2

var = minus = id =

1.0

* ?

A series of additional indirect recursive

calls will determine the value of (3+5)…

R term()R factor()

R factor()+

statement.idList =

Statement.ch = 3

?

R expression()

R expression()

Trace: Input -> var = 2*(3+5);

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t =

R term()

?

R factor()

f = 2

var = minus = id =

1.0

* ?

A series of additional indirect recursive

calls will determine the value of (3+5)…

R term()

+

statement.idList =

Statement.ch =

?

R expression()

R expression()

Trace: Input -> var = 2*(3+5);

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t =

R term()

?

R factor()

f = 2

var = minus = id =

1.0

* ?

)

statement.idList =

Statement.ch =

8

+

?

R expression()

R expression()

Trace: Input -> var = 2*(3+5);

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t =

R term()

?

R factor()

f = 2

var = minus = id =

1.0

* ?

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…

;

statement.idList =

Statement.ch =

R factor()

* 82 * ?

)

8

R expression()

Trace: Input -> var = 2*(3+5);

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t =

R term()

?

f =

var = minus = id =

1.0 • factor() can now return 8 to

term()

16

statement.idList =

Statement.ch =

R expression()

Trace: Input -> var = 2*(3+5);

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t =

R term()

?

f = 2 * 8

• factor() can now return 8 to term()

• term() can return 2*8 =16 to expression()

;

16

statement.idList =

Statement.ch =

R expression()

Trace: Input -> var = 2*(3+5);

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

?

t = 16

• factor() can now return 8 to term()

• term() can return 2*8 =16 to expression()

• expression() also returns 16 to getStatement…

;

16

statement.idList =

Statement.ch =

Trace: Input -> var = 2*(3+5);

Runti

me

Stac

ke = id =command =

getStatement()

varVAR

;

var => 16

Control is returned to the main function, where once again getStatement will be called…

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.