refactor(ast2ir): 移除废弃的ABI依赖并优化类型转换处理
移除了对scc_abi包的依赖,将相关头文件从libs/abi移动到libs/ast2ir目录下。 重构了基本类型解析功能,将parse_base_type函数提取为独立的 scc_ast2ir_parse_base_type实现,并支持有符号/无符号类型区分。 feat(ast2ir): 实现整数常量表达式求值器 新增了完整的整数常量表达式求值功能,支持C11标准中的常量表达式规则, 包括字面量、标识符、sizeof/_Alignof、一元/二元运算、条件表达式和 类型转换等操作。该功能用于数组大小和枚举值的编译期计算验证。 refactor(ast2ir): 完善类型提升和算术转换机制 改进了整数提升和寻常算术转换的实现,修复了移位操作的符号处理问题, 添加了无符号比较操作的支持,增强了类型安全检查,统一了错误处理流程。 fix(ast2ir): 修复赋值表达式返回值和数组大小计算问题 修正了赋值表达式的返回值处理,确保返回右侧值而不是存储指令引用。 使用新的常量表达式求值器替代原有的硬编码数组大小计算,提高了 数组声明的正确性。
This commit is contained in:
@@ -1,48 +1,394 @@
|
||||
#include <ap.h>
|
||||
|
||||
static void *scc_ap_alloc(size_t size) {
|
||||
void *p = SCC_AP_MALLOC(size);
|
||||
SCC_AP_ASSERT(p != NULL);
|
||||
return p;
|
||||
/*
|
||||
* Fast-path (hack) implementation: all values stored in single-digit mode.
|
||||
* data.digit holds the absolute magnitude as u64, len sign indicates sign.
|
||||
* Arithmetic is done via isize with explicit overflow checks — anything
|
||||
* out of isize range triggers SCC_AP_PANIC.
|
||||
*/
|
||||
|
||||
/* ---------- internal helpers ---------- */
|
||||
|
||||
/* Convert from sign-magnitude (digit mode) to isize */
|
||||
static isize ap_to_isize(const scc_ap_t *ap) {
|
||||
SCC_AP_ASSERT(ap != nullptr);
|
||||
SCC_AP_ASSERT(ap->capacity == -1);
|
||||
uint64_t mag = ap->data.digit;
|
||||
if (ap->len < 0) {
|
||||
if (mag == 0)
|
||||
return 0;
|
||||
if (mag == (uint64_t)INTPTR_MAX + 1)
|
||||
return INTPTR_MIN;
|
||||
SCC_AP_ASSERT(mag <= (uint64_t)INTPTR_MAX);
|
||||
return -(isize)(int64_t)mag;
|
||||
}
|
||||
SCC_AP_ASSERT(mag <= (uint64_t)INTPTR_MAX);
|
||||
return (isize)(int64_t)mag;
|
||||
}
|
||||
|
||||
/* 重新分配内存 */
|
||||
static void *scc_ap_realloc_data(void *old, size_t new_size) {
|
||||
void *p = SCC_AP_REALLOC(old, new_size);
|
||||
SCC_AP_ASSERT(p != NULL);
|
||||
return p;
|
||||
/* Store isize value into sign-magnitude (digit mode) */
|
||||
static void ap_from_isize(scc_ap_t *ap, isize val) {
|
||||
ap->capacity = -1;
|
||||
if (val < 0) {
|
||||
ap->len = -1;
|
||||
ap->data.digit = (scc_ap_digit)(-(uint64_t)(int64_t)val);
|
||||
} else {
|
||||
ap->len = 1;
|
||||
ap->data.digit = (scc_ap_digit)val;
|
||||
}
|
||||
}
|
||||
|
||||
/* Checked addition */
|
||||
static isize ap_add_isize(isize a, isize b) {
|
||||
if (b > 0 && a > INTPTR_MAX - b)
|
||||
SCC_AP_PANIC("scc_ap_add: positive overflow");
|
||||
if (b < 0 && a < INTPTR_MIN - b)
|
||||
SCC_AP_PANIC("scc_ap_add: negative overflow");
|
||||
return a + b;
|
||||
}
|
||||
|
||||
/* Checked subtraction: a - b */
|
||||
static isize ap_sub_isize(isize a, isize b) {
|
||||
/* a - b = a + (-b); -INTPTR_MIN overflows, handle specially */
|
||||
if (b == INTPTR_MIN) {
|
||||
if (a < 0)
|
||||
SCC_AP_PANIC("scc_ap_sub: overflow (a - INTPTR_MIN, a < 0)");
|
||||
SCC_AP_PANIC("scc_ap_sub: overflow (a - INTPTR_MIN, a >= 0)");
|
||||
}
|
||||
return ap_add_isize(a, -b);
|
||||
}
|
||||
|
||||
/* Checked multiplication */
|
||||
static isize ap_mul_isize(isize a, isize b) {
|
||||
if (a == 0 || b == 0)
|
||||
return 0;
|
||||
if (a == 1)
|
||||
return b;
|
||||
if (b == 1)
|
||||
return a;
|
||||
|
||||
/* Determine sign of result */
|
||||
int sign = ((a < 0) == (b < 0)) ? 1 : -1;
|
||||
|
||||
/* Absolute values as uint64 */
|
||||
uint64_t ua = (a == INTPTR_MIN)
|
||||
? (uint64_t)INTPTR_MAX + 1
|
||||
: (uint64_t)(a < 0 ? -(int64_t)a : (int64_t)a);
|
||||
uint64_t ub = (b == INTPTR_MIN)
|
||||
? (uint64_t)INTPTR_MAX + 1
|
||||
: (uint64_t)(b < 0 ? -(int64_t)b : (int64_t)b);
|
||||
|
||||
/* Overflow threshold */
|
||||
uint64_t limit =
|
||||
(sign > 0) ? (uint64_t)INTPTR_MAX : (uint64_t)INTPTR_MAX + 1;
|
||||
|
||||
if (ua != 0 && ub > limit / ua)
|
||||
SCC_AP_PANIC("scc_ap_mul: overflow");
|
||||
|
||||
isize result = (isize)(ua * ub);
|
||||
return (sign > 0) ? result : -result;
|
||||
}
|
||||
|
||||
/* Checked division */
|
||||
static isize ap_div_isize(isize a, isize b) {
|
||||
if (b == 0)
|
||||
SCC_AP_PANIC("scc_ap_div: division by zero");
|
||||
if (a == INTPTR_MIN && b == -1)
|
||||
SCC_AP_PANIC("scc_ap_div: overflow (INTPTR_MIN / -1)");
|
||||
return a / b;
|
||||
}
|
||||
|
||||
/* Checked modulo */
|
||||
static isize ap_mod_isize(isize a, isize b) {
|
||||
if (b == 0)
|
||||
SCC_AP_PANIC("scc_ap_mod: modulo by zero");
|
||||
if (a == INTPTR_MIN && b == -1)
|
||||
SCC_AP_PANIC("scc_ap_mod: overflow (INTPTR_MIN %% -1)");
|
||||
return a % b;
|
||||
}
|
||||
|
||||
/* ---------- public API ---------- */
|
||||
|
||||
void scc_ap_drop(scc_ap_t *ap) {
|
||||
SCC_AP_ASSERT(ap);
|
||||
// SCC_AP_FREE(ap->data);
|
||||
SCC_AP_ASSERT(ap != nullptr);
|
||||
/* In digit mode (capacity == -1), there's no heap allocation to free */
|
||||
scc_ap_init(ap);
|
||||
}
|
||||
|
||||
void scc_ap_with_bits(scc_ap_t *ap, int bits) {}
|
||||
|
||||
void scc_ap_from_string(scc_ap_t *ap, const char *str, int len, int base) {
|
||||
SCC_AP_ASSERT(base == 10);
|
||||
SCC_AP_ASSERT(ap && str);
|
||||
if (len == 0) {
|
||||
scc_ap_set_int(ap, 0);
|
||||
}
|
||||
// FIXME
|
||||
int int_lit = 0;
|
||||
for (int i = 0; i < len; i += 1) {
|
||||
int_lit = int_lit * 10 + (str[i] - '0');
|
||||
}
|
||||
scc_ap_set_int(ap, int_lit);
|
||||
void scc_ap_with_bits(scc_ap_t *ap, int bits) {
|
||||
SCC_AP_ASSERT(ap != nullptr);
|
||||
if (bits > (int)(sizeof(scc_ap_digit) * 8))
|
||||
SCC_AP_PANIC(
|
||||
"scc_ap_with_bits: request %d bits but digit only has %zu bits",
|
||||
bits, sizeof(scc_ap_digit) * 8);
|
||||
(void)ap;
|
||||
/* Fast path: always stays in digit mode */
|
||||
}
|
||||
|
||||
void scc_ap_set_digit(scc_ap_t *ap, scc_ap_digit digit) {}
|
||||
void scc_ap_from_string(scc_ap_t *ap, const char *str, int len, int base) {
|
||||
SCC_AP_ASSERT(ap != nullptr && str != nullptr);
|
||||
|
||||
void scc_ap_add_impl(scc_ap_t *to, const scc_ap_t *from_a,
|
||||
const scc_ap_t *from_b) {}
|
||||
/* len < 0 means null-terminated */
|
||||
if (len < 0) {
|
||||
len = 0;
|
||||
while (str[len] != '\0')
|
||||
len++;
|
||||
}
|
||||
if (len == 0) {
|
||||
ap_from_isize(ap, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
void scc_ap_add(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {}
|
||||
int i = 0;
|
||||
int sign = 1;
|
||||
|
||||
void scc_ap_sub(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {}
|
||||
/* Optional leading sign */
|
||||
if (str[i] == '-') {
|
||||
sign = -1;
|
||||
i++;
|
||||
} else if (str[i] == '+') {
|
||||
i++;
|
||||
}
|
||||
|
||||
typedef void (*ap_dump_fn)(const char ch, void *user_data);
|
||||
int scc_ap_dump(scc_ap_t *ap, ap_dump_fn dump_fn, void *user_data) { return 0; }
|
||||
if (i >= len) {
|
||||
ap_from_isize(ap, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
/* ---------- base auto-detection ---------- */
|
||||
/* hex: 0x / 0X */
|
||||
if ((base == 0 || base == 16) &&
|
||||
(i + 2 < len && str[i] == '0' &&
|
||||
(str[i + 1] == 'x' || str[i + 1] == 'X'))) {
|
||||
base = 16;
|
||||
i += 2;
|
||||
}
|
||||
/* binary: 0b / 0B */
|
||||
if ((base == 0 || base == 2) &&
|
||||
(i + 2 < len && str[i] == '0' &&
|
||||
(str[i + 1] == 'b' || str[i + 1] == 'B'))) {
|
||||
base = 2;
|
||||
i += 2;
|
||||
}
|
||||
if (base == 0) {
|
||||
if (i < len && str[i] == '0') {
|
||||
base = 8;
|
||||
i++;
|
||||
} else {
|
||||
base = 10;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- parse digits ---------- */
|
||||
uint64_t val = 0;
|
||||
for (; i < len; i++) {
|
||||
char ch = str[i];
|
||||
unsigned d;
|
||||
if (ch >= '0' && ch <= '9')
|
||||
d = (unsigned)(ch - '0');
|
||||
else if (ch >= 'a' && ch <= 'f')
|
||||
d = (unsigned)(ch - 'a' + 10);
|
||||
else if (ch >= 'A' && ch <= 'F')
|
||||
d = (unsigned)(ch - 'A' + 10);
|
||||
else
|
||||
break;
|
||||
if ((int)d >= base)
|
||||
break;
|
||||
|
||||
/* overflow check: val * base + d <= UINT64_MAX */
|
||||
if (val > (UINT64_MAX - d) / (unsigned)base)
|
||||
SCC_AP_PANIC("scc_ap_from_string: overflow");
|
||||
val = val * (unsigned)base + d;
|
||||
}
|
||||
|
||||
ap->capacity = -1;
|
||||
ap->data.digit = val;
|
||||
ap->len = (sign < 0 && val > 0) ? -1 : 1;
|
||||
}
|
||||
|
||||
void scc_ap_set_digit(scc_ap_t *ap, scc_ap_digit digit) {
|
||||
SCC_AP_ASSERT(ap != nullptr);
|
||||
if (digit > (scc_ap_digit)INTPTR_MAX)
|
||||
SCC_AP_PANIC("scc_ap_set_digit: value %llu exceeds isize range",
|
||||
(unsigned long long)digit);
|
||||
ap->capacity = -1;
|
||||
ap->data.digit = digit;
|
||||
ap->len = 1;
|
||||
}
|
||||
|
||||
void scc_ap_add(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {
|
||||
SCC_AP_ASSERT(to != nullptr && from_a != nullptr && from_b != nullptr);
|
||||
isize a = ap_to_isize(from_a);
|
||||
isize b = ap_to_isize(from_b);
|
||||
ap_from_isize(to, ap_add_isize(a, b));
|
||||
}
|
||||
|
||||
void scc_ap_sub(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {
|
||||
SCC_AP_ASSERT(to != nullptr && from_a != nullptr && from_b != nullptr);
|
||||
isize a = ap_to_isize(from_a);
|
||||
isize b = ap_to_isize(from_b);
|
||||
ap_from_isize(to, ap_sub_isize(a, b));
|
||||
}
|
||||
|
||||
void scc_ap_mul(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {
|
||||
SCC_AP_ASSERT(to != nullptr && from_a != nullptr && from_b != nullptr);
|
||||
isize a = ap_to_isize(from_a);
|
||||
isize b = ap_to_isize(from_b);
|
||||
ap_from_isize(to, ap_mul_isize(a, b));
|
||||
}
|
||||
|
||||
void scc_ap_div(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {
|
||||
SCC_AP_ASSERT(to != nullptr && from_a != nullptr && from_b != nullptr);
|
||||
isize a = ap_to_isize(from_a);
|
||||
isize b = ap_to_isize(from_b);
|
||||
ap_from_isize(to, ap_div_isize(a, b));
|
||||
}
|
||||
|
||||
void scc_ap_mod(scc_ap_t *to, const scc_ap_t *from_a, const scc_ap_t *from_b) {
|
||||
SCC_AP_ASSERT(to != nullptr && from_a != nullptr && from_b != nullptr);
|
||||
isize a = ap_to_isize(from_a);
|
||||
isize b = ap_to_isize(from_b);
|
||||
ap_from_isize(to, ap_mod_isize(a, b));
|
||||
}
|
||||
|
||||
void scc_ap_shl(scc_ap_t *to, const scc_ap_t *from, unsigned shift) {
|
||||
SCC_AP_ASSERT(to != nullptr && from != nullptr);
|
||||
SCC_AP_ASSERT(from->capacity == -1);
|
||||
if (shift >= sizeof(scc_ap_digit) * 8)
|
||||
SCC_AP_PANIC("scc_ap_shl: shift %u exceeds digit width (%zu bits)",
|
||||
shift, sizeof(scc_ap_digit) * 8);
|
||||
/* left shift = multiply by 2^shift */
|
||||
isize val = ap_to_isize(from);
|
||||
isize result = ap_mul_isize(val, (isize)1 << shift);
|
||||
ap_from_isize(to, result);
|
||||
}
|
||||
|
||||
void scc_ap_shr(scc_ap_t *to, const scc_ap_t *from, unsigned shift) {
|
||||
SCC_AP_ASSERT(to != nullptr && from != nullptr);
|
||||
SCC_AP_ASSERT(from->capacity == -1);
|
||||
if (shift >= sizeof(scc_ap_digit) * 8)
|
||||
SCC_AP_PANIC("scc_ap_shr: shift %u exceeds digit width (%zu bits)",
|
||||
shift, sizeof(scc_ap_digit) * 8);
|
||||
/* arithmetic right shift — uses >> on isize (arithmetic on GCC/MSVC/Clang) */
|
||||
isize val = ap_to_isize(from);
|
||||
ap_from_isize(to, val >> shift);
|
||||
}
|
||||
|
||||
void scc_ap_lshr(scc_ap_t *to, const scc_ap_t *from, unsigned shift) {
|
||||
SCC_AP_ASSERT(to != nullptr && from != nullptr);
|
||||
SCC_AP_ASSERT(from->capacity == -1);
|
||||
if (shift >= sizeof(scc_ap_digit) * 8)
|
||||
SCC_AP_PANIC("scc_ap_lshr: shift %u exceeds digit width (%zu bits)",
|
||||
shift, sizeof(scc_ap_digit) * 8);
|
||||
/*
|
||||
* logical right shift: reinterpret the signed value as uint64 bit pattern,
|
||||
* shift right, store as non-negative magnitude.
|
||||
*/
|
||||
uint64_t bits;
|
||||
if (from->len < 0) {
|
||||
/* negative → two's complement bit pattern */
|
||||
bits = -(uint64_t)(int64_t)from->data.digit;
|
||||
} else {
|
||||
bits = from->data.digit;
|
||||
}
|
||||
to->capacity = -1;
|
||||
to->data.digit = bits >> shift;
|
||||
to->len = 1;
|
||||
}
|
||||
|
||||
/* ---------- bitwise ---------- */
|
||||
|
||||
void scc_ap_and(scc_ap_t *to, const scc_ap_t *a, const scc_ap_t *b) {
|
||||
SCC_AP_ASSERT(to != nullptr && a != nullptr && b != nullptr);
|
||||
ap_from_isize(to, ap_to_isize(a) & ap_to_isize(b));
|
||||
}
|
||||
|
||||
void scc_ap_or(scc_ap_t *to, const scc_ap_t *a, const scc_ap_t *b) {
|
||||
SCC_AP_ASSERT(to != nullptr && a != nullptr && b != nullptr);
|
||||
ap_from_isize(to, ap_to_isize(a) | ap_to_isize(b));
|
||||
}
|
||||
|
||||
void scc_ap_xor(scc_ap_t *to, const scc_ap_t *a, const scc_ap_t *b) {
|
||||
SCC_AP_ASSERT(to != nullptr && a != nullptr && b != nullptr);
|
||||
ap_from_isize(to, ap_to_isize(a) ^ ap_to_isize(b));
|
||||
}
|
||||
|
||||
void scc_ap_not(scc_ap_t *to, const scc_ap_t *from) {
|
||||
SCC_AP_ASSERT(to != nullptr && from != nullptr);
|
||||
ap_from_isize(to, ~ap_to_isize(from));
|
||||
}
|
||||
|
||||
/* ---------- unary arithmetic ---------- */
|
||||
|
||||
void scc_ap_neg(scc_ap_t *to, const scc_ap_t *from) {
|
||||
SCC_AP_ASSERT(to != nullptr && from != nullptr);
|
||||
isize val = ap_to_isize(from);
|
||||
if (val == INTPTR_MIN)
|
||||
SCC_AP_PANIC("scc_ap_neg: overflow (INTPTR_MIN)");
|
||||
ap_from_isize(to, -val);
|
||||
}
|
||||
|
||||
/* ---------- comparison ---------- */
|
||||
|
||||
int scc_ap_cmp(const scc_ap_t *a, const scc_ap_t *b) {
|
||||
SCC_AP_ASSERT(a != nullptr && b != nullptr);
|
||||
isize va = ap_to_isize(a);
|
||||
isize vb = ap_to_isize(b);
|
||||
if (va < vb) return -1;
|
||||
if (va > vb) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scc_ap_is_zero(const scc_ap_t *ap) {
|
||||
SCC_AP_ASSERT(ap != nullptr);
|
||||
return ap->data.digit == 0;
|
||||
}
|
||||
|
||||
int scc_ap_eql(const scc_ap_t *a, const scc_ap_t *b) {
|
||||
SCC_AP_ASSERT(a != nullptr && b != nullptr);
|
||||
SCC_AP_ASSERT(a->capacity == -1 && b->capacity == -1);
|
||||
if (a->len != b->len) {
|
||||
/* -0 == +0 */
|
||||
if (a->data.digit == 0 && b->data.digit == 0)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return a->data.digit == b->data.digit;
|
||||
}
|
||||
|
||||
int scc_ap_dump(scc_ap_t *ap, ap_dump_fn dump_fn, void *user_data) {
|
||||
SCC_AP_ASSERT(ap != nullptr && dump_fn != nullptr);
|
||||
SCC_AP_ASSERT(ap->capacity == -1);
|
||||
|
||||
isize val = ap_to_isize(ap);
|
||||
|
||||
if (val == 0) {
|
||||
dump_fn('0', user_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Buffer large enough for INT64_MIN "-9223372036854775808" */
|
||||
char buf[24];
|
||||
int pos = sizeof(buf);
|
||||
|
||||
if (val < 0) {
|
||||
dump_fn('-', user_data);
|
||||
/* Work with positive magnitude to avoid overflow when printing */
|
||||
uint64_t mag = ap->data.digit;
|
||||
while (mag > 0) {
|
||||
buf[--pos] = (char)('0' + (mag % 10));
|
||||
mag /= 10;
|
||||
}
|
||||
} else {
|
||||
uint64_t mag = (uint64_t)val;
|
||||
while (mag > 0) {
|
||||
buf[--pos] = (char)('0' + (mag % 10));
|
||||
mag /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = pos; i < (int)sizeof(buf); i++)
|
||||
dump_fn(buf[i], user_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user