Feat: add compound assignment and shift operators
Compound assignment: +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>= Shift: <<, >> Each compound assignment token parses at the same precedence as `=` (right-associative, lowest) and produces ExprKind::CompoundAssign. Shifts parse between additive and multiplicative precedence. GRAMMAR.ebnf and SYNTAX.md updated accordingly.
This commit is contained in:
44
GRAMMAR.ebnf
44
GRAMMAR.ebnf
@@ -36,20 +36,27 @@ top_level_def = func_def
|
||||
expr = assign_expr ;
|
||||
|
||||
|
||||
(* --- Assignment (lowest-precedence binary operator) --- *)
|
||||
(* --- Assignment and compound assignment (lowest precedence) --- *)
|
||||
(* *)
|
||||
(* Uses token `=`; right-associative via recursion. *)
|
||||
(* The optional form encodes at-most-one assignment target: chains *)
|
||||
(* like `a = b = c` parse as `a = (b = c)` thanks to right *)
|
||||
(* recursion. *)
|
||||
(* assign_op covers `=` and all compound-assignment operators. *)
|
||||
(* All have the same precedence and are right-associative: *)
|
||||
(* `a = b = c` → `a = (b = c)` *)
|
||||
(* `a += b += c` → `a += (b += c)` (unusual but syntactically *)
|
||||
(* valid; semantics checked later) *)
|
||||
(* *)
|
||||
(* Compound assignments expand semantically: *)
|
||||
(* `x += y` → `x = x + y` *)
|
||||
(* `x -= y` → `x = x - y` etc. *)
|
||||
(* *)
|
||||
(* LL(1): after or_expr, peek at next token. *)
|
||||
(* "=" → consume and recurse into assign_expr *)
|
||||
(* assign_op token → consume and recurse into assign_expr *)
|
||||
(* other → return the or_expr as-is *)
|
||||
(* "=" is not in FIRST(stmt), so expr_stmt can still be *)
|
||||
(* distinguished from other statement kinds. *)
|
||||
(* None of the assign_op tokens are in FIRST(stmt), so expr_stmt *)
|
||||
(* remains unambiguous. *)
|
||||
|
||||
assign_expr = or_expr , [ "=" , assign_expr ] ;
|
||||
assign_expr = or_expr , [ assign_op , assign_expr ] ;
|
||||
|
||||
assign_op = "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^=" | "<<=" | ">>=" ;
|
||||
|
||||
|
||||
(* --- Logical OR (lowest-precedence binary operator) --- *)
|
||||
@@ -83,8 +90,14 @@ bitand_expr = additive_expr , { "&" , additive_expr } ;
|
||||
|
||||
(* --- Additive: addition and subtraction --- *)
|
||||
|
||||
additive_expr = multiplicative_expr ,
|
||||
{ ( "+" | "-" ) , multiplicative_expr } ;
|
||||
additive_expr = shift_expr ,
|
||||
{ ( "+" | "-" ) , shift_expr } ;
|
||||
|
||||
|
||||
(* --- Shift: left shift and right shift --- *)
|
||||
|
||||
shift_expr = multiplicative_expr ,
|
||||
{ ( "<<" | ">>" ) , multiplicative_expr } ;
|
||||
|
||||
|
||||
(* --- Multiplicative: multiplication, division, modulo --- *)
|
||||
@@ -183,7 +196,7 @@ arg_list = [ expr , { "," , expr } ] ;
|
||||
|
||||
expr_ns = assign_expr_ns ;
|
||||
|
||||
assign_expr_ns = or_expr_ns , [ "=" , assign_expr_ns ] ;
|
||||
assign_expr_ns = or_expr_ns , [ assign_op , assign_expr_ns ] ;
|
||||
|
||||
or_expr_ns = and_expr_ns , { "or" , and_expr_ns } ;
|
||||
and_expr_ns = bitor_expr_ns , { "and" , bitor_expr_ns } ;
|
||||
@@ -192,8 +205,11 @@ bitor_expr_ns = bitxor_expr_ns , { "|" , bitxor_expr_ns } ;
|
||||
bitxor_expr_ns = bitand_expr_ns , { "^" , bitand_expr_ns } ;
|
||||
bitand_expr_ns = additive_expr_ns , { "&" , additive_expr_ns } ;
|
||||
|
||||
additive_expr_ns = multiplicative_expr_ns ,
|
||||
{ ( "+" | "-" ) , multiplicative_expr_ns } ;
|
||||
additive_expr_ns = shift_expr_ns ,
|
||||
{ ( "+" | "-" ) , shift_expr_ns } ;
|
||||
|
||||
shift_expr_ns = multiplicative_expr_ns ,
|
||||
{ ( "<<" | ">>" ) , multiplicative_expr_ns } ;
|
||||
|
||||
multiplicative_expr_ns = unary_expr_ns ,
|
||||
{ ( "*" | "/" | "%" ) , unary_expr_ns } ;
|
||||
|
||||
Reference in New Issue
Block a user