diff --git a/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java b/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java index a658d9d..b725ff1 100644 --- a/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java +++ b/src/main/java/org/jcnc/snow/compiler/ir/builder/ExpressionBuilder.java @@ -3,6 +3,7 @@ package org.jcnc.snow.compiler.ir.builder; import org.jcnc.snow.compiler.ir.core.IROpCode; import org.jcnc.snow.compiler.ir.instruction.CallInstruction; import org.jcnc.snow.compiler.ir.instruction.LoadConstInstruction; +import org.jcnc.snow.compiler.ir.instruction.UnaryOperationInstruction; import org.jcnc.snow.compiler.ir.value.IRConstant; import org.jcnc.snow.compiler.ir.value.IRVirtualRegister; import org.jcnc.snow.compiler.ir.utils.ExpressionUtils; @@ -59,11 +60,32 @@ public record ExpressionBuilder(IRContext ctx) { case BinaryExpressionNode bin -> buildBinary(bin); // 函数调用 case CallExpressionNode call -> buildCall(call); + case UnaryExpressionNode u -> buildUnary(u); default -> throw new IllegalStateException( "不支持的表达式类型: " + expr.getClass().getSimpleName()); }; } + private IRVirtualRegister buildUnary(UnaryExpressionNode un) { + String op = un.operator(); + IRVirtualRegister val = build(un.operand()); + + // -x → NEG_I32 + if (op.equals("-")) { + IRVirtualRegister dest = ctx.newRegister(); + ctx.addInstruction(new UnaryOperationInstruction( + IROpCode.NEG_I32, dest, val)); + return dest; + } + + // !x → (x == 0) + if (op.equals("!")) { + IRVirtualRegister zero = InstructionFactory.loadConst(ctx, 0); + return InstructionFactory.binOp(ctx, IROpCode.CMP_EQ, val, zero); + } + + throw new IllegalStateException("未知一元运算符: " + op); + } /** * 直接将表达式计算结果写入指定的目标寄存器(dest)。 diff --git a/src/main/java/org/jcnc/snow/compiler/lexer/token/TokenFactory.java b/src/main/java/org/jcnc/snow/compiler/lexer/token/TokenFactory.java index 98155f6..e6463f4 100644 --- a/src/main/java/org/jcnc/snow/compiler/lexer/token/TokenFactory.java +++ b/src/main/java/org/jcnc/snow/compiler/lexer/token/TokenFactory.java @@ -19,9 +19,6 @@ import java.util.Set; *
  • 对不合法的词素自动标记为 UNKNOWN 类型。
  • * *

    - * - * @author 你的名字 - * @version 1.0 */ public class TokenFactory { 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 new file mode 100644 index 0000000..be60c24 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/parser/ast/UnaryExpressionNode.java @@ -0,0 +1,17 @@ +package org.jcnc.snow.compiler.parser.ast; + +import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; + +/** + * 一元表达式节点,例如 -x 或 !x。 + * + * @param operator 运算符字符串 ("-" / "!") + * @param operand 操作数表达式 + */ +public record UnaryExpressionNode(String operator, + ExpressionNode operand) implements ExpressionNode { + + @Override public String toString() { + return operator + operand; + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/parser/expression/PrattExpressionParser.java b/src/main/java/org/jcnc/snow/compiler/parser/expression/PrattExpressionParser.java index 1a1d124..4f79274 100644 --- a/src/main/java/org/jcnc/snow/compiler/parser/expression/PrattExpressionParser.java +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/PrattExpressionParser.java @@ -45,6 +45,10 @@ public class PrattExpressionParser implements ExpressionParser { prefixes.put(TokenType.STRING_LITERAL.name(), new StringLiteralParselet()); prefixes.put(TokenType.BOOL_LITERAL.name(), new BoolLiteralParselet()); + // 注册一元前缀运算 + prefixes.put(TokenType.MINUS.name(), new UnaryOperatorParselet()); + prefixes.put(TokenType.NOT.name(), new UnaryOperatorParselet()); + // 注册中缀解析器 infixes.put("+", new BinaryOperatorParselet(Precedence.SUM, true)); infixes.put("-", new BinaryOperatorParselet(Precedence.SUM, true)); 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 new file mode 100644 index 0000000..9d7a323 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/parser/expression/UnaryOperatorParselet.java @@ -0,0 +1,19 @@ +package org.jcnc.snow.compiler.parser.expression; + +import org.jcnc.snow.compiler.lexer.token.Token; +import org.jcnc.snow.compiler.parser.ast.UnaryExpressionNode; +import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode; +import org.jcnc.snow.compiler.parser.context.ParserContext; +import org.jcnc.snow.compiler.parser.expression.base.PrefixParselet; + +/** 前缀一元运算解析器(支持 - 和 !) */ +public class UnaryOperatorParselet implements PrefixParselet { + + @Override + public ExpressionNode parse(ParserContext ctx, Token token) { + // 递归解析右侧,使用自身优先级 + ExpressionNode right = + new PrattExpressionParser().parseExpression(ctx, Precedence.UNARY); + return new UnaryExpressionNode(token.getLexeme(), right); + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/UnaryExpressionAnalyzer.java b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/UnaryExpressionAnalyzer.java new file mode 100644 index 0000000..37f2ec0 --- /dev/null +++ b/src/main/java/org/jcnc/snow/compiler/semantic/analyzers/expression/UnaryExpressionAnalyzer.java @@ -0,0 +1,49 @@ +package org.jcnc.snow.compiler.semantic.analyzers.expression; + +import org.jcnc.snow.compiler.parser.ast.FunctionNode; +import org.jcnc.snow.compiler.parser.ast.UnaryExpressionNode; +import org.jcnc.snow.compiler.semantic.analyzers.base.ExpressionAnalyzer; +import org.jcnc.snow.compiler.semantic.core.Context; +import org.jcnc.snow.compiler.semantic.core.ModuleInfo; +import org.jcnc.snow.compiler.semantic.error.SemanticError; +import org.jcnc.snow.compiler.semantic.symbol.SymbolTable; +import org.jcnc.snow.compiler.semantic.type.BuiltinType; +import org.jcnc.snow.compiler.semantic.type.Type; + +/** 一元表达式语义分析 */ +public class UnaryExpressionAnalyzer implements ExpressionAnalyzer { + + @Override + public Type analyze(Context ctx, ModuleInfo mi, FunctionNode fn, + SymbolTable locals, UnaryExpressionNode expr) { + + // 先分析操作数 + Type operandType = ctx.getRegistry() + .getExpressionAnalyzer(expr.operand()) + .analyze(ctx, mi, fn, locals, expr.operand()); + + switch (expr.operator()) { + case "-" -> { + if (!operandType.isNumeric()) { + ctx.getErrors().add(new SemanticError(expr, + "'-' 只能应用于数值类型,当前为 " + operandType)); + return BuiltinType.INT; + } + return operandType; + } + case "!" -> { + if (operandType != BuiltinType.BOOLEAN) { + ctx.getErrors().add(new SemanticError(expr, + "'!' 只能应用于 boolean 类型,当前为 " + operandType)); + return BuiltinType.BOOLEAN; + } + return BuiltinType.BOOLEAN; + } + default -> { + ctx.getErrors().add(new SemanticError(expr, + "未知一元运算符: " + expr.operator())); + return BuiltinType.INT; + } + } + } +} diff --git a/src/main/java/org/jcnc/snow/compiler/semantic/core/AnalyzerRegistrar.java b/src/main/java/org/jcnc/snow/compiler/semantic/core/AnalyzerRegistrar.java index 865bb5e..c8de9e0 100644 --- a/src/main/java/org/jcnc/snow/compiler/semantic/core/AnalyzerRegistrar.java +++ b/src/main/java/org/jcnc/snow/compiler/semantic/core/AnalyzerRegistrar.java @@ -55,7 +55,10 @@ public final class AnalyzerRegistrar { registry.registerExpressionAnalyzer(CallExpressionNode.class, new CallExpressionAnalyzer()); registry.registerExpressionAnalyzer(BinaryExpressionNode.class, new BinaryExpressionAnalyzer()); - // 对尚未实现的表达式类型使用兜底处理器(如 MemberExpression) + // ---------- 注册一元表达式分析器 ---------- + registry.registerExpressionAnalyzer(UnaryExpressionNode.class,new UnaryExpressionAnalyzer()); + + // 对尚未实现的表达式类型使用兜底处理器 registry.registerExpressionAnalyzer(MemberExpressionNode.class, new UnsupportedExpressionAnalyzer<>()); }