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 319986a..4a9d3df 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 @@ -10,75 +10,96 @@ import org.jcnc.snow.compiler.parser.expression.PrattExpressionParser; /** * {@code DeclarationStatementParser} 负责解析变量声明语句节点。 *

- * 支持以下两种语法结构: - *

{@code
- * declare myVar:Integer
- * declare myVar:Integer = 42 + 3
- * }
- * 解析器能够识别多维数组类型(如 {@code int[]}, {@code string[][]}),并支持可选初始化表达式。 - *

- * 每个声明语句均要求以换行符结尾,语法不合法时会抛出异常。 - *

+ * */ public class DeclarationStatementParser implements StatementParser { /** - * 解析一条 {@code declare} 语句,生成对应的抽象语法树节点 {@link DeclarationNode}。 - *

- * 支持类型标注和可选初始化表达式。类型部分自动拼接数组维度(如 int[][])。 - *

+ * 解析变量或常量声明语句。 * - * @param ctx 当前语法解析上下文(包含词法流、错误信息等) - * @return {@link DeclarationNode} 表示声明语句结构 - * @throws RuntimeException 语法不合法时抛出 + * @param ctx 语法分析上下文,提供词法单元流与其他辅助功能 + * @return 解析得到的声明节点 {@link DeclarationNode} + * @throws org.jcnc.snow.compiler.parser.context.UnexpectedToken 若语法不合法则抛出异常 */ @Override public DeclarationNode parse(ParserContext ctx) { - // 便捷引用词法 token 流 - var tokens = ctx.getTokens(); + var tokens = ctx.getTokens(); // 获取词法单元流 - // 获取当前 token 的行号、列号和文件名 - int line = tokens.peek().getLine(); + // 记录声明语句在源码中的位置信息(行、列、文件名) + int line = tokens.peek().getLine(); int column = tokens.peek().getCol(); String file = ctx.getSourceName(); - // 声明语句必须以 "declare" 开头 - tokens.expect("declare"); - - // 是否声明为常量 - boolean isConst = tokens.match("const"); - - // 获取变量名称(标识符) - String name = tokens - .expectType(TokenType.IDENTIFIER) - .getLexeme(); - - // 类型标注的冒号分隔符 - tokens.expect(":"); - - // 获取变量类型(类型标识符) - StringBuilder type = new StringBuilder( - tokens - .expectType(TokenType.TYPE) - .getLexeme() - ); - - // 消费多维数组类型后缀 "[]" - while (tokens.match("[")) { - tokens.expectType(TokenType.RBRACKET); // 必须配对 - type.append("[]"); // 类型名称拼接 [],如 int[][] 等 + // 判断并消费声明关键字 declare 或 const + boolean isConst = false; + String first = tokens.peek().getLexeme(); + if ("declare".equals(first)) { + tokens.next(); // 消费 declare + // declare 后可选 const,用于声明常量 + if ("const".equals(tokens.peek().getLexeme())) { + isConst = true; + tokens.next(); // 消费 const + } + } else if ("const".equals(first)) { + // 支持 const 开头的声明写法 + isConst = true; + tokens.next(); // 消费 const + } else { + // 不符合语法规则,抛出异常 + throw new org.jcnc.snow.compiler.parser.context.UnexpectedToken( + "声明应以 'declare' 或 'declare const' 开始,而不是 '" + first + "'", + tokens.peek().getLine(), tokens.peek().getCol()); } - // 可选初始化表达式(=号右侧) + // 获取变量名(标识符) + String name = tokens.expectType(TokenType.IDENTIFIER).getLexeme(); + + // 检查并消费冒号 “:” + tokens.expect(":"); + + // 解析变量类型(类型标识符或自定义结构体名) + StringBuilder type = new StringBuilder(); + if (tokens.peek().getType() == TokenType.TYPE || tokens.peek().getType() == TokenType.IDENTIFIER) { + // 类型可以是基础类型或结构体名 + type.append(tokens.next().getLexeme()); + } else { + // 类型不是合法的 Token,抛出异常 + var t = tokens.peek(); + throw new org.jcnc.snow.compiler.parser.context.UnexpectedToken( + "期望的标记类型为 TYPE 或 IDENTIFIER,但实际得到的是 " + + t.getType() + " ('" + t.getLexeme() + "')", + t.getLine(), t.getCol() + ); + } + + // 处理多维数组类型后缀(支持 int[][] 等类型) + while (tokens.match("[")) { + // 消费左中括号 '[' 后必须跟右中括号 ']' + tokens.expectType(TokenType.RBRACKET); // 消费 ']' + type.append("[]"); // 追加数组后缀 + } + + // 可选的初始化表达式(如 = 10) ExpressionNode init = null; if (tokens.match("=")) { + // 使用 Pratt 解析器解析表达式,获得初始化表达式节点 init = new PrattExpressionParser().parse(ctx); } - // 声明语句必须以换行符结尾 + // 声明语句必须以换行符 NEWLINE 结尾 tokens.expectType(TokenType.NEWLINE); - // 返回构建好的声明语法树节点 - return new DeclarationNode(name, type.toString(), isConst, init, new NodeContext(line, column, file)); + // 组装声明节点并返回 + return new DeclarationNode( + name, // 变量/常量名 + type.toString(), // 类型字符串 + isConst, // 是否常量 + init, // 初始化表达式节点(可为 null) + new NodeContext(line, column, file) // 源码位置信息 + ); } }