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)
|
2018-09-13 20:31:59 +00:00
|
|
|
- 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
|
|
|
|
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]+ ;
|
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')+ ;
|
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
|
|
|
|
2018-09-30 21:07:26 +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));
|
|
|
|
}
|
|
|
|
;
|
|
|
|
|
2018-08-09 22:26:41 +00:00
|
|
|
|
2018-08-11 12:06:43 +00:00
|
|
|
module : (modulestatement | EOL)* EOF ;
|
2018-08-10 21:56:30 +00:00
|
|
|
|
|
|
|
modulestatement: directive | block ;
|
|
|
|
|
2018-08-14 12:33:36 +00:00
|
|
|
block: '~' identifier integerliteral? statement_block EOL ;
|
2018-08-09 22:26:41 +00:00
|
|
|
|
|
|
|
statement :
|
2018-08-08 23:54:43 +00:00
|
|
|
directive
|
2018-08-10 00:58:41 +00:00
|
|
|
| varinitializer
|
|
|
|
| vardecl
|
2018-08-09 22:26:41 +00:00
|
|
|
| constdecl
|
|
|
|
| memoryvardecl
|
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
|
2018-08-12 23:30:33 +00:00
|
|
|
| subroutine
|
2018-10-01 18:05:32 +00:00
|
|
|
| asmsubroutine
|
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
|
2018-09-18 21:14:32 +00:00
|
|
|
| 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
|
|
|
|
2018-08-12 15:16:36 +00:00
|
|
|
labeldef : identifier ':' ;
|
2018-08-10 21:56:30 +00:00
|
|
|
|
2018-08-13 02:12:42 +00:00
|
|
|
unconditionaljump : 'goto' (integerliteral | identifier | 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
|
|
|
|
2018-08-10 00:58:41 +00:00
|
|
|
vardecl: datatype arrayspec? identifier ;
|
2018-08-08 23:54:43 +00:00
|
|
|
|
2018-08-10 00:58:41 +00:00
|
|
|
varinitializer : datatype arrayspec? identifier '=' expression ;
|
2018-08-08 23:54:43 +00:00
|
|
|
|
2018-08-09 22:26:41 +00:00
|
|
|
constdecl: 'const' varinitializer ;
|
|
|
|
|
|
|
|
memoryvardecl: 'memory' varinitializer;
|
|
|
|
|
2018-10-10 07:21:20 +00:00
|
|
|
datatype: 'ubyte' | 'byte' | 'uword' | 'word' | 'float' | 'str' | 'str_p' | 'str_s' | 'str_ps' ;
|
2018-08-09 22:26:41 +00:00
|
|
|
|
2018-10-30 19:29:03 +00:00
|
|
|
arrayspec: '[' expression ']' ;
|
2018-08-09 22:26:41 +00:00
|
|
|
|
|
|
|
assignment : assign_target '=' expression ;
|
2018-08-08 23:54:43 +00:00
|
|
|
|
|
|
|
augassignment :
|
2018-09-18 23:24:28 +00:00
|
|
|
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
|
|
|
| identifier
|
|
|
|
| scoped_identifier
|
2018-10-02 01:07:46 +00:00
|
|
|
| arrayindexed
|
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-08-10 21:56:30 +00:00
|
|
|
'(' expression ')'
|
|
|
|
| functioncall
|
2018-08-11 17:15:39 +00:00
|
|
|
| prefix = ('+'|'-'|'~') expression
|
2018-08-10 21:56:30 +00:00
|
|
|
| left = expression bop = '**' right = expression
|
2018-09-18 23:24:28 +00:00
|
|
|
| left = expression bop = ('*' | '/' | '//' | '%' ) right = expression
|
2018-08-10 21:56:30 +00:00
|
|
|
| left = expression bop = ('+' | '-' ) right = expression
|
|
|
|
| left = expression bop = ('<' | '>' | '<=' | '>=') right = expression
|
|
|
|
| left = expression bop = ('==' | '!=') right = expression
|
|
|
|
| left = expression bop = '&' right = expression
|
|
|
|
| left = expression bop = '^' right = expression
|
|
|
|
| left = expression bop = '|' right = expression
|
2018-09-16 13:40:28 +00:00
|
|
|
| rangefrom = expression 'to' rangeto = expression ('step' rangestep = expression)? // can't create separate rule due to mutual left-recursion
|
2018-08-10 21:56:30 +00:00
|
|
|
| left = expression bop = 'and' right = expression
|
|
|
|
| left = expression bop = 'or' right = expression
|
|
|
|
| left = expression bop = 'xor' 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
|
|
|
| identifier
|
|
|
|
| scoped_identifier
|
2018-10-01 20:23:16 +00:00
|
|
|
| arrayindexed
|
2018-08-08 23:54:43 +00:00
|
|
|
;
|
|
|
|
|
2018-08-10 21:56:30 +00:00
|
|
|
|
2018-10-01 20:23:16 +00:00
|
|
|
arrayindexed :
|
2018-11-02 21:06:57 +00:00
|
|
|
(identifier | scoped_identifier ) arrayspec
|
2018-10-01 20:23:16 +00:00
|
|
|
;
|
|
|
|
|
|
|
|
|
2018-08-10 21:56:30 +00:00
|
|
|
functioncall :
|
2018-08-13 02:12:42 +00:00
|
|
|
(identifier | scoped_identifier) '(' expression_list? ')'
|
2018-08-12 00:53:49 +00:00
|
|
|
;
|
|
|
|
|
2018-08-14 00:22:59 +00:00
|
|
|
|
|
|
|
functioncall_stmt :
|
|
|
|
(identifier | scoped_identifier) '(' expression_list? ')'
|
|
|
|
;
|
|
|
|
|
|
|
|
|
2018-08-12 15:16:36 +00:00
|
|
|
expression_list :
|
2018-10-02 20:52:05 +00:00
|
|
|
expression (',' EOL? expression)*
|
2018-08-08 23:54:43 +00:00
|
|
|
;
|
|
|
|
|
2018-08-12 15:16:36 +00:00
|
|
|
returnstmt : 'return' expression_list? ;
|
|
|
|
|
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
|
|
|
|
2018-08-10 00:58:41 +00:00
|
|
|
scoped_identifier : NAME ('.' NAME)+ ;
|
2018-08-08 23:54:43 +00:00
|
|
|
|
2018-11-02 21:06:57 +00:00
|
|
|
register : 'A' | 'X' | 'Y' ;
|
2018-09-02 16:32:48 +00:00
|
|
|
|
2018-11-09 23:53:50 +00:00
|
|
|
registerpair : 'AX' | 'AY' | 'XY' ;
|
|
|
|
|
2018-10-01 18:05:32 +00:00
|
|
|
statusregister : 'Pc' | 'Pz' | 'Pn' | 'Pv' ;
|
|
|
|
|
2018-09-13 20:31:59 +00:00
|
|
|
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
|
|
|
|
2018-10-02 20:52:05 +00:00
|
|
|
arrayliteral : '[' EOL? expression (',' EOL? expression)* EOL? ']' ;
|
2018-08-08 23:54:43 +00:00
|
|
|
|
2018-08-09 22:26:41 +00:00
|
|
|
stringliteral : STRING ;
|
2018-08-08 23:54:43 +00:00
|
|
|
|
2018-09-30 21:07:26 +00:00
|
|
|
charliteral : SINGLECHAR ;
|
|
|
|
|
2018-08-09 22:26:41 +00:00
|
|
|
floatliteral : FLOAT_NUMBER ;
|
2018-08-08 23:54:43 +00:00
|
|
|
|
2018-08-09 22:26:41 +00:00
|
|
|
literalvalue :
|
|
|
|
integerliteral
|
|
|
|
| booleanliteral
|
|
|
|
| arrayliteral
|
|
|
|
| stringliteral
|
2018-09-30 21:07:26 +00:00
|
|
|
| charliteral
|
2018-08-09 22:26:41 +00:00
|
|
|
| floatliteral
|
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 :
|
2018-10-01 18:05:32 +00:00
|
|
|
'sub' identifier '(' sub_params? ')' sub_return_part? (statement_block EOL)
|
2018-08-13 02:12:42 +00:00
|
|
|
;
|
|
|
|
|
2018-09-30 16:49:58 +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
|
|
|
|
2018-10-02 20:52:05 +00:00
|
|
|
sub_params : sub_param (',' EOL? sub_param)* ;
|
2018-10-01 18:05:32 +00:00
|
|
|
|
|
|
|
sub_param : identifier ':' datatype;
|
|
|
|
|
2018-10-02 20:52:05 +00:00
|
|
|
sub_returns : datatype (',' EOL? datatype)* ;
|
2018-10-01 18:05:32 +00:00
|
|
|
|
|
|
|
asmsubroutine :
|
|
|
|
'asmsub' identifier '(' asmsub_params? ')'
|
|
|
|
'->' 'clobbers' '(' clobber? ')' '->' '(' asmsub_returns? ')' (asmsub_address | statement_block )
|
|
|
|
;
|
|
|
|
|
|
|
|
asmsub_address : '=' address=integerliteral ;
|
|
|
|
|
2018-10-02 20:52:05 +00:00
|
|
|
asmsub_params : asmsub_param (',' EOL? asmsub_param)* ;
|
2018-10-01 18:05:32 +00:00
|
|
|
|
2018-11-09 23:53:50 +00:00
|
|
|
asmsub_param : identifier ':' datatype '@' (register | registerpair | statusregister);
|
2018-10-01 18:05:32 +00:00
|
|
|
|
|
|
|
clobber : register (',' register)* ;
|
2018-08-12 23:30:33 +00:00
|
|
|
|
2018-10-02 20:52:05 +00:00
|
|
|
asmsub_returns : asmsub_return (',' EOL? asmsub_return)* ;
|
2018-08-12 23:30:33 +00:00
|
|
|
|
2018-11-09 23:53:50 +00:00
|
|
|
asmsub_return : datatype '@' (register | registerpair | statusregister) ;
|
2018-08-14 12:33:36 +00:00
|
|
|
|
|
|
|
|
2018-09-23 00:04:45 +00:00
|
|
|
if_stmt : 'if' expression EOL? (statement | statement_block) EOL? else_part? EOL ; // 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
|
|
|
|
|
|
|
|
2018-10-06 20:54:03 +00:00
|
|
|
forloop : 'for' datatype? (register | identifier) 'in' expression EOL? 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 ;
|