fix: 语义分析报错显示未知位置
This commit is contained in:
parent
ec2068615e
commit
8b421d3c92
@ -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,
|
||||
""
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
/**
|
||||
* 返回赋值语句的字符串形式,便于调试与日志输出。
|
||||
|
||||
@ -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 {
|
||||
|
||||
/**
|
||||
* 返回该二元运算表达式的字符串表示形式。
|
||||
|
||||
@ -14,6 +14,7 @@ import java.util.List;
|
||||
* @param arguments 参数表达式列表,表示函数调用中传递给函数的实际参数。参数的顺序与调用顺序一致。
|
||||
* @param line 当前表达式所在的行号,方便调试和错误定位。
|
||||
* @param column 当前表达式所在的列号,用于精确定位错误位置。
|
||||
* @param file 当前表达式所在的文件,用于错误定位。
|
||||
*/
|
||||
public record CallExpressionNode(
|
||||
ExpressionNode callee, // 被调用的表达式节点,表示函数或方法名
|
||||
|
||||
@ -23,6 +23,15 @@ public class DeclarationNode implements StatementNode {
|
||||
/** 可选的初始化表达式 */
|
||||
private final Optional<ExpressionNode> 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<ExpressionNode> getInitializer() {
|
||||
return initializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前表达式所在的行号。
|
||||
*
|
||||
* @return 当前表达式的行号。
|
||||
*/
|
||||
public int line() {
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前表达式所在的列号。
|
||||
*
|
||||
* @return 当前表达式的列号。
|
||||
*/
|
||||
public int column() {
|
||||
return column;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前表达式所在的文件名。
|
||||
*
|
||||
* @return 当前表达式所在的文件名。
|
||||
*/
|
||||
public String file() { return file; }
|
||||
}
|
||||
@ -11,6 +11,14 @@ import org.jcnc.snow.compiler.parser.ast.base.StatementNode;
|
||||
* </p>
|
||||
*
|
||||
* @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 {
|
||||
}
|
||||
@ -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<ParameterNode> parameters, String returnType,
|
||||
List<StatementNode> body) implements Node {
|
||||
public record FunctionNode(
|
||||
String name,
|
||||
List<ParameterNode> parameters,
|
||||
String returnType,
|
||||
List<StatementNode> body,
|
||||
int line,
|
||||
int column,
|
||||
String file
|
||||
) implements Node {
|
||||
}
|
||||
@ -10,8 +10,16 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
|
||||
* </p>
|
||||
*
|
||||
* @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 {
|
||||
|
||||
/**
|
||||
* 返回标识符节点的字符串形式,通常为其名称本身。
|
||||
|
||||
@ -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<StatementNode> thenBranch,
|
||||
List<StatementNode> elseBranch
|
||||
List<StatementNode> elseBranch,
|
||||
int line,
|
||||
int column,
|
||||
String file
|
||||
) implements StatementNode {
|
||||
}
|
||||
@ -14,6 +14,14 @@ import org.jcnc.snow.compiler.parser.ast.base.Node;
|
||||
* </p>
|
||||
*
|
||||
* @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 {
|
||||
}
|
||||
@ -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<StatementNode> body) implements StatementNode {
|
||||
public record LoopNode(
|
||||
StatementNode initializer,
|
||||
ExpressionNode condition,
|
||||
StatementNode update,
|
||||
List<StatementNode> body,
|
||||
int line,
|
||||
int column,
|
||||
String file
|
||||
) implements StatementNode {
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
/**
|
||||
* 返回成员访问表达式的字符串形式。
|
||||
|
||||
@ -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<ImportNode> imports, List<FunctionNode> functions) implements Node {
|
||||
public record ModuleNode(
|
||||
String name,
|
||||
List<ImportNode> imports,
|
||||
List<FunctionNode> functions,
|
||||
int line,
|
||||
int column,
|
||||
String file
|
||||
) implements Node {
|
||||
|
||||
/**
|
||||
* 返回模块节点的字符串表示形式,包含模块名、导入模块列表和函数列表。
|
||||
|
||||
@ -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}。
|
||||
|
||||
@ -23,13 +23,25 @@ public class ReturnNode implements StatementNode {
|
||||
/** 可选的返回值表达式 */
|
||||
private final Optional<ExpressionNode> 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<ExpressionNode> getExpression() {
|
||||
return expression;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前表达式所在的行号。
|
||||
*
|
||||
* @return 当前表达式的行号。
|
||||
*/
|
||||
public int line() {
|
||||
return line;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前表达式所在的列号。
|
||||
*
|
||||
* @return 当前表达式的列号。
|
||||
*/
|
||||
public int column() {
|
||||
return column;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前表达式所在的文件名。
|
||||
*
|
||||
* @return 当前表达式所在的文件名。
|
||||
*/
|
||||
public String file() { return file; }
|
||||
}
|
||||
@ -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"}。
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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<ExpressionNode> 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);
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
* @param ts 当前使用的 {@link TokenStream}。
|
||||
* @param ctx 当前解析上下文,包含 {@link TokenStream} 和符号表等作用域信息。
|
||||
* @return 所有参数节点的列表。
|
||||
*/
|
||||
private List<ParameterNode> parseParameters(TokenStream ts) {
|
||||
private List<ParameterNode> 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;
|
||||
}
|
||||
|
||||
@ -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 语句的结束
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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); // 返回表达式语句节点
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user