428 lines
7.7 KiB
Plaintext
428 lines
7.7 KiB
Plaintext
/*
|
|
* Yet Another Tiger Compiler (YATC)
|
|
*
|
|
* Copyright 2014 Damian Valdés Santiago, Juan Carlos Pujol Mainegra
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*
|
|
*/
|
|
|
|
grammar tiger;
|
|
|
|
options
|
|
{
|
|
language = CSharp3;
|
|
//language = Java;
|
|
output = AST;
|
|
k = 3;
|
|
}
|
|
|
|
tokens
|
|
{
|
|
// para uso del tree adaptor
|
|
ALIAS_DECL;
|
|
ARRAY_ACCESS;
|
|
ARRAY_DECL;
|
|
ARRAY_INST;
|
|
BREAK;
|
|
EXPR_SEQ;
|
|
FIELD_ACCESS;
|
|
FIELD_ACCESS_TERMINAL;
|
|
FIELD_INST;
|
|
FILL_IN_TYPE;
|
|
FOR;
|
|
FUN_CALL;
|
|
FUN_DECL;
|
|
FUN_DECL_SEQ;
|
|
IF;
|
|
LET;
|
|
NEG;
|
|
NIL;
|
|
PROGRAM;
|
|
RECORD_DECL;
|
|
RECORD_INST;
|
|
TYPE;
|
|
TYPE_DECL;
|
|
TYPE_DECL_SEQ;
|
|
TYPE_FIELD;
|
|
VAR_ACCESS;
|
|
VAR_DECL;
|
|
WHILE;
|
|
|
|
// para vista
|
|
ARGS_FIELDS;
|
|
DECL_BLOCK;
|
|
FIELDS_INST;
|
|
FUN_TYPE_WRAPPER;
|
|
PARAM_DECL;
|
|
}
|
|
|
|
@lexer::header
|
|
{
|
|
using System;
|
|
}
|
|
|
|
@lexer::namespace{YATC.Grammar}
|
|
|
|
@lexer::modifier{public}
|
|
|
|
@lexer::ctorModifier{public}
|
|
|
|
@lexer::members
|
|
{
|
|
public override void ReportError(RecognitionException exc)
|
|
{
|
|
/* Abort on first error. */
|
|
throw new ParsingException(GetErrorMessage(exc, TokenNames), exc);
|
|
}
|
|
}
|
|
|
|
@parser::header
|
|
{
|
|
using System;
|
|
}
|
|
|
|
@parser::namespace{YATC.Grammar}
|
|
|
|
@parser::modifier{public}
|
|
|
|
@parser::ctorModifier{public}
|
|
|
|
@parser::members
|
|
{
|
|
public override void ReportError(RecognitionException exc)
|
|
{
|
|
/* Abort on first error. */
|
|
throw new ParsingException(GetErrorMessage(exc, TokenNames), exc);
|
|
}
|
|
}
|
|
|
|
fragment BEGIN_COMMENT
|
|
: '/*'
|
|
;
|
|
|
|
fragment END_COMMENT
|
|
: '*/'
|
|
;
|
|
|
|
// binary ops
|
|
PLUS : '+' ;
|
|
MINUS : '-' ;
|
|
MULT : '*' ;
|
|
DIV : '/' ;
|
|
|
|
// binary comparison
|
|
EQ : '=' ;
|
|
NOTEQ : '<>' ;
|
|
GT : '>' ;
|
|
GTEQ : '>=' ;
|
|
LT : '<' ;
|
|
LTEQ : '<=' ;
|
|
|
|
// logical ops
|
|
AND : '&' ;
|
|
OR : '|' ;
|
|
|
|
// grouping symbols
|
|
LPAREN : '(' ;
|
|
RPAREN : ')' ;
|
|
LBRACKET : '[' ;
|
|
RBRACKET : ']' ;
|
|
LKEY : '{' ;
|
|
RKEY : '}' ;
|
|
|
|
// separators
|
|
COMMA : ',' ;
|
|
SEMI : ';' ;
|
|
COLON : ':' ;
|
|
DOT : '.' ;
|
|
fragment
|
|
QUOTE : '\"';
|
|
|
|
ASSIGN : ':=' ;
|
|
|
|
// keywords
|
|
ARRAYKEY : 'array';
|
|
BREAKKEY : 'break';
|
|
DOKEY : 'do';
|
|
ELSEKEY : 'else';
|
|
ENDKEY : 'end';
|
|
FORKEY : 'for';
|
|
FUNCTIONKEY : 'function';
|
|
IFKEY : 'if';
|
|
INKEY : 'in';
|
|
INTKEY : 'int';
|
|
LETKEY : 'let';
|
|
NILKEY : 'nil';
|
|
OFKEY : 'of';
|
|
STRINGKEY : 'string';
|
|
THENKEY : 'then';
|
|
TOKEY : 'to';
|
|
TYPEKEY : 'type';
|
|
VARKEY : 'var';
|
|
WHILEKEY : 'while';
|
|
|
|
fragment
|
|
DIGIT
|
|
: '0'..'9'
|
|
;
|
|
|
|
fragment
|
|
LETTER
|
|
: 'a'..'z'|'A'..'Z'
|
|
;
|
|
|
|
fragment
|
|
ASCII_ESC
|
|
: '12' '0'..'7'
|
|
| '1' '0'..'1' '0'..'9'
|
|
| '0' '0'..'9' '0'..'9'
|
|
;
|
|
|
|
INT
|
|
: DIGIT+
|
|
;
|
|
|
|
ID : LETTER ( LETTER | DIGIT | '_' ) *
|
|
;
|
|
|
|
WS
|
|
: ( ' '|'\t'|'\r'|'\n' ) +
|
|
{$channel = Hidden;}
|
|
//{$channel = HIDDEN;}
|
|
;
|
|
|
|
fragment
|
|
ESC_SEQ
|
|
: '\\' ( 'n' | 'r' | 't' | QUOTE | ASCII_ESC | WS '\\' )
|
|
;
|
|
|
|
fragment
|
|
PRINTABLE_CHARACTER
|
|
: ((' '..'!') | ('#'.. '[') | (']'..'~'))
|
|
;
|
|
|
|
STRING : QUOTE ( ESC_SEQ | PRINTABLE_CHARACTER )* QUOTE ;
|
|
|
|
COMMENTARY
|
|
: BEGIN_COMMENT
|
|
( options {greedy=false;} : . )*
|
|
( COMMENTARY ( options {greedy=false;} : . )* )*
|
|
END_COMMENT
|
|
{$channel = Hidden;}
|
|
//{$channel = HIDDEN;}
|
|
;
|
|
|
|
public a_program
|
|
: expr ? EOF
|
|
-> ^(PROGRAM expr ?) ;
|
|
|
|
expr
|
|
: (ID LBRACKET disjunction_expr RBRACKET OFKEY) => array_inst
|
|
| (lvalue ASSIGN) => assignment
|
|
| disjunction_expr
|
|
| record_inst
|
|
| while_stat
|
|
| BREAKKEY
|
|
-> BREAK
|
|
;
|
|
|
|
disjunction_expr
|
|
: conjunction_expr (OR^ conjunction_expr)*
|
|
;
|
|
|
|
assignment
|
|
: lvalue ASSIGN^
|
|
( (ID LBRACKET disjunction_expr RBRACKET OFKEY) => array_inst
|
|
| disjunction_expr
|
|
| record_inst
|
|
)
|
|
;
|
|
|
|
record_inst
|
|
: ID LKEY field_inst_list? RKEY
|
|
-> ^(RECORD_INST ID field_inst_list?)
|
|
;
|
|
|
|
/*
|
|
Queremos que en un for solo se puedan evaluar condiciones retornen valor,
|
|
por ello que pedimos que la primera y segunda expresiones sean disjunction_expr,
|
|
para evitar de que no devuelva por otros motivos.
|
|
*/
|
|
for_expr
|
|
: FORKEY type_id ASSIGN disjunction_expr TOKEY disjunction_expr DOKEY expr
|
|
-> ^(FOR type_id disjunction_expr disjunction_expr expr)
|
|
;
|
|
|
|
array_inst
|
|
: ID LBRACKET disjunction_expr RBRACKET OFKEY expr
|
|
-> ^(ARRAY_INST ID disjunction_expr expr)
|
|
;
|
|
|
|
conjunction_expr
|
|
: relational_expr (AND^ relational_expr)*
|
|
;
|
|
|
|
/*
|
|
El operador ? al final de la expresion le da la no asociatividad requerida
|
|
a los operadores de comparacion (notar que en los demas se usa * para
|
|
anidarlos en una lista). Esto es que no se permite a = b = c, pero si a = (b = c).
|
|
*/
|
|
relational_expr
|
|
: arith_expr ((EQ | NOTEQ | GT | LT | GTEQ | LTEQ )^ arith_expr)?
|
|
;
|
|
|
|
arith_expr
|
|
: term_expr ((PLUS | MINUS)^ term_expr)*
|
|
;
|
|
|
|
term_expr
|
|
: atom ((MULT | DIV)^ atom)*
|
|
;
|
|
|
|
field_inst_list
|
|
: record_field_inst ( COMMA record_field_inst )*
|
|
-> ^(FIELDS_INST record_field_inst+)
|
|
;
|
|
|
|
record_field_inst
|
|
: ID EQ expr
|
|
-> ^(FIELD_INST ID expr)
|
|
;
|
|
|
|
decl
|
|
: type_decl+
|
|
-> ^(TYPE_DECL_SEQ type_decl+)
|
|
| var_decl
|
|
| fun_decl+
|
|
-> ^(FUN_DECL_SEQ fun_decl+)
|
|
;
|
|
|
|
type_decl
|
|
: TYPEKEY ID EQ type
|
|
-> ^(TYPE_DECL ID type)
|
|
;
|
|
|
|
var_decl
|
|
: VARKEY type_id COLON type_id ASSIGN expr
|
|
-> ^(VAR_DECL type_id type_id expr)
|
|
| VARKEY type_id ASSIGN expr
|
|
-> ^(VAR_DECL type_id FILL_IN_TYPE expr)
|
|
;
|
|
|
|
fun_decl
|
|
: FUNCTIONKEY type_id LPAREN type_fields? RPAREN (COLON type_id)? EQ expr
|
|
-> ^(FUN_DECL type_id ^(PARAM_DECL type_fields?) ^(FUN_TYPE_WRAPPER type_id?) expr)
|
|
;
|
|
|
|
type_id
|
|
: STRINGKEY
|
|
| INTKEY
|
|
| ID
|
|
;
|
|
|
|
type
|
|
: type_id
|
|
-> ^(ALIAS_DECL type_id)
|
|
| array_decl
|
|
| record_decl
|
|
;
|
|
|
|
record_decl
|
|
: LKEY type_fields? RKEY
|
|
-> ^(RECORD_DECL type_fields?)
|
|
;
|
|
|
|
array_decl
|
|
: ARRAYKEY OFKEY type_id
|
|
-> ^(ARRAY_DECL type_id)
|
|
;
|
|
|
|
type_fields
|
|
: type_field (COMMA type_field)*
|
|
-> type_field+
|
|
;
|
|
|
|
type_field
|
|
: type_id COLON type_id
|
|
-> ^(TYPE_FIELD type_id type_id)
|
|
;
|
|
|
|
atom
|
|
: MINUS atom
|
|
-> ^(NEG atom)
|
|
| constant_value
|
|
| lvalue
|
|
| funcall
|
|
| if_then_expr
|
|
| for_expr
|
|
| let_expr
|
|
| LPAREN expr_seq RPAREN
|
|
-> expr_seq
|
|
;
|
|
|
|
constant_value
|
|
: STRING
|
|
| INT
|
|
| NILKEY
|
|
;
|
|
|
|
if_then_expr
|
|
: IFKEY conditional=disjunction_expr THENKEY then_expr=expr (ELSEKEY else_expr=expr)?
|
|
-> ^(IF $conditional $then_expr $else_expr?)
|
|
;
|
|
|
|
while_stat
|
|
: WHILEKEY cond=disjunction_expr DOKEY do_expr=expr
|
|
-> ^(WHILE $cond $do_expr)
|
|
;
|
|
|
|
let_expr
|
|
: LETKEY decl+ INKEY expr_seq ENDKEY
|
|
-> ^(LET ^(DECL_BLOCK decl+) expr_seq)
|
|
;
|
|
|
|
lvalue
|
|
: type_id lvalue_access? -> ^(VAR_ACCESS type_id lvalue_access?)
|
|
;
|
|
|
|
lvalue_access
|
|
: DOT type_id lvalue_access?
|
|
-> ^(FIELD_ACCESS type_id lvalue_access?)
|
|
| LBRACKET disjunction_expr RBRACKET lvalue_access?
|
|
-> ^(ARRAY_ACCESS disjunction_expr lvalue_access?)
|
|
;
|
|
|
|
funcall
|
|
: type_id LPAREN arg_list? RPAREN
|
|
-> ^(FUN_CALL type_id arg_list?)
|
|
;
|
|
|
|
expr_seq
|
|
: expr (SEMI expr)*
|
|
-> ^(EXPR_SEQ expr+)
|
|
| -> ^(EXPR_SEQ )
|
|
;
|
|
|
|
arg_list
|
|
: expr (COMMA expr)*
|
|
-> ^(ARGS_FIELDS expr+)
|
|
;
|
|
|