Slide 1

Slide 1 text

Practical, General Parser Combinators Anastasia Izmaylova, Ali Afroozeh and Tijs van der Storm

Slide 2

Slide 2 text

Trade-offs Flexibility Expressivity Performance

Slide 3

Slide 3 text

Performance Compiler construction DSLs Reverse Engineering Speed Natural grammars Modularity

Slide 4

Slide 4 text

Performance Compiler construction DSLs Reverse Engineering Speed Natural grammars Modularity

Slide 5

Slide 5 text

Performance Compiler construction DSLs Reverse Engineering Speed Natural grammars Modularity General parsing technology

Slide 6

Slide 6 text

Performance O(n) O(n3) Deterministic Highly Ambiguous

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

E ::= '-' E | E '*' E | E '+' E | Num '*' > '+' Expressivity

Slide 10

Slide 10 text

E ::= '-' E | E '*' E | E '+' E | Num E ::= E '+' T | T T ::= T '*' F | F F ::= '-' F | Num '*' > '+' Expressivity

Slide 11

Slide 11 text

E ::= '-' E | E '*' E | E '+' E | Num E ::= E '+' T | T T ::= T '*' F | F F ::= '-' F | Num E ::= T E1 E1 ::= '+' T E1 | ε T ::= F T1 T1 ::= '*' F | ε F ::= '-' F | Num '*' > '+' Expressivity

Slide 12

Slide 12 text

E ::= '-' E | E '*' E | E '+' E | Num E ::= E '+' T | T T ::= T '*' F | F F ::= '-' F | Num E ::= T E1 E1 ::= '+' T E1 | ε T ::= F T1 T1 ::= '*' F | ε F ::= '-' F | Num '*' > '+' Expressivity

Slide 13

Slide 13 text

E ::= '-' E | E '*' E | E '+' E | Num E ::= E '+' T | T T ::= T '*' F | F F ::= '-' F | Num E ::= T E1 E1 ::= '+' T E1 | ε T ::= F T1 T1 ::= '*' F | ε F ::= '-' F | Num '*' > '+' Expressivity

Slide 14

Slide 14 text

E ::= '-' E | E '*' E | E '+' E | Num E ::= E '+' T | T T ::= T '*' F | F F ::= '-' F | Num E ::= T E1 E1 ::= '+' T E1 | ε T ::= F T1 T1 ::= '*' F | ε F ::= '-' F | Num '*' > '+' Expressivity

Slide 15

Slide 15 text

Flexibility def Primary = ( PrimaryNoNewArray | ArrayCreationExpression ) def PrimaryNoNewArray = ( Literal | Type ~ "." ~ "class" | "void" ~ "." ~ "class" | "this" | ClassName ~ "." ~ "this" | "(" ~ Expression ~ ")" | ClassInstanceCreationExpression | FieldAccess | MethodInvocation | ArrayAccess ) def Literal = ( IntegerLiteral | FloatingPointLiteral | BooleanLiteral | CharacterLiteral | StringLiteral | NullLiteral ) primary : '(' primaryNoNewArray ')'
 | arrayCreationExpression
 ; 
 primaryNoNewArray : literal
 | type '.' 'class' | 'void' '.' 'class' | 'this' | className '.' 'this' | '(' type ')' | '(' expression ')' | classInstanceCreationExpression | fieldAccess | methodInvocation | arrayAccess
 ; literal : integerLiteral
 | floatingPointLiteral | booleanLiteral | characterLiteral | stringLiteral | nullLiteral
 ;

Slide 16

Slide 16 text

General top-down parsing

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

Recursive-descent parsing

Slide 19

Slide 19 text

Recursive-descent parsing Memoization in CFGs Norvig 91

Slide 20

Slide 20 text

Recursive-descent parsing Memoization in CFGs Norvig 91 Memoization in CPS Johnson 91

Slide 21

Slide 21 text

Recursive-descent parsing Memoization in CFGs Norvig 91 Memoization in CPS Johnson 91 LR Parsing Knuth 65

Slide 22

Slide 22 text

Recursive-descent parsing Memoization in CFGs Norvig 91 Memoization in CPS Johnson 91 Recursive-ascent parsing Penello 86 LR Parsing Knuth 65

Slide 23

Slide 23 text

Recursive-descent parsing Memoization in CFGs Norvig 91 Memoization in CPS Johnson 91 Recursive-ascent parsing Penello 86 LR Parsing Knuth 65 GLR Parsing Tomita 85

Slide 24

Slide 24 text

Recursive-descent parsing Memoization in CFGs Norvig 91 Memoization in CPS Johnson 91 Recursive-ascent parsing Penello 86 LR Parsing Knuth 65 GLR Parsing Tomita 85 RNGLR Parsing Scott and Johnstone 06

Slide 25

Slide 25 text

Recursive-descent parsing Memoization in CFGs Norvig 91 Memoization in CPS Johnson 91 Recursive-ascent parsing Penello 86 LR Parsing Knuth 65 GLR Parsing Tomita 85 RNGLR Parsing Scott and Johnstone 06 GLR with reduced stack Aycock and Horspool 99

Slide 26

Slide 26 text

Recursive-descent parsing Memoization in CFGs Norvig 91 Memoization in CPS Johnson 91 Recursive-ascent parsing Penello 86 LR Parsing Knuth 65 GLR Parsing Tomita 85 RNGLR Parsing Scott and Johnstone 06 GLR with reduced stack Aycock and Horspool 99 RIGLR Scott and Johnstone 05

Slide 27

Slide 27 text

Recursive-descent parsing Memoization in CFGs Norvig 91 Memoization in CPS Johnson 91 Recursive-ascent parsing Penello 86 LR Parsing Knuth 65 GLR Parsing Tomita 85 RNGLR Parsing Scott and Johnstone 06 GLR with reduced stack Aycock and Horspool 99 RIGLR Scott and Johnstone 05 GLL Parsing Scott and Johnstone 13

Slide 28

Slide 28 text

Recursive-descent parsing Memoization in CFGs Norvig 91 Memoization in CPS Johnson 91 Recursive-ascent parsing Penello 86 LR Parsing Knuth 65 GLR Parsing Tomita 85 RNGLR Parsing Scott and Johnstone 06 GLR with reduced stack Aycock and Horspool 99 RIGLR Scott and Johnstone 05 GLL Parsing Scott and Johnstone 13 GLL parsing with a different GSS Afroozeh and Izmaylova 15

Slide 29

Slide 29 text

Recursive-descent parsing Memoization in CFGs Norvig 91 Memoization in CPS Johnson 91 Recursive-ascent parsing Penello 86 LR Parsing Knuth 65 GLR Parsing Tomita 85 RNGLR Parsing Scott and Johnstone 06 GLR with reduced stack Aycock and Horspool 99 RIGLR Scott and Johnstone 05 GLL Parsing Scott and Johnstone 13 GLL parsing with a different GSS Afroozeh and Izmaylova 15 This work

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

Basic RD recognizers

Slide 32

Slide 32 text

Basic RD recognizers Memorized CPS recognizers Memorization in top-down parsing Johnson '91

Slide 33

Slide 33 text

Basic RD recognizers Cubic CPS recognizers Memorized CPS recognizers Memorization in top-down parsing Johnson '91

Slide 34

Slide 34 text

Basic RD recognizers Cubic CPS recognizers Binarized SPPFs Memorized CPS recognizers Memorization in top-down parsing Johnson '91 BRNGLR, Scott & Johnstone ’07 GLL Parsing, Scott & Johnstone '13

Slide 35

Slide 35 text

Basic RD recognizers Cubic CPS recognizers Binarized SPPFs Memorized CPS recognizers Memorization in top-down parsing Johnson '91 BRNGLR, Scott & Johnstone ’07 GLL Parsing, Scott & Johnstone '13 Cubic CPS parsers

Slide 36

Slide 36 text

Basic recursive-descent recognizers type Result[T] = Option[T]
 def success[T](t: T) = Some(t)
 def failure[T] = None

Slide 37

Slide 37 text

Basic recursive-descent recognizers type Result[T] = Option[T]
 def success[T](t: T) = Some(t)
 def failure[T] = None type Recognizer = Int => Result[Int]


Slide 38

Slide 38 text

Basic recursive-descent recognizers type Result[T] = Option[T]
 def success[T](t: T) = Some(t)
 def failure[T] = None type Recognizer = Int => Result[Int]
 def epsilon: Recognizer =
 i => success(i)

Slide 39

Slide 39 text

Basic recursive-descent recognizers type Result[T] = Option[T]
 def success[T](t: T) = Some(t)
 def failure[T] = None type Recognizer = Int => Result[Int]
 def epsilon: Recognizer =
 i => success(i) def terminal(t: String): Recognizer =
 i => if(input.startsWith(t, i)) success(i + t.length) else failure

Slide 40

Slide 40 text

Basic recursive-descent recognizers type Result[T] = Option[T]
 def success[T](t: T) = Some(t)
 def failure[T] = None type Recognizer = Int => Result[Int]
 def epsilon: Recognizer =
 i => success(i) def terminal(t: String): Recognizer =
 i => if(input.startsWith(t, i)) success(i + t.length) else failure def seq(rs: Recognizer*): Recognizer =
 rs.reduceLeft((cur, r) => (i => cur(i).flatMap(r)))

Slide 41

Slide 41 text

Basic recursive-descent recognizers type Result[T] = Option[T]
 def success[T](t: T) = Some(t)
 def failure[T] = None type Recognizer = Int => Result[Int]
 def epsilon: Recognizer =
 i => success(i) def terminal(t: String): Recognizer =
 i => if(input.startsWith(t, i)) success(i + t.length) else failure def seq(rs: Recognizer*): Recognizer =
 rs.reduceLeft((cur, r) => (i => cur(i).flatMap(r))) 
 
 
 
 
 
 def rule(nt: String, alts: Recognizer*): Recognizer =
 alts.reduce((cur, alt) => i => cur(i).orElse(alt(i)))

Slide 42

Slide 42 text

Full backtracking

Slide 43

Slide 43 text

Full backtracking trait MonadPlus[T, M[_] <: MonadPlus[_, M]] {
 def map[U](f: T => U): M[U]
 def flatMap[U](f: T => M[U]): M[U]
 def orElse(r: => M[T]): M[T]
 }

Slide 44

Slide 44 text

Full backtracking trait MonadPlus[T, M[_] <: MonadPlus[_, M]] {
 def map[U](f: T => U): M[U]
 def flatMap[U](f: T => M[U]): M[U]
 def orElse(r: => M[T]): M[T]
 } type Result[T] <: MonadPlus[T, Result]

Slide 45

Slide 45 text

Full backtracking trait MonadPlus[T, M[_] <: MonadPlus[_, M]] {
 def map[U](f: T => U): M[U]
 def flatMap[U](f: T => M[U]): M[U]
 def orElse(r: => M[T]): M[T]
 } type Result[T] <: MonadPlus[T, Result] type K[T] = T => Unit
 
 trait Result[T] extends (K[T] => Unit) with MonadPlus[T, Result]

Slide 46

Slide 46 text

Full backtracking r1 = i => k => if (input.charAt(i) == 'a') k(i+1) r2 = i => k => if (input.charAt(i) == 'b') k(i+1) k0: Int => Unit = println(“Success”) r1(i).flatMap(r2): i => k => r1(i)(j => r2(j)(k))

Slide 47

Slide 47 text

Left recursion & memoization

Slide 48

Slide 48 text

Left recursion & memoization def memo[T](f: Int => Result[T]): Int => Result[T] = {
 val table: Map[Int, Result[T]] = HashMap.empty
 i => table.getOrElseUpdate(i, memo_result(f(i)))
 }

Slide 49

Slide 49 text

Left recursion & memoization def memo[T](f: Int => Result[T]): Int => Result[T] = {
 val table: Map[Int, Result[T]] = HashMap.empty
 i => table.getOrElseUpdate(i, memo_result(f(i)))
 }

Slide 50

Slide 50 text

Left recursion & memoization def memo[T](f: Int => Result[T]): Int => Result[T] = {
 val table: Map[Int, Result[T]] = HashMap.empty
 i => table.getOrElseUpdate(i, memo_result(f(i)))
 } def memo_result[T](res: => Result[T]): Result[T] = {
 val Rs: MutableList[T] = MutableList.empty
 val Ks: MutableList[K[T]] = MutableList.empty
 return result(k =>
 if(Ks.isEmpty) {
 Ks += k
 val k_i: K[T] = t => if (!Rs.contains(t)) { 
 Rs += t; for(kt <- Ks) kt(t) 
 }
 res(k_i)
 } else {
 Ks += k
 for(t <- Rs) k(t)
 })
 }

Slide 51

Slide 51 text

Left recursion & memoization def memo[T](f: Int => Result[T]): Int => Result[T] = {
 val table: Map[Int, Result[T]] = HashMap.empty
 i => table.getOrElseUpdate(i, memo_result(f(i)))
 } def memo_result[T](res: => Result[T]): Result[T] = {
 val Rs: MutableList[T] = MutableList.empty
 val Ks: MutableList[K[T]] = MutableList.empty
 return result(k =>
 if(Ks.isEmpty) {
 Ks += k
 val k_i: K[T] = t => if (!Rs.contains(t)) { 
 Rs += t; for(kt <- Ks) kt(t) 
 }
 res(k_i)
 } else {
 Ks += k
 for(t <- Rs) k(t)
 })
 }

Slide 52

Slide 52 text

Left recursion & memoization def memo[T](f: Int => Result[T]): Int => Result[T] = {
 val table: Map[Int, Result[T]] = HashMap.empty
 i => table.getOrElseUpdate(i, memo_result(f(i)))
 } def memo_result[T](res: => Result[T]): Result[T] = {
 val Rs: MutableList[T] = MutableList.empty
 val Ks: MutableList[K[T]] = MutableList.empty
 return result(k =>
 if(Ks.isEmpty) {
 Ks += k
 val k_i: K[T] = t => if (!Rs.contains(t)) { 
 Rs += t; for(kt <- Ks) kt(t) 
 }
 res(k_i)
 } else {
 Ks += k
 for(t <- Rs) k(t)
 })
 }

Slide 53

Slide 53 text

Left recursion & memoization def memo[T](f: Int => Result[T]): Int => Result[T] = {
 val table: Map[Int, Result[T]] = HashMap.empty
 i => table.getOrElseUpdate(i, memo_result(f(i)))
 } def memo_result[T](res: => Result[T]): Result[T] = {
 val Rs: MutableList[T] = MutableList.empty
 val Ks: MutableList[K[T]] = MutableList.empty
 return result(k =>
 if(Ks.isEmpty) {
 Ks += k
 val k_i: K[T] = t => if (!Rs.contains(t)) { 
 Rs += t; for(kt <- Ks) kt(t) 
 }
 res(k_i)
 } else {
 Ks += k
 for(t <- Rs) k(t)
 })
 }

Slide 54

Slide 54 text

Memoization on continutations S ::= S S S | S S | b

Slide 55

Slide 55 text

Memoization on continutations S ::= S S S | S S | b Multiple calls at the same input position

Slide 56

Slide 56 text

Memoization on continutations S ::= S S S | S S | b Multiple calls at the same input position def memo_k[T](f: T => Unit): T => Unit = {
 val s: Set[T] = HashSet.empty
 return t => if(!s.contains(t)) { s += t; f(t) }
 }

Slide 57

Slide 57 text

S ::= a S b S | a S | s Input: aasb

Slide 58

Slide 58 text

S, 0, 4 a, 0, 1 S, 1, 3 b, 3, 4 a, 1, 2 S, 2, 3 s, 2, 3 S, 1, 4 S, 0, 4 a, 0, 1 S, 2, 3 s, 2, 3 a, 1, 2 b, 3, 4 a (a) Parse tree 1 (b) Parse tree 2 S, 0, 4 a, 0, 1 S, 1, 3 b, 3, 4 a, 1, 2 S, 2, 3 s, 2, 3 S, 1, 4 S, 0, 4 a, 0, 1 S, 2, 3 s, 2, 3 a, 1, 2 b, 3, 4 (a) Parse tree 1 (b) Parse tree 2 S ::= a S b S | a S | s Input: aasb

Slide 59

Slide 59 text

S, 0, 4 a, 0, 1 S, 1, 3 b, 3, 4 a, 1, 2 S, 2, 3 s, 2, 3 S, 1, 4 S, 0, 4 a, 0, 1 S, 2, 3 s, 2, 3 a, 1, 2 b, 3, 4 a (a) Parse tree 1 (b) Parse tree 2 S, 0, 4 a, 0, 1 S, 1, 3 b, 3, 4 a, 1, 2 S, 2, 3 s, 2, 3 S, 1, 4 S, 0, 4 a, 0, 1 S, 2, 3 s, 2, 3 a, 1, 2 b, 3, 4 (a) Parse tree 1 (b) Parse tree 2 , 0, 4 , 1, 3 b, 3, 4 S, 2, 3 s, 2, 3 S, 1, 4 S, 0, 4 a, 0, 1 S, 2, 3 s, 2, 3 a, 1, 2 b, 3, 4 S, 0, 4 a, 0, 1 S, 1, 3 b, 3, 4 a, 1, 2 S, 2, 3 s, 2, 3 S, 1, 4 a, 0, 1 S, 1, 3 a, 1, 2 S ::= a S . b, 0, 3 (S ::= aSb., 3) rse tree 1 (b) Parse tree 2 (c) SPPF (d) B S ::= a S b S | a S | s Input: aasb

Slide 60

Slide 60 text

S, 0, 4 a, 0, 1 S, 1, 3 b, 3, 4 a, 1, 2 S, 2, 3 s, 2, 3 S, 1, 4 S, 0, 4 a, 0, 1 S, 2, 3 s, 2, 3 a, 1, 2 b, 3, 4 a (a) Parse tree 1 (b) Parse tree 2 S, 0, 4 a, 0, 1 S, 1, 3 b, 3, 4 a, 1, 2 S, 2, 3 s, 2, 3 S, 1, 4 S, 0, 4 a, 0, 1 S, 2, 3 s, 2, 3 a, 1, 2 b, 3, 4 (a) Parse tree 1 (b) Parse tree 2 S ::= a S b S | a S | s 4 3 b, 3, 4 S, 0, 4 a, 0, 1 S, 1, 3 b, 3, 4 a, 1, 2 S, 2, 3 s, 2, 3 S, 1, 4 S, 0, 4 a, 0, 1 S, 1, 3 b, 3, 4 a, 1, 2 S, 2, 3 s, 2, 3 S, 1, 4 S ::= a S . b, 0, 3 S ::= a S . b, 1, 3 (S ::= aSb., 3) (S ::= aS., 1) ee 2 (c) SPPF (d) Binarized SPPF Input: aasb

Slide 61

Slide 61 text

Cubic CPS parsers type Parser = Int => Result[SPPFNode]

Slide 62

Slide 62 text

Cubic CPS parsers type Parser = Int => Result[SPPFNode] def terminal(t: String): Parser = i => if(input.startsWith(t, i)) success(sppf.getTerminalNode(t, i, i + t.length)) else failure
 def epsilon: Parser = i => success(sppf.getEpsilonNode(i))

Slide 63

Slide 63 text

Cubic CPS parsers type Parser = Int => Result[SPPFNode] def terminal(t: String): Parser = i => if(input.startsWith(t, i)) success(sppf.getTerminalNode(t, i, i + t.length)) else failure
 def epsilon: Parser = i => success(sppf.getEpsilonNode(i)) def seq(ps: Parser*): Parser = ps.reduceLeft(seq2) def seq2(p1: Parser, p2: Parser) = fix(q => i => p1(i).flatMap(t1 => p2(t1.rightExtent).map(t2 => sppf.getIntermediateNode(q, t1, t2))))

Slide 64

Slide 64 text

Cubic CPS parsers type Parser = Int => Result[SPPFNode] def terminal(t: String): Parser = i => if(input.startsWith(t, i)) success(sppf.getTerminalNode(t, i, i + t.length)) else failure
 def epsilon: Parser = i => success(sppf.getEpsilonNode(i)) def seq(ps: Parser*): Parser = ps.reduceLeft(seq2) def seq2(p1: Parser, p2: Parser) = fix(q => i => p1(i).flatMap(t1 => p2(t1.rightExtent).map(t2 => sppf.getIntermediateNode(q, t1, t2)))) def rule(nt: String, alts: Parser*): Parser = alts.map(rule1(nt, _)).reduce((cur, p) => i => cur(i).orElse(p(i))) def rule1(nt: String, p: Parser): Parser = fix(q => i => p(i).map(t => sppf.getNonterminalNode(nt, q, t)))

Slide 65

Slide 65 text

Highly-ambiguous grammar 0 100 200 300 400 500 0 2000 6000 10000 Size (#characters) CPU time (ms) ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● ● y = 0.000064 x3 + 0.0137 x2 − 2.8824 x 91.2971 R2 = 0.9998 Regression line S ::= SSS | SS | b

Slide 66

Slide 66 text

Pragmatics

Slide 67

Slide 67 text

Pragmatics • Lexical disambiguation filters

Slide 68

Slide 68 text

Pragmatics • Lexical disambiguation filters • Layout (whitespace/comment) insertion

Slide 69

Slide 69 text

Pragmatics • Lexical disambiguation filters • Layout (whitespace/comment) insertion • Semantic actions and terms

Slide 70

Slide 70 text

Pragmatics • Lexical disambiguation filters • Layout (whitespace/comment) insertion • Semantic actions and terms See our ScalaDays 2015 talk!

Slide 71

Slide 71 text

Java 3 4 5 0 1 2 3 Size (#characters) in log10 CPU time (ms) in log10 y = 1.138201 x − 8.696786 R2 = 0.9828 Regression line 7449 Java source files from JDK 1.7.0_60-b19

Slide 72

Slide 72 text

Operator Precedence val E: OperatorNonterminal = syn ( right{ E ~ "^" ~ E } |> "-" ~ E |> left ( E ~ "*" ~ E | E ~ "/" ~ E ) |> left ( E ~ "+" ~ E | E ~ "-" ~ E ) | "(" ~ E ~ ")" | "[0-9]".r )

Slide 73

Slide 73 text

val Primary: Nonterminal = syn ( PrimaryNoNewArray | ArrayCreationExpression ) val PrimaryNoNewArray: Nonterminal = syn ( Literal | Type ~ "." ~ "class" | "void" ~ "." ~ "class" | "this" | ClassName ~ "." ~ "this" | "(" ~ Expression ~ ")" | ClassInstanceCreationExpression | FieldAccess | MethodInvocation | ArrayAccess ) val Literal: Nonterminal = syn ( IntegerLiteral | FloatingPointLiteral | BooleanLiteral | CharacterLiteral | StringLiteral | NullLiteral ) val IntegerLiteral: Nonterminal = syn ( DecimalIntegerLiteral.!>>(".") | HexIntegerLiteral.!>>(".") | OctalIntegerLiteral | BinaryIntegerLiteral ) val FloatingPointLiteral: Nonterminal = syn ( DecimalFloatingPointLiteral | HexadecimalFloatingPointLiteral ) val ClassInstanceCreationExpression: Nonterminal = syn ( "new" ~ TypeArguments.? ~ TypeDeclSpecifier ~ TypeArguments | (Primary | QualifiedIdentifier).! ~ "." ~ "new" ~ TypeArgum ) val TypeArgumentsOrDiamond: Nonterminal = syn ( "<" ~ ">" | TypeArguments ) val ArgumentList: Nonterminal = syn (Expression.+(",")) val ArrayCreationExpression: Nonterminal = syn ( "new" ~ (PrimitiveType | ReferenceType).! ~ DimExpr.+ ~ ("[ val Expression: OperatorNonterminal = syn ( Expression ~ "." ~ Identifier | Expression ~ "." ~ "this" | Expression ~ "." ~ "new" ~ TypeArguments.? ~ Identifier ~ TypeArgumentsOrDiamond.? ~ "(" ~ ArgumentList.? ~ ")" ~ ClassBody.? | Expression ~ "." ~ NonWildTypeArguments ~ ExplicitGenericInvocationSuffix | Expression ~ "." ~ "super" ~ ("." ~ Identifier).!.? ~ Arguments | Type ~ "." ~ "class" | "void" ~ "." ~ "class" | Expression ~ "(" ~ ArgumentList.? ~ ")" | Expression ~ "[" ~ Expression ~ "]" |> Expression ~ "++" | Expression ~ "--" |> "+".!>>("+") ~ Expression | "-".!>>("-") ~ Expression | "++" ~ Expression | "--" ~ Expression | "!" ~ Expression | "~" ~ Expression | "new" ~ ClassInstanceCreationExpression | "new" ~ ArrayCreationExpression | "(" ~ PrimitiveType ~ ")" ~ Expression | "(" ~ ReferenceType ~ ")" ~ Expression |> left ( Expression ~ "*" ~ Expression | Expression ~ "/" ~ Expression | Expression ~ "%" ~ Expression ) |> left ( Expression ~ "+".!>>("+") ~ Expression | Expression ~ "-".!>>("-") ~ Expression ) |> left ( Expression ~ "<<" ~ Expression | Expression ~ ">>".!>>(">") ~ Expression | Expression ~ ">>>" ~ Expression ) |> left ( Expression ~ "<".!>>("[=<]".r) ~ Expression | Expression ~ ">".!>>("[=>]".r) ~ Expression | Expression ~ "<=" ~ Expression | Expression ~ ">=" ~ Expression | Expression ~ "instanceof" ~ Type ) |> left ( Expression ~ "==" ~ Expression | Expression ~ "!=" ~ Expression ) |> Expression ~ "&".!>>("&") ~ Expression |> Expression ~ "^" ~ Expression |> Expression ~ "|".!>>("|") ~ Expression |> Expression ~ "&&" ~ Expression |> Expression ~ "||" ~ Expression |> Expression ~ "?" ~ Expression ~ ":" ~ Expression |> Expression ~ AssignmentOperator ~ Expression | "(" ~ Expression ~ ")" | Primary)

Slide 74

Slide 74 text

) val InclusiveOrExpression: Nonterminal = syn ( ExclusiveOrExpression | InclusiveOrExpression ~ "|" ~ ExclusiveOrExpression ) val ConditionalAndExpression: Nonterminal = syn ( InclusiveOrExpression | ConditionalAndExpression ~ "&&" ~ InclusiveOrExpression ) val ConditionalOrExpression: Nonterminal = syn ( ConditionalAndExpression | ConditionalOrExpression ~ "||" ~ ConditionalAndExpression ) val ConditionalExpression: Nonterminal = syn ( ConditionalOrExpression | ConditionalOrExpression ~ "?" ~ Expression ~ ":" ~ Conditio ) val AssignmentExpression: Nonterminal = syn ( ConditionalExpression | Assignment ) val Assignment: Nonterminal = syn ( LeftHandSide ~ AssignmentOperator ~ AssignmentExpression ) val LeftHandSide: Nonterminal = syn ( ExpressionName | "(" ~ LeftHandSide ~ ")" | FieldAccess | ArrayAccess ) val AssignmentOperator: Nonterminal = syn ( "=" | "+=" | "-=" | "*=" | "/=" | "&=" | "|=" | "^=" | "%=" | "<<=" | ">>=" | ">>>=" ) val Expression: Nonterminal = syn ( AssignmentExpression ) val Expression: OperatorNonterminal = syn ( Expression ~ "." ~ Identifier | Expression ~ "." ~ "this" | Expression ~ "." ~ "new" ~ TypeArguments.? ~ Identifier ~ TypeArgumentsOrDiamond.? ~ "(" ~ ArgumentList.? ~ ")" ~ ClassBody.? | Expression ~ "." ~ NonWildTypeArguments ~ ExplicitGenericInvocationSuffix | Expression ~ "." ~ "super" ~ ("." ~ Identifier).!.? ~ Arguments | Type ~ "." ~ "class" | "void" ~ "." ~ "class" | Expression ~ "(" ~ ArgumentList.? ~ ")" | Expression ~ "[" ~ Expression ~ "]" |> Expression ~ "++" | Expression ~ "--" |> "+".!>>("+") ~ Expression | "-".!>>("-") ~ Expression | "++" ~ Expression | "--" ~ Expression | "!" ~ Expression | "~" ~ Expression | "new" ~ ClassInstanceCreationExpression | "new" ~ ArrayCreationExpression | "(" ~ PrimitiveType ~ ")" ~ Expression | "(" ~ ReferenceType ~ ")" ~ Expression |> left ( Expression ~ "*" ~ Expression | Expression ~ "/" ~ Expression | Expression ~ "%" ~ Expression ) |> left ( Expression ~ "+".!>>("+") ~ Expression | Expression ~ "-".!>>("-") ~ Expression ) |> left ( Expression ~ "<<" ~ Expression | Expression ~ ">>".!>>(">") ~ Expression | Expression ~ ">>>" ~ Expression ) |> left ( Expression ~ "<".!>>("[=<]".r) ~ Expression | Expression ~ ">".!>>("[=>]".r) ~ Expression | Expression ~ "<=" ~ Expression | Expression ~ ">=" ~ Expression | Expression ~ "instanceof" ~ Type ) |> left ( Expression ~ "==" ~ Expression | Expression ~ "!=" ~ Expression ) |> Expression ~ "&".!>>("&") ~ Expression |> Expression ~ "^" ~ Expression |> Expression ~ "|".!>>("|") ~ Expression |> Expression ~ "&&" ~ Expression |> Expression ~ "||" ~ Expression |> Expression ~ "?" ~ Expression ~ ":" ~ Expression |> Expression ~ AssignmentOperator ~ Expression | "(" ~ Expression ~ ")" | Primary)

Slide 75

Slide 75 text

Meerkat Parsers Anastasia Izmaylova @IAnastassija & Ali Afroozeh @afruze https://github.com/meerkat-parser