Compare commits
17 Commits
Endabgabe
...
217eccf3d1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
217eccf3d1 | ||
|
|
6f44050743 | ||
| 90bb3f0673 | |||
| 78cfdd0d52 | |||
|
|
bf38f1e5d1 | ||
|
|
cc7bb479b1 | ||
|
|
faa4bf1307 | ||
|
|
14802b11df | ||
|
|
4f3b3b8bd8 | ||
| 592f9a28ac | |||
| 5cb3b8fa57 | |||
|
|
ddeee4cbf2 | ||
|
|
43d767615c | ||
|
|
5e8ce1beda | ||
|
|
322276cd97 | ||
|
|
7e0e7f2f24 | ||
|
|
387b5ea0f0 |
@@ -1,15 +0,0 @@
|
||||
name: Gitea Actions Demo
|
||||
run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
Explore-Gitea-Actions:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
- name: Run the Maven verify phase
|
||||
run: mvn --batch-mode --update-snapshots verify
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -77,10 +77,3 @@ fabric.properties
|
||||
.idea/caches/build_file_checksums.ser
|
||||
|
||||
/target
|
||||
src/main/resources/logs/miniCompilerLog.log
|
||||
src/test/java/main/CompilerInput.class
|
||||
src/test/resources/output/javac/CompilerInput$Test.class
|
||||
src/test/resources/output/javac/CompilerInput.class
|
||||
src/test/resources/output/miniCompiler/CompilerInput.class
|
||||
src/test/resources/output/miniCompiler/CompilerInput$Test.class
|
||||
.idea/inspectionProfiles/Project_Default.xml
|
||||
|
||||
19
.idea/ANTLRv4ToolGrammarProperties.xml
generated
19
.idea/ANTLRv4ToolGrammarProperties.xml
generated
@@ -1,19 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ANTLRv4ToolGrammarProperties">
|
||||
<option name="perGrammarGenerationSettings">
|
||||
<list>
|
||||
<PerGrammarGenerationSettings>
|
||||
<option name="fileName" value="$PROJECT_DIR$/src/main/java/parser/grammar/SimpleJava.g4" />
|
||||
<option name="autoGen" value="true" />
|
||||
<option name="outputDir" value="C:\Users\janni\Desktop\NichtHaskell2.0\src\main\java" />
|
||||
<option name="libDir" value="" />
|
||||
<option name="encoding" value="" />
|
||||
<option name="pkg" value="parser.generated" />
|
||||
<option name="language" value="" />
|
||||
<option name="generateVisitor" value="true" />
|
||||
</PerGrammarGenerationSettings>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
5
.idea/codeStyles/codeStyleConfig.xml
generated
5
.idea/codeStyles/codeStyleConfig.xml
generated
@@ -1,5 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
</state>
|
||||
</component>
|
||||
5
.idea/jarRepositories.xml
generated
5
.idea/jarRepositories.xml
generated
@@ -6,11 +6,6 @@
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven_central" />
|
||||
<option name="name" value="Maven Central" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
|
||||
14
.idea/misc.xml
generated
14
.idea/misc.xml
generated
@@ -6,17 +6,7 @@
|
||||
<PerGrammarGenerationSettings>
|
||||
<option name="fileName" value="$PROJECT_DIR$/src/main/java/parser/SimpleJava.g4" />
|
||||
<option name="autoGen" value="true" />
|
||||
<option name="outputDir" value="C:\Users\ARB00075\Documents\DH\Compilerbau\NichtHaskell2.0\src\main\java" />
|
||||
<option name="libDir" value="" />
|
||||
<option name="encoding" value="" />
|
||||
<option name="pkg" value="parser.generated" />
|
||||
<option name="language" value="" />
|
||||
<option name="generateVisitor" value="true" />
|
||||
</PerGrammarGenerationSettings>
|
||||
<PerGrammarGenerationSettings>
|
||||
<option name="fileName" value="$PROJECT_DIR$/src/main/java/parser/grammar/SimpleJava.g4" />
|
||||
<option name="autoGen" value="true" />
|
||||
<option name="outputDir" value="C:\Users\Maxi\Documents\DHBW\Compilerbau\NichtHaskell2.0\src\main\java" />
|
||||
<option name="outputDir" value="C:\Users\Johannes\Documents\Github\JavaCompiler\src\main\java" />
|
||||
<option name="libDir" value="" />
|
||||
<option name="encoding" value="" />
|
||||
<option name="pkg" value="parser.generated" />
|
||||
@@ -50,7 +40,7 @@
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_22" default="true" project-jdk-name="openjdk-22" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="openjdk-21" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
Binary file not shown.
37
Makefile
37
Makefile
@@ -1,37 +0,0 @@
|
||||
### IntelliJs play buttons do not work. Run in "src/test" folder with "make" command to run all
|
||||
### Or run only parts with "make compile-javac", "make clean" etc.
|
||||
|
||||
all: compile-javac compile-miniCompiler
|
||||
|
||||
compile-javac:
|
||||
#javac -d src/test/resources/output/javac src/test/resources/input/CompilerInput.java
|
||||
|
||||
compile-miniCompiler:
|
||||
cd ../.. ; mvn -DskipTests install
|
||||
cd ../.. ; mvn exec:java -DgenJar=true -DgenClass=true -Dexec.mainClass="main.Main" -Dexec.args="'src/main/resources/input/CompilerInput.java' 'src/main/resources/output'"
|
||||
# cp src/main/resources/output/CompilerInput.class src/test/resources/output/miniCompiler
|
||||
|
||||
test-miniCompiler:
|
||||
# move the compiled class to the test/main folder
|
||||
mv src/main/resources/output/CompilerInput.class src/test/java/main/
|
||||
# compile the test class
|
||||
javac src/test/java/main/EndToEndTester.java
|
||||
# run the test class
|
||||
java -cp src/test/java/main EndToEndTester
|
||||
|
||||
clean:
|
||||
# clean main output folders
|
||||
rm -f src/main/resources/output/*.class
|
||||
rm -f src/main/resources/output/*.jar
|
||||
# clean resources output folders
|
||||
rm -f src/test/resources/output/javac/*.class
|
||||
rm -f src/test/resources/output/miniCompiler/*.class
|
||||
rm -f src/test/resources/output/miniCompiler/*.jar
|
||||
# clean logs
|
||||
rm -f src/main/resources/logs/*
|
||||
# clean test/java/main folders from .class files for End-to-End tests
|
||||
rm -f src/test/java/main/*.class
|
||||
# clean javac output from every folder
|
||||
rm -f src/test/resources/input/*/*.class
|
||||
# clean test results from maven surefire plugin
|
||||
rm -f ../../target/surefire-reports/*.txt
|
||||
Binary file not shown.
136
README.md
136
README.md
@@ -1,136 +0,0 @@
|
||||
# "Nicht Haskel 2.0" Java Compiler
|
||||
|
||||
Realisation of a subset of the Java Standard Compiler in the course Compiler Construction of the 4th semester Computer Science at the Duale Hochschule Stuttgart (Horb).
|
||||
|
||||
This project aims to provide a simplified version of the Java compiler, focusing on key language features and demonstrating the principles of compiler construction.
|
||||
|
||||
## Realised Java syntax
|
||||
|
||||
- **Data types**: `int`, `boolean`, `char`
|
||||
- **Access modifier**: `public`, `protected`, `private`
|
||||
- **Operators**: `=` `+` `-` `*` `%` `/` `>` `<` `>=` `<=` `==` `!=` `!` `&&` `||` `++` `--`
|
||||
- **Keywords**: `class`, `this`, `while`, `do`, `if`, `else`, `for`, `return`, `new`, `switch`, `case`, `break`, `default`, `:`
|
||||
- **Statements**:
|
||||
- `if` ... `if else` ... `else`;
|
||||
- `while` ... ;
|
||||
- `do` ... `while`;
|
||||
- `for`;
|
||||
- **Comments**:
|
||||
- Single line: `// comment`
|
||||
- Multi-line: `/* comment */`
|
||||
- **Further functions**:
|
||||
- All methods are overloadable
|
||||
- High maintainability and expandability through implementation of the visitor pattern
|
||||
- Logging Input and Outputs
|
||||
- Error Handling in the Semantic Check
|
||||
|
||||
## Project Structure
|
||||
|
||||
```plain
|
||||
src/
|
||||
└── main/
|
||||
├── java/
|
||||
│ ├── ast/ -> Defining the structure of the AST
|
||||
│ ├── bytecode/ -> Generate Java bytecode
|
||||
│ ├── main/ -> Running the compiler
|
||||
│ ├── parser/
|
||||
│ │ ├── astBuilder/ -> Builder creating the AST
|
||||
│ │ ├── generated/ -> Antlr generated grammar
|
||||
│ │ └── grammar/ -> Antlr grammar
|
||||
│ ├── semantic/ -> Running the semantic check
|
||||
│ └── visitor/ -> Visitor interface
|
||||
└── resources/
|
||||
test/
|
||||
└── java/
|
||||
│ ├── main/ -> Running E2E tests
|
||||
│ ├── parser/ -> Performs tests on the parser
|
||||
│ ├── semantic/ -> Performs tests on the semantic check
|
||||
└── resources/ -> Ressources for running the Tests
|
||||
```
|
||||
|
||||
## Class-Diagramm AST
|
||||
|
||||

|
||||
|
||||
## Distribution of the realisation
|
||||
|
||||
### i22030 & i22035
|
||||
Ausführliche Beschreibung der Parser Umsetzung:
|
||||
|
||||

|
||||
|
||||
Parser:
|
||||
- Grammar -> (src/main/java/parser/grammar)
|
||||
- Scanner
|
||||
- Parser
|
||||
- Abstract Syntax Tree (AST) -> (src/main/java/ast)
|
||||
- AstBuilder -> (src/main/java/parser/astBuilder)
|
||||
|
||||
Parser tests:
|
||||
- ParserTests -> (src/test/java/parser)
|
||||
- TestCases -> (src/test/resources/input/singeFeatureTests)
|
||||
|
||||
Other:
|
||||
- Documentation -> (README.md)
|
||||
- Ast Class-Diagramm -> (ast.png)
|
||||
- PowerPoint
|
||||
|
||||
### i22005
|
||||
Semantic check:
|
||||
- Set all types and check whether types have been used correctly
|
||||
- Contexts -> (src/main/java/semantic/context)
|
||||
- Exceptions Handling -> (src/main/java/semantic/exceptions)
|
||||
|
||||
Semantic Tests:
|
||||
- Typing and Type checking -> (src/test/java/semantic/EndToTypedAstTest)
|
||||
- Exception and feature test -> (src/test/resources/input/typedAstExceptionsTests)
|
||||
|
||||
### i22007
|
||||
Bytecode generation:
|
||||
- Complete bytecode generation -> (src/mein/java/bytecode)
|
||||
|
||||
### i22011
|
||||
Tests and execution:
|
||||
- Makefile
|
||||
- Running Compiler -> (src/main/main)
|
||||
- Running E2E tests -> (src/test/main)
|
||||
- Typing and Type checking -> (src/test/java/semantic/EndToTypedAstTest)
|
||||
|
||||
|
||||
## Used Tools
|
||||
|
||||
- [Maven 4.0](https://maven.apache.org/index.html)
|
||||
- Used for automating the build process and managing dependencies.
|
||||
- [ANTLR4 v.13.1](https://www.antlr.org/)
|
||||
- Used to parse the input Java code into the Abstract Syntax Tree.
|
||||
|
||||
## How to run the compiler
|
||||
### Possibilities
|
||||
### 1. Start miniCompiler using make:
|
||||
Make needs to be installed
|
||||
```bash
|
||||
cd .\src\test\ ; make clean compile-miniCompiler
|
||||
```
|
||||
|
||||
### 2. Start miniCompiler using jar:
|
||||
If you do not have the .jar, download it [here](https://gitea.hb.dhbw-stuttgart.de/i22005/NichtHaskell2.0/src/branch/main/JavaCompiler-1.0-jar-with-dependencies.jar) or compile it using mvn package or make first
|
||||
```
|
||||
java.exe -DgenJar=bool -DgenClass=bool -jar path_to_jar\jarName.jar 'path_to_input_file.java' 'path_to_output_directory'
|
||||
```
|
||||
|
||||
Example (jar needs to be in the target directory)
|
||||
```bash
|
||||
java.exe -DgenJar=true -DgenClass=true -jar .\target\JavaCompiler-1.0-jar-with-dependencies.jar 'src/main/resources/input/CompilerInput.java' 'src/main/resources/output'
|
||||
```
|
||||
|
||||
- set DgenJar true, to generate the jar, false for no jar
|
||||
|
||||
```
|
||||
DgenJar=true
|
||||
```
|
||||
|
||||
- set DgenClass true, to generate class files, false for no class files
|
||||
|
||||
```
|
||||
DgenClass=true
|
||||
```
|
||||
77
pom.xml
77
pom.xml
@@ -4,14 +4,13 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>de.dhbw-stuttgart</groupId>
|
||||
<groupId>org.example</groupId>
|
||||
<artifactId>JavaCompiler</artifactId>
|
||||
<version>1.0</version>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<java.version>22</java.version>
|
||||
<maven.compiler.source>${java.version}</maven.compiler.source>
|
||||
<maven.compiler.target>${java.version}</maven.compiler.target>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
@@ -20,25 +19,7 @@
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.11.0-M2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
<artifactId>junit-platform-suite-engine</artifactId>
|
||||
<version>1.11.0-M2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>5.11.0-M2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.1</version>
|
||||
<version>5.9.3</version> <!-- Change the version as needed -->
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@@ -46,22 +27,13 @@
|
||||
<artifactId>antlr4-runtime</artifactId>
|
||||
<version>4.13.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.ow2.asm</groupId>
|
||||
<artifactId>asm</artifactId>
|
||||
<version>9.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-databind</artifactId>
|
||||
<version>2.16.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.assertj</groupId>
|
||||
<artifactId>assertj-core</artifactId>
|
||||
<version>3.26.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
@@ -71,41 +43,8 @@
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0-M5</version> <!-- Change the version as needed -->
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>**/*Test.java</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>make-assembly</id> <!-- this is used for inheritance merges -->
|
||||
<phase>package</phase> <!-- bind to the packaging phase -->
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>main.Main</mainClass>
|
||||
</manifest>
|
||||
</archive>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>maven_central</id>
|
||||
<name>Maven Central</name>
|
||||
<url>https://repo.maven.apache.org/maven2/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
</project>
|
||||
15
src/main/java/CompilerInput.txt
Normal file
15
src/main/java/CompilerInput.txt
Normal file
@@ -0,0 +1,15 @@
|
||||
public class Example {
|
||||
|
||||
public int testVar;
|
||||
|
||||
public static int testMethod(char b){
|
||||
|
||||
int a;
|
||||
boolean b;
|
||||
char c;
|
||||
b = 3;
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
41
src/main/java/Main.java
Normal file
41
src/main/java/Main.java
Normal file
@@ -0,0 +1,41 @@
|
||||
import ast.ProgramNode;
|
||||
import bytecode.ByteCodeGenerator;
|
||||
import org.antlr.v4.runtime.CharStream;
|
||||
import org.antlr.v4.runtime.CharStreams;
|
||||
import org.antlr.v4.runtime.CommonTokenStream;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import parser.astBuilder.ASTBuilder;
|
||||
import parser.generated.SimpleJavaLexer;
|
||||
import parser.generated.SimpleJavaParser;
|
||||
import semantic.SemanticAnalyzer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) throws Exception {
|
||||
try {
|
||||
CharStream codeCharStream = CharStreams.fromPath(Paths.get("src/main/java/CompilerInput.txt"));
|
||||
parsefile(codeCharStream);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error reading the file: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void parsefile(CharStream codeCharStream){
|
||||
SimpleJavaLexer lexer = new SimpleJavaLexer(codeCharStream);
|
||||
CommonTokenStream tokens = new CommonTokenStream(lexer);
|
||||
SimpleJavaParser parser = new SimpleJavaParser(tokens);
|
||||
|
||||
ParseTree tree = parser.program(); // parse the input
|
||||
|
||||
ASTBuilder builder = new ASTBuilder();
|
||||
ProgramNode ast = (ProgramNode) builder.visit(tree); // build the AST
|
||||
|
||||
SemanticAnalyzer.generateTast(ast);
|
||||
|
||||
ByteCodeGenerator byteCodeGenerator = new ByteCodeGenerator();
|
||||
byteCodeGenerator.visit(ast);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package ast;
|
||||
|
||||
public interface ASTNode {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
4
src/main/java/ast/BlockNode.java
Normal file
4
src/main/java/ast/BlockNode.java
Normal file
@@ -0,0 +1,4 @@
|
||||
package ast;
|
||||
|
||||
public class BlockNode {
|
||||
}
|
||||
@@ -1,43 +1,42 @@
|
||||
package ast;
|
||||
|
||||
import ast.type.AccessModifierNode;
|
||||
import ast.members.MemberNode;
|
||||
import ast.members.MethodNode;
|
||||
import bytecode.visitor.ClassVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
import visitor.Visitable;
|
||||
import ast.member.ConstructorNode;
|
||||
import ast.member.MemberNode;
|
||||
import ast.type.AccessTypeNode;
|
||||
import ast.type.EnumAccessTypeNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import bytecode.visitor.ClassVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import typechecker.TypeCheckResult;
|
||||
import typechecker.Visitable;
|
||||
|
||||
public class ClassNode implements ASTNode, Visitable {
|
||||
public AccessModifierNode accessType;
|
||||
public String identifier;
|
||||
public AccessTypeNode accessType;
|
||||
public List<MemberNode> members = new ArrayList<>();
|
||||
public boolean hasConstructor = false;
|
||||
|
||||
public ClassNode() {
|
||||
|
||||
}
|
||||
|
||||
public ClassNode(String accessType, String identifier) {
|
||||
this.accessType = new AccessModifierNode(accessType);
|
||||
public ClassNode(AccessTypeNode accessType, String identifier){
|
||||
this.accessType = accessType;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public void addMember(MemberNode member) {
|
||||
if (member instanceof ConstructorNode) {
|
||||
this.hasConstructor = true;
|
||||
}
|
||||
members.add(member);
|
||||
}
|
||||
|
||||
public List<MethodNode> getMethods() {
|
||||
List<MethodNode> methods = new ArrayList<>();
|
||||
for (MemberNode member : members) {
|
||||
if (member instanceof MethodNode methodNode) {
|
||||
methods.add(methodNode);
|
||||
public void ensureConstructor(){
|
||||
if(!hasConstructor) {
|
||||
ConstructorNode constructor = new ConstructorNode(new AccessTypeNode(EnumAccessTypeNode.PUBLIC), identifier);
|
||||
members.add(0,constructor);
|
||||
}
|
||||
}
|
||||
return methods;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
@@ -48,5 +47,4 @@ public class ClassNode implements ASTNode, Visitable {
|
||||
public void accept(ClassVisitor classVisitor) {
|
||||
classVisitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
27
src/main/java/ast/IdentifierNode.java
Normal file
27
src/main/java/ast/IdentifierNode.java
Normal file
@@ -0,0 +1,27 @@
|
||||
package ast;
|
||||
|
||||
public class IdentifierNode {
|
||||
|
||||
private String name;
|
||||
|
||||
public IdentifierNode(String name){
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName(){
|
||||
return name;
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
if(obj instanceof IdentifierNode){
|
||||
IdentifierNode identifier = (IdentifierNode) obj;
|
||||
if(name.equals(identifier.getName())){
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return super.equals(obj);
|
||||
}
|
||||
|
||||
}
|
||||
23
src/main/java/ast/LiteralNode.java
Normal file
23
src/main/java/ast/LiteralNode.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package ast;
|
||||
|
||||
import ast.expression.ExpressionNode;
|
||||
|
||||
public class LiteralNode extends ExpressionNode {
|
||||
|
||||
int value;
|
||||
private String type;
|
||||
|
||||
public LiteralNode(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
package ast;
|
||||
|
||||
import bytecode.visitor.ProgramVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
import visitor.Visitable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import bytecode.visitor.ProgramVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import typechecker.TypeCheckResult;
|
||||
import typechecker.Visitable;
|
||||
|
||||
public class ProgramNode implements ASTNode, Visitable{
|
||||
public List<ClassNode> classes = new ArrayList<>();
|
||||
|
||||
|
||||
21
src/main/java/ast/VarNode.java
Normal file
21
src/main/java/ast/VarNode.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package ast;
|
||||
|
||||
public class VarNode implements ASTNode{
|
||||
|
||||
private String identifier;
|
||||
private String type;
|
||||
|
||||
public VarNode(String type, String identifier){
|
||||
this.type = type;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public String getType(){
|
||||
return type;
|
||||
}
|
||||
|
||||
public String getIdentifier(){
|
||||
return identifier;
|
||||
}
|
||||
|
||||
}
|
||||
13
src/main/java/ast/expression/BinaryExpressionNode.java
Normal file
13
src/main/java/ast/expression/BinaryExpressionNode.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package ast.expression;
|
||||
|
||||
public class BinaryExpressionNode extends ExpressionNode {
|
||||
public ExpressionNode left;
|
||||
public ExpressionNode right;
|
||||
public String operator;
|
||||
|
||||
public BinaryExpressionNode(ExpressionNode left, ExpressionNode right, String operator) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
this.operator = operator;
|
||||
}
|
||||
}
|
||||
9
src/main/java/ast/expression/ExpressionNode.java
Normal file
9
src/main/java/ast/expression/ExpressionNode.java
Normal file
@@ -0,0 +1,9 @@
|
||||
package ast.expression;
|
||||
|
||||
import ast.ASTNode;
|
||||
|
||||
public class ExpressionNode implements ASTNode {
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package ast.expression;
|
||||
|
||||
public class IdentifierExpressionNode extends ExpressionNode {
|
||||
public String name;
|
||||
|
||||
public IdentifierExpressionNode(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
11
src/main/java/ast/expression/UnaryExpressionNode.java
Normal file
11
src/main/java/ast/expression/UnaryExpressionNode.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package ast.expression;
|
||||
|
||||
public class UnaryExpressionNode extends ExpressionNode {
|
||||
public ExpressionNode expression;
|
||||
public String operator;
|
||||
|
||||
public UnaryExpressionNode(ExpressionNode expression, String operator) {
|
||||
this.expression = expression;
|
||||
this.operator = operator;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package ast.expressions;
|
||||
|
||||
import ast.ASTNode;
|
||||
import ast.type.type.ITypeNode;
|
||||
import visitor.Visitable;
|
||||
|
||||
public interface IExpressionNode extends ASTNode, Visitable {
|
||||
|
||||
ITypeNode getType();
|
||||
|
||||
void setType(ITypeNode type);
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package ast.expressions.binaryexpressions;
|
||||
|
||||
import ast.expressions.IExpressionNode;
|
||||
import ast.type.type.*;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
import visitor.Visitable;
|
||||
|
||||
public class BinaryNode implements IExpressionNode, Visitable {
|
||||
|
||||
public ITypeNode typeNode;
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITypeNode getType() {
|
||||
return typeNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(ITypeNode type) {
|
||||
this.typeNode = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package ast.expressions.binaryexpressions;
|
||||
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
|
||||
public class CalculationNode extends BinaryNode {
|
||||
public CalculationNode calculationExpression;
|
||||
public EnumLineOperator operator;
|
||||
public DotNode dotExpression;
|
||||
|
||||
public CalculationNode(CalculationNode calculationExpression, String operator, DotNode dotExpression) {
|
||||
this.calculationExpression = calculationExpression;
|
||||
setOperator(operator);
|
||||
this.dotExpression = dotExpression;
|
||||
}
|
||||
|
||||
public CalculationNode(DotNode dotExpression) {
|
||||
this.dotExpression = dotExpression;
|
||||
}
|
||||
|
||||
public void setOperator(String operator) {
|
||||
if (operator != null) {
|
||||
if (operator.equals("+")) {
|
||||
this.operator = EnumLineOperator.PLUS;
|
||||
} else if (operator.equals("-")) {
|
||||
this.operator = EnumLineOperator.MINUS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package ast.expressions.binaryexpressions;
|
||||
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
|
||||
public class DotNode extends BinaryNode {
|
||||
public DotNode dotExpression;
|
||||
public EnumDotOperator operator;
|
||||
public DotSubtractionNode dotSubtractionExpression;
|
||||
|
||||
public DotNode(DotNode dotExpression, String operator, DotSubtractionNode dotSubtractionExpression) {
|
||||
this.dotExpression = dotExpression;
|
||||
setOperator(operator);
|
||||
this.dotSubtractionExpression = dotSubtractionExpression;
|
||||
}
|
||||
|
||||
public DotNode(DotSubtractionNode dotSubtractionExpression) {
|
||||
this.dotSubtractionExpression = dotSubtractionExpression;
|
||||
}
|
||||
|
||||
public void setOperator(String operator) {
|
||||
switch (operator) {
|
||||
case "*" -> this.operator = EnumDotOperator.MULT;
|
||||
case "/" -> this.operator = EnumDotOperator.DIV;
|
||||
case "%" -> this.operator = EnumDotOperator.MOD;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package ast.expressions.binaryexpressions;
|
||||
|
||||
import ast.expressions.unaryexpressions.MemberAccessNode;
|
||||
import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode;
|
||||
import ast.type.ValueNode;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
|
||||
public class DotSubtractionNode extends BinaryNode {
|
||||
public ValueNode value;
|
||||
public String identifier;
|
||||
public MemberAccessNode memberAccess;
|
||||
public MethodCallNode methodCall;
|
||||
public CalculationNode calculationExpression;
|
||||
|
||||
public DotSubtractionNode(ValueNode value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public DotSubtractionNode(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public DotSubtractionNode(MemberAccessNode memberAccess) {
|
||||
this.memberAccess = memberAccess;
|
||||
}
|
||||
|
||||
public DotSubtractionNode(MethodCallNode methodCall, CalculationNode calculationExpression) {
|
||||
this.methodCall = methodCall;
|
||||
this.calculationExpression = calculationExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package ast.expressions.binaryexpressions;
|
||||
|
||||
public enum EnumDotOperator {
|
||||
MULT, DIV, MOD
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package ast.expressions.binaryexpressions;
|
||||
|
||||
public enum EnumLineOperator {
|
||||
PLUS, MINUS
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package ast.expressions.binaryexpressions;
|
||||
|
||||
public enum EnumNonCalculationOperator {
|
||||
AND, OR, GREATER, LESS, GREATER_EQUAL, LESS_EQUAL, EQUAL, NOT_EQUAL
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package ast.expressions.binaryexpressions;
|
||||
|
||||
import ast.expressions.IExpressionNode;
|
||||
import ast.expressions.unaryexpressions.UnaryNode;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
|
||||
public class NonCalculationNode extends BinaryNode {
|
||||
public UnaryNode unaryExpression;
|
||||
public EnumNonCalculationOperator operator;
|
||||
public IExpressionNode expression;
|
||||
|
||||
public NonCalculationNode(UnaryNode unaryExpression, String operator, IExpressionNode expression) {
|
||||
this.unaryExpression = unaryExpression;
|
||||
setOperator(operator);
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public void setOperator(String operator) {
|
||||
switch (operator) {
|
||||
case "&&" -> this.operator = EnumNonCalculationOperator.AND;
|
||||
case "||" -> this.operator = EnumNonCalculationOperator.OR;
|
||||
case ">" -> this.operator = EnumNonCalculationOperator.GREATER;
|
||||
case "<" -> this.operator = EnumNonCalculationOperator.LESS;
|
||||
case ">=" -> this.operator = EnumNonCalculationOperator.GREATER_EQUAL;
|
||||
case "<=" -> this.operator = EnumNonCalculationOperator.LESS_EQUAL;
|
||||
case "==" -> this.operator = EnumNonCalculationOperator.EQUAL;
|
||||
case "!=" -> this.operator = EnumNonCalculationOperator.NOT_EQUAL;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package ast.expressions.unaryexpressions;
|
||||
|
||||
import ast.ASTNode;
|
||||
import ast.type.type.ITypeNode;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
import visitor.Visitable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MemberAccessNode implements ASTNode, Visitable {
|
||||
public Boolean thisExpr;
|
||||
public List<String> identifiers = new ArrayList<>();
|
||||
private ITypeNode typeNode;
|
||||
|
||||
public MemberAccessNode(Boolean thisExpr) {
|
||||
this.thisExpr = thisExpr;
|
||||
}
|
||||
|
||||
public void addIdentifier(String identifier) {
|
||||
identifiers.add(identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
public ITypeNode getTypeNode() {
|
||||
return typeNode;
|
||||
}
|
||||
|
||||
public void setTypeNode(ITypeNode typeNode) {
|
||||
this.typeNode = typeNode;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package ast.expressions.unaryexpressions;
|
||||
|
||||
import ast.expressions.IExpressionNode;
|
||||
import ast.type.type.ITypeNode;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
|
||||
public class NotNode implements IExpressionNode {
|
||||
public IExpressionNode expression;
|
||||
|
||||
public NotNode(IExpressionNode expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITypeNode getType() {
|
||||
return expression.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(ITypeNode type) {
|
||||
this.expression.setType(type);
|
||||
}
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package ast.expressions.unaryexpressions;
|
||||
|
||||
import ast.expressions.IExpressionNode;
|
||||
import ast.statements.IStatementNode;
|
||||
import ast.type.type.*;
|
||||
import ast.type.ValueNode;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class UnaryNode implements IExpressionNode {
|
||||
public String thisExp;
|
||||
public String identifier;
|
||||
public MemberAccessNode memberAccess;
|
||||
public ValueNode value;
|
||||
public NotNode notExpression;
|
||||
public IStatementNode statement;
|
||||
public IExpressionNode expression;
|
||||
public ITypeNode type;
|
||||
|
||||
public UnaryNode(String value) {
|
||||
if (Objects.equals(value, "this")) {
|
||||
this.thisExp = "this";
|
||||
} else {
|
||||
this.identifier = value;
|
||||
}
|
||||
}
|
||||
|
||||
public UnaryNode(MemberAccessNode memberAccess) {
|
||||
this.memberAccess = memberAccess;
|
||||
}
|
||||
|
||||
public UnaryNode(ValueNode value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public UnaryNode(NotNode notExpression) {
|
||||
this.notExpression = notExpression;
|
||||
}
|
||||
|
||||
public UnaryNode(IStatementNode statement) {
|
||||
this.statement = statement;
|
||||
}
|
||||
|
||||
public UnaryNode(IExpressionNode expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ITypeNode getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(ITypeNode type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
16
src/main/java/ast/member/ConstructorNode.java
Normal file
16
src/main/java/ast/member/ConstructorNode.java
Normal file
@@ -0,0 +1,16 @@
|
||||
package ast.member;
|
||||
|
||||
import ast.type.AccessTypeNode;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import typechecker.Visitable;
|
||||
|
||||
public class ConstructorNode extends MethodNode implements Visitable {
|
||||
public ConstructorNode(AccessTypeNode visibility, String name) {
|
||||
super(visibility, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
package ast.members;
|
||||
package ast.member;
|
||||
|
||||
import ast.type.AccessModifierNode;
|
||||
import ast.type.type.ITypeNode;
|
||||
import ast.type.AccessTypeNode;
|
||||
import ast.type.TypeNode;
|
||||
import bytecode.visitor.ClassVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
import visitor.Visitable;
|
||||
import typechecker.TypeCheckResult;
|
||||
import typechecker.Visitable;
|
||||
|
||||
public class FieldNode implements MemberNode, Visitable {
|
||||
public AccessModifierNode accessTypeNode;
|
||||
public ITypeNode type;
|
||||
public AccessTypeNode accessTypeNode;
|
||||
public TypeNode type;
|
||||
public String identifier;
|
||||
|
||||
public FieldNode(AccessModifierNode accessTypeNode, ITypeNode type, String name) {
|
||||
public FieldNode(AccessTypeNode accessTypeNode, TypeNode type, String name){
|
||||
this.accessTypeNode = accessTypeNode;
|
||||
this.type = type;
|
||||
this.identifier = name;
|
||||
@@ -27,5 +27,4 @@ public class FieldNode implements MemberNode, Visitable {
|
||||
public void accept(ClassVisitor classVisitor) {
|
||||
classVisitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
6
src/main/java/ast/member/MemberNode.java
Normal file
6
src/main/java/ast/member/MemberNode.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package ast.member;
|
||||
|
||||
import ast.ASTNode;
|
||||
|
||||
public interface MemberNode extends ASTNode {
|
||||
}
|
||||
48
src/main/java/ast/member/MethodNode.java
Normal file
48
src/main/java/ast/member/MethodNode.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package ast.member;
|
||||
|
||||
import ast.parameter.ParameterListNode;
|
||||
import ast.statement.StatementNode;
|
||||
import ast.type.AccessTypeNode;
|
||||
import ast.type.TypeNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import typechecker.TypeCheckResult;
|
||||
import typechecker.Visitable;
|
||||
|
||||
public class MethodNode implements MemberNode, Visitable {
|
||||
public AccessTypeNode visibility;
|
||||
public TypeNode type;
|
||||
public String identifier;
|
||||
|
||||
public ParameterListNode parameters;
|
||||
|
||||
public List<StatementNode> statements = new ArrayList<>();
|
||||
|
||||
public MethodNode(AccessTypeNode visibility, TypeNode type, String identifier, ParameterListNode parameters,
|
||||
List<StatementNode> statements){
|
||||
this.visibility = visibility;
|
||||
this.type = type;
|
||||
this.identifier = identifier;
|
||||
this.parameters = parameters;
|
||||
this.statements = statements;
|
||||
}
|
||||
|
||||
public MethodNode(AccessTypeNode visibility, String identifier){
|
||||
this.visibility = visibility;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package ast.members;
|
||||
|
||||
import ast.parameters.ParameterNode;
|
||||
import ast.statements.BlockNode;
|
||||
import ast.type.AccessModifierNode;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import visitor.Visitable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class ConstructorNode extends MethodNode implements Visitable {
|
||||
public ConstructorNode(String accessType, String identifier, BlockNode block) {
|
||||
this.accesModifier = new AccessModifierNode(accessType);
|
||||
this.identifier = identifier;
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
public void addParameter(ParameterNode parameterNode) {
|
||||
parameters.add(parameterNode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
|
||||
public boolean isSame(MethodNode methodNode) {
|
||||
if (!(Objects.equals(this.identifier, methodNode.getIdentifier())) || getParameters().size() != methodNode.getParameters().size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < this.getParameters().size(); i++) {
|
||||
if (!this.getParameters().get(i).type.equals(methodNode.getParameters().get(i).type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package ast.members;
|
||||
|
||||
import ast.statements.BlockNode;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import visitor.Visitable;
|
||||
|
||||
public class MainMethodNode extends MethodNode implements Visitable {
|
||||
|
||||
public MainMethodNode(BlockNode block) {
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package ast.members;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonSubTypes;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
||||
import ast.ASTNode;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY)
|
||||
@JsonSubTypes({
|
||||
@JsonSubTypes.Type(value = MethodNode.class, name = "Method"),
|
||||
|
||||
@JsonSubTypes.Type(value = FieldNode.class, name = "Field")}
|
||||
)
|
||||
|
||||
public interface MemberNode extends ASTNode {
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
package ast.members;
|
||||
|
||||
import ast.parameters.ParameterNode;
|
||||
import ast.statements.BlockNode;
|
||||
import ast.type.AccessModifierNode;
|
||||
import ast.type.type.*;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
import visitor.Visitable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class MethodNode implements MemberNode, Visitable {
|
||||
public AccessModifierNode accesModifier;
|
||||
public ITypeNode type;
|
||||
public Boolean voidType;
|
||||
public String identifier;
|
||||
public List<ParameterNode> parameters = new ArrayList<>();
|
||||
public BlockNode block;
|
||||
|
||||
public MethodNode() {
|
||||
}
|
||||
|
||||
public MethodNode(String accessModifier, ITypeNode type, Boolean voidType, String identifier, BlockNode block) {
|
||||
this.accesModifier = new AccessModifierNode(accessModifier);
|
||||
this.type = type;
|
||||
this.voidType = voidType;
|
||||
this.identifier = identifier;
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
public void addParameter(ParameterNode parameter) {
|
||||
this.parameters.add(parameter);
|
||||
}
|
||||
|
||||
public List<ParameterNode> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
public boolean isSame(MethodNode methodNode) {
|
||||
if (!(Objects.equals(this.identifier, methodNode.getIdentifier())) || type.equals(methodNode.type)
|
||||
|| getParameters().size() != methodNode.getParameters().size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < this.getParameters().size(); i++) {
|
||||
if (!this.getParameters().get(i).type.equals(methodNode.getParameters().get(i).type)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
public ITypeNode getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(ITypeNode type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public void setIdentifier(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
}
|
||||
14
src/main/java/ast/parameter/ParameterListNode.java
Normal file
14
src/main/java/ast/parameter/ParameterListNode.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package ast.parameter;
|
||||
|
||||
import ast.ASTNode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ParameterListNode implements ASTNode {
|
||||
List<ParameterNode> parameters = new ArrayList<>();
|
||||
|
||||
public ParameterListNode(List<ParameterNode> parameters){
|
||||
this.parameters = parameters;
|
||||
}
|
||||
}
|
||||
14
src/main/java/ast/parameter/ParameterNode.java
Normal file
14
src/main/java/ast/parameter/ParameterNode.java
Normal file
@@ -0,0 +1,14 @@
|
||||
package ast.parameter;
|
||||
|
||||
import ast.ASTNode;
|
||||
import ast.type.TypeNode;
|
||||
|
||||
public class ParameterNode implements ASTNode {
|
||||
public TypeNode type;
|
||||
public String identifier;
|
||||
|
||||
public ParameterNode(TypeNode type, String identifier) {
|
||||
this.type = type;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package ast.parameters;
|
||||
|
||||
import ast.ASTNode;
|
||||
import ast.type.type.*;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
import visitor.Visitable;
|
||||
|
||||
public class ParameterNode implements ASTNode, Visitable {
|
||||
public ITypeNode type;
|
||||
public String identifier;
|
||||
|
||||
public ParameterNode(ITypeNode type, String identifier) {
|
||||
this.type = type;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
}
|
||||
22
src/main/java/ast/statement/AssignmentStatementNode.java
Normal file
22
src/main/java/ast/statement/AssignmentStatementNode.java
Normal file
@@ -0,0 +1,22 @@
|
||||
package ast.statement;
|
||||
|
||||
import ast.VarNode;
|
||||
import ast.expression.ExpressionNode;
|
||||
import semantic.SemanticVisitor;
|
||||
import typechecker.TypeCheckResult;
|
||||
import typechecker.Visitable;
|
||||
|
||||
public class AssignmentStatementNode extends StatementNode implements Visitable {
|
||||
public VarNode varNode;
|
||||
public ExpressionNode expression;
|
||||
|
||||
public AssignmentStatementNode(VarNode varNode, ExpressionNode expression) {
|
||||
this.varNode = varNode;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
}
|
||||
15
src/main/java/ast/statement/IfStatementNode.java
Normal file
15
src/main/java/ast/statement/IfStatementNode.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package ast.statement;
|
||||
|
||||
import ast.expression.ExpressionNode;
|
||||
|
||||
public class IfStatementNode extends StatementNode {
|
||||
public ExpressionNode condition;
|
||||
public StatementNode thenStatement;
|
||||
public StatementNode elseStatement;
|
||||
|
||||
public IfStatementNode(ExpressionNode condition, StatementNode thenStatement, StatementNode elseStatement) {
|
||||
this.condition = condition;
|
||||
this.thenStatement = thenStatement;
|
||||
this.elseStatement = elseStatement;
|
||||
}
|
||||
}
|
||||
11
src/main/java/ast/statement/ReturnStatementNode.java
Normal file
11
src/main/java/ast/statement/ReturnStatementNode.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package ast.statement;
|
||||
|
||||
import ast.expression.ExpressionNode;
|
||||
|
||||
public class ReturnStatementNode extends StatementNode {
|
||||
public ExpressionNode expression;
|
||||
|
||||
public ReturnStatementNode(ExpressionNode expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
}
|
||||
7
src/main/java/ast/statement/StatementNode.java
Normal file
7
src/main/java/ast/statement/StatementNode.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package ast.statement;
|
||||
|
||||
import ast.ASTNode;
|
||||
|
||||
public abstract class StatementNode implements ASTNode {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
package ast.statement;
|
||||
|
||||
import ast.type.TypeNode;
|
||||
import ast.expression.ExpressionNode;
|
||||
|
||||
public class VariableDeclarationStatementNode extends StatementNode {
|
||||
public TypeNode type;
|
||||
public String identifier;
|
||||
public ExpressionNode expression;
|
||||
public VariableDeclarationStatementNode(TypeNode type, String identifier, ExpressionNode expression) {
|
||||
this.type = type;
|
||||
this.identifier = identifier;
|
||||
this.expression = expression;
|
||||
}
|
||||
}
|
||||
13
src/main/java/ast/statement/WhileStatementNode.java
Normal file
13
src/main/java/ast/statement/WhileStatementNode.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package ast.statement;
|
||||
|
||||
import ast.expression.ExpressionNode;
|
||||
|
||||
public class WhileStatementNode extends StatementNode {
|
||||
public ExpressionNode condition;
|
||||
public StatementNode body;
|
||||
|
||||
public WhileStatementNode(ExpressionNode condition, StatementNode body) {
|
||||
this.condition = condition;
|
||||
this.body = body;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package ast.statementexpressions;
|
||||
|
||||
import ast.expressions.IExpressionNode;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
|
||||
public class AssignNode implements IStatementExpressionNode {
|
||||
public AssignableNode assignable;
|
||||
public IExpressionNode expression;
|
||||
|
||||
public AssignNode(AssignableNode assignable, IExpressionNode expression) {
|
||||
this.assignable = assignable;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package ast.statementexpressions;
|
||||
|
||||
import ast.expressions.unaryexpressions.MemberAccessNode;
|
||||
import ast.type.type.ITypeNode;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
|
||||
public class AssignableNode implements IStatementExpressionNode {
|
||||
public String identifier;
|
||||
public ITypeNode typeNode;
|
||||
|
||||
public MemberAccessNode memberAccess;
|
||||
|
||||
public AssignableNode(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public AssignableNode(MemberAccessNode memberAccess) {
|
||||
this.memberAccess = memberAccess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
public void setTypeNode(ITypeNode typeNode) {
|
||||
this.typeNode = typeNode;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package ast.statementexpressions;
|
||||
|
||||
import ast.statements.IStatementNode;
|
||||
|
||||
public interface IStatementExpressionNode extends IStatementNode {
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package ast.statementexpressions;
|
||||
|
||||
import ast.expressions.IExpressionNode;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class NewDeclarationNode implements IStatementExpressionNode {
|
||||
public String identifier;
|
||||
public List<IExpressionNode> expressions = new ArrayList<>();
|
||||
|
||||
public NewDeclarationNode(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public void addExpression(IExpressionNode expression) {
|
||||
expressions.add(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package ast.statementexpressions.crementexpressions;
|
||||
|
||||
public enum CrementType {
|
||||
PREFIX, SUFFIX
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package ast.statementexpressions.crementexpressions;
|
||||
|
||||
import ast.statementexpressions.AssignableNode;
|
||||
import ast.statementexpressions.IStatementExpressionNode;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
import visitor.Visitable;
|
||||
|
||||
public class DecrementNode implements IStatementExpressionNode, Visitable {
|
||||
public CrementType crementType;
|
||||
public AssignableNode assignableExpression;
|
||||
|
||||
public DecrementNode(CrementType crementType, AssignableNode assignableExpression) {
|
||||
this.crementType = crementType;
|
||||
this.assignableExpression = assignableExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package ast.statementexpressions.crementexpressions;
|
||||
|
||||
import ast.statementexpressions.AssignableNode;
|
||||
import ast.statementexpressions.IStatementExpressionNode;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import visitor.Visitable;
|
||||
import semantic.TypeCheckResult;
|
||||
|
||||
public class IncrementNode implements IStatementExpressionNode, Visitable {
|
||||
public CrementType crementType;
|
||||
public AssignableNode assignableExpression;
|
||||
|
||||
public IncrementNode(CrementType crementType, AssignableNode assignableExpression) {
|
||||
this.crementType = crementType;
|
||||
this.assignableExpression = assignableExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package ast.statementexpressions.methodcallstatementnexpressions;
|
||||
|
||||
import ast.ASTNode;
|
||||
import ast.expressions.IExpressionNode;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
import visitor.Visitable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ChainedMethodNode implements ASTNode, Visitable {
|
||||
public String identifier;
|
||||
public List<IExpressionNode> expressions = new ArrayList<>();
|
||||
|
||||
public ChainedMethodNode(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public void addExpression(IExpressionNode expression) {
|
||||
expressions.add(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package ast.statementexpressions.methodcallstatementnexpressions;
|
||||
|
||||
import ast.expressions.IExpressionNode;
|
||||
import ast.statements.IStatementNode;
|
||||
import ast.type.type.ITypeNode;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class MethodCallNode implements IStatementNode {
|
||||
public TargetNode target;
|
||||
public ITypeNode type;
|
||||
public List<ChainedMethodNode> chainedMethods = new ArrayList<>();
|
||||
public String identifier;
|
||||
public List<IExpressionNode> parameters = new ArrayList<>();
|
||||
|
||||
public MethodCallNode(TargetNode target, String identifier) {
|
||||
this.target = target;
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public void addChainedMethod(ChainedMethodNode chainedMethode) {
|
||||
chainedMethods.add(chainedMethode);
|
||||
}
|
||||
|
||||
public void addExpression(IExpressionNode parameter) {
|
||||
parameters.add(parameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package ast.statementexpressions.methodcallstatementnexpressions;
|
||||
|
||||
import ast.ASTNode;
|
||||
import ast.expressions.unaryexpressions.MemberAccessNode;
|
||||
import ast.statementexpressions.NewDeclarationNode;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
import visitor.Visitable;
|
||||
|
||||
public class TargetNode implements ASTNode, Visitable {
|
||||
public Boolean thisTar;
|
||||
public MemberAccessNode memberAccess;
|
||||
public NewDeclarationNode newDeclaration;
|
||||
public String identifier;
|
||||
|
||||
public TargetNode(Boolean thisTar) {
|
||||
this.thisTar = thisTar;
|
||||
}
|
||||
|
||||
public TargetNode(MemberAccessNode memberAccess) {
|
||||
this.memberAccess = memberAccess;
|
||||
}
|
||||
|
||||
public TargetNode(NewDeclarationNode newDeclaration) {
|
||||
this.newDeclaration = newDeclaration;
|
||||
}
|
||||
|
||||
public TargetNode(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package ast.statements;
|
||||
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
import visitor.Visitable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class BlockNode implements IStatementNode, Visitable {
|
||||
public List<IStatementNode> statements = new ArrayList<>();
|
||||
|
||||
public BlockNode() {
|
||||
}
|
||||
|
||||
public void addStatement(IStatementNode statement) {
|
||||
statements.add(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package ast.statements;
|
||||
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
|
||||
public class ElseNode implements IStatementNode {
|
||||
public BlockNode block;
|
||||
|
||||
public ElseNode(BlockNode block) {
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package ast.statements;
|
||||
|
||||
import ast.ASTNode;
|
||||
import visitor.Visitable;
|
||||
|
||||
public interface IStatementNode extends ASTNode, Visitable {
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package ast.statements;
|
||||
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class IfElseNode implements IStatementNode {
|
||||
public IfNode ifStatement;
|
||||
public List<IfNode> elseIfStatements = new ArrayList<>();
|
||||
public ElseNode elseStatement;
|
||||
|
||||
public IfElseNode(IfNode ifStatement, ElseNode elseNode) {
|
||||
this.ifStatement = ifStatement;
|
||||
this.elseStatement = elseNode;
|
||||
}
|
||||
|
||||
public void addElseIfStatement(IfNode elseIfStament) {
|
||||
elseIfStatements.add(elseIfStament);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package ast.statements;
|
||||
|
||||
import ast.expressions.IExpressionNode;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
|
||||
public class IfNode implements IStatementNode {
|
||||
public IExpressionNode expression;
|
||||
public BlockNode block;
|
||||
|
||||
public IfNode(IExpressionNode expression, BlockNode block) {
|
||||
this.expression = expression;
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package ast.statements;
|
||||
|
||||
import ast.expressions.IExpressionNode;
|
||||
import ast.type.type.*;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
|
||||
public class LocalVariableDeclarationNode implements IStatementNode {
|
||||
public ITypeNode type;
|
||||
public String identifier;
|
||||
public String assign;
|
||||
public IExpressionNode expression;
|
||||
|
||||
public LocalVariableDeclarationNode(ITypeNode type, String identifier, String assign, IExpressionNode expression) {
|
||||
this.type = type;
|
||||
this.identifier = identifier;
|
||||
this.assign = assign;
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package ast.statements;
|
||||
|
||||
import ast.expressions.IExpressionNode;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
|
||||
public class ReturnNode implements IStatementNode {
|
||||
public IExpressionNode expression;
|
||||
public Boolean voidReturn = false;
|
||||
|
||||
public ReturnNode(IExpressionNode expression) {
|
||||
if (expression != null) {
|
||||
this.expression = expression;
|
||||
} else {
|
||||
voidReturn = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package ast.statements;
|
||||
|
||||
import ast.expressions.IExpressionNode;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
|
||||
public class WhileNode implements IStatementNode {
|
||||
public IExpressionNode expression;
|
||||
public BlockNode block;
|
||||
|
||||
public WhileNode(IExpressionNode expression, BlockNode block) {
|
||||
this.expression = expression;
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
public void test() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package ast.type;
|
||||
|
||||
public class AccessModifierNode {
|
||||
public EnumAccessModifierNode accessType;
|
||||
|
||||
public AccessModifierNode(String accessModifier) {
|
||||
setModifier(accessModifier);
|
||||
}
|
||||
|
||||
private void setModifier(String accessType) {
|
||||
switch (accessType) {
|
||||
case "public":
|
||||
this.accessType = EnumAccessModifierNode.PUBLIC;
|
||||
break;
|
||||
case "public static":
|
||||
this.accessType = EnumAccessModifierNode.PUBLIC_STATIC;
|
||||
break;
|
||||
case "private":
|
||||
this.accessType = EnumAccessModifierNode.PRIVATE;
|
||||
break;
|
||||
case "private static":
|
||||
this.accessType = EnumAccessModifierNode.PRIVATE_STATIC;
|
||||
break;
|
||||
default:
|
||||
this.accessType = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
src/main/java/ast/type/AccessTypeNode.java
Normal file
11
src/main/java/ast/type/AccessTypeNode.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package ast.type;
|
||||
|
||||
import ast.ASTNode;
|
||||
|
||||
public class AccessTypeNode implements ASTNode {
|
||||
public EnumAccessTypeNode enumAccessTypeNode;
|
||||
|
||||
public AccessTypeNode(EnumAccessTypeNode enumAccessTypeNode) {
|
||||
this.enumAccessTypeNode = enumAccessTypeNode;
|
||||
}
|
||||
}
|
||||
11
src/main/java/ast/type/BaseTypeNode.java
Normal file
11
src/main/java/ast/type/BaseTypeNode.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package ast.type;
|
||||
|
||||
public class BaseTypeNode implements TypeNode{
|
||||
|
||||
public EnumTypeNode enumType;
|
||||
|
||||
public BaseTypeNode(EnumTypeNode enumType) {
|
||||
this.enumType = enumType;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package ast.type;
|
||||
|
||||
public enum EnumAccessModifierNode {
|
||||
PUBLIC, PRIVATE, PUBLIC_STATIC, PRIVATE_STATIC
|
||||
}
|
||||
|
||||
5
src/main/java/ast/type/EnumAccessTypeNode.java
Normal file
5
src/main/java/ast/type/EnumAccessTypeNode.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package ast.type;
|
||||
|
||||
public enum EnumAccessTypeNode {
|
||||
PUBLIC, PRIVATE
|
||||
}
|
||||
5
src/main/java/ast/type/EnumTypeNode.java
Normal file
5
src/main/java/ast/type/EnumTypeNode.java
Normal file
@@ -0,0 +1,5 @@
|
||||
package ast.type;
|
||||
|
||||
public enum EnumTypeNode {
|
||||
INT, BOOLEAN, CHAR
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
package ast.type;
|
||||
|
||||
public enum EnumValueNode {
|
||||
INT_VALUE, BOOLEAN_VALUE, CHAR_VALUE, NULL_VALUE
|
||||
}
|
||||
4
src/main/java/ast/type/ReferenceTypeNode.java
Normal file
4
src/main/java/ast/type/ReferenceTypeNode.java
Normal file
@@ -0,0 +1,4 @@
|
||||
package ast.type;
|
||||
|
||||
public class ReferenceTypeNode implements TypeNode{
|
||||
}
|
||||
6
src/main/java/ast/type/TypeNode.java
Normal file
6
src/main/java/ast/type/TypeNode.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package ast.type;
|
||||
|
||||
import ast.ASTNode;
|
||||
|
||||
public interface TypeNode extends ASTNode {
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package ast.type;
|
||||
|
||||
import ast.ASTNode;
|
||||
import bytecode.visitor.MethodVisitor;
|
||||
import semantic.SemanticVisitor;
|
||||
import semantic.TypeCheckResult;
|
||||
import visitor.Visitable;
|
||||
|
||||
public class ValueNode implements ASTNode, Visitable {
|
||||
public EnumValueNode valueType;
|
||||
public String value;
|
||||
|
||||
public ValueNode(EnumValueNode valueType, String value) {
|
||||
this.valueType = valueType;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(MethodVisitor methodVisitor) {
|
||||
methodVisitor.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeCheckResult accept(SemanticVisitor visitor) {
|
||||
return visitor.analyze(this);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package ast.type.type;
|
||||
|
||||
public class BaseType implements ITypeNode {
|
||||
|
||||
public final TypeEnum typeEnum;
|
||||
|
||||
public BaseType(TypeEnum typeEnum) {
|
||||
this.typeEnum = typeEnum;
|
||||
}
|
||||
|
||||
public TypeEnum getTypeEnum() {
|
||||
return typeEnum;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
BaseType other = (BaseType) obj;
|
||||
return typeEnum == other.typeEnum;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
package ast.type.type;
|
||||
|
||||
public interface ITypeNode {
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package ast.type.type;
|
||||
|
||||
public class ReferenceType implements ITypeNode {
|
||||
|
||||
public final String identifier;
|
||||
|
||||
public ReferenceType(String identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
public String getIdentifier() {
|
||||
return identifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
ReferenceType other = (ReferenceType) obj;
|
||||
if (identifier == null) {
|
||||
return other.identifier == null;
|
||||
} else return identifier.equals(other.identifier);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package ast.type.type;
|
||||
|
||||
public enum TypeEnum {
|
||||
VOID,
|
||||
INT,
|
||||
CHAR,
|
||||
BOOL,
|
||||
NULL
|
||||
}
|
||||
@@ -2,89 +2,15 @@ package bytecode;
|
||||
|
||||
import ast.ProgramNode;
|
||||
import ast.ClassNode;
|
||||
import ast.members.MainMethodNode;
|
||||
import ast.members.MemberNode;
|
||||
import bytecode.visitor.ProgramVisitor;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.jar.JarOutputStream;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
public class ByteCodeGenerator implements ProgramVisitor {
|
||||
|
||||
private JarOutputStream jarOutputStream;
|
||||
private ByteArrayOutputStream byteArrayOutputStream;
|
||||
private final String outputDirectory;
|
||||
private final boolean generateJar;
|
||||
private final boolean generateClassFiles;
|
||||
|
||||
public ByteCodeGenerator(String outputDirectory, boolean generateJar, boolean generateClassFiles) {
|
||||
this.outputDirectory = outputDirectory;
|
||||
this.generateJar = generateJar;
|
||||
this.generateClassFiles = generateClassFiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ProgramNode programNode) {
|
||||
if(generateJar) {
|
||||
byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
try {
|
||||
Manifest manifest = new Manifest();
|
||||
manifest.getMainAttributes().putValue("Manifest-Version", "1.0");
|
||||
boolean foundMainClass = false;
|
||||
for (ClassNode classNode : programNode.classes) {
|
||||
if (foundMainClass) {
|
||||
break;
|
||||
}
|
||||
for (MemberNode memberNode : classNode.members) {
|
||||
if (memberNode instanceof MainMethodNode) {
|
||||
manifest.getMainAttributes().putValue("Main-Class", classNode.identifier);
|
||||
foundMainClass = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
jarOutputStream = new JarOutputStream(byteArrayOutputStream, manifest);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
for (ClassNode classDeclarationNode : programNode.classes) {
|
||||
ClassCodeGen classCodeGen = new ClassCodeGen(jarOutputStream, outputDirectory, generateJar, generateClassFiles);
|
||||
classDeclarationNode.accept(classCodeGen);
|
||||
}
|
||||
|
||||
try {
|
||||
jarOutputStream.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
saveJarFile(byteArrayOutputStream.toByteArray(), "output.jar");
|
||||
} else {
|
||||
for (ClassNode classDeclarationNode : programNode.classes) {
|
||||
ClassCodeGen classCodeGen = new ClassCodeGen(jarOutputStream, outputDirectory, generateJar, generateClassFiles);
|
||||
ClassCodeGen classCodeGen = new ClassCodeGen();
|
||||
classDeclarationNode.accept(classCodeGen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveJarFile(byte[] jarBytes, String jarFileName) {
|
||||
File directory = new File(outputDirectory);
|
||||
if (!directory.exists()) {
|
||||
directory.mkdirs();
|
||||
}
|
||||
|
||||
File jarFile = new File(directory, jarFileName);
|
||||
try (FileOutputStream fos = new FileOutputStream(jarFile)) {
|
||||
fos.write(jarBytes);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,43 +1,25 @@
|
||||
package bytecode;
|
||||
|
||||
import ast.ClassNode;
|
||||
import ast.members.FieldNode;
|
||||
import ast.members.MemberNode;
|
||||
import ast.members.MethodNode;
|
||||
import ast.type.type.BaseType;
|
||||
import ast.member.FieldNode;
|
||||
import ast.member.MemberNode;
|
||||
import ast.member.MethodNode;
|
||||
import bytecode.visitor.ClassVisitor;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarOutputStream;
|
||||
|
||||
|
||||
public class ClassCodeGen implements ClassVisitor {
|
||||
private final Mapper mapper;
|
||||
private ClassWriter classWriter;
|
||||
private final JarOutputStream jarOutputStream;
|
||||
private final String outputDirectory;
|
||||
private final boolean generateJar;
|
||||
private final boolean generateClassFiles;
|
||||
|
||||
public ClassCodeGen(JarOutputStream jarOutputStream, String outputDirectory, boolean generateJar, boolean generateClassFiles) {
|
||||
this.mapper = new Mapper();
|
||||
this.jarOutputStream = jarOutputStream;
|
||||
this.outputDirectory = outputDirectory;
|
||||
this.generateJar = generateJar;
|
||||
this.generateClassFiles = generateClassFiles;
|
||||
}
|
||||
Mapper mapper = new Mapper();
|
||||
ClassWriter classWriter;
|
||||
|
||||
@Override
|
||||
public void visit(ClassNode classNode) {
|
||||
classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
|
||||
classWriter.visit(Opcodes.V1_5, mapper.mapAccessTypeToOpcode(classNode.accessType), classNode.identifier, null,
|
||||
classWriter.visit(Opcodes.V1_8, mapper.mapAccesTypeToOpcode(classNode.accessType), classNode.identifier, null,
|
||||
"java/lang/Object", null);
|
||||
|
||||
for (MemberNode memberNode : classNode.members) {
|
||||
@@ -49,31 +31,26 @@ public class ClassCodeGen implements ClassVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
if (generateJar) {
|
||||
writeToJar(classWriter.toByteArray(), classNode.identifier);
|
||||
}
|
||||
if (generateClassFiles) {
|
||||
printIntoClassFile(classWriter.toByteArray(), classNode.identifier, outputDirectory);
|
||||
}
|
||||
classWriter.visitEnd();
|
||||
printIntoClassFile(classWriter.toByteArray(), classNode.identifier);
|
||||
|
||||
classWriter.visitEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(FieldNode fieldNode) {
|
||||
if (fieldNode.type instanceof BaseType) {
|
||||
classWriter.visitField(mapper.mapAccessTypeToOpcode(fieldNode.accessTypeNode), fieldNode.identifier, mapper.getTypeChar((BaseType) fieldNode.type), null, null);
|
||||
}
|
||||
classWriter.visitField(mapper.mapAccesTypeToOpcode(fieldNode.accessTypeNode), fieldNode.identifier, mapper.getTypeChar(fieldNode.type.enumTypeNode), null, null );
|
||||
classWriter.visitEnd();
|
||||
}
|
||||
|
||||
private void printIntoClassFile(byte[] byteCode, String name, String outputDirectory) {
|
||||
File directory = new File(outputDirectory);
|
||||
private void printIntoClassFile(byte[] byteCode, String name) {
|
||||
String directoryPath = "src/main/java/classFileOutput";
|
||||
File directory = new File(directoryPath);
|
||||
if (!directory.exists()) {
|
||||
directory.mkdirs();
|
||||
}
|
||||
|
||||
String filePath = outputDirectory + "/" + name + ".class";
|
||||
String filePath = directoryPath + "/" + name + ".class";
|
||||
try {
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(filePath);
|
||||
fileOutputStream.write(byteCode);
|
||||
@@ -82,15 +59,4 @@ public class ClassCodeGen implements ClassVisitor {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeToJar(byte[] byteCode, String className) {
|
||||
try {
|
||||
JarEntry jarEntry = new JarEntry(className + ".class");
|
||||
jarOutputStream.putNextEntry(jarEntry);
|
||||
jarOutputStream.write(byteCode);
|
||||
jarOutputStream.closeEntry();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
13
src/main/java/bytecode/FieldCodeGen.java
Normal file
13
src/main/java/bytecode/FieldCodeGen.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package bytecode;
|
||||
|
||||
import ast.member.FieldNode;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.FieldVisitor;
|
||||
|
||||
public class FieldCodeGen {
|
||||
|
||||
public void generateFieldCode(ClassWriter classWriter, FieldNode fieldNode) {
|
||||
Mapper mapper = new Mapper();
|
||||
FieldVisitor fieldVisitor = classWriter.visitField(mapper.mapAccesTypeToOpcode(fieldNode.accessTypeNode), fieldNode.identifier, "", null, null);
|
||||
}
|
||||
}
|
||||
@@ -1,64 +1,40 @@
|
||||
package bytecode;
|
||||
|
||||
import ast.parameters.ParameterNode;
|
||||
import ast.type.*;
|
||||
import ast.type.type.BaseType;
|
||||
import ast.type.type.ITypeNode;
|
||||
import ast.type.type.ReferenceType;
|
||||
import ast.type.type.TypeEnum;
|
||||
import ast.type.AccessTypeNode;
|
||||
import ast.type.EnumAccessTypeNode;
|
||||
import ast.type.EnumTypeNode;
|
||||
import ast.type.TypeNode;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Mapper {
|
||||
public int mapAccessTypeToOpcode(AccessModifierNode accessModifierNode) {
|
||||
switch (accessModifierNode.accessType) {
|
||||
case EnumAccessModifierNode.PUBLIC:
|
||||
public int mapAccesTypeToOpcode(AccessTypeNode type) {
|
||||
switch (type.enumAccessTypeNode) {
|
||||
case EnumAccessTypeNode.PUBLIC:
|
||||
return Opcodes.ACC_PUBLIC;
|
||||
case EnumAccessModifierNode.PRIVATE:
|
||||
case EnumAccessTypeNode.PRIVATE:
|
||||
return Opcodes.ACC_PRIVATE;
|
||||
case EnumAccessModifierNode.PUBLIC_STATIC:
|
||||
return Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC;
|
||||
case EnumAccessModifierNode.PRIVATE_STATIC:
|
||||
return Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public String generateMethodDescriptor(ITypeNode type, List<ParameterNode> parameters) {
|
||||
String descriptor = "(";
|
||||
for (ParameterNode parameterNode : parameters) {
|
||||
if(parameterNode.type instanceof BaseType) {
|
||||
descriptor += getTypeChar((BaseType) parameterNode.type);
|
||||
} else {
|
||||
ReferenceType referenceType = (ReferenceType) parameterNode.type;
|
||||
descriptor += "L" + referenceType.getIdentifier() + ";";
|
||||
}
|
||||
}
|
||||
descriptor += ")";
|
||||
if(type instanceof BaseType) {
|
||||
descriptor += getTypeChar((BaseType) type);
|
||||
} else if(type instanceof ReferenceType) {
|
||||
descriptor += "L" + ((ReferenceType) type).getIdentifier() +";";
|
||||
}
|
||||
public String generateMethodDescriptor(TypeNode typeNode) {
|
||||
String descriptor = "()";
|
||||
descriptor += getTypeChar(typeNode.enumTypeNode);
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
public String getTypeChar(BaseType type) {
|
||||
public String getTypeChar(EnumTypeNode enumTypeNode) {
|
||||
String typeChar = "";
|
||||
switch (type.getTypeEnum()) {
|
||||
case TypeEnum.INT:
|
||||
switch (enumTypeNode) {
|
||||
case EnumTypeNode.INT:
|
||||
typeChar = "I";
|
||||
break;
|
||||
case TypeEnum.CHAR:
|
||||
case EnumTypeNode.CHAR:
|
||||
typeChar = "C";
|
||||
break;
|
||||
case TypeEnum.BOOL:
|
||||
case EnumTypeNode.BOOLEAN:
|
||||
typeChar = "Z";
|
||||
break;
|
||||
case TypeEnum.VOID:
|
||||
typeChar = "V";
|
||||
break;
|
||||
}
|
||||
return typeChar;
|
||||
}
|
||||
|
||||
@@ -1,744 +1,38 @@
|
||||
package bytecode;
|
||||
|
||||
import ast.expressions.IExpressionNode;
|
||||
import ast.expressions.binaryexpressions.*;
|
||||
import ast.expressions.unaryexpressions.MemberAccessNode;
|
||||
import ast.expressions.unaryexpressions.NotNode;
|
||||
import ast.expressions.unaryexpressions.UnaryNode;
|
||||
import ast.members.ConstructorNode;
|
||||
import ast.members.MainMethodNode;
|
||||
import ast.members.MethodNode;
|
||||
import ast.parameters.ParameterNode;
|
||||
import ast.statementexpressions.AssignNode;
|
||||
import ast.statementexpressions.AssignableNode;
|
||||
import ast.statementexpressions.NewDeclarationNode;
|
||||
import ast.statementexpressions.crementexpressions.CrementType;
|
||||
import ast.statementexpressions.crementexpressions.DecrementNode;
|
||||
import ast.statementexpressions.crementexpressions.IncrementNode;
|
||||
import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode;
|
||||
import ast.statements.*;
|
||||
import ast.type.AccessModifierNode;
|
||||
import ast.type.EnumAccessModifierNode;
|
||||
import ast.type.ValueNode;
|
||||
import ast.type.type.BaseType;
|
||||
import ast.type.type.ReferenceType;
|
||||
import ast.type.type.TypeEnum;
|
||||
import ast.member.ConstructorNode;
|
||||
import ast.member.MethodNode;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Label;
|
||||
import org.objectweb.asm.MethodVisitor;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.*;
|
||||
|
||||
|
||||
public class MethodCodeGen implements bytecode.visitor.MethodVisitor {
|
||||
|
||||
private final ClassWriter classWriter;
|
||||
private final Mapper mapper;
|
||||
private MethodVisitor methodVisitor;
|
||||
|
||||
private final List<String> localVariables;
|
||||
private ClassWriter classWriter;
|
||||
Mapper mapper = new Mapper();
|
||||
|
||||
public MethodCodeGen(ClassWriter classWriter) {
|
||||
this.classWriter = classWriter;
|
||||
mapper = new Mapper();
|
||||
localVariables = new ArrayList<>();
|
||||
}
|
||||
|
||||
|
||||
// Method nodes
|
||||
|
||||
@Override
|
||||
public void visit(ConstructorNode constructorNode) {
|
||||
methodVisitor =
|
||||
classWriter.visitMethod(mapper.mapAccessTypeToOpcode(constructorNode.accesModifier),
|
||||
MethodVisitor constructor =
|
||||
classWriter.visitMethod(mapper.mapAccesTypeToOpcode(constructorNode.visibility),
|
||||
"<init>",
|
||||
mapper.generateMethodDescriptor(new BaseType(TypeEnum.VOID), constructorNode.parameters),
|
||||
"()V",
|
||||
null,
|
||||
null);
|
||||
|
||||
methodVisitor.visitCode();
|
||||
localVariables.add("this");
|
||||
// Add all method parameters to localVariables
|
||||
for (ParameterNode parameterNode : constructorNode.parameters) {
|
||||
localVariables.add(parameterNode.identifier);
|
||||
}
|
||||
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
|
||||
|
||||
// Visit all statements
|
||||
for (IStatementNode statementNode : constructorNode.block.statements) {
|
||||
statementNode.accept(this);
|
||||
}
|
||||
|
||||
methodVisitor.visitMaxs(0, 0);
|
||||
methodVisitor.visitEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MainMethodNode mainMethodNode) {
|
||||
AccessModifierNode accessModifierNode = new AccessModifierNode("");
|
||||
accessModifierNode.accessType = EnumAccessModifierNode.PUBLIC_STATIC;
|
||||
methodVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
|
||||
"main",
|
||||
"([Ljava/lang/String;)V",
|
||||
null,
|
||||
null);
|
||||
|
||||
methodVisitor.visitCode();
|
||||
localVariables.add("this");
|
||||
localVariables.add("args");
|
||||
|
||||
// Visit all statements
|
||||
for (IStatementNode statementNode : mainMethodNode.block.statements) {
|
||||
statementNode.accept(this);
|
||||
}
|
||||
|
||||
methodVisitor.visitMaxs(0, 0);
|
||||
methodVisitor.visitEnd();
|
||||
constructor.visitEnd();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MethodNode methodNode) {
|
||||
methodVisitor = classWriter.visitMethod(mapper.mapAccessTypeToOpcode(methodNode.accesModifier),
|
||||
methodNode.getIdentifier(),
|
||||
mapper.generateMethodDescriptor(methodNode.getType(), methodNode.parameters),
|
||||
MethodVisitor method = classWriter.visitMethod(mapper.mapAccesTypeToOpcode(methodNode.visibility),
|
||||
methodNode.identifier,
|
||||
mapper.generateMethodDescriptor(methodNode.type),
|
||||
null,
|
||||
null);
|
||||
|
||||
methodVisitor.visitCode();
|
||||
localVariables.add("this");
|
||||
// Add all method parameters to localVariables
|
||||
for (ParameterNode parameterNode : methodNode.parameters) {
|
||||
localVariables.add(parameterNode.identifier);
|
||||
}
|
||||
|
||||
// Visit all statements
|
||||
for (IStatementNode statementNode : methodNode.block.statements) {
|
||||
statementNode.accept(this);
|
||||
}
|
||||
|
||||
methodVisitor.visitMaxs(0, 0);
|
||||
methodVisitor.visitEnd();
|
||||
}
|
||||
|
||||
|
||||
// Binary expressions
|
||||
|
||||
@Override
|
||||
public void visit(BinaryNode binaryNode) {
|
||||
binaryNode.accept(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(CalculationNode calculationNode) {
|
||||
if (calculationNode.calculationExpression != null) {
|
||||
calculationNode.calculationExpression.accept(this);
|
||||
}
|
||||
if (calculationNode.dotExpression != null) {
|
||||
calculationNode.dotExpression.accept(this);
|
||||
}
|
||||
if (calculationNode.operator != null) {
|
||||
switch (calculationNode.operator) {
|
||||
case PLUS:
|
||||
methodVisitor.visitInsn(IADD);
|
||||
break;
|
||||
case MINUS:
|
||||
methodVisitor.visitInsn(ISUB);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(DotNode dotNode) {
|
||||
if (dotNode.dotExpression != null) {
|
||||
dotNode.dotExpression.accept(this);
|
||||
}
|
||||
if (dotNode.dotSubtractionExpression != null) {
|
||||
dotNode.dotSubtractionExpression.accept(this);
|
||||
}
|
||||
if (dotNode.operator != null) {
|
||||
switch (dotNode.operator) {
|
||||
case DIV:
|
||||
methodVisitor.visitInsn(IDIV);
|
||||
break;
|
||||
case MULT:
|
||||
methodVisitor.visitInsn(IMUL);
|
||||
break;
|
||||
case MOD:
|
||||
methodVisitor.visitInsn(IREM);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(DotSubtractionNode dotSubtractionNode) {
|
||||
if (dotSubtractionNode.value != null) {
|
||||
dotSubtractionNode.value.accept(this);
|
||||
} else if (dotSubtractionNode.identifier != null) {
|
||||
methodVisitor.visitVarInsn(ILOAD, localVariables.indexOf(dotSubtractionNode.identifier));
|
||||
} else if (dotSubtractionNode.memberAccess != null) {
|
||||
dotSubtractionNode.memberAccess.accept(this);
|
||||
} else if (dotSubtractionNode.methodCall != null) {
|
||||
dotSubtractionNode.methodCall.accept(this);
|
||||
} else if (dotSubtractionNode.calculationExpression != null) {
|
||||
dotSubtractionNode.calculationExpression.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NonCalculationNode nonCalculationNode) {
|
||||
Label labelFalse = new Label();
|
||||
Label labelTrue = new Label();
|
||||
switch (nonCalculationNode.operator) {
|
||||
case AND:
|
||||
nonCalculationNode.unaryExpression.accept(this);
|
||||
methodVisitor.visitJumpInsn(IFEQ, labelFalse); // Value compared to 0 (false)
|
||||
nonCalculationNode.expression.accept(this);
|
||||
methodVisitor.visitJumpInsn(IFEQ, labelFalse);
|
||||
break;
|
||||
case OR:
|
||||
nonCalculationNode.unaryExpression.accept(this);
|
||||
methodVisitor.visitJumpInsn(IFNE, labelTrue);
|
||||
nonCalculationNode.expression.accept(this);
|
||||
methodVisitor.visitJumpInsn(IFEQ, labelFalse);
|
||||
break;
|
||||
case GREATER:
|
||||
nonCalculationNode.unaryExpression.accept(this);
|
||||
nonCalculationNode.expression.accept(this);
|
||||
methodVisitor.visitJumpInsn(IF_ICMPLE, labelFalse);
|
||||
break;
|
||||
case LESS:
|
||||
nonCalculationNode.unaryExpression.accept(this);
|
||||
nonCalculationNode.expression.accept(this);
|
||||
methodVisitor.visitJumpInsn(IF_ICMPGE, labelFalse);
|
||||
break;
|
||||
case GREATER_EQUAL:
|
||||
nonCalculationNode.unaryExpression.accept(this);
|
||||
nonCalculationNode.expression.accept(this);
|
||||
methodVisitor.visitJumpInsn(IF_ICMPLT, labelFalse);
|
||||
break;
|
||||
case LESS_EQUAL:
|
||||
nonCalculationNode.unaryExpression.accept(this);
|
||||
nonCalculationNode.expression.accept(this);
|
||||
methodVisitor.visitJumpInsn(IF_ICMPGT, labelFalse);
|
||||
break;
|
||||
case EQUAL:
|
||||
nonCalculationNode.unaryExpression.accept(this);
|
||||
nonCalculationNode.expression.accept(this);
|
||||
if (nonCalculationNode.unaryExpression.getType() instanceof BaseType && nonCalculationNode.expression.getType() instanceof BaseType) {
|
||||
methodVisitor.visitJumpInsn(IF_ICMPNE, labelFalse);
|
||||
} else {
|
||||
methodVisitor.visitJumpInsn(IF_ACMPNE, labelFalse);
|
||||
}
|
||||
break;
|
||||
case NOT_EQUAL:
|
||||
nonCalculationNode.unaryExpression.accept(this);
|
||||
nonCalculationNode.expression.accept(this);
|
||||
if (nonCalculationNode.unaryExpression.getType() instanceof BaseType && nonCalculationNode.expression.getType() instanceof BaseType) {
|
||||
methodVisitor.visitJumpInsn(IF_ICMPEQ, labelFalse);
|
||||
} else {
|
||||
methodVisitor.visitJumpInsn(IF_ACMPEQ, labelFalse);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
Label labelEndLogicalExpression = new Label();
|
||||
|
||||
methodVisitor.visitLabel(labelTrue);
|
||||
methodVisitor.visitInsn(ICONST_1); // true
|
||||
methodVisitor.visitJumpInsn(GOTO, labelEndLogicalExpression);
|
||||
|
||||
methodVisitor.visitLabel(labelFalse);
|
||||
methodVisitor.visitInsn(ICONST_0); // false
|
||||
|
||||
methodVisitor.visitLabel(labelEndLogicalExpression);
|
||||
}
|
||||
|
||||
|
||||
// Unary expressions
|
||||
|
||||
@Override
|
||||
public void visit(MemberAccessNode memberAccessNode) {
|
||||
// Only used to get, not to put
|
||||
int localVarIndex = localVariables.indexOf("memberAccessNode.identifier"); // TODO
|
||||
if (localVarIndex >= 0) { // local var object
|
||||
methodVisitor.visitVarInsn(ALOAD, localVarIndex);
|
||||
} else { // this field
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
}
|
||||
|
||||
if (memberAccessNode.getTypeNode() instanceof BaseType) {
|
||||
methodVisitor.visitFieldInsn(GETFIELD, memberAccessNode.identifiers.get(0), memberAccessNode.identifiers.get(1), mapper.getTypeChar((BaseType) memberAccessNode.getTypeNode()));
|
||||
} else if (memberAccessNode.getTypeNode() instanceof ReferenceType) {
|
||||
methodVisitor.visitFieldInsn(GETFIELD, memberAccessNode.identifiers.get(0), memberAccessNode.identifiers.get(1), "L" + ((ReferenceType) memberAccessNode.getTypeNode()).getIdentifier() + ";");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NotNode notNode) {
|
||||
Label labelFalse = new Label();
|
||||
Label labelTrue = new Label();
|
||||
|
||||
notNode.expression.accept(this);
|
||||
methodVisitor.visitJumpInsn(Opcodes.IFNE, labelFalse); // false if value is true (value != 0)
|
||||
|
||||
Label labelEndLogicalExpression = new Label();
|
||||
|
||||
methodVisitor.visitLabel(labelTrue);
|
||||
methodVisitor.visitInsn(ICONST_1); // true
|
||||
methodVisitor.visitJumpInsn(GOTO, labelEndLogicalExpression);
|
||||
|
||||
methodVisitor.visitLabel(labelFalse);
|
||||
methodVisitor.visitInsn(ICONST_0); // false
|
||||
|
||||
methodVisitor.visitLabel(labelEndLogicalExpression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(UnaryNode unaryNode) {
|
||||
if (unaryNode.thisExp != null) {
|
||||
methodVisitor.visitVarInsn(ALOAD, 0); // this
|
||||
} else if (unaryNode.memberAccess != null) {
|
||||
unaryNode.memberAccess.setTypeNode(unaryNode.getType());
|
||||
unaryNode.memberAccess.accept(this);
|
||||
} else if (unaryNode.value != null) {
|
||||
unaryNode.value.accept(this);
|
||||
} else if (unaryNode.notExpression != null) {
|
||||
unaryNode.notExpression.accept(this);
|
||||
} else if (unaryNode.statement != null) {
|
||||
unaryNode.statement.accept(this);
|
||||
} else if (unaryNode.expression != null) {
|
||||
unaryNode.expression.accept(this);
|
||||
} else if (unaryNode.identifier != null) {
|
||||
methodVisitor.visitVarInsn(ILOAD, localVariables.indexOf(unaryNode.identifier));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Statements
|
||||
|
||||
@Override
|
||||
public void visit(BlockNode blockNode) {
|
||||
for (IStatementNode statementNode : blockNode.statements) {
|
||||
statementNode.accept(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IfElseNode ifElseNode) {
|
||||
Label elseLabel = new Label();
|
||||
Label endLabel = new Label();
|
||||
|
||||
Label[] elseIfLabels = new Label[ifElseNode.elseIfStatements.size()];
|
||||
for (int i = 0; i < ifElseNode.elseIfStatements.size(); i++) {
|
||||
elseIfLabels[i] = new Label();
|
||||
}
|
||||
|
||||
ifElseNode.ifStatement.expression.accept(this);
|
||||
if (ifElseNode.elseIfStatements.isEmpty()) {
|
||||
// No else if
|
||||
methodVisitor.visitJumpInsn(IFEQ, elseLabel);
|
||||
} else {
|
||||
// else if statements
|
||||
methodVisitor.visitJumpInsn(IFEQ, elseIfLabels[0]);
|
||||
}
|
||||
|
||||
ifElseNode.ifStatement.block.accept(this); // accept if block
|
||||
|
||||
methodVisitor.visitJumpInsn(GOTO, endLabel);
|
||||
|
||||
for (int i = 0; i < ifElseNode.elseIfStatements.size(); i++) {
|
||||
methodVisitor.visitLabel(elseIfLabels[i]);
|
||||
ifElseNode.elseIfStatements.get(i).expression.accept(this);
|
||||
if (i + 1 < elseIfLabels.length) {
|
||||
// at least one more else if
|
||||
methodVisitor.visitJumpInsn(IFEQ, elseIfLabels[i + 1]);
|
||||
} else {
|
||||
methodVisitor.visitJumpInsn(IFEQ, elseLabel);
|
||||
}
|
||||
ifElseNode.elseIfStatements.get(i).block.accept(this);
|
||||
methodVisitor.visitJumpInsn(GOTO, endLabel);
|
||||
}
|
||||
|
||||
if (ifElseNode.elseStatement != null) {
|
||||
methodVisitor.visitLabel(elseLabel);
|
||||
ifElseNode.elseStatement.block.accept(this);
|
||||
} else {
|
||||
methodVisitor.visitLabel(elseLabel);
|
||||
}
|
||||
|
||||
methodVisitor.visitLabel(endLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(LocalVariableDeclarationNode localVariableDeclarationNode) {
|
||||
if (localVariableDeclarationNode.expression != null) {
|
||||
// Process expression
|
||||
localVariableDeclarationNode.expression.accept(this);
|
||||
|
||||
if (localVariableDeclarationNode.expression instanceof UnaryNode) {
|
||||
UnaryNode unaryNode = (UnaryNode) localVariableDeclarationNode.expression;
|
||||
if (unaryNode.statement instanceof IncrementNode) {
|
||||
IncrementNode incrementNode = (IncrementNode) unaryNode.statement;
|
||||
incrementNode.assignableExpression.typeNode = unaryNode.type;
|
||||
loadIncrement(incrementNode);
|
||||
} else if (unaryNode.statement instanceof DecrementNode) {
|
||||
DecrementNode decrementNode = (DecrementNode) unaryNode.statement;
|
||||
decrementNode.assignableExpression.typeNode = unaryNode.type;
|
||||
loadDecrement(decrementNode);
|
||||
}
|
||||
}
|
||||
|
||||
// add local var to list if not in list
|
||||
if (!localVariables.contains(localVariableDeclarationNode.identifier)) {
|
||||
localVariables.add(localVariableDeclarationNode.identifier);
|
||||
}
|
||||
if (localVariableDeclarationNode.type instanceof BaseType) {
|
||||
methodVisitor.visitVarInsn(ISTORE, localVariables.indexOf(localVariableDeclarationNode.identifier));
|
||||
} else if (localVariableDeclarationNode.type instanceof ReferenceType) {
|
||||
methodVisitor.visitVarInsn(ASTORE, localVariables.indexOf(localVariableDeclarationNode.identifier));
|
||||
}
|
||||
} else {
|
||||
// Local var declaration
|
||||
if (!localVariables.contains(localVariableDeclarationNode.identifier)) {
|
||||
localVariables.add(localVariableDeclarationNode.identifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AssignNode assignNode) {
|
||||
if (assignNode.assignable.memberAccess != null) { // this / object
|
||||
assignNode.assignable.memberAccess.setTypeNode(assignNode.assignable.typeNode);
|
||||
if (assignNode.expression instanceof UnaryNode) {
|
||||
UnaryNode unaryNode = (UnaryNode) assignNode.expression;
|
||||
if (unaryNode.statement instanceof IncrementNode) {
|
||||
IncrementNode incrementNode = (IncrementNode) unaryNode.statement;
|
||||
if (incrementNode.crementType.equals(CrementType.PREFIX)) { // ++i
|
||||
incrementNode.accept(this); // crement
|
||||
fieldOrObjectVarCrementAssign(assignNode); // assign
|
||||
} else { // i++
|
||||
fieldOrObjectVarCrementAssign(assignNode); // assign
|
||||
incrementNode.accept(this); // crement
|
||||
}
|
||||
} else if (unaryNode.statement instanceof DecrementNode) {
|
||||
DecrementNode decrementNode = (DecrementNode) unaryNode.statement;
|
||||
if (decrementNode.crementType.equals(CrementType.PREFIX)) {
|
||||
decrementNode.accept(this); // crement
|
||||
fieldOrObjectVarCrementAssign(assignNode); // assign
|
||||
} else {
|
||||
fieldOrObjectVarCrementAssign(assignNode); // assign
|
||||
decrementNode.accept(this); // crement
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assignFieldOrObjectVar(assignNode);
|
||||
}
|
||||
} else { // local var
|
||||
if (assignNode.expression instanceof UnaryNode) {
|
||||
UnaryNode unaryNode = (UnaryNode) assignNode.expression;
|
||||
if (unaryNode.statement instanceof IncrementNode || unaryNode.statement instanceof DecrementNode) {
|
||||
localVarCrementAssign(assignNode);
|
||||
}
|
||||
} else {
|
||||
assignNode.expression.accept(this);
|
||||
assignLocalVar(assignNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadIncrement(IncrementNode incrementNode) {
|
||||
AssignableNode assignableNode = incrementNode.assignableExpression;
|
||||
if (assignableNode.memberAccess != null) {
|
||||
assignableNode.memberAccess.accept(this);
|
||||
} else {
|
||||
if (assignableNode.typeNode instanceof BaseType) {
|
||||
methodVisitor.visitVarInsn(ILOAD, localVariables.indexOf(assignableNode.identifier));
|
||||
} else if (assignableNode.typeNode instanceof ReferenceType) {
|
||||
methodVisitor.visitVarInsn(ALOAD, localVariables.indexOf(assignableNode.identifier));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadDecrement(DecrementNode decrementNode) {
|
||||
AssignableNode assignableNode = decrementNode.assignableExpression;
|
||||
if (assignableNode.memberAccess != null) {
|
||||
assignableNode.memberAccess.accept(this);
|
||||
} else {
|
||||
if (assignableNode.typeNode instanceof BaseType) {
|
||||
methodVisitor.visitVarInsn(ILOAD, localVariables.indexOf(assignableNode.identifier));
|
||||
} else if (assignableNode.typeNode instanceof ReferenceType) {
|
||||
methodVisitor.visitVarInsn(ALOAD, localVariables.indexOf(assignableNode.identifier));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void assignLocalVar(AssignNode assignNode) {
|
||||
if (!localVariables.contains(assignNode.assignable.identifier)) {
|
||||
localVariables.add(assignNode.assignable.identifier);
|
||||
}
|
||||
|
||||
if (assignNode.expression.getType() instanceof BaseType) {
|
||||
methodVisitor.visitVarInsn(ISTORE, localVariables.indexOf(assignNode.assignable.identifier));
|
||||
} else if (assignNode.expression.getType() instanceof ReferenceType) {
|
||||
methodVisitor.visitVarInsn(ASTORE, localVariables.indexOf(assignNode.assignable.identifier));
|
||||
}
|
||||
}
|
||||
|
||||
private void assignFieldOrObjectVar(AssignNode assignNode) {
|
||||
int localVarIndex = localVariables.indexOf(assignNode.assignable.identifier);
|
||||
if (localVarIndex >= 0) { // object
|
||||
methodVisitor.visitVarInsn(ALOAD, localVarIndex);
|
||||
} else if (assignNode.assignable.memberAccess.thisExpr) { // this
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
} else {
|
||||
localVariables.add(assignNode.assignable.identifier);
|
||||
}
|
||||
|
||||
assignNode.expression.accept(this);
|
||||
|
||||
if (assignNode.expression.getType() instanceof BaseType) {
|
||||
methodVisitor.visitFieldInsn(PUTFIELD, assignNode.assignable.memberAccess.identifiers.get(0), assignNode.assignable.memberAccess.identifiers.get(1), mapper.getTypeChar((BaseType) assignNode.expression.getType()));
|
||||
} else if (assignNode.expression.getType() instanceof ReferenceType) {
|
||||
ReferenceType referenceType = (ReferenceType) assignNode.expression.getType();
|
||||
methodVisitor.visitFieldInsn(PUTFIELD, assignNode.assignable.memberAccess.identifiers.get(0), assignNode.assignable.memberAccess.identifiers.get(1), "L" + referenceType.getIdentifier() + ";");
|
||||
}
|
||||
}
|
||||
|
||||
private void localVarCrementAssign(AssignNode assignNode) {
|
||||
UnaryNode unaryNode = (UnaryNode) assignNode.expression;
|
||||
if (unaryNode.statement instanceof IncrementNode) {
|
||||
IncrementNode incrementNode = (IncrementNode) unaryNode.statement;
|
||||
if (incrementNode.crementType.equals(CrementType.PREFIX)) { // ++i
|
||||
incrementNode.accept(this);
|
||||
incrementNode.assignableExpression.typeNode = unaryNode.getType();
|
||||
loadIncrement(incrementNode);
|
||||
assignLocalVar(assignNode);
|
||||
} else { // i++
|
||||
incrementNode.assignableExpression.typeNode = unaryNode.getType();
|
||||
loadIncrement(incrementNode);
|
||||
assignLocalVar(assignNode);
|
||||
incrementNode.accept(this);
|
||||
}
|
||||
} else if (unaryNode.statement instanceof DecrementNode) {
|
||||
DecrementNode decrementNode = (DecrementNode) unaryNode.statement;
|
||||
if (decrementNode.crementType.equals(CrementType.PREFIX)) {
|
||||
decrementNode.accept(this);
|
||||
decrementNode.assignableExpression.typeNode = unaryNode.getType();
|
||||
loadDecrement(decrementNode);
|
||||
assignLocalVar(assignNode);
|
||||
} else {
|
||||
decrementNode.assignableExpression.typeNode = unaryNode.getType();
|
||||
loadDecrement(decrementNode);
|
||||
assignLocalVar(assignNode);
|
||||
decrementNode.accept(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fieldOrObjectVarCrementAssign(AssignNode assignNode) {
|
||||
int localVarIndex = localVariables.indexOf(assignNode.assignable.identifier);
|
||||
if (localVarIndex >= 0) { // object
|
||||
methodVisitor.visitVarInsn(ALOAD, localVarIndex);
|
||||
} else if (assignNode.assignable.memberAccess.thisExpr) { // field
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
} else {
|
||||
localVariables.add(assignNode.assignable.identifier);
|
||||
}
|
||||
|
||||
UnaryNode unaryNode = (UnaryNode) assignNode.expression;
|
||||
if (unaryNode.statement instanceof IncrementNode) {
|
||||
IncrementNode incrementNode = (IncrementNode) unaryNode.statement;
|
||||
incrementNode.assignableExpression.typeNode = unaryNode.getType();
|
||||
loadIncrement((incrementNode));
|
||||
} else if (unaryNode.statement instanceof DecrementNode) {
|
||||
DecrementNode decrementNode = (DecrementNode) unaryNode.statement;
|
||||
decrementNode.assignableExpression.typeNode = unaryNode.getType();
|
||||
loadDecrement(decrementNode);
|
||||
}
|
||||
|
||||
if (assignNode.expression.getType() instanceof BaseType) {
|
||||
methodVisitor.visitFieldInsn(PUTFIELD, assignNode.assignable.memberAccess.identifiers.get(0), assignNode.assignable.memberAccess.identifiers.get(1), mapper.getTypeChar((BaseType) assignNode.expression.getType()));
|
||||
} else if (assignNode.expression.getType() instanceof ReferenceType) {
|
||||
ReferenceType referenceType = (ReferenceType) assignNode.expression.getType();
|
||||
methodVisitor.visitFieldInsn(PUTFIELD, assignNode.assignable.memberAccess.identifiers.get(0), assignNode.assignable.memberAccess.identifiers.get(1), "L" + referenceType.getIdentifier() + ";");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(IncrementNode incrementNode) {
|
||||
if (incrementNode.assignableExpression.memberAccess != null) { // Object var / field
|
||||
int localVarIndex = localVariables.indexOf(incrementNode.assignableExpression.identifier);
|
||||
if (localVarIndex >= 0) { // object
|
||||
methodVisitor.visitVarInsn(ALOAD, localVarIndex);
|
||||
} else { // this
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
}
|
||||
if (incrementNode.assignableExpression.memberAccess.getTypeNode() instanceof BaseType) {
|
||||
methodVisitor.visitFieldInsn(GETFIELD, incrementNode.assignableExpression.memberAccess.identifiers.get(0), incrementNode.assignableExpression.memberAccess.identifiers.get(1), mapper.getTypeChar((BaseType) incrementNode.assignableExpression.memberAccess.getTypeNode()));
|
||||
} else if (incrementNode.assignableExpression.memberAccess.getTypeNode() instanceof ReferenceType) {
|
||||
methodVisitor.visitFieldInsn(GETFIELD, incrementNode.assignableExpression.memberAccess.identifiers.get(0), incrementNode.assignableExpression.memberAccess.identifiers.get(1), "L" + (((ReferenceType) incrementNode.assignableExpression.memberAccess.getTypeNode()).getIdentifier() + ";"));
|
||||
}
|
||||
methodVisitor.visitInsn(ICONST_1);
|
||||
methodVisitor.visitInsn(IADD);
|
||||
if (incrementNode.assignableExpression.memberAccess.getTypeNode() instanceof BaseType) {
|
||||
methodVisitor.visitFieldInsn(PUTFIELD, incrementNode.assignableExpression.memberAccess.identifiers.get(0), incrementNode.assignableExpression.memberAccess.identifiers.get(1), mapper.getTypeChar((BaseType) incrementNode.assignableExpression.memberAccess.getTypeNode()));
|
||||
} else if (incrementNode.assignableExpression.memberAccess.getTypeNode() instanceof ReferenceType) {
|
||||
methodVisitor.visitFieldInsn(PUTFIELD, incrementNode.assignableExpression.memberAccess.identifiers.get(0), incrementNode.assignableExpression.memberAccess.identifiers.get(1), "L" + (((ReferenceType) incrementNode.assignableExpression.memberAccess.getTypeNode()).getIdentifier() + ";"));
|
||||
}
|
||||
} else { // local var
|
||||
methodVisitor.visitIincInsn(localVariables.indexOf(incrementNode.assignableExpression.identifier), 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(DecrementNode decrementNode) {
|
||||
if (decrementNode.assignableExpression.memberAccess != null) { // Object var / field
|
||||
int localVarIndex = localVariables.indexOf(decrementNode.assignableExpression.identifier);
|
||||
if (localVarIndex >= 0) { // object
|
||||
methodVisitor.visitVarInsn(ALOAD, localVarIndex);
|
||||
} else { // this
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
}
|
||||
if (decrementNode.assignableExpression.memberAccess.getTypeNode() instanceof BaseType) {
|
||||
methodVisitor.visitFieldInsn(GETFIELD, decrementNode.assignableExpression.memberAccess.identifiers.get(0), decrementNode.assignableExpression.memberAccess.identifiers.get(1), mapper.getTypeChar((BaseType) decrementNode.assignableExpression.memberAccess.getTypeNode()));
|
||||
} else if (decrementNode.assignableExpression.memberAccess.getTypeNode() instanceof ReferenceType) {
|
||||
methodVisitor.visitFieldInsn(GETFIELD, decrementNode.assignableExpression.memberAccess.identifiers.get(0), decrementNode.assignableExpression.memberAccess.identifiers.get(1), "L" + (((ReferenceType) decrementNode.assignableExpression.memberAccess.getTypeNode()).getIdentifier() + ";"));
|
||||
}
|
||||
methodVisitor.visitInsn(ICONST_1);
|
||||
methodVisitor.visitInsn(ISUB);
|
||||
if (decrementNode.assignableExpression.memberAccess.getTypeNode() instanceof BaseType) {
|
||||
methodVisitor.visitFieldInsn(PUTFIELD, decrementNode.assignableExpression.memberAccess.identifiers.get(0), decrementNode.assignableExpression.memberAccess.identifiers.get(1), mapper.getTypeChar((BaseType) decrementNode.assignableExpression.memberAccess.getTypeNode()));
|
||||
} else if (decrementNode.assignableExpression.memberAccess.getTypeNode() instanceof ReferenceType) {
|
||||
methodVisitor.visitFieldInsn(PUTFIELD, decrementNode.assignableExpression.memberAccess.identifiers.get(0), decrementNode.assignableExpression.memberAccess.identifiers.get(1), "L" + (((ReferenceType) decrementNode.assignableExpression.memberAccess.getTypeNode()).getIdentifier() + ";"));
|
||||
}
|
||||
} else { // local var
|
||||
methodVisitor.visitIincInsn(localVariables.indexOf(decrementNode.assignableExpression.identifier), -1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NewDeclarationNode newDeclarationNode) {
|
||||
methodVisitor.visitTypeInsn(NEW, newDeclarationNode.identifier);
|
||||
methodVisitor.visitInsn(DUP);
|
||||
List<ParameterNode> parameterNodes = new ArrayList<>();
|
||||
for (IExpressionNode expressionNode : newDeclarationNode.expressions) {
|
||||
expressionNode.accept(this);
|
||||
parameterNodes.add(new ParameterNode(expressionNode.getType(), ""));
|
||||
}
|
||||
methodVisitor.visitMethodInsn(INVOKESPECIAL, newDeclarationNode.identifier, "<init>", mapper.generateMethodDescriptor(new BaseType(TypeEnum.VOID), parameterNodes), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ValueNode valueNode) {
|
||||
switch (valueNode.valueType) {
|
||||
case INT_VALUE:
|
||||
int intValue = Integer.parseInt(valueNode.value);
|
||||
if (intValue >= Byte.MIN_VALUE && intValue <= Byte.MAX_VALUE) { // load int as byte
|
||||
methodVisitor.visitIntInsn(BIPUSH, intValue);
|
||||
} else if (intValue >= Short.MIN_VALUE && intValue <= Short.MAX_VALUE) { // load int as short
|
||||
methodVisitor.visitIntInsn(SIPUSH, intValue);
|
||||
} else { // load int as const
|
||||
methodVisitor.visitLdcInsn(intValue);
|
||||
}
|
||||
break;
|
||||
case BOOLEAN_VALUE:
|
||||
if (valueNode.value.equals("true")) {
|
||||
methodVisitor.visitInsn(ICONST_1);
|
||||
} else {
|
||||
methodVisitor.visitInsn(ICONST_0);
|
||||
}
|
||||
break;
|
||||
case CHAR_VALUE:
|
||||
char charValue = valueNode.value.charAt(0);
|
||||
if (charValue <= Byte.MAX_VALUE) { // load char as byte
|
||||
methodVisitor.visitIntInsn(BIPUSH, charValue);
|
||||
} else if (charValue <= Short.MAX_VALUE) { // load char as short
|
||||
methodVisitor.visitIntInsn(SIPUSH, charValue);
|
||||
} else { // load char as const
|
||||
methodVisitor.visitLdcInsn(charValue);
|
||||
}
|
||||
break;
|
||||
case NULL_VALUE:
|
||||
methodVisitor.visitInsn(ACONST_NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ReturnNode returnNode) {
|
||||
if (returnNode.voidReturn) { // Return nothing
|
||||
methodVisitor.visitInsn(RETURN);
|
||||
} else { // Return something
|
||||
// Process expression
|
||||
returnNode.expression.accept(this);
|
||||
|
||||
if (returnNode.expression instanceof UnaryNode) {
|
||||
UnaryNode unaryNode = (UnaryNode) returnNode.expression;
|
||||
if (unaryNode.statement instanceof IncrementNode) {
|
||||
IncrementNode incrementNode = (IncrementNode) unaryNode.statement;
|
||||
incrementNode.assignableExpression.typeNode = unaryNode.getType();
|
||||
loadIncrement(incrementNode);
|
||||
}
|
||||
if (unaryNode.statement instanceof DecrementNode) {
|
||||
DecrementNode decrementNode = (DecrementNode) unaryNode.statement;
|
||||
decrementNode.assignableExpression.typeNode = unaryNode.getType();
|
||||
loadDecrement(decrementNode);
|
||||
}
|
||||
}
|
||||
|
||||
// Return result of expression
|
||||
if (returnNode.expression.getType() instanceof BaseType) {
|
||||
methodVisitor.visitInsn(IRETURN);
|
||||
} else if (returnNode.expression.getType() instanceof ReferenceType) {
|
||||
methodVisitor.visitInsn(ARETURN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void visit(WhileNode whileNode) {
|
||||
Label loopLabel = new Label();
|
||||
Label endOfLoopLabel = new Label();
|
||||
|
||||
methodVisitor.visitLabel(loopLabel);
|
||||
// while loop
|
||||
whileNode.expression.accept(this);
|
||||
methodVisitor.visitJumpInsn(IFEQ, endOfLoopLabel); // if condition is false, jump out of loop
|
||||
|
||||
whileNode.block.accept(this);
|
||||
methodVisitor.visitJumpInsn(GOTO, loopLabel);
|
||||
|
||||
methodVisitor.visitLabel(endOfLoopLabel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(MethodCallNode methodCallNode) {
|
||||
List<ParameterNode> parameterNodes = new ArrayList<>();
|
||||
int localVarIndex = -1;
|
||||
if (methodCallNode.target.memberAccess.identifiers.size() > 1) {
|
||||
localVarIndex = localVariables.indexOf(methodCallNode.target.memberAccess.identifiers.get(1));
|
||||
}
|
||||
if (localVarIndex >= 0) { // local var object
|
||||
methodVisitor.visitVarInsn(ALOAD, localVarIndex);
|
||||
} else { // this field
|
||||
methodVisitor.visitVarInsn(ALOAD, 0);
|
||||
}
|
||||
for (IExpressionNode expressionNode : methodCallNode.parameters) {
|
||||
expressionNode.accept(this);
|
||||
parameterNodes.add(new ParameterNode(expressionNode.getType(), ""));
|
||||
}
|
||||
if(methodCallNode.type == null) {
|
||||
methodCallNode.type = new BaseType(TypeEnum.INT);
|
||||
}
|
||||
methodVisitor.visitMethodInsn(INVOKEVIRTUAL, methodCallNode.target.memberAccess.identifiers.get(0), methodCallNode.identifier, mapper.generateMethodDescriptor(methodCallNode.type, parameterNodes), false);
|
||||
method.visitEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
package bytecode.visitor;
|
||||
|
||||
import ast.ClassNode;
|
||||
import ast.members.FieldNode;
|
||||
import ast.member.FieldNode;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
|
||||
public interface ClassVisitor {
|
||||
void visit(ClassNode classNode);
|
||||
|
||||
@@ -1,68 +1,9 @@
|
||||
package bytecode.visitor;
|
||||
|
||||
import ast.expressions.binaryexpressions.*;
|
||||
import ast.expressions.unaryexpressions.MemberAccessNode;
|
||||
import ast.expressions.unaryexpressions.NotNode;
|
||||
import ast.expressions.unaryexpressions.UnaryNode;
|
||||
import ast.members.ConstructorNode;
|
||||
import ast.members.MainMethodNode;
|
||||
import ast.members.MethodNode;
|
||||
import ast.statementexpressions.AssignNode;
|
||||
import ast.statementexpressions.NewDeclarationNode;
|
||||
import ast.statementexpressions.crementexpressions.DecrementNode;
|
||||
import ast.statementexpressions.crementexpressions.IncrementNode;
|
||||
import ast.statementexpressions.methodcallstatementnexpressions.ChainedMethodNode;
|
||||
import ast.statementexpressions.methodcallstatementnexpressions.MethodCallNode;
|
||||
import ast.statements.*;
|
||||
import ast.type.ValueNode;
|
||||
import ast.member.ConstructorNode;
|
||||
import ast.member.MethodNode;
|
||||
|
||||
public interface MethodVisitor {
|
||||
// members
|
||||
void visit(ConstructorNode constructorNode);
|
||||
|
||||
void visit(MethodNode methodNode);
|
||||
|
||||
void visit(MainMethodNode mainMethodNode);
|
||||
|
||||
// Binary expressions
|
||||
void visit(BinaryNode binaryNode);
|
||||
|
||||
void visit(CalculationNode calculationNode);
|
||||
|
||||
void visit(DotNode dotNode);
|
||||
|
||||
void visit(DotSubtractionNode dotSubtractionNode);
|
||||
|
||||
void visit(NonCalculationNode nonCalculationNode);
|
||||
|
||||
// Unary expressions
|
||||
void visit(MemberAccessNode memberAccessNode);
|
||||
|
||||
void visit(NotNode notExpressionNode);
|
||||
|
||||
void visit(UnaryNode unaryExpressionNode);
|
||||
|
||||
// statements
|
||||
void visit(BlockNode blockNode);
|
||||
void visit(IfElseNode ifElseNode);
|
||||
|
||||
void visit(IncrementNode incrementNode);
|
||||
void visit(DecrementNode decrementNode);
|
||||
|
||||
void visit(LocalVariableDeclarationNode localVariableDeclarationNode);
|
||||
|
||||
void visit(ReturnNode returnNode);
|
||||
|
||||
void visit(WhileNode whileNode);
|
||||
|
||||
// statement expression
|
||||
void visit(MethodCallNode methodCallNode);
|
||||
|
||||
void visit(AssignNode assignNode);
|
||||
|
||||
void visit(NewDeclarationNode newDeclarationNode);
|
||||
|
||||
// type
|
||||
void visit(ValueNode valueNode);
|
||||
|
||||
}
|
||||
|
||||
BIN
src/main/java/classFileOutput/Example.class
Normal file
BIN
src/main/java/classFileOutput/Example.class
Normal file
Binary file not shown.
BIN
src/main/java/classFileOutput/Test.class
Normal file
BIN
src/main/java/classFileOutput/Test.class
Normal file
Binary file not shown.
@@ -1,116 +0,0 @@
|
||||
package main;
|
||||
|
||||
import ast.ASTNode;
|
||||
import ast.ProgramNode;
|
||||
import parser.astBuilder.ASTBuilder;
|
||||
import parser.generated.SimpleJavaLexer;
|
||||
import parser.generated.SimpleJavaParser;
|
||||
import semantic.SemanticAnalyzer;
|
||||
import bytecode.ByteCodeGenerator;
|
||||
|
||||
import org.antlr.v4.runtime.*;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Start miniCompiler using make:
|
||||
* <p> <code> cd .\src\test\ </code>
|
||||
* <p> <code> make clean compile-miniCompiler </code>
|
||||
* <p> Start miniCompiler using jar:
|
||||
* <p> <code> java.exe -DgenJar=true_OR_false -DgenClass=true_OR_false -jar path_to_jar\JavaCompiler-1.0-jar-with-dependencies.jar 'path_to_input_file.java' 'path_to_output_directory' </code>
|
||||
* <p> Example (jar needs to be in the target directory, compile with make or mvn package first):
|
||||
* <code> java.exe -DgenJar=true -DgenClass=true -jar .\target\JavaCompiler-1.0-jar-with-dependencies.jar 'src/main/resources/input/CompilerInput.java' 'src/main/resources/output' </code>
|
||||
*/
|
||||
public class Main {
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length == 2) {
|
||||
// args[0] is the input file path
|
||||
// args[1] is the output directory path
|
||||
String inputFilePath = args[0];
|
||||
String outputDirectoryPath = args[1];
|
||||
System.out.println("Compiling file: " + inputFilePath);
|
||||
try {
|
||||
CharStream inputCharStream = CharStreams.fromPath(Paths.get(inputFilePath));
|
||||
compileFile(inputCharStream, outputDirectoryPath);
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error reading the file: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
CharStream codeCharStream = CharStreams.fromPath(Paths.get("src/test/resources/input/finalTest/Car.java"));
|
||||
compileFile(codeCharStream, "src/test/resources/input/finalTest");
|
||||
} catch (IOException e) {
|
||||
System.err.println("Error reading the file: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is used to compile a file from a given CharStream and output the bytecode to a specified directory.
|
||||
* It goes through the following steps:
|
||||
* <p>1. Scanner: It uses the SimpleJavaLexer to tokenize the input CharStream.
|
||||
* <p>2. Parser: It uses the SimpleJavaParser to parse the tokens and generate a ParseTree.
|
||||
* <p>3. AST Builder: It uses the ASTBuilder to visit the ParseTree and generate an Abstract Syntax Tree (AST).
|
||||
* <p>4. Semantic Analyzer: It uses the SemanticAnalyzer to generate a typed AST.
|
||||
* <p>5. Bytecode Generator: It uses the ByteCodeGenerator to generate bytecode from the typed AST and output it to the specified directory.
|
||||
*
|
||||
* @param inputCharStream The CharStream representing the input file to be compiled.
|
||||
* @param outputDirectoryPath The path of the directory where the output bytecode should be written.
|
||||
*/
|
||||
static void compileFile(CharStream inputCharStream, String outputDirectoryPath) {
|
||||
// Initialize the logger
|
||||
new MiniCompilerLogger();
|
||||
|
||||
/* ------------------------- Scanner -> tokens ------------------------- */
|
||||
// Use the SimpleJavaLexer to tokenize the input CharStream
|
||||
SimpleJavaLexer lexer = new SimpleJavaLexer(inputCharStream);
|
||||
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
|
||||
tokenStream.fill();
|
||||
// Log the tokens
|
||||
MiniCompilerLogger.logScanner(tokenStream);
|
||||
|
||||
/*------------------------- Parser -> Parsetree -------------------------*/
|
||||
// Use the SimpleJavaParser to parse the tokens and generate a ParseTree
|
||||
SimpleJavaParser parser = new SimpleJavaParser(tokenStream);
|
||||
ParseTree parseTree = parser.program(); // parse the input
|
||||
// Log the ParseTree
|
||||
MiniCompilerLogger.logParser(parseTree, parser);
|
||||
|
||||
/*------------------------- AST builder -> AST -------------------------*/
|
||||
// Use the ASTBuilder to visit the ParseTree and generate an Abstract Syntax Tree (AST)
|
||||
ASTBuilder astBuilder = new ASTBuilder();
|
||||
ASTNode abstractSyntaxTree = astBuilder.visit(parseTree);
|
||||
// Log the AST
|
||||
MiniCompilerLogger.logAST(abstractSyntaxTree);
|
||||
|
||||
/*------------------------- Semantic Analyzer -> typed AST -------------------------*/
|
||||
// Use the SemanticAnalyzer to generate a typed AST
|
||||
ASTNode typedAst = SemanticAnalyzer.generateTast(abstractSyntaxTree);
|
||||
// Log the typed AST
|
||||
MiniCompilerLogger.logSemanticAnalyzer(typedAst);
|
||||
|
||||
if(SemanticAnalyzer.errors.isEmpty()){
|
||||
/*------------------------- Bytecode Generator -> Bytecode -------------------------*/
|
||||
// Use the ByteCodeGenerator to generate bytecode from the typed AST and output it to the specified directory
|
||||
|
||||
final boolean genJar = Optional.ofNullable(System.getProperty("genJar")).map(String::toLowerCase).map(Boolean::parseBoolean).orElse(true);
|
||||
final boolean genClass = Optional.ofNullable(System.getProperty("genClass")).map(String::toLowerCase).map(Boolean::parseBoolean).orElse(true);
|
||||
|
||||
ByteCodeGenerator byteCodeGenerator = new ByteCodeGenerator(outputDirectoryPath, genJar, genClass);
|
||||
assert typedAst != null;
|
||||
byteCodeGenerator.visit((ProgramNode) typedAst);
|
||||
// Log the bytecode generation
|
||||
MiniCompilerLogger.logBytecodeGenerator();
|
||||
} else {
|
||||
for(Exception exception : SemanticAnalyzer.errors){
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
package main;
|
||||
|
||||
import ast.ASTNode;
|
||||
import org.antlr.v4.runtime.CommonTokenStream;
|
||||
import org.antlr.v4.runtime.Parser;
|
||||
import org.antlr.v4.runtime.RuleContext;
|
||||
import org.antlr.v4.runtime.Token;
|
||||
import org.antlr.v4.runtime.tree.ParseTree;
|
||||
import parser.generated.SimpleJavaLexer;
|
||||
import parser.generated.SimpleJavaParser;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.logging.*;
|
||||
|
||||
/**
|
||||
* Beispiel für Logging-Arten:
|
||||
* <p><code>logger.severe("Schwerwiegender Fehler");</code>
|
||||
* <p><code>logger.warning("Warnung");</code>
|
||||
* <p><code>logger.info("Information");</code>
|
||||
* <p><code>logger.config("Konfigurationshinweis");</code>
|
||||
* <p><code>logger.fine("Fein");</code>
|
||||
* <p><code>logger.finer("Feiner");</code>
|
||||
* <p><code>logger.finest("Am feinsten");</code>
|
||||
* <p>You may toggle the logging level of the console and file handlers by
|
||||
* changing the level ALL/OFF/etc. in the constructor.
|
||||
* <code>consoleHandler.setLevel(Level.OFF);</code>
|
||||
* <code>fileHandler.setLevel(Level.ALL);</code>
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
public class MiniCompilerLogger {
|
||||
|
||||
static Logger logger = Logger.getLogger("miniCompilerLogs");
|
||||
|
||||
public MiniCompilerLogger() {
|
||||
// ------------------------- Logging -------------------------
|
||||
logger.setLevel(Level.ALL);
|
||||
logger.getParent().getHandlers()[0].setLevel(Level.ALL);
|
||||
logger.setUseParentHandlers(false);
|
||||
|
||||
// Custom formatter class
|
||||
class CustomFormatter extends Formatter {
|
||||
private final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss dd-MM-yyyy");
|
||||
|
||||
@Override
|
||||
public String format(LogRecord record) {
|
||||
return formatMessage(record) + System.lineSeparator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHead(Handler h) {
|
||||
Date now = new Date();
|
||||
String dateTime = dateFormat.format(now);
|
||||
return "Log Start Time: " + dateTime + "\n"
|
||||
+ "Logger Name: " + h.getFormatter().getClass().getName() + "\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Configure console handler
|
||||
Handler consoleHandler = new ConsoleHandler();
|
||||
// Toggle console logging on/off
|
||||
consoleHandler.setLevel(Level.OFF);
|
||||
consoleHandler.setFormatter(new CustomFormatter());
|
||||
logger.addHandler(consoleHandler);
|
||||
|
||||
// Configure file handler
|
||||
Handler fileHandler = new FileHandler("src/main/resources/logs/miniCompiler.log");
|
||||
// Toggle file logging on/off
|
||||
fileHandler.setLevel(Level.ALL);
|
||||
fileHandler.setFormatter(new CustomFormatter());
|
||||
logger.addHandler(fileHandler);
|
||||
|
||||
} catch (SecurityException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void logScanner(CommonTokenStream tokenStream) {
|
||||
// Printing the tokens
|
||||
logger.info("-------------------- Scanner -> Tokens --------------------");
|
||||
List<Token> tokens = tokenStream.getTokens();
|
||||
for (Token token : tokens) {
|
||||
String tokenType =
|
||||
SimpleJavaLexer.VOCABULARY.getSymbolicName(token.getType());
|
||||
String tokenText = token.getText();
|
||||
// logger.info("Token Type: " + tokenType + ", Token Text: " + tokenText);
|
||||
logger.info(tokenType + " " + tokenText);
|
||||
}
|
||||
logger.info("\n");
|
||||
}
|
||||
|
||||
public static void logParser(ParseTree parseTree, SimpleJavaParser parser) {
|
||||
// Printing the parse tree
|
||||
logger.info("-------------------- Parser -> Parsetree --------------------");
|
||||
logger.info(parseTree.toStringTree(parser)); //one line representation
|
||||
logTree(parseTree, parser, 0);
|
||||
logger.info("\n");
|
||||
}
|
||||
|
||||
public static void logAST(ASTNode abstractSyntaxTree) {
|
||||
// Printing the AST
|
||||
logger.info("-------------------- AST builder -> AST --------------------");
|
||||
logger.info("Abstract Syntax Tree generated, Startnode:");
|
||||
logAST(abstractSyntaxTree, 0);
|
||||
logger.info("\n");
|
||||
}
|
||||
|
||||
public static void logSemanticAnalyzer(ASTNode typedAst) {
|
||||
// Printing the typed AST
|
||||
logger.info("-------------------- Semantic Analyzer -> typed AST --------------------");
|
||||
// logAST(typedAst, 0);
|
||||
logger.info("Typed Abstract Syntax Tree generated without errors");
|
||||
logger.info("\n");
|
||||
}
|
||||
|
||||
public static void logBytecodeGenerator() {
|
||||
// Printing the bytecode
|
||||
logger.info("-------------------- Bytecode Generator -> Bytecode --------------------");
|
||||
logger.info("Bytecode generated without errors");
|
||||
logger.info("\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------- Printing methods ------------------------- */
|
||||
|
||||
/**
|
||||
* This method is used to print the parse tree in a structured format.
|
||||
* It recursively traverses the tree and prints the rule names and text of the
|
||||
* nodes.
|
||||
*
|
||||
* @param tree The parse tree to be printed.
|
||||
* @param parser The parser used to parse the input. It's used to get the rule
|
||||
* names.
|
||||
* @param indent The current indentation level. It's used to format the output.
|
||||
*/
|
||||
public static void logTree(ParseTree tree, Parser parser, int indent) {
|
||||
// Create an indentation string based on the current indentation level
|
||||
String indentString = " ".repeat(indent * 2);
|
||||
|
||||
// If the tree node is an instance of RuleContext (i.e., it's an internal node),
|
||||
// print the rule name
|
||||
if (tree instanceof RuleContext) {
|
||||
int ruleIndex = ((RuleContext) tree).getRuleIndex();
|
||||
String ruleName = parser.getRuleNames()[ruleIndex];
|
||||
logger.info(indentString + ruleName);
|
||||
} else {
|
||||
// If the tree node is not an instance of RuleContext (i.e., it's a leaf node),
|
||||
// print the text of the node
|
||||
logger.info(indentString + tree.getText());
|
||||
}
|
||||
|
||||
// Recursively print the children of the current node, increasing the
|
||||
// indentation level
|
||||
for (int i = 0; i < tree.getChildCount(); i++) {
|
||||
logTree(tree.getChild(i), parser, indent + 1);
|
||||
}
|
||||
}
|
||||
|
||||
public static void logAST(ASTNode abstractSyntaxTree, int indent) {
|
||||
if (abstractSyntaxTree == null) {
|
||||
logger.severe("AST is null !!!");
|
||||
return;
|
||||
}
|
||||
String indentString = " ".repeat(indent * 2);
|
||||
logger.info(indentString + abstractSyntaxTree.getClass());
|
||||
// for (ASTNode child : abstractSyntaxTree.getChildren()) {
|
||||
// logAST(child, indent + 1);
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
46
src/main/java/parser/astBuilder/ClassVisitor.java
Normal file
46
src/main/java/parser/astBuilder/ClassVisitor.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package parser.astBuilder;
|
||||
|
||||
import ast.*;
|
||||
import ast.member.*;
|
||||
import ast.type.*;
|
||||
import parser.generated.SimpleJavaBaseVisitor;
|
||||
import parser.generated.SimpleJavaParser;
|
||||
|
||||
public class ClassVisitor extends SimpleJavaBaseVisitor<ASTNode> {
|
||||
@Override
|
||||
public ASTNode visitClassDeclaration(SimpleJavaParser.ClassDeclarationContext ctx) {
|
||||
ClassNode classNode = new ClassNode((AccessTypeNode) visit(ctx.accessType()), ctx.IDENTIFIER().getText());
|
||||
classNode.identifier = ctx.IDENTIFIER().getText();
|
||||
for (SimpleJavaParser.MemberDeclarationContext member : ctx.memberDeclaration()) {
|
||||
classNode.addMember((MemberNode) visit(member));
|
||||
}
|
||||
classNode.ensureConstructor();
|
||||
return classNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ASTNode visitFieldDeclaration(SimpleJavaParser.FieldDeclarationContext ctx) {
|
||||
AccessTypeNode accessType = (AccessTypeNode) visit(ctx.accessType());
|
||||
TypeNode type = (TypeNode) visit(ctx.type());
|
||||
String identifier = ctx.IDENTIFIER().getText();
|
||||
return new FieldNode(accessType, type, identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ASTNode visitMethodDeclaration(SimpleJavaParser.MethodDeclarationContext ctx) {
|
||||
return new MethodVisitor().visitMethodDeclaration(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ASTNode visitAccessType(SimpleJavaParser.AccessTypeContext ctx) {
|
||||
String typeStr = ctx.getText();
|
||||
switch (typeStr) {
|
||||
case "public":
|
||||
return new AccessTypeNode(EnumAccessTypeNode.PUBLIC);
|
||||
case "private":
|
||||
return new AccessTypeNode(EnumAccessTypeNode.PRIVATE);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported type: " + typeStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user