grammar SysY; /*===-------------------------------------------===*/ /* Lexer rules */ /*===-------------------------------------------===*/ // fragments // keywords CONST: 'const'; INT: 'int'; FLOAT: 'float'; VOID: 'void'; IF: 'if'; ELSE: 'else'; WHILE: 'while'; BREAK: 'break'; CONTINUE: 'continue'; RETURN: 'return'; // operators ASSIGN: '='; ADD: '+'; SUB: '-'; MUL: '*'; DIV: '/'; MODULO: '%'; LT: '<'; GT: '>'; LE: '<='; GE: '>='; EQ: '=='; NE: '!='; AND: '&&'; OR: '||'; NOT: '!'; // punctuations LPAREN: '('; RPAREN: ')'; LBRACKET: '['; RBRACKET: ']'; LBRACE: '{'; RBRACE: '}'; COMMA: ','; SEMICOLON: ';'; // identifier fragment ALPHA: [a-zA-Z]; fragment ALPHANUM: [a-zA-Z0-9]; fragment NONDIGIT: [a-zA-Z_]; ID: NONDIGIT (ALPHANUM | '_')*; // literals 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 | HexDigit+ BinExponent; ILITERAL: NonZeroDecDigit DecDigit* | OctPrefix OctDigit* | HexPrefix HexDigit+; FLITERAL: DecFloat | HexFloat; // string fragment ESC: '\\"' | '\\\\'; STRING: '"' (ESC | .)*? '"'; // white space and comments WS: [ \t\r\n] -> skip; LINECOMMENT: '//' .*? '\r'? '\n' -> skip; BLOCKCOMMENT: '/*' .*? '*/' -> skip; /*===-------------------------------------------===*/ /* Syntax rules */ /*===-------------------------------------------===*/ module: (decl | func)+; // constDecl and varDecl shares the same syntax structure, except that constDecl must have constant // initial values. We combine these two syntax rules, and ensure the constraint above at the // semantic check phase. decl: CONST? btype varDef (COMMA varDef)* SEMICOLON; btype: INT | FLOAT; varDef: lValue (ASSIGN initValue)?; initValue: exp # scalarInitValue | LBRACE (initValue (COMMA initValue)*)? # arrayInitValue; func: funcType ID LPAREN funcFParams? RPAREN blockStmt; funcType: VOID | INT | FLOAT; funcFParams: funcFParam (COMMA funcFParam)*; funcFParam: btype ID (LBRACKET RBRACKET (LBRACKET exp RBRACKET)*)?; blockStmt: LBRACE blockItem* RBRACE; blockItem: decl | stmt; stmt: assignStmt | expStmt | ifStmt | whileStmt | breakStmt | continueStmt | returnStmt | blockStmt | emptyStmt; assignStmt: lValue ASSIGN exp SEMICOLON; expStmt: exp SEMICOLON; ifStmt: IF LPAREN exp RPAREN stmt (ELSE stmt)?; whileStmt: WHILE LPAREN exp RPAREN stmt; breakStmt: BREAK SEMICOLON; continueStmt: CONTINUE SEMICOLON; returnStmt: RETURN exp? SEMICOLON; emptyStmt: SEMICOLON; exp: LPAREN exp RPAREN # parenExp | lValue # lValueExp | number # numberExp | string # stringExp | call # callExp | (ADD | SUB | NOT) exp # unaryExp | exp (MUL | DIV | MODULO) exp # multiplicativeExp | exp (ADD | SUB) exp # additiveExp | exp (LT | GT | LE | GE) exp # relationExp | exp (EQ | NE) exp # equalExp | exp AND exp # andExp | exp OR exp # orExp; call: ID LPAREN funcRParams? RPAREN; lValue: ID (LBRACKET exp RBRACKET)*; number: ILITERAL | FLITERAL; string: STRING; funcRParams: exp (COMMA exp)*;