summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordibyendumajumdar <mobile@majumdar.org.uk>2023-08-26 15:39:13 +0100
committerdibyendumajumdar <mobile@majumdar.org.uk>2023-08-26 15:39:13 +0100
commit867405ea40d3c8acd93e5e0e6030e8ad96eb2470 (patch)
treeada2570ba653c8c4557713949232f466266ce7f7
parent3b07be6d2c30f7539c5e71964c7a1e4c6790f91f (diff)
downloadSimple-867405ea40d3c8acd93e5e0e6030e8ad96eb2470.tar.gz
Simple-867405ea40d3c8acd93e5e0e6030e8ad96eb2470.zip
Avoid using Node as a type as the IR will need this
So just extends the top level Ast class in all the subtypes. Also avoid holding reference to lexer in parser.
-rw-r--r--chapter01/src/main/java/com/seaofnodes/simple/parser/Ast.java10
-rw-r--r--chapter01/src/main/java/com/seaofnodes/simple/parser/Parser.java239
-rw-r--r--chapter01/src/test/java/com/seaofnodes/simple/lexer/TestParser.java12
3 files changed, 130 insertions, 131 deletions
diff --git a/chapter01/src/main/java/com/seaofnodes/simple/parser/Ast.java b/chapter01/src/main/java/com/seaofnodes/simple/parser/Ast.java
index b11d1ddb..51c7b7ac 100644
--- a/chapter01/src/main/java/com/seaofnodes/simple/parser/Ast.java
+++ b/chapter01/src/main/java/com/seaofnodes/simple/parser/Ast.java
@@ -27,13 +27,11 @@ import java.util.stream.Collectors;
*/
public class Ast {
- private Ast() {
+ protected Ast() {
}
- public interface Node {
- }
- public abstract static class Expr implements Node {
+ public abstract static class Expr extends Ast {
public final Token op;
protected Expr(Token op) {
@@ -116,7 +114,7 @@ public class Ast {
}
}
- public abstract static class Statement implements Node {
+ public abstract static class Statement extends Ast {
}
public static class IfElse extends Statement {
@@ -175,7 +173,7 @@ public class Ast {
}
}
- public static class Type implements Node {
+ public static class Type extends Ast {
public final Token.Id typeId;
public Type(Token.Id typeId) {
diff --git a/chapter01/src/main/java/com/seaofnodes/simple/parser/Parser.java b/chapter01/src/main/java/com/seaofnodes/simple/parser/Parser.java
index 263d0b41..fe224105 100644
--- a/chapter01/src/main/java/com/seaofnodes/simple/parser/Parser.java
+++ b/chapter01/src/main/java/com/seaofnodes/simple/parser/Parser.java
@@ -22,53 +22,54 @@ import com.seaofnodes.simple.lexer.ecstasy.Token;
import com.seaofnodes.simple.lexer.ecstasy.Severity;
public class Parser {
- final Lexer lexer;
- Token look;
+ private Token currentToken;
- public Parser(Lexer lexer) {
- this.lexer = lexer;
+ /**
+ * Parse and return a top level Ast
+ * At present this is an Ast.Block
+ * @see Ast.Block
+ */
+ public Ast parse(Lexer lexer) {
+ nextToken(lexer);
+ return parseProgram(lexer);
}
- private Token nextOrEof() {
+ private Token nextOrEof(Lexer lexer) {
if (lexer.hasNext())
return lexer.next();
- return new Token(look.getStartPosition(), look.getEndPosition(), Token.Id.EOF);
+ return new Token(currentToken.getStartPosition(), currentToken.getEndPosition(), Token.Id.EOF);
}
- private void nextToken() {
- look = nextOrEof();
+ private void nextToken(Lexer lexer) {
+ currentToken = nextOrEof(lexer);
// skip comments
- while (look.isComment()) {
- look = nextOrEof();
+ while (currentToken.isComment()) {
+ currentToken = nextOrEof(lexer);
}
- if (look.isContextSensitive() &&
- look.getId() == Token.Id.IDENTIFIER) {
- look = look.convertToKeyword();
+ if (currentToken.isContextSensitive() &&
+ currentToken.getId() == Token.Id.IDENTIFIER) {
+ currentToken = currentToken.convertToKeyword();
}
}
- private void error(Token t, String errorMessage) {
+ private void error(Lexer lexer, Token t, String errorMessage) {
lexer.log(Severity.ERROR, errorMessage, t.getStartPosition(), t.getEndPosition());
throw new CompilerException(errorMessage + ": " + t.toDebugString());
}
- private void match(Token.Id tag) {
- if (look.getId() == tag) {
- nextToken();
+ private void match(Lexer lexer, Token.Id tag) {
+ if (currentToken.getId() == tag) {
+ nextToken(lexer);
} else {
- error(look, "syntax error, expected " + tag);
+ error(lexer, currentToken, "syntax error, expected " + tag);
}
}
- public Ast.Node parse() {
- nextToken();
- return parseProgram();
- }
- private Ast.Statement parseProgram() {
+ private Ast.Statement parseProgram(Lexer lexer) {
var block = new Ast.Block();
- parseDeclarations(block);
- parseStatements(block);
+ parseDeclarations(lexer, block);
+ parseStatements(lexer, block);
return block;
}
@@ -79,172 +80,172 @@ public class Parser {
};
}
- private void parseDeclarations(Ast.Block block) {
- while (isTypeName(look)) {
- var type = new Ast.Type(look.getId());
- nextToken();
- var tok = look;
- match(Token.Id.IDENTIFIER);
- match(Token.Id.SEMICOLON);
+ private void parseDeclarations(Lexer lexer, Ast.Block block) {
+ while (isTypeName(currentToken)) {
+ var type = new Ast.Type(currentToken.getId());
+ nextToken(lexer);
+ var tok = currentToken;
+ match(lexer, Token.Id.IDENTIFIER);
+ match(lexer, Token.Id.SEMICOLON);
var identifier = new Ast.Identifier(tok);
block.stmtList.add(new Ast.Declare(type, identifier));
}
}
- private void parseStatements(Ast.Block block) {
- while (look.getId() != Token.Id.EOF &&
- look.getId() != Token.Id.R_CURLY) {
- block.stmtList.add(parseStatement());
+ private void parseStatements(Lexer lexer, Ast.Block block) {
+ while (currentToken.getId() != Token.Id.EOF &&
+ currentToken.getId() != Token.Id.R_CURLY) {
+ block.stmtList.add(parseStatement(lexer));
}
}
- private Ast.Statement parseStatement() {
+ private Ast.Statement parseStatement(Lexer lexer) {
Ast.Expr x;
Ast.Statement s1;
Ast.Statement s2;
- switch (look.getId()) {
+ switch (currentToken.getId()) {
case IF -> {
- match(Token.Id.IF);
- match(Token.Id.L_PAREN);
- x = parseBool();
- match(Token.Id.R_PAREN);
- s1 = parseStatement();
- if (look.getId() != Token.Id.ELSE) {
+ match(lexer, Token.Id.IF);
+ match(lexer, Token.Id.L_PAREN);
+ x = parseBool(lexer);
+ match(lexer, Token.Id.R_PAREN);
+ s1 = parseStatement(lexer);
+ if (currentToken.getId() != Token.Id.ELSE) {
return new Ast.IfElse(x, s1, null);
}
- s2 = parseStatement();
+ s2 = parseStatement(lexer);
return new Ast.IfElse(x, s1, s2);
}
case WHILE -> {
- match(Token.Id.WHILE);
- match(Token.Id.L_PAREN);
- x = parseBool();
- match(Token.Id.R_PAREN);
- s1 = parseStatement();
+ match(lexer, Token.Id.WHILE);
+ match(lexer, Token.Id.L_PAREN);
+ x = parseBool(lexer);
+ match(lexer, Token.Id.R_PAREN);
+ s1 = parseStatement(lexer);
return new Ast.While(x, s1);
}
case BREAK -> {
- match(Token.Id.BREAK);
- match(Token.Id.SEMICOLON);
+ match(lexer, Token.Id.BREAK);
+ match(lexer, Token.Id.SEMICOLON);
return new Ast.Break();
}
case L_CURLY -> {
- return parseBlock();
+ return parseBlock(lexer);
}
default -> {
- return parseAssign();
+ return parseAssign(lexer);
}
}
}
- private Ast.Statement parseBlock() {
- match(Token.Id.L_CURLY);
+ private Ast.Statement parseBlock(Lexer lexer) {
+ match(lexer, Token.Id.L_CURLY);
var block = new Ast.Block();
- parseDeclarations(block);
- parseStatements(block);
- match(Token.Id.R_CURLY);
+ parseDeclarations(lexer, block);
+ parseStatements(lexer, block);
+ match(lexer, Token.Id.R_CURLY);
return block;
}
- private Ast.Statement parseAssign() {
- Token tok = look;
- match(Token.Id.IDENTIFIER);
+ private Ast.Statement parseAssign(Lexer lexer) {
+ Token tok = currentToken;
+ match(lexer, Token.Id.IDENTIFIER);
Ast.Identifier identifier = new Ast.Identifier(tok);
- match(Token.Id.ASN);
- var s = new Ast.Assign(identifier, parseBool());
- match(Token.Id.SEMICOLON);
+ match(lexer, Token.Id.ASN);
+ var s = new Ast.Assign(identifier, parseBool(lexer));
+ match(lexer, Token.Id.SEMICOLON);
return s;
}
- private Ast.Expr parseBool() {
- var x = parseAnd();
- while (look.getId() == Token.Id.COND_OR) {
- var tok = look;
- nextToken();
- x = new Ast.Binary(tok, x, parseAnd());
+ private Ast.Expr parseBool(Lexer lexer) {
+ var x = parseAnd(lexer);
+ while (currentToken.getId() == Token.Id.COND_OR) {
+ var tok = currentToken;
+ nextToken(lexer);
+ x = new Ast.Binary(tok, x, parseAnd(lexer));
}
return x;
}
- private Ast.Expr parseAnd() {
- var x = parseRelational();
- while (look.getId() == Token.Id.COND_AND) {
- var tok = look;
- nextToken();
- x = new Ast.Binary(tok, x, parseRelational());
+ private Ast.Expr parseAnd(Lexer lexer) {
+ var x = parseRelational(lexer);
+ while (currentToken.getId() == Token.Id.COND_AND) {
+ var tok = currentToken;
+ nextToken(lexer);
+ x = new Ast.Binary(tok, x, parseRelational(lexer));
}
return x;
}
- private Ast.Expr parseRelational() {
- var x = parseAddition();
- while (look.getId() == Token.Id.COMP_EQ ||
- look.getId() == Token.Id.COMP_NEQ ||
- look.getId() == Token.Id.COMP_LT ||
- look.getId() == Token.Id.COMP_GT ||
- look.getId() == Token.Id.COMP_GTEQ ||
- look.getId() == Token.Id.COMP_LTEQ) {
- var tok = look;
- nextToken();
- x = new Ast.Binary(tok, x, parseAddition());
+ private Ast.Expr parseRelational(Lexer lexer) {
+ var x = parseAddition(lexer);
+ while (currentToken.getId() == Token.Id.COMP_EQ ||
+ currentToken.getId() == Token.Id.COMP_NEQ ||
+ currentToken.getId() == Token.Id.COMP_LT ||
+ currentToken.getId() == Token.Id.COMP_GT ||
+ currentToken.getId() == Token.Id.COMP_GTEQ ||
+ currentToken.getId() == Token.Id.COMP_LTEQ) {
+ var tok = currentToken;
+ nextToken(lexer);
+ x = new Ast.Binary(tok, x, parseAddition(lexer));
}
return x;
}
- private Ast.Expr parseAddition() {
- var x = parseMultiplication();
- while (look.getId() == Token.Id.ADD ||
- look.getId() == Token.Id.SUB) {
- var tok = look;
- nextToken();
- x = new Ast.Binary(tok, x, parseMultiplication());
+ private Ast.Expr parseAddition(Lexer lexer) {
+ var x = parseMultiplication(lexer);
+ while (currentToken.getId() == Token.Id.ADD ||
+ currentToken.getId() == Token.Id.SUB) {
+ var tok = currentToken;
+ nextToken(lexer);
+ x = new Ast.Binary(tok, x, parseMultiplication(lexer));
}
return x;
}
- private Ast.Expr parseMultiplication() {
- var x = parseUnary();
- while (look.getId() == Token.Id.MUL ||
- look.getId() == Token.Id.DIV) {
- var tok = look;
- nextToken();
- x = new Ast.Binary(tok, x, parseUnary());
+ private Ast.Expr parseMultiplication(Lexer lexer) {
+ var x = parseUnary(lexer);
+ while (currentToken.getId() == Token.Id.MUL ||
+ currentToken.getId() == Token.Id.DIV) {
+ var tok = currentToken;
+ nextToken(lexer);
+ x = new Ast.Binary(tok, x, parseUnary(lexer));
}
return x;
}
- private Ast.Expr parseUnary() {
- if (look.getId() == Token.Id.SUB ||
- look.getId() == Token.Id.NOT) {
- var tok = look;
- nextToken();
- return new Ast.Unary(tok, parseUnary());
+ private Ast.Expr parseUnary(Lexer lexer) {
+ if (currentToken.getId() == Token.Id.SUB ||
+ currentToken.getId() == Token.Id.NOT) {
+ var tok = currentToken;
+ nextToken(lexer);
+ return new Ast.Unary(tok, parseUnary(lexer));
} else {
- return parsePrimary();
+ return parsePrimary(lexer);
}
}
- private Ast.Expr parsePrimary() {
- switch (look.getId()) {
+ private Ast.Expr parsePrimary(Lexer lexer) {
+ switch (currentToken.getId()) {
case L_PAREN -> {
- nextToken();
- var x = parseBool();
- match(Token.Id.R_PAREN);
+ nextToken(lexer);
+ var x = parseBool(lexer);
+ match(lexer, Token.Id.R_PAREN);
return x;
}
case LIT_INT -> {
- var x = new Ast.Constant(look);
- nextToken();
+ var x = new Ast.Constant(currentToken);
+ nextToken(lexer);
return x;
}
case IDENTIFIER -> {
- var x = new Ast.Symbol(look);
- nextToken();
+ var x = new Ast.Symbol(currentToken);
+ nextToken(lexer);
return x;
}
default -> {
- error(look, "syntax error, expected nested expr, integer value or variable");
+ error(lexer, currentToken, "syntax error, expected nested expr, integer value or variable");
return null;
}
}
diff --git a/chapter01/src/test/java/com/seaofnodes/simple/lexer/TestParser.java b/chapter01/src/test/java/com/seaofnodes/simple/lexer/TestParser.java
index 80917c0f..3f65e0f9 100644
--- a/chapter01/src/test/java/com/seaofnodes/simple/lexer/TestParser.java
+++ b/chapter01/src/test/java/com/seaofnodes/simple/lexer/TestParser.java
@@ -29,8 +29,8 @@ public class TestParser {
{
final String source = "int i;";
Lexer lexer = new Lexer(new Source(source), new ErrorListener());
- Parser parser = new Parser(lexer);
- var ast = parser.parse();
+ Parser parser = new Parser();
+ var ast = parser.parse(lexer);
Assert.assertEquals("{int i;}", ast.toString());
}
@@ -38,8 +38,8 @@ public class TestParser {
public void testParseTwoDecls() {
final String source = "int i;\nint j;";
Lexer lexer = new Lexer(new Source(source), new ErrorListener());
- Parser parser = new Parser(lexer);
- var ast = parser.parse();
+ Parser parser = new Parser();
+ var ast = parser.parse(lexer);
Assert.assertEquals("{int i;int j;}", ast.toString());
}
@@ -59,8 +59,8 @@ public class TestParser {
}
""";
Lexer lexer = new Lexer(new Source(source), new ErrorListener());
- Parser parser = new Parser(lexer);
- var ast = parser.parse();
+ Parser parser = new Parser();
+ var ast = parser.parse(lexer);
Assert.assertEquals("{int i;int j;i=0;j=100;while(1) {i=(i+1);j=(j-1);if((i>=j)) break;}}", ast.toString());
}
}