增加Java Doc
This commit is contained in:
parent
cd402653cb
commit
ff51636fe7
@ -1,26 +1,44 @@
|
|||||||
package org.jcnc.snow.compiler;
|
package org.jcnc.snow.compiler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON 格式化工具类。
|
||||||
|
* 提供将紧凑 JSON 字符串美化为带缩进和换行的易读格式的方法。
|
||||||
|
*/
|
||||||
public class JsonFormatter {
|
public class JsonFormatter {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对一个紧凑的 JSON 字符串进行缩进美化。
|
* 对一个紧凑的 JSON 字符串进行缩进美化。
|
||||||
* @param json 紧凑的 JSON
|
* 例如:
|
||||||
* @return 带换行和缩进的 JSON
|
* <pre>{@code
|
||||||
|
* {"a":1,"b":[2,3]} →
|
||||||
|
* {
|
||||||
|
* "a": 1,
|
||||||
|
* "b": [
|
||||||
|
* 2,
|
||||||
|
* 3
|
||||||
|
* ]
|
||||||
|
* }
|
||||||
|
* }</pre>
|
||||||
|
*
|
||||||
|
* @param json 紧凑的 JSON 字符串。
|
||||||
|
* @return 格式化后的 JSON 字符串,带有缩进与换行。
|
||||||
*/
|
*/
|
||||||
public static String prettyPrint(String json) {
|
public static String prettyPrint(String json) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
int indent = 0;
|
int indent = 0;
|
||||||
boolean inQuotes = false;
|
boolean inQuotes = false;
|
||||||
|
|
||||||
for (int i = 0; i < json.length(); i++) {
|
for (int i = 0; i < json.length(); i++) {
|
||||||
char c = json.charAt(i);
|
char c = json.charAt(i);
|
||||||
// 切换引号状态(忽略转义的 \")
|
|
||||||
|
// 检查是否进入或退出字符串(忽略转义的引号)
|
||||||
if (c == '"' && (i == 0 || json.charAt(i - 1) != '\\')) {
|
if (c == '"' && (i == 0 || json.charAt(i - 1) != '\\')) {
|
||||||
inQuotes = !inQuotes;
|
inQuotes = !inQuotes;
|
||||||
sb.append(c);
|
sb.append(c);
|
||||||
} else if (!inQuotes) {
|
} else if (!inQuotes) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case '{', '[':
|
case '{', '[':
|
||||||
sb.append(c)
|
sb.append(c).append('\n');
|
||||||
.append('\n');
|
|
||||||
indent++;
|
indent++;
|
||||||
appendIndent(sb, indent);
|
appendIndent(sb, indent);
|
||||||
break;
|
break;
|
||||||
@ -31,8 +49,7 @@ public class JsonFormatter {
|
|||||||
sb.append(c);
|
sb.append(c);
|
||||||
break;
|
break;
|
||||||
case ',':
|
case ',':
|
||||||
sb.append(c)
|
sb.append(c).append('\n');
|
||||||
.append('\n');
|
|
||||||
appendIndent(sb, indent);
|
appendIndent(sb, indent);
|
||||||
break;
|
break;
|
||||||
case ':':
|
case ':':
|
||||||
@ -44,14 +61,21 @@ public class JsonFormatter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 在字符串内原样输出
|
// 字符串内部原样输出
|
||||||
sb.append(c);
|
sb.append(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 向字符串构建器追加指定层级的缩进。
|
||||||
|
*
|
||||||
|
* @param sb 输出目标。
|
||||||
|
* @param indent 缩进层级(每层为两个空格)。
|
||||||
|
*/
|
||||||
private static void appendIndent(StringBuilder sb, int indent) {
|
private static void appendIndent(StringBuilder sb, int indent) {
|
||||||
sb.append(" ".repeat(Math.max(0, indent))); // 两个空格
|
sb.append(" ".repeat(Math.max(0, indent)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,31 +10,48 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析引擎入口:循环读取顶层块直到 EOF,自动跳过空行(NEWLINE)。
|
* 解析器主引擎,负责驱动顶层结构(如 module)解析。
|
||||||
|
* 它会循环处理每个顶层语法块,直到遇到 EOF。
|
||||||
|
* 同时自动跳过空行(NEWLINE)以增强容错性。
|
||||||
*/
|
*/
|
||||||
public class ParserEngine {
|
public class ParserEngine {
|
||||||
private final ParserContext ctx;
|
private final ParserContext ctx;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造解析器引擎。
|
||||||
|
*
|
||||||
|
* @param ctx 解析上下文,封装了 Token 流等解析状态。
|
||||||
|
*/
|
||||||
public ParserEngine(ParserContext ctx) {
|
public ParserEngine(ParserContext ctx) {
|
||||||
this.ctx = ctx;
|
this.ctx = ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动解析流程,返回顶层节点列表(模块、导入等)。
|
||||||
|
*
|
||||||
|
* @return 所有解析出的 AST 顶层节点。
|
||||||
|
*/
|
||||||
public List<Node> parse() {
|
public List<Node> parse() {
|
||||||
List<Node> nodes = new ArrayList<>();
|
List<Node> nodes = new ArrayList<>();
|
||||||
TokenStream ts = ctx.getTokens();
|
TokenStream ts = ctx.getTokens();
|
||||||
|
|
||||||
while (ts.isAtEnd()) {
|
while (ts.isAtEnd()) {
|
||||||
// 跳过空行(NEWLINE)
|
// 跳过空行
|
||||||
if (ts.peek().getType() == TokenType.NEWLINE) {
|
if (ts.peek().getType() == TokenType.NEWLINE) {
|
||||||
ts.next();
|
ts.next();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 根据当前关键字分发顶层解析器
|
||||||
String lex = ts.peek().getLexeme();
|
String lex = ts.peek().getLexeme();
|
||||||
TopLevelParser p = TopLevelParserFactory.get(lex);
|
TopLevelParser parser = TopLevelParserFactory.get(lex);
|
||||||
if (p == null) {
|
if (parser == null) {
|
||||||
throw new IllegalStateException("Unexpected top-level token: " + lex);
|
throw new IllegalStateException("Unexpected top-level token: " + lex);
|
||||||
}
|
}
|
||||||
nodes.add(p.parse(ctx));
|
|
||||||
|
nodes.add(parser.parse(ctx));
|
||||||
}
|
}
|
||||||
|
|
||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,16 @@ import org.jcnc.snow.compiler.parser.context.ParserContext;
|
|||||||
import org.jcnc.snow.compiler.parser.ast.Node;
|
import org.jcnc.snow.compiler.parser.ast.Node;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 顶层解析器接口,如 module、import 等。
|
* 顶层结构解析器接口,用于解析模块级别的语法结构,如 {@code module}、{@code import} 等。
|
||||||
|
* 所有顶层解析器应实现该接口。
|
||||||
*/
|
*/
|
||||||
public interface TopLevelParser {
|
public interface TopLevelParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从解析上下文中解析一个顶层语法结构。
|
||||||
|
*
|
||||||
|
* @param ctx 当前解析上下文。
|
||||||
|
* @return 表示顶层结构的 AST 节点。
|
||||||
|
*/
|
||||||
Node parse(ParserContext ctx);
|
Node parse(ParserContext ctx);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,8 +2,19 @@ package org.jcnc.snow.compiler.parser.ast;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASTJsonSerializer 是一个用于将抽象语法树(AST)序列化为 JSON 字符串的工具类。
|
||||||
|
* 该类通过访问不同类型的语法树节点,将其结构以标准 JSON 格式输出,适用于调试、可视化或进一步处理。
|
||||||
|
*/
|
||||||
public class ASTJsonSerializer {
|
public class ASTJsonSerializer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将语法树节点列表序列化为 JSON 字符串。
|
||||||
|
*
|
||||||
|
* @param ast 抽象语法树的节点列表。
|
||||||
|
* @return 表示整个 AST 的 JSON 字符串。
|
||||||
|
*/
|
||||||
public static String toJsonString(List<Node> ast) {
|
public static String toJsonString(List<Node> ast) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("[");
|
sb.append("[");
|
||||||
@ -189,8 +200,12 @@ public class ASTJsonSerializer {
|
|||||||
+ "}";
|
+ "}";
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 把 Java 字符串内容转成 JSON 字符串常量(加双引号并转义) */
|
/**
|
||||||
private static String quote(String s) {
|
* 将字符串转换为合法的 JSON 字符串常量(添加双引号并进行必要的转义)。
|
||||||
|
*
|
||||||
|
* @param s 原始字符串。
|
||||||
|
* @return 转义并加双引号的 JSON 字符串。
|
||||||
|
*/ private static String quote(String s) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("\"");
|
sb.append("\"");
|
||||||
for (char c : s.toCharArray()) {
|
for (char c : s.toCharArray()) {
|
||||||
|
|||||||
@ -3,17 +3,30 @@ package org.jcnc.snow.compiler.parser.ast;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 一个简单的 AST 打印器,将所有节点格式化成可读的多行文本。
|
* AST 打印器,用于将抽象语法树(AST)中的节点打印为可读的、格式化的多行文本。
|
||||||
|
* 每个节点根据其类型和结构打印相应的缩进层级,便于人类阅读和调试。
|
||||||
*/
|
*/
|
||||||
public class ASTPrinter {
|
public class ASTPrinter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印整个语法树的节点列表。
|
||||||
|
*
|
||||||
|
* @param nodes 要打印的 AST 节点列表,通常是顶层模块或语句。
|
||||||
|
*/
|
||||||
public static void print(List<Node> nodes) {
|
public static void print(List<Node> nodes) {
|
||||||
for (Node n : nodes) {
|
for (Node n : nodes) {
|
||||||
print(n, 0);
|
print(n, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 打印单个节点及其子节点,带有缩进格式。
|
||||||
|
*
|
||||||
|
* @param n 要打印的节点。
|
||||||
|
* @param indent 当前的缩进层级(每层两个空格)。
|
||||||
|
*/
|
||||||
private static void print(Node n, int indent) {
|
private static void print(Node n, int indent) {
|
||||||
String pad = " ".repeat(indent);
|
String pad = " ".repeat(indent); // 缩进字符串
|
||||||
|
|
||||||
switch (n) {
|
switch (n) {
|
||||||
case ModuleNode m -> {
|
case ModuleNode m -> {
|
||||||
@ -65,9 +78,10 @@ public class ASTPrinter {
|
|||||||
}
|
}
|
||||||
case ReturnNode r -> System.out.println(pad + "return" +
|
case ReturnNode r -> System.out.println(pad + "return" +
|
||||||
r.getExpression().map(e -> " " + e).orElse(""));
|
r.getExpression().map(e -> " " + e).orElse(""));
|
||||||
case ExpressionStatementNode(ExpressionNode expression) -> System.out.println(pad + expression);
|
case ExpressionStatementNode(ExpressionNode expression) ->
|
||||||
|
System.out.println(pad + expression);
|
||||||
case null, default ->
|
case null, default ->
|
||||||
// 回退:直接调用 toString()
|
// 回退:如果节点类型不在上述范围内,则使用 toString()
|
||||||
System.out.println(pad + n);
|
System.out.println(pad + n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,18 @@
|
|||||||
package org.jcnc.snow.compiler.parser.ast;
|
package org.jcnc.snow.compiler.parser.ast;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 赋值语句节点,例如 x = expr。
|
* 表示赋值语句的 AST(抽象语法树)节点,例如 {@code x = expr}。
|
||||||
|
*
|
||||||
|
* @param variable 赋值语句左侧的变量名。
|
||||||
|
* @param value 赋值语句右侧的表达式节点,表示要赋给变量的值。
|
||||||
*/
|
*/
|
||||||
public record AssignmentNode(String variable, ExpressionNode value) implements StatementNode {
|
public record AssignmentNode(String variable, ExpressionNode value) implements StatementNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回赋值语句的字符串表示形式,例如 {@code x = y + 1}。
|
||||||
|
*
|
||||||
|
* @return 表示赋值语句的字符串。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return variable + " = " + value;
|
return variable + " = " + value;
|
||||||
|
|||||||
@ -1,11 +1,21 @@
|
|||||||
package org.jcnc.snow.compiler.parser.ast;
|
package org.jcnc.snow.compiler.parser.ast;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 二元运算表达式节点,如 a + b。
|
* 表示二元运算表达式的 AST 节点,例如 {@code a + b}。
|
||||||
|
* 该节点包含一个左操作数、一个操作符字符串和一个右操作数。
|
||||||
|
*
|
||||||
|
* @param left 表达式左侧的子表达式。
|
||||||
|
* @param operator 运算符字符串,例如 "+"、"-"、"*"、"/" 等。
|
||||||
|
* @param right 表达式右侧的子表达式。
|
||||||
*/
|
*/
|
||||||
public record BinaryExpressionNode(ExpressionNode left, String operator,
|
public record BinaryExpressionNode(ExpressionNode left, String operator,
|
||||||
ExpressionNode right) implements ExpressionNode {
|
ExpressionNode right) implements ExpressionNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回该二元表达式的字符串表示形式,例如 {@code a + b}。
|
||||||
|
*
|
||||||
|
* @return 表达式的字符串形式。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return left + " " + operator + " " + right;
|
return left + " " + operator + " " + right;
|
||||||
|
|||||||
@ -3,10 +3,19 @@ package org.jcnc.snow.compiler.parser.ast;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 函数调用表达式节点:callee(args…)。
|
* 表示函数调用表达式的 AST 节点,例如 {@code foo(arg1, arg2)}。
|
||||||
|
* 包含一个被调用的表达式(callee)和一个参数列表(arguments)。
|
||||||
|
*
|
||||||
|
* @param callee 被调用的表达式,通常是一个标识符或成员访问表达式。
|
||||||
|
* @param arguments 函数调用的参数列表,每个参数都是一个表达式节点。
|
||||||
*/
|
*/
|
||||||
public record CallExpressionNode(ExpressionNode callee, List<ExpressionNode> arguments) implements ExpressionNode {
|
public record CallExpressionNode(ExpressionNode callee, List<ExpressionNode> arguments) implements ExpressionNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回函数调用表达式的字符串表示形式,例如 {@code foo(x, y)}。
|
||||||
|
*
|
||||||
|
* @return 表达式的字符串形式。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|||||||
@ -3,20 +3,45 @@ package org.jcnc.snow.compiler.parser.ast;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* declare 语句节点:声明变量,可选初始化表达式。
|
* 表示变量声明语句的 AST 节点,例如 {@code int x = 5;}。
|
||||||
|
* 该节点包含变量名称、类型,以及可选的初始化表达式。
|
||||||
*/
|
*/
|
||||||
public class DeclarationNode implements StatementNode {
|
public class DeclarationNode implements StatementNode {
|
||||||
private final String name;
|
private final String name;
|
||||||
private final String type;
|
private final String type;
|
||||||
private final Optional<ExpressionNode> initializer;
|
private final Optional<ExpressionNode> initializer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造一个变量声明节点。
|
||||||
|
*
|
||||||
|
* @param name 变量的名称。
|
||||||
|
* @param type 变量的类型(例如 "int", "string")。
|
||||||
|
* @param initializer 可选的初始化表达式,若为 null 表示未初始化。
|
||||||
|
*/
|
||||||
public DeclarationNode(String name, String type, ExpressionNode initializer) {
|
public DeclarationNode(String name, String type, ExpressionNode initializer) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.initializer = Optional.ofNullable(initializer);
|
this.initializer = Optional.ofNullable(initializer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取变量名称。
|
||||||
|
*
|
||||||
|
* @return 变量名字符串。
|
||||||
|
*/
|
||||||
public String getName() { return name; }
|
public String getName() { return name; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取变量类型。
|
||||||
|
*
|
||||||
|
* @return 变量类型字符串。
|
||||||
|
*/
|
||||||
public String getType() { return type; }
|
public String getType() { return type; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取可选的初始化表达式。
|
||||||
|
*
|
||||||
|
* @return 包含初始化表达式的 Optional 对象,可能为空。
|
||||||
|
*/
|
||||||
public Optional<ExpressionNode> getInitializer() { return initializer; }
|
public Optional<ExpressionNode> getInitializer() { return initializer; }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
package org.jcnc.snow.compiler.parser.ast;
|
package org.jcnc.snow.compiler.parser.ast;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 标记所有表达式节点。
|
* 表示抽象语法树中的表达式节点类型。
|
||||||
|
* 所有具体的表达式(如常量、变量、运算、函数调用等)都应实现该接口。
|
||||||
|
* 这是一个标记接口(marker interface),用于统一处理所有表达式节点。
|
||||||
*/
|
*/
|
||||||
public interface ExpressionNode extends Node {}
|
public interface ExpressionNode extends Node {}
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
package org.jcnc.snow.compiler.parser.ast;
|
package org.jcnc.snow.compiler.parser.ast;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 单独的表达式语句节点(如函数调用、赋值等)。
|
* 表示一条独立的表达式语句,例如 {@code foo();} 或 {@code x = 1;}。
|
||||||
|
* 该节点将一个表达式作为语句出现。
|
||||||
|
*
|
||||||
|
* @param expression 表达式内容,通常是函数调用或赋值操作。
|
||||||
*/
|
*/
|
||||||
public record ExpressionStatementNode(ExpressionNode expression) implements StatementNode {
|
public record ExpressionStatementNode(ExpressionNode expression) implements StatementNode {
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,13 @@ package org.jcnc.snow.compiler.parser.ast;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 函数定义节点:包含函数名、参数列表、返回类型和函数体语句列表。
|
* 表示函数定义的 AST 节点,包含函数名、参数、返回类型和函数体。
|
||||||
|
* 示例:{@code int add(int a, int b) { return a + b; }}
|
||||||
|
*
|
||||||
|
* @param name 函数名称。
|
||||||
|
* @param parameters 参数列表,每个参数是一个 {@link ParameterNode}。
|
||||||
|
* @param returnType 返回值类型,表示函数的返回类型(例如 "int"、"void")。
|
||||||
|
* @param body 函数体,由若干语句组成的列表。
|
||||||
*/
|
*/
|
||||||
public record FunctionNode(String name, List<ParameterNode> parameters, String returnType,
|
public record FunctionNode(String name, List<ParameterNode> parameters, String returnType,
|
||||||
List<StatementNode> body) implements Node {
|
List<StatementNode> body) implements Node {
|
||||||
|
|||||||
@ -1,9 +1,17 @@
|
|||||||
package org.jcnc.snow.compiler.parser.ast;
|
package org.jcnc.snow.compiler.parser.ast;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 标识符表达式节点。
|
* 表示标识符的表达式节点,例如变量名 {@code x}、函数名 {@code foo} 等。
|
||||||
|
*
|
||||||
|
* @param name 标识符的名称。
|
||||||
*/
|
*/
|
||||||
public record IdentifierNode(String name) implements ExpressionNode {
|
public record IdentifierNode(String name) implements ExpressionNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回标识符的字符串表示形式,即其名称。
|
||||||
|
*
|
||||||
|
* @return 标识符名称字符串。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return name;
|
return name;
|
||||||
|
|||||||
@ -3,7 +3,12 @@ package org.jcnc.snow.compiler.parser.ast;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* if 语句节点:包含条件表达式和 then 分支语句列表。
|
* 表示 if 语句的 AST 节点。
|
||||||
|
* 包含一个条件表达式和一个 then 分支的语句列表,不包含 else 分支。
|
||||||
|
* 示例:{@code if (x > 0) { print(x); }}
|
||||||
|
*
|
||||||
|
* @param condition 条件表达式,控制是否执行 then 分支。
|
||||||
|
* @param thenBranch 条件为真时执行的语句列表。
|
||||||
*/
|
*/
|
||||||
public record IfNode(ExpressionNode condition, List<StatementNode> thenBranch) implements StatementNode {
|
public record IfNode(ExpressionNode condition, List<StatementNode> thenBranch) implements StatementNode {
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
package org.jcnc.snow.compiler.parser.ast;
|
package org.jcnc.snow.compiler.parser.ast;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* import 语句节点:仅保存被导入模块名。
|
* 表示 import 语句的 AST 节点。
|
||||||
|
* 该节点仅包含被导入模块的名称。
|
||||||
|
* 示例:{@code import my.module;}
|
||||||
|
*
|
||||||
|
* @param moduleName 被导入的模块名称。
|
||||||
*/
|
*/
|
||||||
public record ImportNode(String moduleName) implements Node {
|
public record ImportNode(String moduleName) implements Node {
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,19 @@ package org.jcnc.snow.compiler.parser.ast;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* loop 语句节点:包含初始化语句、条件表达式、更新语句和循环体。
|
* 表示循环语句(loop)的 AST 节点,结构类似于传统的 for 循环。
|
||||||
|
* 包含初始化语句、循环条件、更新语句和循环体。
|
||||||
|
* 示例:
|
||||||
|
* {@code
|
||||||
|
* for (int i = 0; i < 10; i++) {
|
||||||
|
* print(i);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @param initializer 循环开始前执行的初始化语句。
|
||||||
|
* @param condition 每次迭代前都会评估的条件表达式。
|
||||||
|
* @param update 每次迭代结束时执行的更新语句。
|
||||||
|
* @param body 循环体内的语句列表。
|
||||||
*/
|
*/
|
||||||
public record LoopNode(StatementNode initializer, ExpressionNode condition, StatementNode update,
|
public record LoopNode(StatementNode initializer, ExpressionNode condition, StatementNode update,
|
||||||
List<StatementNode> body) implements StatementNode {
|
List<StatementNode> body) implements StatementNode {
|
||||||
|
|||||||
@ -1,9 +1,19 @@
|
|||||||
package org.jcnc.snow.compiler.parser.ast;
|
package org.jcnc.snow.compiler.parser.ast;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 成员访问表达式节点,如 obj.prop。
|
* 表示成员访问的表达式节点,例如 {@code obj.prop}。
|
||||||
|
* 包含一个对象表达式和成员名称。
|
||||||
|
*
|
||||||
|
* @param object 表达式左侧的对象部分,通常是一个标识符或更复杂的表达式。
|
||||||
|
* @param member 成员名称,表示要访问的字段或方法。
|
||||||
*/
|
*/
|
||||||
public record MemberExpressionNode(ExpressionNode object, String member) implements ExpressionNode {
|
public record MemberExpressionNode(ExpressionNode object, String member) implements ExpressionNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回成员访问表达式的字符串表示形式,例如 {@code obj.prop}。
|
||||||
|
*
|
||||||
|
* @return 成员访问表达式的字符串形式。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return object + "." + member;
|
return object + "." + member;
|
||||||
|
|||||||
@ -1,16 +1,29 @@
|
|||||||
// File: src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java
|
|
||||||
package org.jcnc.snow.compiler.parser.ast;
|
package org.jcnc.snow.compiler.parser.ast;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.StringJoiner;
|
import java.util.StringJoiner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 模块定义节点:包含模块名、import 列表和函数列表。
|
* 表示模块定义的 AST 节点。
|
||||||
|
* 一个模块通常由模块名、导入语句列表和函数定义列表组成。
|
||||||
|
* 示例结构:
|
||||||
|
* {@code
|
||||||
|
* module my.module {
|
||||||
|
* import other.module;
|
||||||
|
* fun foo() { ... }
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @param name 模块名称。
|
||||||
|
* @param imports 模块导入列表,每个导入是一个 {@link ImportNode}。
|
||||||
|
* @param functions 模块中的函数列表,每个函数是一个 {@link FunctionNode}。
|
||||||
*/
|
*/
|
||||||
public record ModuleNode(String name, List<ImportNode> imports, List<FunctionNode> functions) implements Node {
|
public record ModuleNode(String name, List<ImportNode> imports, List<FunctionNode> functions) implements Node {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回模块的字符串表示,便于调试和打印。
|
* 返回模块节点的字符串表示形式,包含模块名、导入模块列表和函数列表。
|
||||||
|
*
|
||||||
|
* @return 模块的简洁字符串表示,用于调试和日志输出。
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
@ -23,7 +36,7 @@ public record ModuleNode(String name, List<ImportNode> imports, List<FunctionNod
|
|||||||
funcJoiner.add(fn.name());
|
funcJoiner.add(fn.name());
|
||||||
}
|
}
|
||||||
return "Module(name=" + name
|
return "Module(name=" + name
|
||||||
+ ", imports=[" + importJoiner.toString() + "]"
|
+ ", imports=[" + importJoiner + "]"
|
||||||
+ ", functions=[" + funcJoiner.toString() + "])";
|
+ ", functions=[" + funcJoiner + "])";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
package org.jcnc.snow.compiler.parser.ast;
|
package org.jcnc.snow.compiler.parser.ast;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 所有 AST 节点的标记接口。
|
* 所有抽象语法树(AST)节点的标记接口。
|
||||||
|
* 所有具体的语法节点类型(如表达式、语句、模块、函数等)都应实现该接口。
|
||||||
|
* 该接口本身不定义任何方法,仅用于类型标识和统一处理。
|
||||||
*/
|
*/
|
||||||
public interface Node {}
|
public interface Node {}
|
||||||
|
|||||||
@ -1,10 +1,18 @@
|
|||||||
package org.jcnc.snow.compiler.parser.ast;
|
package org.jcnc.snow.compiler.parser.ast;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 数字字面量表达式节点。
|
* 表示数字字面量的表达式节点,例如 {@code 42} 或 {@code 3.14}。
|
||||||
|
* 该节点直接保存字面量的字符串形式,便于统一处理整数和浮点数。
|
||||||
|
*
|
||||||
|
* @param value 数字的字符串表示形式。
|
||||||
*/
|
*/
|
||||||
public record NumberLiteralNode(String value) implements ExpressionNode {
|
public record NumberLiteralNode(String value) implements ExpressionNode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回数字字面量的字符串形式。
|
||||||
|
*
|
||||||
|
* @return 字面量的原始字符串值。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return value;
|
return value;
|
||||||
|
|||||||
@ -1,12 +1,18 @@
|
|||||||
package org.jcnc.snow.compiler.parser.ast;
|
package org.jcnc.snow.compiler.parser.ast;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 函数参数节点:包含参数名和类型。
|
* 表示函数参数的 AST 节点,包含参数名称和类型。
|
||||||
|
* 示例:在 {@code int add(int a, int b)} 中,{@code a:int} 和 {@code b:int} 都是参数节点。
|
||||||
|
*
|
||||||
|
* @param name 参数名称。
|
||||||
|
* @param type 参数类型(例如 "int"、"string")。
|
||||||
*/
|
*/
|
||||||
public record ParameterNode(String name, String type) implements Node {
|
public record ParameterNode(String name, String type) implements Node {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回参数的字符串表示,例如 "num1:int",便于列表打印。
|
* 返回参数的字符串表示形式,格式为 {@code name:type},如 {@code num:int}。
|
||||||
|
*
|
||||||
|
* @return 参数的字符串表示,适用于调试或打印参数列表。
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|||||||
@ -3,14 +3,31 @@ package org.jcnc.snow.compiler.parser.ast;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return 语句节点:可选返回表达式。
|
* 表示 return 语句的 AST 节点,支持可选的返回值表达式。
|
||||||
|
* 示例:
|
||||||
|
* <ul>
|
||||||
|
* <li>{@code return;}</li>
|
||||||
|
* <li>{@code return x + 1;}</li>
|
||||||
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public class ReturnNode implements StatementNode {
|
public class ReturnNode implements StatementNode {
|
||||||
private final Optional<ExpressionNode> expression;
|
private final Optional<ExpressionNode> expression;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造一个 return 语句节点。
|
||||||
|
*
|
||||||
|
* @param expression 可选的返回表达式,若为 null 则表示无返回值。
|
||||||
|
*/
|
||||||
public ReturnNode(ExpressionNode expression) {
|
public ReturnNode(ExpressionNode expression) {
|
||||||
this.expression = Optional.ofNullable(expression);
|
this.expression = Optional.ofNullable(expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<ExpressionNode> getExpression() { return expression; }
|
/**
|
||||||
|
* 获取返回表达式。
|
||||||
|
*
|
||||||
|
* @return 表示返回值的可选表达式,如果没有则为 {@code Optional.empty()}。
|
||||||
|
*/
|
||||||
|
public Optional<ExpressionNode> getExpression() {
|
||||||
|
return expression;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
package org.jcnc.snow.compiler.parser.ast;
|
package org.jcnc.snow.compiler.parser.ast;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 标记所有语句节点。
|
* 表示语法树中的语句节点类型。
|
||||||
|
* 所有语句类(如声明、赋值、if、loop、return 等)都应实现该接口。
|
||||||
|
* 这是一个标记接口(marker interface),用于统一处理所有语句节点。
|
||||||
*/
|
*/
|
||||||
public interface StatementNode extends Node {}
|
public interface StatementNode extends Node {}
|
||||||
|
|||||||
@ -1,15 +1,18 @@
|
|||||||
package org.jcnc.snow.compiler.parser.ast;
|
package org.jcnc.snow.compiler.parser.ast;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字符串字面量表达式节点,如 "hello"。
|
* 表示字符串字面量的表达式节点,例如 {@code "hello"}。
|
||||||
|
* 字面量值不包含引号,仅在打印时添加。
|
||||||
*
|
*
|
||||||
* @param value 不包含引号的字符串内容
|
* @param value 字符串内容,不包括两端引号。
|
||||||
*/
|
*/
|
||||||
public record StringLiteralNode(String value) implements ExpressionNode {
|
public record StringLiteralNode(String value) implements ExpressionNode {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 打印时在两端加上引号,
|
* 返回带引号的字符串表示形式,适用于调试和打印。
|
||||||
* 例如 value = Result:,则 toString() 返回 "Result:"。
|
* 例如:如果 {@code value = Result:},则 {@code toString()} 返回 {@code "Result:"}。
|
||||||
|
*
|
||||||
|
* @return 添加双引号后的字符串字面量。
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
|||||||
@ -1,9 +1,16 @@
|
|||||||
package org.jcnc.snow.compiler.parser.context;
|
package org.jcnc.snow.compiler.parser.context;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析时抛出的异常,用于语法错误报告。
|
* 表示解析过程中发生的异常,通常用于报告语法错误。
|
||||||
|
* 在语法分析器发现非法语法或无法处理的结构时抛出。
|
||||||
*/
|
*/
|
||||||
public class ParseException extends RuntimeException {
|
public class ParseException extends RuntimeException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造一个解析异常实例,并提供错误消息。
|
||||||
|
*
|
||||||
|
* @param message 错误描述信息,用于指出语法错误的详情。
|
||||||
|
*/
|
||||||
public ParseException(String message) {
|
public ParseException(String message) {
|
||||||
super(message);
|
super(message);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,15 +4,26 @@ import org.jcnc.snow.compiler.lexer.token.Token;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parser 共享上下文,包含 TokenStream,可扩展错误收集、符号表等功能。
|
* 表示解析器的共享上下文,封装了当前的 {@link TokenStream}。
|
||||||
|
* 后续还可以扩展为包含错误收集器、符号表、作用域信息等。
|
||||||
*/
|
*/
|
||||||
public class ParserContext {
|
public class ParserContext {
|
||||||
private final TokenStream tokens;
|
private final TokenStream tokens;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造解析上下文,并包装传入的词法单元列表为 {@link TokenStream}。
|
||||||
|
*
|
||||||
|
* @param tokens 词法分析器生成的 token 列表。
|
||||||
|
*/
|
||||||
public ParserContext(List<Token> tokens) {
|
public ParserContext(List<Token> tokens) {
|
||||||
this.tokens = new TokenStream(tokens);
|
this.tokens = new TokenStream(tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前的 Token 流,用于驱动语法解析过程。
|
||||||
|
*
|
||||||
|
* @return token 流实例。
|
||||||
|
*/
|
||||||
public TokenStream getTokens() {
|
public TokenStream getTokens() {
|
||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,18 +6,29 @@ import org.jcnc.snow.compiler.lexer.token.TokenType;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 封装 Token 列表并维护当前位置,提供 peek/next/match/expect 等操作,
|
* 封装 Token 列表并维护当前位置,用于解析器消费 Token 的工具类。
|
||||||
* 现在新增 peek(offset) 以便在解析赋值时向前看一个 Token。
|
* 提供常见的操作如 {@code peek}(查看)、{@code next}(消费)、{@code match}(匹配)、
|
||||||
|
* {@code expect}(断言)等,支持向前查看多个 Token 以实现前瞻解析。
|
||||||
*/
|
*/
|
||||||
public class TokenStream {
|
public class TokenStream {
|
||||||
private final List<Token> tokens;
|
private final List<Token> tokens;
|
||||||
private int pos = 0;
|
private int pos = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造 Token 流对象。
|
||||||
|
*
|
||||||
|
* @param tokens 从词法分析器生成的 Token 列表。
|
||||||
|
*/
|
||||||
public TokenStream(List<Token> tokens) {
|
public TokenStream(List<Token> tokens) {
|
||||||
this.tokens = tokens;
|
this.tokens = tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 向前 offset 个位置的 Token,不消费 */
|
/**
|
||||||
|
* 向前查看指定偏移量的 Token(不消费)。
|
||||||
|
*
|
||||||
|
* @param offset 相对于当前位置的偏移量(例如 0 表示当前位置)。
|
||||||
|
* @return 对应位置的 Token,如果越界则返回 EOF Token。
|
||||||
|
*/
|
||||||
public Token peek(int offset) {
|
public Token peek(int offset) {
|
||||||
int idx = pos + offset;
|
int idx = pos + offset;
|
||||||
if (idx >= tokens.size()) {
|
if (idx >= tokens.size()) {
|
||||||
@ -26,19 +37,32 @@ public class TokenStream {
|
|||||||
return tokens.get(idx);
|
return tokens.get(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 默认 peek(0) */
|
/**
|
||||||
|
* 查看当前位置的 Token,等价于 {@code peek(0)}。
|
||||||
|
*
|
||||||
|
* @return 当前 Token。
|
||||||
|
*/
|
||||||
public Token peek() {
|
public Token peek() {
|
||||||
return peek(0);
|
return peek(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 消费并返回当前 Token */
|
/**
|
||||||
|
* 消费并返回当前位置的 Token,内部位置前移。
|
||||||
|
*
|
||||||
|
* @return 当前的 Token。
|
||||||
|
*/
|
||||||
public Token next() {
|
public Token next() {
|
||||||
Token t = peek();
|
Token t = peek();
|
||||||
pos++;
|
pos++;
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 如果当前词素等于 lexeme,则消费并返回 true */
|
/**
|
||||||
|
* 如果当前 Token 的词素等于指定字符串,则消费该 Token 并返回 true。
|
||||||
|
*
|
||||||
|
* @param lexeme 要匹配的词素。
|
||||||
|
* @return 是否成功匹配。
|
||||||
|
*/
|
||||||
public boolean match(String lexeme) {
|
public boolean match(String lexeme) {
|
||||||
if (peek().getLexeme().equals(lexeme)) {
|
if (peek().getLexeme().equals(lexeme)) {
|
||||||
next();
|
next();
|
||||||
@ -47,7 +71,13 @@ public class TokenStream {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 断言 lexeme,否则抛错 */
|
/**
|
||||||
|
* 断言当前 Token 的词素等于指定字符串,否则抛出 {@link ParseException}。
|
||||||
|
*
|
||||||
|
* @param lexeme 期望的词素。
|
||||||
|
* @return 匹配的 Token。
|
||||||
|
* @throws ParseException 如果词素不匹配。
|
||||||
|
*/
|
||||||
public Token expect(String lexeme) {
|
public Token expect(String lexeme) {
|
||||||
Token t = peek();
|
Token t = peek();
|
||||||
if (!t.getLexeme().equals(lexeme)) {
|
if (!t.getLexeme().equals(lexeme)) {
|
||||||
@ -59,7 +89,13 @@ public class TokenStream {
|
|||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 断言类型,否则抛错 */
|
/**
|
||||||
|
* 断言当前 Token 的类型等于指定类型,否则抛出 {@link ParseException}。
|
||||||
|
*
|
||||||
|
* @param type 期望的 Token 类型。
|
||||||
|
* @return 匹配的 Token。
|
||||||
|
* @throws ParseException 如果类型不匹配。
|
||||||
|
*/
|
||||||
public Token expectType(TokenType type) {
|
public Token expectType(TokenType type) {
|
||||||
Token t = peek();
|
Token t = peek();
|
||||||
if (t.getType() != type) {
|
if (t.getType() != type) {
|
||||||
@ -71,6 +107,11 @@ public class TokenStream {
|
|||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断是否还未到达文件结尾(EOF)。
|
||||||
|
*
|
||||||
|
* @return 如果当前位置的 Token 不是 EOF,则返回 true。
|
||||||
|
*/
|
||||||
public boolean isAtEnd() {
|
public boolean isAtEnd() {
|
||||||
return peek().getType() != TokenType.EOF;
|
return peek().getType() != TokenType.EOF;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,29 +6,48 @@ import org.jcnc.snow.compiler.lexer.token.Token;
|
|||||||
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析二元运算符表达式,支持左/右结合。
|
* 表示中缀二元运算符的解析规则(parselet),用于解析如 {@code a + b} 的表达式结构。
|
||||||
|
* 支持设置运算符的优先级和结合性(左结合或右结合)。
|
||||||
*/
|
*/
|
||||||
public class BinaryOperatorParselet implements InfixParselet {
|
public class BinaryOperatorParselet implements InfixParselet {
|
||||||
private final Precedence precedence;
|
private final Precedence precedence;
|
||||||
private final boolean leftAssoc;
|
private final boolean leftAssoc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造二元运算符的解析器。
|
||||||
|
*
|
||||||
|
* @param precedence 运算符的优先级。
|
||||||
|
* @param leftAssoc 是否是左结合(true 表示左结合,false 表示右结合)。
|
||||||
|
*/
|
||||||
public BinaryOperatorParselet(Precedence precedence, boolean leftAssoc) {
|
public BinaryOperatorParselet(Precedence precedence, boolean leftAssoc) {
|
||||||
this.precedence = precedence;
|
this.precedence = precedence;
|
||||||
this.leftAssoc = leftAssoc;
|
this.leftAssoc = leftAssoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析一个中缀表达式。
|
||||||
|
*
|
||||||
|
* @param ctx 解析上下文,包含 Token 流等信息。
|
||||||
|
* @param left 当前已解析出的左表达式。
|
||||||
|
* @return 一个新的 {@link BinaryExpressionNode} 表达式节点。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ExpressionNode parse(ParserContext ctx, ExpressionNode left) {
|
public ExpressionNode parse(ParserContext ctx, ExpressionNode left) {
|
||||||
Token op = ctx.getTokens().next();
|
Token op = ctx.getTokens().next(); // 获取当前运算符 Token
|
||||||
int prec = precedence.ordinal();
|
int prec = precedence.ordinal();
|
||||||
// 若左结合,则右侧优先级减一
|
// 如果是左结合运算符,右表达式的优先级应减一(右边绑定更紧)
|
||||||
ExpressionNode right = new PrattExpressionParser().parseExpression(
|
ExpressionNode right = new PrattExpressionParser().parseExpression(
|
||||||
ctx,
|
ctx,
|
||||||
leftAssoc ? Precedence.values()[prec] : Precedence.values()[prec - 1]
|
leftAssoc ? Precedence.values()[prec] : Precedence.values()[prec - 1]
|
||||||
);
|
);
|
||||||
return new BinaryExpressionNode(left, op.getLexeme(), right);
|
return new BinaryExpressionNode(left, op.getLexeme(), right);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回该运算符的优先级。
|
||||||
|
*
|
||||||
|
* @return 当前运算符的优先级枚举。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Precedence getPrecedence() {
|
public Precedence getPrecedence() {
|
||||||
return precedence;
|
return precedence;
|
||||||
|
|||||||
@ -8,23 +8,40 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析函数调用:left ( args… )
|
* 表示函数调用的解析规则(parselet),用于解析形如 {@code foo(arg1, arg2)} 的调用表达式。
|
||||||
|
* 函数调用的结构为:已解析的 callee 表达式后接一对圆括号和参数列表。
|
||||||
*/
|
*/
|
||||||
public class CallParselet implements InfixParselet {
|
public class CallParselet implements InfixParselet {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析函数调用表达式,形如 {@code callee(args...)}。
|
||||||
|
*
|
||||||
|
* @param ctx 解析上下文,包含 Token 流等信息。
|
||||||
|
* @param left 已解析的函数名或调用目标(即 callee 表达式)。
|
||||||
|
* @return 生成的 {@link CallExpressionNode} 表达式节点。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ExpressionNode parse(ParserContext ctx, ExpressionNode left) {
|
public ExpressionNode parse(ParserContext ctx, ExpressionNode left) {
|
||||||
// 已知 peek 是 "("
|
ctx.getTokens().next(); // 消费 "("
|
||||||
ctx.getTokens().next(); // consume "("
|
|
||||||
List<ExpressionNode> args = new ArrayList<>();
|
List<ExpressionNode> args = new ArrayList<>();
|
||||||
|
|
||||||
|
// 如果不是空参数列表
|
||||||
if (!ctx.getTokens().peek().getLexeme().equals(")")) {
|
if (!ctx.getTokens().peek().getLexeme().equals(")")) {
|
||||||
do {
|
do {
|
||||||
args.add(new PrattExpressionParser().parse(ctx));
|
args.add(new PrattExpressionParser().parse(ctx));
|
||||||
} while (ctx.getTokens().match(","));
|
} while (ctx.getTokens().match(",")); // 支持多个参数,用逗号分隔
|
||||||
}
|
}
|
||||||
ctx.getTokens().expect(")");
|
|
||||||
|
ctx.getTokens().expect(")"); // 消费并校验 ")"
|
||||||
return new CallExpressionNode(left, args);
|
return new CallExpressionNode(left, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取函数调用的优先级,通常是最高级别之一。
|
||||||
|
*
|
||||||
|
* @return {@link Precedence#CALL} 表示函数调用的绑定紧密度。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Precedence getPrecedence() {
|
public Precedence getPrecedence() {
|
||||||
return Precedence.CALL;
|
return Precedence.CALL;
|
||||||
|
|||||||
@ -4,8 +4,16 @@ import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
|
|||||||
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 表达式解析接口。
|
* 表达式解析器接口,用于从 {@link ParserContext} 中解析出一个完整的 {@link ExpressionNode} 表达式。
|
||||||
|
* 不同的解析器实现可以支持不同的解析策略(如 Pratt 解析、递归下降等)。
|
||||||
*/
|
*/
|
||||||
public interface ExpressionParser {
|
public interface ExpressionParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从解析上下文中解析一个表达式。
|
||||||
|
*
|
||||||
|
* @param ctx 当前的解析上下文。
|
||||||
|
* @return 解析后的表达式节点。
|
||||||
|
*/
|
||||||
ExpressionNode parse(ParserContext ctx);
|
ExpressionNode parse(ParserContext ctx);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,9 +5,18 @@ import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
|
|||||||
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析括号表达式: ( expr )
|
* 解析圆括号包裹的表达式,例如 {@code (a + b)}。
|
||||||
|
* 用于提升子表达式的优先级,使其在整体表达式中优先计算。
|
||||||
*/
|
*/
|
||||||
public class GroupingParselet implements PrefixParselet {
|
public class GroupingParselet implements PrefixParselet {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析括号表达式。假定当前 token 是左括号 "(",解析中间的表达式并消费右括号 ")"。
|
||||||
|
*
|
||||||
|
* @param ctx 当前解析上下文。
|
||||||
|
* @param token 当前起始 token(应为 "(")。
|
||||||
|
* @return 被括号包围的表达式节点。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ExpressionNode parse(ParserContext ctx, Token token) {
|
public ExpressionNode parse(ParserContext ctx, Token token) {
|
||||||
ExpressionNode expr = new PrattExpressionParser().parse(ctx);
|
ExpressionNode expr = new PrattExpressionParser().parse(ctx);
|
||||||
|
|||||||
@ -6,9 +6,18 @@ import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
|
|||||||
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析标识符。
|
* 用于解析标识符(identifier)的前缀解析器。
|
||||||
|
* 例如:变量名、函数名等单词形式的表达式,如 {@code x}、{@code count}、{@code isValid} 等。
|
||||||
*/
|
*/
|
||||||
public class IdentifierParselet implements PrefixParselet {
|
public class IdentifierParselet implements PrefixParselet {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将当前的标识符 Token 解析为 {@link IdentifierNode} 表达式节点。
|
||||||
|
*
|
||||||
|
* @param ctx 当前解析上下文(未使用)。
|
||||||
|
* @param token 当前的标识符 Token。
|
||||||
|
* @return 一个表示标识符的表达式节点。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ExpressionNode parse(ParserContext ctx, Token token) {
|
public ExpressionNode parse(ParserContext ctx, Token token) {
|
||||||
return new IdentifierNode(token.getLexeme());
|
return new IdentifierNode(token.getLexeme());
|
||||||
|
|||||||
@ -4,9 +4,26 @@ import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
|
|||||||
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 中缀解析器接口:处理二元运算、函数调用、成员访问等。
|
* 中缀解析器接口(InfixParselet),用于处理中缀表达式的解析逻辑。
|
||||||
|
* 例如二元运算符(如 {@code a + b})、函数调用(如 {@code f(x)})或成员访问(如 {@code obj.prop})。
|
||||||
|
* 实现类需提供解析方法及该表达式的优先级。
|
||||||
*/
|
*/
|
||||||
public interface InfixParselet {
|
public interface InfixParselet {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析一个中缀表达式。
|
||||||
|
*
|
||||||
|
* @param ctx 解析上下文。
|
||||||
|
* @param left 当前已解析的左侧表达式。
|
||||||
|
* @return 组合后的完整表达式节点。
|
||||||
|
*/
|
||||||
ExpressionNode parse(ParserContext ctx, ExpressionNode left);
|
ExpressionNode parse(ParserContext ctx, ExpressionNode left);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前中缀表达式的优先级。
|
||||||
|
* 优先级用于决定运算符的绑定顺序。
|
||||||
|
*
|
||||||
|
* @return 表达式的优先级。
|
||||||
|
*/
|
||||||
Precedence getPrecedence();
|
Precedence getPrecedence();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,21 +7,35 @@ import org.jcnc.snow.compiler.parser.context.ParserContext;
|
|||||||
import org.jcnc.snow.compiler.parser.context.TokenStream;
|
import org.jcnc.snow.compiler.parser.context.TokenStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析成员访问表达式: left . IDENTIFIER
|
* 用于解析成员访问表达式的中缀解析器,例如 {@code object.property}。
|
||||||
|
* 成员访问是一种紧绑定表达式,常用于访问对象的字段或方法。
|
||||||
*/
|
*/
|
||||||
public class MemberParselet implements InfixParselet {
|
public class MemberParselet implements InfixParselet {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析成员访问表达式,形如 {@code left.member}。
|
||||||
|
*
|
||||||
|
* @param ctx 解析上下文。
|
||||||
|
* @param left 已解析的左侧表达式(对象)。
|
||||||
|
* @return 一个 {@link MemberExpressionNode} 表示成员访问的表达式。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ExpressionNode parse(ParserContext ctx, ExpressionNode left) {
|
public ExpressionNode parse(ParserContext ctx, ExpressionNode left) {
|
||||||
TokenStream ts = ctx.getTokens();
|
TokenStream ts = ctx.getTokens();
|
||||||
// 消费掉 "."
|
ts.expect("."); // 消费点号
|
||||||
ts.expect(".");
|
// 接下来应为标识符
|
||||||
// 现在下一个一定是标识符
|
|
||||||
String member = ts
|
String member = ts
|
||||||
.expectType(TokenType.IDENTIFIER)
|
.expectType(TokenType.IDENTIFIER)
|
||||||
.getLexeme();
|
.getLexeme();
|
||||||
return new MemberExpressionNode(left, member);
|
return new MemberExpressionNode(left, member);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取成员访问表达式的优先级。
|
||||||
|
* 与函数调用一样,通常具有较高的优先级。
|
||||||
|
*
|
||||||
|
* @return {@link Precedence#CALL},表示高优先级。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Precedence getPrecedence() {
|
public Precedence getPrecedence() {
|
||||||
return Precedence.CALL;
|
return Precedence.CALL;
|
||||||
|
|||||||
@ -6,9 +6,18 @@ import org.jcnc.snow.compiler.parser.ast.ExpressionNode;
|
|||||||
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析数字字面量。
|
* 用于解析数字字面量的前缀解析器。
|
||||||
|
* 例如 {@code 42}、{@code 3.14} 等常量数值表达式。
|
||||||
*/
|
*/
|
||||||
public class NumberLiteralParselet implements PrefixParselet {
|
public class NumberLiteralParselet implements PrefixParselet {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析一个数字字面量 Token,转换为 {@link NumberLiteralNode} 表达式节点。
|
||||||
|
*
|
||||||
|
* @param ctx 当前解析上下文(未使用)。
|
||||||
|
* @param token 当前的数字 Token。
|
||||||
|
* @return 表示数字字面量的表达式节点。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ExpressionNode parse(ParserContext ctx, Token token) {
|
public ExpressionNode parse(ParserContext ctx, Token token) {
|
||||||
return new NumberLiteralNode(token.getLexeme());
|
return new NumberLiteralNode(token.getLexeme());
|
||||||
|
|||||||
@ -9,45 +9,61 @@ import java.util.HashMap;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pratt 算法实现的表达式解析器,支持算术、比较、调用、成员访问、字面量等。
|
* 基于 Pratt 算法的表达式解析器,实现灵活优雅的运算符优先级与结合性处理。
|
||||||
|
* 支持数字、字符串、标识符、分组表达式、二元运算、函数调用、成员访问等。
|
||||||
*/
|
*/
|
||||||
public class PrattExpressionParser implements ExpressionParser {
|
public class PrattExpressionParser implements ExpressionParser {
|
||||||
|
|
||||||
private static final Map<String, PrefixParselet> prefixes = new HashMap<>();
|
private static final Map<String, PrefixParselet> prefixes = new HashMap<>();
|
||||||
private static final Map<String, InfixParselet> infixes = new HashMap<>();
|
private static final Map<String, InfixParselet> infixes = new HashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// 注册前缀 parselet
|
// 注册前缀解析器(PrefixParselet)
|
||||||
prefixes.put(TokenType.NUMBER_LITERAL.name(), new NumberLiteralParselet());
|
prefixes.put(TokenType.NUMBER_LITERAL.name(), new NumberLiteralParselet());
|
||||||
prefixes.put(TokenType.IDENTIFIER.name(), new IdentifierParselet());
|
prefixes.put(TokenType.IDENTIFIER.name(), new IdentifierParselet());
|
||||||
prefixes.put(TokenType.LPAREN.name(), new GroupingParselet());
|
prefixes.put(TokenType.LPAREN.name(), new GroupingParselet());
|
||||||
prefixes.put(TokenType.STRING_LITERAL.name(), new StringLiteralParselet()); // 新增
|
prefixes.put(TokenType.STRING_LITERAL.name(), new StringLiteralParselet()); // 字符串字面量支持
|
||||||
|
|
||||||
// 注册中缀 parselet(略,保持原样)
|
// 注册中缀解析器(InfixParselet)
|
||||||
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.PRODUCT, true));
|
infixes.put("*", new BinaryOperatorParselet(Precedence.PRODUCT, 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 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 CallParselet());
|
||||||
infixes.put(".", new MemberParselet());
|
infixes.put(".", new MemberParselet());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析完整表达式,入口方法,使用最低优先级启动解析。
|
||||||
|
*
|
||||||
|
* @param ctx 解析上下文。
|
||||||
|
* @return 表达式节点。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ExpressionNode parse(ParserContext ctx) {
|
public ExpressionNode parse(ParserContext ctx) {
|
||||||
return parseExpression(ctx, Precedence.LOWEST);
|
return parseExpression(ctx, Precedence.LOWEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据当前优先级解析表达式。
|
||||||
|
*
|
||||||
|
* @param ctx 解析上下文。
|
||||||
|
* @param prec 当前解析优先级。
|
||||||
|
* @return 表达式节点。
|
||||||
|
*/
|
||||||
ExpressionNode parseExpression(ParserContext ctx, Precedence prec) {
|
ExpressionNode parseExpression(ParserContext ctx, Precedence prec) {
|
||||||
Token token = ctx.getTokens().next();
|
Token token = ctx.getTokens().next();
|
||||||
PrefixParselet prefix = prefixes.get(token.getType().name());
|
PrefixParselet prefix = prefixes.get(token.getType().name());
|
||||||
if (prefix == null) {
|
if (prefix == null) {
|
||||||
throw new IllegalStateException("No prefix for " + token.getType());
|
throw new IllegalStateException("No prefix parselet registered for token type: " + token.getType());
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpressionNode left = prefix.parse(ctx, token);
|
ExpressionNode left = prefix.parse(ctx, token);
|
||||||
|
|
||||||
while (ctx.getTokens().isAtEnd() &&
|
while (ctx.getTokens().isAtEnd() &&
|
||||||
@ -55,11 +71,19 @@ public class PrattExpressionParser implements ExpressionParser {
|
|||||||
String lex = ctx.getTokens().peek().getLexeme();
|
String lex = ctx.getTokens().peek().getLexeme();
|
||||||
InfixParselet infix = infixes.get(lex);
|
InfixParselet infix = infixes.get(lex);
|
||||||
if (infix == null) break;
|
if (infix == null) break;
|
||||||
|
|
||||||
left = infix.parse(ctx, left);
|
left = infix.parse(ctx, left);
|
||||||
}
|
}
|
||||||
|
|
||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取下一个中缀运算符的优先级。
|
||||||
|
*
|
||||||
|
* @param ctx 当前解析上下文。
|
||||||
|
* @return 若存在下一个中缀解析器,则返回其优先级 ordinal;否则返回 -1。
|
||||||
|
*/
|
||||||
private int nextPrecedence(ParserContext ctx) {
|
private int nextPrecedence(ParserContext ctx) {
|
||||||
InfixParselet infix = infixes.get(ctx.getTokens().peek().getLexeme());
|
InfixParselet infix = infixes.get(ctx.getTokens().peek().getLexeme());
|
||||||
return infix != null ? infix.getPrecedence().ordinal() : -1;
|
return infix != null ? infix.getPrecedence().ordinal() : -1;
|
||||||
|
|||||||
@ -1,11 +1,27 @@
|
|||||||
package org.jcnc.snow.compiler.parser.expression;
|
package org.jcnc.snow.compiler.parser.expression;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 运算符优先级枚举,用于 Pratt 算法比较。
|
* 表示运算符优先级的枚举类型,用于 Pratt 解析算法中比较不同运算符的绑定紧密度。
|
||||||
|
* 数值越大,优先级越高。
|
||||||
*/
|
*/
|
||||||
public enum Precedence {
|
public enum Precedence {
|
||||||
LOWEST, // 最低
|
/**
|
||||||
SUM, // + -
|
* 最低优先级,通常用于解析入口。
|
||||||
PRODUCT, // * /
|
*/
|
||||||
CALL // 函数调用、成员访问
|
LOWEST,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 加法、减法等二元运算(+,-)。
|
||||||
|
*/
|
||||||
|
SUM,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 乘法、除法等优先级更高的二元运算(*,/)。
|
||||||
|
*/
|
||||||
|
PRODUCT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 函数调用、成员访问(例如 {@code foo()}、{@code obj.prop}),绑定最紧密。
|
||||||
|
*/
|
||||||
|
CALL
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,8 +5,17 @@ import org.jcnc.snow.compiler.parser.context.ParserContext;
|
|||||||
import org.jcnc.snow.compiler.lexer.token.Token;
|
import org.jcnc.snow.compiler.lexer.token.Token;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 前缀解析器接口:处理数字字面量、标识符、括号等前缀。
|
* 前缀解析器接口(PrefixParselet),用于解析以当前 Token 开头的前缀表达式。
|
||||||
|
* 典型的前缀表达式包括数字字面量、标识符、括号表达式、前缀运算符等。
|
||||||
*/
|
*/
|
||||||
public interface PrefixParselet {
|
public interface PrefixParselet {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析一个前缀表达式。
|
||||||
|
*
|
||||||
|
* @param ctx 当前的解析上下文。
|
||||||
|
* @param token 当前的前缀 Token。
|
||||||
|
* @return 解析得到的表达式节点。
|
||||||
|
*/
|
||||||
ExpressionNode parse(ParserContext ctx, Token token);
|
ExpressionNode parse(ParserContext ctx, Token token);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,15 +6,23 @@ import org.jcnc.snow.compiler.parser.ast.StringLiteralNode;
|
|||||||
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
import org.jcnc.snow.compiler.parser.context.ParserContext;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析字符串字面量前缀,并去掉两端的引号。
|
* 用于解析字符串字面量的前缀解析器。
|
||||||
|
* 会从原始 Token 中提取内容,并去除两端的引号。
|
||||||
|
* 例如,Token 为 {@code "\"hello\""},则解析为 {@code StringLiteralNode("hello")}。
|
||||||
*/
|
*/
|
||||||
public class StringLiteralParselet implements PrefixParselet {
|
public class StringLiteralParselet implements PrefixParselet {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析字符串字面量 Token,去除包裹的引号,生成 {@link StringLiteralNode}。
|
||||||
|
*
|
||||||
|
* @param ctx 当前解析上下文(未使用)。
|
||||||
|
* @param token 当前字符串字面量 Token,包含带引号的原始文本。
|
||||||
|
* @return 解析后的字符串字面量表达式节点。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ExpressionNode parse(ParserContext ctx, Token token) {
|
public ExpressionNode parse(ParserContext ctx, Token token) {
|
||||||
// token.getRaw() 包含原始 "\"Result:\""
|
String raw = token.getRaw(); // 包含引号的原始字符串,例如 "\"Result:\""
|
||||||
String raw = token.getRaw();
|
String content = raw.substring(1, raw.length() - 1); // 去除前后引号
|
||||||
// 去掉首尾引号
|
|
||||||
String content = raw.substring(1, raw.length() - 1);
|
|
||||||
return new StringLiteralNode(content);
|
return new StringLiteralNode(content);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,24 +1,34 @@
|
|||||||
package org.jcnc.snow.compiler.parser.factory;
|
package org.jcnc.snow.compiler.parser.factory;
|
||||||
|
|
||||||
import org.jcnc.snow.compiler.parser.statement.*;
|
import org.jcnc.snow.compiler.parser.statement.*;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 语句解析器工厂:关键字 → 对应 StatementParser。
|
* 语句解析器工厂类,用于根据关键字(如 "if"、"loop")返回对应的 {@link StatementParser} 实例。
|
||||||
|
* 所有语句解析器在静态代码块中预先注册。
|
||||||
|
* 若关键字未注册,则默认返回 {@link ExpressionStatementParser}(空字符串对应)。
|
||||||
*/
|
*/
|
||||||
public class StatementParserFactory {
|
public class StatementParserFactory {
|
||||||
private static final Map<String, StatementParser> registry = new HashMap<>();
|
private static final Map<String, StatementParser> registry = new HashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
// 注册各类语句解析器
|
||||||
registry.put("declare", new DeclarationStatementParser());
|
registry.put("declare", new DeclarationStatementParser());
|
||||||
registry.put("if", new IfStatementParser());
|
registry.put("if", new IfStatementParser());
|
||||||
registry.put("loop", new LoopStatementParser());
|
registry.put("loop", new LoopStatementParser());
|
||||||
registry.put("return", new ReturnStatementParser());
|
registry.put("return", new ReturnStatementParser());
|
||||||
// 默认使用表达式语句
|
// 默认解析器:表达式语句
|
||||||
registry.put("", new ExpressionStatementParser());
|
registry.put("", new ExpressionStatementParser());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据语句关键字获取对应的语句解析器。
|
||||||
|
*
|
||||||
|
* @param keyword 语句开头的关键字,例如 "if"、"loop"、"declare"。
|
||||||
|
* @return 对应的 {@link StatementParser} 实例,若无匹配则返回默认解析器。
|
||||||
|
*/
|
||||||
public static StatementParser get(String keyword) {
|
public static StatementParser get(String keyword) {
|
||||||
return registry.getOrDefault(keyword, registry.get(""));
|
return registry.getOrDefault(keyword, registry.get(""));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,16 +7,25 @@ import java.util.Map;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 顶层解析器工厂:根据首个关键字(如 module)分发对应解析器。
|
* 顶层解析器工厂类,用于根据文件开头的关键字(如 {@code module})分发对应的顶层结构解析器。
|
||||||
|
* 每种顶层结构(模块、导入等)应有一个专门的 {@link TopLevelParser} 实现类。
|
||||||
*/
|
*/
|
||||||
public class TopLevelParserFactory {
|
public class TopLevelParserFactory {
|
||||||
private static final Map<String, TopLevelParser> registry = new HashMap<>();
|
private static final Map<String, TopLevelParser> registry = new HashMap<>();
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
// 注册模块解析器
|
||||||
registry.put("module", new ModuleParser());
|
registry.put("module", new ModuleParser());
|
||||||
// 如需支持 standalone import,可在此注册
|
|
||||||
|
// import、package 在此添加注册项
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据顶层关键字获取对应的解析器。
|
||||||
|
*
|
||||||
|
* @param keyword 顶层结构的关键字(如 "module")。
|
||||||
|
* @return 对应的 {@link TopLevelParser} 实例;若未注册,则返回 null。
|
||||||
|
*/
|
||||||
public static TopLevelParser get(String keyword) {
|
public static TopLevelParser get(String keyword) {
|
||||||
return registry.get(keyword);
|
return registry.get(keyword);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,14 +11,29 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析 function 块:
|
* 用于解析函数定义块(function),包括函数名、参数列表、返回类型、函数体等。
|
||||||
* function: NAME NEWLINE
|
* 支持的语法结构示例:
|
||||||
* parameter: (declare name:type | name:type)*
|
* <pre>{@code
|
||||||
* return_type: TYPE NEWLINE
|
* function: myFunc
|
||||||
* body: ... end body
|
* parameter:
|
||||||
* end function NEWLINE
|
* declare a:int
|
||||||
|
* b:int
|
||||||
|
* return_type: int
|
||||||
|
* body:
|
||||||
|
* declare x:int = 10
|
||||||
|
* return x
|
||||||
|
* end body
|
||||||
|
* end function
|
||||||
|
* }</pre>
|
||||||
*/
|
*/
|
||||||
public class FunctionParser implements TopLevelParser {
|
public class FunctionParser implements TopLevelParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析一个函数定义并返回对应的 {@link FunctionNode}。
|
||||||
|
*
|
||||||
|
* @param ctx 解析上下文。
|
||||||
|
* @return 解析生成的函数节点。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public FunctionNode parse(ParserContext ctx) {
|
public FunctionNode parse(ParserContext ctx) {
|
||||||
TokenStream ts = ctx.getTokens();
|
TokenStream ts = ctx.getTokens();
|
||||||
@ -27,7 +42,7 @@ public class FunctionParser implements TopLevelParser {
|
|||||||
String name = ts.expectType(TokenType.IDENTIFIER).getLexeme();
|
String name = ts.expectType(TokenType.IDENTIFIER).getLexeme();
|
||||||
ts.expectType(TokenType.NEWLINE);
|
ts.expectType(TokenType.NEWLINE);
|
||||||
|
|
||||||
// 参数列表
|
// 解析参数列表
|
||||||
ts.expect("parameter");
|
ts.expect("parameter");
|
||||||
ts.expect(":");
|
ts.expect(":");
|
||||||
ts.expectType(TokenType.NEWLINE);
|
ts.expectType(TokenType.NEWLINE);
|
||||||
@ -41,7 +56,7 @@ public class FunctionParser implements TopLevelParser {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if ("declare".equals(ts.peek().getLexeme())) {
|
if ("declare".equals(ts.peek().getLexeme())) {
|
||||||
ts.next(); // consume 'declare'
|
ts.next(); // 支持 declare 前缀
|
||||||
}
|
}
|
||||||
String paramName = ts.expectType(TokenType.IDENTIFIER).getLexeme();
|
String paramName = ts.expectType(TokenType.IDENTIFIER).getLexeme();
|
||||||
ts.expect(":");
|
ts.expect(":");
|
||||||
@ -50,25 +65,25 @@ public class FunctionParser implements TopLevelParser {
|
|||||||
params.add(new ParameterNode(paramName, paramType));
|
params.add(new ParameterNode(paramName, paramType));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 返回类型
|
// 解析返回类型
|
||||||
ts.expect("return_type");
|
ts.expect("return_type");
|
||||||
ts.expect(":");
|
ts.expect(":");
|
||||||
String returnType = ts.expectType(TokenType.TYPE).getLexeme();
|
String returnType = ts.expectType(TokenType.TYPE).getLexeme();
|
||||||
ts.expectType(TokenType.NEWLINE);
|
ts.expectType(TokenType.NEWLINE);
|
||||||
|
|
||||||
// 函数体解析
|
// 解析函数体
|
||||||
ts.expect("body");
|
ts.expect("body");
|
||||||
ts.expect(":");
|
ts.expect(":");
|
||||||
ts.expectType(TokenType.NEWLINE);
|
ts.expectType(TokenType.NEWLINE);
|
||||||
List<StatementNode> body = new ArrayList<>();
|
List<StatementNode> body = new ArrayList<>();
|
||||||
parseBody(ctx, body);
|
parseBody(ctx, body);
|
||||||
|
|
||||||
// end body
|
// 解析函数体结束标识
|
||||||
ts.expect("end");
|
ts.expect("end");
|
||||||
ts.expect("body");
|
ts.expect("body");
|
||||||
ts.expectType(TokenType.NEWLINE);
|
ts.expectType(TokenType.NEWLINE);
|
||||||
|
|
||||||
// end function
|
// 解析函数定义结束标识
|
||||||
ts.expect("end");
|
ts.expect("end");
|
||||||
ts.expect("function");
|
ts.expect("function");
|
||||||
ts.expectType(TokenType.NEWLINE);
|
ts.expectType(TokenType.NEWLINE);
|
||||||
@ -77,7 +92,10 @@ public class FunctionParser implements TopLevelParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 辅助方法:根据 ParserContext 解析函数体中所有语句,直到遇到 end
|
* 辅助方法:从上下文中解析函数体,直到遇到 "end"。
|
||||||
|
*
|
||||||
|
* @param ctx 当前解析上下文。
|
||||||
|
* @param body 存放解析出的语句节点的列表。
|
||||||
*/
|
*/
|
||||||
private void parseBody(ParserContext ctx, List<StatementNode> body) {
|
private void parseBody(ParserContext ctx, List<StatementNode> body) {
|
||||||
TokenStream ts = ctx.getTokens();
|
TokenStream ts = ctx.getTokens();
|
||||||
@ -90,7 +108,8 @@ public class FunctionParser implements TopLevelParser {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
String key = ts.peek().getLexeme();
|
String key = ts.peek().getLexeme();
|
||||||
body.add(StatementParserFactory.get(key).parse(ctx));
|
StatementNode stmt = StatementParserFactory.get(key).parse(ctx);
|
||||||
|
body.add(stmt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,27 +8,36 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析 import 语句:import: MOD1, MOD2, ... NEWLINE
|
* 负责解析 import 语句的解析器。
|
||||||
* 可以在一行声明多个模块,用逗号分隔。
|
* 支持在一行中导入多个模块,格式如:
|
||||||
|
* {@code import: mod1, mod2, mod3}
|
||||||
*/
|
*/
|
||||||
public class ImportParser {
|
public class ImportParser {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 读取一行 import 声明,返回多个 ImportNode
|
* 解析一条 import 声明语句,返回对应的 {@link ImportNode} 列表。
|
||||||
|
* 格式必须为:{@code import: MODULE[, MODULE]* NEWLINE}
|
||||||
|
*
|
||||||
|
* @param ctx 当前的解析上下文。
|
||||||
|
* @return 所有被导入模块的节点列表。
|
||||||
*/
|
*/
|
||||||
public List<ImportNode> parse(ParserContext ctx) {
|
public List<ImportNode> parse(ParserContext ctx) {
|
||||||
ctx.getTokens().expect("import");
|
ctx.getTokens().expect("import");
|
||||||
ctx.getTokens().expect(":");
|
ctx.getTokens().expect(":");
|
||||||
|
|
||||||
List<ImportNode> imports = new ArrayList<>();
|
List<ImportNode> imports = new ArrayList<>();
|
||||||
// 读取第一个模块名
|
|
||||||
// 继续读取逗号分隔的模块名
|
// 读取第一个模块名,然后继续读取逗号分隔的模块名
|
||||||
do {
|
do {
|
||||||
String mod = ctx.getTokens()
|
String mod = ctx.getTokens()
|
||||||
.expectType(TokenType.IDENTIFIER)
|
.expectType(TokenType.IDENTIFIER)
|
||||||
.getLexeme();
|
.getLexeme();
|
||||||
imports.add(new ImportNode(mod));
|
imports.add(new ImportNode(mod));
|
||||||
} while (ctx.getTokens().match(","));
|
} while (ctx.getTokens().match(","));
|
||||||
// 消费行尾
|
|
||||||
|
// 消费行尾换行符
|
||||||
ctx.getTokens().expectType(TokenType.NEWLINE);
|
ctx.getTokens().expectType(TokenType.NEWLINE);
|
||||||
|
|
||||||
return imports;
|
return imports;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,12 +13,24 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析 module 块:
|
* 模块解析器,用于解析形如 module 块的顶层结构。
|
||||||
* module: NAME NEWLINE
|
* 语法示例:
|
||||||
* (import… | function… )*
|
* <pre>{@code
|
||||||
* end module NEWLINE
|
* module: my.module
|
||||||
|
* import: mod1, mod2
|
||||||
|
* function: ...
|
||||||
|
* end module
|
||||||
|
* }</pre>
|
||||||
|
* 支持导入语句和多个函数定义,允许中间包含空行。
|
||||||
*/
|
*/
|
||||||
public class ModuleParser implements TopLevelParser {
|
public class ModuleParser implements TopLevelParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析模块定义块,返回 {@link ModuleNode} 表示模块结构。
|
||||||
|
*
|
||||||
|
* @param ctx 解析上下文。
|
||||||
|
* @return 模块节点,包含模块名、导入列表和函数列表。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ModuleNode parse(ParserContext ctx) {
|
public ModuleNode parse(ParserContext ctx) {
|
||||||
TokenStream ts = ctx.getTokens();
|
TokenStream ts = ctx.getTokens();
|
||||||
@ -32,17 +44,18 @@ public class ModuleParser implements TopLevelParser {
|
|||||||
ImportParser importParser = new ImportParser();
|
ImportParser importParser = new ImportParser();
|
||||||
FunctionParser funcParser = new FunctionParser();
|
FunctionParser funcParser = new FunctionParser();
|
||||||
|
|
||||||
// 解析导入和函数,支持空行
|
// 解析模块体:包含 import 和 function 语句
|
||||||
while (true) {
|
while (true) {
|
||||||
// 跳过空行
|
// 跳过空行
|
||||||
if (ts.peek().getType() == TokenType.NEWLINE) {
|
if (ts.peek().getType() == TokenType.NEWLINE) {
|
||||||
ts.next();
|
ts.next();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// 如果遇到 end,跳出循环
|
// 遇到 "end" 表示模块结束
|
||||||
if ("end".equals(ts.peek().getLexeme())) {
|
if ("end".equals(ts.peek().getLexeme())) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
String lex = ts.peek().getLexeme();
|
String lex = ts.peek().getLexeme();
|
||||||
if ("import".equals(lex)) {
|
if ("import".equals(lex)) {
|
||||||
imports.addAll(importParser.parse(ctx));
|
imports.addAll(importParser.parse(ctx));
|
||||||
@ -53,9 +66,11 @@ public class ModuleParser implements TopLevelParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 结束模块块结构
|
||||||
ts.expect("end");
|
ts.expect("end");
|
||||||
ts.expect("module");
|
ts.expect("module");
|
||||||
ts.expectType(TokenType.NEWLINE);
|
ts.expectType(TokenType.NEWLINE);
|
||||||
|
|
||||||
return new ModuleNode(name, imports, functions);
|
return new ModuleNode(name, imports, functions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,24 +7,47 @@ import org.jcnc.snow.compiler.parser.context.ParserContext;
|
|||||||
import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser;
|
import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析 declare 语句: declare name:type (= expr)? NEWLINE
|
* 解析变量声明语句的解析器。
|
||||||
|
* 支持语法格式:
|
||||||
|
* <pre>{@code
|
||||||
|
* declare name:type
|
||||||
|
* declare name:type = expression
|
||||||
|
* }</pre>
|
||||||
|
* 每条语句必须以换行(NEWLINE)结束。
|
||||||
*/
|
*/
|
||||||
public class DeclarationStatementParser implements StatementParser {
|
public class DeclarationStatementParser implements StatementParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析一条 declare 声明语句。
|
||||||
|
*
|
||||||
|
* @param ctx 当前解析上下文。
|
||||||
|
* @return 构造好的 {@link DeclarationNode} AST 节点。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public DeclarationNode parse(ParserContext ctx) {
|
public DeclarationNode parse(ParserContext ctx) {
|
||||||
ctx.getTokens().expect("declare");
|
ctx.getTokens().expect("declare");
|
||||||
|
|
||||||
|
// 获取变量名
|
||||||
String name = ctx.getTokens()
|
String name = ctx.getTokens()
|
||||||
.expectType(TokenType.IDENTIFIER)
|
.expectType(TokenType.IDENTIFIER)
|
||||||
.getLexeme();
|
.getLexeme();
|
||||||
|
|
||||||
ctx.getTokens().expect(":");
|
ctx.getTokens().expect(":");
|
||||||
|
|
||||||
|
// 获取变量类型
|
||||||
String type = ctx.getTokens()
|
String type = ctx.getTokens()
|
||||||
.expectType(TokenType.TYPE)
|
.expectType(TokenType.TYPE)
|
||||||
.getLexeme();
|
.getLexeme();
|
||||||
|
|
||||||
|
// 可选初始化表达式
|
||||||
ExpressionNode init = null;
|
ExpressionNode init = null;
|
||||||
if (ctx.getTokens().match("=")) {
|
if (ctx.getTokens().match("=")) {
|
||||||
init = new PrattExpressionParser().parse(ctx);
|
init = new PrattExpressionParser().parse(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 声明语句必须以 NEWLINE 结束
|
||||||
ctx.getTokens().expectType(TokenType.NEWLINE);
|
ctx.getTokens().expectType(TokenType.NEWLINE);
|
||||||
|
|
||||||
return new DeclarationNode(name, type, init);
|
return new DeclarationNode(name, type, init);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,27 +10,38 @@ import org.jcnc.snow.compiler.parser.context.TokenStream;
|
|||||||
import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser;
|
import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将任意表达式或赋值当作语句:
|
* 表达式语句解析器:将赋值表达式或任意表达式作为语句进行解析。
|
||||||
* identifier = expr NEWLINE
|
* 支持的形式包括:
|
||||||
* expr NEWLINE
|
* <pre>
|
||||||
|
* identifier = expression
|
||||||
|
* expression
|
||||||
|
* </pre>
|
||||||
|
* 两者都必须以换行(NEWLINE)结尾。
|
||||||
*/
|
*/
|
||||||
public class ExpressionStatementParser implements StatementParser {
|
public class ExpressionStatementParser implements StatementParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析一个表达式语句,可能是赋值语句或普通表达式。
|
||||||
|
*
|
||||||
|
* @param ctx 当前的解析上下文。
|
||||||
|
* @return 表达式语句节点或赋值语句节点。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public StatementNode parse(ParserContext ctx) {
|
public StatementNode parse(ParserContext ctx) {
|
||||||
TokenStream ts = ctx.getTokens();
|
TokenStream ts = ctx.getTokens();
|
||||||
|
|
||||||
// 先检测赋值语句:IDENTIFIER '=' ...
|
// 检查是否是赋值形式(identifier = expr)
|
||||||
if (ts.peek().getType() == TokenType.IDENTIFIER
|
if (ts.peek().getType() == TokenType.IDENTIFIER
|
||||||
&& ts.peek(1).getLexeme().equals("=")) {
|
&& ts.peek(1).getLexeme().equals("=")) {
|
||||||
|
|
||||||
String varName = ts.next().getLexeme(); // consume identifier
|
String varName = ts.next().getLexeme(); // 消费 identifier
|
||||||
ts.expect("="); // consume '='
|
ts.expect("="); // 消费 '='
|
||||||
ExpressionNode value = new PrattExpressionParser().parse(ctx);
|
ExpressionNode value = new PrattExpressionParser().parse(ctx);
|
||||||
ts.expectType(TokenType.NEWLINE);
|
ts.expectType(TokenType.NEWLINE);
|
||||||
return new AssignmentNode(varName, value);
|
return new AssignmentNode(varName, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 否则当作普通表达式语句
|
// 否则解析为普通表达式语句
|
||||||
ExpressionNode expr = new PrattExpressionParser().parse(ctx);
|
ExpressionNode expr = new PrattExpressionParser().parse(ctx);
|
||||||
ts.expectType(TokenType.NEWLINE);
|
ts.expectType(TokenType.NEWLINE);
|
||||||
return new ExpressionStatementNode(expr);
|
return new ExpressionStatementNode(expr);
|
||||||
|
|||||||
@ -11,23 +11,41 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析 if 语句: if expr then NEWLINE stmts end if NEWLINE
|
* if 语句解析器,支持基本格式:
|
||||||
|
* <pre>{@code
|
||||||
|
* if condition then
|
||||||
|
* statements...
|
||||||
|
* end if
|
||||||
|
* }</pre>
|
||||||
|
* 不支持 else 分支,仅支持 then 分支。
|
||||||
*/
|
*/
|
||||||
public class IfStatementParser implements StatementParser {
|
public class IfStatementParser implements StatementParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析 if 表达式,并构造 {@link IfNode}。
|
||||||
|
*
|
||||||
|
* @param ctx 当前解析上下文。
|
||||||
|
* @return 表示 if 语句的 AST 节点。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public IfNode parse(ParserContext ctx) {
|
public IfNode parse(ParserContext ctx) {
|
||||||
ctx.getTokens().expect("if");
|
ctx.getTokens().expect("if");
|
||||||
|
|
||||||
|
// 解析条件表达式
|
||||||
var cond = new PrattExpressionParser().parse(ctx);
|
var cond = new PrattExpressionParser().parse(ctx);
|
||||||
|
|
||||||
ctx.getTokens().expect("then");
|
ctx.getTokens().expect("then");
|
||||||
ctx.getTokens().expectType(TokenType.NEWLINE);
|
ctx.getTokens().expectType(TokenType.NEWLINE);
|
||||||
|
|
||||||
|
// 解析 then 分支的语句块
|
||||||
List<StatementNode> thenBranch = new ArrayList<>();
|
List<StatementNode> thenBranch = new ArrayList<>();
|
||||||
while (!ctx.getTokens().peek().getLexeme().equals("end")) {
|
while (!ctx.getTokens().peek().getLexeme().equals("end")) {
|
||||||
thenBranch.add(
|
String keyword = ctx.getTokens().peek().getLexeme();
|
||||||
StatementParserFactory.get(ctx.getTokens().peek().getLexeme()).parse(ctx)
|
StatementNode stmt = StatementParserFactory.get(keyword).parse(ctx);
|
||||||
);
|
thenBranch.add(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 匹配 end if 结束语句
|
||||||
ctx.getTokens().expect("end");
|
ctx.getTokens().expect("end");
|
||||||
ctx.getTokens().expect("if");
|
ctx.getTokens().expect("if");
|
||||||
ctx.getTokens().expectType(TokenType.NEWLINE);
|
ctx.getTokens().expectType(TokenType.NEWLINE);
|
||||||
|
|||||||
@ -14,16 +14,29 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析 loop 语句:
|
* 用于解析 loop 语句块,支持以下结构:
|
||||||
* loop: NEWLINE
|
* <pre>{@code
|
||||||
* initializer: … NEWLINE
|
* loop:
|
||||||
* condition: … NEWLINE
|
* initializer:
|
||||||
* update: … NEWLINE
|
* declare i:int = 0
|
||||||
* body: … NEWLINE
|
* condition:
|
||||||
* end body NEWLINE
|
* i < 10
|
||||||
* end loop NEWLINE
|
* update:
|
||||||
|
* i = i + 1
|
||||||
|
* body:
|
||||||
|
* ...语句...
|
||||||
|
* end body
|
||||||
|
* end loop
|
||||||
|
* }</pre>
|
||||||
*/
|
*/
|
||||||
public class LoopStatementParser implements StatementParser {
|
public class LoopStatementParser implements StatementParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析一个完整的 loop 语句块,返回 {@link LoopNode}。
|
||||||
|
*
|
||||||
|
* @param ctx 当前的解析上下文。
|
||||||
|
* @return 表示 loop 结构的 AST 节点。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public LoopNode parse(ParserContext ctx) {
|
public LoopNode parse(ParserContext ctx) {
|
||||||
TokenStream ts = ctx.getTokens();
|
TokenStream ts = ctx.getTokens();
|
||||||
@ -53,7 +66,7 @@ public class LoopStatementParser implements StatementParser {
|
|||||||
ts.expectType(TokenType.NEWLINE);
|
ts.expectType(TokenType.NEWLINE);
|
||||||
skipNewlines(ts);
|
skipNewlines(ts);
|
||||||
|
|
||||||
// update (专用赋值解析):
|
// update:
|
||||||
ts.expect("update");
|
ts.expect("update");
|
||||||
ts.expect(":");
|
ts.expect(":");
|
||||||
ts.expectType(TokenType.NEWLINE);
|
ts.expectType(TokenType.NEWLINE);
|
||||||
@ -90,7 +103,11 @@ public class LoopStatementParser implements StatementParser {
|
|||||||
return new LoopNode(initializer, condition, update, body);
|
return new LoopNode(initializer, condition, update, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 连续跳过所有空行(NEWLINE) */
|
/**
|
||||||
|
* 跳过连续的 NEWLINE token,用于容错和格式整洁。
|
||||||
|
*
|
||||||
|
* @param ts 当前的 Token 流。
|
||||||
|
*/
|
||||||
private void skipNewlines(TokenStream ts) {
|
private void skipNewlines(TokenStream ts) {
|
||||||
while (ts.peek().getType() == TokenType.NEWLINE) {
|
while (ts.peek().getType() == TokenType.NEWLINE) {
|
||||||
ts.next();
|
ts.next();
|
||||||
|
|||||||
@ -7,19 +7,35 @@ import org.jcnc.snow.compiler.parser.context.ParserContext;
|
|||||||
import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser;
|
import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析 return 语句: return expr? NEWLINE
|
* 用于解析 return 语句。
|
||||||
|
* 支持有无返回值两种形式:
|
||||||
|
* <pre>{@code
|
||||||
|
* return
|
||||||
|
* return expression
|
||||||
|
* }</pre>
|
||||||
|
* 语句必须以换行符(NEWLINE)结束。
|
||||||
*/
|
*/
|
||||||
public class ReturnStatementParser implements StatementParser {
|
public class ReturnStatementParser implements StatementParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析 return 语句并构建 {@link ReturnNode}。
|
||||||
|
*
|
||||||
|
* @param ctx 当前解析上下文。
|
||||||
|
* @return 表示 return 语句的 AST 节点。
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public ReturnNode parse(ParserContext ctx) {
|
public ReturnNode parse(ParserContext ctx) {
|
||||||
ctx.getTokens().expect("return");
|
ctx.getTokens().expect("return");
|
||||||
|
|
||||||
ExpressionNode expr = null;
|
ExpressionNode expr = null;
|
||||||
// 如果下一个不是换行,就解析表达式
|
|
||||||
|
// 如果不是换行,说明有返回值
|
||||||
if (ctx.getTokens().peek().getType() != TokenType.NEWLINE) {
|
if (ctx.getTokens().peek().getType() != TokenType.NEWLINE) {
|
||||||
expr = new PrattExpressionParser().parse(ctx);
|
expr = new PrattExpressionParser().parse(ctx);
|
||||||
}
|
}
|
||||||
// 用 expectType 来消费真正的 NEWLINE token
|
|
||||||
ctx.getTokens().expectType(TokenType.NEWLINE);
|
ctx.getTokens().expectType(TokenType.NEWLINE);
|
||||||
|
|
||||||
return new ReturnNode(expr);
|
return new ReturnNode(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,8 +4,16 @@ import org.jcnc.snow.compiler.parser.context.ParserContext;
|
|||||||
import org.jcnc.snow.compiler.parser.ast.StatementNode;
|
import org.jcnc.snow.compiler.parser.ast.StatementNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 语句解析器接口。
|
* 语句解析器接口,用于将解析上下文中的 Token 转换为 {@link StatementNode}。
|
||||||
|
* 各类语句(如声明、赋值、条件、循环、返回等)均应实现该接口。
|
||||||
*/
|
*/
|
||||||
public interface StatementParser {
|
public interface StatementParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从给定的解析上下文中解析出一个语句节点。
|
||||||
|
*
|
||||||
|
* @param ctx 当前的解析上下文。
|
||||||
|
* @return 表示语句的 AST 节点。
|
||||||
|
*/
|
||||||
StatementNode parse(ParserContext ctx);
|
StatementNode parse(ParserContext ctx);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user