// SysY 完整语法文法
// 支持完整的 SysY 语言子集，包括：
// - int/float/void 类型
// - 全局/局部变量和常量声明
// - 数组声明和初始化（一维和多维）
// - 函数定义和调用
// - if-else, while, break, continue
// - 各种运算符（算术、关系、逻辑、一元）
// - 库函数调用

// SysY 子集语法：支持形如
// int main() { int a = 1; int b = 2; return a + b; }
// 的最小返回表达式编译。

// 后续需要自行添加

grammar SysY;

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

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

LE: '<=';
GE: '>=';
EQ: '==';
NE: '!=';
AND: '&&';
OR: '||';

ASSIGN: '=';
LT: '<';
GT: '>';
ADD: '+';
SUB: '-';
MUL: '*';
DIV: '/';
MOD: '%';
NOT: '!';

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

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

HEX_FLOAT_LITERAL
    : ('0x' | '0X') HEX_DIGIT* '.' HEX_DIGIT+ BINARY_EXPONENT
    | ('0x' | '0X') HEX_DIGIT+ '.' HEX_DIGIT* BINARY_EXPONENT
    | ('0x' | '0X') HEX_DIGIT+ BINARY_EXPONENT
    ;

DEC_FLOAT_LITERAL
    : DEC_DIGIT+ '.' DEC_DIGIT* DEC_EXPONENT?
    | '.' DEC_DIGIT+ DEC_EXPONENT?
    | DEC_DIGIT+ DEC_EXPONENT
    ;

HEX_INT_LITERAL
    : ('0x' | '0X') HEX_DIGIT+
    ;

OCT_INT_LITERAL
    : '0' OCT_DIGIT+
    ;

DEC_INT_LITERAL
    : '0'
    | [1-9] DEC_DIGIT*
    ;

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

fragment DEC_DIGIT: [0-9];
fragment OCT_DIGIT: [0-7];
fragment HEX_DIGIT: [0-9a-fA-F];
fragment DEC_EXPONENT: [eE] [+-]? DEC_DIGIT+;
fragment BINARY_EXPONENT: [pP] [+-]? DEC_DIGIT+;

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

compUnit
    : topLevelItem (topLevelItem)* EOF
    ;

topLevelItem
    : decl
    | funcDef
    ;

decl
    : constDecl
    | varDecl
    ;

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

varDecl
    : bType varDef (COMMA varDef)* SEMICOLON
    ;

bType
    : INT
    | FLOAT
    ;

constDef
    : ID constIndex* ASSIGN constInitVal
    ;

varDef
    : ID constIndex* (ASSIGN initVal)?
    ;

constIndex
    : LBRACK constExp RBRACK
    ;

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

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

funcDef
    : funcType ID LPAREN funcFParams? RPAREN block
    ;

funcType
    : VOID
    | INT
    | FLOAT
    ;

funcFParams
    : funcFParam (COMMA funcFParam)*
    ;

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

block
    : LBRACE blockItem* RBRACE
    ;

blockItem
    : decl
    | stmt
    ;

stmt
    : lVal ASSIGN exp SEMICOLON
    | exp? SEMICOLON
    | block
    | IF LPAREN cond RPAREN stmt (ELSE stmt)?
    | WHILE LPAREN cond RPAREN stmt
    | BREAK SEMICOLON
    | CONTINUE SEMICOLON
    | RETURN exp? SEMICOLON
    ;

exp
    : addExp
    ;

cond
    : lOrExp
    ;

lVal
    : ID (LBRACK exp RBRACK)*
    ;

primaryExp
    : LPAREN exp RPAREN
    | lVal
    | number
    ;

number
    : intConst
    | floatConst
    ;

intConst
    : DEC_INT_LITERAL
    | OCT_INT_LITERAL
    | HEX_INT_LITERAL
    ;

floatConst
    : DEC_FLOAT_LITERAL
    | HEX_FLOAT_LITERAL
    ;

unaryExp
    : primaryExp
    | ID LPAREN funcRParams? RPAREN
    | addUnaryOp unaryExp
    ;

addUnaryOp
    : ADD
    | SUB
    ;

funcRParams
    : exp (COMMA exp)*
    ;

mulExp
    : unaryExp
    | mulExp MUL unaryExp
    | mulExp DIV unaryExp
    | mulExp MOD unaryExp
    ;

addExp
    : mulExp
    | addExp ADD mulExp
    | addExp SUB mulExp
    ;

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

eqExp
    : relExp
    | eqExp EQ relExp
    | eqExp NE relExp
    ;

lAndExp
    : condUnaryExp
    | lAndExp AND condUnaryExp
    ;

lOrExp
    : lAndExp
    | lOrExp OR lAndExp
    ;

condUnaryExp
    : eqExp
    | NOT condUnaryExp
    ;

constExp
    : addExp
    ;
