Commiting progress on compiler.
[trinary.git] / extended / tri.g
blob2c71d98eb881ed65cbee87db358c3cd7f3c354fc
1 /*
2    Lexer
3 */
4 header
7 class TriLexer extends Lexer;
9 options
11    k = 2;
12    charVocabulary='\u0000'..'\u007F';
15 tokens
17    STRUCT         =  "struct";
18    INT            =  "int";
19    BOOL           =  "bool";
20    FUN            =  "fun";
21    VOID           =  "void";
22    PRINT          =  "print";
23    ENDL           =  "endl";
24    READ           =  "read";
25    IF             =  "if";
26    ELSE           =  "else";
27    WHILE          =  "while";
28    DELETE         =  "delete";
29    RETURN         =  "return";
30    TRUE           =  "true";
31    FALSE          =  "false";
32    NEW            =  "new";
33    NULL           =  "null";
36 LBRACE   :  "{"   ;
37 RBRACE   :  "}"   ;
38 SEMI     :  ";"   ;
39 COMMA    :  ","   ;
40 LPAREN   :  "("   ;
41 RPAREN   :  ")"   ;
42 ASSIGN   :  "="   ;
43 DOT      :  "."   ;
44 AND      :  "&&"  ;
45 OR       :  "||"  ;
46 EQ       :  "=="  ;
47 LT       :  "<"   ;
48 GT       :  ">"   ;
49 NE       :  "!="  ;
50 LE       :  "<="  ;
51 GE       :  ">="  ;
52 PLUS     :  "+"   ;
53 MINUS    :  "-"   ;
54 TIMES    :  "*"   ;
55 DIVIDE   :  "/"   ;
56 NOT      :  "!"   ;
58 ID options {testLiterals=true;}
59          :  ('a'..'z' | 'A'..'Z')('a'..'z' | 'A'..'Z' | '0'..'9')* ;
61 INTEGER      :  '0' | ('1'..'9') ('0'..'9')* ;
63 WS       :  (  ' '
64             |  '\t'
65             |  '\f'
66                // handle newlines
67             |  (  options {generateAmbigWarnings=false;}
68                :  "\r\n"   // Evil DOS
69                |  '\r'     // Macintosh
70                |  '\n'     // Unix (the right way)
71                )
72                { newline(); }
73             )+
74             { $setType(Token.SKIP); }
75          ;
77 COMMENT  :  "#"(~'\n')* '\n'
78             { newline(); $setType(Token.SKIP); }
79          ;
82    Parser
84 class TriParser extends Parser;
86 options
88    buildAST=true;
89    defaultErrorHandler=false;
92 tokens
94    PROGRAM;
95    TYPES;
96    TYPE;
97    DECLS;
98    FUNCS;
99    DECL;
100    DECLLIST;
101    PARAMS;
102    RETTYPE;
103    BLOCK;
104    STMTS;
105    INVOKE;
106    ARGS;
107    NEG;
110 program
111    :!  t:types d:declarations f:functions EOF!
112       { #program = #([PROGRAM,"PROGRAM"],
113                      #([TYPES,"TYPES"], #t),
114                      #([DECLS,"DECLS"], #d),
115                      #([FUNCS,"FUNCS"], #f)); }
116    ;
117 types
118    :  (STRUCT ID LBRACE) => type_declaration types
119    |
120    ;
121 type_declaration
122    :  STRUCT^ ID LBRACE! nested_decl RBRACE! SEMI!
123    ;
124 nested_decl
125    :  (decl SEMI!)+
126    ;
127 decl
128    :! t:type i:ID { #decl = #([DECL,"DECL"], #([TYPE,"TYPE"],#t), #i); }
129    ;
130 type
131    :  INT
132    |  BOOL
133    |  STRUCT^ ID
134    ;
135 declarations
136    :  (declaration)*
137    ;
138 declaration
139    :!  t:type ilist:id_list SEMI!
140       { #declaration = #([DECLLIST,"DECLLIST"], #([TYPE,"TYPE"], #t), #ilist); }
141    ;
142 id_list
143    :  ID (COMMA! ID)*
144    ;
145 functions
146    :  (function)*
147    ;
148 function
149    :!  FUN<AST=AnnotatedFunctionAST> id:ID p:parameters r:return_type LBRACE d:declarations s:statement_list RBRACE
150       { #function = #(FUN,
151                         #id,
152                         #([PARAMS,"PARAMS"], #p),
153                         #([RETTYPE, "RETTYPE"], #r),
154                         #([DECLS,"DECLS"], #d),
155                         #([STMTS,"STMTS"], #s)
156                      );
157       }
158    ;
159 parameters
160    :  LPAREN! (decl (COMMA! decl)*)? RPAREN!
161    ;
162 return_type
163    :  type
164    |  VOID
165    ;
166 statement
167    :  block
168    |  (lvalue ASSIGN) => assignment
169    |  print
170    |  read
171    |  conditional
172    |  loop
173    |  delete
174    |  ret
175    |  (ID LPAREN) => invocation
176    ;
177 block
178    :!  LBRACE! s:statement_list RBRACE!
179          {
180             #block = #([BLOCK, "BLOCK"],
181                                     #([STMTS,"STMTS"], #s)
182                                    );
183          }
184    ;
185 statement_list
186    :  (statement)*
187    ;
188 assignment
189    :  lvalue ASSIGN^ expression SEMI!
190    ;
191 print
192    :  PRINT^ expression (ENDL)? SEMI!
193    ;
194 read
195    :  READ^ lvalue SEMI!
196    ;
197 conditional
198    :  IF^ LPAREN! expression RPAREN! block (ELSE! block)?
199    ;
200 loop
201    :  WHILE^ LPAREN! expression RPAREN! block
202    ;
203 delete
204    :  DELETE^ expression SEMI!
205    ;
207    :  RETURN^ (expression)? SEMI!
208    ;
209 invocation
210    :! id:ID a:arguments SEMI
211       {
212          #invocation = #([INVOKE,"INVOKE","AnnotatedExpressionAST"], #id, #a);
213       }
214    ;
215 lvalue
216    :  ID (DOT^<AST=DottedAST> ID)*
217    ;
218 expression
219    :  boolterm ((AND^<AST=AnnotatedExpressionAST> | OR^<AST=AnnotatedExpressionAST>) boolterm)*
220    ;
221 boolterm
222    :  simple ((EQ^<AST=AnnotatedExpressionAST> | LT^<AST=AnnotatedExpressionAST> | GT^<AST=AnnotatedExpressionAST> | NE^<AST=AnnotatedExpressionAST> | LE^<AST=AnnotatedExpressionAST> | GE^<AST=AnnotatedExpressionAST>) simple)?
223    ;
224 simple
225    :  term ((PLUS^<AST=AnnotatedExpressionAST> | MINUS^<AST=AnnotatedExpressionAST>) term)*
226    ;
227 term
228    :  unary ((TIMES^<AST=AnnotatedExpressionAST> | DIVIDE^<AST=AnnotatedExpressionAST>) unary)*
229    ;
230 unary
231    :  NOT! odd_not
232    |  MINUS! odd_neg
233    |  selector
234    ;
235 odd_not
236    :  NOT! even_not
237    |!  s:selector { #odd_not = #([NOT,"!","AnnotatedExpressionAST"], #s); }
238    ;
239 even_not
240    :  NOT! odd_not
241    |  selector
242    ;
243 odd_neg
244    :  MINUS! even_neg
245    |!  s:selector { #odd_neg = #([NEG,"NEG","AnnotatedExpressionAST"], #s); }
246    ;
247 even_neg
248    :  MINUS! odd_neg
249    |  selector
250    ;
251 selector
252    :  factor (DOT^<AST=DottedAST> ID)*
253    ;
254 factor
255    :  LPAREN! expression RPAREN!
256    |!  id:ID<AST=AnnotatedExpressionAST> (a:arguments)?
257       {
258          if (#a != null)
259          {
260             #factor = #([INVOKE,"INVOKE","AnnotatedExpressionAST"], #id, #a);
261          }
262          else
263          {
264             #factor = #id;
265          }
266       }
267    |  INTEGER<AST=AnnotatedExpressionAST>
268    |  TRUE<AST=AnnotatedExpressionAST>
269    |  FALSE<AST=AnnotatedExpressionAST>
270    |  NEW^<AST=AnnotatedExpressionAST> ID<AST=AnnotatedExpressionAST>
271    |  NULL<AST=AnnotatedExpressionAST>
272    ;
273 arguments
274    :  LPAREN! arg_list RPAREN!
275    ;
276 arg_list
277    : expression (COMMA! expression)*
278       { #arg_list = #([ARGS,"ARGS"], #arg_list); }
279    |! { #arg_list = #([ARGS,"ARGS"]); }
280    ;
283    EvilTreeParser
284  */
285 class TriTreeParser extends TreeParser;
287 options
289    importVocab=TriLexer;
292 program [record]
293     :  #(PROGRAM types[record] declarations[record] functions[record])
294     ;
296 types [record]
297     :  #(TYPES (type_declarations[record])*)
298     ;
300 type_declarations [record]
301     :  #(STRUCT val:ID
302     {
303         key = val.getText()
304         structure = Entry(key)
305         record.add_to_global(key, structure)
306         record.reset_counter()
307     }
308     (decl[record, structure])+
310     # DELETE? insert into global table
311     #table.put(key, structure);
313     )
314     ;
317 decl [records, structure=False] { value = False }
318     :  #(DECL value=type[records] var:ID)
319     {
320         key = var.getText()
322         if structure == False:
323             records.add_to_local(key, value)
324         else:
325             structure.add_to_members(key, value)
327          # DELETE? insert into local table
328          #local.put("" + (i.count), t);
329         records.increment_counter()
330     }
331     ;
334 type [records] returns [result = False]
335    :  #(TYPE result=datatypes[records])
336    ;
339 datatypes [records] returns [result = False]
340    :  INT
341     {
342         result = Entry(0)
343     }
344     |  BOOL
345     {
346         result = Entry(True)
347     }
348     |  #(STRUCT var:ID)
349     {
350         key = var.getText()
351         result = records.return_value(key)
352     }
353     ;
355 declarations [records, local_decls=False]
356     :  #(DECLS (declarations_inter[records, local_decls])*)
357     ;
359 declarations_inter [records, local_decls]
360     :  #(DECLLIST declaration[records, local_decls])
361     ;
363 declaration [records, local_decls] {entry = False}
364     :  entry=type[records] id_list[records, local_decls, entry]
365     ;
367 id_list [records, local_decls, entry]
368     :  (val:ID
369     {
370         key = val.getText()
371         if local_decls:
372             records.add_to_locals(key, entry)
373         else:
374             records.add_to_globals(key, entry)
375     }
376     )+
377     ;
379 functions [Records table] {boolean tmp, main = false;}
380    :  #(FUNCS (tmp=function[table]
381     {
382         if (tmp == True):
383             main = True
384     }
385     )*)
386     {
387         if (!main) {
388                (new Entry()).printError("'fun main() int {}' not found"); } }
389    ;
391 function [Records table] returns [boolean rtnMain = false]
392    { Entry fn, returnType = null, retn; String value; boolean param = false;}
393    :  #(FUN var2:ID
394       {
395          value = var2.getText();
396          fn = new Entry(value, new Entry(0));
397          table.put(value, fn);
398       }
399    param=parameters[table, fn.table, fn] returnType=return_type[table, fn.table]
400       {
401          fn.table.put(fn.table.RTN, returnType);
403          if (!returnType.isNull) {
404             fn.return_variable = returnType;
405             fn.hasReturnType = true;
406          }
407          else {
408             fn.hasReturnType = false;
409          }
411          if (value.equals("main") && !param && returnType.isInt) {
412             rtnMain = true;
413          }
414       }
415    declarations[table, True] retn=statements[table, fn.table]
416    {
417       if (retn == null && (fn.hasReturnType) && !(fn.return_variable.isNull)) {
418          fn.printError(fn.stringname + " doesn't return through all paths " +
419                        "or there is extra code after the last return statement");
420       }
421       else if (retn != null && !(fn.hasReturnType)) {
422          fn.printError(fn.stringname + " doesn't return a value");
423       }
424    }
425    )
426    ;
428 parameters [Records table, Records local, Entry f_entry]
429    returns [boolean rtn = false;]
430    :  #(PARAMS (params_decl[table, local]
431       {
432          rtn = true;
433          f_entry.hasParams = true;
434       }
435       )?)
436    ;
438 params_decl [Records table, Records local] { Counter i = new Counter(0); }
439    :  (decl[table])+
440    ;
442 return_type [Records table, Records local] returns [Entry t = null]
443    :  #(RETTYPE t=ret_type[table, local])
444    ;
446 ret_type [Records table, Records local] returns [Entry t = null]
447    :  t=datatypes[table, local]
448    |  VOID
449       {
450          t = new Entry();
451       }
452    ;
454 statements [Records table, Records local] returns [Entry rtn = null]
455    :  #(STMTS (rtn=statement[table, local])*)
456    ;
458 statement [Records table, Records local] returns [Entry rtn = null]
459    { Entry tmp = null;}
460    :  rtn=block[table, local]
461    |  assignment[table, local]
462    |  print[table, local]
463    |  read[table, local]
464    |  rtn=conditional[table, local]
465    |  rtn=loop[table, local]
466    |  delete[table, local]
467    |  rtn=ret[table, local]
468    |  tmp=invocation[table, local]
469    ;
471 block [Records table, Records local] returns [Entry rtn = null]
472    :  #(BLOCK rtn=statements[table, local])
473    ;
475 assignment [Records table, Records local]
476    {
477       Entry e;
478       Entry id;
479    }
480    :  #(ASSIGN id=lvalue[table, local] e=expression[table, local])
481       {
482          id.compareTypes(e, "=");
483       }
484    ;
486 print [Records table, Records local]
487    {
488       Entry e;
489    }
490    :  #(PRINT e=expression[table, local] (ENDL)?)
491       {
492          if (!e.isInt) {
493             e.printError("found '" + e.stringname +
494             "', can only print integers");
495          }
496       }
497    ;
499 read [Records table, Records local]
500    {
501       Entry id;
502    }
503    :  #(READ id=lvalue[table, local])
504       {
505          if (!id.isInt) {
506             id.printError("found '" + id.stringname +
507             "', can only read to an integer");
508          }
509       }
510    ;
512 conditional [Records table, Records local] returns [Entry rtn = null]
513    {
514       Entry e, tmp=null;
515    }
516    :  #(IF e=expression[table, local]
517       {
518          if (!e.isBool) {
519             e.printError("found '" + e.stringname
520             +"', condifional needs a boolean guard");
521          }
522       }
524       rtn=block[table, local] (tmp=block[table, local]
525       {
526          if (rtn != null) {
527             rtn = tmp;
528          }
529       }
530       )?)
531    ;
533 loop [Records table, Records local] returns [Entry rtn = null]
534    {
535       Entry e;
536    }
537    :  #(WHILE e=expression[table, local]
538       {
539          if (!e.isBool) {
540             e.printError("found '" + e.stringname
541             +"', loop needs a boolean guard");
542          }
543       }
544       rtn=block[table, local])
545    ;
547 delete [Records table, Records local]
548    {
549       Entry e;
550    }
551    :  #(DELETE e=expression[table, local])
552       {
553          if (!e.isStruct) {
554             e.printError("cannot free '" + e.stringname + "' b/c it is not a struct");
555          }
556       }
557    ;
559 ret [Records table, Records local] returns [Entry t = null]
560    :  #(RETURN (t=expression[table, local]
561          { t.compareTypes( (Entry)local.get(local.RTN) , "return"); }
562       )?)
563    ;
565 invocation [Records table, Records local] returns [Entry rtn = null]
566    { Entry f_entry = null; }
567    : #(INVOKE val:ID
568       {
569          String s = (String)val.getText();
570          f_entry = (Entry)table.ReturnValue(s, local);
571          if (!(f_entry.isFunction)) {
572             f_entry.printError(" '" + s + "' is not a function. invocation failed");
573          }
574       }
575      arguments[table, local, f_entry])
576       {
577          String value = val.getText();
578          rtn = (table.ReturnValue(value, local)).return_variable;
579       }
580    ;
582 lvalue [Records table, Records local] returns [Entry t = null]
583    {
584       Entry id;
585    }
586    :  val0:ID
587       {
588          String value = val0.getText();
589          t = table.ReturnValue(value, local);
590       }
591    |  #(DOT id=lvalue[table, local] val1:ID)
592       {
593          String value = val1.getText();
594          if (!id.isStruct) {
595             id.printError("can't apply . to '" + id.stringname + "' (not a struct)");
596          }
598          t = id.table.ReturnValue(value, null);
599       }
600    ;
602 expression [Records table, Records local] returns [Entry t = null]
603    {Entry lft, rht, f_entry;}
604    :  #(AND lft=expression[table, local] rht=expression[table, local])
605       {
606          if (!lft.isBool) {
607             lft.printError("AND requires boolean types");
608          }
609          lft.compareTypes(rht, "AND");
610          t = new Entry(true);
611       }
612    |  #(OR lft=expression[table, local] rht=expression[table, local])
613       {
614          if (!lft.isBool) {
615             lft.printError("OR requires boolean types");
616          }
617          lft.compareTypes(rht, "OR");
618          t = new Entry(true);
619       }
620    |  #(DIVIDE lft=expression[table, local] rht=expression[table, local])
621       {
622          if (!lft.isInt) {
623             lft.printError("DIVIDE requires int types");
624          }
625          lft.compareTypes(rht, "DIVIDE");
626          t = new Entry(0);
627       }
628    |  #(TIMES lft=expression[table, local] rht=expression[table, local])
629       {
630          if (!lft.isInt) {
631             lft.printError("TIMES requires int types");
632          }
633          lft.compareTypes(rht, "TIMES");
634          t = new Entry(0);
635       }
636    |  #(PLUS lft=expression[table, local] rht=expression[table, local])
637       {
638          if (!lft.isInt) {
639             lft.printError("PLUS requires int types");
640          }
641          lft.compareTypes(rht, "PLUS");
642          t = new Entry(0);
643       }
644    |  #(MINUS lft=expression[table, local] rht=expression[table, local])
645       {
646          if (!lft.isInt) {
647             lft.printError("MINUS requires int types");
648          }
649          lft.compareTypes(rht, "MINUS");
650          t = new Entry(0);
651       }
652    |  #(EQ lft=expression[table, local] rht=expression[table, local])
653       {
654     if (!lft.isInt && !lft.isStruct) {
655        lft.printError("EQ requires int or struct types");
656     }
657          lft.compareTypes(rht, "EQ");
658          t = new Entry(true);
659       }
660    |  #(LT lft=expression[table, local] rht=expression[table, local])
661       {
662          if (!lft.isInt) {
663             lft.printError("LT requires int types");
664          }
665          lft.compareTypes(rht, "LT");
666          t = new Entry(true);
667       }
668    |  #(GT lft=expression[table, local] rht=expression[table, local])
669       {
670          if (!lft.isInt) {
671             lft.printError("GT requires int types");
672          }
673          lft.compareTypes(rht, "GT");
674          t = new Entry(true);
675       }
676    |  #(NE lft=expression[table, local] rht=expression[table, local])
677       {
678          if (!lft.isInt && !lft.isStruct) {
679             lft.printError("NE requires int or struct types");
680          }
681          lft.compareTypes(rht, "NE");
682          t = new Entry(true);
683       }
684    |  #(LE lft=expression[table, local] rht=expression[table, local])
685       {
686          if (!lft.isInt) {
687             lft.printError("LE requires int types");
688          }
689          lft.compareTypes(rht, "LE");
690          t = new Entry(true);
691       }
692    |  #(GE lft=expression[table, local] rht=expression[table, local])
693       {
694          if (!lft.isInt) {
695             lft.printError("GE requires int types");
696          }
697          lft.compareTypes(rht, "GE");
698          t = new Entry(true);
699       }
700    |  #(NOT lft=expression[table, local])
701       {
702          if (lft.isBool) {
703             t = new Entry(true);
704          }
705          else {
706             lft.printError("can't apply NOT to '" + lft.stringname + "'");
707          }
708       }
709    |  #(NEG lft=expression[table, local])
710       {
711          if (lft.isInt) {
712             t = new Entry(0);
713          }
714          else {
715             lft.printError("can't apply NEG to '" + lft.stringname + "'");
716          }
717       }
718    |  #(NEW val0:ID)
719       {
720          String value = val0.getText();
721          lft = table.ReturnValue(value, local);
723          if (lft.isStruct) {
724             t = new Entry(value);
725          }
726          else {
727             lft.printError("can't apply NEW to '" + lft.stringname + "'");
728          }
729       }
730    |  #(INVOKE val4:ID
731       {
732          String s = (String)val4.getText();
733          f_entry = (Entry)table.ReturnValue(s, local);
734          if (!(f_entry.isFunction)) {
735             f_entry.printError(" '" + s + "' is not a function. invocation failed");
736          }
738          t = f_entry.return_variable;
739       }
740       (arguments[table, local, f_entry])?)
741    |  #(DOT lft=expression[table, local] val5:ID)
742       {
743          String value = val5.getText();
744          if (!lft.isStruct) {
745             lft.printError("can't apply . to '" + lft.stringname + "'(not a struct)");
746          }
748          t = table.ReturnValue(value, local, lft.table);
749       }
750    |  val1:ID
751       {
752          String value = val1.getText();
754          t = table.ReturnValue(value, local);
755       }
756    |  val2:INTEGER
757       {
758          int value = (int)Integer.parseInt(val2.getText());
759          t = new Entry(value);
760       }
761    |  val3:TRUE
762       {
763          boolean value = (boolean)Boolean.getBoolean(val3.getText());
764          t = new Entry(value);
765       }
766    |  FALSE
767       {
768          t = new Entry(false);
769       }
770    |  NULL
771       {
772          t = new Entry();
773       }
774    ;
776 arguments [Records table, Records local, Entry f_entry]
777    {
778       Entry e, actual; int count = 0; boolean f_params = false;
779    }
780    :  #(ARGS ((e=expression[table, local]
781          {
782          actual = (Entry)table.ReturnValue("" + count, f_entry.table);
783          actual.compareTypes(e, "argument");
784          count++;
785          }
786       )+
787          {
788          if (!(f_entry.hasParams)) {
789             f_entry.printError(f_entry.stringname + " doesn't require params");
790          }
791          f_params = true;
792          }
793       )?)
794          {
795          if ((f_entry.hasParams) && !f_params) {
796             f_entry.printError(f_entry.stringname + " requires arguments");
797          }
798          else if (f_params && f_entry.table.containsKey("" + count)) {
799             f_entry.printError(f_entry.stringname + " requires more arguments");
800          }
801          }
802    ;