collect parser errors

This commit is contained in:
Boolean-true 2024-07-03 21:56:47 +02:00
parent a5d13fd2a9
commit e23ec8ad82
7 changed files with 112 additions and 71 deletions

View File

@ -14,8 +14,11 @@ import java.util.List;
public class ASTGenerator {
public static CollectingErrorListener errorListener;
public static Class generateAST(DecafParser.ClassContext ctx, CollectingErrorListener errorListener2) {
errorListener = errorListener2;
public static Class generateAST(DecafParser.ClassContext ctx) {
List<Declaration> declarations = new ArrayList<>();
if (ctx.field() != null) {
declarations = ctx.field().stream().map(ASTGenerator::generateFieldVariable).toList();
@ -30,9 +33,9 @@ public class ASTGenerator {
Block mainmeth = null;
if (!ctx.mainmeth().isEmpty()) {
if (ctx.mainmeth().size() > 1) {
throw new RuntimeException("Only one main method allowed!");
errorListener.generatorError("Only one main method allowed!");
}
mainmeth = new BlockGenerator().visit(ctx.mainmeth().get(0).block());
mainmeth = new BlockGenerator(errorListener).visit(ctx.mainmeth().get(0).block());
}
List<Method> meths = new ArrayList<>();
if (ctx.meth() != null) {
@ -55,7 +58,7 @@ public class ASTGenerator {
if (ctx.params() != null) {
params = ctx.params().param().stream().map(ASTGenerator::generateParameter).toList();
}
Block block = new BlockGenerator().visit(ctx.block());
Block block = new BlockGenerator(errorListener).visit(ctx.block());
return new Method(getType(ctx.returntype()), ctx.id().IDENTIFIER().getText(), params, block);
}
@ -64,7 +67,7 @@ public class ASTGenerator {
if (ctx.params() != null) {
params = ctx.params().param().stream().map(ASTGenerator::generateParameter).toList();
}
Block block = new BlockGenerator().visit(ctx.block());
Block block = new BlockGenerator(errorListener).visit(ctx.block());
return new Constructor( ctx.id().getText(), params, block);
}
@ -78,7 +81,8 @@ public class ASTGenerator {
if (ctx.id() != null) {
return Type.REFERENCE(ctx.id().getText());
}
throw new RuntimeException("No type found!");
errorListener.generatorError("No type found");
return null;
}
public static Type getType(DecafParser.ReturntypeContext ctx) {
if (ctx.type() != null){
@ -87,6 +91,7 @@ public class ASTGenerator {
if (ctx.VOID() != null){
return Type.VOID;
}
throw new RuntimeException("No type found!");
errorListener.generatorError("No type found");
return null;
}
}

View File

@ -10,17 +10,22 @@ import java.util.ArrayList;
import java.util.List;
public class BlockGenerator extends DecafBaseVisitor<Block> {
private final CollectingErrorListener errorListener;
public BlockGenerator(CollectingErrorListener errorListener) {
this.errorListener = errorListener;
}
@Override
public Block visitBlock(DecafParser.BlockContext ctx) {
List<Statement> statements = new ArrayList<>(ctx.stmt().size());
for (DecafParser.StmtContext stmtContext : ctx.stmt()) {
List<Statement> statementList = new StatementGenerator().visit(stmtContext);
List<Statement> statementList = new StatementGenerator(errorListener).visit(stmtContext);
if (statementList != null){
statements.addAll(statementList);
}
}
if (ctx.return_() != null){
statements.add(ctx.return_().expr() == null ? new Return(null) : new Return(new ExpressionGenerator().visit(ctx.return_().expr())));
statements.add(ctx.return_().expr() == null ? new Return(null) : new Return(new ExpressionGenerator(errorListener).visit(ctx.return_().expr())));
}
return new Block(statements);
}

View File

@ -0,0 +1,26 @@
package de.maishai;
import org.antlr.v4.runtime.BaseErrorListener;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer;
import java.util.ArrayList;
import java.util.List;
public class CollectingErrorListener extends BaseErrorListener {
private final List<String> errors = new ArrayList<>();
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
errors.add("Error in line " + line + ":" + charPositionInLine + " " + msg);
}
public void generatorError(String msg) {
errors.add("Error: " + msg);
}
public List<String> getErrors() {
return errors;
}
}

View File

@ -23,23 +23,27 @@ public class Compiler {
public static Program generateAST(List<String> fromSources) {
List<Class> classes = new ArrayList<>();
CollectingErrorListener errorListener = new CollectingErrorListener();
for (String fromSource : fromSources) {
CharStream input = CharStreams.fromString(fromSource);
DecafLexer lexer = new DecafLexer(input);
//add custom error listener
lexer.removeErrorListeners();
lexer.addErrorListener(ThrowingErrorListener.INSTANCE);
lexer.addErrorListener(errorListener);
CommonTokenStream tokens = new CommonTokenStream(lexer);
DecafParser parser = new DecafParser(tokens);
//add custom error listener
parser.removeErrorListeners();
parser.addErrorListener(ThrowingErrorListener.INSTANCE);
parser.addErrorListener(errorListener);
DecafParser.ClassContext tree = parser.class_(); //Parsen
classes.add(ASTGenerator.generateAST(tree));
classes.add(ASTGenerator.generateAST(tree, errorListener));
}
for (String error : errorListener.getErrors()) {
LOGGER.severe(error);
}
return new Program(classes);
}

View File

@ -11,9 +11,15 @@ import java.util.ArrayList;
import java.util.List;
public class ExpressionGenerator extends DecafBaseVisitor<Expression> {
private final CollectingErrorListener errorListener;
public ExpressionGenerator(CollectingErrorListener errorListener) {
this.errorListener = errorListener;
}
@Override
public Expression visitBinaryOperation(DecafParser.BinaryOperationContext ctx) {
return generateBinary(ctx);
return generateBinary(ctx, errorListener);
}
@Override
@ -25,12 +31,13 @@ public class ExpressionGenerator extends DecafBaseVisitor<Expression> {
if (ctx.unaryOp().SUB() != null) {
return new Unary(UnaryOperator.SUB, expr);
}
throw new RuntimeException("No unary operator found.");
errorListener.generatorError("No unary operator found");
return null;
}
@Override
public Expression visitConstant(DecafParser.ConstantContext ctx) {
return generateConstant(ctx.literal());
return generateConstant(ctx.literal(), errorListener);
}
@Override
@ -46,7 +53,7 @@ public class ExpressionGenerator extends DecafBaseVisitor<Expression> {
Expression recipient = null;
if (ctx.fieldVarAccess().recipient() != null) {
List<DecafParser.RecipientContext> recipientList = ctx.fieldVarAccess().recipient();
recipient = ExpressionGenerator.generateRecursiveOwnerChain(recipientList, ctx.fieldVarAccess().newCall() != null ? StatementGenerator.generateNew(ctx.fieldVarAccess().newCall()) : null, isField);
recipient = ExpressionGenerator.generateRecursiveOwnerChain(recipientList, ctx.fieldVarAccess().newCall() != null ? StatementGenerator.generateNew(ctx.fieldVarAccess().newCall(), errorListener) : null, isField, errorListener);
}
if (recipient == null) {
return new FieldVarAccess(isField, null, ctx.fieldVarAccess().id().IDENTIFIER().getText());
@ -54,7 +61,7 @@ public class ExpressionGenerator extends DecafBaseVisitor<Expression> {
return new FieldVarAccess(true, recipient, ctx.fieldVarAccess().id().IDENTIFIER().getText());
}
public static Expression generateConstant(DecafParser.LiteralContext ctx) {
public static Expression generateConstant(DecafParser.LiteralContext ctx, CollectingErrorListener errorListener) {
if (ctx.NUMBER() != null) {
return new IntLiteral(Integer.valueOf(ctx.NUMBER().getText()));
}
@ -63,17 +70,19 @@ public class ExpressionGenerator extends DecafBaseVisitor<Expression> {
}
if (ctx.CHARLITERAL() != null) {
if (ctx.CHARLITERAL().getText().length() != 3) {
throw new RuntimeException("Wrong format for Char literal. Good format: 'c' Bad format: " + ctx.CHARLITERAL().getText());
errorListener.generatorError("Wrong format for Char literal. Good format: 'c' Bad format: " + ctx.CHARLITERAL().getText());
return null;
}
return new CharLiteral(ctx.CHARLITERAL().getText().charAt(1));
}
throw new RuntimeException("No literal found!");
errorListener.generatorError("No literal found");
return null;
}
public static Binary generateBinary(DecafParser.BinaryOperationContext ctx) {
ExpressionGenerator eGen = new ExpressionGenerator();
public static Binary generateBinary(DecafParser.BinaryOperationContext ctx, CollectingErrorListener errorListener) {
ExpressionGenerator eGen = new ExpressionGenerator(errorListener);
Binary binary = new Binary(eGen.visit(ctx.expr().get(0)) // left side
, generateOperator(ctx.binaryOp()) //operator
, generateOperator(ctx.binaryOp(), errorListener) //operator
, eGen.visit(ctx.expr().get(1))); //right side
binary = pointBeforeLineLogic(ctx, binary);
@ -81,7 +90,7 @@ public class ExpressionGenerator extends DecafBaseVisitor<Expression> {
return binary;
}
public static Operator generateOperator(DecafParser.BinaryOpContext ctx) {
public static Operator generateOperator(DecafParser.BinaryOpContext ctx, CollectingErrorListener errorListener) {
if (ctx.ADD() != null) return Operator.ADD;
if (ctx.SUB() != null) return Operator.SUB;
if (ctx.MUL() != null) return Operator.MUL;
@ -95,7 +104,8 @@ public class ExpressionGenerator extends DecafBaseVisitor<Expression> {
if (ctx.NE() != null) return Operator.NE;
if (ctx.AND() != null) return Operator.AND;
if (ctx.OR() != null) return Operator.OR;
throw new RuntimeException("No operator found!");
errorListener.generatorError("No operator found");
return null;
}
@Override
@ -109,7 +119,7 @@ public class ExpressionGenerator extends DecafBaseVisitor<Expression> {
Expression recursiveOwnerChain = null;
if (ctx.methCall().recipient() != null) {
List<DecafParser.RecipientContext> recipientList = ctx.methCall().recipient();
recursiveOwnerChain = ExpressionGenerator.generateRecursiveOwnerChain(recipientList, ctx.methCall().newCall() != null ? StatementGenerator.generateNew(ctx.methCall().newCall()) : null, isField);
recursiveOwnerChain = ExpressionGenerator.generateRecursiveOwnerChain(recipientList, ctx.methCall().newCall() != null ? StatementGenerator.generateNew(ctx.methCall().newCall(), errorListener) : null, isField, errorListener);
}
List<Expression> args = new ArrayList<>();
if (ctx.methCall().methName().args() != null) {
@ -126,11 +136,11 @@ public class ExpressionGenerator extends DecafBaseVisitor<Expression> {
@Override
public Expression visitNew(DecafParser.NewContext ctx) {
return StatementGenerator.generateNew(ctx.newCall());
return StatementGenerator.generateNew(ctx.newCall(), errorListener);
}
public static Expression generateRecursiveOwnerChain(List<DecafParser.RecipientContext> ctxList, Expression recipient, Boolean isField) {
public static Expression generateRecursiveOwnerChain(List<DecafParser.RecipientContext> ctxList, Expression recipient, Boolean isField, CollectingErrorListener errorListener) {
if (ctxList.isEmpty()) {
return recipient;
}
@ -141,23 +151,24 @@ public class ExpressionGenerator extends DecafBaseVisitor<Expression> {
if (ctxList.isEmpty()) {
return new FieldVarAccess(isField, recipient, ctx.id().IDENTIFIER().getText());
}
return new FieldVarAccess(true, generateRecursiveOwnerChain(ctxList, recipient, isField), ctx.id().IDENTIFIER().getText());
return new FieldVarAccess(true, generateRecursiveOwnerChain(ctxList, recipient, isField, errorListener), ctx.id().IDENTIFIER().getText());
}
if (ctx.methName() != null) {
List<Expression> args = new ArrayList<>();
if (ctx.methName().args() != null) {
for (var expr : ctx.methName().args().expr()) {
Expression astExpr = expr.accept(new ExpressionGenerator());
Expression astExpr = expr.accept(new ExpressionGenerator(errorListener));
args.add(astExpr);
}
}
if (ctxList.isEmpty()) {
return new MethodCall(new FieldVarAccess(isField, recipient, ctx.methName().id().IDENTIFIER().getText()), args);
}
return new MethodCall(new FieldVarAccess(true, generateRecursiveOwnerChain(ctxList, recipient, isField), ctx.methName().id().IDENTIFIER().getText()), args);
return new MethodCall(new FieldVarAccess(true, generateRecursiveOwnerChain(ctxList, recipient, isField, errorListener), ctx.methName().id().IDENTIFIER().getText()), args);
}
throw new RuntimeException();
errorListener.generatorError("Unknown Recipient while generating Recursive Owner Chain");
return null;
}
private static Binary pointBeforeLineLogic(DecafParser.BinaryOperationContext ctx, Binary binary) {

View File

@ -10,18 +10,24 @@ import java.util.ArrayList;
import java.util.List;
public class StatementGenerator extends DecafBaseVisitor<List<Statement>> {
private final CollectingErrorListener errorListener;
public StatementGenerator(CollectingErrorListener errorListener) {
this.errorListener = errorListener;
}
@Override
public List<Statement> visitIf(DecafParser.IfContext ctx) {
Expression expr = new ExpressionGenerator().visit(ctx.ifCall().expr());
Block ifBlock = new BlockGenerator().visit(ctx.ifCall().block(0));
Expression expr = new ExpressionGenerator(errorListener).visit(ctx.ifCall().expr());
Block ifBlock = new BlockGenerator(errorListener).visit(ctx.ifCall().block(0));
Block elseBlock = null;
if (ctx.ifCall().block().size() == 2) {
elseBlock = new BlockGenerator().visit(ctx.ifCall().block(1));
elseBlock = new BlockGenerator(errorListener).visit(ctx.ifCall().block(1));
}
if (ctx.ifCall().elseIf() != null){
for (int i = ctx.ifCall().elseIf().size()-1; i >= 0; i--) {
IfElse current = new IfElse(new ExpressionGenerator().visit(ctx.ifCall().elseIf(i).expr()),
new BlockGenerator().visit(ctx.ifCall().elseIf(i).block()),
IfElse current = new IfElse(new ExpressionGenerator(errorListener).visit(ctx.ifCall().elseIf(i).expr()),
new BlockGenerator(errorListener).visit(ctx.ifCall().elseIf(i).block()),
elseBlock);
elseBlock = new Block(List.of(current));
}
@ -33,12 +39,12 @@ public class StatementGenerator extends DecafBaseVisitor<List<Statement>> {
@Override
public List<Statement> visitFor(DecafParser.ForContext ctx) {
Expression expr = new ExpressionGenerator().visit(ctx.expr());
Expression expr = new ExpressionGenerator(errorListener).visit(ctx.expr());
Assignment update = generateAssign(ctx.assign().get(ctx.assign().size() - 1));
Block block = new BlockGenerator().visit(ctx.block());
Block block = new BlockGenerator(errorListener).visit(ctx.block());
if (ctx.assign().size() == 1) {
Declaration declaration = new Declaration(ctx.localVarWithInitialization().id().IDENTIFIER().getText(), ASTGenerator.getType(ctx.localVarWithInitialization().type()));
Expression initialization = new ExpressionGenerator().visit(ctx.localVarWithInitialization().expr());
Expression initialization = new ExpressionGenerator(errorListener).visit(ctx.localVarWithInitialization().expr());
Assignment init = new Assignment(new FieldVarAccess(false, null, declaration.name()), initialization);
return List.of(declaration, new For(init, expr, update, block));
}
@ -48,15 +54,15 @@ public class StatementGenerator extends DecafBaseVisitor<List<Statement>> {
@Override
public List<Statement> visitWhile(DecafParser.WhileContext ctx) {
Expression expr = new ExpressionGenerator().visit(ctx.expr());
Block block = new BlockGenerator().visit(ctx.block());
Expression expr = new ExpressionGenerator(errorListener).visit(ctx.expr());
Block block = new BlockGenerator(errorListener).visit(ctx.block());
return List.of(new While(expr, block));
}
@Override
public List<Statement> visitDoWhile(DecafParser.DoWhileContext ctx) {
Block block = new BlockGenerator().visit(ctx.block());
Expression expr = new ExpressionGenerator().visit(ctx.expr());
Block block = new BlockGenerator(errorListener).visit(ctx.block());
Expression expr = new ExpressionGenerator(errorListener).visit(ctx.expr());
return List.of(new DoWhile(block, expr));
}
@ -79,7 +85,7 @@ public class StatementGenerator extends DecafBaseVisitor<List<Statement>> {
@Override
public List<Statement> visitLocalVarDecWithInitialization(DecafParser.LocalVarDecWithInitializationContext ctx) {
Declaration declaration = new Declaration(ctx.localVarWithInitialization().id().IDENTIFIER().getText(), ASTGenerator.getType(ctx.localVarWithInitialization().type()));
Expression initialization = new ExpressionGenerator().visit(ctx.localVarWithInitialization().expr());
Expression initialization = new ExpressionGenerator(errorListener).visit(ctx.localVarWithInitialization().expr());
return List.of(declaration, new Assignment(new FieldVarAccess(false, null, declaration.name()), initialization));
}
@ -91,14 +97,14 @@ public class StatementGenerator extends DecafBaseVisitor<List<Statement>> {
@Override
public List<Statement> visitPrint(DecafParser.PrintContext ctx) {
return List.of(new Print(new ExpressionGenerator().visit(ctx.expr())));
return List.of(new Print(new ExpressionGenerator(errorListener).visit(ctx.expr())));
}
private Assignment generateAssign(DecafParser.AssignContext ctx) {
FieldVarAccess fieldVarAccess;
if (ctx.incrDecr() == null) {
fieldVarAccess = generateField(ctx.fieldVarAccess());
Expression expr = resolveFancyAssign(ctx.assignSign(), fieldVarAccess, new ExpressionGenerator().visit(ctx.expr()));
Expression expr = resolveFancyAssign(ctx.assignSign(), fieldVarAccess, new ExpressionGenerator(errorListener).visit(ctx.expr()), errorListener);
return new Assignment(fieldVarAccess, expr);
}
fieldVarAccess = generateField(ctx.incrDecr().fieldVarAccess());
@ -110,7 +116,7 @@ public class StatementGenerator extends DecafBaseVisitor<List<Statement>> {
Boolean isField = fieldIdContext.THIS() != null;
Expression recipient = null;
if (fieldIdContext.recipient() != null) {
recipient = ExpressionGenerator.generateRecursiveOwnerChain(fieldIdContext.recipient(), null, isField);
recipient = ExpressionGenerator.generateRecursiveOwnerChain(fieldIdContext.recipient(), null, isField, errorListener);
}
if (recipient == null) {
return new FieldVarAccess(isField, null, fieldIdContext.id().IDENTIFIER().getText());
@ -130,14 +136,14 @@ public class StatementGenerator extends DecafBaseVisitor<List<Statement>> {
List<Expression> args = new ArrayList<>();
if (ctx.methCall().methName().args() != null) {
for (var expr : ctx.methCall().methName().args().expr()) {
Expression astExpr = expr.accept(new ExpressionGenerator());
Expression astExpr = expr.accept(new ExpressionGenerator(errorListener));
args.add(astExpr);
}
}
Expression recursiveOwnerChain = null;
if (ctx.methCall().recipient() != null) {
List<DecafParser.RecipientContext> recipientList = ctx.methCall().recipient();
recursiveOwnerChain = ExpressionGenerator.generateRecursiveOwnerChain(recipientList, ctx.methCall().newCall() != null ? generateNew(ctx.methCall().newCall()) : null, isField);
recursiveOwnerChain = ExpressionGenerator.generateRecursiveOwnerChain(recipientList, ctx.methCall().newCall() != null ? generateNew(ctx.methCall().newCall(), errorListener) : null, isField, errorListener);
}
if (recursiveOwnerChain == null) {
return List.of(new MethodCall(new FieldVarAccess(isField, null, ctx.methCall().methName().id().IDENTIFIER().getText()), args));
@ -147,22 +153,22 @@ public class StatementGenerator extends DecafBaseVisitor<List<Statement>> {
@Override
public List<Statement> visitNew(DecafParser.NewContext ctx) {
return List.of( generateNew(ctx.newCall()));
return List.of( generateNew(ctx.newCall(), errorListener));
}
public static New generateNew(DecafParser.NewCallContext ctx){
public static New generateNew(DecafParser.NewCallContext ctx, CollectingErrorListener errorListener) {
Type type = ASTGenerator.getType(ctx.type());
List<Expression> args = new ArrayList<>();
if (ctx.args() != null) {
for (var expr : ctx.args().expr()) {
Expression astExpr = expr.accept(new ExpressionGenerator());
Expression astExpr = expr.accept(new ExpressionGenerator(errorListener));
args.add(astExpr);
}
}
return new New(type, args);
}
public static Expression resolveFancyAssign(DecafParser.AssignSignContext ctx, FieldVarAccess fieldVarAccess, Expression expression) {
public static Expression resolveFancyAssign(DecafParser.AssignSignContext ctx, FieldVarAccess fieldVarAccess, Expression expression, CollectingErrorListener errorListener) {
if (ctx.ASSIGN() != null)
return expression;
if (ctx.ADD_ASSIGN() != null)
@ -175,6 +181,7 @@ public class StatementGenerator extends DecafBaseVisitor<List<Statement>> {
return new Binary(fieldVarAccess, Operator.DIV, expression);
if (ctx.MOD_ASSIGN() != null)
return new Binary(fieldVarAccess, Operator.MOD, expression);
throw new RuntimeException("No assign sign found!");
errorListener.generatorError("No assign sign found");
return null;
}
}

View File

@ -1,17 +0,0 @@
package de.maishai;
import org.antlr.v4.runtime.BaseErrorListener;
import org.antlr.v4.runtime.RecognitionException;
import org.antlr.v4.runtime.Recognizer;
import org.antlr.v4.runtime.misc.ParseCancellationException;
public class ThrowingErrorListener extends BaseErrorListener {
public static final ThrowingErrorListener INSTANCE = new ThrowingErrorListener();
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e)
throws ParseCancellationException {
throw new ParseCancellationException("Error in line " + line + ":" + charPositionInLine + " " + msg);
}
}