From 384c318c18eb9087d0ce0ef5909ff6458e83da19 Mon Sep 17 00:00:00 2001 From: ChUrl Date: Fri, 5 Feb 2021 14:08:08 +0100 Subject: [PATCH] update grammar to remove more junk + upate tests + codegen --- .../codegen/analysis/StackSizeAnalyzer.java | 8 +- .../codegen/flowgraph/FlowGraphGenerator.java | 32 ++++--- src/main/java/typechecker/TypeChecker.java | 2 +- .../java/codegen/FlowGraphGeneratorTest.java | 2 +- .../liveness/LivenessAnalysisTest.java | 2 +- .../java/parser/LexerGrammarParserTest.java | 2 +- .../java/parser/ast/ParseTreeCleanerTest.java | 6 +- .../parser/typechecker/TypeCheckerTest.java | 5 +- .../parser/typechecker/TypeTableTest.java | 2 +- .../resources/exampleGrammars/Grammar.grammar | 93 ------------------- stups.grammar | 15 +-- 11 files changed, 44 insertions(+), 125 deletions(-) delete mode 100644 src/test/resources/exampleGrammars/Grammar.grammar diff --git a/src/main/java/codegen/analysis/StackSizeAnalyzer.java b/src/main/java/codegen/analysis/StackSizeAnalyzer.java index a07a72c..0995b85 100644 --- a/src/main/java/codegen/analysis/StackSizeAnalyzer.java +++ b/src/main/java/codegen/analysis/StackSizeAnalyzer.java @@ -27,7 +27,11 @@ public final class StackSizeAnalyzer { final StackModel stack = new StackModel(); - runStackModel(tree.getRoot().getChildren().get(3).getChildren().get(11), stack); + if (tree.getRoot().getChildren().size() > 1) { + // Or else main-method would be empty + + runStackModel(tree.getRoot().getChildren().get(1), stack); + } Logger.logDebug("Found required stack-depth", StackSizeAnalyzer.class); return stack.getMax(); @@ -64,7 +68,7 @@ public final class StackSizeAnalyzer { private static void println(SyntaxTreeNode root, StackModel stack) { stack.push(root); // Getstatic - runStackModel(root.getChildren().get(1).getChildren().get(1), stack); + runStackModel(root.getChildren().get(0).getChildren().get(0), stack); stack.pop(); // Objectref stack.pop(); // Argument diff --git a/src/main/java/codegen/flowgraph/FlowGraphGenerator.java b/src/main/java/codegen/flowgraph/FlowGraphGenerator.java index 3888f45..123b1da 100644 --- a/src/main/java/codegen/flowgraph/FlowGraphGenerator.java +++ b/src/main/java/codegen/flowgraph/FlowGraphGenerator.java @@ -89,7 +89,7 @@ public final class FlowGraphGenerator { private static FlowGraph initFlowGraph(SyntaxTree tree, Map varMap, String source) { final String bytecodeVersion = "49.0"; - final String clazz = tree.getRoot().getChildren().get(1).getValue(); + final String clazz = tree.getRoot().getChildren().get(0).getValue(); final int stackSize = StackSizeAnalyzer.runStackModel(tree); final int localCount = varMap.size() + 1; @@ -104,8 +104,14 @@ public final class FlowGraphGenerator { public FlowGraph generateGraph() { Logger.logDebug("Beginning generation of source-graph", FlowGraphGenerator.class); + if (this.tree.getRoot().getChildren().size() == 1) { + // Empty main-method + + return this.graph; + } + // Skip the first 2 identifiers: ClassName, MainArgs - this.generateNode(this.tree.getRoot().getChildren().get(3).getChildren().get(11)); + this.generateNode(this.tree.getRoot().getChildren().get(1)); this.graph.purgeEmptyBlocks(); Logger.logDebug("Source-graph generation complete", FlowGraphGenerator.class); @@ -176,7 +182,7 @@ public final class FlowGraphGenerator { this.graph.addLabel("LOOPstart" + currentLabel); // Condition while ( ... ) { - this.generateNode(root.getChildren().get(0).getChildren().get(1)); + this.generateNode(root.getChildren().get(0).getChildren().get(0)); // Jump out of loop if condition is false this.graph.addJump("ifeq", "LOOPend" + currentLabel); @@ -202,7 +208,7 @@ public final class FlowGraphGenerator { final String inst = switch (type) { case "INTEGER_TYPE", "BOOLEAN_TYPE" -> "istore"; case "STRING_TYPE" -> "astore"; - default -> throw new IllegalStateException("Unexpected value: " + type); + default -> throw new CodeGenerationException("Unexpected value: " + type); }; Logger.logInfo("assign(): Node \"" + root.getName() + ": " + root.getValue() + "\" => " + inst, FlowGraphGenerator.class); @@ -239,7 +245,7 @@ public final class FlowGraphGenerator { inst = switch (root.getValue()) { case "ADD" -> ""; case "SUB" -> "ineg"; - default -> throw new IllegalStateException("Unexpected value: " + root.getValue()); + default -> throw new CodeGenerationException("Unexpected value: " + root.getValue()); }; } else if (root.getChildren().size() == 2) { //! Stack - 1 // Binary operator @@ -253,7 +259,7 @@ public final class FlowGraphGenerator { case "MUL" -> "imul"; case "DIV" -> "idiv"; case "MOD" -> "irem"; // Remainder operator - default -> throw new IllegalStateException("Unexpected value: " + root.getValue()); + default -> throw new CodeGenerationException("Unexpected value: " + root.getValue()); }; } @@ -276,7 +282,7 @@ public final class FlowGraphGenerator { if (!"NOT".equals(node.getValue())) { // Possibility doesn't exist, would be frontend-error - throw new IllegalStateException("Unexpected value: " + node.getValue()); + throw new CodeGenerationException("Unexpected value: " + node.getValue()); } this.generateNode(node.getChildren().get(0)); @@ -298,12 +304,12 @@ public final class FlowGraphGenerator { final String cmpeq = switch (type) { case "INTEGER_TYPE", "BOOLEAN_TYPE" -> "if_icmpeq"; case "STRING_TYPE" -> "if_accmpeq"; - default -> throw new IllegalStateException("Unexpected value: " + type); + default -> throw new CodeGenerationException("Unexpected value: " + type); }; final String cmpne = switch (type) { case "INTEGER_TYPE", "BOOLEAN_TYPE" -> "if_icmpne"; case "STRING_TYPE" -> "if_accmpne"; - default -> throw new IllegalStateException("Unexpected value: " + type); + default -> throw new CodeGenerationException("Unexpected value: " + type); }; // The comparison operations need to jump @@ -316,7 +322,7 @@ public final class FlowGraphGenerator { case "LESS_EQUAL" -> this.genComparisonInst("if_icmple", "LE", currentLabel); case "GREATER" -> this.genComparisonInst("if_icmpgt", "GT", currentLabel); case "GREATER_EQUAL" -> this.genComparisonInst("if_icmpge", "GE", currentLabel); - default -> throw new IllegalStateException("Unexpected value: " + node.getValue()); + default -> throw new CodeGenerationException("Unexpected value: " + node.getValue()); } } } @@ -359,7 +365,7 @@ public final class FlowGraphGenerator { final String inst = switch (type) { case "INTEGER_TYPE", "BOOLEAN_TYPE" -> "iload"; case "STRING_TYPE" -> "aload"; - default -> throw new IllegalStateException("Unexpected value: " + type); + default -> throw new CodeGenerationException("Unexpected value: " + type); }; Logger.logInfo("identifier(): Node \"" + node.getName() + ": " + node.getValue() + "\" => " + inst, FlowGraphGenerator.class); @@ -370,12 +376,12 @@ public final class FlowGraphGenerator { private void printlnNode(SyntaxTreeNode node) { //! Stack + 1 this.graph.addInstruction("getstatic", "java/lang/System/out", "Ljava/io/PrintStream;"); - final SyntaxTreeNode expr = node.getChildren().get(1).getChildren().get(1); + final SyntaxTreeNode expr = node.getChildren().get(0).getChildren().get(0); final String type = switch (this.nodeTypeMap.get(expr)) { case "BOOLEAN_TYPE" -> "Z"; case "INTEGER_TYPE" -> "I"; case "STRING_TYPE" -> "Ljava/lang/String;"; - default -> throw new IllegalStateException("Unexpected value: " + this.nodeTypeMap.get(expr)); + default -> throw new CodeGenerationException("Unexpected value: " + this.nodeTypeMap.get(expr)); }; this.generateNode(expr); diff --git a/src/main/java/typechecker/TypeChecker.java b/src/main/java/typechecker/TypeChecker.java index 73ec4cc..2943154 100644 --- a/src/main/java/typechecker/TypeChecker.java +++ b/src/main/java/typechecker/TypeChecker.java @@ -59,7 +59,7 @@ public final class TypeChecker { } else if ("par_expr".equals(root.getName())) { // Nodetable Eintrag für Klammern - final SyntaxTreeNode centerChild = root.getChildren().get(1); + final SyntaxTreeNode centerChild = root.getChildren().get(0); nodeTable.put(root, nodeTable.get(centerChild)); } else if ("IDENTIFIER".equals(root.getName())) { diff --git a/src/test/java/codegen/FlowGraphGeneratorTest.java b/src/test/java/codegen/FlowGraphGeneratorTest.java index 26dc74f..0a23494 100644 --- a/src/test/java/codegen/FlowGraphGeneratorTest.java +++ b/src/test/java/codegen/FlowGraphGeneratorTest.java @@ -36,7 +36,7 @@ class FlowGraphGeneratorTest { @BeforeAll static void init() throws IOException, URISyntaxException { - final Path path = Paths.get(FlowGraphGeneratorTest.class.getClassLoader().getResource("exampleGrammars/Grammar.grammar").toURI()); + final Path path = Paths.get(System.getProperty("user.dir") + "/stups.grammar"); final Grammar grammar = Grammar.fromFile(path); parser = StupsParser.fromGrammar(grammar); stupsGrammar = grammar; diff --git a/src/test/java/codegen/analysis/liveness/LivenessAnalysisTest.java b/src/test/java/codegen/analysis/liveness/LivenessAnalysisTest.java index 04d1a57..5a08cbd 100644 --- a/src/test/java/codegen/analysis/liveness/LivenessAnalysisTest.java +++ b/src/test/java/codegen/analysis/liveness/LivenessAnalysisTest.java @@ -34,7 +34,7 @@ class LivenessAnalysisTest { @BeforeAll static void init() throws IOException, URISyntaxException { - final Path path = Paths.get(LivenessAnalysisTest.class.getClassLoader().getResource("exampleGrammars/Grammar.grammar").toURI()); + final Path path = Paths.get(System.getProperty("user.dir") + "/stups.grammar"); final Grammar grammar = Grammar.fromFile(path); parser = StupsParser.fromGrammar(grammar); stupsGrammar = grammar; diff --git a/src/test/java/parser/LexerGrammarParserTest.java b/src/test/java/parser/LexerGrammarParserTest.java index 0a87b1c..6e814cf 100644 --- a/src/test/java/parser/LexerGrammarParserTest.java +++ b/src/test/java/parser/LexerGrammarParserTest.java @@ -24,7 +24,7 @@ class LexerGrammarParserTest { @BeforeAll static void init() throws IOException, URISyntaxException { - final Path path = Paths.get(LexerGrammarParserTest.class.getClassLoader().getResource("exampleGrammars/Grammar.grammar").toURI()); + final Path path = Paths.get(System.getProperty("user.dir") + "/stups.grammar"); final Grammar grammar = Grammar.fromFile(path); parser = StupsParser.fromGrammar(grammar); } diff --git a/src/test/java/parser/ast/ParseTreeCleanerTest.java b/src/test/java/parser/ast/ParseTreeCleanerTest.java index fcc21d2..0c25890 100644 --- a/src/test/java/parser/ast/ParseTreeCleanerTest.java +++ b/src/test/java/parser/ast/ParseTreeCleanerTest.java @@ -24,7 +24,7 @@ class ParseTreeCleanerTest { @BeforeAll static void init() throws IOException, URISyntaxException { - final Path path = Paths.get(ParseTreeCleanerTest.class.getClassLoader().getResource("exampleGrammars/Grammar.grammar").toURI()); + final Path path = Paths.get(System.getProperty("user.dir") + "/stups.grammar"); grammar = Grammar.fromFile(path); parser = StupsParser.fromGrammar(grammar); } @@ -49,7 +49,7 @@ class ParseTreeCleanerTest { ParseTreeCleaner.deleteChildren(tree, grammar); - assertThat(before - tree.size()).isEqualTo(3); + assertThat(before - tree.size()).isEqualTo(19); } @Test @@ -79,6 +79,6 @@ class ParseTreeCleanerTest { ParseTreeCleaner.clean(tree, grammar); - assertThat(tree.size()).isEqualTo(28); + assertThat(tree.size()).isEqualTo(10); } } diff --git a/src/test/java/parser/typechecker/TypeCheckerTest.java b/src/test/java/parser/typechecker/TypeCheckerTest.java index 2bb2ef1..219c567 100644 --- a/src/test/java/parser/typechecker/TypeCheckerTest.java +++ b/src/test/java/parser/typechecker/TypeCheckerTest.java @@ -23,7 +23,7 @@ import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; class TypeCheckerTest { - private final Path path = Paths.get(this.getClass().getClassLoader().getResource("exampleGrammars/Grammar.grammar").toURI()); + private final Path path = Paths.get(System.getProperty("user.dir") + "/stups.grammar"); private final Grammar grammar = Grammar.fromFile(this.path); private final StupsParser stupsParser = StupsParser.fromGrammar(this.grammar); @@ -39,9 +39,8 @@ class TypeCheckerTest { private SyntaxTree getTree(String expr) { final Lexer lex = new StupsLexer(CharStreams.fromString(exprToProg(expr))); final SyntaxTree tree = this.stupsParser.parse(lex.getAllTokens(), lex.getVocabulary()); - final SyntaxTree ast = SyntaxTree.toAbstractSyntaxTree(tree, this.grammar); - return ast; + return SyntaxTree.toAbstractSyntaxTree(tree, this.grammar); } @ParameterizedTest diff --git a/src/test/java/parser/typechecker/TypeTableTest.java b/src/test/java/parser/typechecker/TypeTableTest.java index 2580b1a..93ff0ac 100644 --- a/src/test/java/parser/typechecker/TypeTableTest.java +++ b/src/test/java/parser/typechecker/TypeTableTest.java @@ -28,7 +28,7 @@ class TypeTableTest { @BeforeAll static void init() throws IOException, URISyntaxException { - final Path path = Paths.get(TypeTableTest.class.getClassLoader().getResource("exampleGrammars/Grammar.grammar").toURI()); + final Path path = Paths.get(System.getProperty("user.dir") + "/stups.grammar"); grammar = Grammar.fromFile(path); parser = StupsParser.fromGrammar(grammar); } diff --git a/src/test/resources/exampleGrammars/Grammar.grammar b/src/test/resources/exampleGrammars/Grammar.grammar deleted file mode 100644 index 8c22435..0000000 --- a/src/test/resources/exampleGrammars/Grammar.grammar +++ /dev/null @@ -1,93 +0,0 @@ -// NTERM, TERM are reserved - -// Some Grammar-Symbols have to be named this way: -// assignment, declaration (for TypeTable creation) -// IDENTIFIER, NOT, ADD, SUB (for TypeChecking) -// expr, par_expr, assignment (for TypeChecking) - -// Nonterminals: -NTERM: val type -NTERM: op unary arith_op logic_op compare_op -NTERM: S class_cnt block_cnt -NTERM: statement stmt print -NTERM: declaration assignment -NTERM: par_expr expr expr_2 expr_f -NTERM: loop cond cond_else single_or_braced - -// Token: -TERM: CLASS PUBLIC STATIC -TERM: STRING_TYPE INTEGER_TYPE BOOLEAN_TYPE VOID_TYPE -TERM: WHILE IF ELSE -TERM: PRINTLN -TERM: ADD MUL SUB DIV MOD -TERM: AND OR NOT -TERM: LESS LESS_EQUAL GREATER GREATER_EQUAL EQUAL NOT_EQUAL -TERM: ASSIGN -TERM: L_BRACE R_BRACE L_BRACKET R_BRACKET L_PAREN R_PAREN SEMICOLON COMMA DOT -TERM: INTEGER_LIT STRING_LIT BOOLEAN_LIT -TERM: IDENTIFIER IDENTIFIER_MAIN - -// Actions: promote - Information "hochreichen": Ersetzt Node mit Child, wenn es nur ein Child gibt -// - val[promote] :: --val--INTEGER_LIT: 5 => --INTEGER_LIT: 5 - -// delifempty - Kann Node löschen, wenn dieser keinen Inhalt hat, normalerweise bei eps -// - block_cnt[delifempty] :: --block_cnt => -- - -// delchild= - Entfernt bestimmte Child-Nodes eines Parents -// - cond[delchild=IF] :: --cond--IF => --cond -// - assignment[delchild=ASSIGN] :: --assignment--ASSIGN => --assignment - -// valtoval= - Verschiebt eine Child-Value in die Parent-Value und entfernt das Child -// - assignment[valtoval=IDENTIFIER] :: --assignment--IDENTIFIER: a => --assignment: a - -// nametoval= - Verschiebt einen Child-Name in die Parent-Value und entfernt das Child -// - expr_2[nametoval=ADD] :: --expr_2--ADD => --expr_2: ADD - -// renameto= - Führt Umbenennung eines Nodes durch -// - expr_2[renameto=expr] :: --expr_2: ADD => --expr: ADD - -// General ----------------------------------------------------------------------------------------- - -val[promote] -> INTEGER_LIT | STRING_LIT | BOOLEAN_LIT | IDENTIFIER -type[promote] -> INTEGER_TYPE | STRING_TYPE | BOOLEAN_TYPE - -// OP-List: ADD,SUB,MUL,DIV,MOD,AND,OR,NOT,LESS,LESS_EQUAL,GREATER,GREATER_EQUAL,EQUAL,NOT_EQUAL -op[promote] -> arith_op | logic_op | compare_op -unary[promote] -> ADD | SUB | NOT -arith_op[promote] -> ADD | SUB | MUL | DIV | MOD -logic_op[promote] -> AND | OR | NOT -compare_op[promote] -> LESS | LESS_EQUAL | GREATER | GREATER_EQUAL | EQUAL | NOT_EQUAL - -// ------------------------------------------------------------------------------------------------- - -// START -> class IDENTIFIER { class_cnt } -S[promote] -> CLASS IDENTIFIER L_BRACE class_cnt R_BRACE | eps - -// class_cnt -> public static void main(String[] args) { block_cnt } -class_cnt[promote delifempty] -> PUBLIC STATIC VOID_TYPE IDENTIFIER_MAIN L_PAREN STRING_TYPE L_BRACKET R_BRACKET IDENTIFIER R_PAREN L_BRACE block_cnt R_BRACE | eps - -// block_ccnt -> stuff in {} | list of statements -block_cnt[promote delifempty] -> statement block_cnt | L_BRACE block_cnt R_BRACE | eps - -// statement -> stuff ending with ; | loop | condition -statement[promote] -> stmt SEMICOLON | loop | cond -stmt[promote] -> print | declaration | assignment -print -> PRINTLN par_expr - -// declaration -> type IDENTIFIER = expr; -declaration[nametoval=INTEGER_TYPE,BOOLEAN_TYPE,STRING_TYPE] -> type assignment -assignment[delchild=ASSIGN valtoval=IDENTIFIER] -> IDENTIFIER ASSIGN expr - -// par_expr -> ( expr ) -par_expr -> L_PAREN expr R_PAREN - -// expr -> expression that returns something | literal -expr[promote nametoval=ADD,SUB,MUL,DIV,MOD,AND,OR,NOT,LESS,LESS_EQUAL,GREATER,GREATER_EQUAL,EQUAL,NOT_EQUAL] -> expr_f expr_2 -expr_2[promote delifempty renameto=expr] -> op expr_f expr_2 | eps -expr_f[promote renameto=expr] -> unary expr_f | par_expr | val - -// Control-Flow -loop[delchild=WHILE] -> WHILE par_expr single_or_braced -cond[delchild=IF] -> IF par_expr single_or_braced cond_else -cond_else[delifempty delchild=ELSE] -> ELSE single_or_braced | eps -single_or_braced -> L_BRACE block_cnt R_BRACE | stmt SEMICOLON diff --git a/stups.grammar b/stups.grammar index 8c22435..039a308 100644 --- a/stups.grammar +++ b/stups.grammar @@ -61,25 +61,27 @@ compare_op[promote] -> LESS | LESS_EQUAL | GREATER | GREATER_EQUAL | EQUAL | NOT // ------------------------------------------------------------------------------------------------- // START -> class IDENTIFIER { class_cnt } -S[promote] -> CLASS IDENTIFIER L_BRACE class_cnt R_BRACE | eps +S[renameto=CLASS delchild=CLASS,R_BRACE,L_BRACE] -> CLASS IDENTIFIER L_BRACE class_cnt R_BRACE | eps // class_cnt -> public static void main(String[] args) { block_cnt } -class_cnt[promote delifempty] -> PUBLIC STATIC VOID_TYPE IDENTIFIER_MAIN L_PAREN STRING_TYPE L_BRACKET R_BRACKET IDENTIFIER R_PAREN L_BRACE block_cnt R_BRACE | eps +// remove all the stuff that is irrelevant to this simple case +class_cnt[promote delifempty delchild=L_BRACE,R_BRACE,L_PAREN,R_PAREN,L_BRACKET,R_BRACKET,IDENTIFIER,IDENTIFIER_MAIN,STRING_TYPE,VOID_TYPE,STATIC,PUBLIC] -> PUBLIC STATIC VOID_TYPE IDENTIFIER_MAIN L_PAREN STRING_TYPE L_BRACKET R_BRACKET IDENTIFIER R_PAREN L_BRACE block_cnt R_BRACE | eps // block_ccnt -> stuff in {} | list of statements block_cnt[promote delifempty] -> statement block_cnt | L_BRACE block_cnt R_BRACE | eps // statement -> stuff ending with ; | loop | condition -statement[promote] -> stmt SEMICOLON | loop | cond +statement[promote delchild=SEMICOLON] -> stmt SEMICOLON | loop | cond stmt[promote] -> print | declaration | assignment -print -> PRINTLN par_expr +print[nametoval=PRINTLN] -> PRINTLN par_expr // declaration -> type IDENTIFIER = expr; declaration[nametoval=INTEGER_TYPE,BOOLEAN_TYPE,STRING_TYPE] -> type assignment assignment[delchild=ASSIGN valtoval=IDENTIFIER] -> IDENTIFIER ASSIGN expr // par_expr -> ( expr ) -par_expr -> L_PAREN expr R_PAREN +// dont [promote] par_expr to make parenthesis-precedence easier +par_expr[delchild=L_PAREN,R_PAREN] -> L_PAREN expr R_PAREN // expr -> expression that returns something | literal expr[promote nametoval=ADD,SUB,MUL,DIV,MOD,AND,OR,NOT,LESS,LESS_EQUAL,GREATER,GREATER_EQUAL,EQUAL,NOT_EQUAL] -> expr_f expr_2 @@ -87,7 +89,8 @@ expr_2[promote delifempty renameto=expr] -> op expr_f expr_2 | eps expr_f[promote renameto=expr] -> unary expr_f | par_expr | val // Control-Flow +// Don't [delifempty] single_or_braced to make it easier to get the expression loop[delchild=WHILE] -> WHILE par_expr single_or_braced cond[delchild=IF] -> IF par_expr single_or_braced cond_else cond_else[delifempty delchild=ELSE] -> ELSE single_or_braced | eps -single_or_braced -> L_BRACE block_cnt R_BRACE | stmt SEMICOLON +single_or_braced[promote delchild=L_BRACE,R_BRACE] -> L_BRACE block_cnt R_BRACE | stmt SEMICOLON