module C-Expressions
imports
  C-Identifiers

exports
  sorts PrimaryExp
  context-free syntax
    IDENTIFIER        -> PrimaryExp
    Constant          -> PrimaryExp
    StringLiteralList -> PrimaryExp
    "(" CommaExp ")"  -> PrimaryExp {bracket}

  sorts PostfixExp
  context-free syntax
    PrimaryExp                           -> PostfixExp
    PostfixExp "[" CommaExp "]"          -> PostfixExp {cons("ArrayIndex")}
    PostfixExp "(" {AssignExp ","}* ")"  -> PostfixExp {cons("FunCall")}
    PostfixExp "."  MemberName           -> PostfixExp {cons("Field")}
    PostfixExp "->" MemberName           -> PostfixExp {cons("DerefMember")}
    PostfixExp "++"                      -> PostfixExp {cons("PostIncr")}
    PostfixExp "--"                      -> PostfixExp {cons("PostDecr")}

  sorts MemberName
  context-free syntax
    IDENTIFIER  -> MemberName
    TypedefName -> MemberName

  sorts UnaryExp
  context-free syntax
    PostfixExp     -> UnaryExp
    "++" UnaryExp  -> UnaryExp {cons("PreIncr")}
    "--" UnaryExp  -> UnaryExp {cons("PreDecr")}
    "&" CastExp    -> UnaryExp {cons("Address")}
    "*" CastExp    -> UnaryExp {cons("Deref")}
    "+" CastExp    -> UnaryExp {cons("Positive")}
    "-" CastExp    -> UnaryExp {cons("Negative")}
    "~" CastExp    -> UnaryExp {cons("Tilde")}
    "!" CastExp    -> UnaryExp {cons("Negation")}

    "sizeof" UnaryExp         -> UnaryExp {cons("SizeofExp")}
    "sizeof" "(" TypeName ")" -> UnaryExp {cons("SizeofType")}

  sorts CastExp
  context-free syntax
    UnaryExp                 -> CastExp
    "(" TypeName ")" CastExp -> CastExp {cons("TypeCast")}

  sorts MulExp
  context-free syntax
    CastExp            -> MulExp
    MulExp "*" CastExp -> MulExp {cons("Mul")}
    MulExp "/" CastExp -> MulExp {cons("Div")}
    MulExp "%" CastExp -> MulExp {cons("Mod")}

  sorts AddExp
  context-free syntax
    MulExp            -> AddExp
    AddExp "+" MulExp -> AddExp {cons("Add")}
    AddExp "-" MulExp -> AddExp {cons("Subt")}

  sorts ShiftExp
  context-free syntax
    AddExp               -> ShiftExp
    ShiftExp "<<" AddExp -> ShiftExp {cons("ShiftLeft")}
    ShiftExp ">>" AddExp -> ShiftExp {cons("ShiftRight")}

  sorts RelExp
  context-free syntax
    ShiftExp             -> RelExp
    RelExp "<" ShiftExp  -> RelExp {cons("Lt")}
    RelExp ">" ShiftExp  -> RelExp {cons("Gt")}
    RelExp "<=" ShiftExp -> RelExp {cons("Le")}
    RelExp ">=" ShiftExp -> RelExp {cons("Ge")}

  sorts EqualityExp
  context-free syntax
    RelExp                  -> EqualityExp
    EqualityExp "==" RelExp -> EqualityExp {cons("Equal")}
    EqualityExp "!=" RelExp -> EqualityExp {cons("NotEqual")}

  sorts ANDExp
  context-free syntax
    EqualityExp            -> ANDExp
    EqualityExp "&" ANDExp -> ANDExp {cons("And")}

  sorts ExclORExp
  context-free syntax
    ANDExp               -> ExclORExp
    ANDExp "^" ExclORExp -> ExclORExp {cons("ExOr")}

  sorts InclORExp
  context-free syntax
    ExclORExp               -> InclORExp
    ExclORExp "|" InclORExp -> InclORExp {cons("IncOr")}

  sorts LogicalANDExp
  context-free syntax
    InclORExp                    -> LogicalANDExp
    LogicalANDExp "&&" InclORExp -> LogicalANDExp {cons("LAnd")}

  lexical restrictions
    "&" -/- [\&]

  sorts LogicalORExp
  context-free syntax
    LogicalANDExp                   -> LogicalORExp
    LogicalORExp "||" LogicalANDExp -> LogicalORExp {cons("LOr")}

  sorts CondExp
  context-free syntax
    LogicalORExp                          -> CondExp
    LogicalORExp "?" CommaExp ":" CondExp -> CondExp {cons("IfExp")}

  sorts AssignExp
  context-free syntax
    CondExp                     -> AssignExp
    UnaryExp AssignOp AssignExp -> AssignExp {cons("Assign")}

  sorts AssignOp
  context-free syntax
    "="   -> AssignOp {cons("AssignEq")}
    "*="  -> AssignOp {cons("AssignMul")}
    "/="  -> AssignOp {cons("AssignDiv")}
    "%="  -> AssignOp {cons("AssignMod")}
    "+="  -> AssignOp {cons("AssignPlus")}
    "-="  -> AssignOp {cons("AssignMin")}
    "<<=" -> AssignOp {cons("AssignSL")}
    ">>=" -> AssignOp {cons("AssignSR")}
    "&="  -> AssignOp {cons("AssignAnd")}
    "^="  -> AssignOp {cons("AssignExp")}
    "|="  -> AssignOp {cons("AssignOr")}

  sorts CommaExp CommaExpOpt
  context-free syntax
    AssignExp              -> CommaExp
    AssignExp "," CommaExp -> CommaExp    {cons("Comma")}

              -> CommaExpOpt {cons("EmptyExp")}
    CommaExp  -> CommaExpOpt

  sorts ConstantExp
  context-free syntax
    CondExp -> ConstantExp

  lexical restrictions
    "+" -/- [\+]
    "-" -/- [\-]
