├── README.md ├── codegen ├── README.md └── src │ ├── java │ ├── Makefile │ ├── codegen │ └── cool │ │ ├── AST.java │ │ ├── ClassPlus.java │ │ ├── ClassTable.java │ │ ├── Codegen.java │ │ ├── CodegenTest.java │ │ ├── Constants.java │ │ ├── CoolLexer.java │ │ ├── CoolParser.java │ │ ├── CoolParserBaseVisitor.java │ │ ├── CoolParserVisitor.java │ │ ├── Error.java │ │ ├── IRClassPlus.java │ │ ├── IRClassTable.java │ │ ├── Makefile │ │ ├── ScopeTable.java │ │ ├── Semantic.java │ │ └── SemanticTest.java │ └── test_cases │ └── helloworld.cl ├── lexer ├── Makefile ├── README.md └── src │ ├── grammar │ ├── CoolLexer.g4 │ ├── Makefile │ └── lexer │ ├── java │ ├── Makefile │ ├── cool │ │ ├── CoolLexer.java │ │ ├── CoolLexer.tokens │ │ └── LexerTest.java │ └── lexer │ └── test_cases │ ├── check.cl │ ├── fact.cl │ ├── fib.cl │ ├── helloworld.cl │ ├── isprime.cl │ ├── isprime.cl~ │ ├── palin.cl │ ├── prod.cl │ ├── test1.cl │ ├── test2.cl │ ├── test3.cl │ ├── test4.cl │ ├── test5.txt │ └── text.txt ├── parser ├── Makefile ├── README.md └── src │ ├── grammar │ ├── CoolParser.g4 │ └── Makefile │ ├── java │ ├── Makefile │ ├── cool │ │ ├── AST.java │ │ ├── CoolLexer.java │ │ ├── CoolLexer.tokens │ │ ├── CoolParser.java │ │ ├── CoolParser.tokens │ │ ├── CoolParserBaseVisitor.java │ │ ├── CoolParserVisitor.java │ │ └── ParserTest.java │ ├── lexer │ └── parser │ └── test_cases │ ├── atoi.cl │ ├── err2.cl │ ├── fib.cl │ ├── fib.s │ ├── isprime.cl │ ├── print-cool.cl │ └── prod.cl └── semantic ├── Makefile ├── README.md └── src ├── java ├── Makefile ├── cool │ ├── AST.java │ ├── ClassPlus.java │ ├── ClassTable.java │ ├── CoolLexer.java │ ├── CoolParser.java │ ├── CoolParserBaseVisitor.java │ ├── CoolParserVisitor.java │ ├── Error.java │ ├── Makefile │ ├── ScopeTable.java │ ├── Semantic.java │ └── SemanticTest.java └── semantic └── test_cases ├── bad.cl ├── bad_hierarchy.cl ├── case_check.cl ├── fib.cl ├── prod.cl └── testing.cl ├── good.cl ├── atoi.cl ├── helloworld.cl ├── list.cl ├── primes.cl └── sort-list.cl └── helloworld.cl /README.md: -------------------------------------------------------------------------------- 1 | ### COOL Compiler 2 | 3 | This repository contains a compiler for COOL (Classroom Object Oriented Language). This was done as a part of IIT Hyderabad's CS3020: Introduction to Compilers course. 4 | 5 | The lexer and parser use ANTLRv4. Please follow the quickstart guide [here](http://www.antlr.org/). 6 | 7 | The code generator generates LLVM IR from COOL code. Learn more about LLVM at [http://llvm.org/](http://llvm.org/). 8 | 9 | 10 | All of the code uses JAVA. The code has been compiled using Oracle Java SE Development Kit 8u73. 11 | -------------------------------------------------------------------------------- /codegen/README.md: -------------------------------------------------------------------------------- 1 | CS3020: Compilers 2 | ================= 3 | 4 | Code Generator Alligator! 5 | ------------------------- 6 | 7 | We have introduced two extra classes: 8 | - IRClassTable 9 | - IRClassPlus 10 | 11 | The IRClassTable stores the table of classes. Each of the entries in this table 12 | is an entry of the IRClassPlus class. The IRClassPlus objects have the 13 | following useful information required for generating code: 14 | 15 | - List of attributes (in order of declaration) 16 | - List of methods (in order of declaration in the virtual table) 17 | - Methods (inherited + within the class) 18 | - Attributes (inherited + within the class) 19 | - Offset of methods in class virtual table 20 | - Offset of objects in class virtual table 21 | - Intermediate Representation name for the method names 22 | 23 | 24 | 25 | Design Decisions : 26 | ================== 27 | 28 | A lot of the boilerplate code has been added as constants. This is because the methods associated with the 29 | base classes are interfaces for system calls (like `abort()` for `exit()`, or `out_string()` for `printf("%s", ...)`) 30 | 31 | This code is added in the initialization phase. This also includes getting the inheritance graph. 32 | 33 | {i32, i8*, baseClass} 34 | 35 | The `i32` stores the class associated integer (from classGraph). 36 | The `i8*` stores pointer to the virtual table. 37 | 38 | ### Designing Class Structure 39 | 40 | Each of the classes is declared twice in the LLVM IR : once as a `%class.ClassName.Base` and once as `%class.ClassName`. 41 | This is done to simplify the inheritance. Each class has a different virtual table. So, a child class inherits only data members of its parent class. So for the purposes of inheritance, the child class has a struct member of the parent base class and not the actual parent class. 42 | 43 | Access to the base class attributes are done via this struct member. Additionally, this member is at 0 offset in the class type declaration. 44 | 45 | ### Designing and Inheriting Virtual Table 46 | 47 | The virual table is absolutely essential. One of the use cases of the virtual tables is illustrated below: 48 | 49 | class A { 50 | // some attributes 51 | f() : Int { 52 | 1 53 | }; 54 | }; 55 | 56 | class B : inherits A { 57 | // some attributes 58 | f() : Int { 59 | 2 60 | }; 61 | }; 62 | 63 | class C { 64 | 65 | func(x : A) : Int{ 66 | // some procedure 67 | x.f() 68 | }; 69 | }; 70 | 71 | 72 | Now, the `func` method in class C takes an object of class A. It could just as well take any other object of a class that conforms to class A. Thus, an object of class B can also be taken. This is one situation where a virtual table comes very handy. Here, the static type of the of the variable x is A. But, if we pass an object of type B, then we should not encounter an error. 73 | 74 | So, how do we handle this situation? Virtual tables come to rescue! 75 | 76 | Basically, the functions within a class are stored in a virtual table associated with the class. The virtual table stores pointers to the functions and not the functions themselves. 77 | 78 | So, in this example, whenever we invoke the function `f()` on the object, it looks for the function pointer at a fixed offset in the virtual table, say offset 3. Thus, we need to make sure that the overriden function in the child class is placed at the same offset in the child classes virtual table. 79 | 80 | 81 | Thus, to implement this scheme, we initialize the virtual table of the `Object` and other basic classes manually. Then, the virtual table of all the derived classes is inherited from the base class. Whenever a method of the base class is overriden, we change the function pointed to in the corresponding virtual table entry of the derived class. Elsewise, we append the new function pointer to the end of the virtual table. 82 | 83 | 84 | -------------------------------------------------------------------------------- /codegen/src/java/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | make -C cool/ 3 | clean: 4 | make -C cool/ clean 5 | -------------------------------------------------------------------------------- /codegen/src/java/codegen: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | java -cp ${CLASSPATH}../java cool.CodegenTest $1 3 | -------------------------------------------------------------------------------- /codegen/src/java/cool/AST.java: -------------------------------------------------------------------------------- 1 | package cool; 2 | import java.util.List; 3 | public class AST{ 4 | public static class ASTNode { 5 | int lineNo; 6 | } 7 | public static String sp = " "; 8 | 9 | static String escapeSpecialCharacters(String text) { 10 | return 11 | text 12 | .replaceAll("\\\\", "\\\\\\\\") 13 | .replaceAll("\n", "\\\\n") 14 | .replaceAll("\t", "\\\\t") 15 | .replaceAll("\b", "\\\\b") 16 | .replaceAll("\f", "\\\\f") 17 | .replaceAll("\"", "\\\\\"") 18 | .replaceAll("\r", "\\\\015") 19 | .replaceAll("\033","\\\\033") 20 | .replaceAll("\001","\\\\001") 21 | .replaceAll("\002","\\\\002") 22 | .replaceAll("\003","\\\\003") 23 | .replaceAll("\004","\\\\004") 24 | .replaceAll("\022","\\\\022") 25 | .replaceAll("\013","\\\\013") 26 | .replaceAll("\000", "\\\\000") 27 | ; 28 | } 29 | 30 | 31 | public static class expression extends ASTNode { 32 | String type; 33 | public expression(){ 34 | type = "_no_type"; 35 | } 36 | String getString(String space){ 37 | return ""; 38 | }; 39 | } 40 | public static class no_expr extends expression { 41 | public no_expr(int l){ 42 | lineNo = l; 43 | } 44 | String getString(String space){ 45 | return space+"#"+lineNo+"\n"+space+"_no_expr\n"+space+": "+type; 46 | } 47 | } 48 | public static class bool_const extends expression{ 49 | public boolean value; 50 | public bool_const(boolean v, int l){ 51 | value = v; 52 | lineNo = l; 53 | } 54 | String getString(String space){ 55 | return space+"#"+lineNo+"\n"+space+"_bool\n"+space+sp+(value?"1":"0")+"\n"+space+": "+type; 56 | } 57 | } 58 | public static class string_const extends expression{ 59 | public String value; 60 | public string_const(String v, int l){ 61 | value = v; 62 | lineNo = l; 63 | } 64 | String getString(String space){ 65 | return space+"#"+lineNo+"\n"+space+"_string\n"+space+sp+"\""+escapeSpecialCharacters(value)+"\""+"\n"+space+": "+type; 66 | } 67 | } 68 | 69 | public static class int_const extends expression{ 70 | public int value; 71 | public int_const(int v, int l){ 72 | value = v; 73 | lineNo = l; 74 | } 75 | String getString(String space){ 76 | return space+"#"+lineNo+"\n"+space+"_int\n"+space+sp+value+"\n"+space+": "+type; 77 | } 78 | } 79 | 80 | public static class object extends expression{ 81 | public String name; 82 | public object(String v, int l){ 83 | name = v; 84 | lineNo = l; 85 | } 86 | String getString(String space){ 87 | return space+"#"+lineNo+"\n"+space+"_object\n"+space+sp+name+"\n"+space+": "+type; 88 | } 89 | } 90 | public static class comp extends expression{ 91 | public expression e1; 92 | public comp(expression v, int l){ 93 | e1 = v; 94 | lineNo = l; 95 | } 96 | String getString(String space){ 97 | return space+"#"+lineNo+"\n"+space+"_comp\n"+e1.getString(space+sp)+"\n"+space+": "+type; 98 | } 99 | } 100 | public static class eq extends expression{ 101 | public expression e1; 102 | public expression e2; 103 | public eq(expression v1, expression v2, int l){ 104 | e1=v1; 105 | e2=v2; 106 | lineNo = l; 107 | } 108 | String getString(String space){ 109 | return space+"#"+lineNo+"\n"+space+"_eq\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 110 | } 111 | } 112 | 113 | 114 | public static class leq extends expression{ 115 | public expression e1; 116 | public expression e2; 117 | public leq(expression v1, expression v2, int l){ 118 | e1 = v1; 119 | e2 = v2; 120 | lineNo = l; 121 | } 122 | String getString(String space){ 123 | return space+"#"+lineNo+"\n"+space+"_leq\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 124 | } 125 | } 126 | 127 | public static class lt extends expression{ 128 | public expression e1; 129 | public expression e2; 130 | public lt(expression v1, expression v2, int l){ 131 | e1 = v1; 132 | e2 = v2; 133 | lineNo = l; 134 | } 135 | String getString(String space){ 136 | return space+"#"+lineNo+"\n"+space+"_lt\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 137 | } 138 | } 139 | public static class neg extends expression{ 140 | public expression e1; 141 | public neg(expression v, int l){ 142 | e1 = v; 143 | lineNo = l; 144 | } 145 | String getString(String space){ 146 | return space+"#"+lineNo+"\n"+space+"_neg\n"+e1.getString(space+sp)+"\n"+space+": "+type; 147 | } 148 | } 149 | public static class divide extends expression{ 150 | public expression e1; 151 | public expression e2; 152 | public divide(expression v1, expression v2, int l){ 153 | e1 = v1; 154 | e2 = v2; 155 | lineNo = l; 156 | } 157 | String getString(String space){ 158 | return space+"#"+lineNo+"\n"+space+"_divide\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 159 | } 160 | } 161 | public static class mul extends expression{ 162 | public expression e1; 163 | public expression e2; 164 | public mul(expression v1, expression v2, int l){ 165 | e1 = v1; 166 | e2 = v2; 167 | lineNo = l; 168 | } 169 | String getString(String space){ 170 | return space+"#"+lineNo+"\n"+space+"_mul\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 171 | } 172 | } 173 | public static class sub extends expression{ 174 | public expression e1; 175 | public expression e2; 176 | public sub(expression v1, expression v2, int l){ 177 | e1 = v1; 178 | e2 = v2; 179 | lineNo = l; 180 | } 181 | String getString(String space){ 182 | return space+"#"+lineNo+"\n"+space+"_sub\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 183 | } 184 | } 185 | public static class plus extends expression{ 186 | public expression e1; 187 | public expression e2; 188 | public plus(expression v1, expression v2, int l){ 189 | e1 = v1; 190 | e2 = v2; 191 | lineNo = l; 192 | } 193 | String getString(String space){ 194 | return space+"#"+lineNo+"\n"+space+"_plus\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 195 | } 196 | } 197 | public static class isvoid extends expression{ 198 | public expression e1; 199 | public isvoid(expression v, int l){ 200 | e1 = v; 201 | lineNo = l; 202 | } 203 | String getString(String space){ 204 | return space+"#"+lineNo+"\n"+space+"_isvoid\n"+e1.getString(space+sp)+"\n"+space+": "+type; 205 | } 206 | } 207 | public static class new_ extends expression{ 208 | public String typeid; 209 | public new_(String t, int l){ 210 | typeid = t; 211 | lineNo = l; 212 | } 213 | String getString(String space){ 214 | return space+"#"+lineNo+"\n"+space+"_new\n"+space+sp+typeid+"\n"+space+": "+type; 215 | } 216 | } 217 | public static class assign extends expression{ 218 | public String name; 219 | public expression e1; 220 | public assign(String n, expression v1, int l){ 221 | name = n; 222 | e1 = v1; 223 | lineNo = l; 224 | } 225 | String getString(String space){ 226 | return space+"#"+lineNo+"\n"+space+"_assign\n"+space+sp+name+"\n"+e1.getString(space+sp)+"\n"+space+": "+type; 227 | } 228 | } 229 | public static class block extends expression{ 230 | public List l1; 231 | public block(List v1, int l){ 232 | l1 = v1; 233 | lineNo = l; 234 | } 235 | String getString(String space){ 236 | String str = space+"#"+lineNo+"\n"+space+"_block\n"; 237 | for (expression e1 : l1){ 238 | str += e1.getString(space+sp)+"\n"; 239 | } 240 | str+=space+": "+type; 241 | return str; 242 | } 243 | } 244 | public static class loop extends expression{ 245 | public expression predicate; 246 | public expression body; 247 | public loop(expression v1, expression v2, int l){ 248 | predicate = v1; 249 | body = v2; 250 | lineNo = l; 251 | } 252 | String getString(String space){ 253 | return space+"#"+lineNo+"\n"+space+"_loop\n"+predicate.getString(space+sp)+"\n"+body.getString(space+sp)+"\n"+space+": "+type; 254 | } 255 | } 256 | public static class cond extends expression{ 257 | public expression predicate; 258 | public expression ifbody; 259 | public expression elsebody; 260 | public cond(expression v1, expression v2, expression v3, int l){ 261 | predicate = v1; 262 | ifbody = v2; 263 | elsebody = v3; 264 | lineNo = l; 265 | } 266 | String getString(String space){ 267 | return space+"#"+lineNo+"\n"+space+"_cond\n"+predicate.getString(space+sp)+"\n"+ifbody.getString(space+sp)+"\n"+elsebody.getString(space+sp)+"\n"+space+": "+type; 268 | } 269 | } 270 | public static class let extends expression{ 271 | public String name; 272 | public String typeid; 273 | public expression value; 274 | public expression body; 275 | public let(String n, String t, expression v, expression b, int l){ 276 | name = n; 277 | typeid = t; 278 | value = v; 279 | body = b; 280 | lineNo = l; 281 | } 282 | String getString(String space){ 283 | return space+"#"+lineNo+"\n"+space+"_let\n"+space+sp+name+"\n"+space+sp+typeid+"\n"+value.getString(space+sp)+"\n"+body.getString(space+sp)+"\n"+space+": "+type; 284 | } 285 | } 286 | public static class dispatch extends expression{ 287 | public expression caller; 288 | public String name; 289 | public List actuals; 290 | public dispatch(expression v1, String n, List a, int l){ 291 | caller = v1; 292 | name = n; 293 | actuals = a; 294 | lineNo = l; 295 | } 296 | String getString(String space){ 297 | String str; 298 | str = space+"#"+lineNo+"\n"+space+"_dispatch\n"+caller.getString(space+sp)+"\n"+space+sp+name+"\n"+space+sp+"(\n"; 299 | for ( expression e1 : actuals ) { 300 | str += e1.getString(space+sp)+"\n"; 301 | } 302 | str+=space+sp+")\n"+space+": "+type; 303 | return str; 304 | } 305 | } 306 | public static class static_dispatch extends expression{ 307 | public expression caller; 308 | public String typeid; 309 | public String name; 310 | public List actuals; 311 | public static_dispatch(expression v1, String t, String n, List a, int l){ 312 | caller = v1; 313 | typeid = t; 314 | name = n; 315 | actuals = a; 316 | lineNo = l; 317 | } 318 | String getString(String space){ 319 | String str; 320 | str = space+"#"+lineNo+"\n"+space+"_static_dispatch\n"+caller.getString(space+sp)+"\n"+space+sp+typeid+"\n"+space+sp+name+"\n"+space+sp+"(\n"; 321 | for ( expression e1 : actuals ) { 322 | str += e1.getString(space+sp)+"\n"; 323 | } 324 | str+=space+sp+")\n"+space+": "+type; 325 | return str; 326 | } 327 | } 328 | public static class typcase extends expression{ 329 | public expression predicate; 330 | public List branches; 331 | public typcase(expression p, List b, int l){ 332 | predicate = p; 333 | branches = b; 334 | lineNo = l; 335 | } 336 | String getString(String space){ 337 | String str = space+"#"+lineNo+"\n"+space+"_typcase\n"+predicate.getString(space+sp)+"\n"; 338 | for ( branch b1 : branches ) { 339 | str += b1.getString(space+sp)+"\n"; 340 | } 341 | str += space+": "+type; 342 | return str; 343 | } 344 | } 345 | public static class branch extends ASTNode { 346 | public String name; 347 | public String type; 348 | public expression value; 349 | public branch(String n, String t, expression v, int l){ 350 | name = n; 351 | type = t; 352 | value = v; 353 | lineNo = l; 354 | } 355 | String getString(String space){ 356 | return space+"#"+lineNo+"\n"+space+"_branch\n"+space+sp+name+"\n"+space+sp+type+"\n"+value.getString(space+sp); 357 | } 358 | } 359 | public static class formal extends ASTNode { 360 | public String name; 361 | public String typeid; 362 | public formal(String n, String t, int l){ 363 | name = n; 364 | typeid = t; 365 | lineNo = l; 366 | } 367 | String getString(String space){ 368 | return space+"#"+lineNo+"\n"+space+"_formal\n"+space+sp+name+"\n"+space+sp+typeid; 369 | } 370 | } 371 | public static class feature extends ASTNode { 372 | public feature(){ 373 | } 374 | String getString(String space){ 375 | return ""; 376 | } 377 | 378 | } 379 | public static class method extends feature { 380 | public String name; 381 | public List formals; 382 | public String typeid; 383 | public expression body; 384 | public method(String n, List f, String t, expression b, int l){ 385 | name = n; 386 | formals = f; 387 | typeid = t; 388 | body = b; 389 | lineNo = l; 390 | } 391 | String getString(String space){ 392 | String str = space+"#"+lineNo+"\n"+space+"_method\n"+space+sp+name+"\n"; 393 | for ( formal f : formals ) { 394 | str += f.getString(space+sp)+"\n"; 395 | } 396 | str += space+sp+typeid+"\n"+body.getString(space+sp); 397 | return str; 398 | } 399 | } 400 | public static class attr extends feature { 401 | public String name; 402 | public String typeid; 403 | public expression value; 404 | public attr(String n, String t, expression v, int l){ 405 | name = n; 406 | typeid = t; 407 | value = v; 408 | lineNo = l; 409 | } 410 | String getString(String space){ 411 | return space+"#"+lineNo+"\n"+space+"_attr\n"+space+sp+name+"\n"+space+sp+typeid+"\n"+value.getString(space+sp); 412 | } 413 | } 414 | public static class class_ extends ASTNode { 415 | public String name; 416 | public String filename; 417 | public String parent; 418 | public List features; 419 | public class_(String n, String f, String p, List fs, int l){ 420 | name = n; 421 | filename = f; 422 | parent = p; 423 | features = fs; 424 | lineNo = l; 425 | } 426 | String getString(String space){ 427 | String str; 428 | str = space+"#"+lineNo+"\n"+space+"_class\n"+space+sp+name+"\n"+space+sp+parent+"\n"+space+sp+"\""+filename+"\""+"\n"+space+sp+"(\n"; 429 | for ( feature f : features ) { 430 | str += f.getString(space+sp)+"\n"; 431 | } 432 | str += space+sp+")"; 433 | return str; 434 | } 435 | } 436 | public static class program extends ASTNode { 437 | public List classes; 438 | public program(List c, int l){ 439 | classes = c; 440 | lineNo = l; 441 | } 442 | String getString(String space){ 443 | String str; 444 | str = space+"#"+lineNo+"\n"+space+"_program"; 445 | for ( class_ c : classes ) { 446 | str += "\n"+c.getString(space+sp); 447 | } 448 | 449 | return str; 450 | } 451 | } 452 | } 453 | -------------------------------------------------------------------------------- /codegen/src/java/cool/ClassPlus.java: -------------------------------------------------------------------------------- 1 | package cool; 2 | import java.util.HashMap; 3 | 4 | public class ClassPlus { 5 | public String name; 6 | public String parent = null; 7 | public HashMap alist; 8 | public HashMap mlist; 9 | 10 | ClassPlus(String nm, String pr, HashMap al, HashMap ml) { 11 | name = new String(nm); 12 | if(pr != null) parent = new String(pr); 13 | alist = new HashMap (); 14 | alist.putAll(al); 15 | mlist = new HashMap (); 16 | mlist.putAll(ml); 17 | } 18 | } -------------------------------------------------------------------------------- /codegen/src/java/cool/ClassTable.java: -------------------------------------------------------------------------------- 1 | package cool; 2 | import java.util.*; 3 | import java.util.Map.Entry; 4 | 5 | 6 | 7 | 8 | public class ClassTable { 9 | private HashMap classes=new HashMap(); // for retrieving class related info and class attributes and features 10 | private HashMap height = new HashMap(); // for retrieving class height in the inheritance hierarchy (for conformance check) 11 | public List errors = new ArrayList(); 12 | 13 | public ClassTable() { 14 | /* Classes already present in the table: 15 | * - Object 16 | * - IO 17 | * - String 18 | * - Int 19 | * - Bool 20 | * 21 | * Object has methods: 22 | * - abort() : Object 23 | * - type_name(): String 24 | * IO has methods: 25 | * - out_string(x : String) : IO 26 | * - out_int(x : Int) : IO 27 | * - in_string() : String 28 | * - in_int() : String 29 | * String has methods: 30 | * - length() : Int 31 | * - concat(s: String) : String 32 | * - substr(i : Int, l : Int) : String 33 | */ 34 | 35 | HashMap ol = new HashMap (); 36 | ol.put("abort", new AST.method("abort", new ArrayList(), "Object", new AST.no_expr(0), 0)); 37 | ol.put("type_name", new AST.method("type_name", new ArrayList(), "String", new AST.no_expr(0), 0)); 38 | 39 | classes.put("Object", new ClassPlus("Object", null, new HashMap(), ol)); 40 | height.put("Object", 0); 41 | 42 | HashMap iol = new HashMap(); 43 | 44 | List os_formals = new ArrayList(); 45 | os_formals.add(new AST.formal("out_string", "String", 0)); 46 | List oi_formals = new ArrayList(); 47 | oi_formals.add(new AST.formal("out_int", "Int", 0)); 48 | 49 | iol.put("out_string", new AST.method("out_string", os_formals, "IO", new AST.no_expr(0), 0)); 50 | iol.put("out_int", new AST.method("out_int", oi_formals, "IO", new AST.no_expr(0), 0)); 51 | iol.put("in_string", new AST.method("in_string", new ArrayList(), "String", new AST.no_expr(0), 0)); 52 | iol.put("in_int", new AST.method("in_int", new ArrayList(), "Int", new AST.no_expr(0), 0)); 53 | classes.put("IO", new ClassPlus("IO", "Object", new HashMap(), iol)); 54 | classes.get("IO").mlist.putAll(ol); // IO inherits from Object 55 | height.put("IO", 1); 56 | 57 | classes.put("Int", new ClassPlus("Int", "Object", new HashMap(), new HashMap())); 58 | height.put("Int", 1); 59 | classes.get("Int").mlist.putAll(ol); // Int inherits from Object 60 | 61 | classes.put("Bool", new ClassPlus("Bool", "Object", new HashMap(), new HashMap())); 62 | height.put("Bool", 1); 63 | classes.get("Bool").mlist.putAll(ol); // Bool inherits from Object 64 | 65 | HashMap sl = new HashMap(); 66 | List concat_formal = new ArrayList(); 67 | concat_formal.add(new AST.formal("s", "String", 0)); 68 | List substr_formal = new ArrayList(); 69 | substr_formal.add(new AST.formal("i", "Int", 0)); 70 | substr_formal.add(new AST.formal("l", "Int", 0)); 71 | 72 | sl.put("length", new AST.method("length", new ArrayList(), "Int", new AST.no_expr(0), 0)); 73 | sl.put("concat", new AST.method("concat", concat_formal, "String", new AST.no_expr(0), 0)); 74 | sl.put("substr", new AST.method("substr", substr_formal, "String", new AST.no_expr(0), 0)); 75 | 76 | classes.put("String", new ClassPlus("String", "Object", new HashMap(), sl)); 77 | height.put("String", 1); 78 | classes.get("String").mlist.putAll(ol); // String Inherits from Object 79 | } 80 | void insert(AST.class_ c) { 81 | /* Whenever a new class is inserted, 82 | * - Inherits the attributes and methods of the parent class. 83 | * - Checks for multiple method or attribute definitions. 84 | * - Checks for correct method overrides and any attribute overrides 85 | */ 86 | String pr = c.parent; 87 | ClassPlus tc = new ClassPlus(c.name, c.parent, classes.get(c.parent).alist, classes.get(c.parent).mlist); // adding the parents attribute list and method list 88 | 89 | 90 | HashMap tc_alist = new HashMap(); 91 | HashMap tc_mlist = new HashMap (); 92 | 93 | /* Checks for the following errors within a class: 94 | * - multiple attribute definitions 95 | * - multiple method definitions 96 | */ 97 | for(AST.feature e : c.features) { 98 | if(e.getClass() == AST.attr.class) { 99 | AST.attr ae = (AST.attr) e; 100 | if(tc_alist.containsKey(ae.name)) 101 | errors.add(new Error(c.filename, ae.lineNo, "Attribute " + ae.name + " is multiply defined in class.")); 102 | else 103 | tc_alist.put(ae.name, ae); 104 | } 105 | else if(e.getClass() == AST.method.class) { 106 | AST.method me = (AST.method) e; 107 | if(tc_mlist.containsKey(me.name)) 108 | errors.add(new Error(c.filename, me.lineNo, "Method " + me.name + " is multiply defined.")); 109 | else 110 | tc_mlist.put(me.name, me); 111 | } 112 | } 113 | 114 | 115 | /* Checks for the following errors with respect to the inherited class: 116 | * - redefinition of an inherited attribute (Note: the class retains the inherited attribute and discards the attribute defined within the class) 117 | * - wrong redefinition of an inherited method (Note : the class retains the inherited method and discards the method defined within the class) 118 | */ 119 | for(Entry entry : tc_alist.entrySet()) { 120 | if(tc.alist.containsKey(entry.getKey())) 121 | errors.add(new Error(c.filename, entry.getValue().lineNo, "Attribute " + entry.getValue().name + " is an attribute of an inherited class")); 122 | else { 123 | tc.alist.put(entry.getKey(), entry.getValue()); 124 | } 125 | 126 | } 127 | boolean foundErr; 128 | for(Entry entry : tc_mlist.entrySet()) { 129 | foundErr = false; 130 | if(tc.mlist.containsKey(entry.getKey())) { 131 | AST.method parent_me = tc.mlist.get(entry.getKey()); 132 | AST.method me = entry.getValue(); 133 | if(me.formals.size() != parent_me.formals.size()) { 134 | errors.add(new Error(c.filename, me.lineNo, "Incompatible number of formal parameters in redefined method " + me.name)); 135 | foundErr = true; 136 | } 137 | else { 138 | if(me.typeid.equals(parent_me.typeid) == false) { 139 | errors.add(new Error(c.filename, me.lineNo, "In redefined method " + me.name + ", return type " 140 | + me.typeid + " is different from original return type " + parent_me.typeid)); 141 | foundErr = true; 142 | } 143 | for(int i = 0; i < me.formals.size(); ++i) { 144 | if(me.formals.get(i).typeid.equals(parent_me.formals.get(i).typeid) == false) { 145 | errors.add(new Error(c.filename, me.lineNo, "In redefined method " + me.name + ", parameter type" 146 | + me.formals.get(i).typeid + " is different from original type " + parent_me.formals.get(i).typeid)); 147 | foundErr = true; 148 | } 149 | } 150 | } 151 | } 152 | 153 | if(foundErr != true) 154 | tc.mlist.put(entry.getKey(), entry.getValue()); 155 | } 156 | height.put(c.name, height.get(c.parent) + 1); 157 | 158 | classes.put(c.name, tc); 159 | } 160 | 161 | 162 | List getErrors() { 163 | return errors; 164 | } 165 | 166 | HashMap getAttrs(String className) { 167 | return classes.get(className).alist; 168 | } 169 | 170 | ClassPlus getClassPlus(String className) { 171 | return classes.get(className); 172 | } 173 | 174 | boolean conforms(String a, String b) { 175 | if(a.equals(b)) 176 | return true; 177 | else { 178 | a = classes.get(a).parent; 179 | if(a == null) return false; 180 | else return conforms(a, b); 181 | } 182 | } 183 | 184 | String lca(String a, String b) { 185 | 186 | if(a.equals(b)) return a; 187 | else if(height.get(a) < height.get(b)) // a must always be deeper in the tree 188 | return lca(b, a); 189 | else 190 | return lca(classes.get(a).parent, b); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /codegen/src/java/cool/CodegenTest.java: -------------------------------------------------------------------------------- 1 | package cool; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.PrintWriter; 5 | import java.io.IOException; 6 | import java.util.Arrays; 7 | 8 | import org.antlr.v4.runtime.ANTLRInputStream; 9 | import org.antlr.v4.runtime.CommonTokenStream; 10 | 11 | import org.antlr.v4.runtime.CommonToken; 12 | import org.antlr.v4.runtime.Token; 13 | import org.antlr.v4.runtime.BaseErrorListener; 14 | import org.antlr.v4.runtime.Recognizer; 15 | import org.antlr.v4.runtime.RecognitionException; 16 | import org.antlr.v4.runtime.tree.*; 17 | import java.nio.file.Paths; 18 | 19 | public class CodegenTest { 20 | 21 | static String[] TOKENS = {"ERROR", "TYPEID", "OBJECTID", "BOOL_CONST", "INT_CONST", "STR_CONST", "'('", "')'", "':'", "'@'", "';'", "','", "'+'", "'-'", "'*'", "'/'", "'~'", "'<'", "'='", "'{'", "'}'", "'.'", "DARROW", "LE", "ASSIGN", "CLASS", "ELSE", "FI", "IF", "IN", "INHERITS", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "OF", "NEW", "ISVOID", "NOT" 22 | }; 23 | 24 | static int VALUED_INDEX_LIMIT = 6; 25 | static int NAMED_TOKEN_INDEX = 23; 26 | static int parser_error_flag = 0; 27 | 28 | static String escapeSpecialCharacters(String text) { 29 | return 30 | text 31 | .replaceAll("\\\\", "\\\\\\\\") 32 | .replaceAll("\n", "\\\\n") 33 | .replaceAll("\t", "\\\\t") 34 | .replaceAll("\b", "\\\\b") 35 | .replaceAll("\f", "\\\\f") 36 | .replaceAll("\"", "\\\\\"") 37 | .replaceAll("\r", "\\\\015") 38 | .replaceAll("\033","\\\\033") 39 | .replaceAll("\001","\\\\001") 40 | .replaceAll("\002","\\\\002") 41 | .replaceAll("\003","\\\\003") 42 | .replaceAll("\004","\\\\004") 43 | .replaceAll("\022","\\\\022") 44 | .replaceAll("\013","\\\\013") 45 | .replaceAll("\000", "\\\\000") 46 | ; 47 | } 48 | 49 | static void compile(String filename) throws Exception{ 50 | ANTLRInputStream inStream=null; 51 | try{ 52 | inStream = new ANTLRInputStream(new FileInputStream(filename)); 53 | }catch(Exception e){ 54 | System.err.println("Could not read file "+filename); 55 | return; 56 | } 57 | 58 | CoolLexer lexer = new CoolLexer(inStream); 59 | CommonTokenStream tokens = new CommonTokenStream(lexer); 60 | tokens.fill(); 61 | int lexer_flag = 0; 62 | for(Token t : tokens.getTokens()){ 63 | if ( t.getType() == 1 ){ 64 | lexer_flag = 1; 65 | System.err.println("Lexical error at "+t.getLine()+": "+escapeSpecialCharacters(t.getText())); 66 | } 67 | } 68 | if (lexer_flag == 1) 69 | return; 70 | 71 | String baseFilename = Paths.get(filename).getFileName().toString(); 72 | 73 | parser_error_flag = 0; 74 | CoolParser parser = new CoolParser(tokens); 75 | parser.removeErrorListeners(); 76 | parser.addErrorListener(new ParserError(baseFilename)); 77 | parser.setFilename(baseFilename); 78 | 79 | CoolParser.ProgramContext prog = null; 80 | try{ 81 | prog = parser.program(); 82 | }catch(Exception e){ 83 | // e.printStackTrace(); 84 | } 85 | if(parser_error_flag == 1){ 86 | System.err.println("Compilation halted due to lex and parse errors"); 87 | return; 88 | } 89 | Semantic semanticAnalyzer=new Semantic(prog.value); 90 | if (semanticAnalyzer.getErrorFlag()){ 91 | System.err.println("Compilation halter due to semantic errors."); 92 | return; 93 | } 94 | 95 | String outputFilename = baseFilename.substring(0, baseFilename.lastIndexOf('.')) + ".ll"; 96 | 97 | PrintWriter writer = new PrintWriter(outputFilename); 98 | 99 | Codegen codeGenerator = new Codegen(prog.value, writer); 100 | writer.close(); 101 | } 102 | 103 | public static void main(String args[]) throws Exception{ 104 | 105 | if(args.length < 1) { 106 | System.err.println("No files given"); 107 | System.exit(1); 108 | } 109 | compile(args[0]); 110 | } 111 | 112 | public static class ParserError extends BaseErrorListener { 113 | 114 | String filename; 115 | public ParserError(String fn) { 116 | super(); 117 | filename=fn; 118 | } 119 | @Override 120 | public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionIntLine, String msg, RecognitionException e){ 121 | parser_error_flag=1; 122 | String sourceName = recognizer.getInputStream().getSourceName(); 123 | String errorMessage=""; 124 | if(filename!=null){ 125 | if(offendingSymbol instanceof CommonToken){ 126 | errorMessage += "\""+filename+"\", line "+line+": syntax error at or near "; 127 | int typeid = ((CommonToken)offendingSymbol).getType(); 128 | if (typeid == -1){ 129 | errorMessage += "EOF"; 130 | } 131 | else if (typeid <= VALUED_INDEX_LIMIT) { 132 | errorMessage += TOKENS[typeid-1] + " = " + ((CommonToken)offendingSymbol).getText(); 133 | }else if(typeid >= NAMED_TOKEN_INDEX){ 134 | errorMessage += TOKENS[typeid-1]; 135 | }else{ 136 | errorMessage += "\'"+escapeSpecialCharacters(((CommonToken)offendingSymbol).getText())+"\'"; 137 | } 138 | } 139 | } 140 | System.err.println(errorMessage); 141 | throw new RuntimeException("One error found!"); 142 | } 143 | } 144 | } 145 | 146 | //objectid, typeid, int_const, string_const, bool_const 147 | // static String[] TOKENS = {"ERROR", "TYPEID", "OBJECTID", "BOOL_CONST", "INT_CONST", "STR_CONST", "'('", "')'", "':'", "'@'", "';'", "','", "'+'", "'-'", "'*'", "'/'", "'~'", "'<'", "'='", "'{'", "'}'", "'.'", "DARROW", "LE", "ASSIGN", "CLASS", "ELSE", "FI", "IF", "IN", "INHERITS", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "OF", "NEW", "ISVOID", "NOT" 148 | // }; 149 | -------------------------------------------------------------------------------- /codegen/src/java/cool/Constants.java: -------------------------------------------------------------------------------- 1 | package cool; 2 | 3 | import java.util.Collections; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | public class Constants { 8 | 9 | /* layout specification separated by - 10 | * e: little endian format 11 | * m: mangling i.e. names are mangled in the output 12 | * then alignment for integer type. 13 | * > taken from clang++ output 14 | */ 15 | static final String DATA_LAYOUT = "target datalayout = \"e-m:e-i64:64-f80:128-n8:16:32:64-S128\""; 16 | /* 17 | * target triple specifies target host 18 | */ 19 | static final String TARGET_TRIPLE = "target triple = \"x86_64-unknown-linux-gnu\""; 20 | 21 | static final String CMETHOD_HELPERS = "@strformatstr = private unnamed_addr constant [3 x i8] c\"%s\\00\", align 1\n" 22 | + "@intformatstr = private unnamed_addr constant [3 x i8] c\"%d\\00\", align 1\n"; 23 | 24 | static final String ERRORS = "@Abortdivby0 = private unnamed_addr constant [22 x i8] c\"Error: Division by 0\\0A\\00\", align 1\n" 25 | + "@Abortdispvoid = private unnamed_addr constant [25 x i8] c\"Error: Dispatch on void\\0A\\00\", align 1\n"; 26 | 27 | static final String CMETHODS = "declare i32 @printf(i8*, ...)\n" 28 | + "declare i32 @scanf(i8*, ...)\n" 29 | + "declare i32 @strcmp(i8*, i8*)\n" 30 | + "declare i8* @strcat(i8*, i8*)\n" 31 | + "declare i8* @strcpy(i8*, i8*)\n" 32 | + "declare i8* @strncpy(i8*, i8*, i32)\n" 33 | + "declare i64 @strlen(i8*)\n" 34 | + "declare i8* @malloc(i64)\n" 35 | + "declare void @exit(i32)"; 36 | 37 | public static final Map FC_TYPES = Collections.unmodifiableMap( /* First Class */ 38 | new HashMap() {{ 39 | put("Int", "i32"); 40 | put("Bool", "i32"); 41 | put("String", "[1024 x i8]*"); 42 | }}); 43 | 44 | static final String OBJECT_ABORT = "define %classObject* @_ZN6Object5abort( %class.Object* %this ) noreturn {\n" 45 | + "entry:\n" 46 | + "call void @exit( i32 1 )\n" 47 | + "ret %classObject* null\n" 48 | + "}\n"; 49 | 50 | static final String STRING_COPY = "define [1024 x i8]* @_ZN6String4copy( [1024 x i8]* %this ) {\n" 51 | + "entry:\n" 52 | + "%0 = call i8* @malloc( i64 1024 )\n" 53 | + "%retval = bitcast i8* %0 to [1024 x i8]*\n" 54 | + "%1 = bitcast [1024 x i8]* %this to i8*\n" 55 | + "%2 = bitcast [1024 x i8]* %retval to i8*\n" 56 | + "%3 = call i8* @strcpy( i8* %2, i8* %1)\n" 57 | + "ret [1024 x i8]* %retval\n" 58 | + "}\n"; 59 | 60 | static final String OBJECT_TYPENAME = "define [1024 x i8]* @_ZN6Object9type_name( %class.Object* %this ) {\n" 61 | + "entry:\n" 62 | + "%0 = getelementptr inbounds %classObject, %classObject* %this, i32 0, i32 0\n" 63 | + "%1 = load i32, i32* %0\n" 64 | + "%2 = getelementptr inbounds [8 x [1024 x i8]], [8 x [1024 x i8]]* @classnames, i32 0, i32 %1\n" 65 | + "%retval = call [1024 x i8]* @_ZN6String4copy( [1024 x i8]* %2 )\n" 66 | + "ret [1024 x i8]* %retval\n" 67 | + "}\n"; 68 | 69 | static final String STRING_CONCAT = "define [1024 x i8]* @_ZN6String6concat( [1024 x i8]* %this, [1024 x i8]* %that ) {\n" 70 | + "entry:\n" 71 | + "%retval = call [1024 x i8]* @_ZN6String4copy( [1024 x i8]* %this )\n" 72 | + "%0 = bitcast [1024 x i8]* %retval to i8*\n" 73 | + "%1 = bitcast [1024 x i8]* %that to i8*\n" 74 | + "%2 = call i8* @strcat( i8* %0, i8* %1 )\n" 75 | + "ret [1024 x i8]* %retval\n" 76 | + "}\n"; 77 | 78 | static final String STRING_LENGTH = "define i32 @_ZN6String6length( [1024 x i8]* %this ) {\n" 79 | + "entry:\n" 80 | + "%0 = bitcast [1024 x i8]* %this to i8*\n" 81 | + "%1 = call i64 @strlen( i8* %0 )\n" 82 | + "%retval = trunc i64 %1 to i32\n" 83 | + "ret i32 %retval\n" 84 | + "}\n"; 85 | 86 | static final String STRING_SUBSTR = "define [1024 x i8]* @_ZN6String6substr( [1024 x i8]* %this, i32 %start, i32 %len ) {\n" 87 | + "entry:\n" 88 | + "%0 = getelementptr inbounds [1024 x i8], [1024 x i8]* %this, i32 0, i32 %start\n" 89 | + "%1 = call i8* @malloc( i64 1024 )\n" 90 | + "%retval = bitcast i8* %1 to [1024 x i8]*\n" 91 | + "%2 = bitcast [1024 x i8]* %retval to i8*\n" 92 | + "%3 = call i8* @strncpy( i8* %2, i8* %0, i32 %len )\n" 93 | + "%4 = getelementptr inbounds [1024 x i8], [1024 x i8]* %retval, i32 0, i32 %len\n" 94 | + "store i8 0, i8* %4\n" 95 | + "ret [1024 x i8]* %retval\n" 96 | + "}\n"; 97 | 98 | static final String OBJECT_COPY = "define %classObject* @_ZN6Object4copy( %class.Object* %this ) {\n" 99 | + "entry:\n" 100 | + "%call = call i8* @malloc( i64 32 )\n" 101 | + "%retval = bitcast i8* %call to %classObject*\n" 102 | + "%0 = getelementptr inbounds %classObject, %classObject* %retval, i32 0, i32 0\n" 103 | + "store i32 0, i32* %0\n" 104 | + "%1 = getelementptr inbounds %classObject, %classObject* %retval, i32 0, i32 1\n" 105 | + "store i8* bitcast ( [3 x i8*]* @VTObject to i8*), i8** %1\n" 106 | + "%2 = getelementptr inbounds %classObject, %classObject* %retval, i32 0, i32 2\n" 107 | + "%3 = getelementptr inbounds %classObject, %classObject* %this, i32 0, i32 2\n" 108 | + "call void @_ZN6Object4copyTo( %classbaseObject* %2, %classbaseObject* %3 )\n" 109 | + "ret %classObject* %retval\n" 110 | + "}\n"; 111 | 112 | static final String OBJECT_MEMCPY = "define %classObject* @_ZN6Object4copyTo( %class.Object* %dst, %class.Object* %src ) \n" 113 | + "entry:\n" 114 | + "ret void\n" 115 | + "}\n"; 116 | 117 | static final String IO_OUTSTRING = "define %classIO* @_ZN2IO10out_string( %class.IO* %this, [1024 x i8]* %str ) {\n" 118 | + "entry:\n" 119 | + "%0 = call i32 (i8*, ...) @printf( i8* bitcast ( [3 x i8]* @strformatstr to i8* ), [1024 x i8]* %str )\n" 120 | + "ret %classIO* %this\n" 121 | + "}\n"; 122 | 123 | static final String IO_OUTINT = "define %classIO* @_ZN2IO7out_int( %class.IO* %this, i32 %int ) {\n" 124 | + "entry:\n" 125 | + "%0 = call i32 (i8*, ...) @printf( i8* bitcast ( [3 x i8]* @intformatstr to i8* ), i32 %int )\n" 126 | + "ret %classIO* %this\n" 127 | + "}\n"; 128 | 129 | static final String IO_INSTRING = "define [1024 x i8]* @_ZN2IO9in_string( %class.IO* %this ) {\n" 130 | + "entry:\n" 131 | + "%0 = call i8* @malloc( i64 1024 )\n" 132 | + "%retval = bitcast i8* %0 to [1024 x i8]*\n" 133 | + "%1 = call i32 (i8*, ...) @scanf( i8* bitcast ( [3 x i8]* @strformatstr to i8* ), [1024 x i8]* %retval )\n" 134 | + "ret [1024 x i8]* %retval\n" 135 | + "}\n"; 136 | 137 | static final String IO_ININT = "define i32 @_ZN2IO9in_int( %class.IO* %this ) {\n" 138 | + "entry:\n" 139 | + "%0 = call i8* @malloc( i64 4 )\n" 140 | + "%1 = bitcast i8* %0 to i32*\n" 141 | + "%2 = call i32 (i8*, ...) @scanf( i8* bitcast ( [3 x i8]* @intformatstr to i8* ), i32* %1 )\n" 142 | + "%retval = load i32, i32* %1\n" 143 | + "ret i32 %retval\n" 144 | + "}\n"; 145 | 146 | static final String OBJECT_BASE = "define void @_Z6ObjectBaseC ( %class.Object.Base ) {\n" 147 | + "entry:\n" 148 | + "ret void\n" 149 | + "}\n"; 150 | 151 | /* Note that each class inherits from class Object. 152 | /* 153 | * Methods default 154 | * Object: abort(); 155 | * void (void) * _ZN5Object5abortEv(%class.Object* %this) 156 | */ 157 | } 158 | -------------------------------------------------------------------------------- /codegen/src/java/cool/CoolParserBaseVisitor.java: -------------------------------------------------------------------------------- 1 | // Generated from CoolParser.g4 by ANTLR 4.5.1 2 | package cool; 3 | 4 | import cool.AST; 5 | import java.util.List; 6 | 7 | import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; 8 | 9 | /** 10 | * This class provides an empty implementation of {@link CoolParserVisitor}, 11 | * which can be extended to create a visitor which only needs to handle a subset 12 | * of the available methods. 13 | * 14 | * @param The return type of the visit operation. Use {@link Void} for 15 | * operations with no return type. 16 | */ 17 | public class CoolParserBaseVisitor extends AbstractParseTreeVisitor implements CoolParserVisitor { 18 | /** 19 | * {@inheritDoc} 20 | * 21 | *

The default implementation returns the result of calling 22 | * {@link #visitChildren} on {@code ctx}.

23 | */ 24 | @Override public T visitProgram(CoolParser.ProgramContext ctx) { return visitChildren(ctx); } 25 | /** 26 | * {@inheritDoc} 27 | * 28 | *

The default implementation returns the result of calling 29 | * {@link #visitChildren} on {@code ctx}.

30 | */ 31 | @Override public T visitClass_list(CoolParser.Class_listContext ctx) { return visitChildren(ctx); } 32 | /** 33 | * {@inheritDoc} 34 | * 35 | *

The default implementation returns the result of calling 36 | * {@link #visitChildren} on {@code ctx}.

37 | */ 38 | @Override public T visitClass_(CoolParser.Class_Context ctx) { return visitChildren(ctx); } 39 | /** 40 | * {@inheritDoc} 41 | * 42 | *

The default implementation returns the result of calling 43 | * {@link #visitChildren} on {@code ctx}.

44 | */ 45 | @Override public T visitFeature_list(CoolParser.Feature_listContext ctx) { return visitChildren(ctx); } 46 | /** 47 | * {@inheritDoc} 48 | * 49 | *

The default implementation returns the result of calling 50 | * {@link #visitChildren} on {@code ctx}.

51 | */ 52 | @Override public T visitFeature(CoolParser.FeatureContext ctx) { return visitChildren(ctx); } 53 | /** 54 | * {@inheritDoc} 55 | * 56 | *

The default implementation returns the result of calling 57 | * {@link #visitChildren} on {@code ctx}.

58 | */ 59 | @Override public T visitFormal_list(CoolParser.Formal_listContext ctx) { return visitChildren(ctx); } 60 | /** 61 | * {@inheritDoc} 62 | * 63 | *

The default implementation returns the result of calling 64 | * {@link #visitChildren} on {@code ctx}.

65 | */ 66 | @Override public T visitFormal(CoolParser.FormalContext ctx) { return visitChildren(ctx); } 67 | /** 68 | * {@inheritDoc} 69 | * 70 | *

The default implementation returns the result of calling 71 | * {@link #visitChildren} on {@code ctx}.

72 | */ 73 | @Override public T visitExpression(CoolParser.ExpressionContext ctx) { return visitChildren(ctx); } 74 | /** 75 | * {@inheritDoc} 76 | * 77 | *

The default implementation returns the result of calling 78 | * {@link #visitChildren} on {@code ctx}.

79 | */ 80 | @Override public T visitExpression_list_actual(CoolParser.Expression_list_actualContext ctx) { return visitChildren(ctx); } 81 | /** 82 | * {@inheritDoc} 83 | * 84 | *

The default implementation returns the result of calling 85 | * {@link #visitChildren} on {@code ctx}.

86 | */ 87 | @Override public T visitExpression_list(CoolParser.Expression_listContext ctx) { return visitChildren(ctx); } 88 | /** 89 | * {@inheritDoc} 90 | * 91 | *

The default implementation returns the result of calling 92 | * {@link #visitChildren} on {@code ctx}.

93 | */ 94 | @Override public T visitCase_list(CoolParser.Case_listContext ctx) { return visitChildren(ctx); } 95 | /** 96 | * {@inheritDoc} 97 | * 98 | *

The default implementation returns the result of calling 99 | * {@link #visitChildren} on {@code ctx}.

100 | */ 101 | @Override public T visitCase_(CoolParser.Case_Context ctx) { return visitChildren(ctx); } 102 | /** 103 | * {@inheritDoc} 104 | * 105 | *

The default implementation returns the result of calling 106 | * {@link #visitChildren} on {@code ctx}.

107 | */ 108 | @Override public T visitLet_looper(CoolParser.Let_looperContext ctx) { return visitChildren(ctx); } 109 | /** 110 | * {@inheritDoc} 111 | * 112 | *

The default implementation returns the result of calling 113 | * {@link #visitChildren} on {@code ctx}.

114 | */ 115 | @Override public T visitStar_slash(CoolParser.Star_slashContext ctx) { return visitChildren(ctx); } 116 | /** 117 | * {@inheritDoc} 118 | * 119 | *

The default implementation returns the result of calling 120 | * {@link #visitChildren} on {@code ctx}.

121 | */ 122 | @Override public T visitPlus_minus(CoolParser.Plus_minusContext ctx) { return visitChildren(ctx); } 123 | /** 124 | * {@inheritDoc} 125 | * 126 | *

The default implementation returns the result of calling 127 | * {@link #visitChildren} on {@code ctx}.

128 | */ 129 | @Override public T visitLt_le_equals(CoolParser.Lt_le_equalsContext ctx) { return visitChildren(ctx); } 130 | } -------------------------------------------------------------------------------- /codegen/src/java/cool/CoolParserVisitor.java: -------------------------------------------------------------------------------- 1 | // Generated from CoolParser.g4 by ANTLR 4.5.1 2 | package cool; 3 | 4 | import cool.AST; 5 | import java.util.List; 6 | 7 | import org.antlr.v4.runtime.tree.ParseTreeVisitor; 8 | 9 | /** 10 | * This interface defines a complete generic visitor for a parse tree produced 11 | * by {@link CoolParser}. 12 | * 13 | * @param The return type of the visit operation. Use {@link Void} for 14 | * operations with no return type. 15 | */ 16 | public interface CoolParserVisitor extends ParseTreeVisitor { 17 | /** 18 | * Visit a parse tree produced by {@link CoolParser#program}. 19 | * @param ctx the parse tree 20 | * @return the visitor result 21 | */ 22 | T visitProgram(CoolParser.ProgramContext ctx); 23 | /** 24 | * Visit a parse tree produced by {@link CoolParser#class_list}. 25 | * @param ctx the parse tree 26 | * @return the visitor result 27 | */ 28 | T visitClass_list(CoolParser.Class_listContext ctx); 29 | /** 30 | * Visit a parse tree produced by {@link CoolParser#class_}. 31 | * @param ctx the parse tree 32 | * @return the visitor result 33 | */ 34 | T visitClass_(CoolParser.Class_Context ctx); 35 | /** 36 | * Visit a parse tree produced by {@link CoolParser#feature_list}. 37 | * @param ctx the parse tree 38 | * @return the visitor result 39 | */ 40 | T visitFeature_list(CoolParser.Feature_listContext ctx); 41 | /** 42 | * Visit a parse tree produced by {@link CoolParser#feature}. 43 | * @param ctx the parse tree 44 | * @return the visitor result 45 | */ 46 | T visitFeature(CoolParser.FeatureContext ctx); 47 | /** 48 | * Visit a parse tree produced by {@link CoolParser#formal_list}. 49 | * @param ctx the parse tree 50 | * @return the visitor result 51 | */ 52 | T visitFormal_list(CoolParser.Formal_listContext ctx); 53 | /** 54 | * Visit a parse tree produced by {@link CoolParser#formal}. 55 | * @param ctx the parse tree 56 | * @return the visitor result 57 | */ 58 | T visitFormal(CoolParser.FormalContext ctx); 59 | /** 60 | * Visit a parse tree produced by {@link CoolParser#expression}. 61 | * @param ctx the parse tree 62 | * @return the visitor result 63 | */ 64 | T visitExpression(CoolParser.ExpressionContext ctx); 65 | /** 66 | * Visit a parse tree produced by {@link CoolParser#expression_list_actual}. 67 | * @param ctx the parse tree 68 | * @return the visitor result 69 | */ 70 | T visitExpression_list_actual(CoolParser.Expression_list_actualContext ctx); 71 | /** 72 | * Visit a parse tree produced by {@link CoolParser#expression_list}. 73 | * @param ctx the parse tree 74 | * @return the visitor result 75 | */ 76 | T visitExpression_list(CoolParser.Expression_listContext ctx); 77 | /** 78 | * Visit a parse tree produced by {@link CoolParser#case_list}. 79 | * @param ctx the parse tree 80 | * @return the visitor result 81 | */ 82 | T visitCase_list(CoolParser.Case_listContext ctx); 83 | /** 84 | * Visit a parse tree produced by {@link CoolParser#case_}. 85 | * @param ctx the parse tree 86 | * @return the visitor result 87 | */ 88 | T visitCase_(CoolParser.Case_Context ctx); 89 | /** 90 | * Visit a parse tree produced by {@link CoolParser#let_looper}. 91 | * @param ctx the parse tree 92 | * @return the visitor result 93 | */ 94 | T visitLet_looper(CoolParser.Let_looperContext ctx); 95 | /** 96 | * Visit a parse tree produced by {@link CoolParser#star_slash}. 97 | * @param ctx the parse tree 98 | * @return the visitor result 99 | */ 100 | T visitStar_slash(CoolParser.Star_slashContext ctx); 101 | /** 102 | * Visit a parse tree produced by {@link CoolParser#plus_minus}. 103 | * @param ctx the parse tree 104 | * @return the visitor result 105 | */ 106 | T visitPlus_minus(CoolParser.Plus_minusContext ctx); 107 | /** 108 | * Visit a parse tree produced by {@link CoolParser#lt_le_equals}. 109 | * @param ctx the parse tree 110 | * @return the visitor result 111 | */ 112 | T visitLt_le_equals(CoolParser.Lt_le_equalsContext ctx); 113 | } -------------------------------------------------------------------------------- /codegen/src/java/cool/Error.java: -------------------------------------------------------------------------------- 1 | package cool; 2 | 3 | public class Error { 4 | public String fname; 5 | public int line; 6 | public String err; 7 | Error(String f, int l, String er) { 8 | fname = new String(f); 9 | line = l; 10 | err = new String(er); 11 | } 12 | } -------------------------------------------------------------------------------- /codegen/src/java/cool/IRClassPlus.java: -------------------------------------------------------------------------------- 1 | package cool; 2 | import java.util.ArrayList; 3 | import java.util.HashMap; 4 | 5 | /* For each class, we have a list of methods and a list of attributes. Additionally, we have a hashmap that stores 6 | * offsets of both methods and attributes. 7 | * 8 | */ 9 | 10 | 11 | public class IRClassPlus { 12 | public String name; 13 | public String parent = null; 14 | public HashMap alist; 15 | public HashMap mlist; 16 | 17 | 18 | public HashMap attrOffset; 19 | public HashMap methodOffset; 20 | public HashMap IRname; 21 | 22 | public ArrayList methodList; 23 | public ArrayList attrList; 24 | 25 | IRClassPlus(String nm, String pr, HashMap al, HashMap ml, HashMap ao, HashMap mo, ArrayList pa, ArrayList pm, HashMap irn) { 26 | name = new String(nm); 27 | if(pr != null) parent = new String(pr); 28 | alist = new HashMap (); 29 | alist.putAll(al); 30 | mlist = new HashMap (); 31 | mlist.putAll(ml); 32 | 33 | attrOffset = new HashMap (); 34 | attrOffset.putAll(ao); 35 | 36 | methodOffset = new HashMap (); 37 | methodOffset.putAll(mo); 38 | 39 | attrList = new ArrayList (); 40 | attrList.addAll(pa); 41 | 42 | methodList = new ArrayList (); 43 | methodList.addAll(pm); 44 | 45 | IRname = new HashMap (); 46 | IRname.putAll(irn); 47 | } 48 | } -------------------------------------------------------------------------------- /codegen/src/java/cool/IRClassTable.java: -------------------------------------------------------------------------------- 1 | package cool; 2 | import java.util.*; 3 | import java.util.Map.Entry; 4 | 5 | 6 | 7 | 8 | public class IRClassTable { 9 | private HashMap classes=new HashMap(); // for retrieving class related info and class attributes and features 10 | private HashMap height = new HashMap(); // for retrieving class height in the inheritance hierarchy (for conformance check) 11 | 12 | 13 | public List errors = new ArrayList(); 14 | 15 | public IRClassTable() { 16 | /* Classes already present in the table: 17 | * - Object 18 | * - IO 19 | * - String 20 | * - Int 21 | * - Bool 22 | * 23 | * Object has methods: 24 | * - abort() : Object 25 | * - type_name(): String 26 | * IO has methods: 27 | * - out_string(x : String) : IO 28 | * - out_int(x : Int) : IO 29 | * - in_string() : String 30 | * - in_int() : String 31 | * String has methods: 32 | * - length() : Int 33 | * - concat(s: String) : String 34 | * - substr(i : Int, l : Int) : String 35 | */ 36 | 37 | List obj_formal = new ArrayList(); 38 | obj_formal.add(new AST.formal("this", "Object", 0)); 39 | 40 | HashMap ol = new HashMap (); 41 | ol.put("abort", new AST.method("abort", obj_formal, "Object", new AST.no_expr(0), 0)); 42 | ol.put("type_name", new AST.method("type_name", obj_formal, "String", new AST.no_expr(0), 0)); 43 | 44 | 45 | ArrayList obj_mlist = new ArrayList (); 46 | obj_mlist.add(new AST.method("abort", obj_formal, "Object", new AST.no_expr(0), 0)); 47 | obj_mlist.add(new AST.method("type_name", obj_formal, "String", new AST.no_expr(0), 0)); 48 | obj_mlist.add(new AST.method("copy", obj_formal, "Object", new AST.no_expr(0), 0)); 49 | 50 | HashMap obj_moffset = new HashMap (); 51 | obj_moffset.put("abort", 0); 52 | obj_moffset.put("type_name", 1); 53 | obj_moffset.put("copy", 2); 54 | 55 | HashMap irname = new HashMap (); 56 | irname.put("abort", "@_ZN6Object5abort"); 57 | irname.put("type_name", "@_ZN6Object9type_name"); 58 | irname.put("copy", "@_ZN6Object4copy"); 59 | 60 | classes.put("Object", new IRClassPlus("Object", null, new HashMap(), ol, new HashMap (), obj_moffset, new ArrayList (), obj_mlist, irname)); 61 | height.put("Object", 0); 62 | 63 | HashMap iol = new HashMap(); 64 | 65 | List os_formals = new ArrayList(); 66 | List io_formal = new ArrayList (); 67 | io_formal.add(new AST.formal("this", "IO", 0)); 68 | os_formals.addAll(io_formal); 69 | os_formals.add(new AST.formal("out_string", "String", 0)); 70 | List oi_formals = new ArrayList(); 71 | oi_formals.addAll(io_formal); 72 | oi_formals.add(new AST.formal("out_int", "Int", 0)); 73 | 74 | 75 | iol.put("out_string", new AST.method("out_string", os_formals, "IO", new AST.no_expr(0), 0)); 76 | iol.put("out_int", new AST.method("out_int", oi_formals, "IO", new AST.no_expr(0), 0)); 77 | iol.put("in_string", new AST.method("in_string", io_formal, "String", new AST.no_expr(0), 0)); 78 | iol.put("in_int", new AST.method("in_int", io_formal, "Int", new AST.no_expr(0), 0)); 79 | 80 | HashMap io_moffset = new HashMap (); 81 | io_moffset.putAll(obj_moffset); 82 | io_moffset.put("out_string", 3); 83 | io_moffset.put("out_int", 4); 84 | io_moffset.put("in_string", 5); 85 | io_moffset.put("in_int", 6); 86 | 87 | ArrayList io_mlist = new ArrayList (); 88 | io_mlist.addAll(obj_mlist); 89 | io_mlist.add(new AST.method("out_string", os_formals, "IO", new AST.no_expr(0), 0)); 90 | io_mlist.add(new AST.method("out_int", oi_formals, "IO", new AST.no_expr(0), 0)); 91 | io_mlist.add(new AST.method("in_string", io_formal, "String", new AST.no_expr(0), 0)); 92 | io_mlist.add(new AST.method("in_int", io_formal, "Int", new AST.no_expr(0), 0)); 93 | 94 | // redefine copy 95 | io_mlist.set(2, new AST.method("copy", io_formal, "IO", new AST.no_expr(0), 0)); 96 | 97 | HashMap io_irname = new HashMap (); 98 | io_irname.putAll(irname); 99 | io_irname.put("out_string", "@_ZN2IO10out_string"); 100 | io_irname.put("in_string", "@_ZN2IO7out_int"); 101 | io_irname.put("in_string", "@_ZN2IO9in_string"); 102 | io_irname.put("in_int", "@_ZN2IO9in_int"); 103 | 104 | // change copy irname 105 | io_irname.put("copy", "@_ZN2IO4copy"); 106 | 107 | 108 | classes.put("IO", new IRClassPlus("IO", "Object", new HashMap(), iol, new HashMap (), io_moffset, new ArrayList (), io_mlist, io_irname)); 109 | classes.get("IO").mlist.putAll(ol); // IO inherits from Object 110 | height.put("IO", 1); 111 | classes.get("IO").attrList.add(new AST.attr("__Base", "Object" + ".Base", new AST.no_expr(0), 0)); 112 | classes.get("IO").attrOffset.put("__Base", 0); 113 | 114 | classes.put("Int", new IRClassPlus("Int", "Object", new HashMap(), new HashMap(), new HashMap (), obj_moffset, new ArrayList (), obj_mlist, irname)); 115 | height.put("Int", 1); 116 | classes.get("Int").mlist.putAll(ol); // Int inherits from Object 117 | classes.get("Int").methodList.get(2).typeid = "Int"; // redefine copy 118 | classes.get("Int").IRname.put("copy", "@_ZN3Int4copy"); 119 | 120 | classes.put("Bool", new IRClassPlus("Bool", "Object", new HashMap(), new HashMap(), new HashMap (), obj_moffset, new ArrayList (), obj_mlist, irname)); 121 | height.put("Bool", 1); 122 | classes.get("Bool").mlist.putAll(ol); // Bool inherits from Object 123 | classes.get("Int").methodList.get(2).typeid = "Bool"; 124 | classes.get("Bool").IRname.put("copy", "@_ZN4Bool4copy"); 125 | 126 | HashMap sl = new HashMap(); 127 | List str_formal = new ArrayList(); 128 | str_formal.add(new AST.formal("this", "String", 0)); 129 | List concat_formal = new ArrayList(); 130 | concat_formal.addAll(str_formal); 131 | concat_formal.add(new AST.formal("that", "String", 0)); 132 | List substr_formal = new ArrayList(); 133 | substr_formal.addAll(str_formal); 134 | substr_formal.add(new AST.formal("index", "Int", 0)); 135 | substr_formal.add(new AST.formal("len", "Int", 0)); 136 | 137 | sl.put("length", new AST.method("length", str_formal, "Int", new AST.no_expr(0), 0)); 138 | sl.put("concat", new AST.method("concat", concat_formal, "String", new AST.no_expr(0), 0)); 139 | sl.put("substr", new AST.method("substr", substr_formal, "String", new AST.no_expr(0), 0)); 140 | 141 | HashMap str_moffset = new HashMap (); 142 | str_moffset.putAll(obj_moffset); 143 | str_moffset.put("length", 3); 144 | str_moffset.put("concat", 4); 145 | str_moffset.put("substr", 5); 146 | 147 | ArrayList str_mlist = new ArrayList (); 148 | str_mlist.addAll(obj_mlist); 149 | str_mlist.add(new AST.method("length", str_formal, "Int", new AST.no_expr(0), 0)); 150 | str_mlist.add(new AST.method("concat", concat_formal, "String", new AST.no_expr(0), 0)); 151 | str_mlist.add(new AST.method("substr", substr_formal, "String", new AST.no_expr(0), 0)); 152 | str_mlist.set(2, new AST.method("copy", str_formal, "String", new AST.no_expr(0), 0)); 153 | str_mlist.get(2).typeid = "String"; // redefine copy 154 | 155 | HashMap str_irname = new HashMap (); 156 | str_irname.putAll(irname); 157 | str_irname.put("length", "@_ZN6String6length"); 158 | str_irname.put("concat", "@_ZN6String6concat"); 159 | str_irname.put("substr", "@_ZN6String6substr"); 160 | 161 | // change copy 162 | str_irname.put("copy", "@_ZN6String4copy"); 163 | 164 | 165 | 166 | classes.put("String", new IRClassPlus("String", "Object", new HashMap(), sl, new HashMap(), str_moffset, new ArrayList (), str_mlist, str_irname)); 167 | height.put("String", 1); 168 | classes.get("String").mlist.putAll(ol); // String Inherits from Object 169 | classes.get("String").IRname.put("copy", "@_ZN5String4copy"); 170 | } 171 | void insert(AST.class_ c) { 172 | /* Whenever a new class is inserted, 173 | * - Inherits the attributes and methods of the parent class. 174 | * - Checks for multiple method or attribute definitions. 175 | * - Checks for correct method overrides and any attribute overrides 176 | */ 177 | String pr = c.parent; 178 | IRClassPlus tc = new IRClassPlus(c.name, c.parent, classes.get(pr).alist, classes.get(pr).mlist, new HashMap (), 179 | classes.get(pr).methodOffset, new ArrayList (), classes.get(pr).methodList, classes.get(pr).IRname); // adding the parents attribute list and method list 180 | 181 | 182 | HashMap tc_alist = new HashMap(); 183 | HashMap tc_mlist = new HashMap (); 184 | 185 | tc.attrList.add(new AST.attr("__Base", pr + ".Base", new AST.no_expr(0), 0)); 186 | tc.attrOffset.put("__Base", 0); 187 | 188 | /* Checks for the following errors with respect to the inherited class: 189 | * - redefinition of an inherited attribute (Note: the class retains the inherited attribute and discards the attribute defined within the class) 190 | * - wrong redefinition of an inherited method (Note : the class retains the inherited method and discards the method defined within the class) 191 | */ 192 | /* adding attrs of parent */ 193 | for(Entry entry : tc_alist.entrySet()) { 194 | tc.alist.put(entry.getKey(), entry.getValue()); 195 | } 196 | 197 | /* attrs of the parent are accessed via the base attr */ 198 | 199 | 200 | /* Checks for the following errors within a class: 201 | * - multiple attribute definitions 202 | * - multiple method definitions 203 | */ 204 | /* adding attrs and methods of class */ 205 | 206 | int attr_ptr = 1; 207 | 208 | for(AST.feature e : c.features) { 209 | if(e.getClass() == AST.attr.class) { 210 | AST.attr ae = (AST.attr) e; 211 | tc_alist.put(ae.name, ae); 212 | tc.attrList.add(ae); 213 | tc.attrOffset.put(ae.name, attr_ptr); 214 | attr_ptr++; 215 | } 216 | else if(e.getClass() == AST.method.class) { 217 | AST.method me = (AST.method) e; 218 | tc_mlist.put(me.name, me); 219 | } 220 | } 221 | 222 | // change the copy method name 223 | tc.IRname.put("copy", "@_ZN" + tc.name.length() + tc.name + "4copy"); 224 | 225 | // tc_mlist contains methods in current class 226 | 227 | int method_ptr = tc.methodList.size(); 228 | for(Entry entry : tc_mlist.entrySet()) { 229 | String me_name = entry.getKey(); 230 | if(tc.mlist.containsKey(entry.getKey())) { // overloaded method 231 | tc.methodList.set(tc.methodOffset.get(me_name), entry.getValue()); 232 | tc.IRname.put(me_name, "@_ZN" + tc.name.length() + tc.name + me_name.length() + me_name); 233 | } else { 234 | tc.methodList.add(entry.getValue()); 235 | tc.methodOffset.put(entry.getKey(), method_ptr); 236 | tc.IRname.put(me_name, "@_ZN" + tc.name.length() + tc.name + me_name.length() + me_name); 237 | method_ptr++; 238 | } 239 | } 240 | height.put(c.name, height.get(c.parent) + 1); 241 | classes.put(c.name, tc); 242 | } 243 | 244 | 245 | List getErrors() { 246 | return errors; 247 | } 248 | 249 | HashMap getAttrs(String className) { 250 | return classes.get(className).alist; 251 | } 252 | 253 | IRClassPlus getIRClassPlus(String className) { 254 | return classes.get(className); 255 | } 256 | 257 | boolean conforms(String a, String b) { 258 | if(a.equals(b)) 259 | return true; 260 | else { 261 | a = classes.get(a).parent; 262 | if(a == null) return false; 263 | else return conforms(a, b); 264 | } 265 | } 266 | 267 | String lca(String a, String b) { 268 | 269 | if(a.equals(b)) return a; 270 | else if(height.get(a) < height.get(b)) // a must always be deeper in the tree 271 | return lca(b, a); 272 | else 273 | return lca(classes.get(a).parent, b); 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /codegen/src/java/cool/Makefile: -------------------------------------------------------------------------------- 1 | ANTLR_JAR = /usr/local/lib/antlr-4.5-complete.jar 2 | 3 | %: all 4 | 5 | all: 6 | javac -cp $(ANTLR_JAR) -Xlint *.java 7 | 8 | clean: 9 | rm *.class 10 | -------------------------------------------------------------------------------- /codegen/src/java/cool/ScopeTable.java: -------------------------------------------------------------------------------- 1 | package cool; 2 | import java.util.*; 3 | public class ScopeTable { 4 | private int scope; 5 | private ArrayList> maps=new ArrayList>(); 6 | public ScopeTable(){ 7 | scope = 0; 8 | maps.add(new HashMap()); 9 | } 10 | void insert(String s, T t){ 11 | maps.get(scope).put(s,t); 12 | } 13 | 14 | void insertAll(HashMap hs) { 15 | maps.get(scope).putAll(hs); 16 | } 17 | void enterScope(){ 18 | scope++; 19 | maps.add(new HashMap()); 20 | } 21 | void exitScope(){ 22 | if (scope>0){ 23 | maps.remove(scope); 24 | scope--; 25 | } 26 | } 27 | T lookUpLocal(String t){ 28 | return maps.get(scope).get(t); 29 | } 30 | T lookUpGlobal(String t){ 31 | for ( int i = scope; i>=0 ; i--){ 32 | if (maps.get(i).containsKey(t)) 33 | return maps.get(i).get(t); 34 | } 35 | return null; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /codegen/src/java/cool/SemanticTest.java: -------------------------------------------------------------------------------- 1 | package cool; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.IOException; 5 | import java.util.Arrays; 6 | 7 | import org.antlr.v4.runtime.ANTLRInputStream; 8 | import org.antlr.v4.runtime.CommonTokenStream; 9 | 10 | import org.antlr.v4.runtime.CommonToken; 11 | import org.antlr.v4.runtime.Token; 12 | import org.antlr.v4.runtime.BaseErrorListener; 13 | import org.antlr.v4.runtime.Recognizer; 14 | import org.antlr.v4.runtime.RecognitionException; 15 | import org.antlr.v4.runtime.tree.*; 16 | import java.nio.file.Paths; 17 | 18 | public class SemanticTest { 19 | 20 | static String[] TOKENS = {"ERROR", "TYPEID", "OBJECTID", "BOOL_CONST", "INT_CONST", "STR_CONST", "'('", "')'", "':'", "'@'", "';'", "','", "'+'", "'-'", "'*'", "'/'", "'~'", "'<'", "'='", "'{'", "'}'", "'.'", "DARROW", "LE", "ASSIGN", "CLASS", "ELSE", "FI", "IF", "IN", "INHERITS", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "OF", "NEW", "ISVOID", "NOT" 21 | }; 22 | 23 | static int VALUED_INDEX_LIMIT = 6; 24 | static int NAMED_TOKEN_INDEX = 23; 25 | static int parser_error_flag = 0; 26 | 27 | static String escapeSpecialCharacters(String text) { 28 | return 29 | text 30 | .replaceAll("\\\\", "\\\\\\\\") 31 | .replaceAll("\n", "\\\\n") 32 | .replaceAll("\t", "\\\\t") 33 | .replaceAll("\b", "\\\\b") 34 | .replaceAll("\f", "\\\\f") 35 | .replaceAll("\"", "\\\\\"") 36 | .replaceAll("\r", "\\\\015") 37 | .replaceAll("\033","\\\\033") 38 | .replaceAll("\001","\\\\001") 39 | .replaceAll("\002","\\\\002") 40 | .replaceAll("\003","\\\\003") 41 | .replaceAll("\004","\\\\004") 42 | .replaceAll("\022","\\\\022") 43 | .replaceAll("\013","\\\\013") 44 | .replaceAll("\000", "\\\\000") 45 | ; 46 | } 47 | 48 | static void printAST(String filename) throws Exception{ 49 | ANTLRInputStream inStream=null; 50 | try{ 51 | inStream = new ANTLRInputStream(new FileInputStream(filename)); 52 | }catch(Exception e){ 53 | System.err.println("Could not read file "+filename); 54 | return; 55 | } 56 | 57 | CoolLexer lexer = new CoolLexer(inStream); 58 | CommonTokenStream tokens = new CommonTokenStream(lexer); 59 | tokens.fill(); 60 | int lexer_flag = 0; 61 | for(Token t : tokens.getTokens()){ 62 | if ( t.getType() == 1 ){ 63 | lexer_flag = 1; 64 | System.err.println("Lexical error at "+t.getLine()+": "+escapeSpecialCharacters(t.getText())); 65 | } 66 | } 67 | if (lexer_flag == 1) 68 | return; 69 | 70 | parser_error_flag = 0; 71 | CoolParser parser = new CoolParser(tokens); 72 | parser.removeErrorListeners(); 73 | parser.addErrorListener(new ParserError(Paths.get(filename).getFileName().toString())); 74 | parser.setFilename(Paths.get(filename).getFileName().toString()); 75 | 76 | CoolParser.ProgramContext prog = null; 77 | try{ 78 | prog = parser.program(); 79 | }catch(Exception e){ 80 | // e.printStackTrace(); 81 | } 82 | if(parser_error_flag == 1){ 83 | System.err.println("Compilation halted due to lex and parse errors"); 84 | return; 85 | } 86 | Semantic semanticAnalyzer=new Semantic(prog.value); 87 | if (semanticAnalyzer.getErrorFlag()){ 88 | System.err.println("Compilation halter due to semantic errors."); 89 | return; 90 | } 91 | System.out.println(prog.value.getString("")); 92 | } 93 | 94 | public static void main(String args[]) throws Exception{ 95 | 96 | if(args.length < 1) { 97 | System.err.println("No files given"); 98 | System.exit(1); 99 | } 100 | printAST(args[0]); 101 | } 102 | 103 | public static class ParserError extends BaseErrorListener { 104 | 105 | String filename; 106 | public ParserError(String fn) { 107 | super(); 108 | filename=fn; 109 | } 110 | @Override 111 | public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionIntLine, String msg, RecognitionException e){ 112 | parser_error_flag=1; 113 | String sourceName = recognizer.getInputStream().getSourceName(); 114 | String errorMessage=""; 115 | if(filename!=null){ 116 | if(offendingSymbol instanceof CommonToken){ 117 | errorMessage += "\""+filename+"\", line "+line+": syntax error at or near "; 118 | int typeid = ((CommonToken)offendingSymbol).getType(); 119 | if (typeid == -1){ 120 | errorMessage += "EOF"; 121 | } 122 | else if (typeid <= VALUED_INDEX_LIMIT) { 123 | errorMessage += TOKENS[typeid-1] + " = " + ((CommonToken)offendingSymbol).getText(); 124 | }else if(typeid >= NAMED_TOKEN_INDEX){ 125 | errorMessage += TOKENS[typeid-1]; 126 | }else{ 127 | errorMessage += "\'"+escapeSpecialCharacters(((CommonToken)offendingSymbol).getText())+"\'"; 128 | } 129 | } 130 | } 131 | System.err.println(errorMessage); 132 | throw new RuntimeException("One error found!"); 133 | } 134 | } 135 | } 136 | 137 | //objectid, typeid, int_const, string_const, bool_const 138 | // static String[] TOKENS = {"ERROR", "TYPEID", "OBJECTID", "BOOL_CONST", "INT_CONST", "STR_CONST", "'('", "')'", "':'", "'@'", "';'", "','", "'+'", "'-'", "'*'", "'/'", "'~'", "'<'", "'='", "'{'", "'}'", "'.'", "DARROW", "LE", "ASSIGN", "CLASS", "ELSE", "FI", "IF", "IN", "INHERITS", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "OF", "NEW", "ISVOID", "NOT" 139 | // }; 140 | -------------------------------------------------------------------------------- /codegen/src/test_cases/helloworld.cl: -------------------------------------------------------------------------------- 1 | class Main { 2 | main():IO { 3 | new IO.out_string("Hello world!\n") 4 | }; 5 | }; 6 | 7 | -------------------------------------------------------------------------------- /lexer/Makefile: -------------------------------------------------------------------------------- 1 | MAKE = make 2 | %: build 3 | 4 | build: 5 | $(MAKE) -C ./src/grammar -f Makefile 6 | $(MAKE) -C ./src/java -f Makefile 7 | 8 | clean: 9 | $(MAKE) -C ./src/grammar -f Makefile clean 10 | $(MAKE) -C ./src/java -f Makefile clean 11 | -------------------------------------------------------------------------------- /lexer/README.md: -------------------------------------------------------------------------------- 1 | # COOL Compiler # 2 | 3 | -------------------------------------------------------------------------------- /lexer/src/grammar/CoolLexer.g4: -------------------------------------------------------------------------------- 1 | lexer grammar CoolLexer; 2 | 3 | tokens{ 4 | ERROR, 5 | TYPEID, 6 | OBJECTID, 7 | BOOL_CONST, 8 | INT_CONST, 9 | STR_CONST, 10 | LPAREN, 11 | RPAREN, 12 | COLON, 13 | ATSYM, 14 | SEMICOLON, 15 | COMMA, 16 | PLUS, 17 | MINUS, 18 | STAR, 19 | SLASH, 20 | TILDE, 21 | LT, 22 | EQUALS, 23 | LBRACE, 24 | RBRACE, 25 | DOT, 26 | DARROW, 27 | LE, 28 | ASSIGN, 29 | CLASS, 30 | ELSE, 31 | FI, 32 | IF, 33 | IN, 34 | INHERITS, 35 | LET, 36 | LOOP, 37 | POOL, 38 | THEN, 39 | WHILE, 40 | CASE, 41 | ESAC, 42 | OF, 43 | NEW, 44 | ISVOID, 45 | NOT 46 | } 47 | 48 | /* 49 | DO NOT EDIT CODE ABOVE THIS LINE 50 | */ 51 | @members{ 52 | 53 | /* 54 | YOU CAN ADD YOUR MEMBER VARIABLES AND METHODS HERE 55 | */ 56 | 57 | /** 58 | * Function to report errors. 59 | * Use this function whenever your lexer encounters any erroneous input 60 | * DO NOT EDIT THIS FUNCTION 61 | */ 62 | public void reportError(String errorString) { 63 | setText(errorString); 64 | setType(ERROR); 65 | } 66 | 67 | public void notFound() { 68 | Token t = _factory.create(_tokenFactorySourcePair, _type, _text, _channel, _tokenStartCharIndex, getCharIndex()-1, _tokenStartLine, _tokenStartCharPositionInLine); 69 | String text = t.getText(); 70 | reportError(text); 71 | } 72 | 73 | public void processString() { 74 | Token t = _factory.create(_tokenFactorySourcePair, _type, _text, _channel, _tokenStartCharIndex, getCharIndex()-1, _tokenStartLine, _tokenStartCharPositionInLine); 75 | String text = t.getText(); 76 | 77 | StringBuilder buf = new StringBuilder(0); 78 | 79 | //write your code to test strings here 80 | for(int i = 0; i < text.length(); ++i) { 81 | if(text.charAt(i) == '\\') { 82 | if(text.charAt(i+1) == 'n') 83 | buf.append('\n'); 84 | else if(text.charAt(i+1) == 'f') 85 | buf.append('\f'); 86 | else if(text.charAt(i+1) == 't') 87 | buf.append('\t'); 88 | else if(text.charAt(i+1) == 'b') 89 | buf.append('\t'); 90 | else if(text.charAt(i+1) == '\"') 91 | buf.append('\"'); 92 | else if(text.charAt(i+1) == '\\') 93 | buf.append('\\'); 94 | else 95 | buf.append(text.charAt(i+1)); 96 | i++; 97 | } 98 | else { 99 | buf.append(text.charAt(i)); 100 | } 101 | } 102 | String ntext = buf.toString(); 103 | if(ntext.length() > 1024) { 104 | reportError("String constant too long"); 105 | return; 106 | } 107 | setText(ntext); 108 | return; 109 | } 110 | } 111 | 112 | 113 | /* 114 | WRITE ALL LEXER RULES BELOW 115 | */ 116 | 117 | // Error String1 118 | ERROR : '"' ( ~[\u0000]* ('\\u0000') )+ ~["\nEOF]* ["\nEOF] { reportError("String contains null character"); } 119 | | '"' ~[\n"]* (EOF) { reportError("EOF in string literal"); } 120 | | '"' ~["\nEOF]* ('\n') { reportError("Unterminated string constant"); } 121 | ; 122 | 123 | SEMICOLON : ';' ; 124 | DARROW : '=>' ; 125 | INT_CONST : [0-9]+ ; // integer constants 126 | 127 | /** String Recognition and Error: 128 | * Unescaped New line 129 | * String too long (Handled in processString()) 130 | * String containing NULL character 131 | */ 132 | 133 | STR_CONST : '"' (ESC|.)*? '"' { processString() ;} ; 134 | fragment ESC: '\\"' | '\\\\' ; 135 | 136 | 137 | SELF : 'self' ; 138 | SELF_TYPE : 'SELF_TYPE' ; 139 | 140 | TYPEID : [A-Z] [a-zA-Z0-9_]* ; 141 | OBJECTID : [a-z] [0-9_a-zA-z]* ; 142 | 143 | BOOL_CONST : 't' ('r'|'R') ('u'|'U') ('e'|'E') 144 | | 'f' ('a'|'A') ('l'|'L') ('s'|'S') ('e'|'E') ; 145 | 146 | LPAREN : '(' ; 147 | RPAREN : ')' ; 148 | COLON : ':' ; 149 | ATSYM : '@' ; 150 | COMMA : ',' ; 151 | PLUS : '+' ; 152 | MINUS : '-' ; 153 | STAR : '*' ; 154 | SLASH : '/' ; 155 | TILDE : '~' ; 156 | LT : '<' ; 157 | EQUALS : '=' ; 158 | LBRACE : '{' ; 159 | RBRACE : '}' ; 160 | DOT : '.' ; 161 | LE : '<='; 162 | ASSIGN : '<-'; 163 | 164 | /** 165 | * Keywords are not case sensitive 166 | */ 167 | CLASS : ('c'|'C') ('l'|'L') ('a'|'A') ('s'|'S') ('s'|'S') ; 168 | ELSE : ('e'|'E') ('l'|'L') ('s'|'S') ('e'|'E') ; 169 | FI : ('f'|'F') ('i'|'I') ; 170 | IF : ('i'|'I') ('f'|'F') ; 171 | IN : ('i'|'I') ('n'|'N') ; 172 | INHERITS : ('i'|'I') ('n'|'N') ('h'|'H') ('e'|'E') ('r'|'R') ('i'|'I') ('t'|'T') ('s'|'S') ; 173 | LET : ('l'|'L') ('e'|'E') ('t'|'T') ; 174 | LOOP : ('l'|'L') ('o'|'O') ('o'|'O') ('p'|'P') ; 175 | POOL : ('p'|'P') ('o'|'O') ('o'|'O') ('l'|'L') ; 176 | THEN : ('t'|'T') ('h'|'H') ('e'|'E') ('n'|'N') ; 177 | WHILE : ('w'|'W') ('h'|'H') ('i'|'I') ('l'|'L') ('e'|'E') ; 178 | CASE : ('c'|'C') ('a'|'A') ('s'|'S') ('e'|'E') ; 179 | ESAC : ('e'|'E') ('s'|'S') ('a'|'A') ('c'|'C') ; 180 | OF : ('o'|'O') ('f'|'F') ; 181 | NEW : ('n'|'N') ('e'|'E') ('w'|'W') ; 182 | ISVOID : ('i'|'I') ('s'|'S') ('v'|'V') ('o'|'O') ('i'|'I') ('d'|'D') ; 183 | NOT : ('n'|'N') ('o'|'O') ('t'|'T') ; 184 | 185 | /** 186 | * The following haven't been declared in 187 | * the list above. 188 | */ 189 | 190 | WS : [ \t\r\n\f\v]+ -> skip ; // skip spaces, tabs, newlines 191 | 192 | /* COMMENT */ 193 | 194 | LINE_COMMENT: '--' .*? '\n' -> skip ; 195 | 196 | END_COMMENT : '*)' EOF { reportError("Unmatched *)"); } ; 197 | UN_COMMENT : '*)' { reportError("Unmatched *)"); } ; 198 | 199 | COMMENT : '(*'-> pushMode(INCOMMENT), skip; 200 | 201 | NOTFOUND : . { notFound(); } ; 202 | 203 | mode INCOMMENT; 204 | ERR : .(EOF) { reportError("EOF in comment"); } ; 205 | OCOMMENT : '(*' -> pushMode(ININCOM), skip ; 206 | CCOMMENT : '*)' -> popMode, skip ; 207 | INCOMMENT_T : . -> skip ; 208 | 209 | mode ININCOM; 210 | ERR3 : .(EOF) { reportError("EOF in comment"); } ; 211 | OCOM : '(*' -> pushMode(ININCOM), skip ; 212 | ERR4 : '*)' EOF { reportError("EOF in comment"); } ; 213 | CCOM : '*)' -> popMode, skip ; 214 | INCOM_TEXT : . -> skip ; 215 | -------------------------------------------------------------------------------- /lexer/src/grammar/Makefile: -------------------------------------------------------------------------------- 1 | ANTLR_JAR = /usr/local/lib/antlr-4.5-complete.jar 2 | ANTLR = java -jar $(ANTLR_JAR) 3 | ANTLR_OUT_DIR = ../java 4 | PACKAGE = cool 5 | ANTLR_FLAGS = -no-listener -visitor -package $(PACKAGE) 6 | LEXER = CoolLexer 7 | PARSER = Cool 8 | 9 | %: all 10 | 11 | all: 12 | $(ANTLR) $(ANTLR_FLAGS) -o $(ANTLR_OUT_DIR)/$(PACKAGE)/ $(LEXER).g4 13 | 14 | clean: 15 | rm -rf ../java/$(PACKAGE)/*.class 16 | rm -rf ../java/$(PACKAGE)/$(PARSER)*.java 17 | rm -rf ../java/$(PACKAGE)/*.tokens 18 | -------------------------------------------------------------------------------- /lexer/src/grammar/lexer: -------------------------------------------------------------------------------- 1 | ../java/lexer -------------------------------------------------------------------------------- /lexer/src/java/Makefile: -------------------------------------------------------------------------------- 1 | ANTLR_JAR = /usr/local/lib/antlr-4.5-complete.jar 2 | 3 | %: all 4 | 5 | all: 6 | javac -cp $(ANTLR_JAR) cool/*.java 7 | 8 | clean: 9 | -------------------------------------------------------------------------------- /lexer/src/java/cool/CoolLexer.tokens: -------------------------------------------------------------------------------- 1 | ERROR=1 2 | TYPEID=2 3 | OBJECTID=3 4 | BOOL_CONST=4 5 | INT_CONST=5 6 | STR_CONST=6 7 | LPAREN=7 8 | RPAREN=8 9 | COLON=9 10 | ATSYM=10 11 | SEMICOLON=11 12 | COMMA=12 13 | PLUS=13 14 | MINUS=14 15 | STAR=15 16 | SLASH=16 17 | TILDE=17 18 | LT=18 19 | EQUALS=19 20 | LBRACE=20 21 | RBRACE=21 22 | DOT=22 23 | DARROW=23 24 | LE=24 25 | ASSIGN=25 26 | CLASS=26 27 | ELSE=27 28 | FI=28 29 | IF=29 30 | IN=30 31 | INHERITS=31 32 | LET=32 33 | LOOP=33 34 | POOL=34 35 | THEN=35 36 | WHILE=36 37 | CASE=37 38 | ESAC=38 39 | OF=39 40 | NEW=40 41 | ISVOID=41 42 | NOT=42 43 | SELF=43 44 | SELF_TYPE=44 45 | WS=45 46 | LINE_COMMENT=46 47 | END_COMMENT=47 48 | UN_COMMENT=48 49 | COMMENT=49 50 | NOTFOUND=50 51 | ERR=51 52 | OCOMMENT=52 53 | CCOMMENT=53 54 | INCOMMENT_T=54 55 | ERR3=55 56 | OCOM=56 57 | ERR4=57 58 | CCOM=58 59 | INCOM_TEXT=59 60 | ';'=11 61 | '=>'=23 62 | 'self'=43 63 | 'SELF_TYPE'=44 64 | '('=7 65 | ')'=8 66 | ':'=9 67 | '@'=10 68 | ','=12 69 | '+'=13 70 | '-'=14 71 | '*'=15 72 | '/'=16 73 | '~'=17 74 | '<'=18 75 | '='=19 76 | '{'=20 77 | '}'=21 78 | '.'=22 79 | '<='=24 80 | '<-'=25 81 | -------------------------------------------------------------------------------- /lexer/src/java/cool/LexerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | PLEASE DO NOT EDIT THIS FILE 3 | */ 4 | 5 | package cool; 6 | 7 | import java.io.FileInputStream; 8 | import java.io.IOException; 9 | import java.util.Arrays; 10 | 11 | import org.antlr.v4.runtime.ANTLRInputStream; 12 | import org.antlr.v4.runtime.CommonTokenStream; 13 | import org.antlr.v4.runtime.Token; 14 | import org.antlr.v4.runtime.BaseErrorListener; 15 | import org.antlr.v4.runtime.Recognizer; 16 | import org.antlr.v4.runtime.RecognitionException; 17 | 18 | public class LexerTest { 19 | 20 | static String[] TOKENS = {"ERROR", "TYPEID", "OBJECTID", "BOOL_CONST", "INT_CONST", "STR_CONST", "'('", "')'", "':'", "'@'", "';'", "','", "'+'", "'-'", "'*'", "'/'", "'~'", "'<'", "'='", "'{'", "'}'", "'.'", "DARROW", "LE", "ASSIGN", "CLASS", "ELSE", "FI", "IF", "IN", "INHERITS", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "OF", "NEW", "ISVOID", "NOT" 21 | }; 22 | 23 | static int VALUED_INDEX_LIMIT = 6; 24 | 25 | static int EOF_TYPEID = -1; 26 | 27 | public static void main(String args[]) { 28 | 29 | if(args.length < 1) { 30 | System.err.println("No files given"); 31 | System.exit(1); 32 | } 33 | 34 | for(String filename : args) 35 | printTokenStream(filename); 36 | } 37 | 38 | static String escapeSpecialCharacters(String text) { 39 | return 40 | text 41 | .replaceAll("\\\\", "\\\\\\\\") 42 | .replaceAll("\n", "\\\\n") 43 | .replaceAll("\t", "\\\\t") 44 | .replaceAll("\b", "\\\\b") 45 | .replaceAll("\f", "\\\\f") 46 | .replaceAll("\"", "\\\\\"") 47 | .replaceAll("\r", "\\\\015") 48 | .replaceAll("\033","\\\\033") 49 | .replaceAll("\001","\\\\001") 50 | .replaceAll("\002","\\\\002") 51 | .replaceAll("\003","\\\\003") 52 | .replaceAll("\004","\\\\004") 53 | .replaceAll("\022","\\\\022") 54 | .replaceAll("\013","\\\\013") 55 | .replaceAll("\000", "\\\\000") 56 | ; 57 | } 58 | 59 | static void printTokenStream(String filename) { 60 | //create input stream 61 | ANTLRInputStream inStream = null; 62 | 63 | try { 64 | inStream = new ANTLRInputStream(new FileInputStream(filename)); 65 | } catch(IOException e) { 66 | System.err.println("Cannot read input file."); 67 | System.exit(1); 68 | } 69 | 70 | CoolLexer lexer = new CoolLexer(inStream); 71 | 72 | //Call Lexer API for token stream 73 | CommonTokenStream tokens = new CommonTokenStream(lexer); 74 | 75 | tokens.fill(); 76 | 77 | //printing the name of the file 78 | String name = filename.substring(filename.lastIndexOf('/') + 1); 79 | System.out.println("#name \"" + name + "\""); 80 | 81 | final int BOOL_CONST_INDEX = Arrays.asList(TOKENS).indexOf("BOOL_CONST"); 82 | final int STR_CONST_INDEX = Arrays.asList(TOKENS).indexOf("STR_CONST"); 83 | final int ERROR_INDEX = Arrays.asList(TOKENS).indexOf("ERROR"); 84 | 85 | //Print tokens 86 | int typeid; 87 | for(Token t: tokens.getTokens()) { 88 | typeid = t.getType(); 89 | if(typeid > TOKENS.length){ 90 | System.out.println("Invalid Token generated - Token id : "+typeid+" for text \""+t.getText()+"\""); 91 | continue; 92 | } 93 | if(typeid != EOF_TYPEID) { 94 | String output = String.format("#%d %s", t.getLine(), TOKENS[typeid - 1]); 95 | 96 | if(typeid <= VALUED_INDEX_LIMIT) { 97 | 98 | if(typeid - 1 == BOOL_CONST_INDEX) 99 | output += " " + t.getText().toLowerCase(); 100 | 101 | else if(typeid - 1 == STR_CONST_INDEX) 102 | output += " \"" + escapeSpecialCharacters(t.getText()) + "\""; 103 | else if(typeid - 1 == ERROR_INDEX) 104 | output += " \"" + escapeSpecialCharacters(t.getText()) + "\""; 105 | else 106 | output += " " + t.getText(); 107 | 108 | } 109 | 110 | System.out.println(output); 111 | } 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /lexer/src/java/lexer: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | java -cp /usr/local/lib/antlr-4.5-complete.jar:../java cool.LexerTest $1 3 | -------------------------------------------------------------------------------- /lexer/src/test_cases/check.cl: -------------------------------------------------------------------------------- 1 | "dakljfldajf 2 | -------------------------------------------------------------------------------- /lexer/src/test_cases/fact.cl: -------------------------------------------------------------------------------- 1 | class Main inherits IO { 2 | 3 | main() : Object { 4 | { 5 | out_string("Enter number to find factorial!\n"); 6 | out_int(fact(in_int())); 7 | out_string("\n"); 8 | } 9 | }; 10 | 11 | fact(i : Int) : Int { 12 | if (i = 0) then 1 else i*fact(i-1) fi 13 | }; 14 | }; 15 | 16 | -------------------------------------------------------------------------------- /lexer/src/test_cases/fib.cl: -------------------------------------------------------------------------------- 1 | class Main inherits IO { 2 | 3 | main(): Object { 4 | { 5 | out_string("Enter n to find nth fibonacci number!\n"); 6 | out_int(fib(in_int())); 7 | out_string("\n"); 8 | } 9 | }; 10 | 11 | fib(i : Int) : Int { 12 | let a : Int <- 1, 13 | b : Int <- 0, 14 | c : Int <- 0 15 | in 16 | { 17 | while (not (i = 0)) loop 18 | { 19 | c <- a + b; 20 | i <- i - 1; 21 | b <- a; 22 | a <- c; 23 | } 24 | pool; 25 | c; 26 | } 27 | }; 28 | 29 | }; 30 | -------------------------------------------------------------------------------- /lexer/src/test_cases/helloworld.cl: -------------------------------------------------------------------------------- 1 | class Main { 2 | main():IO { 3 | new IO.out_string("Hello world!\n") 4 | }; 5 | }; 6 | 7 | -------------------------------------------------------------------------------- /lexer/src/test_cases/isprime.cl: -------------------------------------------------------------------------------- 1 | class Main inherits IO { 2 | main() : Object { 3 | { 4 | out_string("Enter a number to check if number is prime\n"); 5 | let i : Int <- in_int() in { 6 | if(i <= 1) then { 7 | out_string("Invalid Input\n"); 8 | abort(); 9 | } else { 10 | if (isPrime(i) = 1) then 11 | out_string("Number is prime\n") 12 | else 13 | out_string("Number is composite\n") 14 | fi; 15 | } 16 | fi; 17 | }; 18 | } 19 | }; 20 | 21 | mod(i : Int, ) : Int { 22 | i - (i/k)*k 23 | }; 24 | 25 | isPrime(i : Int) : Int { 26 | { 27 | let x : Int <- 2, 28 | c : Int <- 1 in 29 | { 30 | while (not (x = i)) loop 31 | if (mod(i, x) = 0) then { 32 | c <- 0; 33 | x <- i; 34 | } else x <- x + 1 fi 35 | pool; 36 | c; 37 | }; 38 | } 39 | }; 40 | }; 41 | -------------------------------------------------------------------------------- /lexer/src/test_cases/isprime.cl~: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/altairmn/COOL-Compiler/fdbdfe629592d51fd500cfc2d3ac825945f1ce49/lexer/src/test_cases/isprime.cl~ -------------------------------------------------------------------------------- /lexer/src/test_cases/palin.cl: -------------------------------------------------------------------------------- 1 | class Main inherits IO { 2 | main(): Object { 3 | { 4 | out_string("Enter string to check for palindrome\n"); 5 | let str : String <- in_string() in 6 | if (str = reverse(str)) then 7 | out_string("String is a Palindrome\n") 8 | else 9 | out_string("String is not a Palindrome\n") 10 | fi; 11 | } 12 | }; 13 | 14 | reverse(str : String): String { 15 | if (str.length() = 1) then str 16 | else (new String).concat(str.substr(str.length()-1, 1)).concat(reverse(str.substr(0, str.length()-1))) 17 | fi 18 | }; 19 | }; 20 | -------------------------------------------------------------------------------- /lexer/src/test_cases/prod.cl: -------------------------------------------------------------------------------- 1 | class Main inherits IO { 2 | main() : Object { 3 | { 4 | out_string("Enter number of numbers to multiply\n"); 5 | out_int(prod(in_int())); 6 | out_string("\n"); 7 | } 8 | }; 9 | 10 | prod(i : Int) : Int { 11 | let y : Int <- 1 in { 12 | while (not (i = 0) ) loop { 13 | out_string("Enter Number: "); 14 | y <- y * in_int(); 15 | i <- i - 1; 16 | } 17 | pool; 18 | y; 19 | } 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /lexer/src/test_cases/test1.cl: -------------------------------------------------------------------------------- 1 | class Main { 2 | str <- "The big brown fox 3 | jumped over the fence"; 4 | main() : Object { 5 | { 6 | out_string("Yay! This is the newest shites ); 7 | } 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /lexer/src/test_cases/test2.cl: -------------------------------------------------------------------------------- 1 | class Main inherits IO { 2 | str <- "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; 3 | main() : Object { 4 | { 5 | out_string("Enter number of numbers to multiply\n"); 6 | out_int(prod(in_int())); 7 | out_string("\n"); 8 | } 9 | }; 10 | prod(i : Int) : Int { 11 | let y : Int <- 1 in { 12 | while (not (i = 0) ) loop { 13 | out_string("Enter Number: "); 14 | y <- y * in_int(); 15 | i <- i - 1; 16 | } 17 | y; 18 | } 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /lexer/src/test_cases/test3.cl: -------------------------------------------------------------------------------- 1 | class Error() { 2 | 3 | (* There was once a comment, 4 | that was quite long. 5 | But, the reader soon discovered that 6 | the comment was indeed longer than 7 | previously assumed. Now, the reader 8 | was in a real dilemma; is the comment 9 | ever gonna end? If I stop reading, will 10 | it end? 11 | He started imagining all sorts of things. 12 | He thought about heisenberg's cat and how 13 | how that relates to the end of the sentence. 14 | He thought to himself "I'm gonna stop reading". 15 | "If I keep reading this comment, I'm gonna know 16 | the fate of this sentence; That will be disastorous." 17 | He knew that such a comment was gonna extend to 18 | another file. It was too awesome to be contained in 19 | a single file. And he would have kept reading too... 20 | if only... 21 | cool wasn't a super-duper-fab-awesomest language; 22 | but cool is that language; 23 | "This comment shall go not cross this file" said cool. 24 | Alas! The reader could read no more. 25 | There was once a comment, 26 | that was quite long. 27 | But, the reader soon discovered that 28 | the comment was indeed longer than 29 | previously assumed. Now, the reader 30 | was in a real dilemma; is the comment 31 | ever gonna end? If I stop reading, will 32 | it end? 33 | He started imagining all sorts of things. 34 | He thought about heisenberg's cat and how 35 | how that relates to the end of the sentence. 36 | He thought to himself "I'm gonna stop reading". 37 | "If I keep reading this comment, I'm gonna know 38 | the fate of this sentence; That will be disastorous." 39 | He knew that such a comment was gonna extend to 40 | another file. It was too awesome to be contained in 41 | a single file. And he would have kept reading too... 42 | if only... 43 | cool wasn't a super-duper-fab-awesomest language; 44 | but cool is that language; 45 | "This comment shall go not cross this file" said cool. 46 | Alas! The reader could read no more. -------------------------------------------------------------------------------- /lexer/src/test_cases/test4.cl: -------------------------------------------------------------------------------- 1 | classs Doom { 2 | i : Int <- 0; 3 | main() : Object { 4 | if i = 0 then out_string("This is da real *h*t") 5 | 6 | -------------------------------------------------------------------------------- /lexer/src/test_cases/test5.txt: -------------------------------------------------------------------------------- 1 | "lkjdsafkljdsalfj\u0000dsafdsaf\u0000djafslkjdsalf\nsdajf\" lkjfdsasdkjfl"123 2 | adsfasklj 3 | LKldsajf 4 | "lkdsajf" -------------------------------------------------------------------------------- /lexer/src/test_cases/text.txt: -------------------------------------------------------------------------------- 1 | "kjas\"lnnsdj\nfljrdsaf" 2 | # 3 | $ 4 | $ 5 | % 6 | % 7 | "alkjfldajf""dasfadsf -------------------------------------------------------------------------------- /parser/Makefile: -------------------------------------------------------------------------------- 1 | MAKE = make 2 | %: build 3 | 4 | build: 5 | $(MAKE) -C ./src/grammar -f Makefile 6 | $(MAKE) -C ./src/java -f Makefile 7 | 8 | clean: 9 | $(MAKE) -C ./src/grammar -f Makefile clean 10 | $(MAKE) -C ./src/java -f Makefile clean 11 | -------------------------------------------------------------------------------- /parser/README.md: -------------------------------------------------------------------------------- 1 | # COOL Compiler # 2 | 3 | The parser "CoolParser.g4" conforms to the language specification. The description of the implementation and design decisions 4 | is split across the following categories: 5 | 6 | - Precedence of operators 7 | - Handling lists. 8 | - Handling optional entities. 9 | - LET expression 10 | - Typecasting Constants 11 | 12 | ### Precedence of Operators 13 | 14 | The operators rules are listed in the order of correct precedence. According to the "COOL" language specification the precedence rules are as follows: 15 | 16 | . 17 | @ 18 | ~ 19 | isvoid 20 | * / 21 | + - 22 | <= < = 23 | not 24 | <- 25 | 26 | All the parser rules are in keeping with this order. 27 | 28 | 29 | ### Handling lists 30 | 31 | The grammar specification makes it apparent that several kinds of lists (of language constructs) need to be handled separately. For example, we encounter two kinds of expression lists. One of the lists occurs in a block. Each list item is delimeted by a `;`. Note that each expression is **terminated** by a semicolon. 32 | On the other hand, the other expression list is comma separated. We also note that the first list, wherever it can make an appearance, is not optional. While the second kind is. 33 | In short, 34 | 35 | expr, [[, expr]]* // is optional in some instances 36 | [[expr;]]+ // is not optional wherver it occurs 37 | 38 | Other kinds are of lists are : 39 | 40 | - `class_list` : The whole program is one giant class list having at least one element. 41 | - `feature_list`: A class is populated with features (method and attributes) 42 | - `formal_list`: Each method invocation accepts a formal list. 43 | - `expression_list` 44 | - `block_expr_list` 45 | - `branch_list`: All the **Switch case** cases comprise a branch list. 46 | - `let_list`: The let construct accepts a list of attributes. 47 | 48 | 49 | ### Handling Optional Entities 50 | 51 | In the grammar we observe, in multiple places, that some constructs are optional. To handle this construct we have rules which check for presence/absence of these constructs. In each case, a returns a tree node. In case the optional construct is omitted, the tree node is returned with an empty child. 52 | 53 | In the feature rule, we observer that assigment is optional. This is handled by using two rules ; one with assignment and the other without. 54 | 55 | ### LET expression 56 | 57 | Let expressions are recursive beasts. They accept attribute lists. Ofcourse, we resort to a looping method to cycle through all the attributes to the list. Furthermore, all the attributes are concatenated together. 58 | 59 | ### Typecasting Constants 60 | 61 | We get a string stream for tokens. To get the integer value of the `INT_CONST` or boolean value of the `BOOL_CONST` we have to do appropriate typecasting. The implementation is fairly self explanatory in this regard. Note that in the case of `BOOL_CONST`, we are not really type casting. We are analyzing the string input and returning a boolean value as a result of the analysis. 62 | 63 | * * * 64 | 65 | ### Working Programs 66 | 67 | - `fib.cl` : Demonstrates nesting of expressions. Essentially using the `(expr)` RHS of the expression rule. It also demonstrates a feature list present within a class. The program is succesfully parsed. 68 | - `atoi.cl` : A long and complex cool program. Comments have been added to the relevant sections. A featureless class is also added to the code. 69 | - `print-cool.cl` : Very adequately presents the dispatch constructs. 70 | 71 | ### Erroneous Programs 72 | 73 | - `isprime.cl` : The lexical analyzer does not throw an error. The parser throws an error because of the incorrect format of listing formals. 74 | - `err2.cl` : In this case the lexer throws an error. Note that if the lexer did approve the invalid class name as valid then the parser wouldn't be able to spot the error. This means that both are essential components in the compilation process. Also, the lexers role is not only to tokenize the input character stream. 75 | - `prod.cl` : We use a TypeID in place of an ObjectID in a method invocation. -------------------------------------------------------------------------------- /parser/src/grammar/CoolParser.g4: -------------------------------------------------------------------------------- 1 | parser grammar CoolParser; 2 | 3 | options { 4 | tokenVocab = CoolLexer; 5 | } 6 | 7 | @header{ 8 | import cool.AST; 9 | import java.util.List; 10 | } 11 | 12 | @members{ 13 | String filename; 14 | public void setFilename(String f){ 15 | filename = f; 16 | } 17 | 18 | /* 19 | DO NOT EDIT THE FILE ABOVE THIS LINE 20 | Add member functions, variables below. 21 | */ 22 | 23 | } 24 | 25 | /* 26 | Add Grammar rules and appropriate actions for building AST below. 27 | */ 28 | 29 | program returns [AST.program value] : 30 | cl=class_list EOF 31 | { 32 | $value = new AST.program($cl.value, $cl.value.get(0).lineNo); 33 | } 34 | ; 35 | 36 | /* [[class]]+ */ 37 | class_list returns [ArrayList value] 38 | @init 39 | { 40 | $value = new ArrayList(); 41 | } 42 | : 43 | (c = class_ SEMICOLON {$value.add($c.value);})+ 44 | ; 45 | 46 | class_ returns [AST.class_ value] : 47 | /* class TYPE { [[feature]]* } */ 48 | st=CLASS type=TYPEID LBRACE fl=feature_list RBRACE 49 | { 50 | $value = new AST.class_($type.getText(), filename, "Object", $feature_list.value, $st.getLine()); 51 | } 52 | /* class TYPE [inherits TYPE] { [[feature]]* } */ 53 | | st=CLASS type=TYPEID INHERITS p_type=TYPEID LBRACE fl=feature_list RBRACE 54 | { 55 | $value = new AST.class_($type.getText(), filename, $p_type.getText(), $feature_list.value, $st.getLine()); 56 | } 57 | ; 58 | 59 | 60 | feature_list returns [ArrayList value] 61 | @init 62 | { 63 | $value = new ArrayList(); 64 | } 65 | : 66 | (c = feature SEMICOLON {$value.add($c.value);})* 67 | ; 68 | 69 | feature returns [AST.feature value] : 70 | /* ID: TYPE */ 71 | func = method 72 | { 73 | $value = $func.value; 74 | } 75 | | var = attr 76 | { 77 | $value = $var.value; 78 | } 79 | ; 80 | 81 | attr returns [AST.attr value] : 82 | id=OBJECTID COLON type=TYPEID 83 | { 84 | $value = new AST.attr($id.getText(), $type.getText(), new AST.no_expr($id.getLine()), $id.getLine()); 85 | } 86 | /* ID: TYPE [<- expr] */ 87 | | id=OBJECTID COLON type=TYPEID ASSIGN expr=expression 88 | { 89 | $value = new AST.attr($id.getText(), $type.getText(), $expr.value, $id.getLine()); 90 | } 91 | ; 92 | 93 | method returns [AST.method value] : 94 | id=OBJECTID LPAREN RPAREN COLON type=TYPEID LBRACE expr=expression RBRACE 95 | { 96 | $value = new AST.method($id.getText(), new ArrayList(), $type.getText(), $expr.value, $id.getLine()); 97 | } 98 | | id=OBJECTID LPAREN fr_list=formal_list RPAREN COLON type=TYPEID LBRACE expr=expression RBRACE 99 | { 100 | $value = new AST.method($id.getText(), $fr_list.value, $type.getText(), $expr.value, $id.getLine()); 101 | } 102 | ; 103 | 104 | 105 | formal_list returns [ArrayList value] 106 | @init 107 | { 108 | $value = new ArrayList(); 109 | } 110 | : 111 | c = formal {$value.add($c.value);} 112 | 113 | (COMMA y = formal {$value.add($y.value);})* 114 | ; 115 | 116 | 117 | formal returns [AST.formal value] : 118 | id=OBJECTID COLON type=TYPEID 119 | { 120 | $value = new AST.formal($id.getText(), $type.getText(), $id.getLine()) ; 121 | } 122 | ; 123 | 124 | /* [expr [[, expr]]* ] */ 125 | expression_list returns [ArrayList value] 126 | @init 127 | { 128 | $value = new ArrayList(); 129 | } 130 | : 131 | ( expr = expression {$value.add($expr.value);} (COMMA expr = expression {$value.add($expr.value);})* )? 132 | ; 133 | 134 | block_expr_list returns [ArrayList value] 135 | @init 136 | { 137 | $value = new ArrayList(); 138 | } 139 | : 140 | (expr = expression SEMICOLON {$value.add($expr.value);})+ 141 | ; 142 | 143 | branch_list returns [ArrayList value] 144 | @init 145 | { 146 | $value = new ArrayList(); 147 | } 148 | : 149 | (br = branch SEMICOLON {$value.add($br.value);})+ 150 | ; 151 | 152 | branch returns [AST.branch value] : 153 | id=OBJECTID COLON type=TYPEID DARROW expr=expression SEMICOLON 154 | { 155 | $value = new AST.branch($id.getText(), $type.getText(), $expr.value, $id.getLine()); 156 | } 157 | ; 158 | 159 | 160 | 161 | let_list returns [ArrayList value] 162 | @init 163 | { 164 | $value = new ArrayList(); 165 | } 166 | : 167 | at_un = attr { $value.add($at_un.value); } 168 | (COMMA at_deux = attr {$value.add($at_deux.value);})* 169 | ; 170 | 171 | 172 | expression returns [AST.expression value] : 173 | /*expr.ID([expr [[, expr]]* ]) */ 174 | expr=expression DOT id=OBJECTID LPAREN expr_list = expression_list RPAREN 175 | { 176 | $value = new AST.dispatch($expr.value, $id.getText(), $expr_list.value, $expr.value.lineNo); 177 | } 178 | /*expr[@TYPE].ID([expr [[, expr]]* ]) */ 179 | | expr=expression ATSYM type=TYPEID DOT id=OBJECTID LPAREN expr_list = expression_list RPAREN 180 | { 181 | $value = new AST.static_dispatch($expr.value, $type.getText(), $id.getText(), $expr_list.value, $expr.value.lineNo); 182 | } 183 | /*ID ( [expr [[, expr]]* ]) */ 184 | | id=OBJECTID LPAREN expr_list = expression_list RPAREN 185 | { 186 | $value = new AST.dispatch(new AST.object("self" , $id.getLine()) , $id.getText() , $expr_list.value , $id.getLine()); 187 | } 188 | /* ~ expr */ 189 | | st=TILDE e1=expression 190 | { 191 | $value = new AST.comp($e1.value, $st.getLine()); 192 | } 193 | /* isvoid expr */ 194 | | st=ISVOID expr=expression 195 | { 196 | $value = new AST.isvoid($expr.value, $st.getLine()); 197 | } 198 | /* expr * expr */ 199 | | e1=expression STAR e2=expression 200 | { 201 | $value = new AST.mul($e1.value, $e2.value, $e1.value.lineNo); 202 | } 203 | /* expr / expr */ 204 | | e1=expression SLASH e2=expression 205 | { 206 | $value = new AST.divide($e1.value, $e2.value, $e1.value.lineNo); 207 | } 208 | /* expr + expr */ 209 | | e1=expression PLUS e2=expression 210 | { 211 | $value = new AST.plus($e1.value, $e2.value, $e1.value.lineNo); 212 | } 213 | /* expr - expr */ 214 | | e1=expression MINUS e2=expression 215 | { 216 | $value = new AST.sub($e1.value, $e2.value, $e1.value.lineNo); 217 | } 218 | /* expr < expr */ 219 | | e1=expression LT e2=expression 220 | { 221 | $value = new AST.lt($e1.value, $e2.value, $e1.value.lineNo); 222 | } 223 | /* expr <= expr */ 224 | | e1=expression LE e2=expression 225 | { 226 | $value = new AST.leq($e1.value, $e2.value, $e1.value.lineNo); 227 | } 228 | /* expr = expr */ 229 | | e1=expression EQUALS e2=expression 230 | { 231 | $value = new AST.eq($e1.value, $e2.value, $e1.value.lineNo); 232 | } 233 | /* not expr */ 234 | | st=NOT e1=expression 235 | { 236 | $value = new AST.neg($e1.value, $st.getLine()); 237 | } 238 | /* ID <- expr */ 239 | | id=OBJECTID ASSIGN expr=expression 240 | { 241 | $value = new AST.assign($id.getText(), $expr.value, $id.getLine()); 242 | } 243 | /* if expr then expr else expr fi*/ 244 | | st=IF predicate=expression THEN ifbody=expression ELSE elsebody=expression FI 245 | { 246 | $value = new AST.cond($predicate.value, $ifbody.value, $elsebody.value, $st.getLine()); 247 | 248 | } 249 | /* while expr loop expr pool */ 250 | | st=WHILE predicate=expression LOOP body=expression POOL 251 | { 252 | $value = new AST.loop($predicate.value, $body.value, $st.getLine()); 253 | } 254 | /* { [[expr]]* } */ 255 | | st=LBRACE el=block_expr_list RBRACE // define 256 | { 257 | $value = new AST.block($el.value, $st.getLine()); 258 | } 259 | /* let ID:TYPE [[, ID : TYPE [<- expr]]]* in expr */ 260 | | st=LET ll=let_list IN e1=expression 261 | { 262 | $value = $e1.value; 263 | AST.attr this_attr; 264 | for(int i = $ll.value.size() - 1; i >= 0; --i) 265 | { 266 | this_attr = $ll.value.get(i); 267 | $value = new AST.let(this_attr.name, this_attr.typeid, this_attr.value, $value, $st.getLine()); 268 | } 269 | } 270 | /* case expr of [[ID : TYPE => expr;]]+ esac */ 271 | | st=CASE predicate=expression OF bl=branch_list ESAC 272 | { // define 273 | $value = new AST.typcase($predicate.value, $bl.value, $st.getLine()); 274 | } 275 | /* new TYPE */ 276 | | st=NEW type=TYPEID 277 | { 278 | $value = new AST.new_($type.getText(), $st.getLine()); 279 | } 280 | /* (expr) */ 281 | | st=LPAREN e1=expression RPAREN 282 | { 283 | $value = $e1.value; 284 | } 285 | /* ID */ 286 | | id=OBJECTID 287 | { 288 | $value = new AST.object($id.getText(), $id.getLine()); 289 | } 290 | /* integer */ 291 | | v=INT_CONST 292 | { 293 | $value = new AST.int_const(Integer.parseInt($v.getText()), $v.getLine()); 294 | } 295 | /* string */ 296 | | v=STR_CONST 297 | { 298 | $value = new AST.string_const($v.getText(), $v.getLine()); 299 | } 300 | /* true / false */ 301 | | v=BOOL_CONST 302 | { 303 | $value = new AST.bool_const($v.getText().charAt(0)=='t', $v.getLine()); 304 | } 305 | ; 306 | -------------------------------------------------------------------------------- /parser/src/grammar/Makefile: -------------------------------------------------------------------------------- 1 | ANTLR_JAR = /usr/local/lib/antlr-4.5-complete.jar 2 | ANTLR = java -jar $(ANTLR_JAR) 3 | ANTLR_OUT_DIR = ../java 4 | PACKAGE = cool 5 | ANTLR_FLAGS = -no-listener -visitor -package $(PACKAGE) 6 | LEXER = CoolLexer 7 | PARSER = CoolParser 8 | 9 | %: all 10 | 11 | all: 12 | $(ANTLR) $(ANTLR_FLAGS) -o $(ANTLR_OUT_DIR)/$(PACKAGE)/ -lib $(ANTLR_OUT_DIR)/$(PACKAGE)/ $(PARSER).g4 13 | 14 | clean: 15 | rm -rf ../java/$(PACKAGE)/*.class 16 | rm -rf ../java/$(PACKAGE)/$(PARSER)*.java 17 | rm -rf ../java/$(PACKAGE)/$(PARSER)*.tokens 18 | -------------------------------------------------------------------------------- /parser/src/java/Makefile: -------------------------------------------------------------------------------- 1 | ANTLR_JAR = /usr/local/lib/antlr-4.5-complete.jar 2 | 3 | %: all 4 | 5 | all: 6 | javac -cp $(ANTLR_JAR) -Xlint cool/*.java 7 | 8 | clean: 9 | -------------------------------------------------------------------------------- /parser/src/java/cool/AST.java: -------------------------------------------------------------------------------- 1 | package cool; 2 | import java.util.List; 3 | public class AST{ 4 | public static class ASTNode { 5 | int lineNo; 6 | } 7 | public static String sp = " "; 8 | 9 | static String escapeSpecialCharacters(String text) { 10 | return 11 | text 12 | .replaceAll("\\\\", "\\\\\\\\") 13 | .replaceAll("\n", "\\\\n") 14 | .replaceAll("\t", "\\\\t") 15 | .replaceAll("\b", "\\\\b") 16 | .replaceAll("\f", "\\\\f") 17 | .replaceAll("\"", "\\\\\"") 18 | .replaceAll("\r", "\\\\015") 19 | .replaceAll("\033","\\\\033") 20 | .replaceAll("\001","\\\\001") 21 | .replaceAll("\002","\\\\002") 22 | .replaceAll("\003","\\\\003") 23 | .replaceAll("\004","\\\\004") 24 | .replaceAll("\022","\\\\022") 25 | .replaceAll("\013","\\\\013") 26 | .replaceAll("\000", "\\\\000") 27 | ; 28 | } 29 | 30 | 31 | public static class expression extends ASTNode { 32 | String type; 33 | public expression(){ 34 | type = "_no_type"; 35 | } 36 | String getString(String space){ 37 | return ""; 38 | }; 39 | } 40 | public static class no_expr extends expression { 41 | public no_expr(int l){ 42 | lineNo = l; 43 | } 44 | String getString(String space){ 45 | return space+"#"+lineNo+"\n"+space+"_no_expr\n"+space+": "+type; 46 | } 47 | } 48 | public static class bool_const extends expression{ 49 | public boolean value; 50 | public bool_const(boolean v, int l){ 51 | value = v; 52 | lineNo = l; 53 | } 54 | String getString(String space){ 55 | return space+"#"+lineNo+"\n"+space+"_bool\n"+space+sp+(value?"1":"0")+"\n"+space+": "+type; 56 | } 57 | } 58 | public static class string_const extends expression{ 59 | public String value; 60 | public string_const(String v, int l){ 61 | value = v; 62 | lineNo = l; 63 | } 64 | String getString(String space){ 65 | return space+"#"+lineNo+"\n"+space+"_string\n"+space+sp+"\""+escapeSpecialCharacters(value)+"\""+"\n"+space+": "+type; 66 | } 67 | } 68 | 69 | public static class int_const extends expression{ 70 | public int value; 71 | public int_const(int v, int l){ 72 | value = v; 73 | lineNo = l; 74 | } 75 | String getString(String space){ 76 | return space+"#"+lineNo+"\n"+space+"_int\n"+space+sp+value+"\n"+space+": "+type; 77 | } 78 | } 79 | 80 | public static class object extends expression{ 81 | public String name; 82 | public object(String v, int l){ 83 | name = v; 84 | lineNo = l; 85 | } 86 | String getString(String space){ 87 | return space+"#"+lineNo+"\n"+space+"_object\n"+space+sp+name+"\n"+space+": "+type; 88 | } 89 | } 90 | public static class comp extends expression{ 91 | public expression e1; 92 | public comp(expression v, int l){ 93 | e1 = v; 94 | lineNo = l; 95 | } 96 | String getString(String space){ 97 | return space+"#"+lineNo+"\n"+space+"_comp\n"+e1.getString(space+sp)+"\n"+space+": "+type; 98 | } 99 | } 100 | public static class eq extends expression{ 101 | public expression e1; 102 | public expression e2; 103 | public eq(expression v1, expression v2, int l){ 104 | e1=v1; 105 | e2=v2; 106 | lineNo = l; 107 | } 108 | String getString(String space){ 109 | return space+"#"+lineNo+"\n"+space+"_eq\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 110 | } 111 | } 112 | 113 | 114 | public static class leq extends expression{ 115 | public expression e1; 116 | public expression e2; 117 | public leq(expression v1, expression v2, int l){ 118 | e1 = v1; 119 | e2 = v2; 120 | lineNo = l; 121 | } 122 | String getString(String space){ 123 | return space+"#"+lineNo+"\n"+space+"_leq\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 124 | } 125 | } 126 | 127 | public static class lt extends expression{ 128 | public expression e1; 129 | public expression e2; 130 | public lt(expression v1, expression v2, int l){ 131 | e1 = v1; 132 | e2 = v2; 133 | lineNo = l; 134 | } 135 | String getString(String space){ 136 | return space+"#"+lineNo+"\n"+space+"_lt\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 137 | } 138 | } 139 | public static class neg extends expression{ 140 | public expression e1; 141 | public neg(expression v, int l){ 142 | e1 = v; 143 | lineNo = l; 144 | } 145 | String getString(String space){ 146 | return space+"#"+lineNo+"\n"+space+"_neg\n"+e1.getString(space+sp)+"\n"+space+": "+type; 147 | } 148 | } 149 | public static class divide extends expression{ 150 | public expression e1; 151 | public expression e2; 152 | public divide(expression v1, expression v2, int l){ 153 | e1 = v1; 154 | e2 = v2; 155 | lineNo = l; 156 | } 157 | String getString(String space){ 158 | return space+"#"+lineNo+"\n"+space+"_divide\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 159 | } 160 | } 161 | public static class mul extends expression{ 162 | public expression e1; 163 | public expression e2; 164 | public mul(expression v1, expression v2, int l){ 165 | e1 = v1; 166 | e2 = v2; 167 | lineNo = l; 168 | } 169 | String getString(String space){ 170 | return space+"#"+lineNo+"\n"+space+"_mul\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 171 | } 172 | } 173 | public static class sub extends expression{ 174 | public expression e1; 175 | public expression e2; 176 | public sub(expression v1, expression v2, int l){ 177 | e1 = v1; 178 | e2 = v2; 179 | lineNo = l; 180 | } 181 | String getString(String space){ 182 | return space+"#"+lineNo+"\n"+space+"_sub\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 183 | } 184 | } 185 | public static class plus extends expression{ 186 | public expression e1; 187 | public expression e2; 188 | public plus(expression v1, expression v2, int l){ 189 | e1 = v1; 190 | e2 = v2; 191 | lineNo = l; 192 | } 193 | String getString(String space){ 194 | return space+"#"+lineNo+"\n"+space+"_plus\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 195 | } 196 | } 197 | public static class isvoid extends expression{ 198 | public expression e1; 199 | public isvoid(expression v, int l){ 200 | e1 = v; 201 | lineNo = l; 202 | } 203 | String getString(String space){ 204 | return space+"#"+lineNo+"\n"+space+"_isvoid\n"+e1.getString(space+sp)+"\n"+space+": "+type; 205 | } 206 | } 207 | public static class new_ extends expression{ 208 | public String typeid; 209 | public new_(String t, int l){ 210 | typeid = t; 211 | lineNo = l; 212 | } 213 | String getString(String space){ 214 | return space+"#"+lineNo+"\n"+space+"_new\n"+space+sp+typeid+"\n"+space+": "+type; 215 | } 216 | } 217 | public static class assign extends expression{ 218 | public String name; 219 | public expression e1; 220 | public assign(String n, expression v1, int l){ 221 | name = n; 222 | e1 = v1; 223 | lineNo = l; 224 | } 225 | String getString(String space){ 226 | return space+"#"+lineNo+"\n"+space+"_assign\n"+space+sp+name+"\n"+e1.getString(space+sp)+"\n"+space+": "+type; 227 | } 228 | } 229 | public static class block extends expression{ 230 | public List l1; 231 | public block(List v1, int l){ 232 | l1 = v1; 233 | lineNo = l; 234 | } 235 | String getString(String space){ 236 | String str = space+"#"+lineNo+"\n"+space+"_block\n"; 237 | for (expression e1 : l1){ 238 | str += e1.getString(space+sp)+"\n"; 239 | } 240 | str+=space+": "+type; 241 | return str; 242 | } 243 | } 244 | public static class loop extends expression{ 245 | public expression predicate; 246 | public expression body; 247 | public loop(expression v1, expression v2, int l){ 248 | predicate = v1; 249 | body = v2; 250 | lineNo = l; 251 | } 252 | String getString(String space){ 253 | return space+"#"+lineNo+"\n"+space+"_loop\n"+predicate.getString(space+sp)+"\n"+body.getString(space+sp)+"\n"+space+": "+type; 254 | } 255 | } 256 | public static class cond extends expression{ 257 | public expression predicate; 258 | public expression ifbody; 259 | public expression elsebody; 260 | public cond(expression v1, expression v2, expression v3, int l){ 261 | predicate = v1; 262 | ifbody = v2; 263 | elsebody = v3; 264 | lineNo = l; 265 | } 266 | String getString(String space){ 267 | return space+"#"+lineNo+"\n"+space+"_cond\n"+predicate.getString(space+sp)+"\n"+ifbody.getString(space+sp)+"\n"+elsebody.getString(space+sp)+"\n"+space+": "+type; 268 | } 269 | } 270 | public static class let extends expression{ 271 | public String name; 272 | public String typeid; 273 | public expression value; 274 | public expression body; 275 | public let(String n, String t, expression v, expression b, int l){ 276 | name = n; 277 | typeid = t; 278 | value = v; 279 | body = b; 280 | } 281 | String getString(String space){ 282 | return space+"#"+lineNo+"\n"+space+"_let\n"+space+sp+name+"\n"+space+sp+typeid+"\n"+value.getString(space+sp)+"\n"+body.getString(space+sp)+"\n"+space+": "+type; 283 | } 284 | } 285 | public static class dispatch extends expression{ 286 | public expression caller; 287 | public String name; 288 | public List actuals; 289 | public dispatch(expression v1, String n, List a, int l){ 290 | caller = v1; 291 | name = n; 292 | actuals = a; 293 | lineNo = l; 294 | } 295 | String getString(String space){ 296 | String str; 297 | str = space+"#"+lineNo+"\n"+space+"_dispatch\n"+caller.getString(space+sp)+"\n"+space+sp+name+"\n"+space+sp+"(\n"; 298 | for ( expression e1 : actuals ) { 299 | str += e1.getString(space+sp)+"\n"; 300 | } 301 | str+=space+sp+")\n"+space+": "+type; 302 | return str; 303 | } 304 | } 305 | public static class static_dispatch extends expression{ 306 | public expression caller; 307 | public String typeid; 308 | public String name; 309 | public List actuals; 310 | public static_dispatch(expression v1, String t, String n, List a, int l){ 311 | caller = v1; 312 | typeid = t; 313 | name = n; 314 | actuals = a; 315 | lineNo = l; 316 | } 317 | String getString(String space){ 318 | String str; 319 | str = space+"#"+lineNo+"\n"+space+"_static_dispatch\n"+caller.getString(space+sp)+"\n"+space+sp+typeid+"\n"+space+sp+name+"\n"+space+sp+"(\n"; 320 | for ( expression e1 : actuals ) { 321 | str += e1.getString(space+sp)+"\n"; 322 | } 323 | str+=space+sp+")\n"+space+": "+type; 324 | return str; 325 | } 326 | } 327 | public static class typcase extends expression{ 328 | public expression predicate; 329 | public List branches; 330 | public typcase(expression p, List b, int l){ 331 | predicate = p; 332 | branches = b; 333 | lineNo = l; 334 | } 335 | String getString(String space){ 336 | String str = space+"#"+lineNo+"\n"+space+"_typcase\n"+predicate.getString(space+sp)+"\n"; 337 | for ( branch b1 : branches ) { 338 | str += b1.getString(space+sp)+"\n"; 339 | } 340 | str += space+": "+type; 341 | return str; 342 | } 343 | } 344 | public static class branch extends ASTNode { 345 | public String name; 346 | public String type; 347 | public expression value; 348 | public branch(String n, String t, expression v, int l){ 349 | name = n; 350 | type = t; 351 | value = v; 352 | lineNo = l; 353 | } 354 | String getString(String space){ 355 | return space+"#"+lineNo+"\n"+space+"_branch\n"+space+sp+name+"\n"+space+sp+type+"\n"+value.getString(space+sp); 356 | } 357 | } 358 | public static class formal extends ASTNode { 359 | public String name; 360 | public String typeid; 361 | public formal(String n, String t, int l){ 362 | name = n; 363 | typeid = t; 364 | lineNo = l; 365 | } 366 | String getString(String space){ 367 | return space+"#"+lineNo+"\n"+space+"_formal\n"+space+sp+name+"\n"+space+sp+typeid; 368 | } 369 | } 370 | public static class feature extends ASTNode { 371 | public feature(){ 372 | } 373 | String getString(String space){ 374 | return ""; 375 | } 376 | 377 | } 378 | public static class method extends feature { 379 | public String name; 380 | public List formals; 381 | public String typeid; 382 | public expression body; 383 | public method(String n, List f, String t, expression b, int l){ 384 | name = n; 385 | formals = f; 386 | typeid = t; 387 | body = b; 388 | lineNo = l; 389 | } 390 | String getString(String space){ 391 | String str = space+"#"+lineNo+"\n"+space+"_method\n"+space+sp+name+"\n"; 392 | for ( formal f : formals ) { 393 | str += f.getString(space+sp)+"\n"; 394 | } 395 | str += space+sp+typeid+"\n"+body.getString(space+sp); 396 | return str; 397 | } 398 | } 399 | public static class attr extends feature { 400 | public String name; 401 | public String typeid; 402 | public expression value; 403 | public attr(String n, String t, expression v, int l){ 404 | name = n; 405 | typeid = t; 406 | value = v; 407 | lineNo = l; 408 | } 409 | String getString(String space){ 410 | return space+"#"+lineNo+"\n"+space+"_attr\n"+space+sp+name+"\n"+space+sp+typeid+"\n"+value.getString(space+sp); 411 | } 412 | } 413 | public static class class_ extends ASTNode { 414 | public String name; 415 | public String filename; 416 | public String parent; 417 | public List features; 418 | public class_(String n, String f, String p, List fs, int l){ 419 | name = n; 420 | filename = f; 421 | parent = p; 422 | features = fs; 423 | lineNo = l; 424 | } 425 | String getString(String space){ 426 | String str; 427 | str = space+"#"+lineNo+"\n"+space+"_class\n"+space+sp+name+"\n"+space+sp+parent+"\n"+space+sp+"\""+filename+"\""+"\n"+space+sp+"(\n"; 428 | for ( feature f : features ) { 429 | str += f.getString(space+sp)+"\n"; 430 | } 431 | str += space+sp+")"; 432 | return str; 433 | } 434 | } 435 | public static class program extends ASTNode { 436 | public List classes; 437 | public program(List c, int l){ 438 | classes = c; 439 | lineNo = l; 440 | } 441 | String getString(String space){ 442 | String str; 443 | str = space+"#"+lineNo+"\n"+space+"_program"; 444 | for ( class_ c : classes ) { 445 | str += "\n"+c.getString(space+sp); 446 | } 447 | 448 | return str; 449 | } 450 | } 451 | } 452 | -------------------------------------------------------------------------------- /parser/src/java/cool/CoolLexer.tokens: -------------------------------------------------------------------------------- 1 | ERROR=1 2 | TYPEID=2 3 | OBJECTID=3 4 | BOOL_CONST=4 5 | INT_CONST=5 6 | STR_CONST=6 7 | LPAREN=7 8 | RPAREN=8 9 | COLON=9 10 | ATSYM=10 11 | SEMICOLON=11 12 | COMMA=12 13 | PLUS=13 14 | MINUS=14 15 | STAR=15 16 | SLASH=16 17 | TILDE=17 18 | LT=18 19 | EQUALS=19 20 | LBRACE=20 21 | RBRACE=21 22 | DOT=22 23 | DARROW=23 24 | LE=24 25 | ASSIGN=25 26 | CLASS=26 27 | ELSE=27 28 | FI=28 29 | IF=29 30 | IN=30 31 | INHERITS=31 32 | LET=32 33 | LOOP=33 34 | POOL=34 35 | THEN=35 36 | WHILE=36 37 | CASE=37 38 | ESAC=38 39 | OF=39 40 | NEW=40 41 | ISVOID=41 42 | NOT=42 43 | WS=43 44 | THEEND=44 45 | SINGLE_COMMENT=45 46 | COMMENT_CLOSE=46 47 | CLOSED=47 48 | COM_EOF=48 49 | NEWLINE=49 50 | ESC=50 51 | ESC_NULL=51 52 | STR_EOF=52 53 | ERR1=53 54 | ERR2=54 55 | ERR3=55 56 | LQUOTE=56 57 | NL=57 58 | TAB=58 59 | BACKSPAC=59 60 | LINEFEED=60 61 | SLASHN=61 62 | ESC_NL=62 63 | '('=7 64 | ')'=8 65 | ':'=9 66 | '@'=10 67 | ';'=11 68 | ','=12 69 | '+'=13 70 | '-'=14 71 | '*'=15 72 | '/'=16 73 | '~'=17 74 | '<'=18 75 | '='=19 76 | '{'=20 77 | '}'=21 78 | '.'=22 79 | '=>'=23 80 | '<='=24 81 | '<-'=25 82 | '*)'=46 83 | '\\t'=58 84 | '\\b'=59 85 | '\\f'=60 86 | '\\n'=61 87 | '\\\n'=62 88 | -------------------------------------------------------------------------------- /parser/src/java/cool/CoolParser.tokens: -------------------------------------------------------------------------------- 1 | ERROR=1 2 | TYPEID=2 3 | OBJECTID=3 4 | BOOL_CONST=4 5 | INT_CONST=5 6 | STR_CONST=6 7 | LPAREN=7 8 | RPAREN=8 9 | COLON=9 10 | ATSYM=10 11 | SEMICOLON=11 12 | COMMA=12 13 | PLUS=13 14 | MINUS=14 15 | STAR=15 16 | SLASH=16 17 | TILDE=17 18 | LT=18 19 | EQUALS=19 20 | LBRACE=20 21 | RBRACE=21 22 | DOT=22 23 | DARROW=23 24 | LE=24 25 | ASSIGN=25 26 | CLASS=26 27 | ELSE=27 28 | FI=28 29 | IF=29 30 | IN=30 31 | INHERITS=31 32 | LET=32 33 | LOOP=33 34 | POOL=34 35 | THEN=35 36 | WHILE=36 37 | CASE=37 38 | ESAC=38 39 | OF=39 40 | NEW=40 41 | ISVOID=41 42 | NOT=42 43 | WS=43 44 | THEEND=44 45 | SINGLE_COMMENT=45 46 | COMMENT_CLOSE=46 47 | CLOSED=47 48 | COM_EOF=48 49 | NEWLINE=49 50 | ESC=50 51 | ESC_NULL=51 52 | STR_EOF=52 53 | ERR1=53 54 | ERR2=54 55 | ERR3=55 56 | LQUOTE=56 57 | NL=57 58 | TAB=58 59 | BACKSPAC=59 60 | LINEFEED=60 61 | SLASHN=61 62 | ESC_NL=62 63 | '('=7 64 | ')'=8 65 | ':'=9 66 | '@'=10 67 | ';'=11 68 | ','=12 69 | '+'=13 70 | '-'=14 71 | '*'=15 72 | '/'=16 73 | '~'=17 74 | '<'=18 75 | '='=19 76 | '{'=20 77 | '}'=21 78 | '.'=22 79 | '=>'=23 80 | '<='=24 81 | '<-'=25 82 | '*)'=46 83 | '\\t'=58 84 | '\\b'=59 85 | '\\f'=60 86 | '\\n'=61 87 | '\\\n'=62 88 | -------------------------------------------------------------------------------- /parser/src/java/cool/CoolParserBaseVisitor.java: -------------------------------------------------------------------------------- 1 | // Generated from CoolParser.g4 by ANTLR 4.5 2 | package cool; 3 | 4 | import cool.AST; 5 | import java.util.List; 6 | 7 | import org.antlr.v4.runtime.misc.NotNull; 8 | import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; 9 | 10 | /** 11 | * This class provides an empty implementation of {@link CoolParserVisitor}, 12 | * which can be extended to create a visitor which only needs to handle a subset 13 | * of the available methods. 14 | * 15 | * @param The return type of the visit operation. Use {@link Void} for 16 | * operations with no return type. 17 | */ 18 | public class CoolParserBaseVisitor extends AbstractParseTreeVisitor implements CoolParserVisitor { 19 | /** 20 | * {@inheritDoc} 21 | * 22 | *

The default implementation returns the result of calling 23 | * {@link #visitChildren} on {@code ctx}.

24 | */ 25 | @Override public T visitProgram(CoolParser.ProgramContext ctx) { return visitChildren(ctx); } 26 | /** 27 | * {@inheritDoc} 28 | * 29 | *

The default implementation returns the result of calling 30 | * {@link #visitChildren} on {@code ctx}.

31 | */ 32 | @Override public T visitClass_list(CoolParser.Class_listContext ctx) { return visitChildren(ctx); } 33 | /** 34 | * {@inheritDoc} 35 | * 36 | *

The default implementation returns the result of calling 37 | * {@link #visitChildren} on {@code ctx}.

38 | */ 39 | @Override public T visitClass_(CoolParser.Class_Context ctx) { return visitChildren(ctx); } 40 | /** 41 | * {@inheritDoc} 42 | * 43 | *

The default implementation returns the result of calling 44 | * {@link #visitChildren} on {@code ctx}.

45 | */ 46 | @Override public T visitFeature_list(CoolParser.Feature_listContext ctx) { return visitChildren(ctx); } 47 | /** 48 | * {@inheritDoc} 49 | * 50 | *

The default implementation returns the result of calling 51 | * {@link #visitChildren} on {@code ctx}.

52 | */ 53 | @Override public T visitFeature(CoolParser.FeatureContext ctx) { return visitChildren(ctx); } 54 | /** 55 | * {@inheritDoc} 56 | * 57 | *

The default implementation returns the result of calling 58 | * {@link #visitChildren} on {@code ctx}.

59 | */ 60 | @Override public T visitAttr(CoolParser.AttrContext ctx) { return visitChildren(ctx); } 61 | /** 62 | * {@inheritDoc} 63 | * 64 | *

The default implementation returns the result of calling 65 | * {@link #visitChildren} on {@code ctx}.

66 | */ 67 | @Override public T visitMethod(CoolParser.MethodContext ctx) { return visitChildren(ctx); } 68 | /** 69 | * {@inheritDoc} 70 | * 71 | *

The default implementation returns the result of calling 72 | * {@link #visitChildren} on {@code ctx}.

73 | */ 74 | @Override public T visitFormal_list(CoolParser.Formal_listContext ctx) { return visitChildren(ctx); } 75 | /** 76 | * {@inheritDoc} 77 | * 78 | *

The default implementation returns the result of calling 79 | * {@link #visitChildren} on {@code ctx}.

80 | */ 81 | @Override public T visitFormal(CoolParser.FormalContext ctx) { return visitChildren(ctx); } 82 | /** 83 | * {@inheritDoc} 84 | * 85 | *

The default implementation returns the result of calling 86 | * {@link #visitChildren} on {@code ctx}.

87 | */ 88 | @Override public T visitExpression_list(CoolParser.Expression_listContext ctx) { return visitChildren(ctx); } 89 | /** 90 | * {@inheritDoc} 91 | * 92 | *

The default implementation returns the result of calling 93 | * {@link #visitChildren} on {@code ctx}.

94 | */ 95 | @Override public T visitBlock_expr_list(CoolParser.Block_expr_listContext ctx) { return visitChildren(ctx); } 96 | /** 97 | * {@inheritDoc} 98 | * 99 | *

The default implementation returns the result of calling 100 | * {@link #visitChildren} on {@code ctx}.

101 | */ 102 | @Override public T visitBranch_list(CoolParser.Branch_listContext ctx) { return visitChildren(ctx); } 103 | /** 104 | * {@inheritDoc} 105 | * 106 | *

The default implementation returns the result of calling 107 | * {@link #visitChildren} on {@code ctx}.

108 | */ 109 | @Override public T visitBranch(CoolParser.BranchContext ctx) { return visitChildren(ctx); } 110 | /** 111 | * {@inheritDoc} 112 | * 113 | *

The default implementation returns the result of calling 114 | * {@link #visitChildren} on {@code ctx}.

115 | */ 116 | @Override public T visitLet_list(CoolParser.Let_listContext ctx) { return visitChildren(ctx); } 117 | /** 118 | * {@inheritDoc} 119 | * 120 | *

The default implementation returns the result of calling 121 | * {@link #visitChildren} on {@code ctx}.

122 | */ 123 | @Override public T visitExpression(CoolParser.ExpressionContext ctx) { return visitChildren(ctx); } 124 | } -------------------------------------------------------------------------------- /parser/src/java/cool/CoolParserVisitor.java: -------------------------------------------------------------------------------- 1 | // Generated from CoolParser.g4 by ANTLR 4.5 2 | package cool; 3 | 4 | import cool.AST; 5 | import java.util.List; 6 | 7 | import org.antlr.v4.runtime.misc.NotNull; 8 | import org.antlr.v4.runtime.tree.ParseTreeVisitor; 9 | 10 | /** 11 | * This interface defines a complete generic visitor for a parse tree produced 12 | * by {@link CoolParser}. 13 | * 14 | * @param The return type of the visit operation. Use {@link Void} for 15 | * operations with no return type. 16 | */ 17 | public interface CoolParserVisitor extends ParseTreeVisitor { 18 | /** 19 | * Visit a parse tree produced by {@link CoolParser#program}. 20 | * @param ctx the parse tree 21 | * @return the visitor result 22 | */ 23 | T visitProgram(CoolParser.ProgramContext ctx); 24 | /** 25 | * Visit a parse tree produced by {@link CoolParser#class_list}. 26 | * @param ctx the parse tree 27 | * @return the visitor result 28 | */ 29 | T visitClass_list(CoolParser.Class_listContext ctx); 30 | /** 31 | * Visit a parse tree produced by {@link CoolParser#class_}. 32 | * @param ctx the parse tree 33 | * @return the visitor result 34 | */ 35 | T visitClass_(CoolParser.Class_Context ctx); 36 | /** 37 | * Visit a parse tree produced by {@link CoolParser#feature_list}. 38 | * @param ctx the parse tree 39 | * @return the visitor result 40 | */ 41 | T visitFeature_list(CoolParser.Feature_listContext ctx); 42 | /** 43 | * Visit a parse tree produced by {@link CoolParser#feature}. 44 | * @param ctx the parse tree 45 | * @return the visitor result 46 | */ 47 | T visitFeature(CoolParser.FeatureContext ctx); 48 | /** 49 | * Visit a parse tree produced by {@link CoolParser#attr}. 50 | * @param ctx the parse tree 51 | * @return the visitor result 52 | */ 53 | T visitAttr(CoolParser.AttrContext ctx); 54 | /** 55 | * Visit a parse tree produced by {@link CoolParser#method}. 56 | * @param ctx the parse tree 57 | * @return the visitor result 58 | */ 59 | T visitMethod(CoolParser.MethodContext ctx); 60 | /** 61 | * Visit a parse tree produced by {@link CoolParser#formal_list}. 62 | * @param ctx the parse tree 63 | * @return the visitor result 64 | */ 65 | T visitFormal_list(CoolParser.Formal_listContext ctx); 66 | /** 67 | * Visit a parse tree produced by {@link CoolParser#formal}. 68 | * @param ctx the parse tree 69 | * @return the visitor result 70 | */ 71 | T visitFormal(CoolParser.FormalContext ctx); 72 | /** 73 | * Visit a parse tree produced by {@link CoolParser#expression_list}. 74 | * @param ctx the parse tree 75 | * @return the visitor result 76 | */ 77 | T visitExpression_list(CoolParser.Expression_listContext ctx); 78 | /** 79 | * Visit a parse tree produced by {@link CoolParser#block_expr_list}. 80 | * @param ctx the parse tree 81 | * @return the visitor result 82 | */ 83 | T visitBlock_expr_list(CoolParser.Block_expr_listContext ctx); 84 | /** 85 | * Visit a parse tree produced by {@link CoolParser#branch_list}. 86 | * @param ctx the parse tree 87 | * @return the visitor result 88 | */ 89 | T visitBranch_list(CoolParser.Branch_listContext ctx); 90 | /** 91 | * Visit a parse tree produced by {@link CoolParser#branch}. 92 | * @param ctx the parse tree 93 | * @return the visitor result 94 | */ 95 | T visitBranch(CoolParser.BranchContext ctx); 96 | /** 97 | * Visit a parse tree produced by {@link CoolParser#let_list}. 98 | * @param ctx the parse tree 99 | * @return the visitor result 100 | */ 101 | T visitLet_list(CoolParser.Let_listContext ctx); 102 | /** 103 | * Visit a parse tree produced by {@link CoolParser#expression}. 104 | * @param ctx the parse tree 105 | * @return the visitor result 106 | */ 107 | T visitExpression(CoolParser.ExpressionContext ctx); 108 | } -------------------------------------------------------------------------------- /parser/src/java/cool/ParserTest.java: -------------------------------------------------------------------------------- 1 | package cool; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.IOException; 5 | import java.util.Arrays; 6 | 7 | import org.antlr.v4.runtime.ANTLRInputStream; 8 | import org.antlr.v4.runtime.CommonTokenStream; 9 | 10 | import org.antlr.v4.runtime.CommonToken; 11 | import org.antlr.v4.runtime.Token; 12 | import org.antlr.v4.runtime.BaseErrorListener; 13 | import org.antlr.v4.runtime.Recognizer; 14 | import org.antlr.v4.runtime.RecognitionException; 15 | import org.antlr.v4.runtime.tree.*; 16 | import java.nio.file.Paths; 17 | 18 | public class ParserTest { 19 | 20 | static String[] TOKENS = {"ERROR", "TYPEID", "OBJECTID", "BOOL_CONST", "INT_CONST", "STR_CONST", "'('", "')'", "':'", "'@'", "';'", "','", "'+'", "'-'", "'*'", "'/'", "'~'", "'<'", "'='", "'{'", "'}'", "'.'", "DARROW", "LE", "ASSIGN", "CLASS", "ELSE", "FI", "IF", "IN", "INHERITS", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "OF", "NEW", "ISVOID", "NOT" 21 | }; 22 | 23 | static int VALUED_INDEX_LIMIT = 6; 24 | static int NAMED_TOKEN_INDEX = 23; 25 | static int parser_error_flag = 0; 26 | 27 | static String escapeSpecialCharacters(String text) { 28 | return 29 | text 30 | .replaceAll("\\\\", "\\\\\\\\") 31 | .replaceAll("\n", "\\\\n") 32 | .replaceAll("\t", "\\\\t") 33 | .replaceAll("\b", "\\\\b") 34 | .replaceAll("\f", "\\\\f") 35 | .replaceAll("\"", "\\\\\"") 36 | .replaceAll("\r", "\\\\015") 37 | .replaceAll("\033","\\\\033") 38 | .replaceAll("\001","\\\\001") 39 | .replaceAll("\002","\\\\002") 40 | .replaceAll("\003","\\\\003") 41 | .replaceAll("\004","\\\\004") 42 | .replaceAll("\022","\\\\022") 43 | .replaceAll("\013","\\\\013") 44 | .replaceAll("\000", "\\\\000") 45 | ; 46 | } 47 | 48 | static void printAST(String filename) throws Exception{ 49 | ANTLRInputStream inStream=null; 50 | try{ 51 | inStream = new ANTLRInputStream(new FileInputStream(filename)); 52 | }catch(Exception e){ 53 | System.err.println("Could not read file "+filename); 54 | return; 55 | } 56 | 57 | CoolLexer lexer = new CoolLexer(inStream); 58 | CommonTokenStream tokens = new CommonTokenStream(lexer); 59 | tokens.fill(); 60 | int lexer_flag = 0; 61 | for(Token t : tokens.getTokens()){ 62 | if ( t.getType() == 1 ){ 63 | lexer_flag = 1; 64 | System.err.println("Lexical error at "+t.getLine()+": "+escapeSpecialCharacters(t.getText())); 65 | } 66 | } 67 | if (lexer_flag == 1) 68 | return; 69 | 70 | parser_error_flag = 0; 71 | CoolParser parser = new CoolParser(tokens); 72 | parser.removeErrorListeners(); 73 | parser.addErrorListener(new ParserError(Paths.get(filename).getFileName().toString())); 74 | parser.setFilename(Paths.get(filename).getFileName().toString()); 75 | 76 | CoolParser.ProgramContext prog = null; 77 | try{ 78 | prog = parser.program(); 79 | }catch(Exception e){ 80 | // e.printStackTrace(); 81 | } 82 | if(parser_error_flag == 0) 83 | System.out.println(prog.value.getString("")); 84 | else 85 | System.err.println("Compilation halted due to lex and parse errors"); 86 | } 87 | 88 | public static void main(String args[]) throws Exception{ 89 | 90 | if(args.length < 1) { 91 | System.err.println("No files given"); 92 | System.exit(1); 93 | } 94 | 95 | for(String filename : args) 96 | printAST(filename); 97 | } 98 | 99 | public static class ParserError extends BaseErrorListener { 100 | 101 | String filename; 102 | public ParserError(String fn) { 103 | super(); 104 | filename=fn; 105 | } 106 | @Override 107 | public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionIntLine, String msg, RecognitionException e){ 108 | parser_error_flag=1; 109 | String sourceName = recognizer.getInputStream().getSourceName(); 110 | String errorMessage=""; 111 | if(filename!=null){ 112 | if(offendingSymbol instanceof CommonToken){ 113 | errorMessage += "\""+filename+"\", line "+line+": syntax error at or near "; 114 | int typeid = ((CommonToken)offendingSymbol).getType(); 115 | if (typeid == -1){ 116 | errorMessage += "EOF"; 117 | } 118 | else if (typeid <= VALUED_INDEX_LIMIT) { 119 | errorMessage += TOKENS[typeid-1] + " = " + ((CommonToken)offendingSymbol).getText(); 120 | }else if(typeid >= NAMED_TOKEN_INDEX){ 121 | errorMessage += TOKENS[typeid-1]; 122 | }else{ 123 | errorMessage += "\'"+escapeSpecialCharacters(((CommonToken)offendingSymbol).getText())+"\'"; 124 | } 125 | } 126 | } 127 | System.err.println(errorMessage); 128 | throw new RuntimeException("One error found!"); 129 | } 130 | } 131 | } 132 | 133 | //objectid, typeid, int_const, string_const, bool_const 134 | // static String[] TOKENS = {"ERROR", "TYPEID", "OBJECTID", "BOOL_CONST", "INT_CONST", "STR_CONST", "'('", "')'", "':'", "'@'", "';'", "','", "'+'", "'-'", "'*'", "'/'", "'~'", "'<'", "'='", "'{'", "'}'", "'.'", "DARROW", "LE", "ASSIGN", "CLASS", "ELSE", "FI", "IF", "IN", "INHERITS", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "OF", "NEW", "ISVOID", "NOT" 135 | // }; 136 | -------------------------------------------------------------------------------- /parser/src/java/lexer: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | java -cp ${CLASSPATH}../java cool.LexerTest $1 3 | -------------------------------------------------------------------------------- /parser/src/java/parser: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | java -cp ${CLASSPATH}:../java cool.ParserTest $1 3 | -------------------------------------------------------------------------------- /parser/src/test_cases/atoi.cl: -------------------------------------------------------------------------------- 1 | class JustThere { -- class can have no features. 2 | }; 3 | 4 | class A2I { 5 | 6 | c2i(char : String) : Int { 7 | if char = "0" then 0 else 8 | if char = "1" then 1 else 9 | if char = "2" then 2 else 10 | if char = "3" then 3 else 11 | if char = "4" then 4 else 12 | if char = "5" then 5 else 13 | if char = "6" then 6 else 14 | if char = "7" then 7 else 15 | if char = "8" then 8 else 16 | if char = "9" then 9 else 17 | { abort(); 0; } -- Here the formal list is optional. 18 | fi fi fi fi fi fi fi fi fi fi 19 | }; 20 | 21 | 22 | i2c(i : Int) : String { 23 | if i = 0 then "0" else 24 | if i = 1 then "1" else 25 | if i = 2 then "2" else 26 | if i = 3 then "3" else 27 | if i = 4 then "4" else 28 | if i = 5 then "5" else 29 | if i = 6 then "6" else 30 | if i = 7 then "7" else 31 | if i = 8 then "8" else 32 | if i = 9 then "9" else 33 | { abort(); ""; } -- demonstrates an expression block 34 | fi fi fi fi fi fi fi fi fi fi 35 | }; 36 | 37 | a2i(s : String) : Int { 38 | if s.length() = 0 then 0 else 39 | if s.substr(0,1) = "-" then ~a2i_aux(s.substr(1,s.length()-1)) else 40 | if s.substr(0,1) = "+" then a2i_aux(s.substr(1,s.length()-1)) else 41 | a2i_aux(s) 42 | fi fi fi 43 | }; 44 | 45 | a2i_aux(s : String) : Int { 46 | (let int : Int <- 0 in 47 | { 48 | (let j : Int <- s.length() in 49 | (let i : Int <- 0 in 50 | while i < j loop 51 | { 52 | int <- int * 10 + c2i(s.substr(i,1)); -- demonstrates dispatch 53 | i <- i + 1; 54 | } 55 | pool 56 | ) 57 | ); 58 | int; 59 | } 60 | ) 61 | }; 62 | 63 | i2a(i : Int) : String { 64 | if i = 0 then "0" else 65 | if 0 < i then i2a_aux(i) else 66 | "-".concat(i2a_aux(i * ~1)) 67 | fi fi 68 | }; 69 | 70 | 71 | i2a_aux(i : Int) : String { 72 | if i = 0 then "" else 73 | (let next : Int <- i / 10 in 74 | i2a_aux(next).concat(i2c(i - next * 10)) 75 | ) 76 | fi 77 | }; 78 | 79 | }; 80 | 81 | class Main inherits IO { 82 | main () : Object { 83 | let a : Int <- (new A2I).a2i("678987"), 84 | b : String <- (new A2I).i2a(678987) in -- the let expression. Translated to let a: ... in let b: ... in expr. 85 | { 86 | out_int(a) ; 87 | out_string(" == ") ; 88 | out_string(b) ; 89 | out_string("\n"); 90 | } 91 | } ; 92 | } ; 93 | -------------------------------------------------------------------------------- /parser/src/test_cases/err2.cl: -------------------------------------------------------------------------------- 1 | class Main { 2 | main(): Object { 3 | (new alpha).print() 4 | }; 5 | 6 | }; 7 | 8 | (* Class names must begin with uppercase letters *) 9 | class alpha inherits IO { 10 | print() : Object { 11 | out_string("reached!!\n"); 12 | }; 13 | }; 14 | 15 | -------------------------------------------------------------------------------- /parser/src/test_cases/fib.cl: -------------------------------------------------------------------------------- 1 | class Main inherits IO { 2 | -- the class has features. Only methods in this case. 3 | main(): Object { 4 | { 5 | out_string("Enter n to find nth fibonacci number!\n"); 6 | out_int(fib(in_int())); 7 | out_string("\n"); 8 | } 9 | }; 10 | 11 | fib(i : Int) : Int { -- list of formals. And the return type of the method. 12 | let a : Int <- 1, 13 | b : Int <- 0, 14 | c : Int <- 0 15 | in 16 | { 17 | while (not (i = 0)) loop -- expressions are nested. 18 | { 19 | c <- a + b; 20 | i <- i - 1; 21 | b <- a; 22 | a <- c; 23 | } 24 | pool; 25 | c; 26 | } 27 | }; 28 | 29 | }; 30 | -------------------------------------------------------------------------------- /parser/src/test_cases/fib.s: -------------------------------------------------------------------------------- 1 | .data 2 | .align 2 3 | .globl class_nameTab 4 | .globl Main_protObj 5 | .globl Int_protObj 6 | .globl String_protObj 7 | .globl bool_const0 8 | .globl bool_const1 9 | .globl _int_tag 10 | .globl _bool_tag 11 | .globl _string_tag 12 | _int_tag: 13 | .word 3 14 | _bool_tag: 15 | .word 4 16 | _string_tag: 17 | .word 5 18 | .globl _MemMgr_INITIALIZER 19 | _MemMgr_INITIALIZER: 20 | .word _NoGC_Init 21 | .globl _MemMgr_COLLECTOR 22 | _MemMgr_COLLECTOR: 23 | .word _NoGC_Collect 24 | .globl _MemMgr_TEST 25 | _MemMgr_TEST: 26 | .word 0 27 | .word -1 28 | str_const10: 29 | .word 5 30 | .word 5 31 | .word String_dispTab 32 | .word int_const1 33 | .byte 0 34 | .align 2 35 | .word -1 36 | str_const9: 37 | .word 5 38 | .word 6 39 | .word String_dispTab 40 | .word int_const2 41 | .ascii "String" 42 | .byte 0 43 | .align 2 44 | .word -1 45 | str_const8: 46 | .word 5 47 | .word 6 48 | .word String_dispTab 49 | .word int_const3 50 | .ascii "Bool" 51 | .byte 0 52 | .align 2 53 | .word -1 54 | str_const7: 55 | .word 5 56 | .word 5 57 | .word String_dispTab 58 | .word int_const4 59 | .ascii "Int" 60 | .byte 0 61 | .align 2 62 | .word -1 63 | str_const6: 64 | .word 5 65 | .word 6 66 | .word String_dispTab 67 | .word int_const3 68 | .ascii "Main" 69 | .byte 0 70 | .align 2 71 | .word -1 72 | str_const5: 73 | .word 5 74 | .word 5 75 | .word String_dispTab 76 | .word int_const5 77 | .ascii "IO" 78 | .byte 0 79 | .align 2 80 | .word -1 81 | str_const4: 82 | .word 5 83 | .word 6 84 | .word String_dispTab 85 | .word int_const2 86 | .ascii "Object" 87 | .byte 0 88 | .align 2 89 | .word -1 90 | str_const3: 91 | .word 5 92 | .word 8 93 | .word String_dispTab 94 | .word int_const6 95 | .ascii "" 96 | .byte 0 97 | .align 2 98 | .word -1 99 | str_const2: 100 | .word 5 101 | .word 6 102 | .word String_dispTab 103 | .word int_const2 104 | .ascii "fib.cl" 105 | .byte 0 106 | .align 2 107 | .word -1 108 | str_const1: 109 | .word 5 110 | .word 5 111 | .word String_dispTab 112 | .word int_const0 113 | .ascii "\n" 114 | .byte 0 115 | .align 2 116 | .word -1 117 | str_const0: 118 | .word 5 119 | .word 14 120 | .word String_dispTab 121 | .word int_const7 122 | .ascii "Enter n to find nth fibonacci number!\n" 123 | .byte 0 124 | .align 2 125 | .word -1 126 | int_const7: 127 | .word 3 128 | .word 4 129 | .word Int_dispTab 130 | .word 38 131 | .word -1 132 | int_const6: 133 | .word 3 134 | .word 4 135 | .word Int_dispTab 136 | .word 13 137 | .word -1 138 | int_const5: 139 | .word 3 140 | .word 4 141 | .word Int_dispTab 142 | .word 2 143 | .word -1 144 | int_const4: 145 | .word 3 146 | .word 4 147 | .word Int_dispTab 148 | .word 3 149 | .word -1 150 | int_const3: 151 | .word 3 152 | .word 4 153 | .word Int_dispTab 154 | .word 4 155 | .word -1 156 | int_const2: 157 | .word 3 158 | .word 4 159 | .word Int_dispTab 160 | .word 6 161 | .word -1 162 | int_const1: 163 | .word 3 164 | .word 4 165 | .word Int_dispTab 166 | .word 0 167 | .word -1 168 | int_const0: 169 | .word 3 170 | .word 4 171 | .word Int_dispTab 172 | .word 1 173 | .word -1 174 | bool_const0: 175 | .word 4 176 | .word 4 177 | .word Bool_dispTab 178 | .word 0 179 | .word -1 180 | bool_const1: 181 | .word 4 182 | .word 4 183 | .word Bool_dispTab 184 | .word 1 185 | class_nameTab: 186 | .word str_const4 187 | .word str_const5 188 | .word str_const6 189 | .word str_const7 190 | .word str_const8 191 | .word str_const9 192 | class_objTab: 193 | .word Object_protObj 194 | .word Object_init 195 | .word IO_protObj 196 | .word IO_init 197 | .word Main_protObj 198 | .word Main_init 199 | .word Int_protObj 200 | .word Int_init 201 | .word Bool_protObj 202 | .word Bool_init 203 | .word String_protObj 204 | .word String_init 205 | Object_dispTab: 206 | .word Object.abort 207 | .word Object.type_name 208 | .word Object.copy 209 | String_dispTab: 210 | .word Object.abort 211 | .word Object.type_name 212 | .word Object.copy 213 | .word String.length 214 | .word String.concat 215 | .word String.substr 216 | Bool_dispTab: 217 | .word Object.abort 218 | .word Object.type_name 219 | .word Object.copy 220 | Int_dispTab: 221 | .word Object.abort 222 | .word Object.type_name 223 | .word Object.copy 224 | IO_dispTab: 225 | .word Object.abort 226 | .word Object.type_name 227 | .word Object.copy 228 | .word IO.out_string 229 | .word IO.out_int 230 | .word IO.in_string 231 | .word IO.in_int 232 | Main_dispTab: 233 | .word Object.abort 234 | .word Object.type_name 235 | .word Object.copy 236 | .word IO.out_string 237 | .word IO.out_int 238 | .word IO.in_string 239 | .word IO.in_int 240 | .word Main.main 241 | .word Main.fib 242 | .word -1 243 | Object_protObj: 244 | .word 0 245 | .word 3 246 | .word Object_dispTab 247 | .word -1 248 | String_protObj: 249 | .word 5 250 | .word 5 251 | .word String_dispTab 252 | .word int_const1 253 | .word 0 254 | .word -1 255 | Bool_protObj: 256 | .word 4 257 | .word 4 258 | .word Bool_dispTab 259 | .word 0 260 | .word -1 261 | Int_protObj: 262 | .word 3 263 | .word 4 264 | .word Int_dispTab 265 | .word 0 266 | .word -1 267 | IO_protObj: 268 | .word 1 269 | .word 3 270 | .word IO_dispTab 271 | .word -1 272 | Main_protObj: 273 | .word 2 274 | .word 3 275 | .word Main_dispTab 276 | .globl heap_start 277 | heap_start: 278 | .word 0 279 | .text 280 | .globl Main_init 281 | .globl Int_init 282 | .globl String_init 283 | .globl Bool_init 284 | .globl Main.main 285 | Object_init: 286 | addiu $sp $sp -12 287 | sw $fp 12($sp) 288 | sw $s0 8($sp) 289 | sw $ra 4($sp) 290 | addiu $fp $sp 4 291 | move $s0 $a0 292 | move $a0 $s0 293 | lw $fp 12($sp) 294 | lw $s0 8($sp) 295 | lw $ra 4($sp) 296 | addiu $sp $sp 12 297 | jr $ra 298 | String_init: 299 | addiu $sp $sp -12 300 | sw $fp 12($sp) 301 | sw $s0 8($sp) 302 | sw $ra 4($sp) 303 | addiu $fp $sp 4 304 | move $s0 $a0 305 | jal Object_init 306 | move $a0 $s0 307 | lw $fp 12($sp) 308 | lw $s0 8($sp) 309 | lw $ra 4($sp) 310 | addiu $sp $sp 12 311 | jr $ra 312 | Bool_init: 313 | addiu $sp $sp -12 314 | sw $fp 12($sp) 315 | sw $s0 8($sp) 316 | sw $ra 4($sp) 317 | addiu $fp $sp 4 318 | move $s0 $a0 319 | jal Object_init 320 | move $a0 $s0 321 | lw $fp 12($sp) 322 | lw $s0 8($sp) 323 | lw $ra 4($sp) 324 | addiu $sp $sp 12 325 | jr $ra 326 | Int_init: 327 | addiu $sp $sp -12 328 | sw $fp 12($sp) 329 | sw $s0 8($sp) 330 | sw $ra 4($sp) 331 | addiu $fp $sp 4 332 | move $s0 $a0 333 | jal Object_init 334 | move $a0 $s0 335 | lw $fp 12($sp) 336 | lw $s0 8($sp) 337 | lw $ra 4($sp) 338 | addiu $sp $sp 12 339 | jr $ra 340 | IO_init: 341 | addiu $sp $sp -12 342 | sw $fp 12($sp) 343 | sw $s0 8($sp) 344 | sw $ra 4($sp) 345 | addiu $fp $sp 4 346 | move $s0 $a0 347 | jal Object_init 348 | move $a0 $s0 349 | lw $fp 12($sp) 350 | lw $s0 8($sp) 351 | lw $ra 4($sp) 352 | addiu $sp $sp 12 353 | jr $ra 354 | Main_init: 355 | addiu $sp $sp -12 356 | sw $fp 12($sp) 357 | sw $s0 8($sp) 358 | sw $ra 4($sp) 359 | addiu $fp $sp 4 360 | move $s0 $a0 361 | jal IO_init 362 | move $a0 $s0 363 | lw $fp 12($sp) 364 | lw $s0 8($sp) 365 | lw $ra 4($sp) 366 | addiu $sp $sp 12 367 | jr $ra 368 | Main.main: 369 | addiu $sp $sp -12 370 | sw $fp 12($sp) 371 | sw $s0 8($sp) 372 | sw $ra 4($sp) 373 | addiu $fp $sp 4 374 | move $s0 $a0 375 | la $a0 str_const0 376 | sw $a0 0($sp) 377 | addiu $sp $sp -4 378 | move $a0 $s0 379 | bne $a0 $zero label0 380 | la $a0 str_const2 381 | li $t1 1 382 | jal _dispatch_abort 383 | label0: 384 | lw $t1 8($a0) 385 | lw $t1 12($t1) 386 | jalr $t1 387 | move $a0 $s0 388 | bne $a0 $zero label1 389 | la $a0 str_const2 390 | li $t1 1 391 | jal _dispatch_abort 392 | label1: 393 | lw $t1 8($a0) 394 | lw $t1 24($t1) 395 | jalr $t1 396 | sw $a0 0($sp) 397 | addiu $sp $sp -4 398 | move $a0 $s0 399 | bne $a0 $zero label2 400 | la $a0 str_const2 401 | li $t1 1 402 | jal _dispatch_abort 403 | label2: 404 | lw $t1 8($a0) 405 | lw $t1 32($t1) 406 | jalr $t1 407 | sw $a0 0($sp) 408 | addiu $sp $sp -4 409 | move $a0 $s0 410 | bne $a0 $zero label3 411 | la $a0 str_const2 412 | li $t1 1 413 | jal _dispatch_abort 414 | label3: 415 | lw $t1 8($a0) 416 | lw $t1 16($t1) 417 | jalr $t1 418 | la $a0 str_const1 419 | sw $a0 0($sp) 420 | addiu $sp $sp -4 421 | move $a0 $s0 422 | bne $a0 $zero label4 423 | la $a0 str_const2 424 | li $t1 1 425 | jal _dispatch_abort 426 | label4: 427 | lw $t1 8($a0) 428 | lw $t1 12($t1) 429 | jalr $t1 430 | lw $fp 12($sp) 431 | lw $s0 8($sp) 432 | lw $ra 4($sp) 433 | addiu $sp $sp 12 434 | jr $ra 435 | Main.fib: 436 | addiu $sp $sp -28 437 | sw $fp 28($sp) 438 | sw $s0 24($sp) 439 | sw $ra 20($sp) 440 | addiu $fp $sp 4 441 | move $s0 $a0 442 | la $s1 int_const0 443 | la $s2 int_const1 444 | la $s3 int_const1 445 | label5: 446 | lw $s4 28($fp) 447 | la $t2 int_const1 448 | move $t1 $s4 449 | la $a0 bool_const1 450 | beq $t1 $t2 label8 451 | la $a1 bool_const0 452 | jal equality_test 453 | label8: 454 | lw $t1 12($a0) 455 | la $a0 bool_const1 456 | beqz $t1 label7 457 | la $a0 bool_const0 458 | label7: 459 | lw $t1 12($a0) 460 | beq $t1 $zero label6 461 | move $s4 $s1 462 | move $a0 $s2 463 | jal Object.copy 464 | lw $t2 12($a0) 465 | lw $t1 12($s4) 466 | add $t1 $t1 $t2 467 | sw $t1 12($a0) 468 | move $s3 $a0 469 | lw $s4 28($fp) 470 | la $a0 int_const0 471 | jal Object.copy 472 | lw $t2 12($a0) 473 | lw $t1 12($s4) 474 | sub $t1 $t1 $t2 475 | sw $t1 12($a0) 476 | sw $a0 28($fp) 477 | move $s2 $s1 478 | move $s1 $s3 479 | b label5 480 | label6: 481 | move $a0 $zero 482 | move $a0 $s3 483 | lw $fp 28($sp) 484 | lw $s0 24($sp) 485 | lw $ra 20($sp) 486 | addiu $sp $sp 32 487 | jr $ra 488 | -------------------------------------------------------------------------------- /parser/src/test_cases/isprime.cl: -------------------------------------------------------------------------------- 1 | class Main inherits IO { 2 | main() : Object { 3 | { 4 | out_string("Enter a number to check if number is prime\n"); 5 | let i : Int <- in_int() in { 6 | if(i <= 1) then { 7 | out_string("Invalid Input\n"); 8 | abort(); 9 | } else { 10 | if (isPrime(i) = 1) then 11 | out_string("Number is prime\n") 12 | else 13 | out_string("Number is composite\n") 14 | fi; 15 | } 16 | fi; 17 | }; 18 | } 19 | }; 20 | 21 | mod(i : Int, ) : Int { -- Formal list must be comma separated. A comma does not terminate a list of formals. 22 | i - (i/k)*k 23 | }; 24 | 25 | isPrime(i : Int) : Int { 26 | { 27 | let x : Int <- 2, 28 | c : Int <- 1 in 29 | { 30 | while (not (x = i)) loop 31 | if (mod(i, x) = 0) then { 32 | c <- 0; 33 | x <- i; 34 | } else x <- x + 1 fi 35 | pool; 36 | c; 37 | }; 38 | } 39 | }; 40 | }; 41 | -------------------------------------------------------------------------------- /parser/src/test_cases/print-cool.cl: -------------------------------------------------------------------------------- 1 | class Main inherits IO { 2 | main() : SELF_TYPE { 3 | { 4 | out_string((new Object).type_name().substr(4,1)). 5 | out_string((isvoid self).type_name().substr(1,3)); -- demonstrates the dispatch rules. 6 | out_string("\n"); 7 | } 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /parser/src/test_cases/prod.cl: -------------------------------------------------------------------------------- 1 | class Main inherits IO { 2 | main() : Object { 3 | { 4 | out_string("Enter number of numbers to multiply\n"); 5 | out_int(prod(in_int())); 6 | out_string("\n"); 7 | } 8 | }; 9 | 10 | prod(i : Int) : Int { 11 | let y : Int <- 1 in { 12 | while (not (i = 0) ) loop { 13 | out_string("Enter Number: "); 14 | y <- y * in_int(Main : Int); -- the parser correctly catches the error here 15 | i <- i - 1; 16 | } 17 | pool; 18 | y; 19 | } 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /semantic/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | make -C src/java 3 | 4 | clean: 5 | make -C src/java clean 6 | -------------------------------------------------------------------------------- /semantic/README.md: -------------------------------------------------------------------------------- 1 | General Description 2 | =================== 3 | 4 | A total of 3 passes are made over the program to check if it is semantically correct. Sometimes, a few more passes on subtrees (or parts of tree) are required to ascertain correctness. 5 | Note that the semantic analyzer does not handle the `SELF_TYPE` keyword of `COOL` language. This means that programs having `SELF_TYPE` then the semantic analyzer may work unexpectedly. 6 | 7 | Code Structure 8 | =============== 9 | 10 | The code structure is expressed in a high-level manner. Low-level details can be gleaned from the comments in the code. 11 | 12 | The following files have been added : 13 | - `ClassTable.java` : Stores the class hierarchy. Helps in conformance checks and getting methods of a particular class. Also does several inheritance checks. 14 | - `Error.java` : Since `ClassTable.java` does not have access to the `reportError` method of `Semantic.java`, a `List` is returned to `Semantic` to print the errors. 15 | - `ClassPlus.java` : Inspired from `AST.class_` class. Stores class `attr` and `methods` in separate `HashMap`s. Also stores class name and parent name. 16 | 17 | 18 | The following steps happen in order: 19 | 20 | - Inheritance graph is built. 21 | - Cycle checks are done. If any cycles are found, or any instance of bad hierarchy, then the semantic analyzers terminates after reporting an appropriate error. 22 | - HashMaps for both attributes and methods in a class are built. These maps include inherited attributes and methods too. Wherever a clash occurs, the inherited feature is used and appropriate error 23 | message is emitted. 24 | - Expressions within the class are processed and type annotated. Appropriate erros are reported wherever found. 25 | 26 | Design Decision 27 | =============== 28 | 29 | Tree Traversal 30 | -------------- 31 | 32 | ### BFS-order traversal. 33 | 34 | The tree is traversed in BFS-order. This is done, primarily, to avoid using a recursive function. But it also serves to help in better error reporting. 35 | Whenever a class-node, which has been visited before, is visited again, an appropriate error message is reported. 36 | 37 | ### 3 passes 38 | 39 | Three passes over the tree is made because classes maybe defined in any order without regard to the inheritance hierarchy. The second-pass is made because 40 | within a class, the features and attributes may be defined in any order. The third pass takes all the information collected thus far to find semantic errors. 41 | Note that in the second-pass, only the static types of attributes and methods are recorded. 42 | 43 | Additionally, the second-pass is also done in BFS-order. Any top-down order would work though. This is done so that the attribute HashMaps and method HashMaps can be 44 | inherited. 45 | 46 | 47 | Inheritance 48 | ----------- 49 | 50 | ### Attribute overrides 51 | 52 | In the second pass, the attribute HashMap and method HashMap is inherited from the parent class. Thus, if any attribute is overriden in the class being analyzed, 53 | an error is reported. Also note that the current class retains the inherited attribute and discards the redefined attribute. This means that to any of the classes that 54 | inherit the current class, this same inherited attribute is visible. 55 | 56 | ### Method overrides 57 | 58 | The method HashMap is inherited from the parent class. If any method is found to be overriden, it is check for errors. Possible errors are that the method return type may not be the same as the original. 59 | Additionally, the method may take incompatible number of arguments (incomaptible to the inherited attribute). Thirdly, the parameter types may not match. 60 | 61 | Even in this case, the inherited attribute is retained in case of an error. The redefined attribute is discarded. 62 | 63 | Naming and Scoping 64 | ------------------ 65 | 66 | ### Multiple attribute defintions 67 | 68 | This error is checked in the second pass itself. This means, that if any attributes are multiply defined within a class, the error is reported then. Also note that the first instance of all of the multiple defintions 69 | of an attribute is stored in the attribute HashMap. All others are discarded. 70 | 71 | ### Multiple method definitions 72 | 73 | This error is checked in the second pass itself. This means that if any methods are multiply defined within a class, the error is reported then. Also note that the first instance of all of the multiple definitions of a method is stored in the method HashMap. All others are discarded. 74 | 75 | ### Formal parameters of methods 76 | 77 | Errors are check using a scopetable. Formal parameters are analyzed from left-to-right. In effect, each parameter is in the scope of all the parameters to its right. If a parameter is redefined, appropriate error is thrown. Additionally, later definitions of a formal parameter override earlier definitions with the same name. 78 | 79 | ### In case statement 80 | 81 | Within the case statement, the branch types are checked. If any of the branch types are identical, an error is reported. Conformance (and thus the type of the `typcase`) is checked in an ordinary manner. Wherever the expression has an erroneous type, type "Object" is returned. This pattern is observed throughout the program. 82 | 83 | One thing done differently here is that when an undefined class is used as a branch type, then `coolc` just emits that the branch type is illegal. Since the corresponding expression has this branch variable in scope, it can use it in certain operations. In our implementation we have assumed that in the case of an erroneous branch type, the branch type is `Object` for this scope. Cool compiler (seemingly), does not execute any conformance checks at the required places in the corresponding branch expression. 84 | 85 | ### In let expressions 86 | 87 | In let expressions, the object declaration expressions are checked for conformance with object types. In the enclosed scopes, the object type is set to the declared type (not the one infered from the expression). 88 | 89 | 90 | 91 | Type 92 | ----- 93 | 94 | ### Of Objects 95 | 96 | Wherever object types have an associated error, the type "Object" is set for the object. 97 | 98 | ### Of Constructs with declared types 99 | 100 | With declared types, only declared types are used for enclosed scopes. 101 | 102 | ### Wherever else 103 | 104 | In other cases, types which are expected of an expression are used. Appropriate error messages are produced when the erroneous subexpression is being analyzed. 105 | 106 | 107 | * * * 108 | -------------------------------------------------------------------------------- /semantic/src/java/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | make -C cool/ 3 | clean: 4 | make -C cool/ clean 5 | -------------------------------------------------------------------------------- /semantic/src/java/cool/AST.java: -------------------------------------------------------------------------------- 1 | package cool; 2 | import java.util.List; 3 | public class AST{ 4 | public static class ASTNode { 5 | int lineNo; 6 | } 7 | public static String sp = " "; 8 | 9 | static String escapeSpecialCharacters(String text) { 10 | return 11 | text 12 | .replaceAll("\\\\", "\\\\\\\\") 13 | .replaceAll("\n", "\\\\n") 14 | .replaceAll("\t", "\\\\t") 15 | .replaceAll("\b", "\\\\b") 16 | .replaceAll("\f", "\\\\f") 17 | .replaceAll("\"", "\\\\\"") 18 | .replaceAll("\r", "\\\\015") 19 | .replaceAll("\033","\\\\033") 20 | .replaceAll("\001","\\\\001") 21 | .replaceAll("\002","\\\\002") 22 | .replaceAll("\003","\\\\003") 23 | .replaceAll("\004","\\\\004") 24 | .replaceAll("\022","\\\\022") 25 | .replaceAll("\013","\\\\013") 26 | .replaceAll("\000", "\\\\000") 27 | ; 28 | } 29 | 30 | 31 | public static class expression extends ASTNode { 32 | String type; 33 | public expression(){ 34 | type = "_no_type"; 35 | } 36 | String getString(String space){ 37 | return ""; 38 | }; 39 | } 40 | public static class no_expr extends expression { 41 | public no_expr(int l){ 42 | lineNo = l; 43 | } 44 | String getString(String space){ 45 | return space+"#"+lineNo+"\n"+space+"_no_expr\n"+space+": "+type; 46 | } 47 | } 48 | public static class bool_const extends expression{ 49 | public boolean value; 50 | public bool_const(boolean v, int l){ 51 | value = v; 52 | lineNo = l; 53 | } 54 | String getString(String space){ 55 | return space+"#"+lineNo+"\n"+space+"_bool\n"+space+sp+(value?"1":"0")+"\n"+space+": "+type; 56 | } 57 | } 58 | public static class string_const extends expression{ 59 | public String value; 60 | public string_const(String v, int l){ 61 | value = v; 62 | lineNo = l; 63 | } 64 | String getString(String space){ 65 | return space+"#"+lineNo+"\n"+space+"_string\n"+space+sp+"\""+escapeSpecialCharacters(value)+"\""+"\n"+space+": "+type; 66 | } 67 | } 68 | 69 | public static class int_const extends expression{ 70 | public int value; 71 | public int_const(int v, int l){ 72 | value = v; 73 | lineNo = l; 74 | } 75 | String getString(String space){ 76 | return space+"#"+lineNo+"\n"+space+"_int\n"+space+sp+value+"\n"+space+": "+type; 77 | } 78 | } 79 | 80 | public static class object extends expression{ 81 | public String name; 82 | public object(String v, int l){ 83 | name = v; 84 | lineNo = l; 85 | } 86 | String getString(String space){ 87 | return space+"#"+lineNo+"\n"+space+"_object\n"+space+sp+name+"\n"+space+": "+type; 88 | } 89 | } 90 | public static class comp extends expression{ 91 | public expression e1; 92 | public comp(expression v, int l){ 93 | e1 = v; 94 | lineNo = l; 95 | } 96 | String getString(String space){ 97 | return space+"#"+lineNo+"\n"+space+"_comp\n"+e1.getString(space+sp)+"\n"+space+": "+type; 98 | } 99 | } 100 | public static class eq extends expression{ 101 | public expression e1; 102 | public expression e2; 103 | public eq(expression v1, expression v2, int l){ 104 | e1=v1; 105 | e2=v2; 106 | lineNo = l; 107 | } 108 | String getString(String space){ 109 | return space+"#"+lineNo+"\n"+space+"_eq\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 110 | } 111 | } 112 | 113 | 114 | public static class leq extends expression{ 115 | public expression e1; 116 | public expression e2; 117 | public leq(expression v1, expression v2, int l){ 118 | e1 = v1; 119 | e2 = v2; 120 | lineNo = l; 121 | } 122 | String getString(String space){ 123 | return space+"#"+lineNo+"\n"+space+"_leq\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 124 | } 125 | } 126 | 127 | public static class lt extends expression{ 128 | public expression e1; 129 | public expression e2; 130 | public lt(expression v1, expression v2, int l){ 131 | e1 = v1; 132 | e2 = v2; 133 | lineNo = l; 134 | } 135 | String getString(String space){ 136 | return space+"#"+lineNo+"\n"+space+"_lt\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 137 | } 138 | } 139 | public static class neg extends expression{ 140 | public expression e1; 141 | public neg(expression v, int l){ 142 | e1 = v; 143 | lineNo = l; 144 | } 145 | String getString(String space){ 146 | return space+"#"+lineNo+"\n"+space+"_neg\n"+e1.getString(space+sp)+"\n"+space+": "+type; 147 | } 148 | } 149 | public static class divide extends expression{ 150 | public expression e1; 151 | public expression e2; 152 | public divide(expression v1, expression v2, int l){ 153 | e1 = v1; 154 | e2 = v2; 155 | lineNo = l; 156 | } 157 | String getString(String space){ 158 | return space+"#"+lineNo+"\n"+space+"_divide\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 159 | } 160 | } 161 | public static class mul extends expression{ 162 | public expression e1; 163 | public expression e2; 164 | public mul(expression v1, expression v2, int l){ 165 | e1 = v1; 166 | e2 = v2; 167 | lineNo = l; 168 | } 169 | String getString(String space){ 170 | return space+"#"+lineNo+"\n"+space+"_mul\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 171 | } 172 | } 173 | public static class sub extends expression{ 174 | public expression e1; 175 | public expression e2; 176 | public sub(expression v1, expression v2, int l){ 177 | e1 = v1; 178 | e2 = v2; 179 | lineNo = l; 180 | } 181 | String getString(String space){ 182 | return space+"#"+lineNo+"\n"+space+"_sub\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 183 | } 184 | } 185 | public static class plus extends expression{ 186 | public expression e1; 187 | public expression e2; 188 | public plus(expression v1, expression v2, int l){ 189 | e1 = v1; 190 | e2 = v2; 191 | lineNo = l; 192 | } 193 | String getString(String space){ 194 | return space+"#"+lineNo+"\n"+space+"_plus\n"+e1.getString(space+sp)+"\n"+e2.getString(space+sp)+"\n"+space+": "+type; 195 | } 196 | } 197 | public static class isvoid extends expression{ 198 | public expression e1; 199 | public isvoid(expression v, int l){ 200 | e1 = v; 201 | lineNo = l; 202 | } 203 | String getString(String space){ 204 | return space+"#"+lineNo+"\n"+space+"_isvoid\n"+e1.getString(space+sp)+"\n"+space+": "+type; 205 | } 206 | } 207 | public static class new_ extends expression{ 208 | public String typeid; 209 | public new_(String t, int l){ 210 | typeid = t; 211 | lineNo = l; 212 | } 213 | String getString(String space){ 214 | return space+"#"+lineNo+"\n"+space+"_new\n"+space+sp+typeid+"\n"+space+": "+type; 215 | } 216 | } 217 | public static class assign extends expression{ 218 | public String name; 219 | public expression e1; 220 | public assign(String n, expression v1, int l){ 221 | name = n; 222 | e1 = v1; 223 | lineNo = l; 224 | } 225 | String getString(String space){ 226 | return space+"#"+lineNo+"\n"+space+"_assign\n"+space+sp+name+"\n"+e1.getString(space+sp)+"\n"+space+": "+type; 227 | } 228 | } 229 | public static class block extends expression{ 230 | public List l1; 231 | public block(List v1, int l){ 232 | l1 = v1; 233 | lineNo = l; 234 | } 235 | String getString(String space){ 236 | String str = space+"#"+lineNo+"\n"+space+"_block\n"; 237 | for (expression e1 : l1){ 238 | str += e1.getString(space+sp)+"\n"; 239 | } 240 | str+=space+": "+type; 241 | return str; 242 | } 243 | } 244 | public static class loop extends expression{ 245 | public expression predicate; 246 | public expression body; 247 | public loop(expression v1, expression v2, int l){ 248 | predicate = v1; 249 | body = v2; 250 | lineNo = l; 251 | } 252 | String getString(String space){ 253 | return space+"#"+lineNo+"\n"+space+"_loop\n"+predicate.getString(space+sp)+"\n"+body.getString(space+sp)+"\n"+space+": "+type; 254 | } 255 | } 256 | public static class cond extends expression{ 257 | public expression predicate; 258 | public expression ifbody; 259 | public expression elsebody; 260 | public cond(expression v1, expression v2, expression v3, int l){ 261 | predicate = v1; 262 | ifbody = v2; 263 | elsebody = v3; 264 | lineNo = l; 265 | } 266 | String getString(String space){ 267 | return space+"#"+lineNo+"\n"+space+"_cond\n"+predicate.getString(space+sp)+"\n"+ifbody.getString(space+sp)+"\n"+elsebody.getString(space+sp)+"\n"+space+": "+type; 268 | } 269 | } 270 | public static class let extends expression{ 271 | public String name; 272 | public String typeid; 273 | public expression value; 274 | public expression body; 275 | public let(String n, String t, expression v, expression b, int l){ 276 | name = n; 277 | typeid = t; 278 | value = v; 279 | body = b; 280 | lineNo = l; 281 | } 282 | String getString(String space){ 283 | return space+"#"+lineNo+"\n"+space+"_let\n"+space+sp+name+"\n"+space+sp+typeid+"\n"+value.getString(space+sp)+"\n"+body.getString(space+sp)+"\n"+space+": "+type; 284 | } 285 | } 286 | public static class dispatch extends expression{ 287 | public expression caller; 288 | public String name; 289 | public List actuals; 290 | public dispatch(expression v1, String n, List a, int l){ 291 | caller = v1; 292 | name = n; 293 | actuals = a; 294 | lineNo = l; 295 | } 296 | String getString(String space){ 297 | String str; 298 | str = space+"#"+lineNo+"\n"+space+"_dispatch\n"+caller.getString(space+sp)+"\n"+space+sp+name+"\n"+space+sp+"(\n"; 299 | for ( expression e1 : actuals ) { 300 | str += e1.getString(space+sp)+"\n"; 301 | } 302 | str+=space+sp+")\n"+space+": "+type; 303 | return str; 304 | } 305 | } 306 | public static class static_dispatch extends expression{ 307 | public expression caller; 308 | public String typeid; 309 | public String name; 310 | public List actuals; 311 | public static_dispatch(expression v1, String t, String n, List a, int l){ 312 | caller = v1; 313 | typeid = t; 314 | name = n; 315 | actuals = a; 316 | lineNo = l; 317 | } 318 | String getString(String space){ 319 | String str; 320 | str = space+"#"+lineNo+"\n"+space+"_static_dispatch\n"+caller.getString(space+sp)+"\n"+space+sp+typeid+"\n"+space+sp+name+"\n"+space+sp+"(\n"; 321 | for ( expression e1 : actuals ) { 322 | str += e1.getString(space+sp)+"\n"; 323 | } 324 | str+=space+sp+")\n"+space+": "+type; 325 | return str; 326 | } 327 | } 328 | public static class typcase extends expression{ 329 | public expression predicate; 330 | public List branches; 331 | public typcase(expression p, List b, int l){ 332 | predicate = p; 333 | branches = b; 334 | lineNo = l; 335 | } 336 | String getString(String space){ 337 | String str = space+"#"+lineNo+"\n"+space+"_typcase\n"+predicate.getString(space+sp)+"\n"; 338 | for ( branch b1 : branches ) { 339 | str += b1.getString(space+sp)+"\n"; 340 | } 341 | str += space+": "+type; 342 | return str; 343 | } 344 | } 345 | public static class branch extends ASTNode { 346 | public String name; 347 | public String type; 348 | public expression value; 349 | public branch(String n, String t, expression v, int l){ 350 | name = n; 351 | type = t; 352 | value = v; 353 | lineNo = l; 354 | } 355 | String getString(String space){ 356 | return space+"#"+lineNo+"\n"+space+"_branch\n"+space+sp+name+"\n"+space+sp+type+"\n"+value.getString(space+sp); 357 | } 358 | } 359 | public static class formal extends ASTNode { 360 | public String name; 361 | public String typeid; 362 | public formal(String n, String t, int l){ 363 | name = n; 364 | typeid = t; 365 | lineNo = l; 366 | } 367 | String getString(String space){ 368 | return space+"#"+lineNo+"\n"+space+"_formal\n"+space+sp+name+"\n"+space+sp+typeid; 369 | } 370 | } 371 | public static class feature extends ASTNode { 372 | public feature(){ 373 | } 374 | String getString(String space){ 375 | return ""; 376 | } 377 | 378 | } 379 | public static class method extends feature { 380 | public String name; 381 | public List formals; 382 | public String typeid; 383 | public expression body; 384 | public method(String n, List f, String t, expression b, int l){ 385 | name = n; 386 | formals = f; 387 | typeid = t; 388 | body = b; 389 | lineNo = l; 390 | } 391 | String getString(String space){ 392 | String str = space+"#"+lineNo+"\n"+space+"_method\n"+space+sp+name+"\n"; 393 | for ( formal f : formals ) { 394 | str += f.getString(space+sp)+"\n"; 395 | } 396 | str += space+sp+typeid+"\n"+body.getString(space+sp); 397 | return str; 398 | } 399 | } 400 | public static class attr extends feature { 401 | public String name; 402 | public String typeid; 403 | public expression value; 404 | public attr(String n, String t, expression v, int l){ 405 | name = n; 406 | typeid = t; 407 | value = v; 408 | lineNo = l; 409 | } 410 | String getString(String space){ 411 | return space+"#"+lineNo+"\n"+space+"_attr\n"+space+sp+name+"\n"+space+sp+typeid+"\n"+value.getString(space+sp); 412 | } 413 | } 414 | public static class class_ extends ASTNode { 415 | public String name; 416 | public String filename; 417 | public String parent; 418 | public List features; 419 | public class_(String n, String f, String p, List fs, int l){ 420 | name = n; 421 | filename = f; 422 | parent = p; 423 | features = fs; 424 | lineNo = l; 425 | } 426 | String getString(String space){ 427 | String str; 428 | str = space+"#"+lineNo+"\n"+space+"_class\n"+space+sp+name+"\n"+space+sp+parent+"\n"+space+sp+"\""+filename+"\""+"\n"+space+sp+"(\n"; 429 | for ( feature f : features ) { 430 | str += f.getString(space+sp)+"\n"; 431 | } 432 | str += space+sp+")"; 433 | return str; 434 | } 435 | } 436 | public static class program extends ASTNode { 437 | public List classes; 438 | public program(List c, int l){ 439 | classes = c; 440 | lineNo = l; 441 | } 442 | String getString(String space){ 443 | String str; 444 | str = space+"#"+lineNo+"\n"+space+"_program"; 445 | for ( class_ c : classes ) { 446 | str += "\n"+c.getString(space+sp); 447 | } 448 | 449 | return str; 450 | } 451 | } 452 | } 453 | -------------------------------------------------------------------------------- /semantic/src/java/cool/ClassPlus.java: -------------------------------------------------------------------------------- 1 | package cool; 2 | import java.util.HashMap; 3 | 4 | public class ClassPlus { 5 | public String name; 6 | public String parent = null; 7 | public HashMap alist; 8 | public HashMap mlist; 9 | 10 | ClassPlus(String nm, String pr, HashMap al, HashMap ml) { 11 | name = new String(nm); 12 | if(pr != null) parent = new String(pr); 13 | alist = new HashMap (); 14 | alist.putAll(al); 15 | mlist = new HashMap (); 16 | mlist.putAll(ml); 17 | } 18 | } -------------------------------------------------------------------------------- /semantic/src/java/cool/ClassTable.java: -------------------------------------------------------------------------------- 1 | package cool; 2 | import java.util.*; 3 | import java.util.Map.Entry; 4 | 5 | 6 | 7 | 8 | public class ClassTable { 9 | private HashMap classes=new HashMap(); // for retrieving class related info and class attributes and features 10 | private HashMap height = new HashMap(); // for retrieving class height in the inheritance hierarchy (for conformance check) 11 | public List errors = new ArrayList(); 12 | 13 | public ClassTable() { 14 | /* Classes already present in the table: 15 | * - Object 16 | * - IO 17 | * - String 18 | * - Int 19 | * - Bool 20 | * 21 | * Object has methods: 22 | * - abort() : Object 23 | * - type_name(): String 24 | * IO has methods: 25 | * - out_string(x : String) : IO 26 | * - out_int(x : Int) : IO 27 | * - in_string() : String 28 | * - in_int() : String 29 | * String has methods: 30 | * - length() : Int 31 | * - concat(s: String) : String 32 | * - substr(i : Int, l : Int) : String 33 | */ 34 | 35 | HashMap ol = new HashMap (); 36 | ol.put("abort", new AST.method("abort", new ArrayList(), "Object", new AST.no_expr(0), 0)); 37 | ol.put("type_name", new AST.method("type_name", new ArrayList(), "String", new AST.no_expr(0), 0)); 38 | 39 | classes.put("Object", new ClassPlus("Object", null, new HashMap(), ol)); 40 | height.put("Object", 0); 41 | 42 | HashMap iol = new HashMap(); 43 | 44 | List os_formals = new ArrayList(); 45 | os_formals.add(new AST.formal("out_string", "String", 0)); 46 | List oi_formals = new ArrayList(); 47 | oi_formals.add(new AST.formal("out_int", "Int", 0)); 48 | 49 | iol.put("out_string", new AST.method("out_string", os_formals, "IO", new AST.no_expr(0), 0)); 50 | iol.put("out_int", new AST.method("out_int", oi_formals, "IO", new AST.no_expr(0), 0)); 51 | iol.put("in_string", new AST.method("in_string", new ArrayList(), "String", new AST.no_expr(0), 0)); 52 | iol.put("in_int", new AST.method("in_int", new ArrayList(), "Int", new AST.no_expr(0), 0)); 53 | classes.put("IO", new ClassPlus("IO", "Object", new HashMap(), iol)); 54 | classes.get("IO").mlist.putAll(ol); // IO inherits from Object 55 | height.put("IO", 1); 56 | 57 | classes.put("Int", new ClassPlus("Int", "Object", new HashMap(), new HashMap())); 58 | height.put("Int", 1); 59 | classes.get("Int").mlist.putAll(ol); // Int inherits from Object 60 | 61 | classes.put("Bool", new ClassPlus("Bool", "Object", new HashMap(), new HashMap())); 62 | height.put("Bool", 1); 63 | classes.get("Bool").mlist.putAll(ol); // Bool inherits from Object 64 | 65 | HashMap sl = new HashMap(); 66 | List concat_formal = new ArrayList(); 67 | concat_formal.add(new AST.formal("s", "String", 0)); 68 | List substr_formal = new ArrayList(); 69 | substr_formal.add(new AST.formal("i", "Int", 0)); 70 | substr_formal.add(new AST.formal("l", "Int", 0)); 71 | 72 | sl.put("length", new AST.method("length", new ArrayList(), "Int", new AST.no_expr(0), 0)); 73 | sl.put("concat", new AST.method("concat", concat_formal, "String", new AST.no_expr(0), 0)); 74 | sl.put("substr", new AST.method("substr", substr_formal, "String", new AST.no_expr(0), 0)); 75 | 76 | classes.put("String", new ClassPlus("String", "Object", new HashMap(), sl)); 77 | height.put("String", 1); 78 | classes.get("String").mlist.putAll(ol); // String Inherits from Object 79 | } 80 | void insert(AST.class_ c) { 81 | /* Whenever a new class is inserted, 82 | * - Inherits the attributes and methods of the parent class. 83 | * - Checks for multiple method or attribute definitions. 84 | * - Checks for correct method overrides and any attribute overrides 85 | */ 86 | String pr = c.parent; 87 | ClassPlus tc = new ClassPlus(c.name, c.parent, classes.get(c.parent).alist, classes.get(c.parent).mlist); // adding the parents attribute list and method list 88 | 89 | 90 | HashMap tc_alist = new HashMap(); 91 | HashMap tc_mlist = new HashMap (); 92 | 93 | /* Checks for the following errors within a class: 94 | * - multiple attribute definitions 95 | * - multiple method definitions 96 | */ 97 | for(AST.feature e : c.features) { 98 | if(e.getClass() == AST.attr.class) { 99 | AST.attr ae = (AST.attr) e; 100 | if(tc_alist.containsKey(ae.name)) 101 | errors.add(new Error(c.filename, ae.lineNo, "Attribute " + ae.name + " is multiply defined in class.")); 102 | else 103 | tc_alist.put(ae.name, ae); 104 | } 105 | else if(e.getClass() == AST.method.class) { 106 | AST.method me = (AST.method) e; 107 | if(tc_mlist.containsKey(me.name)) 108 | errors.add(new Error(c.filename, me.lineNo, "Method " + me.name + " is multiply defined.")); 109 | else 110 | tc_mlist.put(me.name, me); 111 | } 112 | } 113 | 114 | 115 | /* Checks for the following errors with respect to the inherited class: 116 | * - redefinition of an inherited attribute (Note: the class retains the inherited attribute and discards the attribute defined within the class) 117 | * - wrong redefinition of an inherited method (Note : the class retains the inherited method and discards the method defined within the class) 118 | */ 119 | for(Entry entry : tc_alist.entrySet()) { 120 | if(tc.alist.containsKey(entry.getKey())) 121 | errors.add(new Error(c.filename, entry.getValue().lineNo, "Attribute " + entry.getValue().name + " is an attribute of an inherited class")); 122 | else { 123 | tc.alist.put(entry.getKey(), entry.getValue()); 124 | } 125 | 126 | } 127 | boolean foundErr; 128 | for(Entry entry : tc_mlist.entrySet()) { 129 | foundErr = false; 130 | if(tc.mlist.containsKey(entry.getKey())) { 131 | AST.method parent_me = tc.mlist.get(entry.getKey()); 132 | AST.method me = entry.getValue(); 133 | if(me.formals.size() != parent_me.formals.size()) { 134 | errors.add(new Error(c.filename, me.lineNo, "Incompatible number of formal parameters in redefined method " + me.name)); 135 | foundErr = true; 136 | } 137 | else { 138 | if(me.typeid.equals(parent_me.typeid) == false) { 139 | errors.add(new Error(c.filename, me.lineNo, "In redefined method " + me.name + ", return type " 140 | + me.typeid + " is different from original return type " + parent_me.typeid)); 141 | foundErr = true; 142 | } 143 | for(int i = 0; i < me.formals.size(); ++i) { 144 | if(me.formals.get(i).typeid.equals(parent_me.formals.get(i).typeid) == false) { 145 | errors.add(new Error(c.filename, me.lineNo, "In redefined method " + me.name + ", parameter type" 146 | + me.formals.get(i).typeid + " is different from original type " + parent_me.formals.get(i).typeid)); 147 | foundErr = true; 148 | } 149 | } 150 | } 151 | } 152 | 153 | if(foundErr != true) 154 | tc.mlist.put(entry.getKey(), entry.getValue()); 155 | } 156 | height.put(c.name, height.get(c.parent) + 1); 157 | 158 | classes.put(c.name, tc); 159 | } 160 | 161 | 162 | List getErrors() { 163 | return errors; 164 | } 165 | 166 | HashMap getAttrs(String className) { 167 | return classes.get(className).alist; 168 | } 169 | 170 | ClassPlus getClassPlus(String className) { 171 | return classes.get(className); 172 | } 173 | 174 | boolean conforms(String a, String b) { 175 | if(a.equals(b)) 176 | return true; 177 | else { 178 | a = classes.get(a).parent; 179 | if(a == null) return false; 180 | else return conforms(a, b); 181 | } 182 | } 183 | 184 | String lca(String a, String b) { 185 | 186 | if(a.equals(b)) return a; 187 | else if(height.get(a) < height.get(b)) // a must always be deeper in the tree 188 | return lca(b, a); 189 | else 190 | return lca(classes.get(a).parent, b); 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /semantic/src/java/cool/CoolParserBaseVisitor.java: -------------------------------------------------------------------------------- 1 | // Generated from CoolParser.g4 by ANTLR 4.5.1 2 | package cool; 3 | 4 | import cool.AST; 5 | import java.util.List; 6 | 7 | import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor; 8 | 9 | /** 10 | * This class provides an empty implementation of {@link CoolParserVisitor}, 11 | * which can be extended to create a visitor which only needs to handle a subset 12 | * of the available methods. 13 | * 14 | * @param The return type of the visit operation. Use {@link Void} for 15 | * operations with no return type. 16 | */ 17 | public class CoolParserBaseVisitor extends AbstractParseTreeVisitor implements CoolParserVisitor { 18 | /** 19 | * {@inheritDoc} 20 | * 21 | *

The default implementation returns the result of calling 22 | * {@link #visitChildren} on {@code ctx}.

23 | */ 24 | @Override public T visitProgram(CoolParser.ProgramContext ctx) { return visitChildren(ctx); } 25 | /** 26 | * {@inheritDoc} 27 | * 28 | *

The default implementation returns the result of calling 29 | * {@link #visitChildren} on {@code ctx}.

30 | */ 31 | @Override public T visitClass_list(CoolParser.Class_listContext ctx) { return visitChildren(ctx); } 32 | /** 33 | * {@inheritDoc} 34 | * 35 | *

The default implementation returns the result of calling 36 | * {@link #visitChildren} on {@code ctx}.

37 | */ 38 | @Override public T visitClass_(CoolParser.Class_Context ctx) { return visitChildren(ctx); } 39 | /** 40 | * {@inheritDoc} 41 | * 42 | *

The default implementation returns the result of calling 43 | * {@link #visitChildren} on {@code ctx}.

44 | */ 45 | @Override public T visitFeature_list(CoolParser.Feature_listContext ctx) { return visitChildren(ctx); } 46 | /** 47 | * {@inheritDoc} 48 | * 49 | *

The default implementation returns the result of calling 50 | * {@link #visitChildren} on {@code ctx}.

51 | */ 52 | @Override public T visitFeature(CoolParser.FeatureContext ctx) { return visitChildren(ctx); } 53 | /** 54 | * {@inheritDoc} 55 | * 56 | *

The default implementation returns the result of calling 57 | * {@link #visitChildren} on {@code ctx}.

58 | */ 59 | @Override public T visitFormal_list(CoolParser.Formal_listContext ctx) { return visitChildren(ctx); } 60 | /** 61 | * {@inheritDoc} 62 | * 63 | *

The default implementation returns the result of calling 64 | * {@link #visitChildren} on {@code ctx}.

65 | */ 66 | @Override public T visitFormal(CoolParser.FormalContext ctx) { return visitChildren(ctx); } 67 | /** 68 | * {@inheritDoc} 69 | * 70 | *

The default implementation returns the result of calling 71 | * {@link #visitChildren} on {@code ctx}.

72 | */ 73 | @Override public T visitExpression(CoolParser.ExpressionContext ctx) { return visitChildren(ctx); } 74 | /** 75 | * {@inheritDoc} 76 | * 77 | *

The default implementation returns the result of calling 78 | * {@link #visitChildren} on {@code ctx}.

79 | */ 80 | @Override public T visitExpression_list_actual(CoolParser.Expression_list_actualContext ctx) { return visitChildren(ctx); } 81 | /** 82 | * {@inheritDoc} 83 | * 84 | *

The default implementation returns the result of calling 85 | * {@link #visitChildren} on {@code ctx}.

86 | */ 87 | @Override public T visitExpression_list(CoolParser.Expression_listContext ctx) { return visitChildren(ctx); } 88 | /** 89 | * {@inheritDoc} 90 | * 91 | *

The default implementation returns the result of calling 92 | * {@link #visitChildren} on {@code ctx}.

93 | */ 94 | @Override public T visitCase_list(CoolParser.Case_listContext ctx) { return visitChildren(ctx); } 95 | /** 96 | * {@inheritDoc} 97 | * 98 | *

The default implementation returns the result of calling 99 | * {@link #visitChildren} on {@code ctx}.

100 | */ 101 | @Override public T visitCase_(CoolParser.Case_Context ctx) { return visitChildren(ctx); } 102 | /** 103 | * {@inheritDoc} 104 | * 105 | *

The default implementation returns the result of calling 106 | * {@link #visitChildren} on {@code ctx}.

107 | */ 108 | @Override public T visitLet_looper(CoolParser.Let_looperContext ctx) { return visitChildren(ctx); } 109 | /** 110 | * {@inheritDoc} 111 | * 112 | *

The default implementation returns the result of calling 113 | * {@link #visitChildren} on {@code ctx}.

114 | */ 115 | @Override public T visitStar_slash(CoolParser.Star_slashContext ctx) { return visitChildren(ctx); } 116 | /** 117 | * {@inheritDoc} 118 | * 119 | *

The default implementation returns the result of calling 120 | * {@link #visitChildren} on {@code ctx}.

121 | */ 122 | @Override public T visitPlus_minus(CoolParser.Plus_minusContext ctx) { return visitChildren(ctx); } 123 | /** 124 | * {@inheritDoc} 125 | * 126 | *

The default implementation returns the result of calling 127 | * {@link #visitChildren} on {@code ctx}.

128 | */ 129 | @Override public T visitLt_le_equals(CoolParser.Lt_le_equalsContext ctx) { return visitChildren(ctx); } 130 | } -------------------------------------------------------------------------------- /semantic/src/java/cool/CoolParserVisitor.java: -------------------------------------------------------------------------------- 1 | // Generated from CoolParser.g4 by ANTLR 4.5.1 2 | package cool; 3 | 4 | import cool.AST; 5 | import java.util.List; 6 | 7 | import org.antlr.v4.runtime.tree.ParseTreeVisitor; 8 | 9 | /** 10 | * This interface defines a complete generic visitor for a parse tree produced 11 | * by {@link CoolParser}. 12 | * 13 | * @param The return type of the visit operation. Use {@link Void} for 14 | * operations with no return type. 15 | */ 16 | public interface CoolParserVisitor extends ParseTreeVisitor { 17 | /** 18 | * Visit a parse tree produced by {@link CoolParser#program}. 19 | * @param ctx the parse tree 20 | * @return the visitor result 21 | */ 22 | T visitProgram(CoolParser.ProgramContext ctx); 23 | /** 24 | * Visit a parse tree produced by {@link CoolParser#class_list}. 25 | * @param ctx the parse tree 26 | * @return the visitor result 27 | */ 28 | T visitClass_list(CoolParser.Class_listContext ctx); 29 | /** 30 | * Visit a parse tree produced by {@link CoolParser#class_}. 31 | * @param ctx the parse tree 32 | * @return the visitor result 33 | */ 34 | T visitClass_(CoolParser.Class_Context ctx); 35 | /** 36 | * Visit a parse tree produced by {@link CoolParser#feature_list}. 37 | * @param ctx the parse tree 38 | * @return the visitor result 39 | */ 40 | T visitFeature_list(CoolParser.Feature_listContext ctx); 41 | /** 42 | * Visit a parse tree produced by {@link CoolParser#feature}. 43 | * @param ctx the parse tree 44 | * @return the visitor result 45 | */ 46 | T visitFeature(CoolParser.FeatureContext ctx); 47 | /** 48 | * Visit a parse tree produced by {@link CoolParser#formal_list}. 49 | * @param ctx the parse tree 50 | * @return the visitor result 51 | */ 52 | T visitFormal_list(CoolParser.Formal_listContext ctx); 53 | /** 54 | * Visit a parse tree produced by {@link CoolParser#formal}. 55 | * @param ctx the parse tree 56 | * @return the visitor result 57 | */ 58 | T visitFormal(CoolParser.FormalContext ctx); 59 | /** 60 | * Visit a parse tree produced by {@link CoolParser#expression}. 61 | * @param ctx the parse tree 62 | * @return the visitor result 63 | */ 64 | T visitExpression(CoolParser.ExpressionContext ctx); 65 | /** 66 | * Visit a parse tree produced by {@link CoolParser#expression_list_actual}. 67 | * @param ctx the parse tree 68 | * @return the visitor result 69 | */ 70 | T visitExpression_list_actual(CoolParser.Expression_list_actualContext ctx); 71 | /** 72 | * Visit a parse tree produced by {@link CoolParser#expression_list}. 73 | * @param ctx the parse tree 74 | * @return the visitor result 75 | */ 76 | T visitExpression_list(CoolParser.Expression_listContext ctx); 77 | /** 78 | * Visit a parse tree produced by {@link CoolParser#case_list}. 79 | * @param ctx the parse tree 80 | * @return the visitor result 81 | */ 82 | T visitCase_list(CoolParser.Case_listContext ctx); 83 | /** 84 | * Visit a parse tree produced by {@link CoolParser#case_}. 85 | * @param ctx the parse tree 86 | * @return the visitor result 87 | */ 88 | T visitCase_(CoolParser.Case_Context ctx); 89 | /** 90 | * Visit a parse tree produced by {@link CoolParser#let_looper}. 91 | * @param ctx the parse tree 92 | * @return the visitor result 93 | */ 94 | T visitLet_looper(CoolParser.Let_looperContext ctx); 95 | /** 96 | * Visit a parse tree produced by {@link CoolParser#star_slash}. 97 | * @param ctx the parse tree 98 | * @return the visitor result 99 | */ 100 | T visitStar_slash(CoolParser.Star_slashContext ctx); 101 | /** 102 | * Visit a parse tree produced by {@link CoolParser#plus_minus}. 103 | * @param ctx the parse tree 104 | * @return the visitor result 105 | */ 106 | T visitPlus_minus(CoolParser.Plus_minusContext ctx); 107 | /** 108 | * Visit a parse tree produced by {@link CoolParser#lt_le_equals}. 109 | * @param ctx the parse tree 110 | * @return the visitor result 111 | */ 112 | T visitLt_le_equals(CoolParser.Lt_le_equalsContext ctx); 113 | } -------------------------------------------------------------------------------- /semantic/src/java/cool/Error.java: -------------------------------------------------------------------------------- 1 | package cool; 2 | 3 | public class Error { 4 | public String fname; 5 | public int line; 6 | public String err; 7 | Error(String f, int l, String er) { 8 | fname = new String(f); 9 | line = l; 10 | err = new String(er); 11 | } 12 | } -------------------------------------------------------------------------------- /semantic/src/java/cool/Makefile: -------------------------------------------------------------------------------- 1 | ANTLR_JAR = /usr/local/lib/antlr-4.5-complete.jar 2 | 3 | %: all 4 | 5 | all: 6 | javac -cp $(ANTLR_JAR) -Xlint *.java 7 | 8 | clean: 9 | rm *.class 10 | -------------------------------------------------------------------------------- /semantic/src/java/cool/ScopeTable.java: -------------------------------------------------------------------------------- 1 | package cool; 2 | import java.util.*; 3 | public class ScopeTable { 4 | private int scope; 5 | private ArrayList> maps=new ArrayList>(); 6 | public ScopeTable(){ 7 | scope = 0; 8 | maps.add(new HashMap()); 9 | } 10 | void insert(String s, T t){ 11 | maps.get(scope).put(s,t); 12 | } 13 | 14 | void insertAll(HashMap hs) { 15 | maps.get(scope).putAll(hs); 16 | } 17 | void enterScope(){ 18 | scope++; 19 | maps.add(new HashMap()); 20 | } 21 | void exitScope(){ 22 | if (scope>0){ 23 | maps.remove(scope); 24 | scope--; 25 | } 26 | } 27 | T lookUpLocal(String t){ 28 | return maps.get(scope).get(t); 29 | } 30 | T lookUpGlobal(String t){ 31 | for ( int i = scope; i>=0 ; i--){ 32 | if (maps.get(i).containsKey(t)) 33 | return maps.get(i).get(t); 34 | } 35 | return null; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /semantic/src/java/cool/SemanticTest.java: -------------------------------------------------------------------------------- 1 | package cool; 2 | 3 | import java.io.FileInputStream; 4 | import java.io.IOException; 5 | import java.util.Arrays; 6 | 7 | import org.antlr.v4.runtime.ANTLRInputStream; 8 | import org.antlr.v4.runtime.CommonTokenStream; 9 | 10 | import org.antlr.v4.runtime.CommonToken; 11 | import org.antlr.v4.runtime.Token; 12 | import org.antlr.v4.runtime.BaseErrorListener; 13 | import org.antlr.v4.runtime.Recognizer; 14 | import org.antlr.v4.runtime.RecognitionException; 15 | import org.antlr.v4.runtime.tree.*; 16 | import java.nio.file.Paths; 17 | 18 | public class SemanticTest { 19 | 20 | static String[] TOKENS = {"ERROR", "TYPEID", "OBJECTID", "BOOL_CONST", "INT_CONST", "STR_CONST", "'('", "')'", "':'", "'@'", "';'", "','", "'+'", "'-'", "'*'", "'/'", "'~'", "'<'", "'='", "'{'", "'}'", "'.'", "DARROW", "LE", "ASSIGN", "CLASS", "ELSE", "FI", "IF", "IN", "INHERITS", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "OF", "NEW", "ISVOID", "NOT" 21 | }; 22 | 23 | static int VALUED_INDEX_LIMIT = 6; 24 | static int NAMED_TOKEN_INDEX = 23; 25 | static int parser_error_flag = 0; 26 | 27 | static String escapeSpecialCharacters(String text) { 28 | return 29 | text 30 | .replaceAll("\\\\", "\\\\\\\\") 31 | .replaceAll("\n", "\\\\n") 32 | .replaceAll("\t", "\\\\t") 33 | .replaceAll("\b", "\\\\b") 34 | .replaceAll("\f", "\\\\f") 35 | .replaceAll("\"", "\\\\\"") 36 | .replaceAll("\r", "\\\\015") 37 | .replaceAll("\033","\\\\033") 38 | .replaceAll("\001","\\\\001") 39 | .replaceAll("\002","\\\\002") 40 | .replaceAll("\003","\\\\003") 41 | .replaceAll("\004","\\\\004") 42 | .replaceAll("\022","\\\\022") 43 | .replaceAll("\013","\\\\013") 44 | .replaceAll("\000", "\\\\000") 45 | ; 46 | } 47 | 48 | static void printAST(String filename) throws Exception{ 49 | ANTLRInputStream inStream=null; 50 | try{ 51 | inStream = new ANTLRInputStream(new FileInputStream(filename)); 52 | }catch(Exception e){ 53 | System.err.println("Could not read file "+filename); 54 | return; 55 | } 56 | 57 | CoolLexer lexer = new CoolLexer(inStream); 58 | CommonTokenStream tokens = new CommonTokenStream(lexer); 59 | tokens.fill(); 60 | int lexer_flag = 0; 61 | for(Token t : tokens.getTokens()){ 62 | if ( t.getType() == 1 ){ 63 | lexer_flag = 1; 64 | System.err.println("Lexical error at "+t.getLine()+": "+escapeSpecialCharacters(t.getText())); 65 | } 66 | } 67 | if (lexer_flag == 1) 68 | return; 69 | 70 | parser_error_flag = 0; 71 | CoolParser parser = new CoolParser(tokens); 72 | parser.removeErrorListeners(); 73 | parser.addErrorListener(new ParserError(Paths.get(filename).getFileName().toString())); 74 | parser.setFilename(Paths.get(filename).getFileName().toString()); 75 | 76 | CoolParser.ProgramContext prog = null; 77 | try{ 78 | prog = parser.program(); 79 | }catch(Exception e){ 80 | // e.printStackTrace(); 81 | } 82 | if(parser_error_flag == 1){ 83 | System.err.println("Compilation halted due to lex and parse errors"); 84 | return; 85 | } 86 | Semantic semanticAnalyzer=new Semantic(prog.value); 87 | if (semanticAnalyzer.getErrorFlag()){ 88 | System.err.println("Compilation halter due to semantic errors."); 89 | return; 90 | } 91 | System.out.println(prog.value.getString("")); 92 | } 93 | 94 | public static void main(String args[]) throws Exception{ 95 | 96 | if(args.length < 1) { 97 | System.err.println("No files given"); 98 | System.exit(1); 99 | } 100 | printAST(args[0]); 101 | } 102 | 103 | public static class ParserError extends BaseErrorListener { 104 | 105 | String filename; 106 | public ParserError(String fn) { 107 | super(); 108 | filename=fn; 109 | } 110 | @Override 111 | public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionIntLine, String msg, RecognitionException e){ 112 | parser_error_flag=1; 113 | String sourceName = recognizer.getInputStream().getSourceName(); 114 | String errorMessage=""; 115 | if(filename!=null){ 116 | if(offendingSymbol instanceof CommonToken){ 117 | errorMessage += "\""+filename+"\", line "+line+": syntax error at or near "; 118 | int typeid = ((CommonToken)offendingSymbol).getType(); 119 | if (typeid == -1){ 120 | errorMessage += "EOF"; 121 | } 122 | else if (typeid <= VALUED_INDEX_LIMIT) { 123 | errorMessage += TOKENS[typeid-1] + " = " + ((CommonToken)offendingSymbol).getText(); 124 | }else if(typeid >= NAMED_TOKEN_INDEX){ 125 | errorMessage += TOKENS[typeid-1]; 126 | }else{ 127 | errorMessage += "\'"+escapeSpecialCharacters(((CommonToken)offendingSymbol).getText())+"\'"; 128 | } 129 | } 130 | } 131 | System.err.println(errorMessage); 132 | throw new RuntimeException("One error found!"); 133 | } 134 | } 135 | } 136 | 137 | //objectid, typeid, int_const, string_const, bool_const 138 | // static String[] TOKENS = {"ERROR", "TYPEID", "OBJECTID", "BOOL_CONST", "INT_CONST", "STR_CONST", "'('", "')'", "':'", "'@'", "';'", "','", "'+'", "'-'", "'*'", "'/'", "'~'", "'<'", "'='", "'{'", "'}'", "'.'", "DARROW", "LE", "ASSIGN", "CLASS", "ELSE", "FI", "IF", "IN", "INHERITS", "LET", "LOOP", "POOL", "THEN", "WHILE", "CASE", "ESAC", "OF", "NEW", "ISVOID", "NOT" 139 | // }; 140 | -------------------------------------------------------------------------------- /semantic/src/java/semantic: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | java -cp ${CLASSPATH}../java cool.SemanticTest $1 3 | -------------------------------------------------------------------------------- /semantic/src/test_cases/bad.cl/bad_hierarchy.cl: -------------------------------------------------------------------------------- 1 | class Dash inherits Bash{ 2 | x : Bash <- new Bash; 3 | f(x : Int, z : String) : Int { 4 | 1 5 | }; 6 | y : Int; 7 | }; 8 | 9 | class Bash inherits Dash { 10 | f(x : Int, z : String) : String { 11 | y + 2 12 | }; 13 | y : Bool; 14 | y : Int; 15 | }; 16 | 17 | class Hash inherits Bash { 18 | d(a : Bool) : Bool { 19 | y + 1 20 | }; 21 | y : String; 22 | }; 23 | 24 | class Main inherits IO { 25 | -- the class has features. Only methods in this case. 26 | 27 | 28 | main(): Object { 29 | { 30 | if(a < a) then 31 | (out_string("Whats up?".substr(1, 3))) 32 | else 33 | out_string("Whazzy up?") 34 | fi; 35 | 36 | if(a) then 37 | out_int(1) 38 | else 39 | out_string("Hey browski") 40 | fi; 41 | 42 | if(isvoid(d)) then 43 | out_string(123) 44 | else 45 | out_string("ding dong") 46 | fi; 47 | } 48 | 49 | }; 50 | 51 | main() : Int { 52 | 1 53 | }; 54 | }; 55 | -------------------------------------------------------------------------------- /semantic/src/test_cases/bad.cl/case_check.cl: -------------------------------------------------------------------------------- 1 | class Crash { 2 | }; 3 | 4 | class Brash inherits Crash{ 5 | dl(hl : Brash) : Int { 6 | 1 7 | }; 8 | }; 9 | 10 | class Main inherits IO { 11 | main() : Object { 12 | { 13 | out_string("Enter number of numbers to multiply\n"); 14 | out_int(prod(in_int())); 15 | out_string("\n"); 16 | case (new Crash) of 17 | l : Brash => (new Brash); -- case type reused. 18 | f : Hrash => ((new Brash).dl(f)); 19 | esac; 20 | } 21 | }; 22 | 23 | prod(i : Int) : Int { 24 | let y : Int <- 1 in { 25 | while (not ((new Crash) = (new Brash)) ) loop { 26 | out_string("Enter Number: "); 27 | y <- y * in_int(); 28 | i <- i - 1; 29 | } 30 | pool; 31 | y; 32 | } 33 | }; 34 | }; 35 | -------------------------------------------------------------------------------- /semantic/src/test_cases/bad.cl/fib.cl: -------------------------------------------------------------------------------- 1 | class Bash { 2 | f() : Int { 3 | 1 4 | }; 5 | }; 6 | 7 | class Dash inherits Bash { 8 | f() : Int { 9 | 2 10 | }; 11 | }; 12 | 13 | class Main inherits IO { 14 | 15 | main(): Object { 16 | { 17 | out_string("Enter n to find nth fibonacci number!\n"); 18 | out_int(fib(in_int())); 19 | out_string("\n"); 20 | } 21 | }; 22 | 23 | fib(i : Int) : Int { 24 | let a : Int <- 1, 25 | b : Int <- 0, 26 | c : Int <- 0, 27 | d : Dash <- (new Dash), 28 | f : Bash <- (new Dash) 29 | in 30 | { 31 | while (i) loop 32 | { 33 | c <- a + b; 34 | i <- i - 1; 35 | b <- a; 36 | a <- c + d@Bash.f(); 37 | } 38 | pool; 39 | c; 40 | } 41 | }; 42 | 43 | }; 44 | -------------------------------------------------------------------------------- /semantic/src/test_cases/bad.cl/prod.cl: -------------------------------------------------------------------------------- 1 | class Crash { 2 | }; 3 | 4 | class Brash { 5 | }; 6 | 7 | class Main inherits IO { 8 | main() : Object { 9 | { 10 | out_string("Enter number of numbers to multiply\n"); 11 | out_int(prod(in_int())); 12 | out_string("\n"); 13 | } 14 | }; 15 | 16 | prod(i : Int) : Int { 17 | let y : Int <- 1 in { 18 | while (not ((new Crash) = (1)) ) loop { -- can't compare basic type and some object 19 | out_string("Enter Number: "); 20 | y <- y * in_int(); 21 | i <- i - 1; 22 | } 23 | pool; 24 | y; 25 | } 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /semantic/src/test_cases/bad.cl/testing.cl: -------------------------------------------------------------------------------- 1 | class Dash { 2 | x : Bash <- new Bash; 3 | f(x : Int, z : String) : Int { 4 | 1 5 | }; 6 | y : Int; 7 | }; 8 | 9 | class Bash inherits Dash { 10 | f(x : Int, z : String) : String { 11 | y + 2 12 | }; 13 | y : Bool; 14 | y : Int; 15 | }; 16 | 17 | class Hash inherits Bash { 18 | d(a : Bool) : Bool { 19 | y + 1 20 | }; 21 | y : String; 22 | }; 23 | 24 | class Main inherits IO { 25 | -- the class has features. Only methods in this case. 26 | 27 | 28 | main(): Object { 29 | { 30 | if(a < "a") then 31 | (out_string("Whats up?".substr(1, 3))) 32 | else 33 | out_string("Whazzy up?") 34 | fi; 35 | 36 | if(a) then 37 | out_int(as@Bash.f("heya", 12)) 38 | else 39 | out_string("Hey browski") 40 | fi; 41 | 42 | if(isvoid(d)) then 43 | out_string(123) 44 | else 45 | out_string("ding dong") 46 | fi; 47 | } 48 | 49 | }; 50 | 51 | main() : Int { 52 | 1 53 | }; 54 | 55 | 56 | fa : Int; 57 | 58 | fib(i : Int, i : Int) : Int { -- list of formals. And the return type of the method. 59 | let a : Int, 60 | b : Int <- (new Crash), 61 | c : Int <- 0, 62 | qw : Bash 63 | in 64 | { 65 | fa <- (while (not i) loop -- expressions are nested. 66 | { 67 | c <- "String"; 68 | i <- i - 1; 69 | b <- "ljasd" + (~"lka"); 70 | a <- (new Bash) + (100 + kic); 71 | b <- ~(new Bash); 72 | a = "alj"; 73 | b = (new Object); 74 | (new Object) = a; 75 | (new Bash) = (new Object); 76 | } 77 | pool); 78 | c; 79 | } 80 | }; 81 | 82 | a : Int <- 120; 83 | b : Int <- 200 + c; 84 | c : Int <- 100; 85 | d : Int <- new Int; 86 | qx : Bool <- (a < "a"); 87 | as: Bash <- new Bash; 88 | 89 | }; 90 | -------------------------------------------------------------------------------- /semantic/src/test_cases/good.cl/atoi.cl: -------------------------------------------------------------------------------- 1 | (* 2 | The class A2I provides integer-to-string and string-to-integer 3 | conversion routines. To use these routines, either inherit them 4 | in the class where needed, have a dummy variable bound to 5 | something of type A2I, or simpl write (new A2I).method(argument). 6 | *) 7 | 8 | 9 | (* 10 | c2i Converts a 1-character string to an integer. Aborts 11 | if the string is not "0" through "9" 12 | *) 13 | class A2I { 14 | 15 | c2i(char : String) : Int { 16 | if char = "0" then 0 else 17 | if char = "1" then 1 else 18 | if char = "2" then 2 else 19 | if char = "3" then 3 else 20 | if char = "4" then 4 else 21 | if char = "5" then 5 else 22 | if char = "6" then 6 else 23 | if char = "7" then 7 else 24 | if char = "8" then 8 else 25 | if char = "9" then 9 else 26 | { abort(); 0; } -- the 0 is needed to satisfy the typchecker 27 | fi fi fi fi fi fi fi fi fi fi 28 | }; 29 | 30 | (* 31 | i2c is the inverse of c2i. 32 | *) 33 | i2c(i : Int) : String { 34 | if i = 0 then "0" else 35 | if i = 1 then "1" else 36 | if i = 2 then "2" else 37 | if i = 3 then "3" else 38 | if i = 4 then "4" else 39 | if i = 5 then "5" else 40 | if i = 6 then "6" else 41 | if i = 7 then "7" else 42 | if i = 8 then "8" else 43 | if i = 9 then "9" else 44 | { abort(); ""; } -- the "" is needed to satisfy the typchecker 45 | fi fi fi fi fi fi fi fi fi fi 46 | }; 47 | 48 | (* 49 | a2i converts an ASCII string into an integer. The empty string 50 | is converted to 0. Signed and unsigned strings are handled. The 51 | method aborts if the string does not represent an integer. Very 52 | long strings of digits produce strange answers because of arithmetic 53 | overflow. 54 | 55 | *) 56 | a2i(s : String) : Int { 57 | if s.length() = 0 then 0 else 58 | if s.substr(0,1) = "-" then ~a2i_aux(s.substr(1,s.length()-1)) else 59 | if s.substr(0,1) = "+" then a2i_aux(s.substr(1,s.length()-1)) else 60 | a2i_aux(s) 61 | fi fi fi 62 | }; 63 | 64 | (* 65 | a2i_aux converts the usigned portion of the string. As a programming 66 | example, this method is written iteratively. 67 | *) 68 | a2i_aux(s : String) : Int { 69 | (let int : Int <- 0 in 70 | { 71 | (let j : Int <- s.length() in 72 | (let i : Int <- 0 in 73 | while i < j loop 74 | { 75 | int <- int * 10 + c2i(s.substr(i,1)); 76 | i <- i + 1; 77 | } 78 | pool 79 | ) 80 | ); 81 | int; 82 | } 83 | ) 84 | }; 85 | 86 | (* 87 | i2a converts an integer to a string. Positive and negative 88 | numbers are handled correctly. 89 | *) 90 | i2a(i : Int) : String { 91 | if i = 0 then "0" else 92 | if 0 < i then i2a_aux(i) else 93 | "-".concat(i2a_aux(i * ~1)) 94 | fi fi 95 | }; 96 | 97 | (* 98 | i2a_aux is an example using recursion. 99 | *) 100 | i2a_aux(i : Int) : String { 101 | if i = 0 then "" else 102 | (let next : Int <- i / 10 in 103 | i2a_aux(next).concat(i2c(i - next * 10)) 104 | ) 105 | fi 106 | }; 107 | 108 | }; 109 | 110 | class Main inherits IO { 111 | main () : Object { 112 | let a : Int <- (new A2I).a2i("678987"), 113 | b : String <- (new A2I).i2a(678987) in 114 | { 115 | out_int(a) ; 116 | out_string(" == ") ; 117 | out_string(b) ; 118 | out_string("\n"); 119 | } 120 | } ; 121 | } ; 122 | -------------------------------------------------------------------------------- /semantic/src/test_cases/good.cl/helloworld.cl: -------------------------------------------------------------------------------- 1 | class Main { 2 | main():IO { 3 | new IO.out_string("Hello world!\n") 4 | }; 5 | }; 6 | 7 | -------------------------------------------------------------------------------- /semantic/src/test_cases/good.cl/list.cl: -------------------------------------------------------------------------------- 1 | (* 2 | * This file shows how to implement a list data type for lists of integers. 3 | * It makes use of INHERITANCE and DYNAMIC DISPATCH. 4 | * 5 | * The List class has 4 operations defined on List objects. If 'l' is 6 | * a list, then the methods dispatched on 'l' have the following effects: 7 | * 8 | * isNil() : Bool Returns true if 'l' is empty, false otherwise. 9 | * head() : Int Returns the integer at the head of 'l'. 10 | * If 'l' is empty, execution aborts. 11 | * tail() : List Returns the remainder of the 'l', 12 | * i.e. without the first element. 13 | * cons(i : Int) : List Return a new list containing i as the 14 | * first element, followed by the 15 | * elements in 'l'. 16 | * 17 | * There are 2 kinds of lists, the empty list and a non-empty 18 | * list. We can think of the non-empty list as a specialization of 19 | * the empty list. 20 | * The class List defines the operations on empty list. The class 21 | * Cons inherits from List and redefines things to handle non-empty 22 | * lists. 23 | *) 24 | 25 | 26 | class List { 27 | -- Define operations on empty lists. 28 | 29 | isNil() : Bool { true }; 30 | 31 | -- Since abort() has return type Object and head() has return type 32 | -- Int, we need to have an Int as the result of the method body, 33 | -- even though abort() never returns. 34 | 35 | head() : Int { { abort(); 0; } }; 36 | 37 | -- As for head(), the self is just to make sure the return type of 38 | -- tail() is correct. 39 | 40 | tail() : List { { abort(); self; } }; 41 | 42 | -- When we cons and element onto the empty list we get a non-empty 43 | -- list. The (new Cons) expression creates a new list cell of class 44 | -- Cons, which is initialized by a dispatch to init(). 45 | -- The result of init() is an element of class Cons, but it 46 | -- conforms to the return type List, because Cons is a subclass of 47 | -- List. 48 | 49 | cons(i : Int) : List { 50 | (new Cons).init(i, self) 51 | }; 52 | 53 | }; 54 | 55 | 56 | (* 57 | * Cons inherits all operations from List. We can reuse only the cons 58 | * method though, because adding an element to the front of an emtpy 59 | * list is the same as adding it to the front of a non empty 60 | * list. All other methods have to be redefined, since the behaviour 61 | * for them is different from the empty list. 62 | * 63 | * Cons needs two attributes to hold the integer of this list 64 | * cell and to hold the rest of the list. 65 | * 66 | * The init() method is used by the cons() method to initialize the 67 | * cell. 68 | *) 69 | 70 | class Cons inherits List { 71 | 72 | car : Int; -- The element in this list cell 73 | 74 | cdr : List; -- The rest of the list 75 | 76 | isNil() : Bool { false }; 77 | 78 | head() : Int { car }; 79 | 80 | tail() : List { cdr }; 81 | 82 | init(i : Int, rest : List) : List { 83 | { 84 | car <- i; 85 | cdr <- rest; 86 | self; 87 | } 88 | }; 89 | 90 | }; 91 | 92 | 93 | 94 | (* 95 | * The Main class shows how to use the List class. It creates a small 96 | * list and then repeatedly prints out its elements and takes off the 97 | * first element of the list. 98 | *) 99 | 100 | class Main inherits IO { 101 | 102 | mylist : List; 103 | 104 | -- Print all elements of the list. Calls itself recursively with 105 | -- the tail of the list, until the end of the list is reached. 106 | 107 | print_list(l : List) : Object { 108 | if l.isNil() then out_string("\n") 109 | else { 110 | out_int(l.head()); 111 | out_string(" "); 112 | print_list(l.tail()); 113 | } 114 | fi 115 | }; 116 | 117 | -- Note how the dynamic dispatch mechanism is responsible to end 118 | -- the while loop. As long as mylist is bound to an object of 119 | -- dynamic type Cons, the dispatch to isNil calls the isNil method of 120 | -- the Cons class, which returns false. However when we reach the 121 | -- end of the list, mylist gets bound to the object that was 122 | -- created by the (new List) expression. This object is of dynamic type 123 | -- List, and thus the method isNil in the List class is called and 124 | -- returns true. 125 | 126 | main() : Object { 127 | { 128 | mylist <- new List.cons(1).cons(2).cons(3).cons(4).cons(5); 129 | while (not mylist.isNil()) loop 130 | { 131 | print_list(mylist); 132 | mylist <- mylist.tail(); 133 | } 134 | pool; 135 | } 136 | }; 137 | 138 | }; 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /semantic/src/test_cases/good.cl/primes.cl: -------------------------------------------------------------------------------- 1 | 2 | (* 3 | * methodless-primes.cl 4 | * 5 | * Designed by Jesse H. Willett, jhw@cory, 11103234, with 6 | * Istvan Siposs, isiposs@cory, 12342921. 7 | * 8 | * This program generates primes in order without using any methods. 9 | * Actually, it does use three methods: those of IO to print out each 10 | * prime, and abort() to halt the program. These methods are incidental, 11 | * however, to the information-processing functionality of the program. We 12 | * could regard the attribute 'out's sequential values as our output, and 13 | * the string "halt" as our terminate signal. 14 | * 15 | * Naturally, using Cool this way is a real waste, basically reducing it 16 | * to assembly without the benefit of compilation. 17 | * 18 | * There could even be a subroutine-like construction, in that different 19 | * code could be in the assign fields of attributes of other classes, 20 | * and it could be executed by calling 'new Sub', but no parameters 21 | * could be passed to the subroutine, and it could only return itself. 22 | * but returning itself would be useless since we couldn't call methods 23 | * and the only operators we have are for Int and Bool, which do nothing 24 | * interesting when we initialize them! 25 | *) 26 | 27 | class Main inherits IO { 28 | 29 | main() : Int { -- main() is an atrophied method so we can parse. 30 | 0 31 | }; 32 | 33 | out : Int <- -- out is our 'output'. Its values are the primes. 34 | { 35 | out_string("2 is trivially prime.\n"); 36 | 2; 37 | }; 38 | 39 | testee : Int <- out; -- testee is a number to be tested for primeness. 40 | 41 | divisor : Int; -- divisor is a number which may factor testee. 42 | 43 | stop : Int <- 500; -- stop is an arbitrary value limiting testee. 44 | 45 | m : Object <- -- m supplants the main method. 46 | while true loop 47 | { 48 | 49 | testee <- testee + 1; 50 | divisor <- 2; 51 | 52 | while 53 | if testee < divisor * divisor 54 | then false -- can stop if divisor > sqrt(testee). 55 | else if testee - divisor*(testee/divisor) = 0 56 | then false -- can stop if divisor divides testee. 57 | else true 58 | fi fi 59 | loop 60 | divisor <- divisor + 1 61 | pool; 62 | 63 | if testee < divisor * divisor -- which reason did we stop for? 64 | then -- testee has no factors less than sqrt(testee). 65 | { 66 | out <- testee; -- we could think of out itself as the output. 67 | out_int(out); 68 | out_string(" is prime.\n"); 69 | } 70 | else -- the loop halted on testee/divisor = 0, testee isn't prime. 71 | 0 -- testee isn't prime, do nothing. 72 | fi; 73 | 74 | if stop <= testee then 75 | "halt".abort() -- we could think of "halt" as SIGTERM. 76 | else 77 | "continue" 78 | fi; 79 | 80 | } 81 | pool; 82 | 83 | }; (* end of Main *) 84 | 85 | -------------------------------------------------------------------------------- /semantic/src/test_cases/good.cl/sort-list.cl: -------------------------------------------------------------------------------- 1 | (* 2 | This file presents a fairly large example of Cool programming. The 3 | class List defines the names of standard list operations ala Scheme: 4 | car, cdr, cons, isNil, rev, sort, rcons (add an element to the end of 5 | the list), and print_list. In the List class most of these functions 6 | are just stubs that abort if ever called. The classes Nil and Cons 7 | inherit from List and define the same operations, but now as 8 | appropriate to the empty list (for the Nil class) and for cons cells (for 9 | the Cons class). 10 | 11 | The Main class puts all of this code through the following silly 12 | test exercise: 13 | 14 | 1. prompt for a number N 15 | 2. generate a list of numbers 0..N-1 16 | 3. reverse the list 17 | 4. sort the list 18 | 5. print the sorted list 19 | 20 | Because the sort used is a quadratic space insertion sort, sorting 21 | moderately large lists can be quite slow. 22 | *) 23 | 24 | Class List inherits IO { 25 | (* Since abort() returns Object, we need something of 26 | type Bool at the end of the block to satisfy the typechecker. 27 | This code is unreachable, since abort() halts the program. *) 28 | isNil() : Bool { { abort(); true; } }; 29 | 30 | cons(hd : Int) : Cons { 31 | (let new_cell : Cons <- new Cons in 32 | new_cell.init(hd,self) 33 | ) 34 | }; 35 | 36 | (* 37 | Since abort "returns" type Object, we have to add 38 | an expression of type Int here to satisfy the typechecker. 39 | This code is, of course, unreachable. 40 | *) 41 | car() : Int { { abort(); new Int; } }; 42 | 43 | cdr() : List { { abort(); new List; } }; 44 | 45 | rev() : List { cdr() }; 46 | 47 | sort() : List { cdr() }; 48 | 49 | insert(i : Int) : List { cdr() }; 50 | 51 | rcons(i : Int) : List { cdr() }; 52 | 53 | print_list() : Object { abort() }; 54 | }; 55 | 56 | Class Cons inherits List { 57 | xcar : Int; -- We keep the car in cdr in attributes. 58 | xcdr : List; 59 | 60 | isNil() : Bool { false }; 61 | 62 | init(hd : Int, tl : List) : Cons { 63 | { 64 | xcar <- hd; 65 | xcdr <- tl; 66 | self; 67 | } 68 | }; 69 | 70 | car() : Int { xcar }; 71 | 72 | cdr() : List { xcdr }; 73 | 74 | rev() : List { (xcdr.rev()).rcons(xcar) }; 75 | 76 | sort() : List { (xcdr.sort()).insert(xcar) }; 77 | 78 | insert(i : Int) : List { 79 | if i < xcar then 80 | (new Cons).init(i,self) 81 | else 82 | (new Cons).init(xcar,xcdr.insert(i)) 83 | fi 84 | }; 85 | 86 | 87 | rcons(i : Int) : List { (new Cons).init(xcar, xcdr.rcons(i)) }; 88 | 89 | print_list() : Object { 90 | { 91 | out_int(xcar); 92 | out_string("\n"); 93 | xcdr.print_list(); 94 | } 95 | }; 96 | }; 97 | 98 | Class Nil inherits List { 99 | isNil() : Bool { true }; 100 | 101 | rev() : List { self }; 102 | 103 | sort() : List { self }; 104 | 105 | insert(i : Int) : List { rcons(i) }; 106 | 107 | rcons(i : Int) : List { (new Cons).init(i,self) }; 108 | 109 | print_list() : Object { true }; 110 | 111 | }; 112 | 113 | 114 | Class Main inherits IO { 115 | 116 | l : List; 117 | 118 | (* iota maps its integer argument n into the list 0..n-1 *) 119 | iota(i : Int) : List { 120 | { 121 | l <- new Nil; 122 | (let j : Int <- 0 in 123 | while j < i 124 | loop 125 | { 126 | l <- (new Cons).init(j,l); 127 | j <- j + 1; 128 | } 129 | pool 130 | ); 131 | l; 132 | } 133 | }; 134 | 135 | main() : Object { 136 | { 137 | out_string("How many numbers to sort? "); 138 | iota(in_int()).rev().sort().print_list(); 139 | } 140 | }; 141 | }; 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /semantic/src/test_cases/helloworld.cl: -------------------------------------------------------------------------------- 1 | class Main { 2 | main():IO { 3 | new IO.out_string("Hello world!\n") 4 | }; 5 | }; 6 | 7 | --------------------------------------------------------------------------------