finished exercise

This commit is contained in:
2025-11-08 17:16:16 +01:00
parent e854da56aa
commit c1eef57c97
21 changed files with 348 additions and 95 deletions

View File

@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="lib2" level="project" />
<orderEntry type="library" name="lib" level="project" />
</component>
</module>

View File

@@ -9,8 +9,7 @@ import ssw.mj.scanner.Token;
import javax.xml.stream.FactoryConfigurationError;
import java.util.EnumSet;
import static ssw.mj.Errors.Message.TOKEN_EXPECTED;
import static ssw.mj.Errors.Message.UNDEFINED_ESCAPE;
import static ssw.mj.Errors.Message.*;
import static ssw.mj.scanner.Token.Kind.*;
public final class Parser {
@@ -60,6 +59,10 @@ public final class Parser {
*/
public final Tab tab;
private static int MIN_ERROR_DIST = 3;
private int errorDist = MIN_ERROR_DIST;
public Parser(Scanner scanner) {
this.scanner = scanner;
tab = new Tab(this);
@@ -76,6 +79,7 @@ public final class Parser {
t = la;
la = scanner.next();
sym = la.kind;
errorDist++;
}
/**
@@ -95,8 +99,12 @@ public final class Parser {
public void error(Message msg, Object... msgParams) {
// TODO Exercise UE-P-3: Replace panic mode with error recovery (i.e., keep track of error distance)
// TODO Exercise UE-P-3: Hint: Replacing panic mode also affects scan() method
scanner.errors.error(la.line, la.col, msg, msgParams);
throw new Errors.PanicMode();
if (errorDist >= MIN_ERROR_DIST) {
scanner.errors.error(la.line, la.col, msg, msgParams);
}
errorDist = 0;
}
/**
@@ -124,10 +132,15 @@ public final class Parser {
static final EnumSet<Token.Kind> firstConstDecl = EnumSet.of(Token.Kind.final_);
static final EnumSet<Token.Kind> firstVarDecl = EnumSet.of(Token.Kind.ident);
static final EnumSet<Token.Kind> firstClassDecl = EnumSet.of(Token.Kind.class_);
static final EnumSet<Token.Kind> breakDecl = EnumSet.of(lbrace, eof);
static final EnumSet<Token.Kind> firstStatement = EnumSet.of(ident, if_, while_, break_, return_, read, print, lbrace, semicolon);
static final EnumSet<Token.Kind> breakStatement = EnumSet.of(rbrace, else_, eof);
static final EnumSet<Token.Kind> firstAsignop = EnumSet.of(assign, plusas, minusas, timesas, slashas, remas);
static final EnumSet<Token.Kind> firstFactor = EnumSet.of(ident, number, charConst, new_, lpar);
static final EnumSet<Token.Kind> firstMulop = EnumSet.of(times, slash, rem);
static final EnumSet<Token.Kind> firstMethodDecl = EnumSet.of(ident, void_);
static final EnumSet<Token.Kind> breakMethodDecl = EnumSet.of(rbrace, eof);
static <T extends Enum<T>> EnumSet<T> enumUnion(EnumSet<T> first, EnumSet<T> ...sets) {
final var copy = EnumSet.copyOf(first);
@@ -154,22 +167,26 @@ public final class Parser {
check(Token.Kind.program);
check(Token.Kind.ident);
final var firstDeclarationUnion = enumUnion(firstConstDecl, firstVarDecl, firstClassDecl);
while (firstDeclarationUnion.contains(sym)) {
while (!breakDecl.contains(sym)) {
if (firstVarDecl.contains(sym)) {
VarDecl();
} else if (firstClassDecl.contains(sym)) {
ClassDecl();
} else {
} else if (firstConstDecl.contains(sym)){
ConstDecl();
} else {
recoverDecl();
}
}
check(lbrace);
while (sym == ident || sym == void_) {
MethodDecl();
while (!breakMethodDecl.contains(sym)) {
if (firstMethodDecl.contains(sym)) {
MethodDecl();
} else {
recoverMethodDecl();
}
}
check(rbrace);
@@ -266,7 +283,7 @@ public final class Parser {
}
private void Statement() {
while (firstStatement.contains(sym)) {
while (!breakStatement.contains(sym)) {
switch (sym) {
case ident -> {
Designator();
@@ -340,6 +357,7 @@ public final class Parser {
}
case lbrace -> Block();
case semicolon -> scan();
default -> recoverStatement();
};
}
}
@@ -504,6 +522,40 @@ public final class Parser {
// TODO Exercise UE-P-3: Error recovery methods: recoverDecl, recoverMethodDecl and recoverStat (+ TODO Exercise UE-P-5: Check idents for Type kind)
private void recoverDecl() {
final var firstDeclarationUnion = enumUnion(firstConstDecl, firstVarDecl, firstClassDecl);
final var recoverDeclSet = enumUnion(breakDecl, firstDeclarationUnion);
error(DECLARATION_RECOVERY);
do {
scan();
} while (!recoverDeclSet.contains(sym));
errorDist = 0;
}
private void recoverMethodDecl() {
error(METHOD_DECL_RECOVERY);
final var recoveryMethoDeclSet = enumUnion(breakMethodDecl, firstMethodDecl);
do {
scan();
} while (!recoveryMethoDeclSet.contains(sym));
errorDist = 0;
}
private void recoverStatement() {
error(STATEMENT_RECOVERY);
var recoveryStatementSet = enumUnion(breakStatement, firstStatement);
recoveryStatementSet.remove(ident);
recoveryStatementSet.remove(lbrace);
do {
scan();
} while (!recoveryStatementSet.contains(sym));
errorDist = 0;
}
// ====================================
// ====================================
}