Syssft Compiled Nksrinath

download Syssft Compiled Nksrinath

of 98

Transcript of Syssft Compiled Nksrinath

  • 8/4/2019 Syssft Compiled Nksrinath

    1/98

    1

    e-Notes by N.K.Srinath, RVCE, Bangalore

    COMPILERS

    BASIC COMPILER FUNCTIONS

    A compiler accepts a program written in a high level language as input and produces itsmachine language equivalent as output. For the purpose of compiler construction, a high levelprogramming language is described in terms of a grammar. This grammar specifies the formaldescription of the syntax or legal statements in the

    language.Example: Assignment statement in Pascal is defined as:

    < variable > : = < Expression >

    The compiler has to match statement written by the programmer to the structure defined bythe grammars and generates appropriate object code for each statement. The compilation processis so complex that it is not reasonable to implement it in one single step. It is partitioned into aseries of sub-process called phases. A phase is a logically cohesive operation that takes as inputone representation of the source program and produces an output of another representation. Thebasic phases are - Lexical Analysis, Syntax Analysis, and Code Generation.

    Lexical Analysis: It is the first phase. It is also called scanner. It separates characters of

    the source language into groups that logically belong together. These groupsare called tokens. The usual tokens are:

    Keyword: such as DO or IF,Identifiers: such as x or num,Operator symbols: such as

  • 8/4/2019 Syssft Compiled Nksrinath

    2/98

    2

    {value}

    Fig. 1 Syntax Tree

    Code Generator: It produces the object code by deciding on the memory locations fordata, selecting code to access each datum and selecting the registers in which each computation is

    to be done. Designing a code generator that produces truly efficient object program is one of themost difficult parts of compiler design.In the following sections we discuss the basic elements of a simple compilation

    process, illustrating this application to the example program in fig. 2.

    PROGRAM STATSVAR

    SUM, SUMSQ, I, VALUE, MEAN, VARIANCE : INTEGERBEGIN

    SUM : = 0 ;SUMSQ : = 0 ;FOR I : = 1 to 100 Do

    BEGIN

    READ (VALUE) ;SUM : = SUM + VALUE ;SUMSQ : = SUMSQ + VALUE * VALUE

    END;MEAN : = SUM DIV 100;VARIANCE : = SUMSQ DIV 100 - MEAN * MEAN ;WRITE (MEAN, VARIANCE)

    END

    Fig. 2 Pascal Program

    GRAMMARSA grammar for a programming language is a formal description of the syntax of programs

    and individual statements written in the language. The grammar does not describe the semanticsor memory of the various statements. To differentiate between syntax and semantics consider the

    following example:

    VAR X, Y : REAL VAR I, J, K : INTEGERI : INTEGER

    X : = I + Y ; I : = J + K ;

    Fig .3These two programs statement have identical syntax. Each is an assignment statement;

    the value to be assigned is given by an expression that consists of two variable names separatedby the operator '+'.

    The semantics of the two statements are quite different. The first statement specifies thatthe variables in the expressions are to be added using integer arithmetic operations. The secondstatement specifies a floating-point addition, with the integer operand 2 being connected tofloating point before adding. The difference between the statements would be recognized duringcode generation.

    Grammar can be written using a number of different notations. Backus-Naur Form (BNF)is one of the methods available. It is simple and widely used. It provides capabilities that aredifferent for most purposes.

  • 8/4/2019 Syssft Compiled Nksrinath

    3/98

    3

    A BNF grammar consists of a set of rules, each of which defines the syntax ofsome construct in the programming language.

    A grammar has four components. They are:

    1. A set of tokens, known as terminal symbols non-enclosed in bracket.Example:READ, WRITE

    2. A set of terminals. The character strings enclosed between the angle brackets ()are called terminal symbols. These are the names of the constructs defined in thegrammar.

    3. A set of productions where each production consists of a non-terminal called the leftside of the production, as "is defined to be" (:: = ), and a sequence oftoken and/or non-terminal, called the right side of the product.

    Example: < reads > : : = READ .

    4. A designation of one of the non-terminals as the start symbol.This rule offers two possibilities separated by the symbol, for the syntax of an

    < id - list > may consist simply of a tokenid

    (the notationid

    denotes an identifier that isrecognized by the scanner). The second syntax.

    Example: ALPHAALPHA, BETA

    ALPHA is an < id - list > that consist of another < id - list > ALPHA, followedby a comma, followed by an id BETA.

    Tree: It is also called parse tree or syntax tree. It is convenient to display the analysisof a source statement in terms of a grammar as a tree.

    Example: READ (VALUE)GRAMMAR: (read) : : = READ ( < id -list>)

    Example: Assignment statement:

    SUM : = 0 ;SUM : = + VALUE ;SUM : = - VALUE ;

    Grammar: < assign > : : = id : = < exp >< exp > : : = < term > | < exp > - < term >< term > : : = < factor > | < term > * < factor > | < term > DIV < factor >< factor > : : = id | int | ( < exp > )

    Assign consists of an id followed by the token : = , followed by an expression Fig. 4(a). Show the syntax tree.

    Expressions are sequence of connected by the operations + and - Fig. 4(b).Show the syntax tree.

    Term is a sequence of < factor > S connected by * and DIV Fig. 4(c).

    A factor may consists of an identifies id or an int (which is also recognized bythe scan) or an < exp > enclosed in parenthesis. Fig. 4(d).

    < assign > < exp >

  • 8/4/2019 Syssft Compiled Nksrinath

    4/98

    4

    id : = < term > + < exp >{variance }

    Fig. 4 (a) Fig. 4 (b)

    < term > factor| |

    < factor > Dir < term > id

    X < factor > int

    IdFig.4 (c)

    (< exp > ) Fig. 4 (d)

    Fig. 4 Parse Trees

    For the statement Variance : = SUMSQ Div 100 - MEAN * MEAN ;The list of simplified Pascal grammar is shown in fig.5.

    1. < prog > : : = PROGRAM < program > VAR BEGIN < stmt > - list > END.

    2. < prog - name >: : = id3. < dec - list> : : = < dec > | < dec - list > ; < dec >4. < dec > : : = < id - list > : < type >5. < type > : : = integer6. < id - list > : : = id | < id - list > , id7. : : = < stmt > ; < stmt >8. < stmt > : : = < assign > | | < write > | < for >9. < assign > : : = id : = < exp >10.< exp > : : = < term > | < exp > + < term > | < exp > - < term >11.< term > : : = < factor > | < term > | DIV 12.< factor > : : = id ; int | (< exp >)13.< READ > : : = READ ( < id - list >)14.< write > : : = WRITE ( < id - list >)15.< for > : : = FOR < idex - exp > Do < body >16.< index - exp> : : = id : = < exp > To ( exp >17. < body > : : = < start > | BEGIN < start - list > END

    Fig. 5 Simplified Pascal Grammar

    ( < prog >)|

    PROGRAM < prog - name > VAR dec - list BEGIN END

    Id < dec >

  • 8/4/2019 Syssft Compiled Nksrinath

    5/98

    5

    {STATS}< stmt - list > ; < stmt >

    < id - list > : < type >

    INTEGER < write >

    (id - list) , id

    {VARIANCE} < stmt - list > ; WRITE ( )

    (id - list ) ; id < stmt - list > ; < assign > (id - list ) . id(MEAN) {VARIANCE}

    id(id - list ) , id id : =

    < stmt - list > ; {VARIANCE} < exp >

    < assign >(id - list ) , id

    {I} ; < start >id : =

    , id {mean} {SMSQ} < stmt > < assign > | |

    *

    id | |{SUM} < assign > id : = | | id

    {SUMSQ} | | Div | [MEAN]| | | term | >term> Div idid : < exp > | factor {MEAN}

    | factor | int< term > | id {100} int

    | int {SUM} | {100}< factor > { 0} id

    | {SUMSQ}int {0}

    |

    < for >

    FOR Do < body >

    Id : = To BEGIN END{I} | |

    < term > | |

    ; < stmt >| | |

    int int{I} {100} ;

    | |< stmy >

    | id : =

    < read > (SUMSQid : =

    {SUM}READ ( < id - list > ) < exp > + < term >

    < exp > + < term >

    id | | |{VALUE? < factor > < term > *

    | | | | |< factor >. id id

    | { value} | | {value}

    id id id{SUM} {SUMSQ} {value}

    Next

    Page

  • 8/4/2019 Syssft Compiled Nksrinath

    6/98

    6

    Fig. 6 Parse tree for the Program 1

    Parse tree for Pascal program in fig.1 is shown in fig. 6

    1 (a) Draw parse trees, according to the grammar in fig. 5 for the following S:

    (a) ALPHA < id - list >

    |id

    { ALPHA }

    (b) ALPHA, BETA, GAMMA < id - list >

    id< id - list > , {GAMMA}

    id

    < id - list > , {BETA}

    id[ ALPHA ]

    2 (a) Draw Parse tree, according to the grammar in fig. 5 for the following < exp > S :

    (a)ALPHA + BETA < exp >|

    < term >

    < term >|

    < factor > + < factor >| |

    id id{ALPHA} {BETA}

    (b) ALPHA - BETA + GAMMA< exp

    < exp > - term

    < term > < term > * factor| |

    < factor > < factor > id| {GAMMA}

  • 8/4/2019 Syssft Compiled Nksrinath

    7/98

    7

    id id{ALPHA} {BETA}

    (c) ALPHA DIV (BETA + GAMMA) = DELTA< exp >

    < exp > - < term >

    < term > < factor >|

    < term > Div < factor > {DELTA}

    < factor >( < exp > )

    id

    {ALPHA} < exp > + < term >

    < term > factor

    id id{BETA} {GAMMA}

    3. Suppose the rules of the grammar for < exp > and < term > is as follows:< exp > :: = < term > | < exp > * < term> | < exp> Div < term >< term > :: = | < term > + < factor > | < term > - < factor >

    Draw the parse trees for the following:

    (a)A1 + B1 (b) A1 - B1 * G1 (c) A1 + DIV (B1 + G1) - D1< exp >

    |(a) A1 + B1 term

    < term > + < factor >

    factor|

    id id{A1} {B1}

    (b) A1 - B1 * G1 < exp >|

    teerm

  • 8/4/2019 Syssft Compiled Nksrinath

    8/98

    8

    teerm - < factor >

    factorterm * factor

    |id factor id{A1} id {B1} {G1}

    (c) A1 DIV (B1 + A1) - D1< exp >

    < exp > DIV < term >

    < term > < term > - < factor >

    < factor > < factor > id| {D1}

    id{A1} ( < exp > )

    < term >

    < term > + < factor >

    < factor > id{G1}

    id{B1}

    LEXICAL ANALYSIS

    Lexical Analysis involves scanning the program to be compiled. Scanners are designed torecognize keywords, operations, identifiers, integer, floating point numbers, character strings andother items that are written as part of the source program. Items are recognized directly as singletokens. These tokens could be defined as a part of thegrammar.

    Example: : : = | |

    : : = A | B | C | . . . | Z : : = 0 | 1 | 2 | . . . | 9

    In a such a case the scanner world recognize as tokens the single characters A, B, . . . Z,,0, 1, . . . 9. The parser could interpret a sequence of such characters as the language construct . Scanners can perform this function more efficiently. There can be significant saving incompilation time since large part of the source program consists of multiple-character identifiers.It is also possible to restrict the length of identifiers in a scanner than in a passing notion. Thescanner generally recognizes both single and multiple character tokens directly.

  • 8/4/2019 Syssft Compiled Nksrinath

    9/98

    9

    The scanner output consists of sequence of tokens. This token can be considered to havea fixed length code. The fig. 7 gives a list of integer code for each token for the program in fig. 5in such a type of coding scheme, the PROGRAM is represented bythe integer value 1, VAR has the integer value 2 and so on.

    Token Program VAR BEGIN END END INTEGER FOR

    Code 1 2 3 4 5 6 7

    Token READ WRITE To Do ; : ,

    Token : = + - K DIV ( )

    Token : = + - K DIV ( )

    Code 15 16 17 18 17 20 21

    Token Id IntCode 22 23

    Fig. 7 Token Coding Scheme

    For a keyword or an operator the token loading scheme gives sufficient information. Inthe case of an identifier, it is also necessary to supply particular identifier name that was scanned.It is true for the integer, floating point values, character-string constant etc. A token specifier canbe associated with the type of code for such tokens. This specifier gives the identifier name,integer value, etc., that was found by the scanner.

    Some scanners enter the identifiers directly into a symbol table. The token specifier forthe identifiers may be a pointer to the symbol table entry for that identifier.

    The functions of a scanner are:

    The entire program is not scanned at one time. Scanner is a operator as a procedure that is called by the processor when it needs another

    token.

    Scanner is responsible for reading the lines of the source program and possible forprinting the source listing. The scanner, except for printing as the output listing, ignores comments. Scanner must look into the language characteristics.

    Example: FOTRAN : Columns 1 - 5 Statement number: Column 6 Continuation of line: Column 7 . 22 Program statement

    PASCAL : Blanks function as delimiters for tokens: Statement can be continued freely: End of statement is indicated by ; (semi column)

    Scanners should look into the rules for the formation of tokens.Example: 'READ': Should not be considered as keyword as it is within quotes.

    i.e., all string within quotes should not be considered as token.

    Blanks are significant within the quoted string. Blanks has important factor to play in different language

    Example 1: FORTRAN Statement:

    Do 10 I = 1, 100 ; Do is a key word, I is identifier, 10 is the statement number

  • 8/4/2019 Syssft Compiled Nksrinath

    10/98

    10

    Statement: Do 10 I = 1 ;It is an identifier Do 10 I = 1

    Note: Blanks are ignored in FORTRAN statement and hence it is a assignment statement.In this case the scanner must look ahead to see if there is a comma (,) before it candecide in the proper identification of the charactersDo.

    Example 2: In FORTRAN keywords may also be used as an identifier. Wordssuch as IF, THEN, and ELSE might represent either keywords orvariable names.

    IF (THEN .EQ ELSE) THENIF = THEN

    ELSETHEN = IF

    ENDIF

    Modeling Scanners as Finite Automata

    Finite automatic provides an easy way to visualize the operation of a scanner.Mathematically, a finite automation consists of a finite set of states and a set of transition fromone state to another. Finite automatic is graphically represented. It is shown in fig, State isrepresented by circle. Arrow indicates the transition from one state to another. Each arrow islabeled with a character or set of characters that can be specified for transition to occur. Thestarting state has an arrow entering it that is not connected to anything else.

    State Final State TransitionFig. 8

    Example: Finite automata to recognize tokens is gives in fig. 9. Thecorresponding algorithm is given in fig. 10

    0 - 9A - ZB A - Z

    Fig. 9

    Get first Input-characterIf Input-character in [ 'A' . . ' Z' ] thenbegin

    while Input - character in [ 'A' . . 'Z', ' 0'. . ' 9' ] dobegin

    get next input - characterEnd {while}

    end {if first is [ 'A' .. ' Z' ] }else

    1 2

  • 8/4/2019 Syssft Compiled Nksrinath

    11/98

    11

    return (token-error)

    Fig. 10

    SYNTACTIC ANALYSIS

    During syntactic analysis, the source programs are recognized as language constructsdescribed by the grammar being used. Parse tree uses the above process for

    translation of statements, Parsing techniques are divided into two general classes:-- Bottom up and -- Top down.Top down methods begin with the rule of the grammar that specifies the goal of the

    analysis ( i.e., the root of the tree), and attempt to construct the tree so that the terminal nodesmatch the statement being analyzed.

    Bottom up methods begin with the terminal nodes of the tree and attempt tocombine these into successively high - level nodes until the root is reached.

    OPERATOR PRECEDENCE PARSING

    The bottom up parsing technique considered is called the operator precedence method.This method is loaded on examining pairs of consecutive operators in the sourceprogram and making decisions about which operation should be performed first.

    Example: A + B * C - D (1)

    The usual procedure of operation multiplication and division has higher precedence overaddition and subtraction.

    Now considering equation (1) the two operators (+ and *), we find that + has lower

    precedence than *. This is written as + * [+ has lower precedence *]

    Similarly ( * and - ), we find that * - [* has greater precedence -].The operation precedence method uses such observations to guide the parsing

    process.

    A + B * C - D (2)

    VAR

    BEGIN

    END

    END

    INTEGER

    FOR

    REAS

    WRITE

    TO

    DO

    : : , :=+ - * D

    IV) ( IdIn

    t

    PROGRAMVARBEGINEND

    ) ;

    (c) . . . BEGIN < N2 > ;

    (d) ... < N2 >

  • 8/4/2019 Syssft Compiled Nksrinath

    13/98

    13

    READ ( )

    id(VALUE)

    Fig. 12

    According to the grammar idmay be considered as < factor > . (rule 12), (rule 9) or a < id-list > (rule 6). In operator precedence phase, it is not necessary to indicate whichnon-terminal symbol is being recognized. It is interpreted as non-terminal < N1 >. Hence the newversion is shown in fig. 12(b).

    An operator-precedence parser generally uses a stack to save token that have beenscanned but not yet parsed, so it can reexamine them in this way. Precedence relations hold onlybetween terminal symbols, so < N1 > is not involved in this process and a relationship isdetermined between (and).

    READ () corresponds to rule 13 of the grammar. This rule is the only one that couldbe applied in recognizing this portion of the program. The sequence is simply interpreted as a

    sequence of some interpretation < N2 >. Fig. 12(c) shows thisinterpretation. The parser tree is given in fig. 12(d).

    Note: (1) The parse tree in fig. 1 and fig. 12 (d) are same except for the name of thenon-terminal symbols involved.

    (2) The name of the non-terminals is arbitrarily chosen.

    Example: VARIANCE ; = SUMSQ DIV 100 - MEAN * MEAN

    (i) . . id 1 : = id 2 Div . . .

    (ii) . . . id 1 : = Div int -

    {SUMSQ}(iii) . . . id 1: = Div -

    int

    {SUMSQ} {100}

    (iv) . . . . id 1: = - id 3 *

    DIV id2 int

    {SUMSQ} {100}

    v) . . . . id 1: = - * id 4 ;

    id 3{MEAN}

    (vi) . . . id 1: = - *

  • 8/4/2019 Syssft Compiled Nksrinath

    14/98

    14

    id 4{MEAN}

    (vii) . . . id 1: = -

    *

    id 3 id 4{MEAN} {MEAN}

    (viii) . . . id : =

    -

    (ix) . . .

    id 1 : = {VARIANCE} DIV *

    id 2 int - id 3 id 4{SUMSQ} {100} {MEAN} {MEAN}

    SHIFT REDUCE PARSING

    The operation procedure parsing was developed to shift reduce parsing. This methodmakes use of a stack to store tokens that have not yet been recognized in terms of the grammar.The actions of the parser are controlled by entries in a table, which is somewhat similar to theprecedence matrix. The two main actions of shift reducingparsing are

    Shift: Push the current token into the stack.

    Reduce: Recognize symbols on top of the stack according to a rule of a grammar

    Example: BEGIN READ ( id ) . . .

    Steps Token Stream Stack1. . . . BEGIN READ ( id ) . . .

    2. . . . BEGIN READ ( id )

    Shif

  • 8/4/2019 Syssft Compiled Nksrinath

    15/98

    15

    BEGIN

    3. . . . BEGIN READ ( id ) . . .

    READBEGIN

    4. . . BEGIN READ ( id ) . . .(

    READBEGIN

    5. . . . BEGIN READ ( id ) . . .

    id(READ

    BEGIN

    6. . . . BEGIN READ ( id ) . . ..

    < id-list >(

    READBEGIN

    Explanation

    1. The parser shift (pushing the current token onto the stack) when it encounters BEGIN2 to 4. The shift pushes the next three tokens onto the stack.

    5. The reduce action is invoked. The reduce converts the token on the top of the stack

    to a non-terminal symbol from the grammar.6. The shift pushes onto the stack, to be reduced later as part of the READ

    statement.

    Note: Shift roughly corresponds to the action taken by an operator precedence parses

    when it encounters the relation and . Reduce roughly corresponds to

    the action taken when an operator precedence parser encounters the relation .RECURSIVE DESCENT PARSING

    Recursive-Descent is a top-down parsing technique. A recursive-descent parser is madeup of a precedence for each non-terminal symbol in the grammar. When a precedence is called itattempts to find a sub-string of the input, beginning with the current token, that can be interpreted

    as the non-terminal with which the procedure is associated. During this process it may call otherprocedures, or call itself recursively to search for other non-terminals. If the procedure finds thenon-terminal that is its goal, it returns an indication of success to its caller. It also advances thecurrent-token pointer past the sub-string it has just recognized. If the precedence is unable tofind a sub-stringthat can be interpreted as to the desired non-terminal, it returns an indication of failure.

    Example: < read > : : = READ ( < id - list > )

    Shif

    Shif

    Shif

    Shif

    Shif

  • 8/4/2019 Syssft Compiled Nksrinath

    16/98

    16

    The procedure for < read > in a recursive descent parser first examiner the next twoinput, looking for READ and (. If these are found, the procedures for < read > then call theprocedure for < id - list >. If that procedure succeeds, the < read > procedure examines the nextinput token, looking for). If all these tests are successful, the < read > procedure returns anindication of success. Otherwise the procedure returns a failure.There are problems to write a complete set of procedures for the grammar of fig. 15.

    Example: The procedure for < id - list >, corresponding to rule 6 would be unable todecide between its alternatives since id and < id-list > can begin with id. : : = id | < id-list >, id

    If the procedure somehow decided to try the second alternative , it wouldimmediately call itself recursively to find an . This causes unending chain. Top-downparsers cannot be directly used with a grammar that contains this kind of immediate leftrecursion.

    Similarly the problem occurs for rules 3, 7, 10 and 11. Hence the fig. 13 showsthe rules 3, 6, 7, 10 and 11 modification.

    3 < dec - list > : : = < dec > { ; }6 < id - list > : : = id {; id }

    7 < stmt - list > : : = < stmt > { ; < stmt > }10 < exp > : : = < term > { + < term . | -- < term > }11 < term > : : = < factor > { + < factor > | Div < factor >.}

    Fig. 13

    Fig. 14 illustrates a recursive-descent parse of the READ statement: READ(VALUE); The modified grammar is considered in the procedure for the non-terminal and < id-list >. It is assumed that TOKEN contains the type of the next inputtoken.

    PROCEDURE READBEGIN

    ROUND : = FALSE

    IfTOKEN + 8 { read } THENBEGIN

    advance to next tokenIF TOKEN + 20 { ( } THEN

    BEGINadvance to next tokenIF IDLIST returns success THEN

    IF token = 21 { ) } THENBEGIN

    FOUND : = TRUEadvance to next token

    END { if ) }

    END { if READ }IF FOUND = TRUE THENreturn success

    else failureend (READ)

    Fig. 14

    Procedure IDLIST

  • 8/4/2019 Syssft Compiled Nksrinath

    17/98

    17

    beginFOUND = FALSEif TOKEN = 22 {id} then

    beginFOUND : = TRUE advance to Next tokenwhile (TOKEN = 14 {,}) and (FOUND = TRUE) do

    beginadvance to next tokenif TOKEN = 22 {id} then

    advance to next tokenelseFOUND = FALSE

    End {while}End {if id}

    if FOUND : = TRUE thenreturn success

    elsereturn failure

    end {IDLIST}

    Fig. 15The fig. 15 IDLIST procedure shows an error message if ( , ) is not followed by a id. It

    indicates the failure in the return statement. If the sequence of tokens such as " id,id " could be alegal construct according to the grammar, this recursive-descent technique would not workproperly.

    Fig. 16 shows a graphic representation of the recursive parsing process for thestatement being analyzed.

    (i) In this part, the READ procedure has been invoked and has examined the tokensREAD and ' ( " from the input stream (indicated by the dashed lines).

    (ii) In this part, the READ has called IDLIST (indicated by the solid line), which hasexamined the token id.

    (iii) In this part, the IDLIST has returned to READ indicating success; READ hasthen examined the input token.

    Note that the sequence of procedure calls and token examinations has completely definedthe structures of the READ statement. The parser tree was constructed beginning at the root,hence the term top-down parsing.

    (i) (II) (iii)

    READ READ READ( ( (

    id id{ Value } { Value

    Fig. 16

    Fig. 17 illustrates a recursive discard parse of the assignment statement.

    Variance: = SUNSQ DIVISION - MEAN * MEAN

    The fig. 17 shows the procedures for the non-terminal symbols that areinvolved in parsing this statement.

    REA

    REA

    REA

  • 8/4/2019 Syssft Compiled Nksrinath

    18/98

    18

    Procedure ASSIGNbegin

    FOUND = FALSEif TOKEN = 22 {id} then

    begin

    advance to Next tokenif TOKEN = 15 {: =} thenbegin

    advance to next tokenifEXP returns success then

    FOUND : = TRUEend {if : =}

    if FOUND : = TRUE thenreturn success

    elsereturn failure

    end {ASSIGN}

    Procedure EXPbegin

    FOUND = FALSEIf TERM returns success then

    beginFOUND: = TRUEwhile ((TOKEN = 16 {+ } ) or (TOKEN = 17 { - } ) )

    and (FOUND = TRUE) dobegin

    advance to next tokenif TERM returns success then

    FOUND = FALSE

    end {while}end {if TERM}

    if FOUND : = TRUE thenreturn success

    elsereturn failure

    end {EXP}Procedure TERM

    beginFOUND : = FALSE

    If FACTOR returns success thenbegin

    FOUND : = TRUEwhile ((TOKEN = 18 { * }) or (TOKEN = 19 {DIV })

    and (FOUND = TRUE) dobegin

    advance to next tokenif TERM returns failure then

    FOUND : = FALSEend {while}

    end {if FACTOR}

  • 8/4/2019 Syssft Compiled Nksrinath

    19/98

    19

    if FOUND : = TRUE thenreturn success

    elsereturn failure

    end {TERM}Procedure FACTOR

    beginFOUND : = FALSE

    if (TOKEN = 22 { id } ) or (TOKEN = 23 {int } ) thenbegin

    FOUND : = TRUEadvance to next token

    end { ifid or int }else

    if TOKEN = 20 { ( } thenbegin

    advance to next tokenif EXP returns success then

    if TOKEN = 21 { ) } thenbegin

    (FOUND = TRUE)advance to next token

    end { if ) }end {if ( }

    if FOUND : = TRUE thenreturn success

    elsereturn failure

    end {FACTOR}

    Fig. 17 Recursive-Descent Parse of an Assignment Statement

    A step-by-step representation of the procedure calls and token examination is shown infig. 1

    (i) (ii) (iii)

    id 1 : = id1 : = id 1 : ={ VARIANCE } { VARIANCE } {VARIANCE}

    (iv) (v) (vi)

    id 1 : = id 1 : = id 1 : ={VARIANCE} {VARIANCE} {VARIANCE}

    ASSIGN ASSIGN

    EXP

    ASSIGN ASSIGN

    EXP EXPEXP

    ASSIGN

    TERM

    EXP

  • 8/4/2019 Syssft Compiled Nksrinath

    20/98

    20

    -

    DIV DIV

    id 2 id 2 int id 2 int{SUMSQ} {SUMSQ} {100} {SUMSQ} {100}

    (vii)

    id 1 : ={VARIANCE}

    -

    DIV

    id 2 int id 3{SUMSQ} {100} {MEANS}

    (viii)

    id 1 : =(VARIANCE}

    -

    *DIV DIV

    id 2 int id 3 id 4{SUMSQ} {100} {MEANS} {MEANS}

    Fig. 18 Step by step Representation for Variance : = SUMSQ Div 100 - MEAN * Mean

    GENERATION OF OBJECT CODE

    After the analysis of system, the object code is to be generated. The code generationtechnique used in a set of routine, one for each rule or alternative rule in the grammar. Theroutines that are related to the meaning of he compounding construct in the language is called the

    semantic routines.When the parser recognizes a portion of the source program according to some rule of thegrammar, the corresponding semantic routines are executed. These semantic routines generateobject code directly and hence they are referred as code generation routines. The code generationroutines that is discussed are designed for the use with the grammar in fig. .5. This grammar isused for code generations to emphasize the point that code generation techniques need not beassociated with any particular parsing method.

    TERM

    ASSIGN

    TERMTERMTERM

    FACTOR FACTOR FACTOR FACTOR FACTOR

    ASSIGN

    FACTOR FACTOR

    TERM

    FACTOR

    TERM

    EXP

    FACTOR FACTOR FACTOR FACTOR

    TERM TERM

    EXP

  • 8/4/2019 Syssft Compiled Nksrinath

    21/98

    21

    The parsing technique discussed in 1.3 does not follow the constructs specified by thisgrammar. The operator precedence method ignores certain non-terminal and the recursive-descentmethod must use slightly modified grammar.

    The code generation is for the SIC/XE machine. The technique use two data structure:(1) A List (2) A Stack

    List Count: A variableList count is used to keep a count of the number of itemscurrently in the list. The token specifiers are denoted by ST (token)

    Example: id ST (id) ; name of the identifierint ST (int) ; value of the integer, # 100

    The code generation routines create segments of object code for the compiled program.A symbolic representation is given to these codes using SIC assemblerlanguage.

    LC (Location Counter): It is a counter which is updated to reflect the next variableaddress in the compiled program (exactly as it is in an assembler).

    Application Process to READ Statement:

    (read) + JSUB XREADWORD 1

    < id - list > WORD VALUEREAD ( )

    {VALUE}

    Fig. 19(a) Parse Tree for Read

    Using the rule of the grammar the parser recognizes at each step the left most sub-stringof the input that can be interpreted. In an operator precedence parse, the recognition occurs whena sub-string of the input is reduced to some non-terminal .

    In a recursive-descent parse, the recognition occurs when a procedure returns to its

    caller, indicating success. Thus the parser first recognizes the id VALUE as an < id - list >, andthen recognizes the complete statement as a < read >.

    The symbolic representation of the object code to be generated for the READ statement isas shown in fig. 19(b). This code consists of a call to a statement XREAD, which world be a partof a standard library associated with the compiler. The subroutine any program that wants toperform a READ operation can call XREAD. XREAD is linked together with the generatedobject program by a linking loader or a linkage editor. The technique is commonly used for thecompilation of statements that perform voluntarily complex functions. The use of a subroutineavoids the repetitive generation of large amounts of in-line code, which makes the object programsmaller.

    The parameter list for XREAD is defined immediately after the JSUB that calls it. Thefirst word is the number of variable that will be assigned values by the READ. The following

    word gives the addresses of three variables.Fig. 19(c) shows the routines that might be used to accomplish the codegeneration.

    1. < id - list > : : = idadd ST (id) to listadd 1 to List_count

    2. < id - list > : : = < id - list >, idadd ST (id) to list

  • 8/4/2019 Syssft Compiled Nksrinath

    22/98

    22

    add 1 to LC List_Current3. < read > : : = READ (< id - list >)

    generate [ + JSUB XREAD ]record external reference to XREADgenerate [WORD List - count]for each item on list ofdo

    beginremove ST (ITEM) from listgenerate [WORD ST (ITEM)]

    endList _count : = 0

    Fig. 19 (c) Routine for READ Code Generation

    The first two statements (1) and (2) correspond to alternative structure for < id - list >,that is < id - list > : : = id | < id - list >, id.

    In each case the token specifies ST (id) for a new identifier being called to the < id - list >is inserted into the list used by the code-generation routine, and list-count is updated to reflect theinsertion. After the entire < id-list > has been parsed, the list contains the token specifiers for all

    the identifiers that are part of the < id- list >. When the < read > statement is recognized, thetoken specifiers are removed from the list and used to generate the object code for the READ.

    Code-generation Process for the Assignment Statement

    Example: VARIANCE: = SUMSQ DIV 100 - MEAN * MEAN

    The parser tree for this statement is shown in fig. 20. Most of the work of parsinginvolves the analysis of the < exp > on the right had side of the " : = " statement.:

    < assign >

    < exp >

    < exp > < exp >(term)

    < term >

    < term > < term > < factor >

    < factor >< factor > < factor >

    id : = id DIV int _ id * id{VARIANCE} { SUMSQ } {100} {MEAN} {MEAN}

    Fig. 20

    The parser first recognizes the id SUMSQ as a < factor > and < term > ; then itrecognizes the int 100 as a < factor >; then it recognizes SUNSQ DIV 100 as a < term >, and so

  • 8/4/2019 Syssft Compiled Nksrinath

    23/98

    23

    forth. The order in which the parts of the statements are recognized is the same as the order inwhich the calculations are to be performed. A code-generation routine iscalled for each portion of the statement is recognized.

    Example; For a rule < term >1: : = < term > 2 * < factor > a code is to be

    generated.

    The subscripts are used to distinguish between the two occurrences of < term > .The code-generation routines perform all arithmetic operations using register A. Hence

    the multiple < term >2 * < factor > after multiplication is available in register A. Beforemultiplication one of the operand < term >2 must be located in A-register. The results aftermultiplication will be left in register A. So we need to keep track of the result left in register Aby each segment of code that is generated. This is accomplished by extending the token-specifieridea to non-terminal nodes of the parse tree.

    The node specifier ST (< term1>) would be set to rA, indicating that the result of thecompletion is in register A. the variable REGA is used to indicate the highest level node of theparse tree when value is left in register A by the code generated so far. Clearly there can be onlyone such node at any point in the code-generation process. If the value corresponding to a node is

    not in register A, the specifier for the node is similar to a token specifier: either a pointer to asymbol table entry for the variable that contains the value or an integer constant.

    Fig. 21 shows the code-generation routine considering the A-register of themachine.

    1. < assign > : : = id := < exp >GETA (< exp >)generate [ STA ST (id)]REGA : = null

    2. :: =< term >ST < exp > : = ST (< term >)if ST < exp > = rA then

    REGA : = < exp >

    3. < exp >1 : : = < exp >2 + < term >if SR (< exp >2) = rA then

    generate [ADD ST (< term >)]else if ST (< term >) = rA then

    generate [ADD ST (< exp >2)]else

    beginGETA (< EXP >2)generate [ADD ST(< term >)]

    endST (< exp >1) : = rAREGA : = < exp >1

    4. < exp >1 : : = < exp >2 - < term >if ST (< exp >2) = rA then

    generate [SUB ST (< term >)]else

    beginGETA (< EXP >2)generate [ SUB ST (< term >)]

    end

  • 8/4/2019 Syssft Compiled Nksrinath

    24/98

    24

    SR (< exp >1) : = rAREGA : = < exp >1

    5. < term > : : = < factor >ST (< term >) : = ST (< factor >)if ST () = rA thenREGA : = < term >

    6. < term >1 : : = < term >2 * < factor >if ST (< term >2) = rA then

    generate [ MUL ST (< factor >)]else if S (< factor >) = rA then

    generate [ MUL ST (< term >2)]else

    beginGETA (< term >2)generate [ MUL SrT(< factor >)]

    endST (< term >1) : = rAREGA : = < term >1

    7. < term > : : = < term >2 DIV < factor >if SR (< term >2) = rA then

    generate [DIV ST(< factor >)]else

    beginGETA (< term >2)generate [ DIV ST (< factor >)]

    endSR (< term >1) : = rAREGA : = < term >1

    < factor > : : = idST (< factor >) : = ST ( id)

    9. < factor > : : = intST (< factor >) : = ST ( int)

    10. < factor > : : = < exp >ST (< factor >) : = ST (< exp >)if ST (< factor >) = rA thenREGA : = < factor >

    Fig. 21 Code Generation Routines

    If the node specifies for either operand is rA, the corresponding value is already inregister A, the routine simply generates a MUL instruction. The node specifier for the otheroperand gives the operand address for this MUL. Otherwise, the procedure GETA is called. The

    GETA procedure is shown in fig. 22.

    Procedure - GETA (NODE)begin

    ifREGA = null thengenerate [LDA ST (NODE) ]

    else if ST (NODE) rA thenbegin

    creates a new looking variable Tempi

  • 8/4/2019 Syssft Compiled Nksrinath

    25/98

    25

    generate [STA Tempi]record forward reference to TempiST (REGA) : = TempiGenerate [LDA ST (NODE)]

    end (if rA)ST(NODE) : = rA

    REGA : = NODEend {GETA }

    Fig. 22

    The procedure GETA generates a LDA instruction to load the values associated to 2 into register A. Before loading the value into A-register, it confirms whether A is null.If it is not null it generates STA instruction to save the contents of register-A into Temp-variable.There can be number of Temp variable like Temp 1, Temp2 . . . etc. The temporary variables usedduring a completion will be assigned storage location at the end of the object program. The nodespecifies for the node associated with the value previously in register A, indicated by REGA isreset to indicate the temporary variable used.

    After the necessary instructions are generated, the code-generation routine sets ST (1) and REGA to indicate that the value corresponding to < terms >1 is now in register A.This completes the code-generation action for the * operation.

    The code-generation routine for ' + ' operation is the same as the ' * ' operation. Theroutine ' DIV ' and ' - ' are similar except that for these operations it is necessary for the firstoperand to be in register A. The code generation for < assign > consists of bringing the value tobe assigned into register A (using GETA) and then generating a STA instruction.

    The remaining rules in fig. 21 do not require the generation of any instruction since nocomputation and data movement is involved.

    The object code generated for the assignment statement is shown in fig. 22.

    LDA SUMSQDIV * 100

    STA TMP1LDA MEANMUL MEANSTA TMP2LDA TMP1SUB TMP2STA VARIABLE

    Fig. 22

    For the grammar < prog > the code-generation routine is shown in fig. 23. When is recognized, storage locations are assigned to any temporary (Temp) variables that have beenused. Any references to these variables are then fixed in the object code using the same process

    performed for forward references by a one-pass assembler. The compiler also generates anymodification records required to describe external references to library subroutine.

    < prog > : : = PROGRAM < prog-name > VAR < dec list >BEGIN < stmp -- list > END.

    generate [LDL RETADR]generate [RSUB]

    for each Temp variable used do

  • 8/4/2019 Syssft Compiled Nksrinath

    26/98

    26

    generate [ Temp RESW 1]insert [ J EXADDR ] {jump to first executable instruction}

    in bytes 3 - 5 of object program. fix up forward reference to Tempvariables generate modification records for external references generates[END].

    The < prog-name > generates header information in the object program that is similar tothat created from the START and EXTREF as assembler directives. It also generates instructionsto save the return address and jump to the first executable instruction in the compiled program.Fig. 24 shows the code generation routine for thegrammar < prog-name >.

    < Program > : : = idgenerate [START 0]generate [EXTREF XREAD, XWRITE]generate [STL RETADR]

    add 3 to LC {leave room for jump to first executable instruction}generate [RETADR RESW 1]

    Fig. 24

    Similar to the previous code-generation routine fig. 25 shows the code-generation for < dec - list >, < dec > , < write >, < for > , < index - exp > and body.

    < dec - list > : : = { alternatives }

    save LC as EXADDR {tentative address of first executableinstruction}

    < dec > : : = > id - list > : < type >for each item on list do

    begin

    remove ST (NAME) from listenter LC symbol table as address for NAMEgenerate [ST (NAME) RESW 1]end

    LIST COUNT : = 0

    < write > : : = WRITE ( < id - list > )generate [ + JSUB XWRITE]record external reference to XWRITEgenerate [WORD LISTCOUNT]

    for each item on list dobegin

    remove ST (ITEM) from listgenerate [WORD ST (ITEM)]

    endLIST COUNT : = 0

    < for > : : = FOR < id ex -- exp > Do < body >POP JUMPADDR from stack {address of jump out of loop}POP ST (INDEX) from stack {index variable}POP LOOPADDR from stack {beginning address of loop}

  • 8/4/2019 Syssft Compiled Nksrinath

    27/98

    27

    generate [LDA ST (INDEX)]generate [ADD #1]generate [ J LOOPADDR]insert [ JGT LC ] at location JUMPADDR

    < index - exp > : : = id : = < exp > | TO < exp >2

    GETA (< exp >;)Push LC onto stack {beginning addressing loop}Push ST (id) onto stack {index variable}Generate [STA ST (id)]Generate [ COMP ST (< exp > 2)]Push LC onto stack {address of jump out of loop}and 3 to LC [ leave room for jump instruction]REGA : = null

    Fig. 25

    There are no code-generation for the statements

    < type > : : = INTEGER

    < stmt - list > : : = {either alternative}< stmt > : : = {any alternative}< body > : : = {either alternative}

    For the Pascal program in fig. 1 the complete code-generation process is shown infig. 26.

    1 STATS START 0 {Program Header}EXTREF XREAD, XREAD, XWRITESTL TETADR {Save return address}J {EXADDR}

    2 RETADDR RESW 1

    3 SUM RESW 1SUMSQ RESW 1I RESW 1

    VALUE RESW 1MEAN RESW 1VARIANCE RESW 1

    5 {EXADDR} LDA # 0 {SUM = 0}STA SUM

    6 LDA # 0 {SUMSQ : = 0}STA SUMSQ

    7 LDA # 1 {FOR I : = 1 TO 100}

    {L1} STA ICOMP # 100JGT {L2}

    9 + JSUB X READ {READ (VALUE) }WORD 1WORD VALUE

    10 LDA SUM {SUM : = SUM +VALUE}

  • 8/4/2019 Syssft Compiled Nksrinath

    28/98

    28

    ADD VALUESTA SUM

    11 LDA VALUE {SUMSQ : = SUMSQ * VALUE *VALUE}

    MUL VALUE

    ADD SUMSQSTA SUMSQLDA I {END OF FOR LOOP}ADD # 1J {L1}

    13 {L2} LDA SUM {MEAN : = SUMDIVISION}

    DIV # 100STA MEAN

    14 LDA SUM {VARIABLE : = SUMSQ DIVDIV # 100 100 - MEAN * MEAN}

    STA TEMP1LDA MEANMUL MEANSTA TEMP2LDA TEMP1SUB TEMP2STA VARIANCE

    15 +JSUB XWRITE {WRITE (MEAN, VARIANCE) }WORD 2WORD MEANWORD VARIABLELDL RETADRRSUB

    TEMP 1` RESW 1 {WORKING VARIABLE USED}TEMP 2 RESW 1

    END

    Fig. 25 Object Code Generated for Pascal Program

    8.1 MACHINE DEPENDENT COMPILER FEATURESAt an elementary level, all the code generation is machine dependent. This is because, we

    must know the instruction set of a computer to generate code for it. There aremany more complex issues involved. They are:

    Allocation of register Rearrangement of machine instruction to improve efficiency of execution

    Considering an intermediate form of the program being compiled normally does suchtypes of code optimization. In this intermediate form, the syntax and semantics of the sourcestatements have been completely analyzed, but the actual translation into machine code has notyet been performed. It is easier to analyze and manipulate this intermediate code than to performthe operations on either the source program or the machine code. The intermediate form made ina compiler, is not strictly dependent on the

  • 8/4/2019 Syssft Compiled Nksrinath

    29/98

    29

    machine for which the compiler is designed.

    8.1.1 INTERMEDIATE FORM OF THE PROGRAMThe intermediate form that is discussed here represents the executable instruction

    of the program with a sequence of quadruples. Each quadruples of the form

    Operation, OP1, OP2, result.WhereOperation - is some function to be performed by the object codeOP 1 & OP2 - are the operands for the operation andResult - designation when the resulting value is to be placed.

    Example 1: SUM : = SUM + VALUE could be represented as+ , SUM, Value, i, i1: = i1 , , SUM

    The entry i1, designates an intermediate result (SUM + VALUE); the second quadrupleassigns the value of this intermediate result to SUM. Assignment is treated as aseparate operation ( : =).

    Example 2 : VARIANCE : = SUMSQ, DIV 100 -- MEAN * MEANDIV, SUMSQ, #100, i1*, MEAN, MEAN, i2- , i1, i2, i3

    : : = i3 , VARIABLE

    Note: Quadruples appears in the order in which the corresponding object codeinstructions are to be executed. This greatly simplifies the task of analyzing thecode for purposes of optimization. It is also easy to translateinto machine instructions.

    For the source program in Pascal shown in fig. 1. The corresponding quadruples are

    shown in fig. 27. The READ and WRITE statements are represented with a CALL operation,followed by PARM quadruples that specify the parameters of the READ or WRITE. The JGToperation in quadruples 4 in fig. 27 compares the values of its two operands and jumps toquadruple 15 if the first operand is greater than the second. The J operation in quadruples 14jumps unconditionally to quadruple 4.

    Line Operation OP 1 OP 2 Result Pascal Statement

    1. : = # 0 SUM SUM : = 02. : = # 0 SUMSQ SUMSQ : = 03. : = # 1 I FOR I : = 1 to 1004. JGT I #100 (15)

    5. CALL XREAD READ (VALUE)6. PARAM VALUE7. + SUM VALUE i1 SUM : = SUM + VALUE

    ; = i1 SUM9. * VALUE VALUE i2 SUMSQ : = SUMSQ + VALUE

    10. + SUMSQ i2 i3 *VALUE

    11. : = i3 SUMSQ12. + I #1 i4 End of FOR loop

  • 8/4/2019 Syssft Compiled Nksrinath

    30/98

    30

    13. : = i4 I14. J (4)15. DIV SUM #100 i5 MEAN : = SUM DIV 10016. : = i5 MEAN17. DIV SUMSQ #100 i6 VARIANCE : =1 * MEAN MEAN i7 SUMSQ DIV 100

    19. - i6 i7 i8 - MEAN * MEAN20. : = i8 VARIANCE21. CALL XWRITE WRITE (MEAN, VALIANCE22. PARAM MEAN23. PARAM VARIANCE

    Fig. .27 Intermediate Code for the Pascal Program

    8.1.2 MACHINE - DEPENDENT CODE OPTIMIZATIONThere are several different possibilities for performing machine-dependent code

    optimization .

    -- Assignment and use of registers: Here we concentrate the use of registers asinstruction operand. The bottleneck in all computers to perform with high speed is the access ofdata from memory. If machine instructions use registers as operands the speed of operation ismuch faster. Therefore, we would prefer to keep in registers all variables and intermediate resultthat will be used later in the program.

    There are rarely as many registers available as we would like to use. The problem thenbecomes which register value to replace when it is necessary to assign a register for some otherpurpose. On reasonable approach is to scan the program for the next point at which each registervalue would be used. The value that will not be needed for the longest time is the one that shouldbe replaced. If the register that is being reassigned contains the value of some variable alreadystored in memory, the value can simply be discarded. Otherwise, this value must be saved using atemporary variable. This is one of the functions performed by the GETA procedure. In using

    register assignment, a compiler must also consider control flow of the program. If they are jumpoperations in the program, the register content may not have the value that is intended. Thecontents may be changed. Usually the existence of jump instructions creates difficulty in keepingtrack of registers contents. One way to deal with the problem is to divide the problem into basicblocks.

    A basic block is a sequence of quadruples with one entry point, which is at the beginningof the block, one exit point, which is at the end of the block, and no jumps within the blocks.Since procedure calls can have unpredictable effects as register contents, a CALL operation isusually considered to begin a new basic block. The assignment and use of registers within a basicblock can follow as described previously. When control passes from one block to another, allvalues currently held in registers are saved in temporary variables.

    For the problem is fig. .27, the quadruples can be divided into five blocks. They are:

    Block -- A Quadruples 1 - 3

    Block -- B Quadruples 4

    Block -- C Quadruples 5 - 14

    A : 1 - 3

    B : 4

    C : 5 - 14

    D : 15 -

  • 8/4/2019 Syssft Compiled Nksrinath

    31/98

    31

    Block -- D Quadruples 15 - 20

    Block -- E Quadruples 21 - 23

    Fig. 28

    Fig. 28 shows the basic blocks of the flow group for the quadruples in fig. 27. An arrow

    from one block to another indicates that control can pass directly from one quadruple to another.This kind of representation is called a flow group.

    -- Rearranging quadruples before machine code generation:

    Example : 1) DIV SUMSQ # 100 i12) * MEAN MEAN i23) - i1 i2 i34) : = i3 VARIANCE

    LDA SUMSQ LDA T1

    DIV # 100 SUB T2STA T1 STA VARIANCELDA MEANMUL MEANSTA T2

    Fig. 29

    Fig. 29 shows a typical generation of machine code from the quadruples using only asingle register.

    Note that the value of the intermediate result, is calculated first and stored in temporaryvariable T1. Then the value of i2 is calculated subtracting i2 from ii.

    Even though i2 value is in the register, it is not possible to perform the subtraction

    operation. It is necessary to store the value of i2 in another temporary variable T2 and then loadthe value of i1 from T1 into register A before performing the subtraction.

    The optimizing compiler could rearrange the quadruples so that the second operand of thesubtraction is computed first. This results in reducing two memoryaccesses. Fig. 29 shows the rearrangements.

    * MEAN MEAN i2DIV SUMSQ # 100 i1- i1 i2 i3:= i3 VARIANCE

    LDA MEAN

    MUL MEANSTA T1LDA SUMSQDIV # 100SUB T1STA VARIANCE

    Fig. 29 Rearrangement of Quadruples for Code Optimization

    -

  • 8/4/2019 Syssft Compiled Nksrinath

    32/98

    32

    -- Characteristics and Instructions of Target Machine: These may be special loop -control instructions or addressing modes that can be used to create more efficient object code. Onsome computers there are high-level machine instructions that can perform complicated functionssuch as calling procedure and manipulating data structures in a single operation.

    Some computers have multiple functional blocks. The source code must be rearranged touse all the blocks or most of the blocks concurrently. This is possible if the result of one block

    does not depend on the result of the other. There are some systems where the data flow can bearranged between blocks without storing the intermediate data in any register. An optimizingcompiler for such a machine could rearrange object codeinstructions to take advantage of these properties.

    Machine Independent Compiler Features

    Machine independent compilers describe the method for handling structured variablessuch as arrays. Problems involved in compiling a block-structured languageindicate some possible solution.

    3.1 STRUCTURED VARIABLES

    Structured variables discussed here are arrays, records, strings and sets. The primarily

    consideration is the allocation of storage for such variable and then thegeneration of code to reference then.

    Arrays: In Pascal array declaration -

    (i) Single dimension array: A: ARRAY [ 1 . . 10] OF INTEGER

    If each integer variable occupies one word of memory, then we require 10 words ofmemory to store this array. In general an array declaration is ARRAY [ l .. u ] OF INTEGER

    Memory word allocated = ( u - l + 1) words.

    (ii) Two dimension array : B : ARRAY [ 0 .. 3, 1 . . 3 ] OF INTEGERIn this type of declaration total word memory required is 0 to 3 = 4 ; 1 - 3 = 3 ; 4 x 3 =

    12 word memory locations.In general: ARRAY [ l1 .. u1, l2 . . u2.] OF INTEGER Requires ( u1 - l1 + 1) * ( u2 - l2 +

    1) Memory wordsThe data is stored in memory in two different ways. They are row-major and column

    major. All array elements that have the same value of the first subscript are stored in contiguouslocations. This is called row-major order. It is shown in fig. 30(a). Another way of looking at thisis to scan the words of the array in sequence and observe the subscript values. In row-majororder, the right most subscript varies most rapidly.

    0,1 0,2 0,3 0,4 0,5 0,1 1,2 1,3 1,4 1,5 2,1 2,2 2,3 2,4 2,5 . . .

    Row 0 Row 1 Row 2

    Fig. 30 (a)

    Fig. 30(b) shows the column major way of storing the data in memory. All elements thathave the same value of the second subscript are stored together; this is called column major order.In other words, the column major order, the left most subscript varies most rapidly.

    To refer to an element, we must calculate the address of the referenced element relative tothe base address of the array. Compiler would generate code to place the relative address in anindex register. Index addressing mode is made easier to access the desired array element.

    (1) One Dimensional Array: On a SIC machine to access A [6], the address is

  • 8/4/2019 Syssft Compiled Nksrinath

    33/98

    33

    calculated by starting address of data + size of each data * number of preceding data.

    i.e. Assuming the starting address is 1000HSize of each data is 3 bytes on SIC machineNumber of preceding data is 5

    Therefore the address for A [ 6 ] is = 1000 + 3 * 5 = 1015. In general for A: ARRAY [ l .

    . u ] of integer, if each array element occupies W bytes of storage and if the value of the subscriptis S, then the relative address of the referred element A[ S ] is given by W * ( S - l ).

    The code generation to perform such a calculation is shown in fig. 31.The notation A[ i2 ] in quadruple 3 specifies that the generated machine code should refer

    to A using index addressing after having placed the value

    A: ARRAY [ 1 . . 10 ] OF INTEGER...A[ I ] : = S

    (1) - I # 1 i1+ i1 # 3 i2: = #5 A[i1 ]

    Fig. 31 Code Generation for Single Dimension Array of i2 in the Index Register(2) Multi-Dimensional Array: In multi-dimensional array we assume row major order.

    To access element B[ 2,3 ] of the matrix B[ 6, 4 ], we must skip over two complete rows beforearriving at the beginning of row 2. Each row contains 6 elements so we have to skip 6 x 2 = 12array elements before we come to the beginning of row 2 to arrive at B[ 2, 3 ]. To skip over thefirst two elements of row 2 to arrive at B[ 2, 3 ]. This makes a total of 12 + 2 = 14 elementsbetween the beginning of the array and element B[2, 3 ]. If each element occurs 3 byte as in SIC,the B[2, 3] is located relating at 14 x 3 = 42 address within the array.

    Generally the two dimensional array can be written asB ; ARRAY [ l1 . . . u1, l1 . . . u1, ] OF INTEGER

    The code to perform such an array reference is shown in fig. 32.

    B : ARRAY [ 0 . . 3, 1 . . 6 ] OF INTEGER..B[I, J] : = 5

    1) * I # 6 i1-- j # 1 i2+ i1 i2 i3* i3 #3 i4: = # 5 A [ i1 ]

    Fig. 32 Code Generation for Two Dimensional Array

    The symbol - table entry for an array usually specifies the following:

    The type of the elements in the array The number of dimensions declared The lower and upper limit for each subscript.

  • 8/4/2019 Syssft Compiled Nksrinath

    34/98

    34

    This information is sufficient for the compiler to generate the code required for arrayreference. Some of the languages line FORTRAN 90, the values of ROWS and COLUMNS arenot known at completion time. The compiler cannot directly generate code. Then, the compilercreate a descriptor calleddope vectorfor the array. The descriptor includes space for storing thelower and upper bounds for each array subscript. When storage is allocated for the array, thevalues of these bounds are computed and stored in the descriptor. The generated code for one

    array reference uses the values from the descriptor to calculate relative addresses as required.The descriptor may also include the number of dimension for the array, the type of the arrayelements and a pointer to the beginning of the array. This information can be useful if theallocated array is passed as a parameter to another procedure.

    In the compilation of other structured variables like recode, string and sets the same typeof storage allocations are required. The compiler must store information concerning the structureof the variable and use the information to generate code to access components of the structure andit must construct a description for situation in which the required conformation is not known atcompilation time.

    8.3.1 MACHINE - INDEPENDENT CODE OPTIMIZATIONOne important source of code optimization is the elimination of common sub-expressions. These are sub-expressions that appear at more than one port in the program

    and that compute the same value. Let us consider the example in fig. 33.

    x, y : ARRAY [ 0 . . 10, 1 . . 10 ] OF INTEGER...FOR I : = 1 TO 10 DO

    X [ I, 2 * J - 1 ] : = [ I, 2 * J }

    Fig. 33(a)

    The sub-expression 2 * J is calculated twice. An optimizing compiler should generatecode so that the multiplication is performed only once and the result is used in both places.Common sub-expressions are usually detected through the analysis of an intermediate form of theprogram. This intermediate form is shown in fig. 33(b).

    Line Operation OP 1 OP 2 Result Pascal Statement

    1. : = #1 I [Loop initialization]2. JGT I #10 (20)3. - I #1 i1 [Subscript calculation for x]4. * i1 #10 i25. * #2 J i36. -- i3 #1 i47. -- i4 #1 i5

    + i2 i5 i69. * i6 #3 i7

    10. -- I #1 i8 [Subscript Calculation for y]11. * i8 #10 i912. * #2 J i1013. -- i10 3 1 i11

  • 8/4/2019 Syssft Compiled Nksrinath

    35/98

    35

    14. + i9 i11 i1215. * i12 # 3 i1316. : = y [ i13 } x[ i17 ] [Assignment Operation]17. + #1 I i17 [End of Loop]1 : = i14 I19. J (2)

    20. [Next Statement]

    Fig. 33(b)

    Examining fig. 33(b), the sequence of quadruples, we observe that quadruples 5 and 12are the same except for the name of the intermediate result produced. The operand J is notchanged in value between quadruples 5 and 12. It is not possible to reach quadruple 12 withoutpassing through quadruple 5 first because the quadruples are part of the same basic block.Therefore, quadruples 5 and 12 compute the same value. This means we can delete quadruple 12and replace any reference to its result ( i10 ), with the reference to i3, the result of quadruple 5. thisinformation eliminates the duplicate calculation of 2 * J which we identified previously as acommon expression in the source statement.

    After the substitution of i3 for i10 , quadruples 6 and 13 are the same except for the name

    of the result. Hence the quadruple 13 can be removed and substitute i4 fori11 wherever it is used.Similarly quadruple 10 and 11 can be removed because they are equivalent to quadruples 3 and 4.

    Line Operation OP 1 OP 2 Result Pascal Statement

    1. : = #1 I [Loop initialization]2. JGT I #10 (16)3. - I #1 i1 [Subscript calculation for x]4. * i1 #10 i25. * # 2 J i36. - i3 #1 i47. - i4 # 1 i5

    + i2 i5 i69. * i6 # 3 i7

    10. + i2 i4 i12 [Subscript Calculation for y]11. * i12 # 3 i1312. : = y [ i13 ] x [i7 ] [assignment Operation]13. + #1 I i14 [End of Loop]14. : = i14 I15. J (2)16. [Next Statement]

    Fig. 34

    Names i1 have been left unchanged, except for the substitutions first described, to makethe compromise with fig. 33(b) easier. This optimized code has only 15 quadruples and hence thetime taken is reduced.

    Another method of code optimization is the removal of loop invariants.There are sub-expressions within the loop whose values do not change from one iteration of the loop to the next.Thus the values can be calculated once, before the loop is entered, rather than being recalculatedfor each iteration. In the example shows in fig. 33(a), the loop-invariant computation is the term 2* J [quadruple 5 fig. 34]. The result of this computation depends only on the operand J, whichdoes not change the value during the execution of the loop. Thus we can move quadruple 5 in fig.

  • 8/4/2019 Syssft Compiled Nksrinath

    36/98

    36

    34 to a point immediately before the loop is entered. A similar arrangement can be applied toquadruples 6 and 7. Fig. 35 shows the sequence of quadruples that result from these modification.

    The total number of quadruples remains the same as fig. 34, however, the number ofquadruples within the body of the loop has been reduced from 14 to 11. Our modification havereduced the total number of quadruples for one execution of the FOR from 181 [Fig. 23 (b) ], to114 [Fig 25], which saves a substantial amount of time.

    Line Operation OP 1 OP 2 Result Pascal Statement

    1. * #2 J i3 {Commutation of invariants}2. - i3 #1 i43. - i4 #1 i54. : = #1 I {Loop Initialization}5. JGT I #10 (16)6. - I #1 i17. * i1 #10 i2 {Subscript calculation for x}

    + i2 i5 i69. * i6 #3 i7

    10. + i2 i4 i12 {Subscript Calculation for y}11. * i12 #3 i1312. : = y [ i13 ] x [i7 ] {assignment Operation}13. + #1 I i14 {End of Loop}14. : = i14 I15. J (5)16. {Next Statement}

    Fig. 35

    -- The optimization can be obtained by rewriting the source program.

    Example; The statement in fig. 36(a) could be written as shown in fig. 36 (b).

    FOR I : = 1 To 10 Dox [ I, 2 * J - 1 ] : = y [ I, 2 * J ]

    Fig. 36(a)

    T1 : = 2 * J ;T2 : = T1 -- 1 ;FOR : = 1 To 10 Dox [ I, T2 ] : = y[ I, T1]

    Fig. 36(b)

    This would achieve only a part of the benefits realized by the optimization process

    described. Some time the statement in fig. 36(a) is preferable because it is clearer than themodified version involving T1 and T2. An optimizing compiler should allow the programmer towrite source code that is clearer and easy to read and it shouldcompile such a program into machine code that is efficient to execute.

    -- Code optimization of another source is the substitution of a more efficient operationfor a less efficient one.

    Example: The FORTRAN statement:

  • 8/4/2019 Syssft Compiled Nksrinath

    37/98

    37

    Do 10 I = 1, 20 ; To calculate the first 20 power of 2 and store it inTABLE ( I ) = 2 * * I ; TABLEIn each iteration of the loop, the constant 2 is raised to the power I. The quadruples are

    shown in fig. 37(a). Exponentiation is represented with the operation EXP.This computation can be performed more efficiently. Here, in each iteration of the loop,

    the value of I is incremented by 1. The value of 2 * * I for the current iteration can be found by

    multiplying the value for the previous iteration by 2. This method of computing 2 * * I is muchmore efficient than performing series of multiplication or using a logarithms technique.

    This technique is shown in fig. 37(b).

    Line Operation OP 1 OP 2 Result Pascal Statement

    1. : = #1 I {Loop Initialization}2. EXP #2 I i1 { Calculation of 2 *3. -- I #1 i5 {Subscript calculation }4. * i2 #3 i35. : = i1 TABLE [ i2] {Assignment Operation}6. + I #1 i4 {End of the Loop}

    7. : = i4 IJLE I #20 i3

    Fig. 37(a)

    Line Operation OP 1 OP 2 Result Pascal Statement

    1. : = #1 i1 {Initialize temporaries}2. :: = # (-3) i33. : = #1 I {Loop Initialization}4. * i1 #2 i1 { Calculation of 2 * * I }

    5. + i3 #3 i3 {Subscript calculation }6. : = i1 TABLE [ i3] {Assignment Operation}7. + I #1 i4 {End of the Loop}

    : = i4 I9. JLE I #20 (4)

    Fig. 37(b)

    STORAGE ALLOCATION

    All the program defined variable, temporary variable, including the location used to savethe return address use simple type of storage assignment called static allocation.

    When recursively procedures are called, static allocation cannot be used. This is

    explained with an example. Fig. 38(a) shows the operating system calling the program MAIN.The return address from register 'L' is stored as a static memory location RETADR within MAIN.

    SYSTEM SYSTEM SYSTEM

    (1) MAIN (1) MAIN (1) MAIN

    CALL SUB

    RETADR

    CALL SUB

  • 8/4/2019 Syssft Compiled Nksrinath

    38/98

    38

    (2) (2)

    (a) SUB

    (b) (3)

    (c) (c)

    Fig. 38

    In fig. 38(b) MAIN has called the procedure SUB. The return address for the call hasbeen stored at a fixed location within SUB (invocation 2). If SUB now calls itself recursively asshown in fig. 38(c), a problem occurs. SUB stores the return address for invocation 3 into

    RETADR from register L. This destroys the return address for invocation 2. As a result, there isno possibility of ever making a correct return to MAIN.

    There is no provision of saving the register contents. When the recursive call is made,variable within SUB may set few variables. These variables may be destroyed. However, theseprevious values may be needed by invocation 2 or SUB after the return from the recursive call.Hence it is necessary to preserve the previous values of any variables used by SUB, includingparameters, temporaries, return addresses, register save areas etc., when a recursive call is made.This is accomplished with a dynamic storage allocation technique. In this technique, eachprocedure call creates an activation record that contains storage for all the variables used by theprocedure. If the procedure is called recursively, another activation record is created. Eachactivation record is associated with a particular invocation of the procedure, not with the itself.An activation record is not deleted until a return has been made from the corresponding

    invocation.Activation records are typically allocated on a stack, with the correct record at the tip of

    the stack. It is shown in fig. 39(a). Fig. 39(a) corresponds to fig. 39(b). The procedure MAIN hasbeen called; its activation record appears on the stack. The base register B has been set to indicatethe starting address of this correct activation record. The first word in an activation record wouldnormally contain a pointer PREV to the previous record on the stack. Since the record is the first,the pointer value is null. The second word of the activation record contain a portion NEXT to thefirst unused word of the stack, which will be the starting address for the next activation recordcreated. The third word contain the return address for this invocation of the procedure, and thenecessary words contain the values of variables used by the procedure.

    SYSTEMS

    MAIN

    RETADRNEXT0

    CALL SUB

    RETADR

  • 8/4/2019 Syssft Compiled Nksrinath

    39/98

    39

    Stack

    Fig. 39 (a)

    SYSTEM(1) MAIN

    B

    SUBStack

    Fig. 39(b)

    In fig. 39 (b), MAIN has called the procedure SUB. A new activation record has beencreated on the top of the stack, with register B set to indicate this new current record. The pointers

    PREV and NEXT in the time records have been set as shown.

    SYSTEM(1) MAIN

    B

    Fig. 39 (c) StackIn fig. 39(c), SUB has called itself recursively another activation record has been created

    for this current invocation for SUB. Note that the return address and variable values for the twoinvocations of SUB are kept separate by this process.

    When a procedure returns to its caller, the current activation record (which corresponds tothe most recent invocation) is deleted. The pointer PREV in the deleted record is used toreestablish the previous activation record as the current one, and execution continues.

    SYSTEM(1) MAIN

    CALL SUB

    VariablesFor SUB

    RETADRNEXTPREV

    VariableFor MAINRETADR

    NE XT0

    stacl

    CALL SUB

    VariablesFor SUB

    RETADRNEXT

    PREVVariable

    For MAIN

    RETADR

    NEXT

    PREVVariableFor MAINRETADR

    NEXT

    0

    CALL SUB

    VariablesFor SUB

    RETADRNEXTPREV

    VariableFor MAINRETADR

    NEXT0

    CALL SUB

  • 8/4/2019 Syssft Compiled Nksrinath

    40/98

    40

    B

    SUB

    Fig. 39(d) StackFig. 39(d) shows the stack as it would appear after SUB returns from the recursive call.

    Register B has been reset to point to the instruction record for the previous invocation of SUB.The return address and all the variable values in this activation record are exactly the same asthey were before the recursive call.

    This technique is called automatic allocation of storage. When the technique is used thecompiler must generate code for the reference to variables using some sort of relative addressing.In our example the compiler assigns to each variable an address that is relative to the beginningof the activation record, instead of an actual location within the object program. The address ofthe current activation record is, by convention contained in register B, so a reference to a variableis translated as an instruction that uses base relative addressing. The displacement in thisinstruction is the relative address of the variable within the activation record.

    The compiler must also generate additional code to manage the activation recordsthemselves. At the beginning of each procedure there must be code to create a new activationrecord, linking it to the previous one and setting the appropriate pointers as shown in fig. 39. Thiscode is often called a prologue for the procedure. At the end of the procedure, there must becode to delete the current activation record, resultingpointers as needed. This code is called an epilogue.

    Example: IN FOTRAN 90 :ALLOCATE (MATRIX (ROWS, COLUMNS) )allocation storage for the dynamic array MATRIX with the specified dimensions.

    DE-ALLOCATE MATRIXreleases the storage assigned to MATRIX by a previous ALLOCATE.

    IN PASCAL: NEW (P)allocates storage for a variable and sets the pointer P to indicate the variable just created.DISPOSE (P)

    releases the storage that was previously assigned to the variable pointed to by P.

    In C : MALLCO (SIZE) ; allocate a block of specified size...

    FREE (P) ; frees the storage indicated by pointer P.

    A variable that is dynamically allocated in this way does not occupy a fixed location in anactivation record, so it cannot be referenced directly using base relative addressing. Such a

    variable is usually accessed using indirect addressing through a pointer variable P. Since P doesoccupy a fixed location in the activation record, it can be addressed in the usual way.

    The mechanism to allocate a storage memory to a variable can be done in any ofthe following ways:

    A NEW or MALLOC statement would be translated into a request by theoperating system for an area of storage of the required size.

    The required allocation is handled through a run-time support procedureassociated with the compiler. With this method, a large block of free storage

  • 8/4/2019 Syssft Compiled Nksrinath

    41/98

    41

    called a heap is obtained from the operating system at the beginning of theprogram. Allocations of the storage from the heap are managed by the run-timeprocedure.

    In some systems, the program need not free memory for storage. A run-timegarbage collection procedure scans the pointer in the program and reclaimsareas from the heapthat are no longer used.

    8.3.3 BLOCK - STRUCTURED LANGUAGEA block is a unit that can be divided in a language. It is a portion of a program that has

    the ability to declare its own identifiers. This definition of a block is also meet the units such asprocedures and functions.

    Let us consider a Pascal program with number of procedure blocks as shown in fig. 40.Each procedure corresponds to a block. Note that blocks are rested within other blocks.

    Example: Procedures B and D are rested within procedure A and procedure C is rested withinprocedure B. Each block may contain a declaration of variables. A block may also refer tovariables that are defined in any block that contains it, provided the same names are not redefinedin the inner block. Variables cannot be used outside the block in which they are declared.

    In compiling a program written in a blocks structured language, it is convenient tonumber the blocks as shown in fig. 40. As the beginning of each new block is recognized, it isassigned the next block number in sequence. The compiler can then construct a table thatdescribes the block structure. It is illustrated in fig. 41. The block-level entry gives the nesting depth for each block. The outer most block numberthat is one greater than that of the surrounding block.

    PROCEDURE A ;VAR X, Y, Z : INTEGER ;

    :PROCEDURE B ;VAR W, X, Y : REAL ;

    :PROCEDURE C ;

    VAR W, V : INTEGER ; 1: 3 2

    END { C };:

    END { B };:

    PROCEDURE D ;VAR X, Z : CHAR ;. 2

    .END { D};

    END { A};

    Fig. 40 Nested Blocks in a Program

    Block Surrounding

    Name Number Level Block

  • 8/4/2019 Syssft Compiled Nksrinath

    42/98

    42

    ABCD

    1234

    1232

    --121

    Fig. 41

    Since a name can be declared more than once in a program (by different blocks), eachsymbol-table entry for an identifier must contain the number of the declaring block. Adeclaration of an identifier is legal if there has been no previous declaration of that identifier bythe current block, so there can be several symbolic table entries for the same name. The entriesthat represent declaration of the same name by different blocks can be linked together in thesymbol table with a chain of pointers.

    When a reference to an identifier appears in the source program, the compiler must firstcheck the symbol table for a definition of that identifier by the current block. If not suchdefinition is found, the compiler looks for a definition by the block that surrounds the current one,then by the block that surrounds that and so on. If the outermost block is reached without findinga definition of the identifier, then the reference is an error.

    The search process just described can easily be implemented within a symbol table thatuses hashed addressing. The hashing function is used to locate one definition of the identifier.The chain of definitions for that identifier is then searched for the appropriate entry.

    Most block-structured languages make use of automatic storage allocation. The variablesthat are defined by a block are stored in an activation record that is created each time the block isentered. If a statement refers to a variable that is declared within the current block, this variable ispresent in the current activation record, so it can be accessed in the usual way. It is possible torefer to a variable that is declared in some surrounding block. In that case, the most recentactivation record for that block must be located to access the variable.

    Stack(a) (b)

    Fig. 42 Use of Display for Procedure

    A data structure called display is used to access a variable in surrounding blocks. The

    display contains pointers to the most recent activation records for the current block and for allblocks that surround the current one in the source program. When a block refers to a variable thatis declared in some surrounding block, the generated object code uses the display to find theactivation record that contains this variable.

    Example:

    When a procedure calls itself recursively thus an activation record is created on the stackas a result of the call. Assume procedure C calls itself recursively. It is shown in fig. 42(b) the

    ActivationRecord for

    C

    ActivationRecord for

    B

    ActivationRecord for

    C

    ActivationRecord for

    C

    C

    BC

    B

  • 8/4/2019 Syssft Compiled Nksrinath

    43/98

    43

    record for C is created on the stack as a result of the call. Any reference to a variable declared byC should use this most recent activation record ; the display pointer for C is changed accordingly.Variables that correspond to the previous invocation of C are not accessible for the movement, sothere is no display pointer to thisactivation record.

    Stack Display

    Fig 42(c)

    Now if procedure 'C' call procedure D the resulting stack and display are as illustrated infig. 42(c) . An activation record for D has been created in the usual way and added to the stack.Note, that the display now contains only two pointers: one each to the activation records for Dand A. This is because procedure D cannot refer to variable in B or C, except through parametersthat are passed to it, even though it is called from C.According to the rules for the scope of names in as block-structured language, procedure D canrefer only to variable that are declared by D or by some block that contains D inthe source program.

    8.4 COMPILER DESIGN OPTIONSThe compiler design is briefly discussed in this section. The compiler is divided

    into single pass and multi pass compilers.

    4.1. COMPILER PASSES

    One pass compiler for a subset of the Pascal language was discussed in section 1. In thisdesign the parsing process drove the compiler. The lexical scanner was called when the parserneeded another input token and a code-generation routine was invoked as the parser recognizedeach language construct. The code optimization techniques discussed cannot be applied in total toone-pass compiler without intermediate code-generation. One pass compiler is efficient togenerate the object code.

    One pass compiler cannot be used for translation for all languages. FORTRAN andPASCAL language programs have declaration of variable at the beginning of the program. Anyvariable that is not declared is assigned characteristic by default.

    One pass compiler may fix the formal reference jump instruction without problem as inone pass assembler. But it is difficult to fix if the declaration of an identifier appears after ithas been used in the program as in some programminglanguages.

    Example: X : = Y * Z

    ActivationRecord for

    CActivation

    Record for

    B

    ActivationRecord for A

    Activation D

  • 8/4/2019 Syssft Compiled Nksrinath

    44/98

    44

    If all the variables x, y and z are of type INTEGER, the object code for this statementmight consist of a simple integer multiplication followed by storage of the result. If the variableare a mixture of REAL and INTEGER types, one or more conversion operations will need to beincluded in the object code, and floating point arithmetic instructions may be used. Obviously thecompiler cannot decide what machine instructions to generate for this statement unless instructionabout the operands is available. The statement may even be illegal for certain combinations of

    operand types. Thus a language that allows forward reference to data items cannot be compiled inone pass.

    Some programming language requires more than two passes. Example : ALGOL-98requires at least 3 passes.

    There are a number of factors that should be considered in deciding between one pass andmulti pass compiler designs.

    (1) One Pass Compiles: Speed of compilation is considered important. Computerrunning students jobs tend to spend a large amount of time performing compilations. Theresulting object code is usually executed only once or twice for each compilation, these test runsare not normally very short. In such an environment, improvement in the speed of compilationcan lead to significant benefit in system performance and job turn around time.

    (2) Multi-Pass Compiles: If programs are executed many times for each compilationor if they process large amount of data, then speed of executive becomes more important thanspeed of compilation. In a case, we might prefer a multi-pass compiler design that couldincorporate sophisticated code-optimization technique.

    Multi-pass compilers are also used when the amount of memory, or other systemsresources, is severely limited. The requirements of each pass can be kept smaller if the work bycompilation is divided into several passes.

    Other factors may also influence the design of the compiler. If a compiler is divided intoseveral passes, each pass becomes simpler and therefore, easier to understand, read and test.Different passes can be assigned to different programmers and can be written and tested inparallel, which shortens the overall time require for compiler construction.

    INTERPRETERS

    An interpreter processes a source program written in a high-level language. The maindifference between compiler and interpreter is that interpreters execute a version of the sourceprogram directly, instead of translating it into machine code.

    An interpreter performs lexical and syntactic analysis functions just like compiler andthen translates the source program into an internal form. The internal form may also be asequence of quadruples.

    After translating the source program into an internal form, the interpreter executes theoperations specified by the program. During this phase, an interpreter can be viewed as a set ofsubtractions. The internal form of the program drives the execution of this subtraction.

    The major differences b/w interpreter and compiler are:

    Interpreters Compilers

    1) The process of translating asource

    program into some internalform is

    simpler and faster

    The process of translating asource

    program into some internalform is

    slower than interpreter.

    2) Execution of the translatedprogram

    Executing machine code is muchfaster.

  • 8/4/2019 Syssft Compiled Nksrinath

    45/98

    45

    Mostprogrammi

    nglanguages

    can be

    eithercompiled or

    interpretedsuccessfull

    y.However,

    somelanguages

    areparticularly

    well suitedto the use

    ofinterpreter.Compilers

    usuallygenerate calls to library routines to perform function such as I/O and complex conversionoperations. In such cases, an interpreter might be performed because of its speed of translation.Most of the execution time for the standard program would be consumed by the standard libraryroutines. These routines would be the same, regardless of whether a compiler or an interpreter isused.

    In some languages the type of a variable can change during the execution of a program.Dynamic scoping is used, in which the variable that are referred to by a function or a subroutinesare determined by the sequence of calls made during execution, not by the nesting of blocks in the

    source program. It is difficult to compile such language efficiently and allow for dynamicchanges in the types of variables and the scope of names. These features can be more easilyhandled by an interpreter that providesdelayed binding of symbolic variable names to data types and locations.

    4.3 P-CODE COMPILERS

    P-Code compilers also called byte of code compilers are very similar in concept tointerpreters. A P-code compiler, intermediate form is the machine language for a hypotheticalcomputers, often called pscudo-machine or P-machine. The process of using such a P-code isshown in fig, 43.

    The main advantage of this approach is portability of software. It is not necessary for thecompiler to generate different code for different computers, because the P-code object program

    can be executed on any machine that has a P-code interpreter. Even the compiler itself can betransported if it is written in the language that it compiles. To accomplish this, the source versionof the compiler is compiled into P-code; this P-code can then be interpreted on another compiler.In this way P-code compiler can be used without modification as a wide variety of system if a P-code interpreter is written for each different machine.

    Source Program

    is much slower.

    3) Debugging facilities can beeasily

    provided.

    Provision of bugging facilitiesare

    difficult and complicated.

    4) During execution the

    interpreterproduce symbolic dumps ofdata

    values, trace of programexecution

    related to the sourcestatement.

    The compiler does not produce

    symbolic dumps of date value.Debugging tools are requiredfor

    trace the program.

    5) Program testing can be doneeffectively using interpreter

    as theoperation on different data

    can betraced.

    It is difficult to test as thecompiler

    execution file gives the finalresult.

    6) Easy to handle dynamicscoping

    Difficult to handle dynamicscooping

  • 8/4/2019 Syssft Compiled Nksrinath

    46/98

    46

    Object ProgramP - Code

    Fig. 43

    The design of a P-machine and the associated P-code is often related to the requirementsof the language being compiled. For example, the P-code for a Pascalcompiler might include single P-instructions that perform:

    Array subscript calculation Handle the details of procedure entry and exit and Perform elementary operation on sets

    This simplifies the code generation process, leading to a smaller and more efficientcompiler.

    The P-code object program is often much smaller than a corresponding machine codeprogram. This is particularly useful on machines with severely limited memory size.

    The interpretive execution of P-code program may be much slower than the execution ofthe equivalent machine code. Many P-code compilers are designed for a single user running on adedicated micro-computer systems. In that case, the speed of execution may be relativelyinsignificant because the limiting factor is system performance may be the response time and "think time " of the user.

    If execution speed is important, some P-code compilers support the use of machine-language subtraction. By rewriting a small number of commonly used routines in machinelanguage, rather than P-code, it is often possible to improve the performance. Of course, thisapproach sacrifices some of the portability associated with the use of P-code compilers.

    8.4.2 COMPILER-COMPILERSCompiler-Compiler is software tool that can be used to help in the task of compiler

    construction. Such tools are also ca