diff --git a/MicroJava Compiler/src/ssw/mj/impl/Parser.java b/MicroJava Compiler/src/ssw/mj/impl/Parser.java index f260f0e..95afcd6 100644 --- a/MicroJava Compiler/src/ssw/mj/impl/Parser.java +++ b/MicroJava Compiler/src/ssw/mj/impl/Parser.java @@ -1,12 +1,10 @@ package ssw.mj.impl; -import javassist.bytecode.analysis.ControlFlow; -import javassist.compiler.ast.MethodDecl; -import ssw.mj.Errors; import ssw.mj.Errors.Message; import ssw.mj.scanner.Token; +import ssw.mj.symtab.Obj; +import ssw.mj.symtab.Struct; -import javax.xml.stream.FactoryConfigurationError; import java.util.EnumSet; import static ssw.mj.Errors.Message.*; @@ -142,7 +140,7 @@ public final class Parser { static final EnumSet breakMethodDecl = EnumSet.of(rbrace, eof); - static > EnumSet enumUnion(EnumSet first, EnumSet ...sets) { + static > EnumSet enumUnion(EnumSet first, EnumSet... sets) { final var copy = EnumSet.copyOf(first); for (final var set : sets) { copy.addAll(set); @@ -167,18 +165,25 @@ public final class Parser { check(Token.Kind.program); check(Token.Kind.ident); + final var program = tab.insert(Obj.Kind.Prog, t.val, Tab.noType); + tab.openScope(); + while (!breakDecl.contains(sym)) { if (firstVarDecl.contains(sym)) { VarDecl(); } else if (firstClassDecl.contains(sym)) { ClassDecl(); - } else if (firstConstDecl.contains(sym)){ + } else if (firstConstDecl.contains(sym)) { ConstDecl(); } else { recoverDecl(); } } + if (tab.curScope.nVars() > MAX_GLOBALS) { + error(TOO_MANY_GLOBALS); + } + check(lbrace); while (!breakMethodDecl.contains(sym)) { @@ -190,18 +195,33 @@ public final class Parser { } check(rbrace); + program.locals = tab.curScope.locals(); + tab.closeScope(); } private void ConstDecl() { check(Token.Kind.final_); - Type(); + final var type = Type(); check(Token.Kind.ident); + final var identVal = t.val; check(Token.Kind.assign); if (sym == Token.Kind.number) { + if (type != Tab.intType) { + error(INCOMPATIBLE_TYPES); + } + scan(); + final var obj = tab.insert(Obj.Kind.Con, identVal, type); + obj.val = t.numVal; } else if (sym == Token.Kind.charConst) { + if (type != Tab.charType) { + error(INCOMPATIBLE_TYPES); + } + scan(); + final var obj = tab.insert(Obj.Kind.Con, identVal, type); + obj.val = t.numVal; } else { error(TOKEN_EXPECTED, "number or character constant"); } @@ -210,12 +230,15 @@ public final class Parser { } private void VarDecl() { - Type(); + final var type = Type(); check(ident); + tab.insert(Obj.Kind.Var, t.val, type); while (sym == Token.Kind.comma) { scan(); check(ident); + tab.insert(Obj.Kind.Var, t.val, type); + System.out.println(tab.curScope.nVars()); } check(semicolon); @@ -224,36 +247,81 @@ public final class Parser { private void ClassDecl() { check(class_); check(ident); + final var identVal = t.val; check(lbrace); + final var structObj = new Struct(Struct.Kind.Class); + tab.insert(Obj.Kind.Type, identVal, structObj); + + tab.openScope(); + while (firstVarDecl.contains(sym)) { VarDecl(); } + structObj.fields = tab.curScope.locals(); + + if (tab.curScope.nVars() > MAX_FIELDS) { + error(TOO_MANY_FIELDS); + } + System.out.println(identVal); + tab.closeScope(); check(rbrace); } - private void Type() { + private Struct Type() { check(ident); + final var identVal = t.val; + var isArray = false; if (sym == lbrack) { + isArray = true; scan(); check(rbrack); } + + final var type = switch (identVal) { + case "int" -> Tab.intType; + case "char" -> Tab.charType; + default -> { + final var obj = tab.find(identVal); + + if (obj == tab.noObj) { + error(NAME_NOT_FOUND, identVal); + } + + if (obj.kind != Obj.Kind.Type) { + error(TYPE_EXPECTED); + } + + yield obj.type; + } + }; + + if (isArray) { + return new Struct(type); + } + + return type; } private void MethodDecl() { + var npars = 0; + Struct type = Tab.noType; if (sym == ident) { - Type(); + type = Type(); } else if (sym == void_) { scan(); } check(ident); + final var methodObj = tab.insert(Obj.Kind.Meth, t.val, type); check(lpar); + tab.openScope(); + if (sym == ident) { - FormPars(); + npars = FormPars(); } check(rpar); @@ -262,18 +330,41 @@ public final class Parser { VarDecl(); } + if (tab.curScope.nVars() > MAX_LOCALS) { + error(TOO_MANY_LOCALS); + } + + if (methodObj.name.equals("main") && methodObj.type != Tab.noType) { + error(MAIN_NOT_VOID); + } + + if (methodObj.name.equals("main") && npars > 0) { + error(MAIN_WITH_PARAMS); + } + Block(); + + methodObj.locals = tab.curScope.locals(); + methodObj.nPars = npars; + tab.closeScope(); } - private void FormPars() { - Type(); + private int FormPars() { + var nPars = 0; + var type = Type(); check(ident); + tab.insert(Obj.Kind.Var, t.val, type); + nPars++; while (sym == comma) { scan(); - Type(); + type = Type(); check(ident); + tab.insert(Obj.Kind.Var, t.val, type); + nPars++; } + + return nPars; } private void Block() { @@ -322,7 +413,7 @@ public final class Parser { check(rpar); Statement(); } - case break_-> { + case break_ -> { scan(); check(semicolon); } @@ -358,17 +449,31 @@ public final class Parser { case lbrace -> Block(); case semicolon -> scan(); default -> recoverStatement(); - }; + } } } private void Designator() { check(ident); + final var targetObject = tab.find(t.val); + var lastType = targetObject.type; + + if (targetObject == tab.noObj) { + error(NAME_NOT_FOUND, t.val); + } + while (sym == period || sym == lbrack) { if (sym == period) { scan(); check(ident); + final var fieldObject = tab.findField(t.val, lastType); + + if (fieldObject == tab.noObj) { + error(FIELD_NOT_FOUND, t.val); + } + + lastType = fieldObject.type; } else { scan(); @@ -378,10 +483,11 @@ public final class Parser { Expr(); + lastType = lastType.elemType; + check(rbrack); } } - } private void AssignOp() { @@ -392,7 +498,8 @@ public final class Parser { case timesas -> scan(); case slashas -> scan(); case remas -> scan(); - default -> error(TOKEN_EXPECTED, "unexpected token. assignment token (=, +=, -=, *=, /=, %=), method call (\"(\"), increment (++) or decrement (--)"); + default -> + error(TOKEN_EXPECTED, "unexpected token. assignment token (=, +=, -=, *=, /=, %=), method call (\"(\"), increment (++) or decrement (--)"); } } @@ -411,7 +518,6 @@ public final class Parser { } private void ActPars() { - check(lpar); if (sym == minus || firstFactor.contains(sym)) { @@ -446,20 +552,37 @@ public final class Parser { } private void Factor() { - switch(sym) { - case ident -> Designator(); + switch (sym) { + case ident -> { + Designator(); + + if (sym == lpar) { + ActPars(); + } + } case number -> scan(); case charConst -> scan(); case new_ -> { scan(); check(ident); + if (sym == lbrack) { scan(); Expr(); check(rbrack); + } else { + final var typeObj = tab.find(t.val); + + if (typeObj == tab.noObj) { + error(NAME_NOT_FOUND, t.val); + } + + if (typeObj.type.kind != Struct.Kind.Class) { + error(CLASS_TYPE_EXPECTED); + } } } - case lpar -> { + case lpar -> { scan(); Expr(); check(rpar); diff --git a/MicroJava Compiler/src/ssw/mj/impl/Tab.java b/MicroJava Compiler/src/ssw/mj/impl/Tab.java index 8e7ad71..e1642a9 100644 --- a/MicroJava Compiler/src/ssw/mj/impl/Tab.java +++ b/MicroJava Compiler/src/ssw/mj/impl/Tab.java @@ -1,100 +1,143 @@ package ssw.mj.impl; +import javassist.tools.rmi.StubGenerator; +import ssw.mj.Errors; import ssw.mj.symtab.Obj; import ssw.mj.symtab.Scope; import ssw.mj.symtab.Struct; public final class Tab { - // Universe - public static final Struct noType = new Struct(Struct.Kind.None); - public static final Struct intType = new Struct(Struct.Kind.Int); - public static final Struct charType = new Struct(Struct.Kind.Char); - public static final Struct nullType = new Struct(Struct.Kind.Class); + // Universe + public static final Struct noType = new Struct(Struct.Kind.None); + public static final Struct intType = new Struct(Struct.Kind.Int); + public static final Struct charType = new Struct(Struct.Kind.Char); + public static final Struct nullType = new Struct(Struct.Kind.Class); - public final Obj noObj, chrObj; - public Obj ordObj, lenObj; + public final Obj noObj, chrObj; + public Obj ordObj, lenObj; - /** - * Only used for reporting errors. - */ - private final Parser parser; - /** - * The current top scope. - */ - public Scope curScope = null; - // First scope opening (universe) will increase this to -1 - /** - * Nesting level of current scope. - */ - private int curLevel = -2; + /** + * Only used for reporting errors. + */ + private final Parser parser; + /** + * The current top scope. + */ + public Scope curScope = null; + // First scope opening (universe) will increase this to -1 + /** + * Nesting level of current scope. + */ + private int curLevel = -2; - public Tab(Parser p) { - parser = p; + public Tab(Parser p) { + parser = p; - // setting up "universe" (= predefined names) - // opening scope (curLevel goes to -1, which is the universe level) - openScope(); + // setting up "universe" (= predefined names) + // opening scope (curLevel goes to -1, which is the universe level) + openScope(); - noObj = new Obj(Obj.Kind.Var, "noObj", noType); + noObj = new Obj(Obj.Kind.Var, "noObj", noType); - insert(Obj.Kind.Type, "int", intType); - insert(Obj.Kind.Type, "char", charType); - insert(Obj.Kind.Con, "null", nullType); + insert(Obj.Kind.Type, "int", intType); + insert(Obj.Kind.Type, "char", charType); + insert(Obj.Kind.Con, "null", nullType); - chrObj = insert(Obj.Kind.Meth, "chr", charType); - openScope(); - Obj iVarObj = insert(Obj.Kind.Var, "i", intType); - iVarObj.level = 1; - chrObj.nPars = curScope.nVars(); - chrObj.locals = curScope.locals(); - closeScope(); + chrObj = insert(Obj.Kind.Meth, "chr", charType); + openScope(); + Obj iVarObj = insert(Obj.Kind.Var, "i", intType); + iVarObj.level = 1; + chrObj.nPars = curScope.nVars(); + chrObj.locals = curScope.locals(); + closeScope(); - // TODO Exercise UE-P-4: build "ord" universe method and store in ordObj + // TODO Exercise UE-P-4: build "ord" universe method and store in ordObj - // TODO Exercise UE-P-4: build "len" universe method and store in lenObj + ordObj = insert(Obj.Kind.Meth, "ord", intType); + openScope(); + Obj chVarObj = insert(Obj.Kind.Var, "ch", charType); + chVarObj.level = 1; + ordObj.nPars = curScope.nVars(); + ordObj.locals = curScope.locals(); + closeScope(); - // still on level -1 - // now that the universe is constructed, the next node that will be added is the Program itself - // (which will open its own scope with level 0) - } + // TODO Exercise UE-P-4: build "len" universe method and store in lenObj - // =============================================== - // TODO Exercise UE-P-4: implementation of symbol table - // =============================================== + final var notypeArrStruct = new Struct(noType); + lenObj = insert(Obj.Kind.Meth, "len", intType); + openScope(); + Obj arrVarObj = insert(Obj.Kind.Var, "arr", notypeArrStruct); + arrVarObj.level = 1; + lenObj.nPars = curScope.nVars(); + lenObj.locals = curScope.locals(); + closeScope(); - public void openScope() { - curScope = new Scope(curScope); - curLevel++; - } + // still on level -1 + // now that the universe is constructed, the next node that will be added is the Program itself + // (which will open its own scope with level 0) + } - public void closeScope() { - curScope = curScope.outer(); - curLevel--; - } + // =============================================== + // TODO Exercise UE-P-4: implementation of symbol table + // =============================================== - public Obj insert(Obj.Kind kind, String name, Struct type) { - // TODO Exercise UE-P-4 - return noObj; - } + public void openScope() { + curScope = new Scope(curScope); + curLevel++; + } - /** - * Retrieves the object with name from the innermost scope. - */ - public Obj find(String name) { - // TODO Exercise UE-P-4 - return noObj; - } + public void closeScope() { + curScope = curScope.outer(); + curLevel--; + } - /** - * Retrieves the field name from the fields of - * type. - */ - public Obj findField(String name, Struct type) { - // TODO Exercise UE-P-4 - return noObj; - } + public Obj insert(Obj.Kind kind, String name, Struct type) { + final var obj = new Obj(kind, name, type); - // =============================================== - // =============================================== + if (kind == Obj.Kind.Var) { + obj.adr = curScope.nVars(); + obj.level = curLevel; + } + + final var duplicate = curScope.locals().get(name); + + if (duplicate != null) { + parser.error(Errors.Message.DUPLICATE_NAME_IN_SCOPE, name); + } + + curScope.insert(obj); + // TODO Exercise UE-P-4 + return obj; + } + + /** + * Retrieves the object with name from the innermost scope. + */ + public Obj find(String name) { + // TODO Exercise UE-P-4 + + var scope = curScope; + + while (scope != null) { + final var result = scope.locals().get(name); + if (result != null) return result; + scope = scope.outer(); + } + + return noObj; + } + + /** + * Retrieves the field name from the fields of + * type. + */ + public Obj findField(String name, Struct type) { + // TODO Exercise UE-P-5 + final var fieldObject = type.findField(name); + return fieldObject == null ? noObj : fieldObject; + } + + // =============================================== + // =============================================== }