// SysY 语法：支持完整的 SysY 子集

grammar SysY;

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

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

ASSIGN: '=';
ADD: '+';
SUB: '-';
MUL: '*';
DIV: '/';
MOD: '%';

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

AND: '&&';
OR: '||';
NOT: '!';

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

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

ILITERAL
    : [0-9]+                  
    | '0' [xX] [0-9a-fA-F]+   
    ;

FLITERAL
    : [0-9]+ '.' [0-9]* ([eE] [+-]? [0-9]+)?  
    | [0-9]+ [eE] [+-]? [0-9]+                
    | '.' [0-9]+ ([eE] [+-]? [0-9]+)?         
    | '0' [xX] [0-9a-fA-F]* '.' [0-9a-fA-F]+ [pP] [+-]? [0-9]+  
    | '0' [xX] [0-9a-fA-F]+ [pP] [+-]? [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
    : lValue ASSIGN initValue
    ;

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

constExp
    : exp
    ;

varDecl
    : btype varDef (COMMA varDef)* SEMICOLON
    ;

btype
    : INT
    | FLOAT
    ;

varDef
    : lValue (ASSIGN initValue)?
    ;

initValue
    : exp
    | arrayInit
    ;

arrayInit
    : LBRACE (initValue (COMMA initValue)*)? RBRACE
    ;

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

funcType
    : INT
    | VOID
    | FLOAT
    ;

funcFParams
    : funcFParam (COMMA funcFParam)*
    ;

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

blockStmt
    : LBRACE blockItem* RBRACE
    ;

blockItem
    : decl
    | stmt
    ;

stmt
    : returnStmt
    | assignStmt
    | ifStmt
    | whileStmt
    | breakStmt
    | continueStmt
    | exprStmt
    | blockStmt
    ;

continueStmt
    : CONTINUE SEMICOLON
    ;

returnStmt
    : RETURN (exp)? SEMICOLON
    ;

assignStmt
    : lValue ASSIGN exp SEMICOLON
    ;

ifStmt
    : IF LPAREN cond RPAREN stmt (ELSE stmt)?
    ;

whileStmt
    : WHILE LPAREN cond RPAREN stmt
    ;

breakStmt
    : BREAK SEMICOLON
    ;

exprStmt
    : exp SEMICOLON
    ;

cond
    : exp
    ;

exp
    : LPAREN exp RPAREN          # parenExp
    | var                        # varExp
    | number                     # numberExp
    | ID LPAREN (exp (COMMA exp)*)? RPAREN # funcCallExp
    | SUB exp                    # unaryMinusExp
    | NOT exp                    # unaryNotExp
    | exp MUL exp                # multiplicativeExp
    | exp DIV exp                # multiplicativeExp
    | exp MOD exp                # multiplicativeExp
    | exp ADD exp                # additiveExp
    | exp SUB exp                # additiveExp
    | exp LT exp                 # relationalExp
    | exp LE exp                 # relationalExp
    | exp GT exp                 # relationalExp
    | exp GE exp                 # relationalExp
    | exp EQ exp                 # equalityExp
    | exp NEQ exp                # equalityExp
    | exp AND exp                # logicalAndExp
    | exp OR exp                 # logicalOrExp
    ;

var
    : ID (LBRACK exp RBRACK)*
    ;

lValue
    : ID (LBRACK exp RBRACK)*
    ;

number
    : ILITERAL
    | FLITERAL
    ;
