-
Notifications
You must be signed in to change notification settings - Fork 41
/
TIP.g4
128 lines (97 loc) · 3.45 KB
/
TIP.g4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
grammar TIP;
// Grammar for Moeller and Schwartzbach's Tiny Imperative Language (TIP)
////////////////////// TIP Programs //////////////////////////
program : (function)+
;
function : nameDeclaration
'(' (nameDeclaration (',' nameDeclaration)*)? ')'
KPOLY?
'{' (declaration*) (statement*) returnStmt '}'
;
////////////////////// TIP Declarations /////////////////////////
declaration : KVAR nameDeclaration (',' nameDeclaration)* ';' ;
nameDeclaration : IDENTIFIER ;
////////////////////// TIP Expressions //////////////////////////
// Expressions in TIP are ordered to capture precedence.
// We adopt the C convention that orders operators as:
// postfix, unary, multiplicative, additive, relational, and equality
//
// NB: # creates rule label that can be accessed in visitor
//
// ANTLR4 can automatically refactor direct left-recursion so we
// place all recursive rules as options in a single rule. This
// means that we have some complex rules here that might otherwise
// be separated out, e.g., funAppExpr, and that we can't factor out
// other useful concepts, e.g., defining a rule for the subset of
// expressions that can be used as an l-value. We prefer a clean
// grammar, which simplifies AST construction, and work around these
// issues elsewhere in the compiler, e.g., introducing an assignable expr
// weeding pass.
//
expr : expr '(' (expr (',' expr)*)? ')' #funAppExpr
| expr '.' IDENTIFIER #accessExpr
| '*' expr #deRefExpr
| SUB NUMBER #negNumber
| '&' expr #refExpr
| expr op=(MUL | DIV) expr #multiplicativeExpr
| expr op=(ADD | SUB) expr #additiveExpr
| expr op=GT expr #relationalExpr
| expr op=(EQ | NE) expr #equalityExpr
| IDENTIFIER #varExpr
| NUMBER #numExpr
| KINPUT #inputExpr
| KALLOC expr #allocExpr
| KNULL #nullExpr
| recordExpr #recordRule
| '(' expr ')' #parenExpr
;
recordExpr : '{' (fieldExpr (',' fieldExpr)*)? '}' ;
fieldExpr : IDENTIFIER ':' expr ;
////////////////////// TIP Statements //////////////////////////
statement : blockStmt
| assignStmt
| whileStmt
| ifStmt
| outputStmt
| errorStmt
;
assignStmt : expr '=' expr ';' ;
blockStmt : '{' (statement*) '}' ;
whileStmt : KWHILE '(' expr ')' statement ;
ifStmt : KIF '(' expr ')' statement (KELSE statement)? ;
outputStmt : KOUTPUT expr ';' ;
errorStmt : KERROR expr ';' ;
returnStmt : KRETURN expr ';' ;
////////////////////// TIP Lexicon //////////////////////////
// By convention ANTLR4 lexical elements use all caps
MUL : '*' ;
DIV : '/' ;
ADD : '+' ;
SUB : '-' ;
GT : '>' ;
EQ : '==' ;
NE : '!=' ;
NUMBER : [0-9]+ ;
// Placing the keyword definitions first causes ANTLR4 to prioritize
// their matching relative to IDENTIFIER (which comes later).
KALLOC : 'alloc' ;
KINPUT : 'input' ;
KWHILE : 'while' ;
KIF : 'if' ;
KELSE : 'else' ;
KVAR : 'var' ;
KRETURN : 'return' ;
KNULL : 'null' ;
KOUTPUT : 'output' ;
KERROR : 'error' ;
// Keyword to declare functions as polymorphic
KPOLY : 'poly' ;
IDENTIFIER : [a-zA-Z_][a-zA-Z0-9_]* ;
// ANTLR4 has a nice mechanism for specifying the characters that should
// skipped during parsing. You write "-> skip" after the pattern and
// let ANTLR4s pattern matching do the rest.
// Ignore whitespace
WS : [ \t\n\r]+ -> skip ;
// This does not handle nested block comments.
BLOCKCOMMENT: '/*' .*? '*/' -> skip ;
COMMENT : '//' ~[\n\r]* -> skip ;