7 class TriLexer extends Lexer;
12 charVocabulary='\u0000'..'\u007F';
58 ID options {testLiterals=true;}
59 : ('a'..'z' | 'A'..'Z')('a'..'z' | 'A'..'Z' | '0'..'9')* ;
61 INTEGER : '0' | ('1'..'9') ('0'..'9')* ;
67 | ( options {generateAmbigWarnings=false;}
70 | '\n' // Unix (the right way)
74 { $setType(Token.SKIP); }
77 COMMENT : "#"(~'\n')* '\n'
78 { newline(); $setType(Token.SKIP); }
84 class TriParser extends Parser;
89 defaultErrorHandler=false;
111 :! t:types d:declarations f:functions EOF!
112 { #program = #([PROGRAM,"PROGRAM"],
113 #([TYPES,"TYPES"], #t),
114 #([DECLS,"DECLS"], #d),
115 #([FUNCS,"FUNCS"], #f)); }
118 : (STRUCT ID LBRACE) => type_declaration types
122 : STRUCT^ ID LBRACE! nested_decl RBRACE! SEMI!
128 :! t:type i:ID { #decl = #([DECL,"DECL"], #([TYPE,"TYPE"],#t), #i); }
139 :! t:type ilist:id_list SEMI!
140 { #declaration = #([DECLLIST,"DECLLIST"], #([TYPE,"TYPE"], #t), #ilist); }
149 :! FUN<AST=AnnotatedFunctionAST> id:ID p:parameters r:return_type LBRACE d:declarations s:statement_list RBRACE
152 #([PARAMS,"PARAMS"], #p),
153 #([RETTYPE, "RETTYPE"], #r),
154 #([DECLS,"DECLS"], #d),
155 #([STMTS,"STMTS"], #s)
160 : LPAREN! (decl (COMMA! decl)*)? RPAREN!
168 | (lvalue ASSIGN) => assignment
175 | (ID LPAREN) => invocation
178 :! LBRACE! s:statement_list RBRACE!
180 #block = #([BLOCK, "BLOCK"],
181 #([STMTS,"STMTS"], #s)
189 : lvalue ASSIGN^ expression SEMI!
192 : PRINT^ expression (ENDL)? SEMI!
198 : IF^ LPAREN! expression RPAREN! block (ELSE! block)?
201 : WHILE^ LPAREN! expression RPAREN! block
204 : DELETE^ expression SEMI!
207 : RETURN^ (expression)? SEMI!
210 :! id:ID a:arguments SEMI
212 #invocation = #([INVOKE,"INVOKE","AnnotatedExpressionAST"], #id, #a);
216 : ID (DOT^<AST=DottedAST> ID)*
219 : boolterm ((AND^<AST=AnnotatedExpressionAST> | OR^<AST=AnnotatedExpressionAST>) boolterm)*
222 : simple ((EQ^<AST=AnnotatedExpressionAST> | LT^<AST=AnnotatedExpressionAST> | GT^<AST=AnnotatedExpressionAST> | NE^<AST=AnnotatedExpressionAST> | LE^<AST=AnnotatedExpressionAST> | GE^<AST=AnnotatedExpressionAST>) simple)?
225 : term ((PLUS^<AST=AnnotatedExpressionAST> | MINUS^<AST=AnnotatedExpressionAST>) term)*
228 : unary ((TIMES^<AST=AnnotatedExpressionAST> | DIVIDE^<AST=AnnotatedExpressionAST>) unary)*
237 |! s:selector { #odd_not = #([NOT,"!","AnnotatedExpressionAST"], #s); }
245 |! s:selector { #odd_neg = #([NEG,"NEG","AnnotatedExpressionAST"], #s); }
252 : factor (DOT^<AST=DottedAST> ID)*
255 : LPAREN! expression RPAREN!
256 |! id:ID<AST=AnnotatedExpressionAST> (a:arguments)?
260 #factor = #([INVOKE,"INVOKE","AnnotatedExpressionAST"], #id, #a);
267 | INTEGER<AST=AnnotatedExpressionAST>
268 | TRUE<AST=AnnotatedExpressionAST>
269 | FALSE<AST=AnnotatedExpressionAST>
270 | NEW^<AST=AnnotatedExpressionAST> ID<AST=AnnotatedExpressionAST>
271 | NULL<AST=AnnotatedExpressionAST>
274 : LPAREN! arg_list RPAREN!
277 : expression (COMMA! expression)*
278 { #arg_list = #([ARGS,"ARGS"], #arg_list); }
279 |! { #arg_list = #([ARGS,"ARGS"]); }
285 class TriTreeParser extends TreeParser;
289 importVocab=TriLexer;
293 : #(PROGRAM types[record] declarations[record] functions[record])
297 : #(TYPES (type_declarations[record])*)
300 type_declarations [record]
304 structure = Entry(key)
305 record.add_to_global(key, structure)
306 record.reset_counter()
308 (decl[record, structure])+
310 # DELETE? insert into global table
311 #table.put(key, structure);
317 decl [records, structure=False] { value = False }
318 : #(DECL value=type[records] var:ID)
322 if structure == False:
323 records.add_to_local(key, value)
325 structure.add_to_members(key, value)
327 # DELETE? insert into local table
328 #local.put("" + (i.count), t);
329 records.increment_counter()
334 type [records] returns [result = False]
335 : #(TYPE result=datatypes[records])
339 datatypes [records] returns [result = False]
351 result = records.return_value(key)
355 declarations [records, local_decls=False]
356 : #(DECLS (declarations_inter[records, local_decls])*)
359 declarations_inter [records, local_decls]
360 : #(DECLLIST declaration[records, local_decls])
363 declaration [records, local_decls] {entry = False}
364 : entry=type[records] id_list[records, local_decls, entry]
367 id_list [records, local_decls, entry]
372 records.add_to_locals(key, entry)
374 records.add_to_globals(key, entry)
379 functions [Records table] {boolean tmp, main = false;}
380 : #(FUNCS (tmp=function[table]
388 (new Entry()).printError("'fun main() int {}' not found"); } }
391 function [Records table] returns [boolean rtnMain = false]
392 { Entry fn, returnType = null, retn; String value; boolean param = false;}
395 value = var2.getText();
396 fn = new Entry(value, new Entry(0));
397 table.put(value, fn);
399 param=parameters[table, fn.table, fn] returnType=return_type[table, fn.table]
401 fn.table.put(fn.table.RTN, returnType);
403 if (!returnType.isNull) {
404 fn.return_variable = returnType;
405 fn.hasReturnType = true;
408 fn.hasReturnType = false;
411 if (value.equals("main") && !param && returnType.isInt) {
415 declarations[table, True] retn=statements[table, fn.table]
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");
421 else if (retn != null && !(fn.hasReturnType)) {
422 fn.printError(fn.stringname + " doesn't return a value");
428 parameters [Records table, Records local, Entry f_entry]
429 returns [boolean rtn = false;]
430 : #(PARAMS (params_decl[table, local]
433 f_entry.hasParams = true;
438 params_decl [Records table, Records local] { Counter i = new Counter(0); }
442 return_type [Records table, Records local] returns [Entry t = null]
443 : #(RETTYPE t=ret_type[table, local])
446 ret_type [Records table, Records local] returns [Entry t = null]
447 : t=datatypes[table, local]
454 statements [Records table, Records local] returns [Entry rtn = null]
455 : #(STMTS (rtn=statement[table, local])*)
458 statement [Records table, Records local] returns [Entry rtn = null]
460 : rtn=block[table, local]
461 | assignment[table, local]
462 | print[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]
471 block [Records table, Records local] returns [Entry rtn = null]
472 : #(BLOCK rtn=statements[table, local])
475 assignment [Records table, Records local]
480 : #(ASSIGN id=lvalue[table, local] e=expression[table, local])
482 id.compareTypes(e, "=");
486 print [Records table, Records local]
490 : #(PRINT e=expression[table, local] (ENDL)?)
493 e.printError("found '" + e.stringname +
494 "', can only print integers");
499 read [Records table, Records local]
503 : #(READ id=lvalue[table, local])
506 id.printError("found '" + id.stringname +
507 "', can only read to an integer");
512 conditional [Records table, Records local] returns [Entry rtn = null]
516 : #(IF e=expression[table, local]
519 e.printError("found '" + e.stringname
520 +"', condifional needs a boolean guard");
524 rtn=block[table, local] (tmp=block[table, local]
533 loop [Records table, Records local] returns [Entry rtn = null]
537 : #(WHILE e=expression[table, local]
540 e.printError("found '" + e.stringname
541 +"', loop needs a boolean guard");
544 rtn=block[table, local])
547 delete [Records table, Records local]
551 : #(DELETE e=expression[table, local])
554 e.printError("cannot free '" + e.stringname + "' b/c it is not a struct");
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"); }
565 invocation [Records table, Records local] returns [Entry rtn = null]
566 { Entry f_entry = null; }
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");
575 arguments[table, local, f_entry])
577 String value = val.getText();
578 rtn = (table.ReturnValue(value, local)).return_variable;
582 lvalue [Records table, Records local] returns [Entry t = null]
588 String value = val0.getText();
589 t = table.ReturnValue(value, local);
591 | #(DOT id=lvalue[table, local] val1:ID)
593 String value = val1.getText();
595 id.printError("can't apply . to '" + id.stringname + "' (not a struct)");
598 t = id.table.ReturnValue(value, null);
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])
607 lft.printError("AND requires boolean types");
609 lft.compareTypes(rht, "AND");
612 | #(OR lft=expression[table, local] rht=expression[table, local])
615 lft.printError("OR requires boolean types");
617 lft.compareTypes(rht, "OR");
620 | #(DIVIDE lft=expression[table, local] rht=expression[table, local])
623 lft.printError("DIVIDE requires int types");
625 lft.compareTypes(rht, "DIVIDE");
628 | #(TIMES lft=expression[table, local] rht=expression[table, local])
631 lft.printError("TIMES requires int types");
633 lft.compareTypes(rht, "TIMES");
636 | #(PLUS lft=expression[table, local] rht=expression[table, local])
639 lft.printError("PLUS requires int types");
641 lft.compareTypes(rht, "PLUS");
644 | #(MINUS lft=expression[table, local] rht=expression[table, local])
647 lft.printError("MINUS requires int types");
649 lft.compareTypes(rht, "MINUS");
652 | #(EQ lft=expression[table, local] rht=expression[table, local])
654 if (!lft.isInt && !lft.isStruct) {
655 lft.printError("EQ requires int or struct types");
657 lft.compareTypes(rht, "EQ");
660 | #(LT lft=expression[table, local] rht=expression[table, local])
663 lft.printError("LT requires int types");
665 lft.compareTypes(rht, "LT");
668 | #(GT lft=expression[table, local] rht=expression[table, local])
671 lft.printError("GT requires int types");
673 lft.compareTypes(rht, "GT");
676 | #(NE lft=expression[table, local] rht=expression[table, local])
678 if (!lft.isInt && !lft.isStruct) {
679 lft.printError("NE requires int or struct types");
681 lft.compareTypes(rht, "NE");
684 | #(LE lft=expression[table, local] rht=expression[table, local])
687 lft.printError("LE requires int types");
689 lft.compareTypes(rht, "LE");
692 | #(GE lft=expression[table, local] rht=expression[table, local])
695 lft.printError("GE requires int types");
697 lft.compareTypes(rht, "GE");
700 | #(NOT lft=expression[table, local])
706 lft.printError("can't apply NOT to '" + lft.stringname + "'");
709 | #(NEG lft=expression[table, local])
715 lft.printError("can't apply NEG to '" + lft.stringname + "'");
720 String value = val0.getText();
721 lft = table.ReturnValue(value, local);
724 t = new Entry(value);
727 lft.printError("can't apply NEW to '" + lft.stringname + "'");
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");
738 t = f_entry.return_variable;
740 (arguments[table, local, f_entry])?)
741 | #(DOT lft=expression[table, local] val5:ID)
743 String value = val5.getText();
745 lft.printError("can't apply . to '" + lft.stringname + "'(not a struct)");
748 t = table.ReturnValue(value, local, lft.table);
752 String value = val1.getText();
754 t = table.ReturnValue(value, local);
758 int value = (int)Integer.parseInt(val2.getText());
759 t = new Entry(value);
763 boolean value = (boolean)Boolean.getBoolean(val3.getText());
764 t = new Entry(value);
768 t = new Entry(false);
776 arguments [Records table, Records local, Entry f_entry]
778 Entry e, actual; int count = 0; boolean f_params = false;
780 : #(ARGS ((e=expression[table, local]
782 actual = (Entry)table.ReturnValue("" + count, f_entry.table);
783 actual.compareTypes(e, "argument");
788 if (!(f_entry.hasParams)) {
789 f_entry.printError(f_entry.stringname + " doesn't require params");
795 if ((f_entry.hasParams) && !f_params) {
796 f_entry.printError(f_entry.stringname + " requires arguments");
798 else if (f_params && f_entry.table.containsKey("" + count)) {
799 f_entry.printError(f_entry.stringname + " requires more arguments");