Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Meerkat parsers: a general parser combinator library for real programming languages

Meerkat parsers: a general parser combinator library for real programming languages

Anastasia Izmaylova

June 09, 2015
Tweet

More Decks by Anastasia Izmaylova

Other Decks in Programming

Transcript

  1. An expression language sealed trait E case class Add(l: E,

    r: E) extends E case class Mul(l: E, r: E) extends E case class Sub(l: E, r: E) extends E case class Div(l: E, r: E) extends E case class Neg(l: E) extends E case class Pow(l: E, r: E) extends E case class Num(n: Int) extends E
  2. An expression language E ::= E '+' E | E

    '*' E | E '-' E | E '/' E | '-' E | E '^' E | Num val E: Parser = E ~ '+' ~ E | E ~ '*' ~ E | E ~ '-' ~ E | E ~ '/' ~ E | '-' ~ E | E ~ '^' ~ E | Num BNF-like notation Combinators
  3. Left recursion def E(i: Int)(implicit input: String): Result[Tree] = {

    // E ::= E + E E(i) flatMap { j => . . . // E * E . . . }
  4. Left recursion def E(i: Int)(implicit input: String): Result[Tree] = {

    // E ::= E + E E(i) flatMap { j => . . . // E * E . . . } Left recursion in top-down parsing can lead to non-termination
  5. E ::= '-' E | E '*' E | E

    '+' E | Num '*' > '+' Natural grammars
  6. E ::= '-' E | E '*' E | E

    '+' E | Num E ::= E '+' T | T T ::= T '*' F | F F ::= '-' F | Num '*' > '+' Natural grammars
  7. 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 '*' > '+' Natural grammars
  8. 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 '*' > '+' Natural grammars
  9. 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 '*' > '+' Natural grammars
  10. 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 '*' > '+' Natural grammars
  11. Backtracking schemes 1 2 3 2 3 4 3 4

    5 5 6 A ::= a b | a c "ac"
  12. Nondeterminism and Ambiguity 1*2+3 E E + E E *

    E 1 2 3 E E * E E + E 1 2 3 1*(2+3) (1*2)+3
  13. Expression = AssignmentExpression AssignmentExpression = ConditionalExpression | Assignment ConditionalExpression =

    ConditionalOrExpression | ConditionalOrExpression "?" Expression ":" ConditionalExpression ConditionalOrExpression = ConditionalAndExpression | ConditionalOrExpression "||" ConditionalAndExpression ConditionalAndExpression = InclusiveOrExpression | ConditionalAndExpression "&&" InclusiveOrExpression InclusiveOrExpression = ExclusiveOrExpression | InclusiveOrExpression "|" ExclusiveOrExpression ExclusiveOrExpression = AndExpression | ExclusiveOrExpression "^" AndExpression . . .
  14. if (x > 10) { println(x) } Lexer IF (

    ID > 10 ) { ID ( ID ) } Lexing and Parsing
  15. if (x > 10) { println(x) } Lexer IF (

    ID > 10 ) { ID ( ID ) } Lexing and Parsing Whitespace/ Comment
  16. if (x > 10) { println(x) } Lexer IF (

    ID > 10 ) { ID ( ID ) } Lexing and Parsing Whitespace/ Comment Longest Match
  17. if (x > 10) { println(x) } Lexer IF (

    ID > 10 ) { ID ( ID ) } Lexing and Parsing Whitespace/ Comment Longest Match Keyword Reservation
  18. if (x > 10) { println(x) } Lexer IF (

    ID > 10 ) { ID ( ID ) } Lexing and Parsing Whitespace/ Comment Longest Match Keyword Reservation Scannerless Parsing
  19. Best of both worlds Parser Generators Parser Combinators Flexibility, extensibility

    Left recursion Cubic bound Operator precedence Scannerless parsing
  20. Shared Packed Parse Forest (SPPF) S ::= 'a' S 'b'

    | 'a' S | 's' "aasb" 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
  21. Shared Packed Parse Forest (SPPF) S ::= 'a' S 'b'

    | 'a' S | 's' "aasb" 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 s, 2, 3 s, 2, 3 Figure 1: Two parse trees (left) and their corresponding SPPF (r To enable general context-free parsing in O(n3) without manu ing the grammar, Scott and Johnstone [18] introduced the notio SPPFs, which use additional intermediate nodes. Intermediate the form (L, i, j) where L is a grammar position and i and j are extents. Grammar positions for intermediate nodes are of the fo where |↵| >= 2. For example, S ::= aS · b for the rule S ::= aSb. version of SPPF in Figure 1 is shown in Figure 2. Intermediate similar to nonterminal nodes, can be ambiguous, in which case h one packed nodes as children. 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 ::= aS · b, 0, 3 S ::= aS · b, 1, 3 Figure 2: Binarized SPPF Packed nodes in a binarized SPPF are of the form (L, k), where L
  22. Parse forest representation sealed trait Tree case class Appl(r: Rule,

    ts: Seq[Tree]) extends Tree case class Amb(ts: Set[Tree]) extends Tree case class Terminal(name: String) extends Tree ASF+SDF Rascal Spoofax
  23. Parse forest representation Amb S ::= a S b S

    ::= a S "a" S ::= a S "b" "a" S ::= s "s" "a" S ::= a S b "a" S ::= s "b" "s" S ::= 'a' S 'b' | 'a' S | 's' "aasb"
  24. Basic Parsers type Parser = (Input,Int,SPPFLookup) => Result[SPPFNode] trait Result[+T]

    extends ((T => Unit) => Unit) { def map[U](f: T => U): Result[U] def flatMap[U](f: T => Result[U]): Result[U] def orElse[U >: T](r: Result[U]): Result[U] }
  25. val E: Nonterminal = syn ( E ~ '*' ~

    E | E ~ '+' ~ E | Num ) Basic Parsers
  26. val E: Nonterminal = syn ( E ~ '*' ~

    E | E ~ '+' ~ E | Num ) Basic Parsers Tony Sloane, dsinfo library
  27. val E: Nonterminal = syn ( E ~ '*' ~

    E | E ~ '+' ~ E | Num ) 1+2*3 Basic Parsers Tony Sloane, dsinfo library
  28. val E: Nonterminal = syn ( E ~ '*' ~

    E | E ~ '+' ~ E | Num ) Amb E ::= E * E E ::= E + E E ::= E + E "*" E ::= Num E ::= Num "+" E ::= Num Num ::= [0-9] "1" Num ::= [0-9] "2" Num ::= [0-9] "3" E ::= Num "+" E ::= E * E Num ::= [0-9] "1" E ::= Num "*" E ::= Num Num ::= [0-9] "2" Num ::= [0-9] "3" 1+2*3 Basic Parsers Tony Sloane, dsinfo library
  29. Operator parsers val E: Nonterminal = syn ( E ~

    '*' ~ E | E ~ '+' ~ E | Num )
  30. Operator parsers val E: OperatorNonterminal = syn ( left {

    E ~ '*' ~ E } |> left { E ~ '+' ~ E } | Num )
  31. Operator parsers val E: OperatorNonterminal = syn ( left {

    E ~ '*' ~ E } |> left { E ~ '+' ~ E } | Num )
  32. Operator parsers val E: OperatorNonterminal = syn ( left {

    E ~ '*' ~ E } |> left { E ~ '+' ~ E } | Num )
  33. Operator parsers type OperatorNonterminal = (Int,Int) => Nonterminal val E:

    OperatorNonterminal = syn ( left { E ~ '*' ~ E } |> left { E ~ '+' ~ E } | Num )
  34. Operator parsers E(l,r) = [2>=l,2>=r] E(2,2) '*' E(3,3) // 2

    | [1>=l,1>=r] E(0,0) '+' E(2,2) // 1 | Num type OperatorNonterminal = (Int,Int) => Nonterminal val E: OperatorNonterminal = syn ( left { E ~ '*' ~ E } |> left { E ~ '+' ~ E } | Num )
  35. Operator parsers val E: OperatorNonterminal = syn ( left {

    E ~ '*' ~ E } |> left { E ~ '+' ~ E } | Num ) E(0,0) ::= E(1,1) + E(2,2) E(1,1) ::= Num "+" E(2,2) ::= E(2,2) * E(3,3) Num ::= [0-9] "1" E(2,2) ::= Num "*" E(3,3) ::= Num Num ::= [0-9] "2" Num ::= [0-9] "3"
  36. Semantic actions val E: OperatorNonterminal & Int = syn (

    '-' ~ E & { x => -x } |> left { E ~ '*' ~ E } & { case x~y => x*y } |> left { E ~ '+' ~ E } & { case x~y => x+y } | Num ^ { toInt(_) } )
  37. Semantic actions val E: OperatorNonterminal & Int = syn (

    '-' ~ E & { x => -x } |> left { E ~ '*' ~ E } & { case x~y => x*y } |> left { E ~ '+' ~ E } & { case x~y => x+y } | Num ^ { toInt(_) } )
  38. Semantic actions val E: OperatorNonterminal & Int = syn (

    '-' ~ E & { x => -x } |> left { E ~ '*' ~ E } & { case x~y => x*y } |> left { E ~ '+' ~ E } & { case x~y => x+y } | Num ^ { toInt(_) } )
  39. Semantic actions val E: OperatorNonterminal & Int = syn (

    '-' ~ E & { x => -x } |> left { E ~ '*' ~ E } & { case x~y => x*y } |> left { E ~ '+' ~ E } & { case x~y => x+y } | Num ^ { toInt(_) } )
  40. Semantic actions val E: OperatorNonterminal & Int = syn (

    '-' ~ E & { x => -x } |> left { E ~ '*' ~ E } & { case x~y => x*y } |> left { E ~ '+' ~ E } & { case x~y => x+y } | Num ^ { toInt(_) } )
  41. Semantic actions val E: OperatorNonterminal & Int = syn (

    '-' ~ E & { x => -x } |> left { E ~ '*' ~ E } & { case x~y => x*y } |> left { E ~ '+' ~ E } & { case x~y => x+y } | Num ^ { toInt(_) } ) Executed post-parse!
  42. Whitespace/Comment def ~ (p: Symbol)(implicit layout: Layout): Sequence def ~~

    (p: Symbol): Sequence if (x > 10 ) { println(x) }
  43. Character-level disambiguation filters val Id = syn ( ('a'--'z').+ \

    ("if") .!>> ("[a-z]".r) ) if (x > 10 ) { println(x) }
  44. type DDParser[T] = (Input,Int,SPPFLookup) => Result[(SPPFNode,T)] val L8 = syn

    ( '~{' ~ Num ~ '+'.? ~ '}' ~ Octet.* ) ~{ 5 } X X X X X Data-dependent parsers
  45. type DDParser[T] = (Input,Int,SPPFLookup) => Result[(SPPFNode,T)] val L8 = syn

    ( '~{' ~ Num ~ '+'.? ~ '}' ~ Octet.* ) def Octets(n: Int, p: Nonterminal) = n match { case 0 => syn ( epsilon ) case 1 => syn ( p ) case _ => syn ( (1 to n-2).foldLeft(p ~ p)((q,_) => q ~ p) ) } ~{ 5 } X X X X X Data-dependent parsers
  46. type DDParser[T] = (Input,Int,SPPFLookup) => Result[(SPPFNode,T)] def Octets(n: Int, p:

    Nonterminal) = n match { case 0 => syn ( epsilon ) case 1 => syn ( p ) case _ => syn ( (1 to n-2).foldLeft(p ~ p)((q,_) => q ~ p) ) } val L8 = syn ( '~{' ~ Num.map(toInt) ~ '+'.? ~ '}' ~ Octet.* ) ~{ 5 } X X X X X Data-dependent parsers
  47. type DDParser[T] = (Input,Int,SPPFLookup) => Result[(SPPFNode,T)] def Octets(n: Int, p:

    Nonterminal) = n match { case 0 => syn ( epsilon ) case 1 => syn ( p ) case _ => syn ( (1 to n-2).foldLeft(p ~ p)((q,_) => q ~ p) ) } val L8 = syn ( '~{' ~ Num.map(toInt) ~ '+'.? ~ '}' ~>> {Octets(_,Octet)} ) ~{ 5 } X X X X X Data-dependent parsers
  48. Case study: expression language val E: OperatorNonterminal & E =

    syn ( right { E ~ "^" ~ E } & { case x~y => Pow(x, y) } |> "-" ~ E & { Neg(_) } |> left ( E ~ "*" ~ E & { case x~y => Mul(x, y) } | E ~ "/" ~ E & { case x~y => Div(x, y) } ) |> left ( E ~ "+" ~ E & { case x~y => Add(x, y) } | E ~ "-" ~ E & { case x~y => Sub(x, y) } ) | "(" ~ E ~ ")" | "[0-9]".r ^ { s => Num(toInt(s)) } ) sealed trait E case class Add(l: E, r: E) extends E case class Mul(l: E, r: E) extends E case class Sub(l: E, r: E) extends E case class Div(l: E, r: E) extends E case class Neg(l: E) extends E case class Pow(l: E, r: E) extends E case class Num(n: Int) extends E
  49. Case study: expression language val E: OperatorNonterminal & E =

    syn ( right { E ~ "^" ~ E } & { case x~y => Pow(x, y) } |> "-" ~ E & { Neg(_) } |> left ( E ~ "*" ~ E & { case x~y => Mul(x, y) } | E ~ "/" ~ E & { case x~y => Div(x, y) } ) |> left ( E ~ "+" ~ E & { case x~y => Add(x, y) } | E ~ "-" ~ E & { case x~y => Sub(x, y) } ) | "(" ~ E ~ ")" | "[0-9]".r ^ { s => Num(toInt(s)) } ) sealed trait E case class Add(l: E, r: E) extends E case class Mul(l: E, r: E) extends E case class Sub(l: E, r: E) extends E case class Div(l: E, r: E) extends E case class Neg(l: E) extends E case class Pow(l: E, r: E) extends E case class Num(n: Int) extends E
  50. Case study: expression language val = syn ( right {

    E ~ |> |> left ( E ~ | E ~ |> left ( E ~ | E ~ | | ) sealed case case case case case case case Associativity groups
  51. Case study: expression language val = syn ( right {

    E ~ |> |> left ( E ~ | E ~ |> left ( E ~ | E ~ | | ) sealed case case case case case case case Associativity groups Other character-level filters
  52. Case study: expression language val = syn ( right {

    E ~ |> |> left ( E ~ | E ~ |> left ( E ~ | E ~ | | ) sealed case case case case case case case Associativity groups Other character-level filters EBNF constructs
  53. 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)
  54. 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)
  55. ) 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)
  56. Operator precedence Left recursion Parse Forest Semantic actions Data- dependency

    Meerkat Parsers A @IAnastassija & A @afruze Scannerless Parsing https://github.com/Anastassija/Meerkat