// SysY Lab1 语法：覆盖常见声明、控制流、数组、函数与表达式优先级。

grammar SysY;

/*===-------------------------------------------===*/
/* Lexer rules                                     */
/*===-------------------------------------------===*/

CONST: 'const';
INT: 'int';
FLOAT: 'float';
VOID: 'void';
IF: 'if';
ELSE: 'else';
WHILE: 'while';
BREAK: 'break';
CONTINUE: 'continue';
RETURN: 'return';

ASSIGN: '=';
EQ: '==';
NE: '!=';
LT: '<';
GT: '>';
LE: '<=';
GE: '>=';

ADD: '+';
SUB: '-';
MUL: '*';
DIV: '/';
MOD: '%';
NOT: '!';
AND: '&&';
OR: '||';

LPAREN: '(';
RPAREN: ')';
LBRACK: '[';
RBRACK: ']';
LBRACE: '{';
RBRACE: '}';
COMMA: ',';
SEMICOLON: ';';

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

FLITERAL
    : DECIMAL_FLOAT
    | HEX_FLOAT
    ;

ILITERAL
    : HEX_INT
    | OCT_INT
    | DEC_INT
    ;

fragment DEC_INT: '0' | [1-9] [0-9]*;
fragment OCT_INT: '0' [0-7]+;
fragment HEX_INT: '0' [xX] [0-9a-fA-F]+;

fragment DECIMAL_FLOAT
    : [0-9]+ '.' [0-9]* EXP?
    | '.' [0-9]+ EXP?
    | [0-9]+ EXP
    ;

fragment HEX_FLOAT
    : '0' [xX] [0-9a-fA-F]+ ('.' [0-9a-fA-F]*)? [pP] [+-]? [0-9]+
    | '0' [xX] '.' [0-9a-fA-F]+ [pP] [+-]? [0-9]+
    ;

fragment EXP: [eE] [+-]? [0-9]+;

WS: [ \t\r\n] -> skip;
LINECOMMENT: '//' ~[\r\n]* -> skip;
BLOCKCOMMENT: '/*' .*? '*/' -> skip;

/*===-------------------------------------------===*/
/* Syntax rules                                    */
/*===-------------------------------------------===*/

compUnit
    : (decl | funcDef)+ EOF
    ;

decl
    : constDecl
    | varDecl
    ;

constDecl
    : CONST btype constDef (COMMA constDef)* SEMICOLON
    ;

constDef
    : ID (LBRACK constExp RBRACK)* ASSIGN constInitValue
    ;

constInitValue
    : constExp
    | LBRACE (constInitValue (COMMA constInitValue)*)? RBRACE
    ;

varDecl
    : btype varDef (COMMA varDef)* SEMICOLON
    ;

btype
    : INT
    | FLOAT
    ;

varDef
    : ID (LBRACK constExp RBRACK)* (ASSIGN initValue)?
    ;

initValue
    : exp
    | LBRACE (initValue (COMMA initValue)*)? RBRACE
    ;

funcDef
    : funcType ID LPAREN (funcFParams)? RPAREN blockStmt
    ;

funcType
    : INT
    | FLOAT
    | VOID
    ;

funcFParams
    : funcFParam (COMMA funcFParam)*
    ;

funcFParam
    : btype ID (LBRACK RBRACK (LBRACK exp RBRACK)*)?
    ;

blockStmt
    : LBRACE blockItem* RBRACE
    ;

blockItem
    : decl
    | stmt
    ;

stmt
    : lValue ASSIGN exp SEMICOLON
    | (exp)? SEMICOLON
    | blockStmt
    | IF LPAREN cond RPAREN stmt (ELSE stmt)?
    | WHILE LPAREN cond RPAREN stmt
    | BREAK SEMICOLON
    | CONTINUE SEMICOLON
    | returnStmt
    ;

returnStmt
    : RETURN (exp)? SEMICOLON
    ;

exp
    : addExp
    ;

cond
    : lOrExp
    ;

lValue
    : ID (LBRACK exp RBRACK)*
    ;

primaryExp
    : LPAREN exp RPAREN
    | lValue
    | number
    ;

number
    : ILITERAL
    | FLITERAL
    ;

unaryExp
    : primaryExp
    | ID LPAREN (funcRParams)? RPAREN
    | unaryOp unaryExp
    ;

unaryOp
    : ADD
    | SUB
    | NOT
    ;

funcRParams
    : exp (COMMA exp)*
    ;

mulExp
    : unaryExp
    | mulExp (MUL | DIV | MOD) unaryExp
    ;
    
addExp
    : mulExp
    | addExp (ADD | SUB) mulExp
    ;

relExp
    : addExp
    | relExp (LT | GT | LE | GE) addExp
    ;

eqExp
    : relExp
    | eqExp (EQ | NE) relExp
    ;

lAndExp
    : eqExp
    | lAndExp AND eqExp
    ;

lOrExp
    : lAndExp
    | lOrExp OR lAndExp
    ;

constExp
    : addExp
    ;
