瀏覽代碼

first interpreter framework

runningwater 2 年之前
父節點
當前提交
73ff604276

+ 9 - 0
.idea/markdown.xml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="MarkdownSettings">
+    <enabledExtensions>
+      <entry key="MermaidLanguageExtension" value="false" />
+      <entry key="PlantUMLLanguageExtension" value="false" />
+    </enabledExtensions>
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

+ 24 - 0
README.md

@@ -0,0 +1,24 @@
+
+Lox
+```c
+ // Your first Lox program!
+ print "Hello, world!";
+```
+- Dynamic typing
+- Automatic memory management
+- Data Types
+  - Booleans
+  - Numbers
+  - Strings
+  - Nil
+- Expressions
+  - Arithmetic
+  - Comparison and equality
+  - Logical operators
+  - Precedence and grouping
+- Statements
+- Variables
+- Control Flow
+- Functions
+- Closures
+- Classes

二進制
doc/A Map of the Territory.pdf


+ 88 - 0
src/main/java/com/craftinginterpreters/lox/Lox.java

@@ -0,0 +1,88 @@
+/* Copyright (C) 2019-2023 Hangzhou HSH Co. Ltd.
+ * All right reserved.*/
+package com.craftinginterpreters.lox;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+
+/**
+ * @author simon
+ * @date 2023-06-04 15:21
+ * @desc
+ */
+public class Lox {
+    private static boolean hadError = false;
+
+    public static void main(String[] args) throws IOException {
+        if (args.length > 1) {
+            System.out.println("Usage: jlox [script]");
+            System.exit(64);
+        } else if (args.length == 1) {
+            runFile(args[0]);
+        } else {
+            runPrompt();
+        }
+    }
+
+    /**
+     * start jlox from the command line and give it a path to a file,
+     * it reads the file and executes it
+     *
+     * @param path 文件路径
+     */
+    private static void runFile(String path) throws IOException {
+        byte[] bytes = Files.readAllBytes(Path.of(path));
+        run(new String(bytes, Charset.defaultCharset()));
+
+        // Indicate an error in the exit code.
+        if (hadError) System.exit(65);
+    }
+
+    /**
+     * 提示符里面输入
+     */
+    private static void runPrompt() throws IOException {
+        InputStreamReader input = new InputStreamReader(System.in);
+        BufferedReader reader = new BufferedReader(input);
+
+        for (; ; ) {
+            System.out.print("> ");
+            String line = reader.readLine();
+            if (line == null) break;
+            run(line);
+
+            // reset this flag in the interactive loop. If the user makes a mistake,
+            // it shouldn’t kill their entire session.
+            hadError = true;
+        }
+    }
+
+    private static void run(String source) {
+        Scanner scanner = new Scanner(source);
+        List<Token> tokens = scanner.scanTokens();
+
+        for (Token token : tokens) {
+            System.out.println(token);
+        }
+    }
+
+    /**
+     * 错误处理
+     *
+     * @param line    行号
+     * @param message 消息
+     */
+    static void error(int line, String message) {
+        report(line, "", message);
+    }
+
+    private static void report(int line, String where, String message) {
+        System.err.println("[line " + line + " ] Error" + where + ": " + message);
+        hadError = true;
+    }
+}

+ 108 - 0
src/main/java/com/craftinginterpreters/lox/Scanner.java

@@ -0,0 +1,108 @@
+/* Copyright (C) 2019-2023 Hangzhou HSH Co. Ltd.
+ * All right reserved.*/
+package com.craftinginterpreters.lox;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.craftinginterpreters.lox.TokenType.*;
+
+/**
+ * @author simon
+ * @date 2023-06-04 16:30
+ * @desc
+ */
+public class Scanner {
+    private final String source;
+    private final List<Token> tokens = new ArrayList<>();
+    private int start = 0;  //  points to the first character in the lexeme being scanned
+    private int current = 0; // points at the character currently being considered.
+    private int line = 1;
+
+    public Scanner(String source) {
+        this.source = source;
+    }
+
+    public List<Token> scanTokens() {
+        while (!isAtEnd()) {
+            // We are at the beginning of the next lexeme.
+            start = current;
+            scanToken();
+        }
+
+        // add finish token to the end of list
+        tokens.add(new Token(EOF, "", null, line));
+        return tokens;
+    }
+
+    private void scanToken() {
+        char c = advance();
+        switch (c) {
+            case '(' -> addToken(LEFT_PARAM);
+            case ')' -> addToken(RIGHT_PARAM);
+            case '{' -> addToken(LEFT_BRACE);
+            case '}' -> addToken(RIGHT_BRACE);
+            case ',' -> addToken(COMMA);
+            case '.' -> addToken(DOT);
+            case '-' -> addToken(MINUS);
+            case '+' -> addToken(PLUS);
+            case ';' -> addToken(SEMICOLON);
+            case '*' -> addToken(STAR);
+            // 两个字符 != == >= <=
+            case '!' -> addToken(match('=') ? BANG_EQUAL : BANG);
+            case '=' -> addToken(match('=') ? EQUAL_EQUAL : EQUAL);
+            case '<' -> addToken(match('=') ? LESS_EQUAL : LESS);
+            case '>' -> addToken(match('=') ? GRATER_EQUAL : GRATER);
+            case '/' -> {
+                if (match('/')) {
+                    // A comment goes until the end of the line.
+                    while (peek() != '\n' && !isAtEnd()) advance();
+                } else {
+                    addToken(SLASH);
+                }
+            }
+
+            // Ignore whitespace
+            case ' ', '\r', '\t' -> {
+            }
+            case '\n' -> line++;
+
+            default -> Lox.error(line, "Unexpected character: " + c);
+        }
+    }
+
+    private char peek() {
+        if (isAtEnd()) return '\0';
+        return source.charAt(current);
+    }
+
+    private void addToken(TokenType type) {
+        addToken(type, null);
+    }
+
+    private void addToken(TokenType type, Object literal) {
+        String text = source.substring(start, current);
+        tokens.add(new Token(type, text, literal, line));
+    }
+
+    /**
+     * consumes the next character in the source file and returns it
+     *
+     * @return
+     */
+    private char advance() {
+        return source.charAt(current++);
+    }
+
+    private boolean isAtEnd() {
+        return current >= source.length();
+    }
+
+    private boolean match(char expected) {
+        if (isAtEnd()) return false;
+        if (source.charAt(current) != expected) return false;
+
+        current++;
+        return true;
+    }
+}

+ 27 - 0
src/main/java/com/craftinginterpreters/lox/Token.java

@@ -0,0 +1,27 @@
+/* Copyright (C) 2019-2023 Hangzhou HSH Co. Ltd.
+ * All right reserved.*/
+package com.craftinginterpreters.lox;
+
+/**
+ * @author simon
+ * @date 2023-06-04 16:26
+ * @desc
+ */
+class Token {
+    final TokenType type;
+    final String lexeme;
+    final Object literal;
+    final int line;
+
+    Token(TokenType type, String lexeme, Object literal, int line) {
+        this.type = type;
+        this.lexeme = lexeme;
+        this.literal = literal;
+        this.line = line;
+    }
+
+    @Override
+    public String toString() {
+        return type + " " + lexeme + " " + literal;
+    }
+}

+ 29 - 0
src/main/java/com/craftinginterpreters/lox/TokenType.java

@@ -0,0 +1,29 @@
+/* Copyright (C) 2019-2023 Hangzhou HSH Co. Ltd.
+ * All right reserved.*/
+package com.craftinginterpreters.lox;
+
+/**
+ * @author simon
+ * @date 2023-06-04 16:17
+ * @desc
+ */
+public enum TokenType {
+    // single-character tokens.
+    LEFT_PARAM, RIGHT_PARAM, LEFT_BRACE, RIGHT_BRACE,
+    COMMA, DOT, MINUS, PLUS, SEMICOLON, SLASH, STAR,
+
+    // one or two character tokens.
+    BANG, BANG_EQUAL,
+    EQUAL, EQUAL_EQUAL,
+    LESS, LESS_EQUAL,
+    GRATER, GRATER_EQUAL,
+
+    // Literals
+    IDENTIFIER, STRING, NUMBER,
+
+    // keywords
+    AND, CLASS, ELSE, FALSE, FUN, FOR, IF, NIL, OR,
+    PRINT, RETURN, SUPER, THIS, TRUE, VAR, WHILE,
+
+    EOF
+}