A Backtracking LR Algorithm for Parsing Ambiguous Context-Dependent Languages

Total Page:16

File Type:pdf, Size:1020Kb

A Backtracking LR Algorithm for Parsing Ambiguous Context-Dependent Languages A Backtracking LR Algorithm for Parsing Ambiguous Context-Dependent Languages Adrian D. Thurston and James R. Cordy School of Computing Queen’s University Kingston, ON, Canada {thurston, cordy}@cs.queensu.ca Abstract 1 Introduction Parsing context-dependent computer lan- To successfully parse modern programming guages requires an ability to maintain and languages such as C, Java and C# requires query data structures while parsing for the an ability to handle context dependencies. We purpose of influencing the parse. Parsing must lookup the meaning of an identifier to de- ambiguous computer languages requires an termine what kind of symbol we are dealing ability to generate a parser for arbitrary with before we proceed to parse the identifier. context-free grammars. In both cases we have The established practice for dealing with this tools for generating parsers from a grammar. problem is the “lexical feedback hack.” During However, languages that have both of these forward parsing, semantic actions are respon- properties simultaneously are much more sible for maintaining lookup tables. The lex- difficult to parse. Consequently, we have ical analyzer is then responsible for querying fewer techniques. One approach to parsing the type of an identifier before sending it to such languages is to endow traditional LR the parser. We have many tools which support systems with backtracking. This is a step this method of parsing. towards a working solution, however there are number of problems. In this work we present A different language classification criteria is two enhancements to a basic backtracking LR ambiguity. To parse context-free languages approach which enable the parsing of computer that are ambiguous requires an ability to pur- languages that are both context-dependent sue at least one parse given multiple potential and ambiguous. Using our system we have pro- parses. Again, we have many tools for gener- duced a fast parser for C++ that is composed ating parsers from ambiguous grammars. The of strictly a scanner, a name lookup stage and techniques available to use include GLR, Ear- parser generated from a grammar augmented ley parsing, and generalized recursive descent. with semantic actions and semantic ‘undo’ Languages that are both context-dependent actions. Language ambiguities are resolved by and ambiguous are considerably more difficult prioritizing grammar declarations. to parse than languages with just one of these properties. They require that our facilities for Copyright c 2006 Adrian D. Thurston and James considering alternatives accommodate our need R. Cordy. Permission to copy is hereby granted pro- vided the original copyright notice is reproduced in to maintain and query global state. For exam- copies made. ple, we may pursue one potential parse, ma- 1 nipulating global state while doing so, only to to write a grammar-based C++ parser in a discover that we have made the wrong guess straightforward manner. Reduction actions are and we must give up and try an alternative free to change the global data structures that parse. Before we can however, our manipu- are used to determine the type of identifiers. lation of the global state must be abandoned. This may entail pushing a namespace to the Since the nature of these manipulations are de- declaration stack, or inserting a class name termined by the semantics of the language to into a dictionary. Immediately below a reduc- be parsed, they must be programmed by the tion action which modifies global state, the dis- user of the parser generator. They cannot be ciplined programmer is responsible for imple- declared by the user and generated automati- menting the reverse of the reduction action, for cally by the parser generator. example popping the declaration stack or re- C++ is an example of a language that has moving an item from a dictionary. This allows context dependencies and which is ambiguous. the parser to correctly backtrack. We very rarely find C++ parsers to be gener- At strategic points, such as statement ated from a grammar. boundaries, parse trees may be committed and One approach to parsing these languages is non-reversible actions executed. In these non- to convert a standard LR parser into a back- reversible actions, which we call final actions, tracking parser. Examples of such systems in- the user may perform permanent tasks such as clude BtYacc [4], Basil [20], Ratatosk [15] and constructing an AST or printing the result of Lark [7]. There are a number of advantages the parse. Finally, rules for resolving C++ lan- to pursuing a backtracking LR approach. The guage ambiguities are implemented by ordering parser will inherit the speed of LR parsing, the mutually ambiguous productions in the order simplicity and power of the bottom-up seman- in which they should be tried. tic action model, and the ease-of-use of back- In the next section we discuss the vari- tracking, giving us a natural ability to handle ous grammar-based approaches to generating ambiguities. parsers for ambiguous context-dependent lan- There are two problems with simply endow- guages, including existing backtracking LR sys- ing an LR parser with backtracking which make tems. In Section 3 we describe our enhance- it difficult to apply the approach to the pars- ment to backtracking LR which allows ambigu- ing of ambiguous context-dependent languages. ities and context dependencies to co-exist. In Existing backtracking LR systems only back- Section 4 we describe our enhancement which track at the level of parsing. They do not el- puts control of the backtracking strategy in the evate backtracking to the level of semantic ac- hands of the user. In Section 5 we show how tions. We therefore cannot backtrack over any our parsing algorithm can be applied to C++. attempted parse that has modified the global state in preparation for handling context de- pendencies. Secondly, with these systems it 2 Related Work is difficult or impossible for the user to spec- ify which potential parses should be preferred 2.1 GLR when the grammar contains ambiguities. The generalized LR parsing method [10] is In this work we have solved these two prob- one approach to parsing ambiguous context- lems. The forward parsing phase is free to dependent languages. Due to inherent paral- manipulate the global state because our back- lelism, use of GLR relies on post-processing of tracker invokes semantic undo actions during the parse trees. backtracking. Semantic undo actions can be In the course of building a parse table, stan- used to revert the effects of the forward phase. dard LR parser generators will emit an error Secondly, we have devised a method of ordering upon discovering shift-reduce or reduce-reduce the attempts of conflicting actions to achieve a conflicts. Some parser generators may choose user-controlled and predictable parse of an am- one action by default and produce code that biguous grammar. runs, but does not necessarily work as intended. This approach has been successfully used Others generators may simply fail to proceed. 2 GLR parser generators will accept any gram- 2.2 Generalized Top-Down mar and will always produce a working parser regardless of the number of conflicts contained Generalized top-down parsing with full back- in it. At run time, the generated parser will tracking is a very flexible parsing method that take conflicts in stride; when encountering mul- can be applied to ambiguous languages. When tiple actions on a single arc of the parse table, provisions are made for handling left recursion it will simultaneously take all actions. From a wide range of parsing tasks can be imple- then on all potential parses are parsed in lock- mented. The TXL [2] programming language, step. Since parsing in lockstep requires multi- a language designed for prototyping and ma- ple stack instances, much research as gone into nipulating language descriptions, tools and ap- managing a shared stack which conserves space plications, contains a parser which implements and computation time, making the approach the generalized top-down parsing method. It much more practical. allows the definition of arbitrary context-free grammars, according to which it will parse in- The GLR method can be applied very suc- put using a top-down parser with full back- cessfully to the parsing of ambiguous lan- tracking. This parsing strategy has been shown guages, but we experience problems when we to be very useful in language design and soft- introduce context dependencies. The need to ware renovation tasks. maintain type information while concurrently A key advantage of this method is that it pursuing multiple parses requires that we also puts the user in control of the parsing strat- maintain multiple copies of the global data egy when the grammar is ambiguous. The pre- structures which store the type information. ferred order in which to attempt to parse mu- It may be possible to extend the idea of au- tually ambiguous alternatives can be specified tomatic parse forest sharing to the global con- locally. This is advantageous for grammar com- text dependency state. After all the parse tree position tasks in software engineering [3]. The is itself a global state. No work in this area is innermost backtracking strategy makes it easy known. However, if we consider that the struc- for the user to predict the result of the parse. ture of the global state information is depen- Definite clause grammars (DCGs) [17] are dent on the language being parsed, it seems a syntactic shorthand for producing parsers doubtful that automatic sharing of context de- with Prolog clauses which represent the in- pendency information is a task that can be put with difference lists. Prolog-based pars- moved to the parser generator. C++ has a ing is a very expressive parsing technique which unique and complicated namespace structure, can be considered a generalized top-down pars- accompanied by many nontrivial name lookup ing method.
Recommended publications
  • Syntax-Directed Translation, Parse Trees, Abstract Syntax Trees
    Syntax-Directed Translation Extending CFGs Grammar Annotation Parse Trees Abstract Syntax Trees (ASTs) Readings: Section 5.1, 5.2, 5.5, 5.6 Motivation: parser as a translator syntax-directed translation stream of ASTs, or tokens parser assembly code syntax + translation rules (typically hardcoded in the parser) 1 Mechanism of syntax-directed translation syntax-directed translation is done by extending the CFG a translation rule is defined for each production given X Æ d A B c the translation of X is defined in terms of translation of nonterminals A, B values of attributes of terminals d, c constants To translate an input string: 1. Build the parse tree. 2. Working bottom-up • Use the translation rules to compute the translation of each nonterminal in the tree Result: the translation of the string is the translation of the parse tree's root nonterminal Why bottom up? a nonterminal's value may depend on the value of the symbols on the right-hand side, so translate a non-terminal node only after children translations are available 2 Example 1: arith expr to its value Syntax-directed translation: the CFG translation rules E Æ E + T E1.trans = E2.trans + T.trans E Æ T E.trans = T.trans T Æ T * F T1.trans = T2.trans * F.trans T Æ F T.trans = F.trans F Æ int F.trans = int.value F Æ ( E ) F.trans = E.trans Example 1 (cont) E (18) Input: 2 * (4 + 5) T (18) T (2) * F (9) F (2) ( E (9) ) int (2) E (4) * T (5) Annotated Parse Tree T (4) F (5) F (4) int (5) int (4) 3 Example 2: Compute type of expr E -> E + E if ((E2.trans == INT) and (E3.trans == INT) then E1.trans = INT else E1.trans = ERROR E -> E and E if ((E2.trans == BOOL) and (E3.trans == BOOL) then E1.trans = BOOL else E1.trans = ERROR E -> E == E if ((E2.trans == E3.trans) and (E2.trans != ERROR)) then E1.trans = BOOL else E1.trans = ERROR E -> true E.trans = BOOL E -> false E.trans = BOOL E -> int E.trans = INT E -> ( E ) E1.trans = E2.trans Example 2 (cont) Input: (2 + 2) == 4 1.
    [Show full text]
  • Derivatives of Parsing Expression Grammars
    Derivatives of Parsing Expression Grammars Aaron Moss Cheriton School of Computer Science University of Waterloo Waterloo, Ontario, Canada [email protected] This paper introduces a new derivative parsing algorithm for recognition of parsing expression gram- mars. Derivative parsing is shown to have a polynomial worst-case time bound, an improvement on the exponential bound of the recursive descent algorithm. This work also introduces asymptotic analysis based on inputs with a constant bound on both grammar nesting depth and number of back- tracking choices; derivative and recursive descent parsing are shown to run in linear time and constant space on this useful class of inputs, with both the theoretical bounds and the reasonability of the in- put class validated empirically. This common-case constant memory usage of derivative parsing is an improvement on the linear space required by the packrat algorithm. 1 Introduction Parsing expression grammars (PEGs) are a parsing formalism introduced by Ford [6]. Any LR(k) lan- guage can be represented as a PEG [7], but there are some non-context-free languages that may also be represented as PEGs (e.g. anbncn [7]). Unlike context-free grammars (CFGs), PEGs are unambiguous, admitting no more than one parse tree for any grammar and input. PEGs are a formalization of recursive descent parsers allowing limited backtracking and infinite lookahead; a string in the language of a PEG can be recognized in exponential time and linear space using a recursive descent algorithm, or linear time and space using the memoized packrat algorithm [6]. PEGs are formally defined and these algo- rithms outlined in Section 3.
    [Show full text]
  • Lecture 4 Dynamic Programming
    1/17 Lecture 4 Dynamic Programming Last update: Jan 19, 2021 References: Algorithms, Jeff Erickson, Chapter 3. Algorithms, Gopal Pandurangan, Chapter 6. Dynamic Programming 2/17 Backtracking is incredible powerful in solving all kinds of hard prob- lems, but it can often be very slow; usually exponential. Example: Fibonacci numbers is defined as recurrence: 0 if n = 0 Fn =8 1 if n = 1 > Fn 1 + Fn 2 otherwise < ¡ ¡ > A direct translation in:to recursive program to compute Fibonacci number is RecFib(n): if n=0 return 0 if n=1 return 1 return RecFib(n-1) + RecFib(n-2) Fibonacci Number 3/17 The recursive program has horrible time complexity. How bad? Let's try to compute. Denote T(n) as the time complexity of computing RecFib(n). Based on the recursion, we have the recurrence: T(n) = T(n 1) + T(n 2) + 1; T(0) = T(1) = 1 ¡ ¡ Solving this recurrence, we get p5 + 1 T(n) = O(n); = 1.618 2 So the RecFib(n) program runs at exponential time complexity. RecFib Recursion Tree 4/17 Intuitively, why RecFib() runs exponentially slow. Problem: redun- dant computation! How about memorize the intermediate computa- tion result to avoid recomputation? Fib: Memoization 5/17 To optimize the performance of RecFib, we can memorize the inter- mediate Fn into some kind of cache, and look it up when we need it again. MemFib(n): if n = 0 n = 1 retujrjn n if F[n] is undefined F[n] MemFib(n-1)+MemFib(n-2) retur n F[n] How much does it improve upon RecFib()? Assuming accessing F[n] takes constant time, then at most n additions will be performed (we never recompute).
    [Show full text]
  • Parser Tables for Non-LR(1) Grammars with Conflict Resolution Joel E
    View metadata, citation and similar papers at core.ac.uk brought to you by CORE provided by Elsevier - Publisher Connector Science of Computer Programming 75 (2010) 943–979 Contents lists available at ScienceDirect Science of Computer Programming journal homepage: www.elsevier.com/locate/scico The IELR(1) algorithm for generating minimal LR(1) parser tables for non-LR(1) grammars with conflict resolution Joel E. Denny ∗, Brian A. Malloy School of Computing, Clemson University, Clemson, SC 29634, USA article info a b s t r a c t Article history: There has been a recent effort in the literature to reconsider grammar-dependent software Received 17 July 2008 development from an engineering point of view. As part of that effort, we examine a Received in revised form 31 March 2009 deficiency in the state of the art of practical LR parser table generation. Specifically, LALR Accepted 12 August 2009 sometimes generates parser tables that do not accept the full language that the grammar Available online 10 September 2009 developer expects, but canonical LR is too inefficient to be practical particularly during grammar development. In response, many researchers have attempted to develop minimal Keywords: LR parser table generation algorithms. In this paper, we demonstrate that a well known Grammarware Canonical LR algorithm described by David Pager and implemented in Menhir, the most robust minimal LALR LR(1) implementation we have discovered, does not always achieve the full power of Minimal LR canonical LR(1) when the given grammar is non-LR(1) coupled with a specification for Yacc resolving conflicts. We also detail an original minimal LR(1) algorithm, IELR(1) (Inadequacy Bison Elimination LR(1)), which we have implemented as an extension of GNU Bison and which does not exhibit this deficiency.
    [Show full text]
  • Buffered Shift-Reduce Parsing*
    BUFFERED SHIFT-REDUCE PARSING* Bing Swen (Sun Bin) Dept. of Computer Science, Peking University, Beijing 100871, China [email protected] Abstract A parsing method called buffered shift-reduce parsing is presented, which adds an intermediate buffer (queue) to the usual LR parser. The buffer’s usage is analogous to that of the wait-and-see parsing, but it has unlimited buffer length, and may serve as a separate reduction (pruning) stack. The general structure of its parser and some features of its grammars and parsing tables are discussed. 1. Introduction It is well known that the LR parsing is hitherto the most general shift-reduce method of bottom-up parsing [1], and is among the most widely used. For example, almost all compilers of mainstream programming languages employ the LR-like parsing (via an LALR(1) compiler generator such as YACC or GNU Bison [2]), and many NLP systems use a generalized version of LR parsing (GLR, also called the Tomita algorithm [3]). In some earlier research work on LR(k) extensions for NLP [4] and generalization of compiler generator [5], an idea naturally occurred that one can make a modification to the LR parsing so that after each reduction, the resulting symbol may not be necessarily pushed onto the analysis stack, but instead put back into the input, waiting for decisions in the following steps. This strategy postpones the time of some reduction actions in traditional LR parser, partly deviating from leftmost pruning (Leftmost Reduction). This may cause performance loss for some grammars, with the gained opportunities of earlier error detecting and avoidance of false reductions, as well as later handling of ambiguities, which is significant for the processing of highly ambiguous input strings like natural language sentences.
    [Show full text]
  • Exhaustive Recursion and Backtracking
    CS106B Handout #19 J Zelenski Feb 1, 2008 Exhaustive recursion and backtracking In some recursive functions, such as binary search or reversing a file, each recursive call makes just one recursive call. The "tree" of calls forms a linear line from the initial call down to the base case. In such cases, the performance of the overall algorithm is dependent on how deep the function stack gets, which is determined by how quickly we progress to the base case. For reverse file, the stack depth is equal to the size of the input file, since we move one closer to the empty file base case at each level. For binary search, it more quickly bottoms out by dividing the remaining input in half at each level of the recursion. Both of these can be done relatively efficiently. Now consider a recursive function such as subsets or permutation that makes not just one recursive call, but several. The tree of function calls has multiple branches at each level, which in turn have further branches, and so on down to the base case. Because of the multiplicative factors being carried down the tree, the number of calls can grow dramatically as the recursion goes deeper. Thus, these exhaustive recursion algorithms have the potential to be very expensive. Often the different recursive calls made at each level represent a decision point, where we have choices such as what letter to choose next or what turn to make when reading a map. Might there be situations where we can save some time by focusing on the most promising options, without committing to exploring them all? In some contexts, we have no choice but to exhaustively examine all possibilities, such as when trying to find some globally optimal result, But what if we are interested in finding any solution, whichever one that works out first? At each decision point, we can choose one of the available options, and sally forth, hoping it works out.
    [Show full text]
  • Efficient Computation of LALR(1) Look-Ahead Sets
    Efficient Computation of LALR(1) Look-Ahead Sets FRANK DeREMER and THOMAS PENNELLO University of California, Santa Cruz, and MetaWare TM Incorporated Two relations that capture the essential structure of the problem of computing LALR(1) look-ahead sets are defined, and an efficient algorithm is presented to compute the sets in time linear in the size of the relations. In particular, for a PASCAL grammar, the algorithm performs fewer than 15 percent of the set unions performed by the popular compiler-compiler YACC. When a grammar is not LALR(1), the relations, represented explicitly, provide for printing user- oriented error messages that specifically indicate how the look-ahead problem arose. In addition, certain loops in the digraphs induced by these relations indicate that the grammar is not LR(k) for any k. Finally, an oft-discovered and used but incorrect look-ahead set algorithm is similarly based on two other relations defined for the fwst time here. The formal presentation of this algorithm should help prevent its rediscovery. Categories and Subject Descriptors: D.3.1 [Programming Languages]: Formal Definitions and Theory--syntax; D.3.4 [Programming Languages]: Processors--translator writing systems and compiler generators; F.4.2 [Mathematical Logic and Formal Languages]: Grammars and Other Rewriting Systems--parsing General Terms: Algorithms, Languages, Theory Additional Key Words and Phrases: Context-free grammar, Backus-Naur form, strongly connected component, LALR(1), LR(k), grammar debugging, 1. INTRODUCTION Since the invention of LALR(1) grammars by DeRemer [9], LALR grammar analysis and parsing techniques have been popular as a component of translator writing systems and compiler-compilers.
    [Show full text]
  • Backtrack Parsing Context-Free Grammar Context-Free Grammar
    Context-free Grammar Problems with Regular Context-free Grammar Language and Is English a regular language? Bad question! We do not even know what English is! Two eggs and bacon make(s) a big breakfast Backtrack Parsing Can you slide me the salt? He didn't ought to do that But—No! Martin Kay I put the wine you brought in the fridge I put the wine you brought for Sandy in the fridge Should we bring the wine you put in the fridge out Stanford University now? and University of the Saarland You said you thought nobody had the right to claim that they were above the law Martin Kay Context-free Grammar 1 Martin Kay Context-free Grammar 2 Problems with Regular Problems with Regular Language Language You said you thought nobody had the right to claim [You said you thought [nobody had the right [to claim that they were above the law that [they were above the law]]]] Martin Kay Context-free Grammar 3 Martin Kay Context-free Grammar 4 Problems with Regular Context-free Grammar Language Nonterminal symbols ~ grammatical categories Is English mophology a regular language? Bad question! We do not even know what English Terminal Symbols ~ words morphology is! They sell collectables of all sorts Productions ~ (unordered) (rewriting) rules This concerns unredecontaminatability Distinguished Symbol This really is an untiable knot. But—Probably! (Not sure about Swahili, though) Not all that important • Terminals and nonterminals are disjoint • Distinguished symbol Martin Kay Context-free Grammar 5 Martin Kay Context-free Grammar 6 Context-free Grammar Context-free
    [Show full text]
  • Adaptive LL(*) Parsing: the Power of Dynamic Analysis
    Adaptive LL(*) Parsing: The Power of Dynamic Analysis Terence Parr Sam Harwell Kathleen Fisher University of San Francisco University of Texas at Austin Tufts University [email protected] [email protected] kfi[email protected] Abstract PEGs are unambiguous by definition but have a quirk where Despite the advances made by modern parsing strategies such rule A ! a j ab (meaning “A matches either a or ab”) can never as PEG, LL(*), GLR, and GLL, parsing is not a solved prob- match ab since PEGs choose the first alternative that matches lem. Existing approaches suffer from a number of weaknesses, a prefix of the remaining input. Nested backtracking makes de- including difficulties supporting side-effecting embedded ac- bugging PEGs difficult. tions, slow and/or unpredictable performance, and counter- Second, side-effecting programmer-supplied actions (muta- intuitive matching strategies. This paper introduces the ALL(*) tors) like print statements should be avoided in any strategy that parsing strategy that combines the simplicity, efficiency, and continuously speculates (PEG) or supports multiple interpreta- predictability of conventional top-down LL(k) parsers with the tions of the input (GLL and GLR) because such actions may power of a GLR-like mechanism to make parsing decisions. never really take place [17]. (Though DParser [24] supports The critical innovation is to move grammar analysis to parse- “final” actions when the programmer is certain a reduction is time, which lets ALL(*) handle any non-left-recursive context- part of an unambiguous final parse.) Without side effects, ac- free grammar. ALL(*) is O(n4) in theory but consistently per- tions must buffer data for all interpretations in immutable data forms linearly on grammars used in practice, outperforming structures or provide undo actions.
    [Show full text]
  • The Design & Implementation of an Abstract Semantic Graph For
    Clemson University TigerPrints All Dissertations Dissertations 12-2011 The esiD gn & Implementation of an Abstract Semantic Graph for Statement-Level Dynamic Analysis of C++ Applications Edward Duffy Clemson University, [email protected] Follow this and additional works at: https://tigerprints.clemson.edu/all_dissertations Part of the Computer Sciences Commons Recommended Citation Duffy, Edward, "The eD sign & Implementation of an Abstract Semantic Graph for Statement-Level Dynamic Analysis of C++ Applications" (2011). All Dissertations. 832. https://tigerprints.clemson.edu/all_dissertations/832 This Dissertation is brought to you for free and open access by the Dissertations at TigerPrints. It has been accepted for inclusion in All Dissertations by an authorized administrator of TigerPrints. For more information, please contact [email protected]. THE DESIGN &IMPLEMENTATION OF AN ABSTRACT SEMANTIC GRAPH FOR STATEMENT-LEVEL DYNAMIC ANALYSIS OF C++ APPLICATIONS A Dissertation Presented to the Graduate School of Clemson University In Partial Fulfillment of the Requirements for the Degree Doctor of Philosophy Computer Science by Edward B. Duffy December 2011 Accepted by: Dr. Brian A. Malloy, Committee Chair Dr. James B. von Oehsen Dr. Jason P. Hallstrom Dr. Pradip K. Srimani In this thesis, we describe our system, Hylian, for statement-level analysis, both static and dynamic, of a C++ application. We begin by extending the GNU gcc parser to generate parse trees in XML format for each of the compilation units in a C++ application. We then provide verification that the generated parse trees are structurally equivalent to the code in the original C++ application. We use the generated parse trees, together with an augmented version of the gcc test suite, to recover a grammar for the C++ dialect that we parse.
    [Show full text]
  • Parsing 1. Grammars and Parsing 2. Top-Down and Bottom-Up Parsing 3
    Syntax Parsing syntax: from the Greek syntaxis, meaning “setting out together or arrangement.” 1. Grammars and parsing Refers to the way words are arranged together. 2. Top-down and bottom-up parsing Why worry about syntax? 3. Chart parsers • The boy ate the frog. 4. Bottom-up chart parsing • The frog was eaten by the boy. 5. The Earley Algorithm • The frog that the boy ate died. • The boy whom the frog was eaten by died. Slide CS474–1 Slide CS474–2 Grammars and Parsing Need a grammar: a formal specification of the structures allowable in Syntactic Analysis the language. Key ideas: Need a parser: algorithm for assigning syntactic structure to an input • constituency: groups of words may behave as a single unit or phrase sentence. • grammatical relations: refer to the subject, object, indirect Sentence Parse Tree object, etc. Beavis ate the cat. S • subcategorization and dependencies: refer to certain kinds of relations between words and phrases, e.g. want can be followed by an NP VP infinitive, but find and work cannot. NAME V NP All can be modeled by various kinds of grammars that are based on ART N context-free grammars. Beavis ate the cat Slide CS474–3 Slide CS474–4 CFG example CFG’s are also called phrase-structure grammars. CFG’s Equivalent to Backus-Naur Form (BNF). A context free grammar consists of: 1. S → NP VP 5. NAME → Beavis 1. a set of non-terminal symbols N 2. VP → V NP 6. V → ate 2. a set of terminal symbols Σ (disjoint from N) 3.
    [Show full text]
  • Abstract Syntax Trees & Top-Down Parsing
    Abstract Syntax Trees & Top-Down Parsing Review of Parsing • Given a language L(G), a parser consumes a sequence of tokens s and produces a parse tree • Issues: – How do we recognize that s ∈ L(G) ? – A parse tree of s describes how s ∈ L(G) – Ambiguity: more than one parse tree (possible interpretation) for some string s – Error: no parse tree for some string s – How do we construct the parse tree? Compiler Design 1 (2011) 2 Abstract Syntax Trees • So far, a parser traces the derivation of a sequence of tokens • The rest of the compiler needs a structural representation of the program • Abstract syntax trees – Like parse trees but ignore some details – Abbreviated as AST Compiler Design 1 (2011) 3 Abstract Syntax Trees (Cont.) • Consider the grammar E → int | ( E ) | E + E • And the string 5 + (2 + 3) • After lexical analysis (a list of tokens) int5 ‘+’ ‘(‘ int2 ‘+’ int3 ‘)’ • During parsing we build a parse tree … Compiler Design 1 (2011) 4 Example of Parse Tree E • Traces the operation of the parser E + E • Captures the nesting structure • But too much info int5 ( E ) – Parentheses – Single-successor nodes + E E int 2 int3 Compiler Design 1 (2011) 5 Example of Abstract Syntax Tree PLUS PLUS 5 2 3 • Also captures the nesting structure • But abstracts from the concrete syntax a more compact and easier to use • An important data structure in a compiler Compiler Design 1 (2011) 6 Semantic Actions • This is what we’ll use to construct ASTs • Each grammar symbol may have attributes – An attribute is a property of a programming language construct
    [Show full text]