Slide 1Slide 2Slide 3Slide 4Slide 5Slide 6Slide 7Slide 8Slide 9Slide 10Slide 11Slide 12Slide 13Slide 14Slide 15Slide 16Slide 17Slide 18Slide 19Slide 20Slide 21Slide 22Slide 23Parsing III (Top-down parsing: recursive descent & LL(1) )Roadmap (Where are we?)PreviouslyWe set out to study parsing• Specifying syntax Context-free grammarsAmbiguity• Top-down parsers Algorithm & its problem with left recursionLeft-recursion removalToday•Predictive top-down parsingThe LL(1) conditionSimple recursive descent parsersTable-driven LL(1) parsersPicking the “Right” ProductionIf it picks the wrong production, a top-down parser may backtrack Alternative is to look ahead in input & use context to pick correctlyHow much lookahead is needed?• In general, an arbitrarily large amount• Use the Cocke-Younger, Kasami algorithm or Earley’s algorithmFortunately,• Large subclasses of CFGs can be parsed with limited lookahead• Most programming language constructs fall in those subclassesAmong the interesting subclasses are LL(1) and LR(1) grammarsPredictive ParsingBasic ideaGiven A , the parser should be able to choose between & FIRST setsFor some rhs G, define FIRST() as the set of tokens that appear as the first symbol in some string that derives from That is, x FIRST() if * x , for some We will defer the problem of how to compute FIRST sets until we look at the LR(1) table construction algorithmPredictive ParsingBasic ideaGiven A , the parser should be able to choose between & FIRST setsFor some rhs G, define FIRST() as the set of tokens that appear as the first symbol in some string that derives from That is, x FIRST() if * x , for some The LL(1) Property If A and A both appear in the grammar, we would like FIRST() FIRST() = This would allow the parser to make a correct choice with a lookahead of exactly one symbol !This is almost correctSee the next slidePredictive ParsingWhat about -productions?They complicate the definition of LL(1)If A and A and FIRST(), then we need to ensure that FIRST() is disjoint from FOLLOW(), tooDefine FIRST+() as•FIRST() FOLLOW(), if FIRST()•FIRST(), otherwiseThen, a grammar is LL(1) iff A and A implies FIRST+() FIRST+() = FOLLOW() is the set of all words in the grammar that can legally appear immediately after an Predictive ParsingGiven a grammar that has the LL(1) property• Can write a simple routine to recognize each lhs • Code is both simple & fastConsider A 1 | 2 | 3, with FIRST+(1) FIRST+ (2) FIRST+ (3) = /* find an A */if (current_word FIRST(1)) find a 1 and return trueelse if (current_word FIRST(2)) find a 2 and return trueelse if (current_word FIRST(3)) find a 3 and return trueelse report an error and return falseOf course, there is more detail to “find a i” (§ 3.3.4 in EAC)Grammars with the LL(1) property are called predictive grammars because the parser can “predict” the correct expansion at each point in the parse.Parsers that capitalize on the LL(1) property are called predictive parsers.One kind of predictive parser is the recursive descent parser.Recursive Descent ParsingRecall the expression grammar, after transformationThis produces a parser with six mutually recursive routines:• Goal• Expr• EPrime• Term• TPrime• FactorEach recognizes one NT or TThe term descent refers to the direction in which the parse tree is built.1 Goal Expr 2 Expr Term Expr 3 Expr + Term Expr 4 | – Term Expr 5 | 6 Term Factor Term 7 Term * Factor Term 8 | / Factor Term 9 | 10 Factor number 11 | idRecursive Descent Parsing (Procedural)A couple of routines from the expression parserGoal( ) word nextWord( ); if (Expr( ) = true & word = EOF) then proceed to next step; else return false;Expr( ) if (Term( ) = false) then return false; else return Eprime( );Factor( ) if (word = ( ) then word nextWord( ); if (Expr() = false) then return false else if (word != ) ) then report syntax error; return false; else if (word != num and word != ident) then report syntax error; return false; else word nextWord( ); return true;EPrime, Term, & TPrime follow the same basic lines (Figure 3.7, EAC)looking for EOF,found tokenlooking for Number or Identifier, found token insteadRecursive Descent ParsingTo build a parse tree:• Augment parsing routines to build nodes • Pass nodes between routines using a stack • Node for each symbol on rhs • Action is to pop rhs nodes, make them children of lhs node, and push this subtreeTo build an abstract syntax tree • Build fewer nodes• Put them together in a different orderExpr( ) result true; if (Term( ) = false) then return false; else if (EPrime( ) = false) then result false; else build an Expr node pop EPrime node pop Term node make EPrime & Term children of Expr push Expr node return result;This is a preview of Chapter 4Success build a piece of the parse treeLeft FactoringWhat if my grammar does not have the LL(1) property?Sometimes, we can transform the grammarThe Algorithm A NT, find the longest prefix that occurs in two or more right-hand sides of A if ≠ then replace all of the A productions, A 1 | 2 | … | n | , with A Z | Z 1 | 2 | … | n where Z is a new element of NTRepeat until no common prefixes remainA graphical explanation for the same ideabecomes …Left Factoring A 1 | 2 | 3 A ZZ 1 | 2 | n A132Z132ALeft Factoring (An example)Consider the following fragment of the expression grammarAfter left factoring, it becomesThis form has the same syntax, with the LL(1) propertyFactor Identifier | Identifier [ ExprList ] | Identifier ( ExprList ) FIRST(rhs1) = { Identifier }FIRST(rhs2) = { Identifier }FIRST(rhs3) = {
View Full Document