KEMBAR78
Recursive Descent Parser - Wikipedia | PDF | Grammar | Theoretical Computer Science
0% found this document useful (0 votes)
19 views5 pages

Recursive Descent Parser - Wikipedia

A recursive descent parser is a top-down parser that uses mutually recursive procedures to implement grammar nonterminals, closely mirroring the grammar structure. Predictive parsers, a subset of recursive descent parsers, do not require backtracking and operate on LL(k) grammars, allowing for linear time parsing. The document also includes an example of a C implementation for a recursive descent parser and mentions various parser generators.

Uploaded by

headpecker334
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views5 pages

Recursive Descent Parser - Wikipedia

A recursive descent parser is a top-down parser that uses mutually recursive procedures to implement grammar nonterminals, closely mirroring the grammar structure. Predictive parsers, a subset of recursive descent parsers, do not require backtracking and operate on LL(k) grammars, allowing for linear time parsing. The document also includes an example of a C implementation for a recursive descent parser and mentions various parser generators.

Uploaded by

headpecker334
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 5

Recursive descent parser

In computer science, a recursive descent parser is a kind of top-down parser built from a set of
mutually recursive procedures (or a non-recursive equivalent) where each such procedure implements
one of the nonterminals of the grammar. Thus the structure of the resulting program closely mirrors
that of the grammar it recognizes.[1][2]

A predictive parser is a recursive descent parser that does not require backtracking.[3] Predictive
parsing is possible only for the class of LL(k) grammars, which are the context-free grammars for
which there exists some positive integer k that allows a recursive descent parser to decide which
production to use by examining only the next k tokens of input. The LL(k) grammars therefore
exclude all ambiguous grammars, as well as all grammars that contain left recursion. Any context-free
grammar can be transformed into an equivalent grammar that has no left recursion, but removal of
left recursion does not always yield an LL(k) grammar. A predictive parser runs in linear time.

Recursive descent with backtracking is a technique that determines which production to use by trying
each production in turn. Recursive descent with backtracking is not limited to LL(k) grammars, but is
not guaranteed to terminate unless the grammar is LL(k). Even when they terminate, parsers that use
recursive descent with backtracking may require exponential time.

Although predictive parsers are widely used, and are frequently chosen if writing a parser by hand,
programmers often prefer to use a table-based parser produced by a parser generator, either for an
LL(k) language or using an alternative parser, such as LALR or LR. This is particularly the case if a
grammar is not in LL(k) form, as transforming the grammar to LL to make it suitable for predictive
parsing is involved. Predictive parsers can also be automatically generated, using tools like ANTLR.

Predictive parsers can be depicted using transition diagrams for each non-terminal symbol where the
edges between the initial and the final states are labelled by the symbols (terminals and non-
terminals) of the right side of the production rule.[4]

Example parser
The following EBNF-like grammar (for Niklaus Wirth's PL/0 programming language, from
Algorithms + Data Structures = Programs) is in LL(1) form:

program = block "." .

block =
["const" ident "=" number {"," ident "=" number} ";"]
["var" ident {"," ident} ";"]
{"procedure" ident ";" block ";"} statement .

statement =
ident ":=" expression
| "call" ident
| "begin" statement {";" statement } "end"
| "if" condition "then" statement
| "while" condition "do" statement .

condition =
"odd" expression
| expression ("="|"#"|"<"|"<="|">"|">=") expression .

expression = ["+"|"-"] term {("+"|"-") term} .

term = factor {("*"|"/") factor} .

factor =
ident
| number
| "(" expression ")" .

Terminals are expressed in quotes. Each nonterminal is defined by a rule in the grammar, except for
ident and number, which are assumed to be implicitly defined.

C implementation
What follows is an implementation of a recursive descent parser for the above language in C. The
parser reads in source code, and exits with an error message if the code fails to parse, exiting silently if
the code parses correctly.

Notice how closely the predictive parser below mirrors the grammar above. There is a procedure for
each nonterminal in the grammar. Parsing descends in a top-down manner until the final
nonterminal has been processed. The program fragment depends on a global variable, sym, which
contains the current symbol from the input, and the function nextsym, which updates sym when
called.

The implementations of the functions nextsym and error are omitted for simplicity.

typedef enum {ident, number, lparen, rparen, times, slash, plus,


minus, eql, neq, lss, leq, gtr, geq, callsym, beginsym, semicolon,
endsym, ifsym, whilesym, becomes, thensym, dosym, constsym, comma,
varsym, procsym, period, oddsym} Symbol;

Symbol sym;
void nextsym(void);
void error(const char msg[]);

int accept(Symbol s) {
if (sym == s) {
nextsym();
return 1;
}
return 0;
}

int expect(Symbol s) {
if (accept(s))
return 1;
error("expect: unexpected symbol");
return 0;
}

void factor(void) {
if (accept(ident)) {
;
} else if (accept(number)) {
;
} else if (accept(lparen)) {
expression();
expect(rparen);
} else {
error("factor: syntax error");
nextsym();
}
}

void term(void) {
factor();
while (sym == times || sym == slash) {
nextsym();
factor();
}
}

void expression(void) {
if (sym == plus || sym == minus)
nextsym();
term();
while (sym == plus || sym == minus) {
nextsym();
term();
}
}

void condition(void) {
if (accept(oddsym)) {
expression();
} else {
expression();
if (sym == eql || sym == neq || sym == lss || sym == leq || sym == gtr || sym == geq) {
nextsym();
expression();
} else {
error("condition: invalid operator");
nextsym();
}
}
}

void statement(void) {
if (accept(ident)) {
expect(becomes);
expression();
} else if (accept(callsym)) {
expect(ident);
} else if (accept(beginsym)) {
do {
statement();
} while (accept(semicolon));
expect(endsym);
} else if (accept(ifsym)) {
condition();
expect(thensym);
statement();
} else if (accept(whilesym)) {
condition();
expect(dosym);
statement();
} else {
error("statement: syntax error");
nextsym();
}
}

void block(void) {
if (accept(constsym)) {
do {
expect(ident);
expect(eql);
expect(number);
} while (accept(comma));
expect(semicolon);
}
if (accept(varsym)) {
do {
expect(ident);
} while (accept(comma));
expect(semicolon);
}
while (accept(procsym)) {
expect(ident);
expect(semicolon);
block();
expect(semicolon);
}
statement();
}

void program(void) {
nextsym();
block();
expect(period);
}

Examples
Some recursive descent parser generators:

TMG – an early compiler-compiler used in the 1960s and early 1970s


JavaCC
Coco/R
ANTLR
Spirit Parser Framework – a C++ recursive descent parser generator framework requiring no pre-
compile step
parboiled (Java) – a recursive descent PEG parsing library for Java

See also
Parser combinator – a higher-order function used in combinatory parsing, a method of factoring
recursive descent parser designs
Parsing expression grammar – another form representing recursive descent grammar
Recursive ascent parser
Tail recursive parser – a variant of the recursive descent parser

References
1. This article is based on material taken from Recursive+descent+parser (https://foldoc.org/Recursi
ve+descent+parser) at the Free On-line Dictionary of Computing prior to 1 November 2008 and
incorporated under the "relicensing" terms of the GFDL, version 1.3 or later.
2. Burge, W.H. (1975). Recursive Programming Techniques (https://archive.org/details/recursiveprog
ram0000burg). Addison-Wesley Publishing Company. ISBN 0-201-14450-6.
3. Watson, Des (22 March 2017). A Practical Approach to Compiler Construction (https://books.googl
e.com/books?id=05B0DgAAQBAJ&q=%22predictive+parser%22). Springer. ISBN 978-3-319-
52789-5.
4. Aho, Alfred V.; Sethi, Ravi; Ullman, Jeffrey (1986). Compilers: Principles, Techniques and Tools (ht
tps://archive.org/details/compilers00ahoa) (first ed.). Addison Wesley. p. 183 (https://archive.org/d
etails/compilers00ahoa/page/n193).

General references
Compilers: Principles, Techniques, and Tools, first edition, Alfred V Aho, Ravi Sethi, and Jeffrey D
Ullman, in particular Section 4.4.
Modern Compiler Implementation in Java, Second Edition, Andrew Appel, 2002, ISBN 0-521-
82060-X.
Recursive Programming Techniques, W.H. Burge, 1975, ISBN 0-201-14450-6
Crafting a Compiler with C, Charles N Fischer and Richard J LeBlanc, Jr, 1991, ISBN 0-8053-
2166-7.
Compiling with C# and Java, Pat Terry, 2005, ISBN 0-321-26360-X, 624
Algorithms + Data Structures = Programs, Niklaus Wirth, 1975, ISBN 0-13-022418-9
Compiler Construction, Niklaus Wirth, 1996, ISBN 0-201-40353-6

External links
Jack W. Crenshaw: Let's Build A Compiler (1988-1995) (https://compilers.iecc.com/crenshaw/), in
Pascal, with assembly language output, using a "keep it simple" approach

Retrieved from "https://en.wikipedia.org/w/index.php?title=Recursive_descent_parser&oldid=1253332543"

You might also like