prog8/parser/antlr/prog8.g4

320 lines
7.6 KiB
Plaintext
Raw Normal View History

2018-08-08 23:54:43 +00:00
/*
2018-09-15 14:21:05 +00:00
Prog8 combined lexer and parser grammar
2018-08-10 21:56:30 +00:00
NOTES:
- whitespace is ignored. (tabs/spaces)
- every position can be empty, be a comment, or contain ONE statement.
2018-08-10 21:56:30 +00:00
2018-08-08 23:54:43 +00:00
*/
2018-09-15 14:21:05 +00:00
grammar prog8;
2018-08-08 23:54:43 +00:00
2019-01-29 11:06:33 +00:00
@header {
package prog8.parser;
}
2018-08-11 12:06:43 +00:00
LINECOMMENT : [\r\n][ \t]* COMMENT -> channel(HIDDEN);
2018-08-10 21:56:30 +00:00
COMMENT : ';' ~[\r\n]* -> channel(HIDDEN) ;
2018-08-09 22:26:41 +00:00
WS : [ \t] -> skip ;
2018-08-10 21:56:30 +00:00
EOL : [\r\n]+ ;
// WS2 : '\\' EOL -> skip;
VOID: 'void';
2018-08-08 23:54:43 +00:00
NAME : [a-zA-Z_][a-zA-Z0-9_]* ;
2018-08-09 22:26:41 +00:00
DEC_INTEGER : ('0'..'9') | (('1'..'9')('0'..'9')+);
HEX_INTEGER : '$' (('a'..'f') | ('A'..'F') | ('0'..'9'))+ ;
BIN_INTEGER : '%' ('0' | '1')+ ;
ADDRESS_OF: '&';
ALT_STRING_ENCODING: '@';
2018-08-08 23:54:43 +00:00
2018-08-09 22:26:41 +00:00
FLOAT_NUMBER : FNUMBER (('E'|'e') ('+' | '-')? FNUMBER)? ; // sign comes later from unary expression
fragment FNUMBER : ('0' .. '9') + ('.' ('0' .. '9') +)? ;
2018-08-08 23:54:43 +00:00
2018-08-09 22:26:41 +00:00
fragment STRING_ESCAPE_SEQ : '\\' . | '\\' EOL;
STRING :
'"' ( STRING_ESCAPE_SEQ | ~[\\\r\n\f"] )* '"'
{
// get rid of the enclosing quotes
String s = getText();
setText(s.substring(1, s.length() - 1));
}
2018-08-08 23:54:43 +00:00
;
2018-08-10 21:56:30 +00:00
INLINEASMBLOCK :
'{{' .+? '}}'
{
// get rid of the enclosing double braces
String s = getText();
setText(s.substring(2, s.length() - 2));
}
;
2018-08-08 23:54:43 +00:00
SINGLECHAR :
'\'' ( STRING_ESCAPE_SEQ | ~[\\\r\n\f"] ) '\''
{
// get rid of the enclosing quotes
String s = getText();
setText(s.substring(1, s.length() - 1));
}
;
2019-01-26 21:46:01 +00:00
ZEROPAGE :
'@zp'
;
ARRAYSIG :
'[]'
;
2018-08-09 22:26:41 +00:00
2020-03-14 12:23:13 +00:00
module : (directive | block | EOL)* EOF ;
2018-08-10 21:56:30 +00:00
block: identifier integerliteral? '{' EOL (block_statement | EOL) * '}' EOL ;
block_statement:
directive
| variabledeclaration
| subroutinedeclaration
| inlineasm
;
2018-08-09 22:26:41 +00:00
statement :
2018-08-08 23:54:43 +00:00
directive
2020-03-14 12:23:13 +00:00
| variabledeclaration
2018-08-08 23:54:43 +00:00
| assignment
| augassignment
2018-08-10 21:56:30 +00:00
| unconditionaljump
| postincrdecr
2018-08-14 00:22:59 +00:00
| functioncall_stmt
2018-08-14 12:33:36 +00:00
| if_stmt
2018-09-02 16:32:48 +00:00
| branch_stmt
2020-03-14 12:23:13 +00:00
| subroutinedeclaration
2018-08-10 21:56:30 +00:00
| inlineasm
2018-08-12 15:16:36 +00:00
| returnstmt
2018-09-16 01:00:32 +00:00
| forloop
2018-09-23 00:04:45 +00:00
| whileloop
| repeatloop
2019-07-08 22:02:38 +00:00
| whenstmt
| breakstmt
| continuestmt
2018-09-19 00:41:35 +00:00
| labeldef
2018-08-08 23:54:43 +00:00
;
2018-09-16 01:00:32 +00:00
2020-03-14 12:23:13 +00:00
variabledeclaration :
varinitializer
| structvarinitializer
| vardecl
| structvardecl
| constdecl
| memoryvardecl
| structdecl
;
subroutinedeclaration :
subroutine
| asmsubroutine
| romsubroutine
;
2018-08-12 15:16:36 +00:00
labeldef : identifier ':' ;
2018-08-10 21:56:30 +00:00
2019-01-02 22:32:41 +00:00
unconditionaljump : 'goto' (integerliteral | scoped_identifier) ;
2018-08-08 23:54:43 +00:00
2018-08-10 21:56:30 +00:00
directive :
2018-10-08 22:01:53 +00:00
directivename=('%output' | '%launcher' | '%zeropage' | '%zpreserved' | '%address' | '%import' |
2018-08-13 08:51:05 +00:00
'%breakpoint' | '%asminclude' | '%asmbinary' | '%option')
2018-08-10 21:56:30 +00:00
(directivearg? | directivearg (',' directivearg)*)
;
2018-08-08 23:54:43 +00:00
2018-08-10 21:56:30 +00:00
directivearg : stringliteral | identifier | integerliteral ;
2018-08-08 23:54:43 +00:00
vardecl: datatype ZEROPAGE? (arrayindex | ARRAYSIG) ? varname=identifier ;
structvardecl: structname=identifier varname=identifier ;
2018-08-08 23:54:43 +00:00
2019-01-26 21:46:01 +00:00
varinitializer : vardecl '=' expression ;
2018-08-08 23:54:43 +00:00
structvarinitializer : structvardecl '=' expression ;
2018-08-09 22:26:41 +00:00
constdecl: 'const' varinitializer ;
memoryvardecl: ADDRESS_OF varinitializer;
2018-08-09 22:26:41 +00:00
2019-07-12 04:14:59 +00:00
structdecl: 'struct' identifier '{' EOL vardecl ( EOL vardecl)* EOL? '}' EOL;
2020-02-07 19:47:38 +00:00
datatype: 'ubyte' | 'byte' | 'uword' | 'word' | 'float' | 'str' ;
2018-08-09 22:26:41 +00:00
arrayindex: '[' expression ']' ;
2018-08-09 22:26:41 +00:00
2019-07-10 07:33:19 +00:00
assignment : assign_target '=' expression ;
2018-08-08 23:54:43 +00:00
augassignment :
assign_target operator=('+=' | '-=' | '/=' | '*=' | '**=' | '&=' | '|=' | '^=' | '%=' | '<<=' | '>>=' ) expression
2018-08-08 23:54:43 +00:00
;
2018-08-09 22:26:41 +00:00
assign_target:
register
2018-08-10 00:58:41 +00:00
| scoped_identifier
2018-10-02 01:07:46 +00:00
| arrayindexed
| directmemory
2018-08-09 22:26:41 +00:00
;
2018-08-08 23:54:43 +00:00
2018-08-10 21:56:30 +00:00
postincrdecr : assign_target operator = ('++' | '--') ;
2018-08-08 23:54:43 +00:00
expression :
2018-12-31 03:48:26 +00:00
functioncall
| <assoc=right> prefix = ('+'|'-'|'~') expression
| left = expression EOL? bop = '**' EOL? right = expression
| left = expression EOL? bop = ('*' | '/' | '%' ) EOL? right = expression
| left = expression EOL? bop = ('+' | '-' ) EOL? right = expression
| left = expression EOL? bop = ('<<' | '>>' ) EOL? right = expression
| left = expression EOL? bop = ('<' | '>' | '<=' | '>=') EOL? right = expression
| left = expression EOL? bop = ('==' | '!=') EOL? right = expression
| left = expression EOL? bop = '&' EOL? right = expression
| left = expression EOL? bop = '^' EOL? right = expression
| left = expression EOL? bop = '|' EOL? right = expression
2020-03-11 19:47:42 +00:00
| rangefrom = expression rto = ('to'|'downto') rangeto = expression ('step' rangestep = expression)? // can't create separate rule due to mutual left-recursion
| left = expression EOL? bop = 'and' EOL? right = expression
| left = expression EOL? bop = 'or' EOL? right = expression
| left = expression EOL? bop = 'xor' EOL? right = expression
2018-08-11 17:15:39 +00:00
| prefix = 'not' expression
2018-08-08 23:54:43 +00:00
| literalvalue
| register
2018-08-10 00:58:41 +00:00
| scoped_identifier
2018-10-01 20:23:16 +00:00
| arrayindexed
| directmemory
2019-04-11 18:55:20 +00:00
| addressof
| expression typecast
2018-12-31 03:48:26 +00:00
| '(' expression ')'
2018-08-08 23:54:43 +00:00
;
2018-08-10 21:56:30 +00:00
typecast : 'as' datatype;
arrayindexed : scoped_identifier arrayindex ;
2018-10-01 20:23:16 +00:00
2018-12-31 03:48:26 +00:00
directmemory : '@' '(' expression ')';
addressof : <assoc=right> ADDRESS_OF scoped_identifier ;
2019-04-04 19:02:24 +00:00
2018-10-01 20:23:16 +00:00
functioncall : scoped_identifier '(' expression_list? ')' ;
2018-08-14 00:22:59 +00:00
functioncall_stmt : VOID? scoped_identifier '(' expression_list? ')' ;
2018-08-14 00:22:59 +00:00
2018-08-12 15:16:36 +00:00
expression_list :
2018-12-31 00:52:18 +00:00
expression (',' EOL? expression)* // you can split the expression list over several lines
2018-08-08 23:54:43 +00:00
;
returnstmt : 'return' expression? ;
2018-08-12 15:16:36 +00:00
2018-09-16 01:00:32 +00:00
breakstmt : 'break';
continuestmt: 'continue';
2018-08-10 00:58:41 +00:00
identifier : NAME ;
2018-08-08 23:54:43 +00:00
2019-01-02 22:32:41 +00:00
scoped_identifier : NAME ('.' NAME)* ;
2018-08-08 23:54:43 +00:00
register : 'A' | 'X' | 'Y' ;
2018-09-02 16:32:48 +00:00
2019-07-09 02:09:29 +00:00
registerorpair : 'A' | 'X' | 'Y' | 'AX' | 'AY' | 'XY' ; // pairs can only be used in subroutine params and returnvalues
statusregister : 'Pc' | 'Pz' | 'Pn' | 'Pv' ;
integerliteral : intpart=(DEC_INTEGER | HEX_INTEGER | BIN_INTEGER) wordsuffix? ;
wordsuffix : '.w' ;
2018-08-08 23:54:43 +00:00
2018-08-09 22:26:41 +00:00
booleanliteral : 'true' | 'false' ;
2018-08-08 23:54:43 +00:00
2019-07-15 22:08:28 +00:00
arrayliteral : '[' EOL? expression (',' EOL? expression)* EOL? ']' ; // you can split the values over several lines
structliteral : '{' EOL? expression (',' EOL? expression)* EOL? '}' ; // you can split the values over several lines
2018-08-08 23:54:43 +00:00
stringliteral : ALT_STRING_ENCODING? STRING ;
2018-08-08 23:54:43 +00:00
charliteral : ALT_STRING_ENCODING? SINGLECHAR ;
2018-08-09 22:26:41 +00:00
floatliteral : FLOAT_NUMBER ;
2018-08-08 23:54:43 +00:00
2019-07-15 22:08:28 +00:00
2018-08-09 22:26:41 +00:00
literalvalue :
integerliteral
| booleanliteral
| arrayliteral
| stringliteral
| charliteral
2018-08-09 22:26:41 +00:00
| floatliteral
2019-07-15 22:08:28 +00:00
| structliteral
2018-08-08 23:54:43 +00:00
;
2018-08-10 21:56:30 +00:00
inlineasm : '%asm' INLINEASMBLOCK;
2018-08-12 23:30:33 +00:00
subroutine :
'sub' identifier '(' sub_params? ')' sub_return_part? (statement_block EOL)
2018-08-13 02:12:42 +00:00
;
sub_return_part : '->' sub_returns ;
2018-08-14 12:33:36 +00:00
statement_block :
2018-08-13 02:12:42 +00:00
'{' EOL
2018-08-12 23:30:33 +00:00
(statement | EOL) *
2018-08-14 12:33:36 +00:00
'}'
2018-08-12 23:30:33 +00:00
;
2018-08-13 02:12:42 +00:00
sub_params : vardecl (',' EOL? vardecl)* ;
sub_returns : datatype (',' EOL? datatype)* ;
asmsubroutine :
2020-03-10 22:09:31 +00:00
'asmsub' asmsub_decl statement_block
;
2020-03-10 22:09:31 +00:00
romsubroutine :
'romsub' integerliteral '=' asmsub_decl
;
asmsub_decl : identifier '(' asmsub_params? ')' asmsub_clobbers? asmsub_returns? ;
asmsub_params : asmsub_param (',' EOL? asmsub_param)* ;
2019-07-08 21:00:18 +00:00
asmsub_param : vardecl '@' (registerorpair | statusregister | stack='stack') ;
asmsub_clobbers : 'clobbers' '(' clobber? ')' ;
clobber : register (',' register)* ;
2018-08-12 23:30:33 +00:00
2019-07-08 21:00:18 +00:00
asmsub_returns : '->' asmsub_return (',' EOL? asmsub_return)* ;
2018-08-12 23:30:33 +00:00
asmsub_return : datatype '@' (registerorpair | statusregister | stack='stack') ;
2018-08-14 12:33:36 +00:00
2019-01-01 17:45:21 +00:00
if_stmt : 'if' expression EOL? (statement | statement_block) EOL? else_part? ; // statement is constrained later
2018-08-14 12:33:36 +00:00
else_part : 'else' EOL? (statement | statement_block) ; // statement is constrained later
2018-09-02 16:32:48 +00:00
branch_stmt : branchcondition EOL? (statement | statement_block) EOL? else_part? EOL ;
2018-09-21 22:33:25 +00:00
branchcondition: 'if_cs' | 'if_cc' | 'if_eq' | 'if_z' | 'if_ne' | 'if_nz' | 'if_pl' | 'if_pos' | 'if_mi' | 'if_neg' | 'if_vs' | 'if_vc' ;
2018-09-16 01:00:32 +00:00
forloop : 'for' (register | identifier) 'in' expression EOL? (statement | statement_block) ;
2018-09-23 00:04:45 +00:00
whileloop: 'while' expression EOL? (statement | statement_block) ;
repeatloop: 'repeat' (statement | statement_block) EOL? 'until' expression ;
2019-07-08 22:02:38 +00:00
whenstmt: 'when' expression '{' EOL (when_choice | EOL) * '}' EOL? ;
when_choice: (expression_list | 'else' ) '->' (statement | statement_block ) ;
2019-07-12 04:14:59 +00:00