修复注释

This commit is contained in:
Luke 2025-05-10 15:40:59 +08:00
parent 98ceb4faa8
commit 59dbafb2b6
3 changed files with 41 additions and 47 deletions

View File

@ -7,6 +7,7 @@ import org.jcnc.snow.compiler.ir.core.IRFunction;
import org.jcnc.snow.compiler.ir.core.IRProgram; import org.jcnc.snow.compiler.ir.core.IRProgram;
import org.jcnc.snow.compiler.lexer.core.LexerEngine; import org.jcnc.snow.compiler.lexer.core.LexerEngine;
import org.jcnc.snow.compiler.lexer.token.Token; import org.jcnc.snow.compiler.lexer.token.Token;
import org.jcnc.snow.compiler.lexer.utils.TokenPrinter;
import org.jcnc.snow.compiler.parser.ast.base.Node; import org.jcnc.snow.compiler.parser.ast.base.Node;
import org.jcnc.snow.compiler.parser.context.ParserContext; import org.jcnc.snow.compiler.parser.context.ParserContext;
import org.jcnc.snow.compiler.parser.core.ParserEngine; import org.jcnc.snow.compiler.parser.core.ParserEngine;
@ -48,9 +49,9 @@ public class SnowCompiler {
List<Node> ast = new ParserEngine(ctx).parse(); List<Node> ast = new ParserEngine(ctx).parse();
// System.out.println(source); // System.out.println(source);
// TokenPrinter.print(tokens); // 打印 Token 列表 TokenPrinter.print(tokens); // 打印 Token 列表
ASTPrinter.print(ast); // 打印 AST ASTPrinter.print(ast); // 打印 AST
// ASTPrinter.printJson(ast); // 打印JSON AST ASTPrinter.printJson(ast); // 打印JSON AST
/* 3. 语义分析 */ /* 3. 语义分析 */
SemanticAnalyzerRunner.runSemanticAnalysis(ast, false); SemanticAnalyzerRunner.runSemanticAnalysis(ast, false);

View File

@ -10,23 +10,18 @@ import java.util.function.Predicate;
/** /**
* 通用的解析器用于解析结构化的内容部分完全解耦合关键字和语法 * 通用的解析器用于解析结构化的内容部分完全解耦合关键字和语法
* <p> *
* {@code FlexibleSectionParser} 提供了一个灵活的机制来解析可变的语法块每个语法块的解析逻辑通过外部提供 * FlexibleSectionParser 提供了一个灵活的机制来解析可变的语法块每个语法块的解析逻辑通过外部提供
* 该类仅负责按顺序解析不同的区块直到遇到结束标记它完全解耦了具体的语法关键字和解析逻辑 * 该类仅负责按顺序解析不同的区块直到遇到结束标记同时能够跳过并收集注释供后续使用
* </p> *
* <p> * 使用此类可以解析如函数定义中的多个部分如参数返回类型函数体等而无需在解析器中硬编码这些结构
* 使用此类可以解析如函数定义中的多个部分如参数返回类型函数体等而无需在解析器中硬编码这些结构 * 并且保留注释信息以便 IDE 或工具链进行注释跳转重构等操作
* </p>
*/ */
public class FlexibleSectionParser { public class FlexibleSectionParser {
/** /**
* 解析一系列的可变区块解析顺序和具体内容由外部定义 * 解析一系列的可变区块解析顺序和具体内容由外部定义
* <p> * 在解析过程中会跳过并收集注释以及跳过空行
* 该方法接受一个包含区块定义的映射每个区块定义包含一个条件Predicate<TokenStream>
* 和一个解析器BiConsumer<ParserContext, TokenStream>
* 条件用于判断当前是否应解析该区块解析器则执行解析逻辑
* </p>
* *
* @param ctx 当前的解析上下文包含语法分析所需的所有信息如作用域错误处理等 * @param ctx 当前的解析上下文包含语法分析所需的所有信息如作用域错误处理等
* @param tokens 当前的词法 token 用于逐个查看或消耗 token * @param tokens 当前的词法 token 用于逐个查看或消耗 token
@ -36,66 +31,63 @@ public class FlexibleSectionParser {
TokenStream tokens, TokenStream tokens,
Map<String, SectionDefinition> sectionDefinitions) { Map<String, SectionDefinition> sectionDefinitions) {
// 跳过最开始的空行避免误判开始关键字 // 在开始解析之前跳过并收集所有紧邻开头的注释和空行
while (tokens.peek().getType() == TokenType.NEWLINE) { skipCommentsAndNewlines(tokens);
tokens.next();
}
// 主循环逐个处理区块直到遇到 "end" 为止
while (true) { while (true) {
// 获取当前 token 的字面量通常是关键字字符串 // 在每次解析前跳过并收集注释和空行
skipCommentsAndNewlines(tokens);
String keyword = tokens.peek().getLexeme(); String keyword = tokens.peek().getLexeme();
// 尝试在映射中找到对应该关键字的区块定义 if ("end".equals(keyword)) {
SectionDefinition definition = sectionDefinitions.get(keyword); // 遇到 'end' 则终止解析
break;
}
// 如果找到了定义且其条件满足当前 token SectionDefinition definition = sectionDefinitions.get(keyword);
if (definition != null && definition.condition().test(tokens)) { if (definition != null && definition.condition().test(tokens)) {
// 执行该区块的解析逻辑 // 执行该区块的解析逻辑
definition.parser().accept(ctx, tokens); definition.parser().accept(ctx, tokens);
} else if ("end".equals(keyword)) {
// 如果遇到 "end"表示所有区块结束退出循环
break;
} else { } else {
// 如果关键字无法识别或不满足条件则抛出异常 // 无法识别该关键字或条件不满足则报错
throw new RuntimeException("未识别的关键字或条件不满足: " + keyword); throw new RuntimeException("未识别的关键字或条件不满足: " + keyword);
} }
// 每次解析完成后继续跳过空行准备进入下一个区块的判断
while (tokens.peek().getType() == TokenType.NEWLINE) {
tokens.next();
} }
} }
/**
* 跳过所有连续的注释行和空行
*
* @param tokens 词法流
*/
private static void skipCommentsAndNewlines(TokenStream tokens) {
while (true) {
TokenType type = tokens.peek().getType();
if (type == TokenType.COMMENT || type == TokenType.NEWLINE) {
tokens.next();
continue;
}
break;
}
} }
/** /**
* 区块定义类表示一个语法区块的匹配条件和解析逻辑 * 区块定义类表示一个语法区块的匹配条件和解析逻辑
* <p>
* 每个区块由两个部分组成 * 每个区块由两个部分组成
* - 条件用于判断当前 token 流是否应进入该区块的解析 * - 条件用于判断当前 token 流是否应进入该区块的解析
* - 解析器具体的解析逻辑通常是消费若干 token 并更新解析上下文 * - 解析器具体的解析逻辑通常是消费若干 token 并更新解析上下文
* </p>
* *
* @param condition 匹配条件返回 true 表示此区块应被解析 * @param condition 匹配条件返回 true 表示此区块应被解析
* @param parser 实际解析逻辑 * @param parser 实际解析逻辑
*/ */
public record SectionDefinition(Predicate<TokenStream> condition, BiConsumer<ParserContext, TokenStream> parser) { public record SectionDefinition(Predicate<TokenStream> condition,
BiConsumer<ParserContext, TokenStream> parser) {
/**
* 获取条件判断函数
*
* @return 一个用于判断是否进入该区块的 Predicate
*/
@Override @Override
public Predicate<TokenStream> condition() { public Predicate<TokenStream> condition() {
return condition; return condition;
} }
/**
* 获取解析器函数
*
* @return 一个解析该区块的 BiConsumer 函数
*/
@Override @Override
public BiConsumer<ParserContext, TokenStream> parser() { public BiConsumer<ParserContext, TokenStream> parser() {
return parser; return parser;

3
test
View File

@ -2,9 +2,10 @@ module: CommonTasks
function: main1 function: main1
parameter: parameter:
declare num1: int declare num1: int
declare num2: int declare num2: int // 1
return_type:int return_type:int
body: body:
num1 = 10 num1 = 10
return num1 return num1