grammar SysY;

compUnit
    : (funcDef | decl)+ EOF
    ;

decl
    : constDecl
    | varDecl
    ;

constDecl
    : Const bType constDef (Comma constDef)* Semi
    ;

bType
    : Int
    | Float
    ;

constDef
    : Ident (L_BRAKT constExp R_BRAKT)* Assign constInitVal
    ;

constInitVal
    : constExp
    | L_BRACE (constInitVal (Comma constInitVal)*)? R_BRACE
    ;

varDecl
    : bType varDef (Comma varDef)* Semi
    ;

funcDef
    : funcType Ident L_PAREN (funcFParams)? R_PAREN block
    ;

varDef
    : Ident (L_BRAKT constExp R_BRAKT)* (Assign initVal)?
    ;

initVal
    : exp
    | L_BRACE (initVal (Comma initVal)*)? R_BRACE
    ;

funcType
    : Void
    | Int
    | Float
    ;

funcFParams
    : funcFParam (Comma funcFParam)*
    ;

funcFParam
    : bType Ident (L_BRAKT R_BRAKT (L_BRAKT exp R_BRAKT)*)?
    ;

block
    : L_BRACE (blockItem)* R_BRACE
    ;

blockItem
    : decl
    | stmt
    ;

stmt
    : lVar Assign exp Semi
    | (exp)? Semi
    | block
    | If L_PAREN cond R_PAREN stmt (Else stmt)?
    | While L_PAREN cond R_PAREN stmt
    | Break Semi
    | Continue Semi
    | Return (exp)? Semi
    ;

exp
    : addExp
    ;

cond
    : lOrExp
    ;

lVar
    : Ident (L_BRAKT exp R_BRAKT)*
    ;

primaryExp
    : L_PAREN exp R_PAREN
    | lVar
    | number
    ;

number
    : IntConst
    | FloatConst
    ;

unaryExp
    : primaryExp
    | Ident L_PAREN (funcRParams)? R_PAREN
    | unaryOp unaryExp
    ;

unaryOp : AddOp | '!';

funcRParams
    : exp (Comma exp)*
    ;

mulExp
    : unaryExp (MulOp unaryExp)*
    ;

addExp
    : mulExp (AddOp mulExp)*
    ;

relExp
    : addExp (RelOp addExp)*
    ;

eqExp
    : relExp (EqOp relExp)*
    ;

lAndExp
    : eqExp ('&&' eqExp)*
    ;

lOrExp
    : lAndExp ('||' lAndExp)*
    ;

constExp
    : addExp
    ;

Void    : 'void';
Int     : 'int';
Float   : 'float';
Const   : 'const';
If      : 'if';
Else    : 'else';
While   : 'while';
Break   : 'break';
Continue: 'continue';
Return  : 'return';

Comma   : ',';
Semi    : ';';
L_PAREN : '(';
R_PAREN : ')';
L_BRAKT : '[';
R_BRAKT : ']';
L_BRACE : '{';
R_BRACE : '}';
Assign  : '=';

MulOp   : '*' | '/' | '%';
AddOp   : '+' | '-';
RelOp   : '<' | '>' | '<=' | '>=';
EqOp    : '==' | '!=';

Ident
    : [a-zA-Z_][a-zA-Z_0-9]*
    ;

IntConst
    : DecInt
    | OctInt
    | HexInt
    ;

fragment DecInt
    : NonZeroD Digit*
    ;

fragment OctInt
    : '0' OctDigit*
    ;

fragment HexInt
    : HexPre HexDigit+
    ;

FloatConst
    : DecFloat
	| HexFloat
    ;

fragment DecFloat
	: Fraction Exponent?
	| DiSeq Exponent
	;

fragment HexFloat
	: HexPre (HexFraction | HexDiSeq) BiExponent
	;

fragment Fraction
	: DiSeq? '.' DiSeq
	| DiSeq '.'
	;

fragment Exponent
	: [eE] ('+' | '-')? DiSeq
	;

fragment DiSeq
	: Digit+
	;

fragment HexFraction
	: HexDiSeq? '.' HexDiSeq
	| HexDiSeq '.'
	;

fragment BiExponent
	: [pP] ('+' | '-')? DiSeq
	;

fragment HexDiSeq
	: HexDigit+
	;

fragment NonZeroD: [1-9];
fragment Digit   : [0-9];
fragment OctDigit: [0-7];
fragment HexPre  : '0' [xX];
fragment HexDigit: [0-9A-Fa-f];


WS
    : [ \t\r\n]+ -> skip
    ;

COMMENT
    : '//' ~[\r\n]* -> skip
    ;

BLOCK_COMMENT
    : '/*' .*? '*/' -> skip
    ;
