update grammar to remove more junk + upate tests + codegen
This commit is contained in:
@ -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
|
||||
|
@ -89,7 +89,7 @@ public final class FlowGraphGenerator {
|
||||
|
||||
private static FlowGraph initFlowGraph(SyntaxTree tree, Map<String, Integer> 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);
|
||||
|
@ -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())) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
@ -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
|
||||
|
Reference in New Issue
Block a user