Share
Embed
Meerkat parsers: a general parser combinator library for real programming languages
Presented at ScalaDays 2015, Amsterdam
http://event.scaladays.org/scaladays-amsterdam-2015#!#schedulePopupExtras-6892
Github repository: https://github.com/Anastassija/Meerkat
Anastasia Izmaylova
June 09, 2015
Transcript
94 slides
-
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 -
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 -
Left recursion def E(i: Int)(implicit input: String): Result[Tree] = {
// E ::= E + E E(i) flatMap { j => . . . // E * E . . . } -
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 -
E ::= '-' E | E '*' E | E
'+' E | Num '*' > '+' Natural grammars -
E ::= '-' E | E '*' E | E
'+' E | Num E ::= E '+' T | T T ::= T '*' F | F F ::= '-' F | Num '*' > '+' Natural grammars -
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 -
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 -
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 -
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 -
Backtracking schemes 1 2 3 2 3 4 3 4
5 5 6 A ::= a b | a c "ac" -
Backtracking schemes Deterministic (LL(k)) 1 2 3 2 3 4
3 4 5 5 6 A ::= a b | a c "ac" -
Backtracking schemes Deterministic (LL(k)) 1 2 3 2 3 4
3 4 5 5 6 A ::= a b | a c "ac" -
Backtracking schemes Deterministic (LL(k)) 1 2 3 2 3 4
3 4 5 5 6 A ::= a b | a c "ac" -
"abd" Backtracking schemes Local backtracking (PEG) 1 2 3 2
3 4 3 4 5 5 6 A ::= B d B ::= a | ab -
"abd" Backtracking schemes Local backtracking (PEG) 1 2 3 2
3 4 3 4 5 5 6 A ::= B d B ::= a | ab -
"abd" Backtracking schemes Local backtracking (PEG) 1 2 3 2
3 4 3 4 5 5 6 A ::= B d B ::= a | ab -
"abd" Backtracking schemes Local backtracking (PEG) 1 2 3 2
3 4 3 4 5 5 6 A ::= B d B ::= a | ab -
"abd" Backtracking schemes Local backtracking (PEG) 1 2 3 2
3 4 3 4 5 5 6 A ::= B d B ::= a | ab -
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 -
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 . . . -
if (x > 10) { println(x) } Lexer IF (
ID > 10 ) { ID ( ID ) } Lexing and Parsing -
if (x > 10) { println(x) } Lexer IF (
ID > 10 ) { ID ( ID ) } Lexing and Parsing Whitespace/ Comment -
if (x > 10) { println(x) } Lexer IF (
ID > 10 ) { ID ( ID ) } Lexing and Parsing Whitespace/ Comment Longest Match -
if (x > 10) { println(x) } Lexer IF (
ID > 10 ) { ID ( ID ) } Lexing and Parsing Whitespace/ Comment Longest Match Keyword Reservation -
if (x > 10) { println(x) } Lexer IF (
ID > 10 ) { ID ( ID ) } Lexing and Parsing Whitespace/ Comment Longest Match Keyword Reservation Scannerless Parsing -
Best of both worlds Parser Generators Parser Combinators Flexibility, extensibility
Left recursion Cubic bound Operator precedence Scannerless parsing -
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 -
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 -
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 -
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" -
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] } -
val E: Nonterminal = syn ( E ~ '*' ~
E | E ~ '+' ~ E | Num ) Basic Parsers -
val E: Nonterminal = syn ( E ~ '*' ~
E | E ~ '+' ~ E | Num ) Basic Parsers Tony Sloane, dsinfo library -
val E: Nonterminal = syn ( E ~ '*' ~
E | E ~ '+' ~ E | Num ) 1+2*3 Basic Parsers Tony Sloane, dsinfo library -
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 -
Operator parsers val E: Nonterminal = syn ( E ~
'*' ~ E | E ~ '+' ~ E | Num ) -
Operator parsers val E: OperatorNonterminal = syn ( E ~
'*' ~ E | E ~ '+' ~ E | Num ) -
Operator parsers val E: OperatorNonterminal = syn ( left {
E ~ '*' ~ E } |> left { E ~ '+' ~ E } | Num ) -
Operator parsers val E: OperatorNonterminal = syn ( left {
E ~ '*' ~ E } |> left { E ~ '+' ~ E } | Num ) -
Operator parsers val E: OperatorNonterminal = syn ( left {
E ~ '*' ~ E } |> left { E ~ '+' ~ E } | Num ) -
Operator parsers type OperatorNonterminal = (Int,Int) => Nonterminal val E:
OperatorNonterminal = syn ( left { E ~ '*' ~ E } |> left { E ~ '+' ~ E } | Num ) -
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 ) -
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" -
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(_) } ) -
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(_) } ) -
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(_) } ) -
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(_) } ) -
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(_) } ) -
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! -
Whitespace/Comment def ~ (p: Symbol)(implicit layout: Layout): Sequence if (x
> 10 ) { println(x) } -
Whitespace/Comment def ~ (p: Symbol)(implicit layout: Layout): Sequence def ~~
(p: Symbol): Sequence if (x > 10 ) { println(x) } -
Character-level disambiguation filters val Id = syn ( ('a' --
'z').+ ) if (x > 10 ) { println(x) } -
Character-level disambiguation filters val Id = syn ( ('a'--'z').+ \
("if") ) if (x > 10 ) { println(x) } -
Character-level disambiguation filters val Id = syn ( ('a'--'z').+ \
("if") .!>> ("[a-z]".r) ) if (x > 10 ) { println(x) } -
type DDParser[T] = (Input,Int,SPPFLookup) => Result[(SPPFNode,T)] val L8 = syn
( '~{' ~ Num ~ '+'.? ~ '}' ~ Octet.* ) ~{ 5 } X X X X X Data-dependent parsers -
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 -
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 -
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 -
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 -
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 -
Case study: expression language val = syn ( right {
E ~ |> |> left ( E ~ | E ~ |> left ( E ~ | E ~ | | ) sealed case case case case case case case Associativity groups -
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 -
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 -
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) -
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) -
) 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) -
Operator precedence Left recursion Parse Forest Semantic actions Data- dependency
Meerkat Parsers A @IAnastassija & A @afruze Scannerless Parsing https://github.com/Anastassija/Meerkat