Files
mysysy/src/frontend/SysY.g4
2025-07-29 21:30:30 +08:00

183 lines
4.3 KiB
ANTLR

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;