diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java index a1168ec..5513fdc 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/IRProgramBuilder.java @@ -76,6 +76,14 @@ public final class IRProgramBuilder { * @return 生成的 FunctionNode,用于后续 IRFunction 构建 */ private FunctionNode wrapTopLevel(StatementNode stmt) { - return new FunctionNode("_start", null, String.valueOf(List.of()), List.of(stmt)); + return new FunctionNode( + "_start", + null, + String.valueOf(List.of()), + List.of(stmt), + -1, + -1, + "" + ); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/AssignmentNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/AssignmentNode.java index 69781b9..eace610 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/AssignmentNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/AssignmentNode.java @@ -16,8 +16,17 @@ import org.jcnc.snow.compiler.parser.ast.base.StatementNode; * * @param variable 左值变量名(即赋值目标) * @param value 表达式右值(即赋值来源) + * @param line 当前节点所在的行号 + * @param column 当前节点所在的列号 + * @param file 当前节点所在的文件 */ -public record AssignmentNode(String variable, ExpressionNode value) implements StatementNode { +public record AssignmentNode( + String variable, + ExpressionNode value, + int line, + int column, + String file +) implements StatementNode { /** * 返回赋值语句的字符串形式,便于调试与日志输出。 diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/BinaryExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/BinaryExpressionNode.java index 6e49e63..40412de 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/BinaryExpressionNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/BinaryExpressionNode.java @@ -12,9 +12,18 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; * @param left 左操作数(子表达式) * @param operator 运算符字符串(如 "+", "-", "*", "/" 等) * @param right 右操作数(子表达式) + * @param line 当前节点所在的行号 + * @param column 当前节点所在的列号 + * @param file 当前节点所在的文件 */ -public record BinaryExpressionNode(ExpressionNode left, String operator, - ExpressionNode right) implements ExpressionNode { +public record BinaryExpressionNode( + ExpressionNode left, + String operator, + ExpressionNode right, + int line, + int column, + String file +) implements ExpressionNode { /** * 返回该二元运算表达式的字符串表示形式。 diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/CallExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/CallExpressionNode.java index ac36871..22f47bc 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/CallExpressionNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/CallExpressionNode.java @@ -14,6 +14,7 @@ import java.util.List; * @param arguments 参数表达式列表,表示函数调用中传递给函数的实际参数。参数的顺序与调用顺序一致。 * @param line 当前表达式所在的行号,方便调试和错误定位。 * @param column 当前表达式所在的列号,用于精确定位错误位置。 + * @param file 当前表达式所在的文件,用于错误定位。 */ public record CallExpressionNode( ExpressionNode callee, // 被调用的表达式节点,表示函数或方法名 diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/DeclarationNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/DeclarationNode.java index 1819d1f..9e1edf5 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/DeclarationNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/DeclarationNode.java @@ -23,6 +23,15 @@ public class DeclarationNode implements StatementNode { /** 可选的初始化表达式 */ private final Optional initializer; + /** 当前节点所在的行号 **/ + private final int line; + + /** 当前节点所在的列号 **/ + private final int column; + + /** 当前节点所在的文件 **/ + private final String file; + /** * 构造一个 {@code DeclarationNode} 实例。 * @@ -30,10 +39,13 @@ public class DeclarationNode implements StatementNode { * @param type 变量类型字符串(如 "int"、"string") * @param initializer 可选初始化表达式,若为 {@code null} 表示未初始化 */ - public DeclarationNode(String name, String type, ExpressionNode initializer) { + public DeclarationNode(String name, String type, ExpressionNode initializer, int line, int column, String file) { this.name = name; this.type = type; this.initializer = Optional.ofNullable(initializer); + this.line = line; + this.column = column; + this.file = file; } /** @@ -62,4 +74,29 @@ public class DeclarationNode implements StatementNode { public Optional getInitializer() { return initializer; } + + /** + * 获取当前表达式所在的行号。 + * + * @return 当前表达式的行号。 + */ + public int line() { + return line; + } + + /** + * 获取当前表达式所在的列号。 + * + * @return 当前表达式的列号。 + */ + public int column() { + return column; + } + + /** + * 获取当前表达式所在的文件名。 + * + * @return 当前表达式所在的文件名。 + */ + public String file() { return file; } } \ No newline at end of file diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java index cf62fb1..1a2f7a5 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ExpressionStatementNode.java @@ -11,6 +11,14 @@ import org.jcnc.snow.compiler.parser.ast.base.StatementNode; *

* * @param expression 表达式主体,通常为函数调用、赋值、方法链式调用等可求值表达式。 + * @param line 当前节点所在的行号 + * @param column 当前节点所在的列号 + * @param file 当前节点所在的文件 */ -public record ExpressionStatementNode(ExpressionNode expression) implements StatementNode { +public record ExpressionStatementNode( + ExpressionNode expression, + int line, + int column, + String file +) implements StatementNode { } \ No newline at end of file diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/FunctionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/FunctionNode.java index 7ab55dd..29ab884 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/FunctionNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/FunctionNode.java @@ -17,7 +17,17 @@ import java.util.List; * @param parameters 参数列表,每项为 {@link ParameterNode} 表示一个形参定义 * @param returnType 函数的返回类型(如 "int"、"void" 等) * @param body 函数体语句块,由一组 {@link StatementNode} 构成 + * @param line 当前节点所在的行号 + * @param column 当前节点所在的列号 + * @param file 当前节点所在的文件 */ -public record FunctionNode(String name, List parameters, String returnType, - List body) implements Node { +public record FunctionNode( + String name, + List parameters, + String returnType, + List body, + int line, + int column, + String file +) implements Node { } \ No newline at end of file diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/IdentifierNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/IdentifierNode.java index cfce3d4..de0ed17 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/IdentifierNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/IdentifierNode.java @@ -10,8 +10,16 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; *

* * @param name 标识符的文本名称(如变量名 "x",函数名 "foo") + * @param line 当前节点所在的行号 + * @param column 当前节点所在的列号 + * @param file 当前节点所在的文件 */ -public record IdentifierNode(String name) implements ExpressionNode { +public record IdentifierNode( + String name, + int line, + int column, + String file +) implements ExpressionNode { /** * 返回标识符节点的字符串形式,通常为其名称本身。 diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/IfNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/IfNode.java index 9ac9371..a26c8e2 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/IfNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/IfNode.java @@ -29,10 +29,16 @@ import java.util.List; * @param condition 控制分支执行的条件表达式 * @param thenBranch 条件为 true 时执行的语句块 * @param elseBranch 条件为 false 时执行的语句块(可为空) + * @param line 当前节点所在的行号 + * @param column 当前节点所在的列号 + * @param file 当前节点所在的文件 */ public record IfNode( ExpressionNode condition, List thenBranch, - List elseBranch + List elseBranch, + int line, + int column, + String file ) implements StatementNode { } \ No newline at end of file diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java index f551fd9..c6b65e9 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ImportNode.java @@ -14,6 +14,14 @@ import org.jcnc.snow.compiler.parser.ast.base.Node; *

* * @param moduleName 被导入的模块名称,通常为点分层次结构(如 "core.utils") + * @param line 当前节点所在的行号 + * @param column 当前节点所在的列号 + * @param file 当前节点所在的文件 */ -public record ImportNode(String moduleName) implements Node { +public record ImportNode( + String moduleName, + int line, + int column, + String file +) implements Node { } \ No newline at end of file diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java index 7821ae4..a8ddbe1 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/LoopNode.java @@ -17,7 +17,17 @@ import java.util.List; * @param condition 每次迭代前评估的条件表达式,控制循环是否继续 * @param update 每轮迭代完成后执行的更新语句 * @param body 循环体语句列表,表示循环主体执行逻辑 + * @param line 当前节点所在的行号 + * @param column 当前节点所在的列号 + * @param file 当前节点所在的文件 */ -public record LoopNode(StatementNode initializer, ExpressionNode condition, StatementNode update, - List body) implements StatementNode { +public record LoopNode( + StatementNode initializer, + ExpressionNode condition, + StatementNode update, + List body, + int line, + int column, + String file +) implements StatementNode { } \ No newline at end of file diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/MemberExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/MemberExpressionNode.java index 7b49db3..d0ac38e 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/MemberExpressionNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/MemberExpressionNode.java @@ -11,8 +11,17 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; * * @param object 左侧对象表达式,表示成员所属的作用域或容器 * @param member 要访问的成员名称(字段名或方法名) + * @param line 当前节点所在的行号 + * @param column 当前节点所在的列号 + * @param file 当前节点所在的文件 */ -public record MemberExpressionNode(ExpressionNode object, String member) implements ExpressionNode { +public record MemberExpressionNode( + ExpressionNode object, + String member, + int line, + int column, + String file +) implements ExpressionNode { /** * 返回成员访问表达式的字符串形式。 diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java index 564402a..05d47de 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ModuleNode.java @@ -13,8 +13,18 @@ import java.util.StringJoiner; * @param name 模块名称。 * @param imports 模块导入列表,每个导入是一个 {@link ImportNode}。 * @param functions 模块中的函数列表,每个函数是一个 {@link FunctionNode}。 + * @param line 当前节点所在的行号 + * @param column 当前节点所在的列号 + * @param file 当前节点所在的文件 */ -public record ModuleNode(String name, List imports, List functions) implements Node { +public record ModuleNode( + String name, + List imports, + List functions, + int line, + int column, + String file +) implements Node { /** * 返回模块节点的字符串表示形式,包含模块名、导入模块列表和函数列表。 diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ParameterNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ParameterNode.java index 91e93aa..0fbdc18 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ParameterNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ParameterNode.java @@ -11,8 +11,17 @@ import org.jcnc.snow.compiler.parser.ast.base.Node; * * @param name 参数名称标识符 * @param type 参数类型字符串(如 "int"、"string") + * @param line 当前节点所在的行号 + * @param column 当前节点所在的列号 + * @param file 当前节点所在的文件 */ -public record ParameterNode(String name, String type) implements Node { +public record ParameterNode( + String name, + String type, + int line, + int column, + String file +) implements Node { /** * 返回参数的字符串形式,格式为 {@code name:type}。 diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/ReturnNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/ReturnNode.java index 28143dd..0fc2254 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/ReturnNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/ReturnNode.java @@ -23,13 +23,25 @@ public class ReturnNode implements StatementNode { /** 可选的返回值表达式 */ private final Optional expression; + /** 当前节点所在的行号 **/ + private final int line; + + /** 当前节点所在的列号 **/ + private final int column; + + /** 当前节点所在的文件 **/ + private final String file; + /** * 构造一个 {@code ReturnNode} 实例。 * * @param expression 返回值表达式,如果无返回值则可为 {@code null} */ - public ReturnNode(ExpressionNode expression) { + public ReturnNode(ExpressionNode expression, int line, int column, String file) { this.expression = Optional.ofNullable(expression); + this.line = line; + this.column = column; + this.file = file; } /** @@ -40,4 +52,29 @@ public class ReturnNode implements StatementNode { public Optional getExpression() { return expression; } + + /** + * 获取当前表达式所在的行号。 + * + * @return 当前表达式的行号。 + */ + public int line() { + return line; + } + + /** + * 获取当前表达式所在的列号。 + * + * @return 当前表达式的列号。 + */ + public int column() { + return column; + } + + /** + * 获取当前表达式所在的文件名。 + * + * @return 当前表达式所在的文件名。 + */ + public String file() { return file; } } \ No newline at end of file diff --git a/src/main/java/org/jcnc/snow/compiler/parser/ast/UnaryExpressionNode.java b/src/main/java/org/jcnc/snow/compiler/parser/ast/UnaryExpressionNode.java index d956fc8..7e38ebc 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/ast/UnaryExpressionNode.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/UnaryExpressionNode.java @@ -15,9 +15,17 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; * * @param operator 一元运算符(仅 "-" 或 "!") * @param operand 运算对象 / 右操作数 + * @param line 当前节点所在的行号 + * @param column 当前节点所在的列号 + * @param file 当前节点所在的文件 */ -public record UnaryExpressionNode(String operator, - ExpressionNode operand) implements ExpressionNode { +public record UnaryExpressionNode( + String operator, + ExpressionNode operand, + int line, + int column, + String file +) implements ExpressionNode { /** * 生成调试友好的字符串表示,例如 {@code "-x"} 或 {@code "!flag"}。 diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/BinaryOperatorParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/BinaryOperatorParselet.java index da86f01..adee8bd 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/BinaryOperatorParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/BinaryOperatorParselet.java @@ -37,6 +37,11 @@ public record BinaryOperatorParselet(Precedence precedence, boolean leftAssoc) i */ @Override public ExpressionNode parse(ParserContext ctx, ExpressionNode left) { + // 获取当前 token 的行号、列号和文件名 + int line = ctx.getTokens().peek().getLine(); + int column = ctx.getTokens().peek().getCol(); + String file = ctx.getSourceName(); + Token op = ctx.getTokens().next(); int prec = precedence.ordinal(); @@ -46,7 +51,7 @@ public record BinaryOperatorParselet(Precedence precedence, boolean leftAssoc) i leftAssoc ? Precedence.values()[prec] : Precedence.values()[prec - 1] ); - return new BinaryExpressionNode(left, op.getLexeme(), right); + return new BinaryExpressionNode(left, op.getLexeme(), right, line, column, file); } /** diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/CallParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/CallParselet.java index 9499f6d..9f5478a 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/CallParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/CallParselet.java @@ -26,14 +26,15 @@ public class CallParselet implements InfixParselet { */ @Override public ExpressionNode parse(ParserContext ctx, ExpressionNode left) { + // 获取函数名 token 的行号、列号和文件名 + int line = ctx.getTokens().peek(-1).getLine(); + int column = ctx.getTokens().peek(-1).getCol(); + String file = ctx.getSourceName(); + ctx.getTokens().next(); // 消费 "(" List args = new ArrayList<>(); - // 获取当前 token 的行号和列号 - int line = ctx.getTokens().peek().getLine(); - int column = ctx.getTokens().peek().getCol(); - // 解析函数调用参数 if (!ctx.getTokens().peek().getLexeme().equals(")")) { do { @@ -43,8 +44,7 @@ public class CallParselet implements InfixParselet { ctx.getTokens().expect(")"); // 消费并验证 ")" - // 创建 CallExpressionNode 并传递位置信息,文件名称 - String file = ctx.getSourceName(); + // 创建 CallExpressionNode 并传递位置信息 return new CallExpressionNode(left, args, line, column, file); } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/IdentifierParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/IdentifierParselet.java index 057c425..7e46337 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/IdentifierParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/IdentifierParselet.java @@ -24,6 +24,11 @@ public class IdentifierParselet implements PrefixParselet { */ @Override public ExpressionNode parse(ParserContext ctx, Token token) { - return new IdentifierNode(token.getLexeme()); + // 获取标识符 token 的行号、列号和文件名 + int line = ctx.getTokens().peek(-1).getLine(); + int column = ctx.getTokens().peek(-1).getCol(); + String file = ctx.getSourceName(); + + return new IdentifierNode(token.getLexeme(), line, column, file); } } \ No newline at end of file diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/MemberParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/MemberParselet.java index b0f1e5f..ed3cd58 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/MemberParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/MemberParselet.java @@ -28,8 +28,13 @@ public class MemberParselet implements InfixParselet { TokenStream ts = ctx.getTokens(); ts.expect("."); // 消费点号 + // 获取当前 token 的行号、列号和文件名 + int line = ctx.getTokens().peek().getLine(); + int column = ctx.getTokens().peek().getCol(); + String file = ctx.getSourceName(); + String member = ts.expectType(TokenType.IDENTIFIER).getLexeme(); - return new MemberExpressionNode(left, member); + return new MemberExpressionNode(left, member, line, column, file); } /** diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/UnaryOperatorParselet.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/UnaryOperatorParselet.java index abfa97a..5aedf93 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/UnaryOperatorParselet.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/UnaryOperatorParselet.java @@ -41,6 +41,11 @@ public class UnaryOperatorParselet implements PrefixParselet { */ @Override public ExpressionNode parse(ParserContext ctx, Token token) { + // 获取当前 token 的行号、列号和文件名 + int line = ctx.getTokens().peek().getLine(); + int column = ctx.getTokens().peek().getCol(); + String file = ctx.getSourceName(); + /* ------------------------------------------------------------ * 1. 以 UNARY 优先级递归解析操作数,避免错误结合顺序。 * ------------------------------------------------------------ */ @@ -50,6 +55,6 @@ public class UnaryOperatorParselet implements PrefixParselet { /* ------------------------------------------------------------ * 2. 封装成 AST 节点并返回。 * ------------------------------------------------------------ */ - return new UnaryExpressionNode(token.getLexeme(), operand); + return new UnaryExpressionNode(token.getLexeme(), operand, line, column, file); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/function/FunctionParser.java b/src/main/java/org/jcnc/snow/compiler/parser/function/FunctionParser.java index af2251e..a7a3449 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/function/FunctionParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/function/FunctionParser.java @@ -57,6 +57,11 @@ public class FunctionParser implements TopLevelParser { public FunctionNode parse(ParserContext ctx) { TokenStream ts = ctx.getTokens(); + // 获取当前 token 的行号、列号和文件名 + int line = ctx.getTokens().peek().getLine(); + int column = ctx.getTokens().peek().getCol(); + String file = ctx.getSourceName(); + parseFunctionHeader(ts); String functionName = parseFunctionName(ts); @@ -69,7 +74,7 @@ public class FunctionParser implements TopLevelParser { parseFunctionFooter(ts); - return new FunctionNode(functionName, parameters, returnType[0], body); + return new FunctionNode(functionName, parameters, returnType[0], body, line, column, file); } /** @@ -92,7 +97,7 @@ public class FunctionParser implements TopLevelParser { map.put("parameter", new SectionDefinition( (TokenStream stream) -> stream.peek().getLexeme().equals("parameter"), - (ParserContext context, TokenStream stream) -> params.addAll(parseParameters(stream)) + (ParserContext context, TokenStream stream) -> params.addAll(parseParameters(context)) )); map.put("return_type", new SectionDefinition( @@ -154,10 +159,12 @@ public class FunctionParser implements TopLevelParser { * *

* - * @param ts 当前使用的 {@link TokenStream}。 + * @param ctx 当前解析上下文,包含 {@link TokenStream} 和符号表等作用域信息。 * @return 所有参数节点的列表。 */ - private List parseParameters(TokenStream ts) { + private List parseParameters(ParserContext ctx) { + TokenStream ts = ctx.getTokens(); + ts.expect("parameter"); ts.expect(":"); skipComments(ts); @@ -175,13 +182,19 @@ public class FunctionParser implements TopLevelParser { if (lex.equals("return_type") || lex.equals("body") || lex.equals("end")) { break; } + + // 获取当前 token 的行号、列号和文件名 + int line = ctx.getTokens().peek().getLine(); + int column = ctx.getTokens().peek().getCol(); + String file = ctx.getSourceName(); + ts.expect("declare"); String pname = ts.expectType(TokenType.IDENTIFIER).getLexeme(); ts.expect(":"); String ptype = ts.expectType(TokenType.TYPE).getLexeme(); skipComments(ts); ts.expectType(TokenType.NEWLINE); - list.add(new ParameterNode(pname, ptype)); + list.add(new ParameterNode(pname, ptype, line, column, file)); } return list; } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java b/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java index 38dd788..d5443ac 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/module/ImportParser.java @@ -46,13 +46,18 @@ public class ImportParser { // 解析一个或多个模块名(标识符),允许使用逗号分隔多个模块 do { + // 获取当前 token 的行号、列号和文件名 + int line = ctx.getTokens().peek().getLine(); + int column = ctx.getTokens().peek().getCol(); + String file = ctx.getSourceName(); + // 获取当前标识符类型的词法单元,并提取其原始词素 String mod = ctx.getTokens() .expectType(TokenType.IDENTIFIER) .getLexeme(); // 创建 ImportNode 节点并加入列表 - imports.add(new ImportNode(mod)); + imports.add(new ImportNode(mod, line, column, file)); } while (ctx.getTokens().match(",")); // 如果匹配到逗号,继续解析下一个模块名 // 最后必须匹配换行符,标志 import 语句的结束 diff --git a/src/main/java/org/jcnc/snow/compiler/parser/module/ModuleParser.java b/src/main/java/org/jcnc/snow/compiler/parser/module/ModuleParser.java index b696410..ac9e05d 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/module/ModuleParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/module/ModuleParser.java @@ -40,6 +40,11 @@ public class ModuleParser implements TopLevelParser { // 获取当前上下文中提供的词法流 TokenStream ts = ctx.getTokens(); + // 获取当前 token 的行号、列号和文件名 + int line = ctx.getTokens().peek().getLine(); + int column = ctx.getTokens().peek().getCol(); + String file = ctx.getSourceName(); + // 期望模块声明以关键字 "module:" 开始 ts.expect("module"); ts.expect(":"); @@ -90,6 +95,6 @@ public class ModuleParser implements TopLevelParser { ts.expect("module"); // 构建并返回完整的模块语法树节点 - return new ModuleNode(name, imports, functions); + return new ModuleNode(name, imports, functions, line, column, file); } } \ No newline at end of file diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java index b99d09c..2323ada 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/DeclarationStatementParser.java @@ -43,6 +43,11 @@ public class DeclarationStatementParser implements StatementParser { */ @Override public DeclarationNode parse(ParserContext ctx) { + // 获取当前 token 的行号、列号和文件名 + int line = ctx.getTokens().peek().getLine(); + int column = ctx.getTokens().peek().getCol(); + String file = ctx.getSourceName(); + // 声明语句必须以 "declare" 开头 ctx.getTokens().expect("declare"); @@ -69,6 +74,6 @@ public class DeclarationStatementParser implements StatementParser { ctx.getTokens().expectType(TokenType.NEWLINE); // 返回构建好的声明语法树节点 - return new DeclarationNode(name, type, init); + return new DeclarationNode(name, type, init, line, column, file); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java index dd9df94..526dbf0 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/ExpressionStatementParser.java @@ -50,6 +50,11 @@ public class ExpressionStatementParser implements StatementParser { throw new IllegalStateException("Cannot parse expression starting with keyword: " + ts.peek().getLexeme()); } + // 获取当前 token 的行号、列号和文件名 + int line = ctx.getTokens().peek().getLine(); + int column = ctx.getTokens().peek().getCol(); + String file = ctx.getSourceName(); + // 处理赋值语句:格式为 identifier = expression if (ts.peek().getType() == TokenType.IDENTIFIER && ts.peek(1).getLexeme().equals("=")) { @@ -58,13 +63,13 @@ public class ExpressionStatementParser implements StatementParser { ts.expect("="); // 消耗等号 ExpressionNode value = new PrattExpressionParser().parse(ctx); // 解析表达式 ts.expectType(TokenType.NEWLINE); // 语句必须以换行符结束 - return new AssignmentNode(varName, value); // 返回赋值节点 + return new AssignmentNode(varName, value, line, column, file); // 返回赋值节点 } // 处理普通表达式语句,如函数调用、字面量、运算表达式等 ExpressionNode expr = new PrattExpressionParser().parse(ctx); ts.expectType(TokenType.NEWLINE); // 语句必须以换行符结束 - return new ExpressionStatementNode(expr); // 返回表达式语句节点 + return new ExpressionStatementNode(expr, line, column, file); // 返回表达式语句节点 } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/IfStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/IfStatementParser.java index f0e2498..eda8bb1 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/IfStatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/IfStatementParser.java @@ -47,6 +47,11 @@ public class IfStatementParser implements StatementParser { public IfNode parse(ParserContext ctx) { var ts = ctx.getTokens(); // 获取 token 流引用 + // 获取当前 token 的行号、列号和文件名 + int line = ctx.getTokens().peek().getLine(); + int column = ctx.getTokens().peek().getCol(); + String file = ctx.getSourceName(); + // 消耗起始关键字 "if" ts.expect("if"); @@ -120,6 +125,6 @@ public class IfStatementParser implements StatementParser { ts.expectType(TokenType.NEWLINE); // 构建并返回 IfNode,包含条件、then 分支和 else 分支 - return new IfNode(condition, thenBranch, elseBranch); + return new IfNode(condition, thenBranch, elseBranch, line, column, file); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java index 583b5c9..4422636 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/LoopStatementParser.java @@ -64,6 +64,12 @@ public class LoopStatementParser implements StatementParser { public LoopNode parse(ParserContext ctx) { TokenStream ts = ctx.getTokens(); + // 获取当前 token 的行号、列号 + int loop_line = ctx.getTokens().peek().getLine(); + int loop_column = ctx.getTokens().peek().getCol(); + + String file = ctx.getSourceName(); + // 匹配 loop: 起始语法 ParserUtils.matchHeader(ts, "loop"); @@ -101,12 +107,16 @@ public class LoopStatementParser implements StatementParser { sections.put("update", new FlexibleSectionParser.SectionDefinition( ts1 -> ts1.peek().getLexeme().equals("update"), (ctx1, ts1) -> { + // 获取当前 token 的行号、列号 + int line = ctx.getTokens().peek().getLine(); + int column = ctx.getTokens().peek().getCol(); + ParserUtils.matchHeader(ts1, "update"); String varName = ts1.expectType(TokenType.IDENTIFIER).getLexeme(); ts1.expect("="); ExpressionNode expr = new PrattExpressionParser().parse(ctx1); ts1.expectType(TokenType.NEWLINE); - update[0] = new AssignmentNode(varName, expr); + update[0] = new AssignmentNode(varName, expr, line, column, file); ParserUtils.skipNewlines(ts1); } )); @@ -140,6 +150,6 @@ public class LoopStatementParser implements StatementParser { ParserUtils.matchFooter(ts, "loop"); // 返回构造完成的 LoopNode - return new LoopNode(initializer[0], condition[0], update[0], body); + return new LoopNode(initializer[0], condition[0], update[0], body, loop_line, loop_column, file); } } diff --git a/src/main/java/org/jcnc/snow/compiler/parser/statement/ReturnStatementParser.java b/src/main/java/org/jcnc/snow/compiler/parser/statement/ReturnStatementParser.java index 8a6a6a2..080f1e6 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/statement/ReturnStatementParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/statement/ReturnStatementParser.java @@ -35,6 +35,11 @@ public class ReturnStatementParser implements StatementParser { */ @Override public ReturnNode parse(ParserContext ctx) { + // 获取当前 token 的行号、列号和文件名 + int line = ctx.getTokens().peek().getLine(); + int column = ctx.getTokens().peek().getCol(); + String file = ctx.getSourceName(); + // 消耗 "return" 关键字 ctx.getTokens().expect("return"); @@ -49,6 +54,6 @@ public class ReturnStatementParser implements StatementParser { ctx.getTokens().expectType(TokenType.NEWLINE); // 构建并返回 ReturnNode(可能为空表达式) - return new ReturnNode(expr); + return new ReturnNode(expr, line, column, file); } }