DOC PREVIEW
UW-Madison CS 536 - Lecture 21

This preview shows page 1-2-23-24 out of 24 pages.

Save
View full document
View full document
Premium Document
Do you want full access? Go Premium and unlock all 24 pages.
Access to all documents
Download any document
Ad free experience
View full document
Premium Document
Do you want full access? Go Premium and unlock all 24 pages.
Access to all documents
Download any document
Ad free experience
View full document
Premium Document
Do you want full access? Go Premium and unlock all 24 pages.
Access to all documents
Download any document
Ad free experience
View full document
Premium Document
Do you want full access? Go Premium and unlock all 24 pages.
Access to all documents
Download any document
Ad free experience
Premium Document
Do you want full access? Go Premium and unlock all 24 pages.
Access to all documents
Download any document
Ad free experience

Unformatted text preview:

267CS 536 Spring 2007©Recursive Descent ParsersAn early implementation of top-down (LL(1)) parsing wasrecursive descent.A parser was organized as a set ofparsing procedures, one for eachnon-terminal. Each parsingprocedure was responsible forparsing a sequence of tokensderivable from its non-terminal.For example, a parsing procedure,A, when called, would call thescanner and match a tokensequence derivable from A.Starting with the start symbol’sparsing procedure, we would thenmatch the entire input, whichmust be derivable from the startsymbol.268CS 536 Spring 2007©This approach is called recursivedescent because the parsingprocedures were typicallyrecursive, and they descendeddown the input’s parse tree (astop-down parsers always do).269CS 536 Spring 2007©Building A Recursive DescentParserWe start with a procedure Match,that matches the current inputtoken against a predicted token:void Match(Terminal a) {if (a == currentToken)currentToken = Scanner();else SyntaxErrror();}To build a parsing procedure for anon-terminal A, we look at allproductions with A on thelefthand side:A → X1...Xn | A → Y1...Ym| ...We use predict sets to decidewhich production to match (LL(1)grammars always have disjointpredict sets).We match a production’srighthand side by calling Match to270CS 536 Spring 2007©match terminals, and callingparsing procedures to match non-terminals.The general form of a parsingprocedure forA → X1...Xn | A → Y1...Ym| ... isvoid A() {if (currentToken in Predict(A→X1...Xn))for(i=1;i<=n;i++)if (X[i] is a terminal)Match(X[i]);else X[i]();elseif (currentToken in Predict(A→Y1...Ym))for(i=1;i<=m;i++)if (Y[i] is a terminal)Match(Y[i]);else Y[i]();else // Handle other A →... productionselse // No production predictedSyntaxError();}271CS 536 Spring 2007©Usually this general form isn’tused.Instead, each production is“macro-expanded” into asequence of Match and parsingprocedure calls.272CS 536 Spring 2007©Example: CSX-LiteProduction Predict SetProg → { Stmts } Eof {Stmts → Stmt Stmts id ifStmts →λ }Stmt → id = Expr ; idStmt → if ( Expr ) Stmt ifExpr → id Etail idEtail → + Expr +Etail → - Expr -Etail →λ ) ;273CS 536 Spring 2007©CSX-Lite Parsing Proceduresvoid Prog() {Match("{");Stmts();Match("}");Match(Eof);}void Stmts() {if (currentToken == id ||currentToken == if){Stmt();Stmts();} else {/* null */}}void Stmt() {if (currentToken == id){Match(id);Match("=");Expr();Match(";");} else {Match(if);Match("(");Expr();Match(")");Stmt();}}274CS 536 Spring 2007©void Expr() {Match(id);Etail();}void Etail() {if (currentToken == "+") {Match("+");Expr();} else if (currentToken == "-"){ Match("-");Expr();} else {/* null */}}275CS 536 Spring 2007©Let’s use recursive descent to parse{ a = b + c; } EofWe start by calling Prog() since thisrepresents the start symbol.Calls Pending Remaining InputProg() {a=b+c;}EofMatch("{");Stmts();Match("}");Match(Eof);{a=b+c;}EofStmts();Match("}");Match(Eof);a = b + c; } EofStmt();Stmts();Match("}");Match(Eof);a = b + c; } EofMatch(id);Match("=");Expr();Match(";");Stmts();Match("}");Match(Eof);a = b + c; } Eof276CS 536 Spring 2007©Match("=");Expr();Match(";");Stmts();Match("}");Match(Eof); = b + c; } EofExpr();Match(";");Stmts();Match("}");Match(Eof); b + c; } EofMatch(id);Etail();Match(";");Stmts();Match("}");Match(Eof); b + c; } EofEtail();Match(";");Stmts();Match("}");Match(Eof); + c; } EofCalls Pending Remaining Input277CS 536 Spring 2007©Match("+");Expr();Match(";");Stmts();Match("}");Match(Eof); + c; } EofExpr();Match(";");Stmts();Match("}");Match(Eof); c; } EofMatch(id);Etail();Match(";");Stmts();Match("}");Match(Eof); c; } EofEtail();Match(";");Stmts();Match("}");Match(Eof);; } Eof/* null */Match(";");Stmts();Match("}");Match(Eof);; } EofCalls Pending Remaining Input278CS 536 Spring 2007©Match(";");Stmts();Match("}");Match(Eof);; } EofStmts();Match("}");Match(Eof);} Eof/* null */Match("}");Match(Eof);} EofMatch("}");Match(Eof);} EofMatch(Eof);EofDone!All input matchedCalls Pending Remaining Input279CS 536 Spring 2007©Syntax Errors in RecursiveDescent ParsingIn recursive descent parsing,syntax errors are automaticallydetected. In fact, they aredetected as soon as possible (assoon as the first illegal token isseen).How? When an illegal token isseen by the parser, either it failsto predict any valid production orit fails to match an expectedtoken in a call to Match.Let’s see how the following illegalCSX-lite program is parsed:{ b + c = a; } Eof(Where should the first syntaxerror be detected?)280CS 536 Spring 2007©Calls Pending Remaining InputProg() {b+c=a;}EofMatch("{");Stmts();Match("}");Match(Eof);{b+c=a;}EofStmts();Match("}");Match(Eof);b + c = a; } EofStmt();Stmts();Match("}");Match(Eof);b + c = a; } EofMatch(id);Match("=");Expr();Match(";");Stmts();Match("}");Match(Eof);b + c = a; } Eof281CS 536 Spring 2007©Match("=");Expr();Match(";");Stmts();Match("}");Match(Eof); + c = a; } EofCall to Match fails! + c = a; } EofCalls Pending Remaining Input282CS 536 Spring 2007©Table-Driven Top-DownParsersRecursive descent parsers havemany attractive features. They areactual pieces of code that can beread by programmers andextended.This makes it fairly easy tounderstand how parsing is done.Parsing procedures are alsoconvenient places to add code tobuild ASTs, or to do type-checking, or to generate code.A major drawback of recursivedescent is that it is quiteinconvenient to change thegrammar being parsed. Anychange, even a minor one, mayforce parsing procedures to be283CS 536 Spring 2007©reprogrammed, as productionsand predict sets are modified.To a less extent, recursive descentparsing is less efficient than itmight be, since subprograms arecalled just to match a single tokenor to recognize a righthand side.An alternative to parsingprocedures is to encode allprediction in a parsing table. Apre-programed driver programcan use a parse table (and list ofproductions) to parse any LL(1)grammar.If a grammar is changed, theparse table and list of productionswill change, but the driver neednot be changed.284CS 536 Spring 2007©LL(1) Parse TablesAn LL(1) parse table, T, is a two-dimensional array. Entries in T areproduction numbers or blank(error) entries.T is indexed by:• A, a non-terminal. A is the non-terminal we want to expand.• CT, the current token that is to bematched.• T[A][CT] = A → X1...Xnif CT is in Predict(A → X1...Xn)T[A][CT] = errorif CT predicts no production with A asits


View Full Document

UW-Madison CS 536 - Lecture 21

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

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

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

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

or

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

Already a member?