支持float32double64byte8short15float32double64

This commit is contained in:
Luke 2025-05-10 16:34:46 +08:00
parent 59dbafb2b6
commit a7e2e61b10
4 changed files with 263 additions and 209 deletions

View File

@ -1,6 +1,9 @@
package org.jcnc.snow.compiler.ir.builder;
import org.jcnc.snow.compiler.ir.core.IROpCode;
import org.jcnc.snow.compiler.ir.instruction.BinaryOperationInstruction;
import org.jcnc.snow.compiler.ir.instruction.LoadConstInstruction;
import org.jcnc.snow.compiler.ir.value.IRConstant;
import org.jcnc.snow.compiler.ir.value.IRVirtualRegister;
import org.jcnc.snow.compiler.parser.ast.BinaryExpressionNode;
import org.jcnc.snow.compiler.parser.ast.IdentifierNode;
@ -10,79 +13,104 @@ import org.jcnc.snow.compiler.parser.ast.base.ExpressionNode;
import java.util.Map;
/**
* ExpressionBuilder 负责将 AST 中的 ExpressionNode 构建为 IR 指令并返回结果寄存器
* <p>
* 功能
* ExpressionBuilder AST 中的 ExpressionNode 转换为 IR 指令并返回结果虚拟寄存器
* 支持
* <ol>
* <li>处理数字字面量节点生成加载常量指令</li>
* <li>处理标识符节点从作用域获取对应的虚拟寄存器</li>
* <li>处理二元表达式节点递归构建左右操作数并生成二元运算指令</li>
* <li>NumberLiteralNode根据文本后缀b/S/L/f/d或内容自动区分 bytke/short/int/long/float/double并生成常量加载指令</li>
* <li>IdentifierNode从作用域获取已声明的虚拟寄存器</li>
* <li>BinaryExpressionNode递归构建子表达式根据数据宽度和符号生成对应的二元运算指令</li>
* </ol>
*/
public class ExpressionBuilder {
/**
* 操作符到 IR 操作码的映射表
*/
private static final Map<String, IROpCode> OP_MAP = Map.of(
"+", IROpCode.ADD_I32,
"-", IROpCode.SUB_I32,
"*", IROpCode.MUL_I32,
"/", IROpCode.DIV_I32
);
// 不同位宽整数和浮点的运算码映射
private static final Map<String, IROpCode> OP_I8 = Map.of("+", IROpCode.ADD_B8, "-", IROpCode.SUB_B8, "*", IROpCode.MUL_B8, "/", IROpCode.DIV_B8);
private static final Map<String, IROpCode> OP_I16 = Map.of("+", IROpCode.ADD_S16, "-", IROpCode.SUB_S16, "*", IROpCode.MUL_S16, "/", IROpCode.DIV_S16);
private static final Map<String, IROpCode> OP_I32 = Map.of("+", IROpCode.ADD_I32, "-", IROpCode.SUB_I32, "*", IROpCode.MUL_I32, "/", IROpCode.DIV_I32);
private static final Map<String, IROpCode> OP_L64 = Map.of("+", IROpCode.ADD_L64, "-", IROpCode.SUB_L64, "*", IROpCode.MUL_L64, "/", IROpCode.DIV_L64);
private static final Map<String, IROpCode> OP_F32 = Map.of("+", IROpCode.ADD_F32, "-", IROpCode.SUB_F32, "*", IROpCode.MUL_F32, "/", IROpCode.DIV_F32);
private static final Map<String, IROpCode> OP_D64 = Map.of("+", IROpCode.ADD_D64, "-", IROpCode.SUB_D64, "*", IROpCode.MUL_D64, "/", IROpCode.DIV_D64);
/**
* 当前 IR 构建上下文包含 IRFunction IRBuilderScope
*/
private final IRContext ctx;
/**
* 构造方法注入 IRContext
*
* @param ctx 构建 IR 所需上下文管理函数作用域和指令添加
*/
public ExpressionBuilder(IRContext ctx) {
this.ctx = ctx;
}
/**
* 将给定的表达式节点转换为 IR并返回存放结果的虚拟寄存器
*
* @param expr 要构建的表达式节点
* @return 存放表达式计算结果的虚拟寄存器
* @throws IllegalStateException 若遇到不支持的表达式节点或未定义变量
*/
public IRVirtualRegister build(ExpressionNode expr) {
// 处理数字常
// 1. 常量字面量
if (expr instanceof NumberLiteralNode(String value)) {
int v = Integer.parseInt(value);
// 生成加载常量指令并返回结果寄存器
return InstructionFactory.loadConst(ctx, v);
// 判断后缀
char suffix = value.isEmpty() ? '\0' : Character.toLowerCase(value.charAt(value.length() - 1));
String digits = (suffix == 'b' || suffix == 's' || suffix == 'l' || suffix == 'f' || suffix == 'd') ? value.substring(0, value.length() - 1) : value;
IRVirtualRegister reg = ctx.newRegister();
switch (suffix) {
case 'b': // byte
byte bv = Byte.parseByte(digits);
ctx.addInstruction(new LoadConstInstruction(reg, new IRConstant(bv)));
break;
case 's': // short
short sv = Short.parseShort(digits);
ctx.addInstruction(new LoadConstInstruction(reg, new IRConstant(sv)));
break;
case 'l': // long
long lv = Long.parseLong(digits);
ctx.addInstruction(new LoadConstInstruction(reg, new IRConstant(lv)));
break;
case 'f': // float
float fv = Float.parseFloat(digits);
ctx.addInstruction(new LoadConstInstruction(reg, new IRConstant(fv)));
break;
case 'd': // double
double dv = Double.parseDouble(digits);
ctx.addInstruction(new LoadConstInstruction(reg, new IRConstant(dv)));
break;
default: // 无后缀数字中有小数点或指数 => double否则 int
if (digits.contains(".") || digits.matches(".*[eE].*")) {
double dd = Double.parseDouble(digits);
ctx.addInstruction(new LoadConstInstruction(reg, new IRConstant(dd)));
} else {
int iv = Integer.parseInt(digits);
ctx.addInstruction(new LoadConstInstruction(reg, new IRConstant(iv)));
}
}
return reg;
}
// 处理变量引用
// 2. 标识符 => 作用域寄存器
if (expr instanceof IdentifierNode(String name)) {
// 从作用域查找已声明的寄存器
IRVirtualRegister vr = ctx.getScope().lookup(name);
if (vr == null) {
throw new IllegalStateException("未定义的变量: " + name);
}
return vr;
IRVirtualRegister reg = ctx.getScope().lookup(name);
if (reg == null) throw new IllegalStateException("未定义变量: " + name);
return reg;
}
// 处理二元表达式
// 3. 二元表达式
if (expr instanceof BinaryExpressionNode(ExpressionNode left, String operator, ExpressionNode right)) {
// 递归构建左右子表达式
IRVirtualRegister l = build(left);
IRVirtualRegister r = build(right);
// 根据操作符获取 IR 操作码
IROpCode op = OP_MAP.get(operator);
if (op == null) {
throw new IllegalStateException("不支持的运算符: " + operator);
}
// 生成二元运算指令并返回结果寄存器
return InstructionFactory.binOp(ctx, op, l, r);
IRVirtualRegister lreg = build(left);
IRVirtualRegister rreg = build(right);
// 判断计算类型检查两侧是否为 NumberLiteralNode 并提取后缀
char leftS = (left instanceof NumberLiteralNode(
String value
)) ? Character.toLowerCase(value.charAt(value.length() - 1)) : '\0';
char rightS = (right instanceof NumberLiteralNode(
String value
)) ? Character.toLowerCase(value.charAt(value.length() - 1)) : '\0';
// 选择优先级: byte < short < int < long < float < double
char suf = (leftS == 'd' || rightS == 'd') ? 'd' : (leftS == 'f' || rightS == 'f') ? 'f' : (leftS == 'l' || rightS == 'l') ? 'l' : (leftS == 's' || rightS == 's') ? 's' : (leftS == 'b' || rightS == 'b') ? 'b' : '\0';
IROpCode code = switch (suf) {
case 'b' -> OP_I8.get(operator);
case 's' -> OP_I16.get(operator);
case 'l' -> OP_L64.get(operator);
case 'f' -> OP_F32.get(operator);
case 'd' -> OP_D64.get(operator);
default -> OP_I32.get(operator);
};
if (code == null) throw new IllegalStateException("不支持的运算符: " + operator);
IRVirtualRegister dest = ctx.newRegister();
ctx.addInstruction(new BinaryOperationInstruction(code, dest, lreg, rreg));
return dest;
}
// 其他表达式类型暂不支持
throw new IllegalStateException(
"不支持的表达式类型: " + expr.getClass().getSimpleName()
);
throw new IllegalStateException("不支持的表达式类型: " + expr.getClass().getSimpleName());
}
}

View File

@ -4,75 +4,92 @@ package org.jcnc.snow.compiler.ir.core;
* IROpCode IR 层支持的操作码Opcode枚举类型
* <p>
* 本枚举类定义了中间表示层可用的所有基本指令类型 {@link IRInstruction} 使用
* 每个枚举值代表一种语义明确的 IR 操作涵盖常见的算术逻辑数据操作和控制流指令
* 每个枚举值代表一种语义明确的 IR 操作涵盖不同位宽的整数和浮点算术逻辑数据操作和控制流指令
* 可根据后续需求继续扩展
*/
public enum IROpCode {
/* ───── 算术运算 ───── */
/* ───── 算术运算 (8位整数: byte) ───── */
/** 8位整型加法 (byte): a = b + c */
ADD_B8,
/** 8位整型减法 */
SUB_B8,
/** 8位整型乘法 */
MUL_B8,
/** 8位整型除法 */
DIV_B8,
/** 8位整型取负 */
NEG_B8,
/** 整型加法32位形如a = b + c */
/* ───── 算术运算 (16位整数: short) ───── */
/** 16位整型加法 (short) */
ADD_S16,
/** 16位整型减法 */
SUB_S16,
/** 16位整型乘法 */
MUL_S16,
/** 16位整型除法 */
DIV_S16,
/** 16位整型取负 */
NEG_S16,
/* ───── 算术运算 (32位整数: int) ───── */
/** 32位整型加法 (int) */
ADD_I32,
/** 整型减法32位形如a = b - c */
/** 32位整型减法 */
SUB_I32,
/** 整型乘法32位形如a = b * c */
/** 32位整型乘法 */
MUL_I32,
/** 整型除法32位形如a = b / c */
/** 32位整型除法 */
DIV_I32,
/** 整型取负32位形如a = -b一元运算 */
/** 32位整型取负 */
NEG_I32,
/* ───── 算术运算 (64位整数: long) ───── */
/** 64位整型加法 (long) */
ADD_L64,
/** 64位整型减法 */
SUB_L64,
/** 64位整型乘法 */
MUL_L64,
/** 64位整型除法 */
DIV_L64,
/** 64位整型取负 */
NEG_L64,
/* ───── 算术运算 (单精度浮点: float) ───── */
ADD_F32,
SUB_F32,
MUL_F32,
DIV_F32,
NEG_F32,
/* ───── 算术运算 (双精度浮点: double) ───── */
ADD_D64,
SUB_D64,
MUL_D64,
DIV_D64,
NEG_D64,
/* ───── 逻辑/比较运算 ───── */
/** 相等比较(==结果为布尔值形如a = (b == c) */
CMP_EQ,
/** 不等比较(!=结果为布尔值形如a = (b != c) */
CMP_NE,
/** 小于比较(<结果为布尔值形如a = (b < c) */
CMP_LT,
/** 大于比较(>结果为布尔值形如a = (b > c) */
CMP_GT,
/** 小于等于(<=结果为布尔值形如a = (b <= c) */
CMP_LE,
/** 大于等于(>=结果为布尔值形如a = (b >= c) */
CMP_GE,
/* ───── 数据搬运 ───── */
/** 从内存加载到寄存器Load形如a = *addr */
LOAD,
/** 将数据存储到内存地址Store形如*addr = a */
STORE,
/** 加载常量值IRConstant到寄存器形如a = 123 */
CONST,
/* ───── 控制流 ───── */
/** 无条件跳转Jump直接跳转到指定标签位置 */
JUMP,
/** 条件跳转Jump if zero如果条件为 0 则跳转 */
JUMP_IF_ZERO,
/** 标签定义Label作为跳转目标使用 */
LABEL,
/* ───── 函数调用相关 ───── */
/** 函数调用Call可能带返回值和参数 */
CALL,
/** 函数返回Return结束当前函数执行可返回值 */
RET
}

View File

@ -1,5 +1,6 @@
package org.jcnc.snow.compiler.parser.function;
import org.jcnc.snow.compiler.lexer.token.Token;
import org.jcnc.snow.compiler.lexer.token.TokenType;
import org.jcnc.snow.compiler.parser.base.TopLevelParser;
import org.jcnc.snow.compiler.parser.ast.FunctionNode;
@ -17,104 +18,97 @@ import java.util.List;
import java.util.Map;
/**
* {@code FunctionParser} 是一个顶层语法分析器用于解析函数定义的语法结构
* <p>
* 该解析器通过 {@code FlexibleSectionParser} 解析函数定义的多个部分包括
* <ul>
* <li>函数名</li>
* <li>参数列表</li>
* <li>返回类型</li>
* <li>函数体</li>
* </ul>
* 各部分的顺序不固定 FlexibleSectionParser 按规则识别和处理
* </p>
* 顶层的函数定义解析器
*
* 通过 FlexibleSectionParser 按区块顺序解析函数的各个部分
* 函数头名称参数列表返回类型函数体并最终生成 FunctionNode
* 支持在参数或返回类型声明中出现注释自动跳过注释和空行而不干扰语法解析
*/
public class FunctionParser implements TopLevelParser {
/**
* 解析函数定义构建函数的抽象语法树节点
* <p>
* 此方法首先解析函数的头部和名称然后通过 FlexibleSectionParser
* 分别解析函数的参数返回类型和函数体最后封装为 FunctionNode 返回
* </p>
* 顶层解析入口解析完整个函数定义并返回 FunctionNode
*
* @param ctx 解析上下文包含 Token 作用域信息等
* @return 构建完成 FunctionNode
* @param ctx 解析上下文包含 TokenStream 和作用域信息
* @return 构建好的 FunctionNode
*/
@Override
public FunctionNode parse(ParserContext ctx) {
TokenStream tokens = ctx.getTokens();
TokenStream ts = ctx.getTokens();
// 匹配并消费 "function:" 标记
parseFunctionHeader(tokens);
// 1. 解析函数头function:
parseFunctionHeader(ts);
// 2. 读取并消费函数名称
String functionName = parseFunctionName(ts);
// 获取函数名称
String functionName = parseFunctionName(tokens);
// 用于接收参数返回类型和函数体的容器
// 容器用于收集解析结果
List<ParameterNode> parameters = new ArrayList<>();
String[] returnType = {null}; // 使用数组模拟引用以便 lambda 内修改值
String[] returnType = new String[1]; // 用一元素数组模拟可变引用
List<StatementNode> body = new ArrayList<>();
// 构建区块解析定义参数返回类型函数体
Map<String, SectionDefinition> sectionDefinitions = getStringSectionDefinitionMap(parameters, returnType, body);
// 3. 构建区块解析逻辑并使用 FlexibleSectionParser 解析
Map<String, SectionDefinition> sections = getSectionDefinitions(parameters, returnType, body);
FlexibleSectionParser.parse(ctx, ts, sections);
// 使用 FlexibleSectionParser 解析区块顺序无关
FlexibleSectionParser.parse(ctx, tokens, sectionDefinitions);
// 4. 解析函数尾部end function
parseFunctionFooter(ts);
// 匹配函数结束部分end function
parseFunctionFooter(tokens);
// 构建语法树节点并返回
// 5. 构造并返回 AST
return new FunctionNode(functionName, parameters, returnType[0], body);
}
/**
* 构造区块定义映射包括参数返回类型函数体
* 构造各区块的解析定义
* 参数parameter返回类型return_type函数体body
*
* @param parameters 参数节点容器
* @param returnType 返回类型容器数组模拟引用
* @param body 函数体语句节点容器
* @return 各关键字对应的解析逻辑映射
* @param params 参数节点列表容器
* @param returnType 返回类型容器
* @param body 函数体语句列表容器
* @return 区块关键字到解析逻辑的映射
*/
private Map<String, SectionDefinition> getStringSectionDefinitionMap(List<ParameterNode> parameters, String[] returnType, List<StatementNode> body) {
Map<String, SectionDefinition> sectionDefinitions = new HashMap<>();
private Map<String, SectionDefinition> getSectionDefinitions(
List<ParameterNode> params,
String[] returnType,
List<StatementNode> body) {
Map<String, SectionDefinition> map = new HashMap<>();
// 参数部分解析规则
sectionDefinitions.put("parameter", new SectionDefinition(
ts -> ts.peek().getLexeme().equals("parameter"),
(_, ts1) -> parameters.addAll(parseParameters(ts1))
// 参数区块
map.put("parameter", new SectionDefinition(
(TokenStream stream) -> stream.peek().getLexeme().equals("parameter"),
(ParserContext context, TokenStream stream) -> params.addAll(parseParameters(stream))
));
// 返回类型部分解析规则
sectionDefinitions.put("return_type", new SectionDefinition(
ts -> ts.peek().getLexeme().equals("return_type"),
(_, ts1) -> returnType[0] = parseReturnType(ts1)
// 返回类型区块
map.put("return_type", new SectionDefinition(
(TokenStream stream) -> stream.peek().getLexeme().equals("return_type"),
(ParserContext context, TokenStream stream) -> returnType[0] = parseReturnType(stream)
));
// 函数体部分解析规则
sectionDefinitions.put("body", new SectionDefinition(
ts -> ts.peek().getLexeme().equals("body"),
(ctx1, ts1) -> body.addAll(parseFunctionBody(ctx1, ts1))
// 函数体区块
map.put("body", new SectionDefinition(
(TokenStream stream) -> stream.peek().getLexeme().equals("body"),
(ParserContext context, TokenStream stream) -> body.addAll(parseFunctionBody(context, stream))
));
return sectionDefinitions;
return map;
}
/**
* 匹配并解析函数头部function:
* 解析函数头部匹配 "function:"并跳过后续的注释和空行
*
* @param ts Token
* @param ts TokenStream
*/
private void parseFunctionHeader(TokenStream ts) {
ts.expect("function");
ts.expect(":");
skipComments(ts);
skipNewlines(ts);
}
/**
* 解析函数名称并跳过换行
* 解析函数名称IDENTIFIER + 换行
*
* @param ts Token
* @param ts TokenStream
* @return 函数名称
*/
private String parseFunctionName(TokenStream ts) {
@ -124,9 +118,9 @@ public class FunctionParser implements TopLevelParser {
}
/**
* 匹配并解析函数尾部end function
* 解析函数尾部匹配 "end function" + 换行
*
* @param ts Token
* @param ts TokenStream
*/
private void parseFunctionFooter(TokenStream ts) {
ts.expect("end");
@ -135,108 +129,123 @@ public class FunctionParser implements TopLevelParser {
}
/**
* 解析函数参数部分格式
* 解析参数区块参数列表支持在声明行尾添加注释
* 格式
* <pre>
* parameter:
* declare param1: int
* declare param2: string
* declare x: int // 注释
* ...
* </pre>
*
* @param ts Token
* @return 参数节点列表
* @param ts TokenStream
* @return ParameterNode 列表
*/
private List<ParameterNode> parseParameters(TokenStream ts) {
ts.expect("parameter");
ts.expect(":");
skipComments(ts);
ts.expectType(TokenType.NEWLINE);
skipNewlines(ts);
List<ParameterNode> params = new ArrayList<>();
// 持续解析参数声明行直到下一个区块或 "end"
List<ParameterNode> list = new ArrayList<>();
while (true) {
skipComments(ts);
if (ts.peek().getType() == TokenType.NEWLINE) {
ts.next(); // 跳过空行
ts.next();
continue;
}
// 到达下一个区块或函数结尾时停止
String keyword = ts.peek().getLexeme();
if ("return_type".equals(keyword) || "body".equals(keyword) || "end".equals(keyword)) {
String lex = ts.peek().getLexeme();
if (lex.equals("return_type") || lex.equals("body") || lex.equals("end")) {
break;
}
// 匹配 "declare paramName: Type" 格式
ts.expect("declare");
String paramName = ts.expectType(TokenType.IDENTIFIER).getLexeme();
String pname = ts.expectType(TokenType.IDENTIFIER).getLexeme();
ts.expect(":");
String paramType = ts.expectType(TokenType.TYPE).getLexeme();
String ptype = ts.expectType(TokenType.TYPE).getLexeme();
// 跳过行内注释
skipComments(ts);
ts.expectType(TokenType.NEWLINE);
params.add(new ParameterNode(paramName, paramType));
list.add(new ParameterNode(pname, ptype));
}
return params;
return list;
}
/**
* 解析返回类型部分格式如下
* <pre>
* return_type: int
* </pre>
* 解析返回类型区块支持在类型声明前后添加注释
* 格式<pre>return_type: TYPE</pre>
*
* @param ts Token
* @param ts TokenStream
* @return 返回类型字符串
*/
private String parseReturnType(TokenStream ts) {
ts.expect("return_type");
ts.expect(":");
String returnType = ts.expectType(TokenType.TYPE).getLexeme();
// 跳过块前注释
skipComments(ts);
// 捕获类型 token
Token typeToken = ts.expectType(TokenType.TYPE);
String rtype = typeToken.getLexeme();
// 跳过行内注释
skipComments(ts);
// 匹配换行
ts.expectType(TokenType.NEWLINE);
return returnType;
// 跳过多余空行
skipNewlines(ts);
return rtype;
}
/**
* 解析函数体部分格式示例
* <pre>
* body:
* print "hello"
* return x
* end body
* </pre>
* 解析函数体区块直到遇到 "end body"
*
* @param ctx 解析上下文
* @param ts Token
* @return 语句节点列表
* @param ctx ParserContext
* @param ts TokenStream
* @return StatementNode 列表
*/
private List<StatementNode> parseFunctionBody(ParserContext ctx, TokenStream ts) {
ts.expect("body");
ts.expect(":");
skipComments(ts);
ts.expectType(TokenType.NEWLINE);
skipNewlines(ts);
List<StatementNode> body = new ArrayList<>();
// 持续解析直到遇到 end
List<StatementNode> stmts = new ArrayList<>();
while (true) {
skipComments(ts);
if (ts.peek().getType() == TokenType.NEWLINE) {
ts.next();
continue;
}
if ("end".equals(ts.peek().getLexeme())) {
break;
}
// 获取当前语句关键字并通过工厂选择对应的语句解析器
String keyword = ts.peek().getLexeme();
StatementNode statement = StatementParserFactory.get(keyword).parse(ctx);
body.add(statement);
stmts.add(StatementParserFactory.get(ts.peek().getLexeme()).parse(ctx));
}
// 匹配 end body
ts.expect("end");
ts.expect("body");
ts.expectType(TokenType.NEWLINE);
skipNewlines(ts);
return stmts;
}
return body;
/**
* 跳过所有连续的注释行COMMENT
*
* @param ts TokenStream
*/
private void skipComments(TokenStream ts) {
while (ts.peek().getType() == TokenType.COMMENT) {
ts.next();
}
}
/**
* 跳过所有连续的空行NEWLINE
*
* @param ts TokenStream
*/
private void skipNewlines(TokenStream ts) {
while (ts.peek().getType() == TokenType.NEWLINE) {
ts.next();
}
}
}

6
test
View File

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