Unformatted text preview:

1Interpreters Program executed immediately, rather than translating to machine code that can be executed later Advantages: Quicker move from code to execution Easier to write an interpreter that runs on many machines Easier (often necessary) to have runtime checks Disadvantage: Resulting code is SLOW!Some Interpreter Approaches Single command parsed, executed Examples: LISP, Scheme, Prolog Single command parsed, executed (possibly with optimization) Example: most versions of SQL File partially compiled, resulting code interpreted Example: Java File parsed, result executed in interpreter (possibly multiple times) Examples: Perl, versions of awk2Single Command Interpreters> (defun foo (x y) (cond ((zerop x) 0)(t (+ y (foo (- x 1) y)))))FOO DEFINED> (foo 4 3)12 Much like execution of commands in a shell Read next command Execute command RepeatSingle Command Interpreters Generally scoping is much simpler Generally a small number of scope layers Example: foo declared globally, x and y are local to foo As a result, most meaningful data is held globally Often these types of language allow you to Save the current environment (including everything declared up to now) Execute a set of commands as a batch In some cases, allow compilation of command files3Optimization in Single Command Interpreters SQL (Standard Query Language for DBs) generally execute one command at a timeSELECT S.name, G.gradeFROM Student S, Class C, Grade GWHERE (C.dept is “CS”) and (C.num = 5641) and (C.cid = G.cid) and (S.sid = G.sid); Resulting query produces an initial plan for executing the query (an AST-like structure representing the query) result is then optimized to take advantage of aspects of the DB (only need one cid from relation Class, look that up first, then up corresponding Grade entries, etc.)Partial Compilation In Java, code is partially compiled (into byte code) that is low level, but not at machine level (since Java tries to be machine/OS independent) Resulting code is then interpreted at run-time (allowing the same byte code to be used across multiple platforms) Result is slow One approach to speeding up – just in time compilers  As translation from byte code to actual machine code occurs keep track of translation and reuse when possible4Interpreting a Program File Some interpreters follow many of the early steps of a compiler (parsing/scanning, semantic analysis) but then go straight to execution rather than compiling Disadvantage: have to “recompile” every time Advantage: often can use the same “program” on multiple platforms Execution is generally done by interpreting the AST resulting from the semantic analysis step (as will be done in our project)Key Issues in Executing a File How to manage memory/variables? One approach – use a variant of the list of hashtables representation for a symbol table (keep all hashtables making a tree) How to execute each piece of code? Surprisingly simple – often written in high level language with many similar features (e.g., implement an IF using an if command(s)) Need to represent variables that result from calculation/execution How to deal with code that jumps out of a context (return statements, break, exceptions, etc.)? Harder to deal with, often have to pass around flags used to control execution5A Scope TreeCode:int a;float b;char c (float a, int b) {int c;while (a < 100) {char b = ‘A’;a++;}int d;print(d);}int d (int a) {float b;c(1.0,2);d(3);}a: int, 1b: float, 1c: (float X int)→char, 1d: (int)→int, 1a: float, 2b: int, 2c: int, 2d: int, 2 b: char, 3a: int, 2b: float, 2Simple Solution – Memory Management (No Recursion) Associate with each entry in the symbol table tree an appropriate amount of memory connected to that variable At scope entry (start of function or block), reset memory to initial value (as appropriate) Works if there is no recursion6Memory Management with Recursion May be many versions of a local variable/parameter during execution Example: int f1 (int v) { if (v = 1) return 1; else return v * f1(v – 1); } One version of v for each recursive function call But only the most recent v is ever active at one time Idea: maintain memory locations associated with v as a stack/linked list Top of stack is the most recent/current value of v At scope entrance, go through entire scope, push new memory location for each variable At scope exit, go through entire scope, pop the top of stack for each variableRepresenting Values Need a mechanism for representing the result of calculations Option 1: Single class with field indicating type of variable and corresponding memory for each possible typeenum PossibleValues { vchar, vint, vfloat, vstring};class Value {PossibleValues vtype;void *vloc;}; Works well for simple types, but not for complex/constructed types7Representing Values Option 2: Single base type with multiple possible extension typesclass BaseValue {};class IntValue : public BaseValue {int ival;}; Better for complex types, may want to have isa() field:class BaseValue {virtual PossibleTypes isa() {}};class IntValue : public BaseValue {int ival;PossibleTypes isa() { return simple; }}; But could simply track type during type checking (annotate node with type(s)) and determine from thatRepresenting Values Option 3: Simply pass void* to variable location, use type checking to determine context Value type is known by operations applied/to be applied to it More on this next8Execution Steps Depends partly on language Example: LISP – declarations, function definitions, statement calls all mixed Execution: get next item, execute Executing a file that has been parsed depends on language, for example (Pascal): Create variables and deal with global scope (set any initial global variables) Execute “main” body statement (in C, C++ this would correspond to finding and executing the main function)Execution Functions Generally execution done with (yet another!) AST tree traversal Usually implement two key functions (most nodes use only one or the other function) ExprVal() – determine the value of an expression StmtExec() – execute a statement (generally when the statement does NOT produce a value)9Evaluating Expressions, Simplevoid *IntLitNode::ExprVal() {// ival of IntLitNode holds corresponding


View Full Document

U of M CS 5641 - Interpreters

Download Interpreters
Our administrator received your request to download this document. We will send you the file to your email shortly.
Loading Unlocking...
Login

Join to view Interpreters and access 3M+ class-specific study document.

or
We will never post anything without your permission.
Don't have an account?
Sign Up

Join to view Interpreters 2 2 and access 3M+ class-specific study document.

or

By creating an account you agree to our Privacy Policy and Terms Of Use

Already a member?