commit 2b90f84c1e7b6f9be583c23ea6a5cc54ba74b8fe Author: JanUlrich Date: Wed Mar 13 13:25:49 2024 +0100 Initialize Template diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..3a22547 --- /dev/null +++ b/pom.xml @@ -0,0 +1,92 @@ + + + + 4.0.0 + + de.dhbw.horb + decaf + 1.0-SNAPSHOT + + decaf + + + UTF-8 + 19 + 19 + + + + + junit + junit + 4.13.1 + test + + + org.antlr + antlr4 + 4.11.1 + + + + + + + org.antlr + antlr4-maven-plugin + 4.11.1 + + true + + + + antlr + + antlr4 + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + diff --git a/src/main/antlr4/de/dhbw/horb/Decaf.g4 b/src/main/antlr4/de/dhbw/horb/Decaf.g4 new file mode 100644 index 0000000..c1940f6 --- /dev/null +++ b/src/main/antlr4/de/dhbw/horb/Decaf.g4 @@ -0,0 +1,55 @@ +grammar Decaf; + +program : (var | func)*; + +var : type id ';'; +type : INT | BOOL | VOID ; + +func : 'def' type id '(' params? ')' block; +params : param (',' param)*; +param : type id; + +block : '{' var* stmt* '}'; + +stmt : loc '=' expr ';' #Assign + | funcCall ';' #FunctionCall + | 'if' '(' expr ')' block ('else' block)? #If + | 'while' '(' expr ')' block #While + | 'return' expr ';' #Return + | 'return' ';' #ReturnVoid + | 'break' ';' #Break + | 'continue' ';' #Continue + ; + +expr : expr binaryOp expr #BinaryOperation + | literal #Constant + | '(' expr ')' #Expression + | funcCall #FunCallExpression + | loc #Location +; + +binaryOp : ADD | SUB | MUL; + +loc : id ; + +funcCall : id '(' args? ')'; +args : expr (',' expr)*; + +literal : number | boolean; + +boolean : 'true' | 'false' ; + +number : Number; +id : IDENTIFIER; + +SUB : '-'; +ADD : '+'; +MUL : '*'; + +INT : 'int'; +BOOL : 'bool'; +VOID : 'void'; + +IDENTIFIER : [a-zA-Z]+; +Number : [0-9]+; +WS : [ \t\r\n] -> skip; diff --git a/src/main/java/de/dhbw/horb/ASTGenerator.java b/src/main/java/de/dhbw/horb/ASTGenerator.java new file mode 100644 index 0000000..d0802eb --- /dev/null +++ b/src/main/java/de/dhbw/horb/ASTGenerator.java @@ -0,0 +1,43 @@ +package de.dhbw.horb; + +import de.dhbw.horb.ast.*; + +import java.util.ArrayList; +import java.util.List; + +public class ASTGenerator { + + public static Program generateAST(DecafParser.ProgramContext parseTree){ + List variables = new ArrayList<>(); + for(DecafParser.VarContext varCtx : parseTree.var()){ + variables.add(generateVariable(varCtx)); + } + List funcs = new ArrayList<>(); + for(DecafParser.FuncContext fctx : parseTree.func()){ + funcs.add(generateFunc(fctx)); + } + return new Program(variables, funcs); + } + + public static Variable generateVariable(DecafParser.VarContext ctx) { + return new Variable(ctx.id().getText(), getType(ctx.type())); + } + + public static Variable generateVariable(DecafParser.ParamContext ctx) { + return new Variable(ctx.id().getText(), getType(ctx.type())); + } + + public static Function generateFunc(DecafParser.FuncContext ctx) { + throw new RuntimeException("TODO"); + } + + public static Type getType(DecafParser.TypeContext ctx){ + if(ctx.INT() != null) + return Type.INT; + if(ctx.BOOL() != null) + return Type.BOOL; + if(ctx.VOID() != null) + return Type.VOID; + throw new RuntimeException(); + } +} diff --git a/src/main/java/de/dhbw/horb/Compiler.java b/src/main/java/de/dhbw/horb/Compiler.java new file mode 100644 index 0000000..3562d1a --- /dev/null +++ b/src/main/java/de/dhbw/horb/Compiler.java @@ -0,0 +1,28 @@ +package de.dhbw.horb; + +import de.dhbw.horb.ast.*; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CommonTokenStream; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Decaf language Compiler + */ +public class Compiler +{ + + public static Program generateAST(String fromSource){ + CharStream input = CharStreams.fromString(fromSource); + DecafLexer lexer = new DecafLexer(input); + CommonTokenStream tokens = new CommonTokenStream(lexer); + DecafParser parser = new DecafParser(tokens); + DecafParser.ProgramContext tree = parser.program(); //Parsen + return ASTGenerator.generateAST(tree); + } + + +} diff --git a/src/main/java/de/dhbw/horb/ExpressionGenerator.java b/src/main/java/de/dhbw/horb/ExpressionGenerator.java new file mode 100644 index 0000000..205eb65 --- /dev/null +++ b/src/main/java/de/dhbw/horb/ExpressionGenerator.java @@ -0,0 +1,55 @@ +package de.dhbw.horb; + +import de.dhbw.horb.ast.*; + +public class ExpressionGenerator extends DecafBaseVisitor { + @Override + public Expression visitBinaryOperation(DecafParser.BinaryOperationContext ctx) { + return generateBinary(ctx); + } + + @Override + public Expression visitFunCallExpression(DecafParser.FunCallExpressionContext ctx) { + throw new RuntimeException("TODO"); + } + + @Override + public Expression visitConstant(DecafParser.ConstantContext ctx) { + return generateConstant(ctx.literal()); + } + + @Override + public Expression visitExpression(DecafParser.ExpressionContext ctx) { + //ParseTree for ( expr ) + //Just pass it down to the inner expr: + return this.visit(ctx.expr()); + } + + @Override + public Expression visitLocation(DecafParser.LocationContext ctx) { + return generateLocation(ctx.loc()); + } + + public static Expression generateConstant(DecafParser.LiteralContext ctx){ + if(ctx.number() != null) + return new IntConstant(Integer.valueOf(ctx.number().getText())); + if(ctx.boolean_() != null) + return new BoolConstant(Boolean.valueOf(ctx.boolean_().getText())); + throw new RuntimeException(); + } + public static Operator generateOperator(DecafParser.BinaryOpContext ctx){ + if(ctx.ADD() != null)return Operator.ADD; + if(ctx.SUB() != null)return Operator.SUB; + if(ctx.MUL() != null)return Operator.MUL; + throw new RuntimeException(); + } + public static Binary generateBinary(DecafParser.BinaryOperationContext ctx){ + ExpressionGenerator eGen = new ExpressionGenerator(); + return new Binary(eGen.visit(ctx.expr().get(0)) // left side + , generateOperator(ctx.binaryOp()) //operator + , eGen.visit(ctx.expr().get(1))); //right side + } + public static Location generateLocation(DecafParser.LocContext loc) { + return new Location(loc.id().getText()); + } +} diff --git a/src/main/java/de/dhbw/horb/StatementGenerator.java b/src/main/java/de/dhbw/horb/StatementGenerator.java new file mode 100644 index 0000000..77efb6b --- /dev/null +++ b/src/main/java/de/dhbw/horb/StatementGenerator.java @@ -0,0 +1,44 @@ +package de.dhbw.horb; + +import de.dhbw.horb.ast.*; + +import java.util.ArrayList; +import java.util.List; + +public class StatementGenerator extends DecafBaseVisitor { + @Override + public Statement visitAssign(DecafParser.AssignContext ctx) { + throw new RuntimeException("TODO"); + } + + @Override + public Statement visitIf(DecafParser.IfContext ctx) { + throw new RuntimeException("TODO"); + } + + @Override + public Statement visitWhile(DecafParser.WhileContext ctx) { + throw new RuntimeException("TODO"); + } + + @Override + public Statement visitReturn(DecafParser.ReturnContext ctx) { + throw new RuntimeException("TODO"); + } + + @Override + public Statement visitReturnVoid(DecafParser.ReturnVoidContext ctx) { + throw new RuntimeException("TODO"); + } + + @Override + public Statement visitBreak(DecafParser.BreakContext ctx) { + throw new RuntimeException("TODO"); + } + + @Override + public Statement visitContinue(DecafParser.ContinueContext ctx) { + throw new RuntimeException("TODO"); + } + +} diff --git a/src/main/java/de/dhbw/horb/ast/ASTVisitor.java b/src/main/java/de/dhbw/horb/ast/ASTVisitor.java new file mode 100644 index 0000000..e64bf2c --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/ASTVisitor.java @@ -0,0 +1,4 @@ +package de.dhbw.horb.ast; + +public class ASTVisitor { +} diff --git a/src/main/java/de/dhbw/horb/ast/Assignment.java b/src/main/java/de/dhbw/horb/ast/Assignment.java new file mode 100644 index 0000000..75ed1da --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/Assignment.java @@ -0,0 +1,6 @@ +package de.dhbw.horb.ast; + +import java.util.List; + +public record Assignment(Location loc, Expression value) implements Statement { +} diff --git a/src/main/java/de/dhbw/horb/ast/Binary.java b/src/main/java/de/dhbw/horb/ast/Binary.java new file mode 100644 index 0000000..7603b07 --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/Binary.java @@ -0,0 +1,8 @@ +package de.dhbw.horb.ast; + +import de.dhbw.horb.ExpressionGenerator; + +import java.util.List; + +public record Binary(Expression left, Operator op, Expression right) implements Expression{ +} diff --git a/src/main/java/de/dhbw/horb/ast/Block.java b/src/main/java/de/dhbw/horb/ast/Block.java new file mode 100644 index 0000000..4e0d96c --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/Block.java @@ -0,0 +1,7 @@ +package de.dhbw.horb.ast; + +import java.util.ArrayList; +import java.util.List; + +public record Block(List vars, List stmts) implements Node { +} diff --git a/src/main/java/de/dhbw/horb/ast/BoolConstant.java b/src/main/java/de/dhbw/horb/ast/BoolConstant.java new file mode 100644 index 0000000..f27b21d --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/BoolConstant.java @@ -0,0 +1,6 @@ +package de.dhbw.horb.ast; + +import java.util.List; + +public record BoolConstant(Boolean value) implements Expression { +} diff --git a/src/main/java/de/dhbw/horb/ast/Break.java b/src/main/java/de/dhbw/horb/ast/Break.java new file mode 100644 index 0000000..ff06254 --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/Break.java @@ -0,0 +1,6 @@ +package de.dhbw.horb.ast; + +import java.util.List; + +public record Break() implements Statement { +} diff --git a/src/main/java/de/dhbw/horb/ast/Continue.java b/src/main/java/de/dhbw/horb/ast/Continue.java new file mode 100644 index 0000000..aa1a499 --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/Continue.java @@ -0,0 +1,6 @@ +package de.dhbw.horb.ast; + +import java.util.List; + +public record Continue() implements Statement { +} diff --git a/src/main/java/de/dhbw/horb/ast/Expression.java b/src/main/java/de/dhbw/horb/ast/Expression.java new file mode 100644 index 0000000..a2d1be1 --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/Expression.java @@ -0,0 +1,4 @@ +package de.dhbw.horb.ast; + +public sealed interface Expression extends Node permits Binary, IntConstant, BoolConstant, Location, FunctionCall { +} diff --git a/src/main/java/de/dhbw/horb/ast/Function.java b/src/main/java/de/dhbw/horb/ast/Function.java new file mode 100644 index 0000000..e55a8de --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/Function.java @@ -0,0 +1,7 @@ +package de.dhbw.horb.ast; + +import java.util.List; + +public record Function(Type type, String name, List params, + Block block) implements Node { +} diff --git a/src/main/java/de/dhbw/horb/ast/FunctionCall.java b/src/main/java/de/dhbw/horb/ast/FunctionCall.java new file mode 100644 index 0000000..85150f5 --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/FunctionCall.java @@ -0,0 +1,6 @@ +package de.dhbw.horb.ast; + +import java.util.List; + +public record FunctionCall(String name, List args) implements Expression { +} diff --git a/src/main/java/de/dhbw/horb/ast/IfElse.java b/src/main/java/de/dhbw/horb/ast/IfElse.java new file mode 100644 index 0000000..aba94d0 --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/IfElse.java @@ -0,0 +1,6 @@ +package de.dhbw.horb.ast; + +import java.util.List; + +public record IfElse(Expression cond, Block ifBlock, Block elseBlock) implements Statement { +} diff --git a/src/main/java/de/dhbw/horb/ast/IntConstant.java b/src/main/java/de/dhbw/horb/ast/IntConstant.java new file mode 100644 index 0000000..887e583 --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/IntConstant.java @@ -0,0 +1,6 @@ +package de.dhbw.horb.ast; + +import java.util.List; + +public record IntConstant(Integer value) implements Expression { +} diff --git a/src/main/java/de/dhbw/horb/ast/Location.java b/src/main/java/de/dhbw/horb/ast/Location.java new file mode 100644 index 0000000..f96125c --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/Location.java @@ -0,0 +1,6 @@ +package de.dhbw.horb.ast; + +import java.util.List; + +public record Location(String name) implements Expression { +} diff --git a/src/main/java/de/dhbw/horb/ast/Node.java b/src/main/java/de/dhbw/horb/ast/Node.java new file mode 100644 index 0000000..9d46901 --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/Node.java @@ -0,0 +1,6 @@ +package de.dhbw.horb.ast; + +import java.util.List; + +public interface Node { +} diff --git a/src/main/java/de/dhbw/horb/ast/Operator.java b/src/main/java/de/dhbw/horb/ast/Operator.java new file mode 100644 index 0000000..9aea30c --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/Operator.java @@ -0,0 +1,7 @@ +package de.dhbw.horb.ast; + +public enum Operator { + ADD, + SUB, + MUL +} diff --git a/src/main/java/de/dhbw/horb/ast/Program.java b/src/main/java/de/dhbw/horb/ast/Program.java new file mode 100644 index 0000000..54601b0 --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/Program.java @@ -0,0 +1,6 @@ +package de.dhbw.horb.ast; + +import java.util.List; + +public record Program(List variables, List methods) implements Node { +} diff --git a/src/main/java/de/dhbw/horb/ast/Return.java b/src/main/java/de/dhbw/horb/ast/Return.java new file mode 100644 index 0000000..6d24a86 --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/Return.java @@ -0,0 +1,7 @@ +package de.dhbw.horb.ast; + +import java.util.ArrayList; +import java.util.List; + +public record Return(Expression ret) implements Statement { +} diff --git a/src/main/java/de/dhbw/horb/ast/ReturnVoid.java b/src/main/java/de/dhbw/horb/ast/ReturnVoid.java new file mode 100644 index 0000000..1f7326e --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/ReturnVoid.java @@ -0,0 +1,6 @@ +package de.dhbw.horb.ast; + +import java.util.List; + +public record ReturnVoid() implements Statement { +} diff --git a/src/main/java/de/dhbw/horb/ast/Statement.java b/src/main/java/de/dhbw/horb/ast/Statement.java new file mode 100644 index 0000000..11bbbdb --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/Statement.java @@ -0,0 +1,4 @@ +package de.dhbw.horb.ast; + +public sealed interface Statement extends Node permits Assignment, VoidFunctionCall, IfElse, While, Return, ReturnVoid, Break, Continue { +} diff --git a/src/main/java/de/dhbw/horb/ast/Type.java b/src/main/java/de/dhbw/horb/ast/Type.java new file mode 100644 index 0000000..3004d76 --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/Type.java @@ -0,0 +1,7 @@ +package de.dhbw.horb.ast; + +public enum Type { + INT, + BOOL, + VOID +} diff --git a/src/main/java/de/dhbw/horb/ast/Variable.java b/src/main/java/de/dhbw/horb/ast/Variable.java new file mode 100644 index 0000000..0785857 --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/Variable.java @@ -0,0 +1,6 @@ +package de.dhbw.horb.ast; + +import java.util.List; + +public record Variable(String name, Type type) implements Node{ +} diff --git a/src/main/java/de/dhbw/horb/ast/VoidFunctionCall.java b/src/main/java/de/dhbw/horb/ast/VoidFunctionCall.java new file mode 100644 index 0000000..f1570e3 --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/VoidFunctionCall.java @@ -0,0 +1,4 @@ +package de.dhbw.horb.ast; + +public record VoidFunctionCall(FunctionCall expr) implements Statement { +} diff --git a/src/main/java/de/dhbw/horb/ast/While.java b/src/main/java/de/dhbw/horb/ast/While.java new file mode 100644 index 0000000..e3fa76c --- /dev/null +++ b/src/main/java/de/dhbw/horb/ast/While.java @@ -0,0 +1,6 @@ +package de.dhbw.horb.ast; + +import java.util.List; + +public record While(Expression cond, Block block) implements Statement { +} diff --git a/src/test/java/de/dhbw/horb/CompilerTest.java b/src/test/java/de/dhbw/horb/CompilerTest.java new file mode 100644 index 0000000..79d1049 --- /dev/null +++ b/src/test/java/de/dhbw/horb/CompilerTest.java @@ -0,0 +1,32 @@ +package de.dhbw.horb; + +import static org.junit.Assert.assertTrue; + +import de.dhbw.horb.ast.Program; +import org.junit.Test; + +/** + * Unit test for simple App. + */ +public class CompilerTest +{ + /** + * Rigorous Test :-) + */ + @Test + public void generateASTTest() + { + String inputString = "def int add(int x, int y)\n" + + "{\n" + + "return x + y;\n" + + "}\n" + + "def int main()\n" + + "{\n" + + "int a;\n" + + "a = 3;\n" + + "return add(a, 2);\n" + + "}"; + Program ast = Compiler.generateAST(inputString); + assertTrue( ast.methods().size() == 2 ); + } +} diff --git a/src/test/java/de/dhbw/horb/ExpressionGeneratorTest.java b/src/test/java/de/dhbw/horb/ExpressionGeneratorTest.java new file mode 100644 index 0000000..3c252cf --- /dev/null +++ b/src/test/java/de/dhbw/horb/ExpressionGeneratorTest.java @@ -0,0 +1,64 @@ +package de.dhbw.horb; + +import de.dhbw.horb.ast.*; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CommonTokenStream; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; + +/** + * Unit test for AST Generation of Expressions. + */ +public class ExpressionGeneratorTest +{ + @Test + public void binaryTest() + { + Expression binary = generateExpression("x + 3"); + assertTrue(binary instanceof Binary); + assertTrue( ((Binary) binary).left() instanceof Location); + assertTrue( ((Binary) binary).right() instanceof IntConstant); + } + @Test + public void locationTest() + { + Expression location = generateExpression("x"); + assertTrue(location instanceof Location); + assertTrue(((Location) location).name().equals("x")); + } + + @Test + public void methodCallTest() + { + Expression mCall = generateExpression("m(x,y)"); + assertTrue(mCall instanceof FunctionCall); + assertTrue(((FunctionCall) mCall).name().equals("m")); + assertTrue(((FunctionCall) mCall).args().size() == 2); + } + + @Test + public void intConstantTest() + { + Expression intCons = generateExpression("3"); + assertTrue(intCons instanceof IntConstant); + assertTrue(((IntConstant) intCons).value() == 3); + } + @Test + public void boolConstantTest() + { + Expression boolCons = generateExpression("true"); + assertTrue(boolCons instanceof BoolConstant); + assertTrue(((BoolConstant) boolCons).value() == true); + } + + private Expression generateExpression(String from){ + String inputString = from; + CharStream input = CharStreams.fromString(inputString); + DecafLexer lexer = new DecafLexer(input); + CommonTokenStream tokens = new CommonTokenStream(lexer); + DecafParser parser = new DecafParser(tokens); + return new ExpressionGenerator().visit(parser.expr()); + } +} \ No newline at end of file diff --git a/src/test/java/de/dhbw/horb/StatementGeneratorTest.java b/src/test/java/de/dhbw/horb/StatementGeneratorTest.java new file mode 100644 index 0000000..4229bf1 --- /dev/null +++ b/src/test/java/de/dhbw/horb/StatementGeneratorTest.java @@ -0,0 +1,32 @@ +package de.dhbw.horb; + +import de.dhbw.horb.ast.*; +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CommonTokenStream; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; + +/** + * Unit test for AST Generation of Expressions. + */ +public class StatementGeneratorTest +{ + @Test + public void whileTest() + { + Statement whileStmt = generateStatement("while(true){}"); + assertTrue(whileStmt instanceof While); + assertTrue( ((While) whileStmt).block().stmts().size() == 0); + } + + private Statement generateStatement(String from){ + String inputString = from; + CharStream input = CharStreams.fromString(inputString); + DecafLexer lexer = new DecafLexer(input); + CommonTokenStream tokens = new CommonTokenStream(lexer); + DecafParser parser = new DecafParser(tokens); + return new StatementGenerator().visit(parser.stmt()); + } +} \ No newline at end of file