Content deleted Content added
Rescuing 1 sources and tagging 0 as dead.) #IABot (v2.0.9.5 |
|||
(30 intermediate revisions by 22 users not shown) | |||
Line 1:
{{Short description|Bottom-up parser that interprets an operator-precedence grammar}}
In [[computer science]], an '''operator [[Edsger Dijkstra]]'s [[shunting yard algorithm]] is commonly used to implement operator
== Relationship to other parsers ==
Line 7 ⟶ 8:
An operator-precedence parser is a simple [[shift-reduce parser]] that is capable of parsing a subset of [[LR parser|LR(1)]] grammars. More precisely, the operator-precedence parser can parse all LR(1) grammars where two consecutive [[nonterminal]]s and [[empty string|epsilon]] never appear in the right-hand side of any rule.
Operator-precedence parsers are not used often in practice; however they do have some properties that make them useful within a larger design. First, they are simple enough to write by hand, which is not generally the case with more sophisticated right shift-reduce parsers. Second, they can be written to consult an operator table at [[Run time (program lifecycle phase)|run time]], which makes them suitable for languages that can add to or change their operators while parsing. (An example is [[Haskell (programming language)|Haskell]], which allows user-defined infix operators with custom associativity and precedence;
[[Raku (programming language)|Raku]] sandwiches an operator-precedence parser between two [[recursive descent parser]]s in order to achieve a balance of speed and dynamism
== Precedence climbing method ==
Line 16 ⟶ 17:
An infix-notation expression grammar in [[EBNF]] format will usually look like this:
<syntaxhighlight lang="
expression ::= equality-expression
equality-expression ::= additive-expression ( ( '==' | '!=' ) additive-expression ) *
Line 34 ⟶ 35:
The pseudocode for the algorithm is as follows. The parser starts at function ''parse_expression''. Precedence levels are greater than or equal to 0.
<u>parse_expression()</u>
'''return''' parse_expression_1(parse_primary(), 0)
<u>parse_expression_1(lhs, min_precedence)</u>
''lookahead'' := peek next token
'''while''' ''lookahead'' is a binary operator whose precedence is >= ''min_precedence''
Line 47 ⟶ 48:
than ''op''<nowiki>'</nowiki>s, or a right-associative operator
whose precedence is equal to ''op'''s
''rhs'' := ''parse_expression_1'' (''rhs'', precedence of ''op'' + (1 if ''lookahead'
''lookahead'' := peek next token
''lhs'' := the result of applying ''op'' with operands ''lhs'' and ''rhs''
Line 54 ⟶ 55:
Note that in the case of a production rule like this (where the operator can only appear once):
<syntaxhighlight lang="
equality-expression ::= additive-expression ( '==' | '!=' ) additive-expression
</syntaxhighlight>
Line 92 ⟶ 93:
== Pratt parsing ==
{{external links|section|date=August 2023}}
Another precedence parser known as Pratt parsing was first described by
Pratt designed the parser originally to implement the [[CGOL]] programming language, and it was treated in much more depth in a Masters Thesis under his supervision.<ref>Van De Vanter, Michael L. "[http://publications.csail.mit.edu/lcs/specpub.php?id=715 A Formalization and Correctness Proof of the CGOL Language System]." (Master's Thesis). MIT Laboratory for Computer Science Technical Report MIT-LCS-TR-147 (Cambridge, Massachusetts). 1975.</ref>
Line 101 ⟶ 102:
* Comparison between Python implementations of precedence climbing and Pratt parsing: [http://www.oilshell.org/blog/2016/11/01.html "Pratt Parsing and Precedence Climbing Are the Same Algorithm" (2016) by Andy Chu]
* Tutorial using [[Rust (programming language)|Rust]]: [https://matklad.github.io/2020/04/13/simple-but-powerful-pratt-parsing.html "Simple but Powerful Pratt Parsing" (2020) by Aleksey Kladov]
* Tutorial using [[
* Tutorial using [[Python (programming language)|Python]]: [http://effbot.org/zone/simple-top-down-parsing.htm "Simple Top-Down Parsing in Python" (2008) by Fredrik Lundh] {{Webarchive|url=https://web.archive.org/web/20150228044653/http://effbot.org/zone/simple-top-down-parsing.htm |date=2015-02-28 }}
* Tutorial using [[Java (programming language)|Java]]: [http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/ "Pratt Parsers: Expression Parsing Made Easy" (2011) by Bob Nystrom, author of Crafting Interpreters]
* Implementation in [[C Sharp (programming language)|C#]]: [https://github.com/atifaziz/Gratt "Gratt: A Generic Vaughn Pratt's top-down operator precedence parser for .NET Standard"] (a [[Generic programming|generic]] version inspired by the Java implementation presented by Bob Nystrom in [http://journal.stuffwithstuff.com/2011/03/19/pratt-parsers-expression-parsing-made-easy/ "Pratt Parsers: Expression Parsing Made Easy"])
== Alternative methods ==
Line 111 ⟶ 113:
Such trees do not necessarily need to be implemented using data structures conventionally used for trees. Instead, tokens can be stored in flat structures, such as tables, by simultaneously building a priority list which states what elements to process in which order.
=== Full parenthesization ===
Another approach is to first fully parenthesize the expression, inserting a number of parentheses around each operator, such that they lead to the correct precedence even when parsed with a linear, left-to-right parser. This algorithm was used in the early [[Fortran#FORTRAN|FORTRAN I]] compiler:<ref name="Padua2000">{{cite journal |last1=Padua |first1=David |title=The Fortran I Compiler |year=2000 |journal=Computing in Science & Engineering |volume=2 |issue=1 |pages=70–75 |url=http://polaris.cs.uiuc.edu/publications/c1070.pdf |doi=10.1109/5992.814661 |bibcode=2000CSE.....2a..70P |archive-date=2020-06-17 |access-date=2016-03-29 |archive-url=https://web.archive.org/web/20200617113640/http://polaris.cs.uiuc.edu/publications/c1070.pdf |url-status=dead }}</ref>
<blockquote>
Line 121 ⟶ 124:
Although not obvious, the algorithm was correct, and, in the words of [[Donald Knuth|Knuth]], “The resulting formula is properly parenthesized, believe it or not.”<ref name="Knuth1962">{{cite journal |last1=Knuth |first1=Donald E. |title=A HISTORY OF WRITING COMPILERS |year=1962 |publisher=Edmund C. Berkeley |journal=Computers and Automation |volume=11 |issue=12 |pages=8–14 |url=https://archive.org/details/bitsavers_computersA_13990695}}</ref>
</blockquote>
{{missing information|section|why parenthesization works|date=May 2023}}
Example code of a simple C application that handles parenthesisation of basic math operators (<code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>, <code>^</code>, <code>(</code> and <code>)</code><!-- parentheses -->):
Line 127 ⟶ 131:
#include <string.h>
// The command-line argument boundary is our lexer.
int main(int argc, char *argv[]) {
int i;
printf("((((");
for (i=1; i!=argc; i++) {
// strlen(argv[i]) == 2
if (argv[i] && !argv[i][1]) {
switch (*argv[i]) {
case '(': printf("(((("); continue;
case ')': printf("))))"); continue;
case '^': printf(")^("); continue;
case '*': printf("))*(("); continue;
case '/': printf("))/(("); continue;
case '+':
// unary check: either first or had an operator expecting secondary argument
if (i == 1 || strchr("(^*/+-", *argv[i-1]))
printf("+");
Line 159 ⟶ 166:
</syntaxhighlight>
First, you need to compile your program. Assuming your program is written in C and the source code is in a file named program.c, you would use the following command:
<pre>
The above command tells gcc to compile program.c and create an executable named program.
Command to run the program with parameters, For example; a * b + c ^ d / e
<pre>./program a '*' b + c '^' d / e</pre>
it produces
<pre>((((a))*((b)))+(((c)^(d))/((e))))</pre>
Line 177 ⟶ 189:
* {{cite web| last=Clarke | first=Keith | date=1992-05-26 | title=Re: compact recursive-descent parsing of expressions | url=http://groups.google.com/group/comp.compilers/browse_thread/thread/aee24b9504d527ca/1210ef8ae529accd?#1210ef8ae529accd | access-date=2012-01-24}}
* [http://groups.google.com/group/comp.compilers/browse_thread/thread/442ca111b2dfb38d/5390237263b3625b?#5390237263b3625b Example C++ code by Keith Clarke for parsing infix expressions using the precedence climbing method]
* {{cite journal| last=Samelson | first=Klaus | author-link=Klaus Samelson |author2=Friedrich L. Bauer |author2-link=Friedrich L. Bauer |date=February 1960 | title=Sequential formula translation | journal=Communications of the ACM | volume=3 | issue=2 | pages=76–83 | doi=10.1145/366959.366968| doi-access=free }}
* [https://web.archive.org/web/20160817143616/http://radovan-augustin.info/techpapers/parser/Parser.pdf Parser for expression with infix notation using precedence lists]
{{Parsers}}
|