Presentation is loading. Please wait.

Presentation is loading. Please wait.

ISBN 0-321-19362-8 Chapter 4 Lexical and Syntax Analysis The Parsing Problem Recursive-Descent Parsing.

Similar presentations


Presentation on theme: "ISBN 0-321-19362-8 Chapter 4 Lexical and Syntax Analysis The Parsing Problem Recursive-Descent Parsing."— Presentation transcript:

1 ISBN 0-321-19362-8 Chapter 4 Lexical and Syntax Analysis The Parsing Problem Recursive-Descent Parsing

2 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-2 Introduction Reasons to separate lexical and syntax analysis: –Simplicity - less complex approaches can be used for lexical analysis; separating them simplifies the parser –Efficiency - separation allows optimization of the lexical analyzer –Portability - parts of the lexical analyzer may not be portable, but the parser always is portable

3 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-3 The Parsing Problem Goals of the parser, given an input program: –Find all syntax errors; for each, produce an appropriate diagnostic message, and recover quickly –Produce the parse tree, or at least a trace of the parse tree for the program

4 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-4 The Parsing Problem Two categories of parsers –Top down - produce the parse tree, beginning at the root Order is that of a leftmost derivation –Bottom up - produce the parse tree, beginning at the leaves Order is that of the reverse of a rightmost derivation Parsers look only one token ahead in the input

5 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-5 The Parsing Problem Top-down Parsers –Given a sentential form, xA , the parser must choose the correct A-rule to get the next sentential form in the leftmost derivation, using only the first token produced by A The most common top-down parsing algorithms: –Recursive descent - a coded implementation –LL parsers - table driven implementation

6 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-6 The Parsing Problem Bottom-up parsers –Given a right sentential form, , determine what substring of  is the right-hand side of the rule in the grammar that must be reduced to produce the previous sentential form in the right derivation –The most common bottom-up parsing algorithms are in the LR family

7 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-7 The Parsing Problem The Complexity of Parsing –Parsers that work for any unambiguous grammar are complex and inefficient ( O(n 3 ), where n is the length of the input ) –Compilers use parsers that only work for a subset of all unambiguous grammars, but do it in linear time ( O(n), where n is the length of the input )

8 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-8 Recursive-Descent Parsing Recursive Descent Process –There is a subprogram for each nonterminal in the grammar, which can parse sentences that can be generated by that nonterminal –EBNF is ideally suited for being the basis for a recursive-descent parser, because EBNF minimizes the number of nonterminals

9 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-9 Recursive-Descent Parsing A grammar for simple expressions:  {(+ | -) }  {(* | /) }  id | ( )

10 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-10 Recursive-Descent Parsing Assume we have a lexical analyzer named lex, which puts the next token code in nextToken The coding process when there is only one RHS: –For each terminal symbol in the RHS, compare it with the next input token; if they match, continue, else there is an error –For each nonterminal symbol in the RHS, call its associated parsing subprogram

11 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-11 Recursive-Descent Parsing /* Function expr Parses strings in the language generated by the rule: → {(+ | -) } */ void expr() { /* Parse the first term */ term(); …

12 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-12 Recursive-Descent Parsing /* As long as the next token is + or -, call lex to get the next token, and parse the next term */ while (nextToken == PLUS_CODE || nextToken == MINUS_CODE){ lex(); term(); } This particular routine does not detect errors Convention: Every parsing routine leaves the next token in nextToken

13 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-13 Recursive-Descent Parsing A nonterminal that has more than one RHS requires an initial process to determine which RHS it is to parse –The correct RHS is chosen on the basis of the next token of input (the lookahead) –The next token is compared with the first token that can be generated by each RHS until a match is found –If no match is found, it is a syntax error

14 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-14 Recursive-Descent Parsing /* Function factor Parses strings in the language generated by the rule: -> id | ( ) */ void factor() { /* Determine which RHS */ if (nextToken) == ID_CODE) /* For the RHS id, just call lex */ lex();

15 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-15 Recursive-Descent Parsing /* If the RHS is ( ) – call lex to pass over the left parenthesis, call expr, and check for the right parenthesis */ else if (nextToken == LEFT_PAREN_CODE) { lex(); expr(); if (nextToken == RIGHT_PAREN_CODE) lex(); else error(); } /* End of else if (nextToken ==... */ else error(); /* Neither RHS matches */ }

16 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-16 LL Grammar Class The LL Grammar Class (including recursive descent parsing) cannot handle all grammars Problem situations –The Left Recursion Problem If a grammar has left recursion, either direct or indirect, it cannot be the basis for a top-down parser –A grammar can be modified to remove left recursion –Using EBNF form fixes the following left-recursive rule  - |

17 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-17 Pairwise Disjointness The other characteristic of grammars that disallows top-down parsing is the lack of pairwise disjointness –The inability to determine the correct RHS on the basis of one token of lookahead –Def: FIRST(  ) = {a |  =>* a  } (If  =>* ,  is in FIRST(  )) Pairwise Disjointness Test: –For each nonterminal, A, in the grammar that has more than one RHS, for each pair of rules, A   i and A   j, it must be true that FIRST(  i ) FIRST(  j ) = 

18 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-18 Pairwise Disjointness In plain English, a single non-terminal should not have two rules that start with the same terminal Examples: –Acceptable A  a | bB | cAb –Not acceptable A  a | aB

19 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-19 Left Factoring Left factoring can resolve the problem Replace  identifier | identifier [ ] with  identifier   | [ ] or  identifier [[ ]] (the outer brackets are metasymbols of EBNF)

20 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-20 Left Factoring Consider the following grammar which does not satisfy the pairwise disjointness test A  aB | aAb We can re-write the grammar as follows A  aY Y  B | Ab

21 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-21 Bottom-up Parsing The most common bottom-up parsing algorithms are in the LR family –Parse code from left to right –Reverse of a rightmost derivation Typically, build a table which says what should be done for each possible next token based on what tokens have come before –A state machine A parser table can be generated from a given grammar with a tool, e.g., yacc

22 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-22 Bottom-up Parsing Advantages of LR parsers: –They will work for nearly all grammars that describe programming languages. –They work on a larger class of grammars than other bottom-up algorithms, but are as efficient as any other bottom-up parser. –They can detect syntax errors as soon as it is possible. –The LR class of grammars is a superset of the class parsable by LL parsers.

23 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-23

24 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-24 Each non-terminal becomes a procedure whose structure is determined by the grammar rules for that non-terminal. A function called match is used to check if a token is the appropriate terminal. A non-terminal in a rule generates a call to the corresponding function. If there are several rules for a non-terminal, you will need to check to see which one is being used.

25 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-25 Helper functions for the parser A helper function called check is used to look ahead to see if the next lexeme has a particular token. A helper function called advance may be used to move on to the next token. A helper function called match is used when the next token has to be a particular terminal. –Match reports an error if the next lexeme does not have the right token.

26 Copyright © 2004 Pearson Addison-Wesley. All rights reserved.4-26 Building Parse Trees For scanning, the Lexeme class needed to store the token and possibly a string or numeric value. To build a parse tree, we need tree nodes. In the working parser, the Lexemes are binary tree nodes. –For assignment and arithmetic operators, this works –Later, we’ll find that it is not the perfect solution for other parts of a language.


Download ppt "ISBN 0-321-19362-8 Chapter 4 Lexical and Syntax Analysis The Parsing Problem Recursive-Descent Parsing."

Similar presentations


Ads by Google