Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

Practical, General Parser Combinators

Ali Afroozeh
January 19, 2016

Practical, General Parser Combinators

Presented at PEPM '16 in St. Petersburg, FL, January 2016.

Event link:
http://conf.researchr.org/track/POPL-2016/pepm-2016-main#program

Meerkat parsers: http://meerkat-parser.github.io/

Ali Afroozeh

January 19, 2016
Tweet

More Decks by Ali Afroozeh

Other Decks in Research

Transcript

  1. E ::= '-' E | E '*' E | E

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

    '+' E | Num E ::= E '+' T | T T ::= T '*' F | F F ::= '-' F | Num '*' > '+' Expressivity
  3. 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
  4. 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
  5. 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
  6. 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
  7. 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
 ;
  8. Recursive-descent parsing Memoization in CFGs Norvig 91 Memoization in CPS

    Johnson 91 Recursive-ascent parsing Penello 86 LR Parsing Knuth 65
  9. 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
  10. 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
  11. 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
  12. 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
  13. 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
  14. 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
  15. 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
  16. 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
  17. 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
  18. 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]

  19. 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)
  20. 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
  21. 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)))
  22. 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)))
  23. 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]
 }
  24. 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]
  25. 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]
  26. 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))
  27. 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)))
 }
  28. 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)))
 }
  29. 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)
 })
 }
  30. 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)
 })
 }
  31. 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)
 })
 }
  32. 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)
 })
 }
  33. Memoization on continutations S ::= S S S | S

    S | b Multiple calls at the same input position
  34. 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) }
 }
  35. S ::= a S b S | a S |

    s Input: aasb
  36. 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
  37. 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
  38. 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
  39. 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))
  40. 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))))
  41. 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)))
  42. 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
  43. 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
  44. Operator Precedence val E: OperatorNonterminal = syn ( right{ E

    ~ "^" ~ E } |> "-" ~ E |> left ( E ~ "*" ~ E | E ~ "/" ~ E ) |> left ( E ~ "+" ~ E | E ~ "-" ~ E ) | "(" ~ E ~ ")" | "[0-9]".r )
  45. 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)
  46. ) 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)