summaryrefslogtreecommitdiff
path: root/src/main/java
diff options
context:
space:
mode:
authorElias Haugsbakk <[email protected]>2026-09-18 23:10:31 +0200
committerElias Haugsbakk <[email protected]>2026-09-19 01:59:23 +0200
commit1ef6f0e6b9083748e5b91743f15f10f09c6b8432 (patch)
tree66a0144ae1ffb8f42b915551021ef5e30f64fe2a /src/main/java
parentdf845a788a831c169a0725f49f96cae0a896ad64 (diff)
Implement parser creating AST
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/Main.java17
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/AST.java7
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/Parser.java79
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/ParserException.java7
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/node/ASTNode.java7
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/node/Program.java16
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/Expression.java17
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/FunctionCall.java16
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/StringLiteral.java12
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/ExpressionStatement.java10
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/Statement.java15
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/tokenization/Lexer.java2
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/tokenization/Token.java13
-rw-r--r--src/main/java/no/eliashaugsbakk/kompilator/tokenization/TokenType.java2
14 files changed, 206 insertions, 14 deletions
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/Main.java b/src/main/java/no/eliashaugsbakk/kompilator/Main.java
index aad3753..fa7f79c 100644
--- a/src/main/java/no/eliashaugsbakk/kompilator/Main.java
+++ b/src/main/java/no/eliashaugsbakk/kompilator/Main.java
@@ -6,6 +6,11 @@ import no.eliashaugsbakk.kompilator.IO.FileReaderWriter;
import no.eliashaugsbakk.kompilator.IO.FileReaderWriterException;
import no.eliashaugsbakk.kompilator.asmGeneration.AssemblyBuilder;
import no.eliashaugsbakk.kompilator.assembleAndLink.AssemblerAndLinker;
+import no.eliashaugsbakk.kompilator.parsing.AST;
+import no.eliashaugsbakk.kompilator.parsing.Parser;
+import no.eliashaugsbakk.kompilator.parsing.ParserException;
+import no.eliashaugsbakk.kompilator.tokenization.Lexer;
+import no.eliashaugsbakk.kompilator.tokenization.Token;
public class Main {
public static final String programFileExtension = "spå";
@@ -33,6 +38,18 @@ public class Main {
System.exit(1);
}
+ List<Token> tokens = new Lexer(inputProgram.fileBody()).tokenize();
+ AST ast = null;
+ try {
+ ast = new Parser(tokens).parse();
+ } catch (ParserException e) {
+ IO.println("Error while parsing: " + e.getMessage());
+ }
+
+ // TODO:
+ // new Analyzer(ast).analyze();
+ // List<String> IR = new IRGenerator(ast).generate();
+
List<String> IR = List.of();
String assembly = new AssemblyBuilder().createAssembly(IR);
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/AST.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/AST.java
index 3f54e3c..95ec77c 100644
--- a/src/main/java/no/eliashaugsbakk/kompilator/parsing/AST.java
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/AST.java
@@ -1,4 +1,11 @@
package no.eliashaugsbakk.kompilator.parsing;
+import no.eliashaugsbakk.kompilator.parsing.node.ASTNode;
+
public class AST {
+ ASTNode root;
+
+ AST(ASTNode root) {
+ this.root = root;
+ }
}
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/Parser.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/Parser.java
index a41a1bf..53af71c 100644
--- a/src/main/java/no/eliashaugsbakk/kompilator/parsing/Parser.java
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/Parser.java
@@ -1,4 +1,83 @@
package no.eliashaugsbakk.kompilator.parsing;
+import static no.eliashaugsbakk.kompilator.tokenization.TokenType.EOF;
+import static no.eliashaugsbakk.kompilator.tokenization.TokenType.KEYWORD;
+import static no.eliashaugsbakk.kompilator.tokenization.TokenType.LPAREN;
+import static no.eliashaugsbakk.kompilator.tokenization.TokenType.RPAREN;
+import static no.eliashaugsbakk.kompilator.tokenization.TokenType.SEMICOLON;
+import static no.eliashaugsbakk.kompilator.tokenization.TokenType.STRING;
+
+import java.util.ArrayList;
+import java.util.List;
+import no.eliashaugsbakk.kompilator.parsing.node.Program;
+import no.eliashaugsbakk.kompilator.parsing.node.expression.Expression;
+import no.eliashaugsbakk.kompilator.parsing.node.expression.FunctionCall;
+import no.eliashaugsbakk.kompilator.parsing.node.expression.StringLiteral;
+import no.eliashaugsbakk.kompilator.parsing.node.statement.ExpressionStatement;
+import no.eliashaugsbakk.kompilator.tokenization.Token;
+
public class Parser {
+ private final List<Token> tokens;
+ private int position = 0;
+
+ public Parser(List<Token> tokens) {
+ this.tokens = tokens;
+ }
+
+ public AST parse() throws ParserException {
+ Program rootNode = new Program();
+
+ while (position < tokens.size()) {
+ Token token = tokens.get(position);
+
+ if (token.type() == KEYWORD) {
+ String functionName = token.value();
+ position++;
+
+ List<Expression> arguments = parseArguments();
+
+ FunctionCall functionCall = new FunctionCall(functionName, arguments);
+ rootNode.addStatement(new ExpressionStatement(functionCall));
+ } else if (token.type() == EOF) {
+ break;
+ } else {
+ IO.println("Unknown token: " + token.value() + ". Skipping...");
+ position++;
+ }
+ }
+
+ return new AST(rootNode);
+ }
+
+ List<Expression> parseArguments() throws ParserException {
+ List<Expression> arguments = new ArrayList<>();
+
+ if (position >= tokens.size() || tokens.get(position).type() != LPAREN) {
+ throw new ParserException(tokens.get(position).line(), tokens.get(position).colum(),
+ "Unexpected token:" + tokens.get(position).value() + "\n Expected: (");
+ }
+ position++;
+
+ while (position < tokens.size() && tokens.get(position).type() != RPAREN) {
+ if (tokens.get(position).type() == STRING) {
+ arguments.add(new StringLiteral(tokens.get(position).value()));
+ }
+ position++;
+ }
+
+ if (position >= tokens.size()) {
+ throw new ParserException(-1, -1, "Unexpected end of file, expected )");
+ }
+ position++;
+
+ if (position >= tokens.size() || tokens.get(position).type() != SEMICOLON) {
+ throw new ParserException(position < tokens.size() ? tokens.get(position).line() : -1,
+ position < tokens.size() ? tokens.get(position).colum() : -1,
+ "Unexpected token: " + (position < tokens.size() ? tokens.get(position).value() : "EOF") +
+ "\n" + "Expected: ;");
+ }
+ position++;
+
+ return arguments;
+ }
}
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/ParserException.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/ParserException.java
new file mode 100644
index 0000000..ac96a5c
--- /dev/null
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/ParserException.java
@@ -0,0 +1,7 @@
+package no.eliashaugsbakk.kompilator.parsing;
+
+public class ParserException extends Exception {
+ public ParserException(int line, int column, String message) {
+ super(line + ":" + column + ", " + message);
+ }
+}
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/ASTNode.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/ASTNode.java
new file mode 100644
index 0000000..1eb201c
--- /dev/null
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/ASTNode.java
@@ -0,0 +1,7 @@
+package no.eliashaugsbakk.kompilator.parsing.node;
+
+/**
+ * Base class for all nodes in the Abstract Syntax Tree.
+ */
+public abstract class ASTNode {
+}
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/Program.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/Program.java
new file mode 100644
index 0000000..0c7cd32
--- /dev/null
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/Program.java
@@ -0,0 +1,16 @@
+package no.eliashaugsbakk.kompilator.parsing.node;
+
+import java.util.ArrayList;
+import java.util.List;
+import no.eliashaugsbakk.kompilator.parsing.node.statement.Statement;
+
+/**
+ * Root node of the AST. Contains all top-level statements.
+ */
+public class Program extends ASTNode {
+ public List<Statement> statements = new ArrayList<>();
+
+ public void addStatement(Statement statement) {
+ this.statements.add(statement);
+ }
+}
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/Expression.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/Expression.java
new file mode 100644
index 0000000..6ca58b2
--- /dev/null
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/Expression.java
@@ -0,0 +1,17 @@
+package no.eliashaugsbakk.kompilator.parsing.node.expression;
+
+import no.eliashaugsbakk.kompilator.parsing.node.ASTNode;
+
+/**
+ * Base class for all expression nodes.
+ * An expression is a piece of code that evaluates to a value.
+ * Expressions cannot stand alone as statements; they must be used within statements.
+ * <p>
+ * Examples:
+ * - "Hello" (string literal expression)
+ * - 42 (number literal expression)
+ * - x + 5 (binary operation expression)
+ * - myFunction() (function call expression)
+ */
+public abstract class Expression extends ASTNode {
+}
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/FunctionCall.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/FunctionCall.java
new file mode 100644
index 0000000..3c46ec4
--- /dev/null
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/FunctionCall.java
@@ -0,0 +1,16 @@
+package no.eliashaugsbakk.kompilator.parsing.node.expression;
+
+import java.util.List;
+
+/**
+ * Represents a function call statement (e.g., print("Hello, world")).
+ */
+public class FunctionCall extends Expression {
+ public String functionName;
+ public List<Expression> arguments;
+
+ public FunctionCall(String functionName, List<Expression> arguments) {
+ this.functionName = functionName;
+ this.arguments = arguments;
+ }
+}
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/StringLiteral.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/StringLiteral.java
new file mode 100644
index 0000000..67ce405
--- /dev/null
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/expression/StringLiteral.java
@@ -0,0 +1,12 @@
+package no.eliashaugsbakk.kompilator.parsing.node.expression;
+
+/**
+ * Represents a string literal expression (e.g., "Hello, World").
+ */
+public class StringLiteral extends Expression {
+ public final String value;
+
+ public StringLiteral(String value) {
+ this.value = value;
+ }
+}
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/ExpressionStatement.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/ExpressionStatement.java
new file mode 100644
index 0000000..64bc0a8
--- /dev/null
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/ExpressionStatement.java
@@ -0,0 +1,10 @@
+package no.eliashaugsbakk.kompilator.parsing.node.statement;
+
+import no.eliashaugsbakk.kompilator.parsing.node.expression.Expression;
+
+public class ExpressionStatement extends Statement {
+ public Expression expression;
+ public ExpressionStatement(Expression expression) {
+ this.expression = expression;
+ }
+}
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/Statement.java b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/Statement.java
new file mode 100644
index 0000000..fc52f9a
--- /dev/null
+++ b/src/main/java/no/eliashaugsbakk/kompilator/parsing/node/statement/Statement.java
@@ -0,0 +1,15 @@
+package no.eliashaugsbakk.kompilator.parsing.node.statement;
+
+import no.eliashaugsbakk.kompilator.parsing.node.ASTNode;
+
+/**
+ * Base class for all statement nodes.
+ * A statement is a top-level line of code that performs an action.
+ * <p>
+ * Examples:
+ * - print("Hello"); (function call statement)
+ * - var x: int = 5; (variable declaration statement)
+ * - if (x > 0) { } (conditional statement)
+ */
+public abstract class Statement extends ASTNode {
+}
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/tokenization/Lexer.java b/src/main/java/no/eliashaugsbakk/kompilator/tokenization/Lexer.java
index 4149b4f..62d2359 100644
--- a/src/main/java/no/eliashaugsbakk/kompilator/tokenization/Lexer.java
+++ b/src/main/java/no/eliashaugsbakk/kompilator/tokenization/Lexer.java
@@ -30,7 +30,7 @@ public class Lexer {
this.input = input;
}
- List<Token> tokenize() {
+ public List<Token> tokenize() {
while (position < input.length()) {
char current = input.charAt(position);
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/tokenization/Token.java b/src/main/java/no/eliashaugsbakk/kompilator/tokenization/Token.java
index 519b6b6..09c5d83 100644
--- a/src/main/java/no/eliashaugsbakk/kompilator/tokenization/Token.java
+++ b/src/main/java/no/eliashaugsbakk/kompilator/tokenization/Token.java
@@ -1,15 +1,4 @@
package no.eliashaugsbakk.kompilator.tokenization;
-class Token {
- TokenType type;
- String value;
- int line;
- int colum;
-
- Token(TokenType type, String value, int line, int colum) {
- this.type = type;
- this.value = value;
- this.line = line;
- this.colum = colum;
- }
+public record Token(TokenType type, String value, int line, int colum) {
}
diff --git a/src/main/java/no/eliashaugsbakk/kompilator/tokenization/TokenType.java b/src/main/java/no/eliashaugsbakk/kompilator/tokenization/TokenType.java
index 408abb2..696b46c 100644
--- a/src/main/java/no/eliashaugsbakk/kompilator/tokenization/TokenType.java
+++ b/src/main/java/no/eliashaugsbakk/kompilator/tokenization/TokenType.java
@@ -1,6 +1,6 @@
package no.eliashaugsbakk.kompilator.tokenization;
-enum TokenType {
+public enum TokenType {
KEYWORD, // print, var, if, while, function, etc.
IDENTIFIER, // variable_1
STRING, // "Hello, World!"