finished exercise

This commit is contained in:
2025-11-22 18:14:30 +01:00
parent 669709e6aa
commit 01fbd78bc5
2 changed files with 262 additions and 96 deletions

View File

@@ -1,12 +1,10 @@
package ssw.mj.impl; 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.Errors.Message;
import ssw.mj.scanner.Token; 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 java.util.EnumSet;
import static ssw.mj.Errors.Message.*; import static ssw.mj.Errors.Message.*;
@@ -167,6 +165,9 @@ public final class Parser {
check(Token.Kind.program); check(Token.Kind.program);
check(Token.Kind.ident); check(Token.Kind.ident);
final var program = tab.insert(Obj.Kind.Prog, t.val, Tab.noType);
tab.openScope();
while (!breakDecl.contains(sym)) { while (!breakDecl.contains(sym)) {
if (firstVarDecl.contains(sym)) { if (firstVarDecl.contains(sym)) {
VarDecl(); VarDecl();
@@ -179,6 +180,10 @@ public final class Parser {
} }
} }
if (tab.curScope.nVars() > MAX_GLOBALS) {
error(TOO_MANY_GLOBALS);
}
check(lbrace); check(lbrace);
while (!breakMethodDecl.contains(sym)) { while (!breakMethodDecl.contains(sym)) {
@@ -190,18 +195,33 @@ public final class Parser {
} }
check(rbrace); check(rbrace);
program.locals = tab.curScope.locals();
tab.closeScope();
} }
private void ConstDecl() { private void ConstDecl() {
check(Token.Kind.final_); check(Token.Kind.final_);
Type(); final var type = Type();
check(Token.Kind.ident); check(Token.Kind.ident);
final var identVal = t.val;
check(Token.Kind.assign); check(Token.Kind.assign);
if (sym == Token.Kind.number) { if (sym == Token.Kind.number) {
if (type != Tab.intType) {
error(INCOMPATIBLE_TYPES);
}
scan(); scan();
final var obj = tab.insert(Obj.Kind.Con, identVal, type);
obj.val = t.numVal;
} else if (sym == Token.Kind.charConst) { } else if (sym == Token.Kind.charConst) {
if (type != Tab.charType) {
error(INCOMPATIBLE_TYPES);
}
scan(); scan();
final var obj = tab.insert(Obj.Kind.Con, identVal, type);
obj.val = t.numVal;
} else { } else {
error(TOKEN_EXPECTED, "number or character constant"); error(TOKEN_EXPECTED, "number or character constant");
} }
@@ -210,12 +230,15 @@ public final class Parser {
} }
private void VarDecl() { private void VarDecl() {
Type(); final var type = Type();
check(ident); check(ident);
tab.insert(Obj.Kind.Var, t.val, type);
while (sym == Token.Kind.comma) { while (sym == Token.Kind.comma) {
scan(); scan();
check(ident); check(ident);
tab.insert(Obj.Kind.Var, t.val, type);
System.out.println(tab.curScope.nVars());
} }
check(semicolon); check(semicolon);
@@ -224,36 +247,81 @@ public final class Parser {
private void ClassDecl() { private void ClassDecl() {
check(class_); check(class_);
check(ident); check(ident);
final var identVal = t.val;
check(lbrace); check(lbrace);
final var structObj = new Struct(Struct.Kind.Class);
tab.insert(Obj.Kind.Type, identVal, structObj);
tab.openScope();
while (firstVarDecl.contains(sym)) { while (firstVarDecl.contains(sym)) {
VarDecl(); VarDecl();
} }
structObj.fields = tab.curScope.locals();
if (tab.curScope.nVars() > MAX_FIELDS) {
error(TOO_MANY_FIELDS);
}
System.out.println(identVal);
tab.closeScope();
check(rbrace); check(rbrace);
} }
private void Type() { private Struct Type() {
check(ident); check(ident);
final var identVal = t.val;
var isArray = false;
if (sym == lbrack) { if (sym == lbrack) {
isArray = true;
scan(); scan();
check(rbrack); 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() { private void MethodDecl() {
var npars = 0;
Struct type = Tab.noType;
if (sym == ident) { if (sym == ident) {
Type(); type = Type();
} else if (sym == void_) { } else if (sym == void_) {
scan(); scan();
} }
check(ident); check(ident);
final var methodObj = tab.insert(Obj.Kind.Meth, t.val, type);
check(lpar); check(lpar);
tab.openScope();
if (sym == ident) { if (sym == ident) {
FormPars(); npars = FormPars();
} }
check(rpar); check(rpar);
@@ -262,18 +330,41 @@ public final class Parser {
VarDecl(); VarDecl();
} }
Block(); if (tab.curScope.nVars() > MAX_LOCALS) {
error(TOO_MANY_LOCALS);
} }
private void FormPars() { if (methodObj.name.equals("main") && methodObj.type != Tab.noType) {
Type(); 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 int FormPars() {
var nPars = 0;
var type = Type();
check(ident); check(ident);
tab.insert(Obj.Kind.Var, t.val, type);
nPars++;
while (sym == comma) { while (sym == comma) {
scan(); scan();
Type(); type = Type();
check(ident); check(ident);
tab.insert(Obj.Kind.Var, t.val, type);
nPars++;
} }
return nPars;
} }
private void Block() { private void Block() {
@@ -358,17 +449,31 @@ public final class Parser {
case lbrace -> Block(); case lbrace -> Block();
case semicolon -> scan(); case semicolon -> scan();
default -> recoverStatement(); default -> recoverStatement();
}; }
} }
} }
private void Designator() { private void Designator() {
check(ident); 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) { while (sym == period || sym == lbrack) {
if (sym == period) { if (sym == period) {
scan(); scan();
check(ident); check(ident);
final var fieldObject = tab.findField(t.val, lastType);
if (fieldObject == tab.noObj) {
error(FIELD_NOT_FOUND, t.val);
}
lastType = fieldObject.type;
} else { } else {
scan(); scan();
@@ -378,10 +483,11 @@ public final class Parser {
Expr(); Expr();
lastType = lastType.elemType;
check(rbrack); check(rbrack);
} }
} }
} }
private void AssignOp() { private void AssignOp() {
@@ -392,7 +498,8 @@ public final class Parser {
case timesas -> scan(); case timesas -> scan();
case slashas -> scan(); case slashas -> scan();
case remas -> 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() { private void ActPars() {
check(lpar); check(lpar);
if (sym == minus || firstFactor.contains(sym)) { if (sym == minus || firstFactor.contains(sym)) {
@@ -447,16 +553,33 @@ public final class Parser {
private void Factor() { private void Factor() {
switch (sym) { switch (sym) {
case ident -> Designator(); case ident -> {
Designator();
if (sym == lpar) {
ActPars();
}
}
case number -> scan(); case number -> scan();
case charConst -> scan(); case charConst -> scan();
case new_ -> { case new_ -> {
scan(); scan();
check(ident); check(ident);
if (sym == lbrack) { if (sym == lbrack) {
scan(); scan();
Expr(); Expr();
check(rbrack); 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 -> {

View File

@@ -1,5 +1,7 @@
package ssw.mj.impl; package ssw.mj.impl;
import javassist.tools.rmi.StubGenerator;
import ssw.mj.Errors;
import ssw.mj.symtab.Obj; import ssw.mj.symtab.Obj;
import ssw.mj.symtab.Scope; import ssw.mj.symtab.Scope;
import ssw.mj.symtab.Struct; import ssw.mj.symtab.Struct;
@@ -52,8 +54,25 @@ public final class Tab {
// 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
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();
// TODO Exercise UE-P-4: build "len" universe method and store in lenObj // TODO Exercise UE-P-4: build "len" universe method and store in lenObj
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();
// still on level -1 // still on level -1
// now that the universe is constructed, the next node that will be added is the Program itself // 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) // (which will open its own scope with level 0)
@@ -74,8 +93,22 @@ public final class Tab {
} }
public Obj insert(Obj.Kind kind, String name, Struct type) { 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 // TODO Exercise UE-P-4
return noObj; return obj;
} }
/** /**
@@ -83,6 +116,15 @@ public final class Tab {
*/ */
public Obj find(String name) { public Obj find(String name) {
// TODO Exercise UE-P-4 // 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; return noObj;
} }
@@ -91,8 +133,9 @@ public final class Tab {
* <code>type</code>. * <code>type</code>.
*/ */
public Obj findField(String name, Struct type) { public Obj findField(String name, Struct type) {
// TODO Exercise UE-P-4 // TODO Exercise UE-P-5
return noObj; final var fieldObject = type.findField(name);
return fieldObject == null ? noObj : fieldObject;
} }
// =============================================== // ===============================================