600 likes | 772 Views
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. First, let’s clear up some terminology….
E N D
Case Study:A Recursive Descent InterpreterImplementation 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
Interpreter • 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 blurringhowever… Examples of “Interpreted” Languages • Python • Pearl • JavaScript • Ruby • Smalltalk • Java
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 piecesusing recursion.
Recursive Descent • For Example: • The statement: var = 2*(3+5); can be parsed and broken down into its individual piecesusing 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 ) ; ID Operator Operator Operator
var = 2 * ( 3 + 5 ) ; ID Factor Factor Factor Operator Operator Operator
var = 2 * ( 3 + 5 ) ; Term Term ID Factor Factor Factor Operator Operator Operator
var = 2 * ( 3 + 5 ) ; Expression Expression Term Term ID Factor Factor Factor Operator Operator Operator
var = 2 * ( 3 + 5 ) ; Expression Expression Term Term ID Factor Factor Factor Operator Operator Operator
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”…
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”…
So – let’s go back to our concrete example and trace the program…
Trace: Input -> var = 2*(3+5); statement.idList = Statement.ch =
Trace: Input -> var = 2*(3+5); statement.idList = Statement.ch = Runtime Stack getStatement() e = id = command =
Trace: Input -> var = 2*(3+5); statement.idList = Statement.ch = var Runtime Stack getStatement() e = id = command = var VAR
Trace: Input -> var = 2*(3+5); statement.idList = Statement.ch = var = Runtime Stack R expression() getStatement() e = id = command = ? var VAR
Trace: Input -> var = 2*(3+5); statement.idList = Statement.ch = = Runtime Stack R term() R expression() t = ? getStatement() e = id = command = ? var VAR
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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