Compilers Notes
Compilers Notes
A compiler is a program that reads a program in one language, the source language and translates into an equivalent program in another language, the target language. The translation process should also report the presence of errors in the source program. Source Program
Compiler
Target Program
Error Messages There are two parts of compilation. The analysis part breaks up the source program into constant piece and creates an intermediate representation of the source program. The synthesis part constructs the desired target program from the intermediate representation.
Phases of Compiler
The compiler has a number of phases plus symbol table manager and an error handler. Input Source Program
Lexical Analyzer
Syntax Analyzer
Code Optimizer
Code Generator
Out Target Program The cousins of the compiler are 1. Preprocessor. 2. Assembler. 3. Loader and Link-editor. Front End vs Back End of a Compilers. The phases of a compiler are collected into front end and back end. The front end includes all analysis phases end the intermediate code generator. The back end includes the code optimization phase and final code generation phase. The front end analyzes the source program and produces intermediate code while the back end synthesizes the target program from the intermediate code.
A naive approach (front force) to that front end might run the phases serially. 1. Lexical analyzer takes the source program as an input and produces a long string of tokens. 2. Syntax Analyzer takes an out of lexical analyzer and produces a large tree. 3. Semantic analyzer takes the output of syntax analyzer and produces another tree. 4. Similarly, intermediate code generator takes a tree as an input produced by semantic analyzer and produces intermediate code. Minus Points
Requires enormous amount of space to store tokens and trees. Very slow since each phase would have to input and output to and from temporary disk
Remedy
use syntax directed translation to inter leaves the actions of phases. Compiler construction tools.
Parser Generators: The specification of input based on regular expression. The organization is based on finite automation. Scanner Generator: The specification of input based on regular expression. The organization is based on finite automation. Syntax-Directed Translation: It walks the parse tee and as a result generate intermediate code. Automatic Code Generators: Translates intermediate rampage into machine language. Data-Flow Engines: It does code optimization using data-flow analysis.
Syntax Definition
A contex free grammar, CFG, (synonyms: Backus-Naur Firm of BNF) is a common notation for specifying the syntax of a languages For example, an "IF-ELSE" statement in c-language has the form IF (Expr) stmt ELSE stmt In other words, it is the concatenation of:
an expression Expr ; a closing parenthesis ) ; a statement stmt ; a keyword ELSE ; Finally, another statement stmt.
The syntax of an 'IF-ELSE' statement can be specified by the following 'production rule' in the CFG. stmt IF (Expr) stmt ELSE stmt The arrow ( ) is read as "can have the form". A context-free grammar (CFG) has four components: 1. 2. 3. 4. A set of tokens called terminals. A set of variable called nonterminals. A set of production rules. A designation of one of the nonterminals as the start symbol.
Multiple production with the same nonterminal on the left like: list + digit list - digit list may be grouped together separated by vertical bars, like: list list + digit | list - digit | digit
Ambiguity
A grammar is ambiguous if two or more different parse trees can be desire the same token string. Equivalently, an ambiguous grammar allows two different derivations for a token string. Grammar for complier should be unambiguous since different parse trees will give a token string different meaning. Consider the following grammar
string string + string | string - string |0|2|...|9 To show that a grammar is ambiguous all we need to find a "single" stringthat has more than one perse tree.
Figure:23 --- pg.31 Above figure show two different parse trees for the token string 9 - 5 + 2 that corresponds to two different way of parenthesizing the expression: ( - 5) + 2 and 9 -(5 + 2). The first parenthesization evaluates to 2. Perhaps, the most famous example of ambiguity in a programming language is the dangling 'ELSE'. Consider the grammar G with the production: S IF b THEN S ELSE S | IF b THEN S | a G is ambiguous since the sentence IF b THEN IF b THEN a ELSE a has two different parse trees or derivation trees. Parse tree I figure This parse tree imposes the interpretation IF b THEN (IF b THEN a ) ELSE a Parse Tree II Figure This parse tree imposes the interpretation
IF b THEN (IF b THEN a ELSE a) The reason that the grammar G is ambiguous is that an 'ELSE' can be associated with two different THENs. For this reason, programming languages which allows both IF-THENELSE and IF-THEN constant can be ambiguous.
Associativity of Operators
If operand has operators on both side then by connection, operand should be associated with the operator on the left. In most programming languages arithmetic operators like addition, subtraction, multiplication, and division are left associative.
Token string: 9 - 5 + 2 Production rules list list - digit | digit digit 0 | 1 | 2 | . . . | 9 Parse tree for left-associative operator is
figure 24 on pg. 31 In the C programming language the assignment operator, =, is right associative. That is, token string a = b = c should be treated as a = (b = c).
Token string: a = b =c. Production rules: right letter = right | letter letter a | b | . . . | z Parse tree for right-associative operator is:
Figure
Precedence of Operators
An expression 9 + 5 * 2 has two possible interpretation:
(9 + 5) * 2 and 9 + (5 * L) The associativity of '+' and '*' do not resolve this ambiguity. For this reason, we need to know the relative precedence of operators. The convention is to give multiplication and division higher precedence than addition and subtraction. Only when we have the operations of equal precedence, we apply the rules of associative. So, in the example expression: 9 + 5 * 2. We perform operation of higher precedence i.e., * before operations of lower precedence i.e., +. Therefore, the correct interpretation is 9 + (5 *).
Separate Rule
Consider the following grammar and language again. S IF b THEN S ELSE S | IF b THEN S | a An ambiguity can be removed if we arbitrary decide that an ELSE should be attached to the last preceding THEN, like: Figure
We can revise the grammar to have two nonterminals S1 and S2. We insist that S2 generates IF-THEN-ELSE, while S1 is free to generate either kind of statements. The rules of the new grammar are: S1 IF b THEN S1 | IF b THEN S2 THEN S1 | a S2 IF b THEN S2 ELSE S2 | a Although there is no general algorithm that can be used to determine if a given grammar is ambiguous, it is certainly possible to isolate rules which leads to ambiguity or ambiguous grammar. A grammar containing the productions.
A AA | Alpha is ambiguous because the substring AAA has different parse tree. Figure This ambiguity disappears if we use the productions A AB | B B or A BA | B B Syntax of Expressions A grammar of arithmetic expressions looks like: Expr expr + term | expr - term | term term term * factor | term/factor | factor factor id | num | (expr) That is, expr is a string of terms separated by '+' and '-'. A term is a string of factors separated by '*' and '/' and a factor is a single operand or an expression wrapped inside of parenthesis.
Syntax-Directed Translation
Modern compilers use syntax-directed translation to interleaves the actions of the compiler phases. The syntax analyzer directs the whole process during the parsing of the source code.
Calls the lexical analyzer whenever syntax analyzer wants another token. Perform the actions of semantic analyzer. Perform the actions of the intermediate code generator.
The actions of the semantic analyzer and the intermediate code generator require the passage of information up and/or down the parse tree.
We think of this information as attributes attached to the nodes of the parse tree and the parser moving this information between parent nodes and children nodes as it performs the productions of the grammar. Postfix Notation Postfix notation also called reverse polish notation or RPN places each binary arithmetic operator after its two operands instead of between them. Infix : (9 - 5) + Expression 2 = (95 -) + 2 = (95-) 2 + = 95 - 2 + : Postfix Notation
Infix : 9 - (5 + Expression 2) =9(52+) = 9 (52+) = 9 5 2 + : Postfix Notation Why postfix notation? There are two reasons
There is only one interpretation We do not need parenthesis to disambignate the grammar.
Syntax-Directed Definitions
A syntax-directed definition uses a CFG to specify the syntatic structure of the input. A syntax-directed definition associates a set of attributes with each grammar symbol. A syntax-directed definition associates a set of semantic rules with each production rule.
And also let that nodes X, Y and Z have associated attributes X.a, Y.a and Z.a respectively. The annotated parse tree looks like: diagram If the semantic rule {X.a := Y.a + Z.a} is associated with the production XYZ then parser should add the attribute 'a' of node Y and attribute 'a' of node Z together and set the attribute 'a' of node X to their sum. Synthesized Attributes An attribute is synthesized if its value at a parent node can be determined from attributes of its children. diagram Since in this example, the value of a node X can be determined from 'a' attribute of Y and Z nodes attribute 'a' in a synthesized attribute. Synthesized attributes can be evaluated by a single bottom-up traversal of the parse tree. Example 2.6: Following figure shows the syntax-directed definition of an infix-topostfix translator. Figure 2.5 Pg. 34 PRODUCTION expr expr1 + term expr expr1 term expr term term 0 term 1 : : term 9 SEMANTIC RULE expr.t : = expr1.t + | | term.t | | '+' expr.t : = expr1.t + | | term.t | | '-' expr.t : = term.t term.t : = '0' term.t : = '1' : : term.t : = '9'
10
Annotated parse tree corresponds to semantic rules. Diagram The above annotated parse tree shows how the input infix expression 9 - 5 + 2 is translated to the prefix expression 95 - 2 + at the root. Depth-First Traversals A depth-first traversal of a parse tree is one way of evaluating attributes. Note that a syntax-directed definition does not impose any particular order as long as order computes attribute of parent after all its children's attributes. PROCEDURE visit (n: node) BEGIN FOR each child m of n, from left to right Do visist (m); Evaluate semantic rules at node n END Diagram Translation Schemes A translation scheme is another way of specifying a syntax-directed translation. This scheme is a CFG in which program fragments called semantic actions are embedded within the right sides of productions. For example, rest + term {primt ( ' + ' )} rest, indicates that a '+' sign should be printed between:
depth-first traversal of the term node, and depth first traversal of the rest, node.
Diagram Ex. 2.8 REVISION: SYNTAX-DIRECTED TRANSLATION Step1: Syntax-directed definition for translating infix expression to postfix form. PRODUCTION expr expr1 + term expr expr1 term SEMANTIC RULE expr.t : = expr1.t + | | term.t | | '+' expr.t : = expr1.t + | | term.t | | '-'
11
Step 2: A translation scheme derived from syntax-direction definition is : Figure 2.15 on pg. 39 expr term expr term expr term term expr + expr term 0 1 9 {print( ' + ' )} {print( ' - ')} {print( ' 0 ' )} {print( ' 1 ' )} : : {print( ' 9 ' )}
: : term
Figure 2.14 on pg. 40 Note that it is not necessary to actually construct the parse tree.
Parsing
The parsing is a process of finding a parse tree for a string of tokens. Equivalently, it is a process of determining whether a string of tokens can be generated by a grammar. The worst-case time pf parsing algorithms are O(nn3) but typical is : O(n) time. For example. The production rules of grammar G is: list list + digit | list - digit | digit digit 0 | 1 | . . . | 9
12
Given token string is 9-5+2. Parse tree is: diagram Each node in the parse tree is labeled by a grammar symbol. the interior node corresponds to the left side of the production. the children of the interior node corresponds to the right side of production. The language defined by a grammar is the set of all token strings can be derived from its start symbol. The language defined by the grammar: list list + digit | list - digit | digit digit 0 | 1 | 2 | . . . | 9 contains all lists of digits separated by plus and minus signs. The Epsilon, E, on the right side of the production denotes the empty string. As we have mentioned above, the parsing is the process of determining if a string of tokens can be generated by a grammar. A parser must be capable of constructing the tree, or else the translation cannot be guaranteed correct. For any language that can be described by CFG, the parsing requires O(n3) time to parse string of n token. However, most programming languages are so simple that a parser requires just O(n) time with a single left-to-right scan over the iput string of n tokens. There are two types of Parsing 1. Top-down Parsing (start from start symbol and derive string) A Top-down parser builds a parse tree by starting at the root and working down towards the leaves. o Easy to generate by hand. o Examples are : Recursive-descent, Predictive. 2. Bottom-up Parsing (start from string and reduce to start symbol) A bottom-up parser builds a parser tree by starting at the leaves and working up towards the root. o Not easy to handle by hands, usually compiler-generating software generate bottom up parser o But handles larger class of grammar o Example is LR parser.
13
Top-Down Parsing
Consider the CFG with productions: expr term rest rest + term rest | - term rest term 0 | 1 | . . . | 9 Step 0: Initialization: Root must be starting symbol Step 1: expr term rest Step 2: term 9 Step 3 rest term rest Step 4: term 5 Step 5: rest term rest Step 6: term 2 Step 7: rest E In the example above, the grammar made it easy for the top-down parser to pick the correct production in each step. This is not true in general, see example of dangling 'else'.
Predictive Parsing
Recursive-descent parsing is a top-down method of syntax analysis that executes a set of recursive procedure to process the input. A procedure is associated with each nonterminal of a grammar. A predictive parsing is a special form of recursive-descent parsing, in which the current input token unambiguously determines the production to be applied at each step. Let the grammar be:
14
expr term rest rest + term rest | - term rest | 6 term 0 | 1 | . . . | 9 In a recursive-descent parsing, we write code for each nonterminal of a grammar. In the case of above grammar, we should have three procedure, correspond to nonterminals expr, rest, and term. Since there is only one production for nonterminal expr, the procedure expr is: expr ( ) { term ( ); rest ( ); return } Since there are three (3) productions for rest, procedure rest uses a global variable, 'lookahead', to select the correct production or simply selects "no action" i.e., E - production, indicating that lookahead variable is neither + nor rest ( ) { IF (lookahead = = '+') { match ( ' + ' ); term ( ); rest ( ); return } ELSE IF ( lookahead = = '-') { match (' - '); term ( ); rest ( ); return { ELSE { return; } } The procedure term checks whether global variable lookahead is a digit. term ( ) { IF ( isdigit (lookahead)) { match (lookahead);
15
return; } else{ ReportError ( ); } After loading first input token into variable 'lookahead' predictive parser is stared by calling starting symbol, 'expr'. If the input is error free, the parser conducts a depth-first traversal of the parse tree and return to caller routine through expr. Problem with Predictive Parsing: left recursion
Left Recursion
The production is left-recursive if the leftmost symbol on the right side is the same as the non terminal on the left side. For example, expr expr + term. If one were to code this production in a recursive-descent parser, the parser would go in an infinite loop. diagram We can eliminate the left-recursion by introducing new nonterminals and new productions rules. For example, the left-recursive grammar is: E E+T|T E T*F|F F (E) | id. We can redefine E and T without left-recursion as: E TE` E` + TE` | E T FT` T * FT` | E F (E) | id
16
Getting rid of such immediate left recursion is not enough. One must get rid of indirect left recursion too, where two or more nonterminals are mutually left-recursive.
Lexical Analyzer
The main task of lexical Analyzer is to read a stream of characters as an input and produce a sequence of tokens such as names, keywords, punctuation marks etc.. for syntax analyzer. It discards the white spaces and comments between the tokens and also keep track of line numbers. <fig: 3.1 pp. 84>
Tokens, Patterns, Lexemes Specification of Tokens o Regular Expressions o Notational Shorthand Finite Automata o Nondeterministic Finite Automata (NFA). o Deterministic Finite Automata (DFA). o Conversion of an NFA into a DFA. o From a Regular Expression to an NFA.
Type token (id, num, real, . . . ) Punctuation tokens (IF, void, return, . . . ) Alphabetic tokens (keywords)
Example of non-tokens:
17
Patterns
There is a set of strings in the input for which the same token is produced as output. This set of strings is described by a rule called a pattern associated with the token. Regular expressions are an important notation for specifying patterns. For example, the pattern for the Pascal identifier token, id, is: id letter (letter | digit)*.
Lexeme
A lexeme is a sequence of characters in the source program that is matched by the pattern for a token. For example, the pattern for the RELOP token contains six lexemes ( =, < >, <, < =, >, >=) so the lexical analyzer should return a RELOP token to parser whenever it sees any one of the six.
18
By definition S0 is an empty string, , and S` = S. For example, if x =ba and na then xy2 = banana. Languages A language is a set of strings over some fixed alphabet. The language may contain a finite or an infinite number of strings. Let L and M be two languages where L = {dog, ba, na} and M = {house, ba} then
Union: LUM = {dog, ba, na, house} Concatenation: LM = {doghouse, dogba, bahouse, baba, nahouse, naba} Expontentiation: L2 = LL By definition: L0 ={ } and L` = L
The kleene closure of language L, denoted by L*, is "zero or more Concatenation of" L. L* = L0 U L` U L2 U L3 . . . U Ln . . . For example, If L = {a, b}, then L* = { , a, b, aa, ab, ab, ba, bb, aaa, aba, baa, . . . } The positive closure of Language L, denoted by L+, is "one or more Concatenation of" L. L+ = L` U L2 U L3 . . . U Ln . . . For example, If L = {a, b}, then L+ = {a, b, aa, ba, bb, aaa, aba, . . . }
Regular Expressions
1. The regular expressions over alphabet specifies a language according to the following rules. is a regular expression that denotes { }, that is, the set containing the empty string. 2. If a is a symbol in alphabet, then a is a regular expression that denotes {a}, that is, the set containing the string a. 3. Suppose r and s are regular expression denoting the languages L(r) and L(s). Then a. (r)|(s) is a regular expression denoting L(r) U L(s). b. (r)(s) is a regular expression denoting L(r) L(s). c. (r)* is a regular expression denoting (L(r))*.
19
d. (r) is a regular expression denoting L(r), that is, extra pairs of parentheses may be used around regular expressions. Unnecessary parenthesis can be avoided in regular expressions using the following conventions:
The unary operator * (kleene closure) has the highest precedence and is left associative. Concatenation has a second highest precedence and is left associative. Union has lowest precedence and is left associative.
Regular Definitions
A regular definition gives names to certain regular expressions and uses those names in other regular expressions. Here is a regular definition for the set of Pascal identifiers that is define as the set of strings of letter and digits beginning with a letters. letter A | B | . . . | Z | a | b | . . . | z digit 0 | 1 | 2 | . . . | 9 id letter (letter | digit)* The regular expression id is the pattern for the Pascal identifier token and defines letter and digit. Where letter is a regular expression for the set of all upper-case and lower case letters in the alphabet and digit is the regular for the set of all decimal digits. The pattern for the Pascal unsigned token can be specified as follows: digit 0 | 1 | 2 | . . . | 9 digit digit digit* Optimal-fraction . digits |
Optimal-exponent (E (+ | - | ) digits) | num digits optimal-fraction optimal-exponent. This regular definition says that
20
An optimal-fraction is either a decimal point followed by one or more digits or it is missing (i.e., an empty string). An optimal-exponent is either an empty string or it is the letter E followed by an ' optimal + or - sign, followed by one or more digits.
Notational Shorthand
The unary postfix operator + means "one of more instances of " (r)+ = rr* The unary postfix operator? means "zero or one instance of" r? = (r | ) Using these shorthand notation, Pascal unsigned number token can be written as: digit 0 | 1 | 2 | . . . | 9 digits digit+ optimal-fraction (. digits)? optimal-exponent (E (+ | -)?digits)? num digits optimal-fraction optimal-exponent
Finite Automata
A recognizer for a language is a program that takes a string x as an input and answers "yes" if x is a sentence of the language and "no" otherwise. One can compile any regular expression into a recognizer by constructing a generalized transition diagram called a finite automation. A finite automation can be deterministic means that more than one transition out of a state may be possible on a same input symbol. Both automata are capable of recognizing what regular expression can denote.
A nondeterministic finite automation is a mathematical model consists of 1. 2. 3. 4. 5. a set of states S; a set of input symbol, , called the input symbols alphabet. a transition function move that maps state-symbol pairs to sets of states. a state so called the initial or the start state. a set of states F called the accepting or final state.
An NFA can be described by a transition graph (labeled graph) where the nodes are states and the edges shows the transition function. The labeled on each edge is either a symbol in the set of alphabet, , or denoting empty string. Following figure shows an NFA that recognizes the language: (a | b)* a bb.
FIGURE 3.19 - pp 114 This automation is nondeterministic because when it is in state-0 and the input symbol is a, it can either go to state-1 or stay in state-0. The transition is FIGURE 115 pp. 115 The advantage of transition table is that it provides fast access to the transitions of states and the disadvantage is that it can take up a lot of soace. The following diagram shows the move made in accepting the input strings abb, aabb and ba bb. abb :
In general, more than one sequence of moves can lead to an accepting state. If at least one such move ended up in a final state. For instance
The language defined by an NFA is the set of input strings that particular NFA accepts.
22
Following figure shows an NFA that recognize aa* | bb*. Note that 's disappear in a cancatenation. FIGURE 3.21 pp. 116 The transition table is:
OUTPUT:
The function move (S, C) gives a new state from state s on input character C. The function 'nextchar' returns the next character in the string. Initialization: S := S0 C := nextchar;
23
while not end-of-file do S := move (S, C) C := nextchar; If S is in F then return "yes" else return "No". Following figure shows a DFA that recognizes the language (a|b)*abb. FIGURE The transition table is state 0 1 2 3 a 1 1 1 1 b 0 2 3 0
With this DFA and the input string "ababb", above algorithm follows the sequence of states:
FIGURE
In the transition table of an NFA, entry is a set of states; In the transition table of a DFA, each entry is a single state;
The general idea behind the NFA-to-DFA construction is that the each DFA state corresponds to a set of NFA states.
24
For example, let T be the set of all states that an NFA could reach after reading input: a1, a2, . . . , an - then the state that the DFA reaches after reading a1, a2, . . . , an corresponds to set T. Theoretically, the number of states of the DFA can be exponential in the number of states of the NFA, i.e., (2n), but in practice this worst case rarely occurs. Algorithm: Subset construction. INPUT: An NFA N OUTPUT: A DFA D accepting the same language. METHOD: Construct a transition table DTrans. Each DFA state is a set of NFA states. DTran simulates in parallel all possible moves N can make on a given string. Operations to keep track of sets of NFA states: Closure (S) Set of states reachable from state S via epsilon. Closure (T) Set of states reachable from any state in set T via epsilon. move (T, a) Set of states to which there is an NFA transition from states in T on a symbol a. Algorithm: initially, -Closure (S0) in DTrans. While unmarked state T in DTrans mark T for each input symbol 'a' do u = Closure (T, a) If u is not in DTrans then add u to DTrans DTrans [T, a] = U Following algorithm shows a computation of -Closure function. Push all states in T onto stack. initialize -Closure (T) to T while stack is not empty do pop top element t for each state u with -edge t to u do If u is not in -Closure(T) do add u Closure (T) push u onto stack
25
Following example illustrates the method by constructing a DFA for the NFA.
figure
figure
26
figure
figure
figure We get r7 =(a|b)* a Similarly for r8 and r10 - use case 2 figure figure And get r11 by case 3b figure We have r = (a|b)*abb.
Code Generation
Introduction
Phases of typical compiler and position of code generation.
27
Since code generation is an "undecidable problem (mathematically speaking), we must be content with heuristic technique that generate "good" code (not necessarily optimal code). Code generation must do following things:
1. Memory Management Mapping names in the source program to address of data object is cooperating done in pass 1 (Front end) and pass 2 (code generator). Quadruples address Instruction. Local variables (local to functions or procedures ) are stack-allocated in the activation record while global variables are in a static area. 2. Instruction Selection The nature of instruction set of the target machine determines selection. -"Easy" if instruction set is regular that is uniform and complete. Uniform: all triple addresses all stack single addresses. Complete: use all register for any operation. If we don't care about efficiency of target program, instruction selection is straight forward. For example, the address code is: a := b + c d := a + e Inefficient assembly code is: 28
1. 2. 3. 4. 5. 6.
R0 b R0 c + R 0 a R0 R0 a R0 e + R 0 d R0
Here the fourth statement is redundant, and so is the third statement if 'a' is not subsequently used. 3. Register Allocation Register can be accessed faster than memory words. Frequently accessed variables should reside in registers (register allocation). Register assignment is picking a specific register for each such variable. Formally, there are two steps in register allocation: 1. Register allocation (what register?) This is a register selection process in which we select the set of variables that will reside in register. 2. Register assignment (what variable?) Here we pick the register that contain variable. Note that this is a NP-Complete problem. Some of the issues that complicate register allocation (problem). 1. Special use of hardware for example, some instructions require specific register. 2. Convention for Software: For example
Register R6 (say) always return address. Register R5 (say) for stack pointer. Similarly, we assigned registers for branch and link, frames, heaps, etc.,
3. Choice of Evaluation order Changing the order of evaluation may produce more efficient code. This is NP-complete problem but we can bypass this hindrance by generating code for quadruples in the order in which they have been produced by intermediate code generator. ADD x, Y, T1 ADD a, b, T2 is legal because X, Y and a, b are different (not dependent).
29
Typical Architecture: 1. 2. 3. 4. Target machine is : Bit addressing (factor of 1). Word purpose registers. Three address instruction of forms: Op source 1, source 2, destination e.g., ADD A, B, C Byte-addressable memory with 4 bytes per word and n general-purpose registers, R0, R1, . . . , Rn-1. Each integer requires 2 bytes (16-bits). Two address instruction of the form mnemonic source, destination MODE FORM ADDRESS EXAMPLE Absolute register Index Indirect register ADDEDCOST M M ADD R0, R1 1 ADD temp, R R 0 R1 ADD c (R) c + contents (R) 1 100(R2), R1 ADD * R2, *R contents (R) 0 R1
30
*c (R) #c
1 1
Each instruction has a cost of 1 plus added costs for the source and destination. => cost of instruction = 1 + cost associated the source and destination address mode. This cost corresponds to the length (in words ) of instruction. Examples 1. Move register to memory R0 M. MOV R0, M cost = 1+1 = 2. 2. Indirect indexed mode: MOV * 4 (R0), M cost = 1 plus indirect index plus instruction word =1+1+1=3 3. Indexed mode: MOV 4(R0), M cost = 1 + 1 + 1 = 3 4. Litetral mode: MOV #1, R0 cost = 1 + 1 = 2 5. Move memory to memory MOV m, m cost = 1 + 1 + 1 = 3
31