diff options
Diffstat (limited to 'chapter01/src/main/java')
5 files changed, 0 insertions, 714 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 deleted file mode 100644 index 4e456416..00000000 --- a/chapter01/src/main/java/com/seaofnodes/simple/parser/AST.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * DO NOT REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * <p> - * Contributor(s): - * <p> - * The Initial Developer of the Original Software is Dibyendu Majumdar. - * <p> - * This file is part of the Sea Of Nodes Simple Programming language - * implementation. See https://github.com/SeaOfNodes/Simple - * <p> - * The contents of this file are subject to the terms of the - * Apache License Version 2 (the "APL"). You may not use this - * file except in compliance with the License. A copy of the - * APL may be obtained from: - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.seaofnodes.simple.parser; - -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Collectors; - -/** - * A simple AST definition. - */ -public class AST { - - protected AST() { - } - - - public abstract static class Expr extends AST { - public final Token op; - - protected Expr(Token op) { - this.op = op; - } - } - - /** - * A name in the language - */ - public static class Identifier extends Expr { - public final String name; - - public Identifier(Token op) { - super(op); - name = op.str; - } - - @Override - public String toString() { - return name; - } - } - - /** - * Reference to a name in the language - */ - public static class Symbol extends Expr { - public final String name; - - public Symbol(Token op) { - super(op); - name = op.str; - } - - @Override - public String toString() { - return name; - } - } - - public static class Binary extends Expr { - public final Expr expr1; - public final Expr expr2; - - public Binary(Token op, Expr expr1, Expr expr2) { - super(op); - this.expr1 = expr1; - this.expr2 = expr2; - } - - @Override - public String toString() { - return "(" + expr1 + op.toString() + expr2 + ")"; - } - } - - public static class Unary extends Expr { - public final Expr expr; - - public Unary(Token op, Expr expr) { - super(op); - this.expr = expr; - } - - @Override - public String toString() { - return "(" + op.toString() + "(" + expr + "))"; - } - } - - public static class Constant extends Expr { - public Constant(Token op) { - super(op); - } - - @Override - public String toString() { - return op.toString(); - } - } - - public abstract static class Statement extends AST { - } - - public static class IfElse extends Statement { - public final Expr expr; - public final Statement ifStmt; - public final Statement elseStmt; - - public IfElse(Expr expr, Statement ifStmt, Statement elseStmt) { - this.expr = expr; - this.ifStmt = ifStmt; - this.elseStmt = elseStmt; - } - - @Override - public String toString() { - if (elseStmt != null) - return "if(" + expr + ") " + ifStmt + " else " + elseStmt; - return "if(" + expr + ") " + ifStmt; - } - } - - public static class While extends Statement { - public final Expr expr; - public final Statement stmt; - - public While(Expr expr, Statement stmt) { - this.expr = expr; - this.stmt = stmt; - } - - @Override - public String toString() { - return "while(" + expr.toString() + ") " + stmt; - } - } - - public static class Break extends Statement { - @Override - public String toString() { - return "break;"; - } - } - - public static class Assign extends Statement { - public final Identifier identifier; - public final Expr expr; - - public Assign(Identifier identifier, Expr expr) { - this.identifier = identifier; - this.expr = expr; - } - - @Override - public String toString() { - return identifier.toString() + "=" + expr.toString() + ";"; - } - } - - public static class Type extends AST { - public final String typeId; - - public Type(String typeId) { - this.typeId = typeId; - } - - @Override - public String toString() { - return typeId; - } - } - - public static class Declare extends Statement { - public final Type type; - public final Identifier identifier; - - public Declare(Type type, Identifier identifier) { - this.type = type; - this.identifier = identifier; - } - - @Override - public String toString() { - return type.toString() + " " + identifier.toString() + ";"; - } - } - - public static class Block extends Statement { - public final List<Statement> stmtList = new ArrayList<>(); - - @Override - public String toString() { - return "{" + - stmtList.stream().map(Object::toString).collect(Collectors.joining()) + "}"; - } - } -} diff --git a/chapter01/src/main/java/com/seaofnodes/simple/parser/CompilerException.java b/chapter01/src/main/java/com/seaofnodes/simple/parser/CompilerException.java deleted file mode 100644 index a62fa034..00000000 --- a/chapter01/src/main/java/com/seaofnodes/simple/parser/CompilerException.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * DO NOT REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * <p> - * Contributor(s): - * <p> - * The Initial Developer of the Original Software is Dibyendu Majumdar. - * <p> - * This file is part of the Sea Of Nodes Simple Programming language - * implementation. See https://github.com/SeaOfNodes/Simple - * <p> - * The contents of this file are subject to the terms of the - * Apache License Version 2 (the "APL"). You may not use this - * file except in compliance with the License. A copy of the - * APL may be obtained from: - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.seaofnodes.simple.parser; - -public class CompilerException extends RuntimeException { - public CompilerException(String message) { - super(message); - } - - public CompilerException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/chapter01/src/main/java/com/seaofnodes/simple/parser/Lexer.java b/chapter01/src/main/java/com/seaofnodes/simple/parser/Lexer.java deleted file mode 100644 index fbe8c239..00000000 --- a/chapter01/src/main/java/com/seaofnodes/simple/parser/Lexer.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * DO NOT REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * <p> - * Contributor(s): - * <p> - * The Initial Developer of the Original Software is Dibyendu Majumdar. - * <p> - * This file is part of the Sea Of Nodes Simple Programming language - * implementation. See https://github.com/SeaOfNodes/Simple - * <p> - * The contents of this file are subject to the terms of the - * Apache License Version 2 (the "APL"). You may not use this - * file except in compliance with the License. A copy of the - * APL may be obtained from: - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.seaofnodes.simple.parser; - -import java.text.NumberFormat; -import java.text.ParseException; - -public class Lexer { - - private final char[] input; - /** - * Tracks current position in input buffer - */ - private int position = 0; - private char peek = ' '; - - private final NumberFormat numberFormat; - - public Lexer(String source) { - input = source.toCharArray(); - numberFormat = NumberFormat.getInstance(); - numberFormat.setGroupingUsed(false); - } - - private boolean isEOF() { - return position >= input.length; - } - - private char advance() { - if (isEOF()) - return 0; // Special value that causes parsing to terminate - return input[position++]; - } - - private boolean readch() { - peek = advance(); - return true; - } - - private boolean readch(char c) { - if (readch() && peek != c) - return false; - peek = ' '; - return true; - } - - /** - * Note that EOF is not whitespace! - */ - private boolean isWhiteSpace(char c) { - return c == ' ' || - c == '\t' || - c == '\n' || - c == '\r'; - } - - private void skipWhitespace() { - while (isWhiteSpace(peek)) - readch(); - } - - /** - * Parses number in format nnn[.nnn] - * where n is a digit - */ - private Token parseNumber() { - assert Character.isDigit(peek); - StringBuilder sb = new StringBuilder(); - sb.append(peek); - while (readch() && Character.isDigit(peek)) - sb.append(peek); - if (peek == '.') { - sb.append(peek); - while (readch() && Character.isDigit(peek)) - sb.append(peek); - } - String str = sb.toString(); - Number number = parseNumber(str); - return Token.newNum(number, str); - } - - private Number parseNumber(String str) { - try { - return numberFormat.parse(str); - } catch (ParseException e) { - throw new CompilerException("Failed to parse number " + str, e); - } - } - - private boolean isIdentifierStart(char ch) { - return Character.isAlphabetic(ch) || ch == '_'; - } - - private boolean isIdentifierLetter(char ch) { - return Character.isLetterOrDigit(ch) || ch == '_'; - } - - private Token parseIdentifier() { - assert isIdentifierStart(peek); - StringBuilder sb = new StringBuilder(); - sb.append(peek); - while (readch() && isIdentifierLetter(peek)) - sb.append(peek); - return Token.newIdent(sb.toString()); - } - - public Token scan() { - skipWhitespace(); - switch (peek) { - case 0: - return Token.EOF; - case '&': - return readch('&') ? Token.newPunct("&&") : Token.newPunct("&"); - case '|': - return readch('|') ? Token.newPunct("||") : Token.newPunct("|"); - case '=': - return readch('=') ? Token.newPunct("==") : Token.newPunct("="); - case '<': - return readch('=') ? Token.newPunct("<=") : Token.newPunct("<"); - case '>': - return readch('=') ? Token.newPunct(">=") : Token.newPunct(">"); - default: { - return scanOthers(); - } - } - } - - private Token scanOthers() { - if (Character.isDigit(peek)) - return parseNumber(); - else if (isIdentifierLetter(peek)) - return parseIdentifier(); - Token token = Token.newPunct(Character.toString(peek)); - peek = ' '; - return token; - } -} diff --git a/chapter01/src/main/java/com/seaofnodes/simple/parser/Parser.java b/chapter01/src/main/java/com/seaofnodes/simple/parser/Parser.java deleted file mode 100644 index d8f80090..00000000 --- a/chapter01/src/main/java/com/seaofnodes/simple/parser/Parser.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * DO NOT REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Contributor(s): - * - * The Initial Developer of the Original Software is Dibyendu Majumdar. - * - * This file is part of the Sea Of Nodes Simple Programming language - * implementation. See https://github.com/SeaOfNodes/Simple - * - * The contents of this file are subject to the terms of the - * Apache License Version 2 (the "APL"). You may not use this - * file except in compliance with the License. A copy of the - * APL may be obtained from: - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.seaofnodes.simple.parser; - -public class Parser { - private Token currentToken; - - /** - * 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 void nextToken(Lexer lexer) { - currentToken = lexer.scan(); - } - - private void error(Token t, String errorMessage) { - throw new CompilerException(errorMessage + ": " + t.toString()); - } - - private void matchKind(Lexer lexer, Token.Kind kind) { - if (currentToken.kind == kind) { - nextToken(lexer); - } else { - error(currentToken, "syntax error, expected " + kind); - } - } - - private void matchPunctuation(Lexer lexer, String value) { - if (currentToken.kind == Token.Kind.PUNCT && isToken(currentToken, value)) { - nextToken(lexer); - } else { - error(currentToken, "syntax error, expected " + value + " got " + currentToken.str); - } - } - - private void matchIdentifier(Lexer lexer, String identifier) { - if (currentToken.kind == Token.Kind.IDENT && isToken(currentToken, identifier)) { - nextToken(lexer); - } else { - error(currentToken, "syntax error, expected " + identifier); - } - } - - private boolean isToken(Token token, String value) { - return token.str.equals(value); - } - - private AST.Statement parseProgram(Lexer lexer) { - var block = new AST.Block(); - parseDeclarations(lexer, block); - parseStatements(lexer, block); - return block; - } - - private boolean isTypeName(Token tok) { - return tok.kind == Token.Kind.IDENT && - (isToken(tok, "int") || - isToken(tok, "char") || - isToken(tok, "float")); - } - - private void parseDeclarations(Lexer lexer, AST.Block block) { - while (isTypeName(currentToken)) { - var type = new AST.Type(currentToken.str); - nextToken(lexer); - var tok = currentToken; - matchKind(lexer, Token.Kind.IDENT); - matchPunctuation(lexer, ";"); - var identifier = new AST.Identifier(tok); - block.stmtList.add(new AST.Declare(type, identifier)); - } - } - - private boolean isEOF(Token tok) { - return tok.kind == Token.Kind.EOZ; - } - - private boolean isPunct(Token tok, String str) { - return tok.kind == Token.Kind.PUNCT && isToken(tok, str); - } - - private void parseStatements(Lexer lexer, AST.Block block) { - while (!isEOF(currentToken) && !isPunct(currentToken, "}")) { - block.stmtList.add(parseStatement(lexer)); - } - } - - private AST.Statement parseStatement(Lexer lexer) { - AST.Expr x; - AST.Statement s1; - AST.Statement s2; - - switch (currentToken.str) { - case "if" -> { - matchIdentifier(lexer, "if"); - matchPunctuation(lexer, "("); - x = parseBool(lexer); - matchPunctuation(lexer, ")"); - s1 = parseStatement(lexer); - if (!isToken(currentToken, "else")) { - return new AST.IfElse(x, s1, null); - } - s2 = parseStatement(lexer); - return new AST.IfElse(x, s1, s2); - } - case "while" -> { - matchIdentifier(lexer, "while"); - matchPunctuation(lexer, "("); - x = parseBool(lexer); - matchPunctuation(lexer, ")"); - s1 = parseStatement(lexer); - return new AST.While(x, s1); - } - case "break" -> { - matchIdentifier(lexer, "break"); - matchPunctuation(lexer, ";"); - return new AST.Break(); - } - case "{" -> { - return parseBlock(lexer); - } - default -> { - return parseAssign(lexer); - } - } - } - - private AST.Statement parseBlock(Lexer lexer) { - matchPunctuation(lexer, "{"); - var block = new AST.Block(); - parseDeclarations(lexer, block); - parseStatements(lexer, block); - matchPunctuation(lexer, "}"); - return block; - } - - private AST.Statement parseAssign(Lexer lexer) { - Token tok = currentToken; - matchKind(lexer, Token.Kind.IDENT); - AST.Identifier identifier = new AST.Identifier(tok); - matchPunctuation(lexer, "="); - var s = new AST.Assign(identifier, parseBool(lexer)); - matchPunctuation(lexer, ";"); - return s; - } - - private AST.Expr parseBool(Lexer lexer) { - var x = parseAnd(lexer); - while (isToken(currentToken, "||")) { - var tok = currentToken; - nextToken(lexer); - x = new AST.Binary(tok, x, parseAnd(lexer)); - } - return x; - } - - private AST.Expr parseAnd(Lexer lexer) { - var x = parseRelational(lexer); - while (isToken(currentToken, "&&")) { - var tok = currentToken; - nextToken(lexer); - x = new AST.Binary(tok, x, parseRelational(lexer)); - } - return x; - } - - private AST.Expr parseRelational(Lexer lexer) { - var x = parseAddition(lexer); - while (isToken(currentToken, "==") || - isToken(currentToken, "!=") || - isToken(currentToken, "<=") || - isToken(currentToken, "<") || - isToken(currentToken, ">") || - isToken(currentToken, ">=")) { - var tok = currentToken; - nextToken(lexer); - x = new AST.Binary(tok, x, parseAddition(lexer)); - } - return x; - } - - private AST.Expr parseAddition(Lexer lexer) { - var x = parseMultiplication(lexer); - while (isToken(currentToken, "-") || - isToken(currentToken, "+")) { - var tok = currentToken; - nextToken(lexer); - x = new AST.Binary(tok, x, parseMultiplication(lexer)); - } - return x; - } - - private AST.Expr parseMultiplication(Lexer lexer) { - var x = parseUnary(lexer); - while (isToken(currentToken, "*") || - isToken(currentToken, "/")) { - var tok = currentToken; - nextToken(lexer); - x = new AST.Binary(tok, x, parseUnary(lexer)); - } - return x; - } - - private AST.Expr parseUnary(Lexer lexer) { - if (isToken(currentToken, "-") || - isToken(currentToken, "!")) { - var tok = currentToken; - nextToken(lexer); - return new AST.Unary(tok, parseUnary(lexer)); - } else { - return parsePrimary(lexer); - } - } - - private AST.Expr parsePrimary(Lexer lexer) { - switch (currentToken.kind) { - case PUNCT -> { - /* Nested expression */ - matchPunctuation(lexer, "("); - nextToken(lexer); - var x = parseBool(lexer); - matchPunctuation(lexer, ")"); - return x; - } - case NUM -> { - var x = new AST.Constant(currentToken); - nextToken(lexer); - return x; - } - case IDENT -> { - var x = new AST.Symbol(currentToken); - nextToken(lexer); - return x; - } - default -> { - error(currentToken, "syntax error, expected nested expr, integer value or variable"); - return null; - } - } - } -} diff --git a/chapter01/src/main/java/com/seaofnodes/simple/parser/Token.java b/chapter01/src/main/java/com/seaofnodes/simple/parser/Token.java deleted file mode 100644 index d45bef5a..00000000 --- a/chapter01/src/main/java/com/seaofnodes/simple/parser/Token.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * DO NOT REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * <p> - * Contributor(s): - * <p> - * The Initial Developer of the Original Software is Dibyendu Majumdar. - * <p> - * This file is part of the Sea Of Nodes Simple Programming language - * implementation. See https://github.com/SeaOfNodes/Simple - * <p> - * The contents of this file are subject to the terms of the - * Apache License Version 2 (the "APL"). You may not use this - * file except in compliance with the License. A copy of the - * APL may be obtained from: - * http://www.apache.org/licenses/LICENSE-2.0 - */ -package com.seaofnodes.simple.parser; - -public class Token { - - enum Kind { - IDENT, - NUM, - PUNCT, - EOZ // Special kind to signal end of file - } - - public final Kind kind; - /** - * String representation of a token - always - * populated - */ - public final String str; - /** - * The parsed number value, only populated for Kind.NUM - */ - public final Number num; - - public Token(Kind kind, String str, Number num) { - this.kind = kind; - this.str = str; - this.num = num; - } - - public static Token newIdent(String str) { - return new Token(Kind.IDENT, str.intern(), null); - } - public static Token newNum(Number num, String str) { - return new Token(Kind.NUM, str, num); - } - public static Token newPunct(String str) { - return new Token(Kind.PUNCT, str.intern(), null); - } - - /** - * Special token that indicates that source has been exhausted - */ - public static Token EOF = new Token(Kind.EOZ, "", null); - - public String toString() { - return str; - } -} |
