make
java [MainClassName] [file1] [file2] ... [fileN]4 components run in sequence:
- SymTableVisitor → builds symbol table + duplicate checks
- TypeCheckingVisitor → type checking using symbol table
- OverridingOverloadingVisitor → method overloading/overriding rules
- OffsetCalculator → calculates and prints field/method offsets
- Creates symbol table and checks for duplicate declaratioins
- ClassName(String), ClassInfo:
- Parent Name (String)
- Variables: LinkedHashMap<String, String> — name -> type (order preserved)
- Methods: LinkedHashMap<String, List> — name -> list of methods
- MethodInfo:
- Method Name (String)
- Method Type/return type (String)
- Formal Parameters: LinkedHashMap<String, String> — name -> type (order matters!)
- Variables: LinkedHashMap<String, String> — name -> type
- MethodInfo:
- Duplicate class names
- Duplicate field names(int the same class)
- Duplicate local var name(in the same method)
- Duplicate parameter names(in the same method)
- Local variable cannot have same name as parameter
- MethodInfo getCurrentMethod(String className, String methodName) - returns the last added method — during Visitor 1 traversal the current method is always the last one added to the list
- Methods stored as List per name to support overloading
- LinkedHashMap used everywhere to preserve insertion order
- Main class stored in symbol table with a MethodInfo for main to support type checking inside main body
Takes the symbol table from Visitor1 and performs type checking
- Checks:
- Parent class exists
- Circular dependency
- Type validity checks(vars,methods,parameters, return types)
- Type checking in assignments
- Type checking in methods
- Array operations
- If/while conditions
- Print statements
- Return type
- checkType(var1, var2) — checks if var1 is subtype of var2
- checkMethod(classname, methodname) — finds method list in class or parents
- MethodInfo getCurrentMethod(String className, String methodName) - returns the last added method — during Visitor 1 traversal the current method is always the last one added to the list
- The visit(Identifier) function in visitor2 does not return the identifier name, instead it returns the type of the identifier. So in order to get identifier name i use i.fn.f0.toString() .
- If argu.methodName is null (class level context), returns the name string
- Always pass argu when visiting expressions — needed for variable lookup context
- argu.argTypes list collects method call argument types in MessageSend
Takes the symbol table and checks method overloading and overriding rules.
Rules are written in comments in the code
- checkType(var1, var2) — checks if var1 is same type or subtype of var2
- checkOverloading(classname) — checks overloading rules within the same class
- checkExtendBoth(classname, parentname) — checks overloading/overriding rules against parent chain
- checkExtendBoth walks up the inheritance chain recursively
- Two boolean flags used:
- sameType — tracks if all argument positions have exactly the same types (override)
- noSubtype — tracks if at least one position has no subtype relationship (valid overloading )
Calculates and prints field/method offsets for each class.
- Uses LinkedHashMap for offsets to preserve declaration order
- Tracks total field/method size per class so subclasses know where to start
- Overridden methods don't get a new offset slot — they reuse the parent's slot
- Main class is skipped — it has no fields and main is static with no offset
- If parent is main class, child starts at offset 0
- ClassInfo — holds class information (parent, fields, methods)
- MethodInf — holds method information (name, return type, params, locals)
- Argu — context passed through visitors (className, methodName, argTypes list)
All errors reported via RuntimeException — program stops at first error per file but continues to next file.