grammar SysY;

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


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

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

// relational operators
EQ: '==';
NE: '!=';
LT: '<';
LE: '<=';
GT: '>';
GE: '>=';

// logical operators
AND: '&&';
OR: '||';
NOT: '!';

// assignment operators
ASSIGN: '=';

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

// fragments
fragment DecDigit: [0-9];
fragment OctDigit: [0-7];
fragment HexDigit: [0-9a-fA-F];
fragment OctPrefix: '0';
fragment HexPrefix: '0' [xX];
fragment NonZeroDecDigit: [1-9];
fragment Sign: '+' | '-';
fragment DecFractional: DecDigit* '.' DecDigit+ | DecDigit+ '.';
fragment Exponent: [eE] Sign? DecDigit+;
fragment DecFloat: DecFractional Exponent? | DecDigit+ Exponent;
fragment HexFractional: HexDigit* '.' HexDigit+ | HexDigit+ '.';
fragment BinExponent: [pP] Sign? DecDigit+;
fragment HexFloat:
	HexPrefix HexFractional BinExponent
	| HexPrefix HexDigit+ BinExponent;

fragment ESC: '\\"' | '\\\\';


// identifier
fragment ALPHA: [a-zA-Z];
fragment ALPHANUM: [a-zA-Z0-9];
fragment NONDIGIT: [a-zA-Z_];
Ident: NONDIGIT (ALPHANUM | '_')*;

// IntConst -> ILITERAL
// FloatConst -> FLITERAL
// literals
ILITERAL:
	NonZeroDecDigit DecDigit*
	| OctPrefix OctDigit*
	| HexPrefix HexDigit+;

// fliteral
FLITERAL: DecFloat | HexFloat;

// string
STRING: '"' (ESC | .)*? '"';

// white space and comments
WS: [\t\r\n ] -> skip;
LINECOMMENT: '//' .*? '\r'? '\n' -> skip;
BLOCKCOMMENT: '/*' .*? '*/' -> skip;

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

// CompUnit: (CompUnit)? (decl |funcDef);

compUnit: (globalDecl |funcDef)+;

globalDecl: constDecl                           # globalConstDecl
        | varDecl                               # globalVarDecl;

decl: constDecl | varDecl;

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

bType: INT | FLOAT;

constDef: Ident (LBRACK constExp RBRACK)* ASSIGN constInitVal;

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

varDecl: bType varDef (COMMA varDef)* SEMICOLON;

varDef: Ident (LBRACK constExp RBRACK)*
		| Ident (LBRACK constExp RBRACK)* ASSIGN initVal;

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

funcType: VOID | INT | FLOAT;

funcDef: funcType Ident LPAREN funcFParams? RPAREN blockStmt;

funcFParams: funcFParam (COMMA funcFParam)*;

// 函数形参感觉定义有问题
// 应该是funcFParam: bType Ident ((LBRACK RBRACK)* (LBRACK exp RBRACK)*)?;
funcFParam: bType Ident (LBRACK RBRACK (LBRACK exp RBRACK)*)?;

blockStmt: LBRACE blockItem* RBRACE;

blockItem: decl | stmt;

stmt: lValue ASSIGN exp SEMICOLON					#assignStmt
		| exp? SEMICOLON							#expStmt
		| blockStmt									#blkStmt
		| IF LPAREN cond RPAREN stmt (ELSE stmt)?	#ifStmt
		| WHILE LPAREN cond RPAREN stmt				#whileStmt
		| BREAK SEMICOLON							#breakStmt
		| CONTINUE SEMICOLON						#continueStmt
		| RETURN exp? SEMICOLON						#returnStmt;

exp: addExp;
cond: lOrExp;
lValue: Ident (LBRACK exp RBRACK)*;

// 为了方便测试 primaryExp 可以是一个string
primaryExp: LPAREN exp RPAREN
			| lValue
			| number
			| string;

number: ILITERAL | FLITERAL;
call: Ident LPAREN (funcRParams)? RPAREN;
unaryExp: primaryExp								
			| call
			| unaryOp unaryExp;

unaryOp: ADD|SUB|NOT;
funcRParams: exp (COMMA exp)*;
string: STRING;
mulExp: unaryExp ((MUL|DIV|MOD) unaryExp)*;
addExp: mulExp ((ADD|SUB) mulExp)*;
relExp: addExp ((LT|GT|LE|GE) addExp)*;
eqExp: relExp ((EQ|NE) relExp)*;
lAndExp: eqExp (AND eqExp)*;
lOrExp: lAndExp (OR lAndExp)*;
constExp: addExp;
// mulExp: unaryExp ((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;