definition
module C-AbstractDeclarators
exports
  context-free syntax
    "*" TypeQualifier* -> Pointer {cons("PointerOf")}

  context-free syntax
    UnaryAbstractDeclarator      -> AbstractDeclarator
    PostfixAbstractDeclarator    -> AbstractDeclarator
    PostfixingAbstractDeclarator -> AbstractDeclarator

  context-free syntax
    Pointer+ ( PostfixAbstractDeclarator | PostfixingAbstractDeclarator )? -> UnaryAbstractDeclarator {cons("Pointer")}

  context-free syntax
    ArrayAbstractDeclarator                   -> PostfixingAbstractDeclarator
    "(" {ParamDeclaration ","}+ "," "..." ")" -> PostfixingAbstractDeclarator {cons("ParamListVarArgs")}
    "(" {ParamDeclaration ","}* ")"           -> PostfixingAbstractDeclarator {cons("ParamList")}

  context-free syntax
    ArrayAbstractDeclarator? "[" ConstantExp? "]" -> ArrayAbstractDeclarator {cons("ArrayDecl")}

  context-free syntax
    "(" UnaryAbstractDeclarator ")"                              -> PostfixAbstractDeclarator {cons("DeclBracket")}
    "(" PostfixAbstractDeclarator ")"                            -> PostfixAbstractDeclarator {cons("DeclBracket")}
    "(" PostfixingAbstractDeclarator ")"                         -> PostfixAbstractDeclarator {cons("DeclBracket")}
    "(" UnaryAbstractDeclarator ")" PostfixingAbstractDeclarator -> PostfixAbstractDeclarator {cons("FunType")}

module C-ParameterDeclarators
exports
  context-free syntax
    ParamDeclTypeSpec ( AbstractDeclarator | IdDeclarator )?   -> ParamDeclaration {cons("ParamDecl")}
    ( DeclarationSpecifier | TypeSpecifier ) TypedefDeclarator -> ParamDeclaration {cons("ParamDecl2")}

    %%% TODO: These are almost the same as for FunDef ... 

    TypeSpecifier             -> ParamDeclTypeSpec
    DeclarationSpecifier      -> ParamDeclTypeSpec
    DeclarationQualifierList  -> ParamDeclTypeSpec
    TypeQualifier+            -> ParamDeclTypeSpec

  context-free syntax
    TypeSpecifier  AbstractDeclarator? -> TypeName {cons("TypeName")}
    TypeQualifier+ AbstractDeclarator? -> TypeName {cons("TypeName1")}

module C-Enumerators
exports
  context-free syntax
    "enum" IdOrTypedefName? "{" {Enumerator ","}+ "}" -> EnumSpecifier {cons("Enum")}
    "enum" IdOrTypedefName                            -> EnumSpecifier {cons("EnumId")}

  context-free syntax
    IdOrTypedefName EnumeratorValue? -> Enumerator {cons("Enumerator")}

  context-free syntax
    "=" ConstantExp -> EnumeratorValue {cons("EnumVal")}

module C-StructsAndUnions
exports
  context-free syntax
    StructSpecifier -> ElaboratedTypeName
    UnionSpecifier  -> ElaboratedTypeName
    EnumSpecifier   -> ElaboratedTypeName

  context-free syntax
    "struct" IdOrTypedefName? "{" MemberDeclaration+ "}" -> StructSpecifier {cons("Struct")}
    "struct" IdOrTypedefName                             -> StructSpecifier {cons("StructId")}

  context-free syntax
    "union" IdOrTypedefName? "{" MemberDeclaration+ "}" -> UnionSpecifier {cons("Union")}
    "union" IdOrTypedefName                             -> UnionSpecifier {cons("UnionId")}

  context-free syntax
    TypeSpecifier  {MemberDeclarator   ","}+ ";" -> MemberDeclaration {cons("MemDecl")}
    TypeQualifier+ {MemberIdDeclarator ","}+ ";" -> MemberDeclaration {cons("MemDecl1")}

  context-free syntax
    Declarator                  -> MemberDeclarator
    Declarator? ":" ConstantExp -> MemberDeclarator {cons("BitFieldSize")}

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
    "+" -/- [\+]
    "-" -/- [\-]

module C-Types
imports
  C-Expressions

exports
  context-free syntax
    "typedef"  -> StorageClass {cons("Typedef")}
    "extern"   -> StorageClass {cons("Extern")}
    "static"   -> StorageClass {cons("Static")}
    "auto"     -> StorageClass {cons("Auto")}
    "register" -> StorageClass {cons("Register")}

  context-free syntax
    "int"      -> BasicTypeName {cons("Int")}
    "char"     -> BasicTypeName {cons("Char")}
    "short"    -> BasicTypeName {cons("Short")}
    "long"     -> BasicTypeName {cons("Long")}
    "float"    -> BasicTypeName {cons("Float")}
    "double"   -> BasicTypeName {cons("Double")}
    "signed"   -> BasicTypeName {cons("Signed")}
    "unsigned" -> BasicTypeName {cons("Unsigned")}
    "void"     -> BasicTypeName {cons("Void")}

  context-free syntax
    "const"    -> TypeQualifier {cons("Const")}
    "volatile" -> TypeQualifier {cons("Volatile")}

  context-free syntax
    ( DeclarationQualifierList | TypeQualifier+ ) {IdDecl ","}* ";" -> Declaration {cons("Declaration")}
    ( DeclarationSpecifier | TypeSpecifier ) {VarDecl ","}* ";"     -> Declaration {cons("Declaration2")}

  context-free syntax
    IdDeclarator                   -> IdDecl
    IdDeclarator "=" Initializer   -> IdDecl      {cons("IdDeclInit")}
    Declarator                     -> VarDecl
    Declarator   "=" Initializer   -> VarDecl     {cons("DeclInit")}

    "{" {Initializer ","}+ "}"     -> Initializer {cons("ArrayInit")}
    "{" {Initializer ","}+ "," "}" -> Initializer {cons("ArrayInitIncomplete")}
    AssignExp                      -> Initializer {cons("AssignInit")}

  context-free syntax
    TypeQualifier* TypeOrDefName (TypeQualifier | BasicTypeName)* -> TypeSpecifier {cons("TypeSpec")}

  context-free syntax
    StorageClass  -> DeclarationQualifier
    TypeQualifier -> DeclarationQualifier

  context-free syntax
    TypeQualifier* StorageClass DeclarationQualifier*  -> DeclarationQualifierList {cons("DQualifiers")}

  context-free syntax
    TypeQualifier* StorageClass DeclarationQualifier* TypeOrDefName
    (DeclarationQualifier | BasicTypeName)* -> DeclarationSpecifier {cons("DeclSpec")}

    (BasicTypeName | ElaboratedTypeName | TypedefName) -> TypeOrDefName



module C-Identifiers
imports C-Keywords

exports
  sorts ID
  lexical syntax
    [a-zA-Z\_] [a-zA-Z\_0-9]* -> ID

    Keyword -> ID {reject}

  lexical restrictions
    ID -/- [a-zA-Z\_0-9]

  sorts IDENTIFIER
  context-free syntax
    ID          -> IDENTIFIER {cons("Id")}
    ID          -> TypedefName {cons("TypeId"), avoid}
    IDENTIFIER  -> IdOrTypedefName
    TypedefName -> IdOrTypedefName



module C-Statements
imports
  C-Expressions

exports
  sorts Stm

  context-free syntax
    LabeledStm    -> Stm
    CompoundStm   -> Stm
    ExpStm        -> Stm
    SelectionStm  -> Stm
    IterationStm  -> Stm
    JumpStm       -> Stm

  sorts LabeledStm
  context-free syntax
    IdOrTypedefName ":" Stm     -> LabeledStm {cons("Label")}
    "case" ConstantExp ":" Stm  -> LabeledStm {cons("Case")}
    "default" ":" Stm           -> LabeledStm {cons("Default")}

  sorts CompoundStm
  context-free syntax
    "{" Declaration* Stm* "}" -> CompoundStm {cons("Compound")}

  sorts ExpStm
  context-free syntax
    CommaExpOpt ";" -> ExpStm {cons("Stat")}

  sorts SelectionStm
  context-free syntax
    "if" "(" CommaExp ")" Stm             -> SelectionStm {cons("If")}
    "if" "(" CommaExp ")" Stm "else" Stm  -> SelectionStm {cons("IfElse")}
    "switch" "(" CommaExp ")" Stm         -> SelectionStm {cons("Switch")}

  sorts IterationStm
  context-free syntax
    "while" "(" CommaExp ")" Stm           -> IterationStm {cons("While")}
    "do" Stm "while" "(" CommaExp ")" ";"  -> IterationStm {cons("DoWhile")}
    "for" "(" CommaExpOpt ";" CommaExpOpt ";" CommaExpOpt ")" Stm -> IterationStm {cons("For")}

  sorts JumpStm
  context-free syntax
    "goto" IdOrTypedefName ";" -> JumpStm {cons("Goto")}
    "continue" ";"             -> JumpStm {cons("Continue")}
    "break" ";"                -> JumpStm {cons("Break")}
    "return" CommaExpOpt ";"   -> JumpStm {cons("Return")}
    "exit" CommaExpOpt ";"     -> JumpStm {cons("Exit")}

module C-Program
exports
  sorts TranslationUnit ExternalDef FunDef FunDefTypeSpec NoTypeSpecifier FunDefDecl

  context-free syntax
    ExternalDef+ -> TranslationUnit {cons("TranslationUnit")}

    FunDef      -> ExternalDef
    Declaration -> ExternalDef

    FunDefTypeSpec FunDefDecl CompoundStm -> FunDef {cons("FunDef")}

    FunDef -> Declaration %% injection for internal functions (a GCC extension of C)

    NoTypeSpecifier           -> FunDefTypeSpec
    TypeSpecifier             -> FunDefTypeSpec
    DeclarationSpecifier      -> FunDefTypeSpec
    DeclarationQualifierList  -> FunDefTypeSpec
    TypeQualifier+            -> FunDefTypeSpec

     -> NoTypeSpecifier {cons("NoTypeSpecifier")}

    IdDeclarator                   -> FunDefDecl
%%    OldFunDeclarator Declaration*  -> FunDefDecl {cons("OldFunDefDecl")}



module C-Declarators
imports
  C-Identifiers

exports
  sorts Declarator
  context-free syntax
    IdDeclarator      -> Declarator
    TypedefDeclarator -> Declarator

  sorts IdDeclarator
  context-free syntax
    Pointer* IDENTIFIER PostfixingAbstractDeclarator?           -> IdDeclarator {cons("IdDecl")}
    Pointer* "(" IdDeclarator ")" PostfixingAbstractDeclarator? -> IdDeclarator {cons("FunDecl")}

  sorts TypedefDeclarator
  context-free syntax
    Pointer* TypedefName PostfixingAbstractDeclarator?               -> TypedefDeclarator {cons("TypedefDeclarator1")}
    Pointer* "(" TypedefDeclarator ")" PostfixingAbstractDeclarator? -> TypedefDeclarator {cons("TypedefDeclarator2")}

  sorts OldFunDeclarator ParenIdDeclarator 
  context-free syntax
    Pointer* ParenIdDeclarator "(" {IDENTIFIER ","}+ ")"         -> OldFunDeclarator     {cons("OldFunction1")}
    Pointer* "(" OldFunDeclarator ")" PostfixingAbstractDeclarator? -> OldFunDeclarator     {cons("OldFunction2")}
    IDENTIFIER                                                     -> ParenIdDeclarator
    "(" ParenIdDeclarator ")"                                    -> ParenIdDeclarator {bracket}

module C-Preprocessor
exports
  sorts TokenChar Slash Token TokWS WS TokenSeq FileName
  lexical syntax
    ~[\ \t\n\/]                           -> TokenChar
    [\/]                                  -> Slash
    Slash                                 -> TokenChar
    TokenChar+                            -> Token
    ( [\ \t] | ( [\\] [\n] ) | Comment )+ -> TokWS
    ( [\ \t] | Comment )*                 -> WS
    {Token TokWS}+                        -> TokenSeq
    ~[\"\ \t\n\>]+                        -> FileName

  lexical restrictions
    Slash    -/- [\*]
    Token    -/- ~[\ \t\n\/]
    TokenSeq -/- ~[\ \t\n]
    WS       -/- [\ \t]

  sorts ControlLine ControlLineNot IfLine ElifLine ElseLine
  lexical syntax
    "#" WS "define" WS ID WS ( "(" WS {( ID WS ) ( "," WS )}* ")" WS )? TokenSeq? WS [\n] -> ControlLine

  lexical syntax
    "#" WS "undef" WS ID WS [\n]                                     -> ControlLine
    "#" WS "include" WS "<" FileName ">" WS [\n]                     -> ControlLine
    "#" WS "include" WS "\"" FileName "\"" WS [\n]                   -> ControlLine
    "#" WS "include" WS TokenSeq WS [\n]                             -> ControlLineNot
    "#" WS "line" WS [0-9]+ WS ( "\"" WS FileName WS "\"" )? WS [\n] -> ControlLine
    "#" WS IntLiteral WS "\"" FileName "\"" WS {LineFlag [\ ]+}* [\n] -> ControlLine
   
    "#" WS "error" WS TokenSeq? WS [\n]                              -> ControlLine
    "#" WS "pragma" WS TokenSeq? WS [\n]                             -> ControlLine
    "#" WS "if" WS ConstantExp WS [\n]                               -> IfLine
    "#" WS "if" WS ID WS [\n]                                        -> IfLine
    "#" WS "if" WS ID WS "!=" WS [0-9]+ WS [\n]                      -> IfLine
    "#" WS "ifdef" WS ID WS [\n]                                     -> IfLine
    "#" WS "ifndef" WS ID WS [\n]                                    -> IfLine
    "#" WS "elif" WS ConstantExp WS [\n]                             -> ElifLine
    "#" WS "else" WS [\n]                                            -> ElseLine
    
    "1" -> LineFlag
    "2" -> LineFlag
    "3" -> LineFlag
    "4" -> LineFlag

  context-free syntax
    ControlLine -> ExternalDef {cons("PpControl")}
    ControlLine -> MemberDeclaration {cons("PpControl")}

  context-free syntax
    IfLine ExternalDef* 
    ( ElifLine ExternalDef* )* 
    ( ElseLine ExternalDef* )? 
    "#" "endif" -> ExternalDef {cons("PpIf")}

module C-Lexical
hiddens
  sorts Asterisk Comment

exports
  lexical syntax
    [\ \t\n\12]                     -> LAYOUT
    "/*" ( ~[\*] | Asterisk )* "*/" -> Comment
    Comment                         -> LAYOUT
    [\*]                            -> Asterisk
    "//" ~[\n]* [\n]                -> Comment

  lexical restrictions
    Asterisk -/- [\/]

  context-free restrictions
    LAYOUT? -/- [\ \t\n]

module C-Constants
exports
  sorts Constant StringLiteralList
  context-free syntax
    IntLiteral   -> Constant {cons("IntConst")}
    HexLiteral   -> Constant {cons("HexConst")}
    OctLiteral   -> Constant {cons("OctConst")}
    FloatLiteral -> Constant {cons("FloatConst")}    
    CharLiteral  -> Constant {cons("CharConst")}

    %%% TODO: Why a list??
    StringLiteral+ -> StringLiteralList {cons("StringLit")}

  sorts StringLiteral CharLiteral IntLiteral HexLiteral OctLiteral FloatLiteral
        Char StringChar OctalEsc IntFlags FloatFlags
  lexical syntax
    [L]? "\"" StringChar* "\"" -> StringLiteral
    [L]? "'" Char "'"          -> CharLiteral    
    
    [1-9][0-9]*            IntFlags? -> IntLiteral
    "0"                    IntFlags? -> IntLiteral
    "0" [xX] [0-9a-fA-F]+  IntFlags? -> HexLiteral
    "0" [0-7]+             IntFlags? -> OctLiteral    
        
    "." [0-9]+ ( [eE] "-"? [0-9]+ )?        FloatFlags? -> FloatLiteral
    [0-9]+ "." [0-9]* ( [eE] "-"? [0-9]+ )? FloatFlags? -> FloatLiteral
    [0-9]+ [eE] "-"? [0-9]+                 FloatFlags? -> FloatLiteral

    ~[\\\'\n]                  -> Char
    [\\] [ntvbrfa\\\?\'\"]     -> Char
    [\\] [x] [0-9A-E] [0-9A-E] -> Char
    OctalEsc                   -> Char

    ~[\\\"\n]                  -> StringChar
    [\\] [ntvbrfa\\\?\"]       -> StringChar
    [\\] [x] [0-9A-E] [0-9A-E] -> StringChar
    OctalEsc                   -> StringChar
    
    [\\] [0-7] [0-7]? [0-7]?   -> OctalEsc
    
    [uUlL]   -> IntFlags
    [uU][lL] -> IntFlags
    
    [lLfF]   -> FloatFlags
    [lL][fF] -> FloatFlags
    
  lexical restrictions
    FloatLiteral -/- [0-9lLfF]
    IntLiteral   -/- [0-9UuLl]
    HexLiteral   -/- [0-9a-zA-F]
    OctLiteral   -/- [0-9a-zA-F]

module C-Keywords
exports
  lexical syntax
    "auto"     -> Keyword
    "double"   -> Keyword
    "int"      -> Keyword
    "struct"   -> Keyword
    "break"    -> Keyword
    "else"     -> Keyword
    "long"     -> Keyword
    "switch"   -> Keyword
    "case"     -> Keyword
    "enum"     -> Keyword
    "register" -> Keyword
    "typedef"  -> Keyword
    "char"     -> Keyword
    "extern"   -> Keyword
    "return"   -> Keyword
    "exit"     -> Keyword
    "union"    -> Keyword
    "const"    -> Keyword
    "float"    -> Keyword
    "short"    -> Keyword
    "unsigned" -> Keyword
    "continue" -> Keyword
    "for"      -> Keyword
    "signed"   -> Keyword
    "void"     -> Keyword
    "default"  -> Keyword
    "goto"     -> Keyword
    "sizeof"   -> Keyword
    "volatile" -> Keyword
    "do"       -> Keyword
    "if"       -> Keyword
    "static"   -> Keyword
    "while"    -> Keyword

  lexical restrictions

    "auto"
    "double"   
    "int"      
    "struct"   
    "break"    
    "else"     
    "long"     
    "switch"   
    "case"     
    "enum"     
    "register" 
    "typedef"  
    "char"     
    "extern"   
    "return"   
    "exit"     
    "union"    
    "const"    
    "float"    
    "short"    
    "unsigned" 
    "continue" 
    "for"      
    "signed"   
    "void"     
    "default"  
    "goto"     
    "sizeof"   
    "volatile" 
    "do"       
    "if"       
    "static"   
    "while"    -/- [a-zA-Z\_0-9]

module C
imports
    C-Keywords
    C-Constants
    C-Lexical
    C-Preprocessor
    C-Declarators
    C-Program
    C-Statements
    C-Identifiers
    C-Types
    C-Expressions
    C-StructsAndUnions
    C-Enumerators
    C-ParameterDeclarators
    C-AbstractDeclarators

hiddens
  context-free start-symbols TranslationUnit AssignExp Stm