实现AST

This commit is contained in:
Luke 2025-04-22 21:45:05 +08:00
parent 2b7a2b86b8
commit 8d1b180c2d
51 changed files with 1743 additions and 10 deletions

View File

@ -0,0 +1,60 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/JsonFormatter.java
package org.jcnc.snow.compiler;
public class JsonFormatter {
/**
* 对一个紧凑的 JSON 字符串进行缩进美化
* @param json 紧凑的 JSON
* @return 带换行和缩进的 JSON
*/
public static String prettyPrint(String json) {
StringBuilder sb = new StringBuilder();
int indent = 0;
boolean inQuotes = false;
for (int i = 0; i < json.length(); i++) {
char c = json.charAt(i);
// 切换引号状态忽略转义的 \"
if (c == '"' && (i == 0 || json.charAt(i - 1) != '\\')) {
inQuotes = !inQuotes;
sb.append(c);
} else if (!inQuotes) {
switch (c) {
case '{', '[':
sb.append(c)
.append('\n');
indent++;
appendIndent(sb, indent);
break;
case '}', ']':
sb.append('\n');
indent--;
appendIndent(sb, indent);
sb.append(c);
break;
case ',':
sb.append(c)
.append('\n');
appendIndent(sb, indent);
break;
case ':':
sb.append(c).append(' ');
break;
default:
if (!Character.isWhitespace(c)) {
sb.append(c);
}
}
} else {
// 在字符串内原样输出
sb.append(c);
}
}
return sb.toString();
}
private static void appendIndent(StringBuilder sb, int indent) {
for (int i = 0; i < indent; i++) {
sb.append(" "); // 两个空格
}
}
}

View File

@ -1,25 +1,46 @@
// File: org/jcnc/snow/compiler/Main.java
package org.jcnc.snow.compiler;
import org.jcnc.snow.compiler.lexer.LexerEngine;
import org.jcnc.snow.compiler.lexer.token.Token;
import org.jcnc.snow.compiler.lexer.utils.TokenPrinter;
import org.jcnc.snow.compiler.parser.ParserEngine;
import org.jcnc.snow.compiler.parser.ast.ASTJsonSerializer;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.parser.ast.Node;
import org.jcnc.snow.compiler.parser.ast.ASTPrinter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
public class Main {
public static void main(String[] args) throws IOException {
// 如果命令行中提供了文件名就读取该文件否则默认读取当前目录下的 "opcode" 文件
// 读取源文件
String filePath = args.length > 0 ? args[0] : "test";
String source = Files.readString(Path.of(filePath), StandardCharsets.UTF_8);
// 词法分析
// 1. 词法分析
LexerEngine lexerEngine = new LexerEngine(source);
// 打印所有 Token
TokenPrinter.printTokens(lexerEngine.getAllTokens());
}
List<Token> tokens = lexerEngine.getAllTokens();
TokenPrinter.printTokens(tokens); // 可选打印 Token 列表
// 2. 语法分析
ParserContext ctx = new ParserContext(tokens);
List<Node> ast = new ParserEngine(ctx).parse();
// 3. 可读地打印 AST
ASTPrinter.print(ast);
// 1) 输出紧凑 JSON
String compact = ASTJsonSerializer.toJsonString(ast);
System.out.println("=== Compact JSON ===");
System.out.println(compact);
// 2) 输出美化后的 JSON
System.out.println("=== Pretty JSON ===");
System.out.println(JsonFormatter.prettyPrint(compact));
}
}

View File

@ -0,0 +1,41 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ParserEngine.java
package org.jcnc.snow.compiler.parser;
import org.jcnc.snow.compiler.lexer.token.TokenType;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.parser.context.TokenStream;
import org.jcnc.snow.compiler.parser.factory.TopLevelParserFactory;
import org.jcnc.snow.compiler.parser.ast.Node;
import java.util.ArrayList;
import java.util.List;
/**
* 解析引擎入口循环读取顶层块直到 EOF自动跳过空行NEWLINE
*/
public class ParserEngine {
private final ParserContext ctx;
public ParserEngine(ParserContext ctx) {
this.ctx = ctx;
}
public List<Node> parse() {
List<Node> nodes = new ArrayList<>();
TokenStream ts = ctx.getTokens();
while (!ts.isAtEnd()) {
// 跳过空行NEWLINE
if (ts.peek().getType() == TokenType.NEWLINE) {
ts.next();
continue;
}
String lex = ts.peek().getLexeme();
TopLevelParser p = TopLevelParserFactory.get(lex);
if (p == null) {
throw new IllegalStateException("Unexpected top-level token: " + lex);
}
nodes.add(p.parse(ctx));
}
return nodes;
}
}

View File

@ -0,0 +1,12 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/TopLevelParser.java
package org.jcnc.snow.compiler.parser;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.parser.ast.Node;
/**
* 顶层解析器接口 moduleimport
*/
public interface TopLevelParser {
Node parse(ParserContext ctx);
}

View File

@ -0,0 +1,210 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/ASTJsonSerializer.java
package org.jcnc.snow.compiler.parser.ast;
import java.util.List;
public class ASTJsonSerializer {
public static String toJsonString(List<Node> ast) {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < ast.size(); i++) {
sb.append(nodeToJson(ast.get(i)));
if (i + 1 < ast.size()) sb.append(",");
}
sb.append("]");
return sb.toString();
}
private static String nodeToJson(Node n) {
if (n instanceof ModuleNode m) return moduleToJson(m);
if (n instanceof FunctionNode f) return functionToJson(f);
if (n instanceof DeclarationNode d) return declarationToJson(d);
if (n instanceof AssignmentNode a) return assignmentToJson(a);
if (n instanceof IfNode i) return ifToJson(i);
if (n instanceof LoopNode l) return loopToJson(l);
if (n instanceof ReturnNode r) return returnToJson(r);
if (n instanceof ExpressionStatementNode es)
return exprStmtToJson(es);
// fallback仅输出类型名
return "{\"type\":\"" + n.getClass().getSimpleName() + "\"}";
}
private static String moduleToJson(ModuleNode m) {
StringBuilder sb = new StringBuilder();
sb.append("{\"type\":\"Module\",")
.append("\"name\":").append(quote(m.getName())).append(",");
// imports
sb.append("\"imports\":[");
for (int i = 0; i < m.getImports().size(); i++) {
ImportNode imp = m.getImports().get(i);
sb.append("{\"type\":\"Import\",\"module\":")
.append(quote(imp.getModuleName())).append("}");
if (i + 1 < m.getImports().size()) sb.append(",");
}
sb.append("],");
// functions
sb.append("\"functions\":[");
for (int i = 0; i < m.getFunctions().size(); i++) {
sb.append(functionToJson(m.getFunctions().get(i)));
if (i + 1 < m.getFunctions().size()) sb.append(",");
}
sb.append("]}");
return sb.toString();
}
private static String functionToJson(FunctionNode f) {
StringBuilder sb = new StringBuilder();
sb.append("{\"type\":\"Function\",")
.append("\"name\":").append(quote(f.getName())).append(",");
// parameters
sb.append("\"parameters\":[");
for (int i = 0; i < f.getParameters().size(); i++) {
ParameterNode p = f.getParameters().get(i);
sb.append("{\"name\":").append(quote(p.getName()))
.append(",\"type\":").append(quote(p.getType())).append("}");
if (i + 1 < f.getParameters().size()) sb.append(",");
}
sb.append("],");
sb.append("\"returnType\":").append(quote(f.getReturnType())).append(",");
// body
sb.append("\"body\":[");
List<StatementNode> body = f.getBody();
for (int i = 0; i < body.size(); i++) {
sb.append(nodeToJson(body.get(i)));
if (i + 1 < body.size()) sb.append(",");
}
sb.append("]}");
return sb.toString();
}
private static String declarationToJson(DeclarationNode d) {
StringBuilder sb = new StringBuilder();
sb.append("{\"type\":\"Declaration\",")
.append("\"name\":").append(quote(d.getName())).append(",")
.append("\"varType\":").append(quote(d.getType()));
d.getInitializer().ifPresent(init ->
sb.append(",\"initializer\":").append(exprToJson(init))
);
sb.append("}");
return sb.toString();
}
private static String assignmentToJson(AssignmentNode a) {
return "{\"type\":\"Assignment\",\"variable\":"
+ quote(a.getVariable())
+ ",\"value\":"
+ exprToJson(a.getValue())
+ "}";
}
private static String ifToJson(IfNode i) {
StringBuilder sb = new StringBuilder();
sb.append("{\"type\":\"If\",\"condition\":")
.append(exprToJson(i.getCondition())).append(",");
sb.append("\"then\":[");
List<StatementNode> thenBranch = i.getThenBranch();
for (int j = 0; j < thenBranch.size(); j++) {
sb.append(nodeToJson(thenBranch.get(j)));
if (j + 1 < thenBranch.size()) sb.append(",");
}
sb.append("]}");
return sb.toString();
}
private static String loopToJson(LoopNode l) {
StringBuilder sb = new StringBuilder();
sb.append("{\"type\":\"Loop\",")
.append("\"initializer\":").append(nodeToJson(l.getInitializer())).append(",")
.append("\"condition\":").append(exprToJson(l.getCondition())).append(",")
.append("\"update\":").append(nodeToJson(l.getUpdate())).append(",")
.append("\"body\":[");
List<StatementNode> body = l.getBody();
for (int i = 0; i < body.size(); i++) {
sb.append(nodeToJson(body.get(i)));
if (i + 1 < body.size()) sb.append(",");
}
sb.append("]}");
return sb.toString();
}
private static String returnToJson(ReturnNode r) {
StringBuilder sb = new StringBuilder();
sb.append("{\"type\":\"Return\"");
r.getExpression().ifPresent(expr ->
sb.append(",\"value\":").append(exprToJson(expr))
);
sb.append("}");
return sb.toString();
}
private static String exprStmtToJson(ExpressionStatementNode es) {
return "{\"type\":\"ExpressionStatement\",\"expression\":"
+ exprToJson(es.getExpression())
+ "}";
}
private static String exprToJson(ExpressionNode expr) {
if (expr instanceof BinaryExpressionNode b) return binaryToJson(b);
if (expr instanceof IdentifierNode id) return idToJson(id);
if (expr instanceof NumberLiteralNode num) return numToJson(num);
if (expr instanceof StringLiteralNode str) return strToJson(str);
if (expr instanceof CallExpressionNode c) return callToJson(c);
if (expr instanceof MemberExpressionNode m) return memberToJson(m);
// fallback
return "{\"type\":\"" + expr.getClass().getSimpleName() + "\"}";
}
private static String binaryToJson(BinaryExpressionNode b) {
return "{\"type\":\"BinaryExpression\","
+ "\"left\":" + exprToJson(b.getLeft()) + ","
+ "\"operator\":" + quote(b.getOperator()) + ","
+ "\"right\":" + exprToJson(b.getRight())
+ "}";
}
private static String idToJson(IdentifierNode id) {
return "{\"type\":\"Identifier\",\"name\":" + quote(id.getName()) + "}";
}
private static String numToJson(NumberLiteralNode num) {
return "{\"type\":\"NumberLiteral\",\"value\":" + quote(num.getValue()) + "}";
}
private static String strToJson(StringLiteralNode str) {
return "{\"type\":\"StringLiteral\",\"value\":" + quote(str.getValue()) + "}";
}
private static String callToJson(CallExpressionNode c) {
StringBuilder sb = new StringBuilder();
sb.append("{\"type\":\"CallExpression\",\"callee\":")
.append(exprToJson(c.getCallee())).append(",")
.append("\"arguments\":[");
for (int i = 0; i < c.getArguments().size(); i++) {
sb.append(exprToJson(c.getArguments().get(i)));
if (i + 1 < c.getArguments().size()) sb.append(",");
}
sb.append("]}");
return sb.toString();
}
private static String memberToJson(MemberExpressionNode m) {
return "{\"type\":\"MemberExpression\",\"object\":"
+ exprToJson(m.getObject())
+ ",\"member\":" + quote(m.getMember())
+ "}";
}
/** 把 Java 字符串内容转成 JSON 字符串常量(加双引号并转义) */
private static String quote(String s) {
StringBuilder sb = new StringBuilder();
sb.append("\"");
for (char c : s.toCharArray()) {
switch (c) {
case '\\': sb.append("\\\\"); break;
case '"': sb.append("\\\""); break;
case '\n': sb.append("\\n"); break;
case '\r': sb.append("\\r"); break;
case '\t': sb.append("\\t"); break;
default: sb.append(c);
}
}
sb.append("\"");
return sb.toString();
}
}

View File

@ -0,0 +1,75 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/ASTPrinter.java
package org.jcnc.snow.compiler.parser.ast;
import java.util.List;
/**
* 一个简单的 AST 打印器将所有节点格式化成可读的多行文本
*/
public class ASTPrinter {
public static void print(List<Node> nodes) {
for (Node n : nodes) {
print(n, 0);
}
}
private static void print(Node n, int indent) {
String pad = " ".repeat(indent);
if (n instanceof ModuleNode m) {
System.out.println(pad + "module " + m.getName());
for (ImportNode imp : m.getImports()) {
System.out.println(pad + " import " + imp.getModuleName());
}
for (FunctionNode fn : m.getFunctions()) {
print(fn, indent + 1);
}
} else if (n instanceof FunctionNode f) {
System.out.println(pad + "function " + f.getName()
+ "(params=" + f.getParameters() + ", return=" + f.getReturnType() + ")");
for (StatementNode stmt : f.getBody()) {
print(stmt, indent + 1);
}
} else if (n instanceof DeclarationNode d) {
String init = d.getInitializer()
.map(Object::toString)
.map(s -> " = " + s)
.orElse("");
System.out.println(pad + "declare " + d.getName() + ":" + d.getType() + init);
} else if (n instanceof AssignmentNode a) {
System.out.println(pad + a.getVariable() + " = " + a.getValue());
} else if (n instanceof IfNode i) {
System.out.println(pad + "if " + i.getCondition());
for (StatementNode stmt : i.getThenBranch()) {
print(stmt, indent + 1);
}
} else if (n instanceof LoopNode l) {
System.out.println(pad + "loop {");
print(l.getInitializer(), indent + 1);
System.out.println(pad + " condition: " + l.getCondition());
System.out.println(pad + " update: " + l.getUpdate());
System.out.println(pad + " body {");
for (StatementNode stmt : l.getBody()) {
print(stmt, indent + 2);
}
System.out.println(pad + " }");
System.out.println(pad + "}");
} else if (n instanceof ReturnNode r) {
System.out.println(pad + "return" +
r.getExpression().map(e -> " " + e).orElse(""));
} else if (n instanceof ExpressionStatementNode es) {
System.out.println(pad + es.getExpression());
} else {
// 回退直接调用 toString()
System.out.println(pad + n);
}
}
}

View File

@ -0,0 +1,28 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/AssignmentNode.java
package org.jcnc.snow.compiler.parser.ast;
/**
* 赋值语句节点例如 x = expr
*/
public class AssignmentNode implements StatementNode {
private final String variable;
private final ExpressionNode value;
public AssignmentNode(String variable, ExpressionNode value) {
this.variable = variable;
this.value = value;
}
public String getVariable() {
return variable;
}
public ExpressionNode getValue() {
return value;
}
@Override
public String toString() {
return variable + " = " + value;
}
}

View File

@ -0,0 +1,26 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/BinaryExpressionNode.java
package org.jcnc.snow.compiler.parser.ast;
/**
* 二元运算表达式节点 a + b
*/
public class BinaryExpressionNode implements ExpressionNode {
private final ExpressionNode left;
private final String operator;
private final ExpressionNode right;
public BinaryExpressionNode(ExpressionNode left, String operator, ExpressionNode right) {
this.left = left;
this.operator = operator;
this.right = right;
}
public ExpressionNode getLeft() { return left; }
public String getOperator() { return operator; }
public ExpressionNode getRight() { return right; }
@Override
public String toString() {
return left + " " + operator + " " + right;
}
}

View File

@ -0,0 +1,32 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/CallExpressionNode.java
package org.jcnc.snow.compiler.parser.ast;
import java.util.List;
/**
* 函数调用表达式节点callee(args)
*/
public class CallExpressionNode implements ExpressionNode {
private final ExpressionNode callee;
private final List<ExpressionNode> arguments;
public CallExpressionNode(ExpressionNode callee, List<ExpressionNode> arguments) {
this.callee = callee;
this.arguments = arguments;
}
public ExpressionNode getCallee() { return callee; }
public List<ExpressionNode> getArguments() { return arguments; }
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(callee).append("(");
for (int i = 0; i < arguments.size(); i++) {
sb.append(arguments.get(i));
if (i + 1 < arguments.size()) sb.append(", ");
}
sb.append(")");
return sb.toString();
}
}

View File

@ -0,0 +1,23 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/DeclarationNode.java
package org.jcnc.snow.compiler.parser.ast;
import java.util.Optional;
/**
* declare 语句节点声明变量可选初始化表达式
*/
public class DeclarationNode implements StatementNode {
private final String name;
private final String type;
private final Optional<ExpressionNode> initializer;
public DeclarationNode(String name, String type, ExpressionNode initializer) {
this.name = name;
this.type = type;
this.initializer = Optional.ofNullable(initializer);
}
public String getName() { return name; }
public String getType() { return type; }
public Optional<ExpressionNode> getInitializer() { return initializer; }
}

View File

@ -0,0 +1,7 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionNode.java
package org.jcnc.snow.compiler.parser.ast;
/**
* 标记所有表达式节点
*/
public interface ExpressionNode extends Node {}

View File

@ -0,0 +1,15 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java
package org.jcnc.snow.compiler.parser.ast;
/**
* 单独的表达式语句节点如函数调用赋值等
*/
public class ExpressionStatementNode implements StatementNode {
private final ExpressionNode expression;
public ExpressionStatementNode(ExpressionNode expression) {
this.expression = expression;
}
public ExpressionNode getExpression() { return expression; }
}

View File

@ -0,0 +1,27 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/FunctionNode.java
package org.jcnc.snow.compiler.parser.ast;
import java.util.List;
/**
* 函数定义节点包含函数名参数列表返回类型和函数体语句列表
*/
public class FunctionNode implements Node {
private final String name;
private final List<ParameterNode> parameters;
private final String returnType;
private final List<StatementNode> body;
public FunctionNode(String name, List<ParameterNode> parameters,
String returnType, List<StatementNode> body) {
this.name = name;
this.parameters = parameters;
this.returnType = returnType;
this.body = body;
}
public String getName() { return name; }
public List<ParameterNode> getParameters() { return parameters; }
public String getReturnType() { return returnType; }
public List<StatementNode> getBody() { return body; }
}

View File

@ -0,0 +1,19 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/IdentifierNode.java
package org.jcnc.snow.compiler.parser.ast;
/**
* 标识符表达式节点
*/
public class IdentifierNode implements ExpressionNode {
private final String name;
public IdentifierNode(String name) {
this.name = name;
}
public String getName() { return name; }
@Override
public String toString() {
return name;
}
}

View File

@ -0,0 +1,20 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/IfNode.java
package org.jcnc.snow.compiler.parser.ast;
import java.util.List;
/**
* if 语句节点包含条件表达式和 then 分支语句列表
*/
public class IfNode implements StatementNode {
private final ExpressionNode condition;
private final List<StatementNode> thenBranch;
public IfNode(ExpressionNode condition, List<StatementNode> thenBranch) {
this.condition = condition;
this.thenBranch = thenBranch;
}
public ExpressionNode getCondition() { return condition; }
public List<StatementNode> getThenBranch() { return thenBranch; }
}

View File

@ -0,0 +1,15 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java
package org.jcnc.snow.compiler.parser.ast;
/**
* import 语句节点仅保存被导入模块名
*/
public class ImportNode implements Node {
private final String moduleName;
public ImportNode(String moduleName) {
this.moduleName = moduleName;
}
public String getModuleName() { return moduleName; }
}

View File

@ -0,0 +1,29 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java
package org.jcnc.snow.compiler.parser.ast;
import java.util.List;
/**
* loop 语句节点包含初始化语句条件表达式更新语句和循环体
*/
public class LoopNode implements StatementNode {
private final StatementNode initializer;
private final ExpressionNode condition;
private final StatementNode update;
private final List<StatementNode> body;
public LoopNode(StatementNode initializer,
ExpressionNode condition,
StatementNode update,
List<StatementNode> body) {
this.initializer = initializer;
this.condition = condition;
this.update = update;
this.body = body;
}
public StatementNode getInitializer() { return initializer; }
public ExpressionNode getCondition() { return condition; }
public StatementNode getUpdate() { return update; }
public List<StatementNode> getBody() { return body; }
}

View File

@ -0,0 +1,22 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/MemberExpressionNode.java
package org.jcnc.snow.compiler.parser.ast;
/**
* 成员访问表达式节点 obj.prop
*/
public class MemberExpressionNode implements ExpressionNode {
private final ExpressionNode object;
private final String member;
public MemberExpressionNode(ExpressionNode object, String member) {
this.object = object;
this.member = member;
}
public ExpressionNode getObject() { return object; }
public String getMember() { return member; }
@Override
public String toString() {
return object + "." + member;
}
}

View File

@ -0,0 +1,50 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java
package org.jcnc.snow.compiler.parser.ast;
import java.util.List;
import java.util.StringJoiner;
/**
* 模块定义节点包含模块名import 列表和函数列表
*/
public class ModuleNode implements Node {
private final String name;
private final List<ImportNode> imports;
private final List<FunctionNode> functions;
public ModuleNode(String name, List<ImportNode> imports, List<FunctionNode> functions) {
this.name = name;
this.imports = imports;
this.functions = functions;
}
public String getName() {
return name;
}
public List<ImportNode> getImports() {
return imports;
}
public List<FunctionNode> getFunctions() {
return functions;
}
/**
* 返回模块的字符串表示便于调试和打印
*/
@Override
public String toString() {
StringJoiner importJoiner = new StringJoiner(", ");
for (ImportNode imp : imports) {
importJoiner.add(imp.getModuleName());
}
StringJoiner funcJoiner = new StringJoiner(", ");
for (FunctionNode fn : functions) {
funcJoiner.add(fn.getName());
}
return "Module(name=" + name
+ ", imports=[" + importJoiner.toString() + "]"
+ ", functions=[" + funcJoiner.toString() + "])";
}
}

View File

@ -0,0 +1,7 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/Node.java
package org.jcnc.snow.compiler.parser.ast;
/**
* 所有 AST 节点的标记接口
*/
public interface Node {}

View File

@ -0,0 +1,20 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/NumberLiteralNode.java
package org.jcnc.snow.compiler.parser.ast;
/**
* 数字字面量表达式节点
*/
public class NumberLiteralNode implements ExpressionNode {
private final String value;
public NumberLiteralNode(String value) {
this.value = value;
}
public String getValue() { return value; }
@Override
public String toString() {
return value;
}
}

View File

@ -0,0 +1,31 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/ParameterNode.java
package org.jcnc.snow.compiler.parser.ast;
/**
* 函数参数节点包含参数名和类型
*/
public class ParameterNode implements Node {
private final String name;
private final String type;
public ParameterNode(String name, String type) {
this.name = name;
this.type = type;
}
public String getName() {
return name;
}
public String getType() {
return type;
}
/**
* 返回参数的字符串表示例如 "num1:int"便于列表打印
*/
@Override
public String toString() {
return name + ":" + type;
}
}

View File

@ -0,0 +1,17 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/ReturnNode.java
package org.jcnc.snow.compiler.parser.ast;
import java.util.Optional;
/**
* return 语句节点可选返回表达式
*/
public class ReturnNode implements StatementNode {
private final Optional<ExpressionNode> expression;
public ReturnNode(ExpressionNode expression) {
this.expression = Optional.ofNullable(expression);
}
public Optional<ExpressionNode> getExpression() { return expression; }
}

View File

@ -0,0 +1,7 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/StatementNode.java
package org.jcnc.snow.compiler.parser.ast;
/**
* 标记所有语句节点
*/
public interface StatementNode extends Node {}

View File

@ -0,0 +1,27 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/StringLiteralNode.java
package org.jcnc.snow.compiler.parser.ast;
/**
* 字符串字面量表达式节点 "hello"
*/
public class StringLiteralNode implements ExpressionNode {
/** 不包含引号的字符串内容 */
private final String value;
public StringLiteralNode(String value) {
this.value = value;
}
public String getValue() {
return value;
}
/**
* 打印时在两端加上引号
* 例如 value = Result: toString() 返回 "Result:"
*/
@Override
public String toString() {
return "\"" + value + "\"";
}
}

View File

@ -0,0 +1,11 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/context/ParseException.java
package org.jcnc.snow.compiler.parser.context;
/**
* 解析时抛出的异常用于语法错误报告
*/
public class ParseException extends RuntimeException {
public ParseException(String message) {
super(message);
}
}

View File

@ -0,0 +1,20 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/context/ParserContext.java
package org.jcnc.snow.compiler.parser.context;
import org.jcnc.snow.compiler.lexer.token.Token;
import java.util.List;
/**
* Parser 共享上下文包含 TokenStream可扩展错误收集符号表等功能
*/
public class ParserContext {
private final TokenStream tokens;
public ParserContext(List<Token> tokens) {
this.tokens = new TokenStream(tokens);
}
public TokenStream getTokens() {
return tokens;
}
}

View File

@ -0,0 +1,78 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/context/TokenStream.java
package org.jcnc.snow.compiler.parser.context;
import org.jcnc.snow.compiler.lexer.token.Token;
import org.jcnc.snow.compiler.lexer.token.TokenType;
import java.util.List;
/**
* 封装 Token 列表并维护当前位置提供 peek/next/match/expect 等操作
* 现在新增 peek(offset) 以便在解析赋值时向前看一个 Token
*/
public class TokenStream {
private final List<Token> tokens;
private int pos = 0;
public TokenStream(List<Token> tokens) {
this.tokens = tokens;
}
/** 向前 offset 个位置的 Token不消费 */
public Token peek(int offset) {
int idx = pos + offset;
if (idx >= tokens.size()) {
return Token.eof(tokens.size() + 1);
}
return tokens.get(idx);
}
/** 默认 peek(0) */
public Token peek() {
return peek(0);
}
/** 消费并返回当前 Token */
public Token next() {
Token t = peek();
pos++;
return t;
}
/** 如果当前词素等于 lexeme则消费并返回 true */
public boolean match(String lexeme) {
if (peek().getLexeme().equals(lexeme)) {
next();
return true;
}
return false;
}
/** 断言 lexeme否则抛错 */
public Token expect(String lexeme) {
Token t = peek();
if (!t.getLexeme().equals(lexeme)) {
throw new ParseException(
"Expected lexeme '" + lexeme + "' but got '" + t.getLexeme() +
"' at " + t.getLine() + ":" + t.getCol()
);
}
return next();
}
/** 断言类型,否则抛错 */
public Token expectType(TokenType type) {
Token t = peek();
if (t.getType() != type) {
throw new ParseException(
"Expected token type " + type + " but got " + t.getType() +
" ('" + t.getLexeme() + "') at " + t.getLine() + ":" + t.getCol()
);
}
return next();
}
public boolean isAtEnd() {
return peek().getType() == TokenType.EOF;
}
}

View File

@ -0,0 +1,37 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/expression/BinaryOperatorParselet.java
package org.jcnc.snow.compiler.parser.expression;
import org.jcnc.snow.compiler.parser.ast.BinaryExpressionNode;
import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
import org.jcnc.snow.compiler.lexer.token.Token;
import org.jcnc.snow.compiler.parser.context.ParserContext;
/**
* 解析二元运算符表达式支持左/右结合
*/
public class BinaryOperatorParselet implements InfixParselet {
private final Precedence precedence;
private final boolean leftAssoc;
public BinaryOperatorParselet(Precedence precedence, boolean leftAssoc) {
this.precedence = precedence;
this.leftAssoc = leftAssoc;
}
@Override
public ExpressionNode parse(ParserContext ctx, ExpressionNode left) {
Token op = ctx.getTokens().next();
int prec = precedence.ordinal();
// 若左结合则右侧优先级减一
ExpressionNode right = new PrattExpressionParser().parseExpression(
ctx,
leftAssoc ? Precedence.values()[prec] : Precedence.values()[prec - 1]
);
return new BinaryExpressionNode(left, op.getLexeme(), right);
}
@Override
public Precedence getPrecedence() {
return precedence;
}
}

View File

@ -0,0 +1,33 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/expression/CallParselet.java
package org.jcnc.snow.compiler.parser.expression;
import org.jcnc.snow.compiler.parser.ast.CallExpressionNode;
import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import java.util.ArrayList;
import java.util.List;
/**
* 解析函数调用left ( args )
*/
public class CallParselet implements InfixParselet {
@Override
public ExpressionNode parse(ParserContext ctx, ExpressionNode left) {
// 已知 peek "("
ctx.getTokens().next(); // consume "("
List<ExpressionNode> args = new ArrayList<>();
if (!ctx.getTokens().peek().getLexeme().equals(")")) {
do {
args.add(new PrattExpressionParser().parse(ctx));
} while (ctx.getTokens().match(","));
}
ctx.getTokens().expect(")");
return new CallExpressionNode(left, args);
}
@Override
public Precedence getPrecedence() {
return Precedence.CALL;
}
}

View File

@ -0,0 +1,12 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/expression/ExpressionParser.java
package org.jcnc.snow.compiler.parser.expression;
import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
import org.jcnc.snow.compiler.parser.context.ParserContext;
/**
* 表达式解析接口
*/
public interface ExpressionParser {
ExpressionNode parse(ParserContext ctx);
}

View File

@ -0,0 +1,18 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/expression/GroupingParselet.java
package org.jcnc.snow.compiler.parser.expression;
import org.jcnc.snow.compiler.lexer.token.Token;
import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
import org.jcnc.snow.compiler.parser.context.ParserContext;
/**
* 解析括号表达式 ( expr )
*/
public class GroupingParselet implements PrefixParselet {
@Override
public ExpressionNode parse(ParserContext ctx, Token token) {
ExpressionNode expr = new PrattExpressionParser().parse(ctx);
ctx.getTokens().expect(")");
return expr;
}
}

View File

@ -0,0 +1,17 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/expression/IdentifierParselet.java
package org.jcnc.snow.compiler.parser.expression;
import org.jcnc.snow.compiler.lexer.token.Token;
import org.jcnc.snow.compiler.parser.ast.IdentifierNode;
import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
import org.jcnc.snow.compiler.parser.context.ParserContext;
/**
* 解析标识符
*/
public class IdentifierParselet implements PrefixParselet {
@Override
public ExpressionNode parse(ParserContext ctx, Token token) {
return new IdentifierNode(token.getLexeme());
}
}

View File

@ -0,0 +1,12 @@
package org.jcnc.snow.compiler.parser.expression;
import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
import org.jcnc.snow.compiler.parser.context.ParserContext;
/**
* 中缀解析器接口处理二元运算函数调用成员访问等
*/
public interface InfixParselet {
ExpressionNode parse(ParserContext ctx, ExpressionNode left);
Precedence getPrecedence();
}

View File

@ -0,0 +1,30 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/expression/MemberParselet.java
package org.jcnc.snow.compiler.parser.expression;
import org.jcnc.snow.compiler.lexer.token.TokenType;
import org.jcnc.snow.compiler.parser.ast.MemberExpressionNode;
import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.parser.context.TokenStream;
/**
* 解析成员访问表达式 left . IDENTIFIER
*/
public class MemberParselet implements InfixParselet {
@Override
public ExpressionNode parse(ParserContext ctx, ExpressionNode left) {
TokenStream ts = ctx.getTokens();
// 消费掉 "."
ts.expect(".");
// 现在下一个一定是标识符
String member = ts
.expectType(TokenType.IDENTIFIER)
.getLexeme();
return new MemberExpressionNode(left, member);
}
@Override
public Precedence getPrecedence() {
return Precedence.CALL;
}
}

View File

@ -0,0 +1,17 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/expression/NumberLiteralParselet.java
package org.jcnc.snow.compiler.parser.expression;
import org.jcnc.snow.compiler.lexer.token.Token;
import org.jcnc.snow.compiler.parser.ast.NumberLiteralNode;
import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
import org.jcnc.snow.compiler.parser.context.ParserContext;
/**
* 解析数字字面量
*/
public class NumberLiteralParselet implements PrefixParselet {
@Override
public ExpressionNode parse(ParserContext ctx, Token token) {
return new NumberLiteralNode(token.getLexeme());
}
}

View File

@ -0,0 +1,68 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/expression/PrattExpressionParser.java
package org.jcnc.snow.compiler.parser.expression;
import org.jcnc.snow.compiler.lexer.token.Token;
import org.jcnc.snow.compiler.lexer.token.TokenType;
import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import java.util.HashMap;
import java.util.Map;
/**
* Pratt 算法实现的表达式解析器支持算术比较调用成员访问字面量等
*/
public class PrattExpressionParser implements ExpressionParser {
private static final Map<String, PrefixParselet> prefixes = new HashMap<>();
private static final Map<String, InfixParselet> infixes = new HashMap<>();
static {
// 注册前缀 parselet
prefixes.put(TokenType.NUMBER_LITERAL.name(), new NumberLiteralParselet());
prefixes.put(TokenType.IDENTIFIER.name(), new IdentifierParselet());
prefixes.put(TokenType.LPAREN.name(), new GroupingParselet());
prefixes.put(TokenType.STRING_LITERAL.name(), new StringLiteralParselet()); // 新增
// 注册中缀 parselet保持原样
infixes.put("+", new BinaryOperatorParselet(Precedence.SUM, true));
infixes.put("-", new BinaryOperatorParselet(Precedence.SUM, true));
infixes.put("*", new BinaryOperatorParselet(Precedence.PRODUCT, true));
infixes.put("/", new BinaryOperatorParselet(Precedence.PRODUCT, true));
infixes.put(">", new BinaryOperatorParselet(Precedence.SUM, true));
infixes.put("<", new BinaryOperatorParselet(Precedence.SUM, true));
infixes.put("==", new BinaryOperatorParselet(Precedence.SUM, true));
infixes.put("!=", new BinaryOperatorParselet(Precedence.SUM, true));
infixes.put(">=", new BinaryOperatorParselet(Precedence.SUM, true));
infixes.put("<=", new BinaryOperatorParselet(Precedence.SUM, true));
infixes.put("(", new CallParselet());
infixes.put(".", new MemberParselet());
}
@Override
public ExpressionNode parse(ParserContext ctx) {
return parseExpression(ctx, Precedence.LOWEST);
}
ExpressionNode parseExpression(ParserContext ctx, Precedence prec) {
Token token = ctx.getTokens().next();
PrefixParselet prefix = prefixes.get(token.getType().name());
if (prefix == null) {
throw new IllegalStateException("No prefix for " + token.getType());
}
ExpressionNode left = prefix.parse(ctx, token);
while (!ctx.getTokens().isAtEnd() &&
prec.ordinal() < nextPrecedence(ctx)) {
String lex = ctx.getTokens().peek().getLexeme();
InfixParselet infix = infixes.get(lex);
if (infix == null) break;
left = infix.parse(ctx, left);
}
return left;
}
private int nextPrecedence(ParserContext ctx) {
InfixParselet infix = infixes.get(ctx.getTokens().peek().getLexeme());
return infix != null ? infix.getPrecedence().ordinal() : -1;
}
}

View File

@ -0,0 +1,11 @@
package org.jcnc.snow.compiler.parser.expression;// File: src/main/java/org/jcnc/snow/compiler/parser/expression/Precedence.java
/**
* 运算符优先级枚举用于 Pratt 算法比较
*/
public enum Precedence {
LOWEST, // 最低
SUM, // + -
PRODUCT, // * /
CALL // 函数调用成员访问
}

View File

@ -0,0 +1,13 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/expression/PrefixParselet.java
package org.jcnc.snow.compiler.parser.expression;
import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.lexer.token.Token;
/**
* 前缀解析器接口处理数字字面量标识符括号等前缀
*/
public interface PrefixParselet {
ExpressionNode parse(ParserContext ctx, Token token);
}

View File

@ -0,0 +1,21 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/expression/StringLiteralParselet.java
package org.jcnc.snow.compiler.parser.expression;
import org.jcnc.snow.compiler.lexer.token.Token;
import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
import org.jcnc.snow.compiler.parser.ast.StringLiteralNode;
import org.jcnc.snow.compiler.parser.context.ParserContext;
/**
* 解析字符串字面量前缀并去掉两端的引号
*/
public class StringLiteralParselet implements PrefixParselet {
@Override
public ExpressionNode parse(ParserContext ctx, Token token) {
// token.getRaw() 包含原始 "\"Result:\""
String raw = token.getRaw();
// 去掉首尾引号
String content = raw.substring(1, raw.length() - 1);
return new StringLiteralNode(content);
}
}

View File

@ -0,0 +1,26 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/factory/StatementParserFactory.java
package org.jcnc.snow.compiler.parser.factory;
import org.jcnc.snow.compiler.parser.statement.*;
import java.util.Map;
import java.util.HashMap;
/**
* 语句解析器工厂关键字 对应 StatementParser
*/
public class StatementParserFactory {
private static final Map<String, StatementParser> registry = new HashMap<>();
static {
registry.put("declare", new DeclarationStatementParser());
registry.put("if", new IfStatementParser());
registry.put("loop", new LoopStatementParser());
registry.put("return", new ReturnStatementParser());
// 默认使用表达式语句
registry.put("", new ExpressionStatementParser());
}
public static StatementParser get(String keyword) {
return registry.getOrDefault(keyword, registry.get(""));
}
}

View File

@ -0,0 +1,24 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/factory/TopLevelParserFactory.java
package org.jcnc.snow.compiler.parser.factory;
import org.jcnc.snow.compiler.parser.TopLevelParser;
import org.jcnc.snow.compiler.parser.module.ModuleParser;
import java.util.Map;
import java.util.HashMap;
/**
* 顶层解析器工厂根据首个关键字 module分发对应解析器
*/
public class TopLevelParserFactory {
private static final Map<String, TopLevelParser> registry = new HashMap<>();
static {
registry.put("module", new ModuleParser());
// 如需支持 standalone import可在此注册
}
public static TopLevelParser get(String keyword) {
return registry.get(keyword);
}
}

View File

@ -0,0 +1,97 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/function/FunctionParser.java
package org.jcnc.snow.compiler.parser.function;
import org.jcnc.snow.compiler.lexer.token.TokenType;
import org.jcnc.snow.compiler.parser.TopLevelParser;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.parser.context.TokenStream;
import org.jcnc.snow.compiler.parser.ast.*;
import org.jcnc.snow.compiler.parser.factory.StatementParserFactory;
import java.util.ArrayList;
import java.util.List;
/**
* 解析 function
* function: NAME NEWLINE
* parameter: (declare name:type | name:type)*
* return_type: TYPE NEWLINE
* body: ... end body
* end function NEWLINE
*/
public class FunctionParser implements TopLevelParser {
@Override
public FunctionNode parse(ParserContext ctx) {
TokenStream ts = ctx.getTokens();
ts.expect("function");
ts.expect(":");
String name = ts.expectType(TokenType.IDENTIFIER).getLexeme();
ts.expectType(TokenType.NEWLINE);
// 参数列表
ts.expect("parameter");
ts.expect(":");
ts.expectType(TokenType.NEWLINE);
List<ParameterNode> params = new ArrayList<>();
while (true) {
if (ts.peek().getType() == TokenType.NEWLINE) {
ts.next();
continue;
}
if ("return_type".equals(ts.peek().getLexeme())) {
break;
}
if ("declare".equals(ts.peek().getLexeme())) {
ts.next(); // consume 'declare'
}
String paramName = ts.expectType(TokenType.IDENTIFIER).getLexeme();
ts.expect(":");
String paramType = ts.expectType(TokenType.TYPE).getLexeme();
ts.expectType(TokenType.NEWLINE);
params.add(new ParameterNode(paramName, paramType));
}
// 返回类型
ts.expect("return_type");
ts.expect(":");
String returnType = ts.expectType(TokenType.TYPE).getLexeme();
ts.expectType(TokenType.NEWLINE);
// 函数体解析
ts.expect("body");
ts.expect(":");
ts.expectType(TokenType.NEWLINE);
List<StatementNode> body = new ArrayList<>();
parseBody(ctx, body);
// end body
ts.expect("end");
ts.expect("body");
ts.expectType(TokenType.NEWLINE);
// end function
ts.expect("end");
ts.expect("function");
ts.expectType(TokenType.NEWLINE);
return new FunctionNode(name, params, returnType, body);
}
/**
* 辅助方法根据 ParserContext 解析函数体中所有语句直到遇到 end
*/
private void parseBody(ParserContext ctx, List<StatementNode> body) {
TokenStream ts = ctx.getTokens();
while (true) {
if (ts.peek().getType() == TokenType.NEWLINE) {
ts.next();
continue;
}
if ("end".equals(ts.peek().getLexeme())) {
break;
}
String key = ts.peek().getLexeme();
body.add(StatementParserFactory.get(key).parse(ctx));
}
}
}

View File

@ -0,0 +1,39 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java
package org.jcnc.snow.compiler.parser.module;
import org.jcnc.snow.compiler.lexer.token.TokenType;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.parser.ast.ImportNode;
import java.util.ArrayList;
import java.util.List;
/**
* 解析 import 语句import: MOD1, MOD2, ... NEWLINE
* 可以在一行声明多个模块用逗号分隔
*/
public class ImportParser {
/**
* 读取一行 import 声明返回多个 ImportNode
*/
public List<ImportNode> parse(ParserContext ctx) {
ctx.getTokens().expect("import");
ctx.getTokens().expect(":");
List<ImportNode> imports = new ArrayList<>();
// 读取第一个模块名
String name = ctx.getTokens()
.expectType(TokenType.IDENTIFIER)
.getLexeme();
imports.add(new ImportNode(name));
// 继续读取逗号分隔的模块名
while (ctx.getTokens().match(",")) {
String mod = ctx.getTokens()
.expectType(TokenType.IDENTIFIER)
.getLexeme();
imports.add(new ImportNode(mod));
}
// 消费行尾
ctx.getTokens().expectType(TokenType.NEWLINE);
return imports;
}
}

View File

@ -0,0 +1,62 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/module/ModuleParser.java
package org.jcnc.snow.compiler.parser.module;
import org.jcnc.snow.compiler.lexer.token.TokenType;
import org.jcnc.snow.compiler.parser.TopLevelParser;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.parser.context.TokenStream;
import org.jcnc.snow.compiler.parser.ast.ImportNode;
import org.jcnc.snow.compiler.parser.ast.ModuleNode;
import org.jcnc.snow.compiler.parser.ast.FunctionNode;
import org.jcnc.snow.compiler.parser.function.FunctionParser;
import java.util.ArrayList;
import java.util.List;
/**
* 解析 module
* module: NAME NEWLINE
* (import | function )*
* end module NEWLINE
*/
public class ModuleParser implements TopLevelParser {
@Override
public ModuleNode parse(ParserContext ctx) {
TokenStream ts = ctx.getTokens();
ts.expect("module");
ts.expect(":");
String name = ts.expectType(TokenType.IDENTIFIER).getLexeme();
ts.expectType(TokenType.NEWLINE);
List<ImportNode> imports = new ArrayList<>();
List<FunctionNode> functions = new ArrayList<>();
ImportParser importParser = new ImportParser();
FunctionParser funcParser = new FunctionParser();
// 解析导入和函数支持空行
while (true) {
// 跳过空行
if (ts.peek().getType() == TokenType.NEWLINE) {
ts.next();
continue;
}
// 如果遇到 end跳出循环
if ("end".equals(ts.peek().getLexeme())) {
break;
}
String lex = ts.peek().getLexeme();
if ("import".equals(lex)) {
imports.addAll(importParser.parse(ctx));
} else if ("function".equals(lex)) {
functions.add(funcParser.parse(ctx));
} else {
throw new IllegalStateException("Unexpected token in module: " + lex);
}
}
ts.expect("end");
ts.expect("module");
ts.expectType(TokenType.NEWLINE);
return new ModuleNode(name, imports, functions);
}
}

View File

@ -0,0 +1,31 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java
package org.jcnc.snow.compiler.parser.statement;
import org.jcnc.snow.compiler.lexer.token.TokenType;
import org.jcnc.snow.compiler.parser.ast.DeclarationNode;
import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser;
/**
* 解析 declare 语句 declare name:type (= expr)? NEWLINE
*/
public class DeclarationStatementParser implements StatementParser {
@Override
public DeclarationNode parse(ParserContext ctx) {
ctx.getTokens().expect("declare");
String name = ctx.getTokens()
.expectType(TokenType.IDENTIFIER)
.getLexeme();
ctx.getTokens().expect(":");
String type = ctx.getTokens()
.expectType(TokenType.TYPE)
.getLexeme();
ExpressionNode init = null;
if (ctx.getTokens().match("=")) {
init = new PrattExpressionParser().parse(ctx);
}
ctx.getTokens().expectType(TokenType.NEWLINE);
return new DeclarationNode(name, type, init);
}
}

View File

@ -0,0 +1,39 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java
package org.jcnc.snow.compiler.parser.statement;
import org.jcnc.snow.compiler.lexer.token.TokenType;
import org.jcnc.snow.compiler.parser.ast.AssignmentNode;
import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
import org.jcnc.snow.compiler.parser.ast.ExpressionStatementNode;
import org.jcnc.snow.compiler.parser.ast.StatementNode;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.parser.context.TokenStream;
import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser;
/**
* 将任意表达式或赋值当作语句
* identifier = expr NEWLINE
* expr NEWLINE
*/
public class ExpressionStatementParser implements StatementParser {
@Override
public StatementNode parse(ParserContext ctx) {
TokenStream ts = ctx.getTokens();
// 先检测赋值语句IDENTIFIER '=' ...
if (ts.peek().getType() == TokenType.IDENTIFIER
&& ts.peek(1).getLexeme().equals("=")) {
String varName = ts.next().getLexeme(); // consume identifier
ts.expect("="); // consume '='
ExpressionNode value = new PrattExpressionParser().parse(ctx);
ts.expectType(TokenType.NEWLINE);
return new AssignmentNode(varName, value);
}
// 否则当作普通表达式语句
ExpressionNode expr = new PrattExpressionParser().parse(ctx);
ts.expectType(TokenType.NEWLINE);
return new ExpressionStatementNode(expr);
}
}

View File

@ -0,0 +1,38 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/statement/IfStatementParser.java
package org.jcnc.snow.compiler.parser.statement;
import org.jcnc.snow.compiler.lexer.token.TokenType;
import org.jcnc.snow.compiler.parser.ast.IfNode;
import org.jcnc.snow.compiler.parser.ast.StatementNode;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser;
import org.jcnc.snow.compiler.parser.factory.StatementParserFactory;
import java.util.ArrayList;
import java.util.List;
/**
* 解析 if 语句 if expr then NEWLINE stmts end if NEWLINE
*/
public class IfStatementParser implements StatementParser {
@Override
public IfNode parse(ParserContext ctx) {
ctx.getTokens().expect("if");
var cond = new PrattExpressionParser().parse(ctx);
ctx.getTokens().expect("then");
ctx.getTokens().expectType(TokenType.NEWLINE);
List<StatementNode> thenBranch = new ArrayList<>();
while (!ctx.getTokens().peek().getLexeme().equals("end")) {
thenBranch.add(
StatementParserFactory.get(ctx.getTokens().peek().getLexeme()).parse(ctx)
);
}
ctx.getTokens().expect("end");
ctx.getTokens().expect("if");
ctx.getTokens().expectType(TokenType.NEWLINE);
return new IfNode(cond, thenBranch);
}
}

View File

@ -0,0 +1,100 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java
package org.jcnc.snow.compiler.parser.statement;
import org.jcnc.snow.compiler.lexer.token.TokenType;
import org.jcnc.snow.compiler.parser.ast.AssignmentNode;
import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
import org.jcnc.snow.compiler.parser.ast.LoopNode;
import org.jcnc.snow.compiler.parser.ast.StatementNode;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.parser.context.TokenStream;
import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser;
import org.jcnc.snow.compiler.parser.factory.StatementParserFactory;
import java.util.ArrayList;
import java.util.List;
/**
* 解析 loop 语句
* loop: NEWLINE
* initializer: NEWLINE
* condition: NEWLINE
* update: NEWLINE
* body: NEWLINE
* end body NEWLINE
* end loop NEWLINE
*/
public class LoopStatementParser implements StatementParser {
@Override
public LoopNode parse(ParserContext ctx) {
TokenStream ts = ctx.getTokens();
// loop:
ts.expect("loop");
ts.expect(":");
ts.expectType(TokenType.NEWLINE);
skipNewlines(ts);
// initializer:
ts.expect("initializer");
ts.expect(":");
ts.expectType(TokenType.NEWLINE);
skipNewlines(ts);
StatementNode initializer =
StatementParserFactory.get(ts.peek().getLexeme()).parse(ctx);
skipNewlines(ts);
// condition:
ts.expect("condition");
ts.expect(":");
ts.expectType(TokenType.NEWLINE);
skipNewlines(ts);
ExpressionNode condition =
new PrattExpressionParser().parse(ctx);
ts.expectType(TokenType.NEWLINE);
skipNewlines(ts);
// update (专用赋值解析):
ts.expect("update");
ts.expect(":");
ts.expectType(TokenType.NEWLINE);
skipNewlines(ts);
String varName = ts.expectType(TokenType.IDENTIFIER).getLexeme();
ts.expect("=");
ExpressionNode updateExpr = new PrattExpressionParser().parse(ctx);
ts.expectType(TokenType.NEWLINE);
AssignmentNode update = new AssignmentNode(varName, updateExpr);
skipNewlines(ts);
// body:
ts.expect("body");
ts.expect(":");
ts.expectType(TokenType.NEWLINE);
skipNewlines(ts);
List<StatementNode> body = new ArrayList<>();
while (!"end".equals(ts.peek().getLexeme())) {
body.add(StatementParserFactory.get(ts.peek().getLexeme()).parse(ctx));
skipNewlines(ts);
}
// end body
ts.expect("end");
ts.expect("body");
ts.expectType(TokenType.NEWLINE);
skipNewlines(ts);
// end loop
ts.expect("end");
ts.expect("loop");
ts.expectType(TokenType.NEWLINE);
return new LoopNode(initializer, condition, update, body);
}
/** 连续跳过所有空行NEWLINE */
private void skipNewlines(TokenStream ts) {
while (ts.peek().getType() == TokenType.NEWLINE) {
ts.next();
}
}
}

View File

@ -0,0 +1,26 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/statement/ReturnStatementParser.java
package org.jcnc.snow.compiler.parser.statement;
import org.jcnc.snow.compiler.lexer.token.TokenType;
import org.jcnc.snow.compiler.parser.ast.ReturnNode;
import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser;
/**
* 解析 return 语句 return expr? NEWLINE
*/
public class ReturnStatementParser implements StatementParser {
@Override
public ReturnNode parse(ParserContext ctx) {
ctx.getTokens().expect("return");
ExpressionNode expr = null;
// 如果下一个不是换行就解析表达式
if (ctx.getTokens().peek().getType() != TokenType.NEWLINE) {
expr = new PrattExpressionParser().parse(ctx);
}
// expectType 来消费真正的 NEWLINE token
ctx.getTokens().expectType(TokenType.NEWLINE);
return new ReturnNode(expr);
}
}

View File

@ -0,0 +1,12 @@
// File: src/main/java/org/jcnc/snow/compiler/parser/statement/StatementParser.java
package org.jcnc.snow.compiler.parser.statement;
import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.parser.ast.StatementNode;
/**
* 语句解析器接口
*/
public interface StatementParser {
StatementNode parse(ParserContext ctx);
}