mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
461 lines
17 KiB
C
461 lines
17 KiB
C
// Copyright (c) 2019 Christoffer Lerno. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
#include "llvm_codegen_internal.h"
|
|
#include "compiler_internal.h"
|
|
|
|
LLVMValueRef gencontext_emit_address(GenContext *context, Expr *expr)
|
|
{
|
|
switch (expr->expr_kind)
|
|
{
|
|
case EXPR_IDENTIFIER:
|
|
return expr->identifier_expr.decl->var.backend_ref;
|
|
case EXPR_CONST:
|
|
case EXPR_TYPE:
|
|
UNREACHABLE
|
|
case EXPR_UNARY:
|
|
{
|
|
UnaryOp op = unaryop_from_token(expr->unary_expr.operator);
|
|
assert(op == UNARYOP_DEREF);
|
|
return gencontext_emit_expr(context, expr->unary_expr.expr);
|
|
}
|
|
case EXPR_ACCESS:
|
|
TODO;
|
|
{
|
|
// LLVMValueRef value = gencontext_emit_address(context, expr->access_expr.parent);
|
|
// LLVMBuildExtractValue(context->builder, value, (unsigned)expr->access_expr.index, expr->access_expr.ref->name.string);
|
|
}
|
|
case EXPR_POISONED:
|
|
case EXPR_TRY:
|
|
case EXPR_SIZEOF:
|
|
UNREACHABLE
|
|
case EXPR_BINARY:
|
|
TODO;
|
|
case EXPR_CONDITIONAL:
|
|
TODO;
|
|
case EXPR_POST_UNARY:
|
|
TODO;
|
|
case EXPR_TYPE_ACCESS:
|
|
TODO
|
|
case EXPR_CALL:
|
|
TODO
|
|
case EXPR_SUBSCRIPT:
|
|
TODO
|
|
case EXPR_STRUCT_VALUE:
|
|
TODO
|
|
case EXPR_STRUCT_INIT_VALUES:
|
|
TODO
|
|
case EXPR_INITIALIZER_LIST:
|
|
TODO
|
|
case EXPR_EXPRESSION_LIST:
|
|
TODO
|
|
case EXPR_CAST:
|
|
TODO
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static inline LLVMValueRef gencontext_emit_cast_expr(GenContext *context, Expr *expr)
|
|
{
|
|
LLVMValueRef rhs = gencontext_emit_expr(context, expr->expr_cast.expr);
|
|
switch (expr->expr_cast.kind)
|
|
{
|
|
case CAST_ERROR:
|
|
UNREACHABLE
|
|
case CAST_PTRPTR:
|
|
return LLVMBuildPointerCast(context->builder, rhs, BACKEND_TYPE(expr->type), "ptrptr");
|
|
case CAST_PTRXI:
|
|
return LLVMBuildPtrToInt(context->builder, rhs, BACKEND_TYPE(expr->type), "ptrxi");
|
|
case CAST_VARRPTR:
|
|
TODO
|
|
case CAST_ARRPTR:
|
|
TODO
|
|
case CAST_STRPTR:
|
|
TODO
|
|
case CAST_PTRBOOL:
|
|
return LLVMBuildICmp(context->builder, LLVMIntNE, rhs, LLVMConstPointerNull(BACKEND_TYPE(expr->type->canonical->pointer)), "ptrbool");
|
|
case CAST_BOOLINT:
|
|
return LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "boolsi");
|
|
case CAST_FPBOOL:
|
|
return LLVMBuildFCmp(context->builder, LLVMRealUNE, rhs, LLVMConstNull(LLVMTypeOf(rhs)), "fpbool");
|
|
case CAST_BOOLFP:
|
|
return LLVMBuildSIToFP(context->builder, rhs, BACKEND_TYPE(expr->type), "boolfp");
|
|
case CAST_INTBOOL:
|
|
return LLVMBuildICmp(context->builder, LLVMIntNE, rhs, LLVMConstNull(LLVMTypeOf(rhs)), "intbool");
|
|
case CAST_FPFP:
|
|
return type_convert_will_trunc(expr->type, expr->expr_cast.expr->type)
|
|
? LLVMBuildFPTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "fpfptrunc")
|
|
: LLVMBuildFPExt(context->builder, rhs, BACKEND_TYPE(expr->type), "fpfpext");
|
|
case CAST_FPSI:
|
|
return LLVMBuildFPToSI(context->builder, rhs, BACKEND_TYPE(expr->type), "fpsi");
|
|
case CAST_FPUI:
|
|
return LLVMBuildFPToUI(context->builder, rhs, BACKEND_TYPE(expr->type), "fpui");
|
|
case CAST_SISI:
|
|
return type_convert_will_trunc(expr->type, expr->expr_cast.expr->type)
|
|
? LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "sisitrunc")
|
|
: LLVMBuildSExt(context->builder, rhs, BACKEND_TYPE(expr->type), "sisiext");
|
|
case CAST_SIUI:
|
|
return type_convert_will_trunc(expr->type, expr->expr_cast.expr->type)
|
|
? LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "siuitrunc")
|
|
: LLVMBuildZExt(context->builder, rhs, BACKEND_TYPE(expr->type), "siuiext");
|
|
break;
|
|
case CAST_SIFP:
|
|
return LLVMBuildSIToFP(context->builder, rhs, BACKEND_TYPE(expr->type), "sifp");
|
|
case CAST_XIPTR:
|
|
return LLVMBuildIntToPtr(context->builder, rhs, BACKEND_TYPE(expr->type), "xiptr");
|
|
case CAST_UISI:
|
|
return type_convert_will_trunc(expr->type, expr->expr_cast.expr->type)
|
|
? LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "uisitrunc")
|
|
: LLVMBuildZExt(context->builder, rhs, BACKEND_TYPE(expr->type), "uisiext");
|
|
case CAST_UIUI:
|
|
return type_convert_will_trunc(expr->type, expr->expr_cast.expr->type)
|
|
? LLVMBuildTrunc(context->builder, rhs, BACKEND_TYPE(expr->type), "uiuitrunc")
|
|
: LLVMBuildZExt(context->builder, rhs, BACKEND_TYPE(expr->type), "uiuiext");
|
|
case CAST_UIFP:
|
|
return LLVMBuildUIToFP(context->builder, rhs, BACKEND_TYPE(expr->type), "uifp");
|
|
case CAST_ENUMSI:
|
|
TODO
|
|
}
|
|
}
|
|
|
|
LLVMValueRef gencontext_emit_unary_expr(GenContext *context, Expr *expr)
|
|
{
|
|
UnaryOp unary_op = unaryop_from_token(expr->unary_expr.operator);
|
|
switch (unary_op)
|
|
{
|
|
case UNARYOP_ERROR:
|
|
FATAL_ERROR("Illegal unary op %s", expr->unary_expr.operator);
|
|
case UNARYOP_NOT:
|
|
return LLVMBuildXor(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), LLVMConstInt(type_bool->backend_type, 1, 0), "not");
|
|
case UNARYOP_BITNEG:
|
|
return LLVMBuildNot(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "bnot");
|
|
case UNARYOP_NEG:
|
|
if (type_is_float(expr->unary_expr.expr->type->canonical))
|
|
{
|
|
return LLVMBuildFNeg(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "fneg");
|
|
}
|
|
return LLVMBuildNeg(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "neg");
|
|
case UNARYOP_ADDR:
|
|
return gencontext_emit_address(context, expr->unary_expr.expr);
|
|
case UNARYOP_DEREF:
|
|
return LLVMBuildLoad(context->builder, gencontext_emit_expr(context, expr->unary_expr.expr), "deref");
|
|
case UNARYOP_INC:
|
|
TODO
|
|
case UNARYOP_DEC:
|
|
TODO
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static LLVMValueRef gencontext_emit_assign(GenContext *context, Expr *left, LLVMValueRef right)
|
|
{
|
|
LLVMValueRef addr = gencontext_emit_address(context, left);
|
|
return LLVMBuildStore(context->builder, right, addr);
|
|
}
|
|
|
|
static LLVMValueRef gencontext_emit_logical_and_or(GenContext *context, Expr *expr, BinaryOp op)
|
|
{
|
|
// Value *ScalarExprEmitter::VisitBinLAnd(const BinaryOperator *E)
|
|
// For vector implementation.
|
|
|
|
// Set up basic blocks, following Cone
|
|
LLVMBasicBlockRef start_block = LLVMGetInsertBlock(context->builder);
|
|
LLVMBasicBlockRef phi_block = LLVMCreateBasicBlockInContext(context->context, op == BINARYOP_AND ? "and.phi" : "or.phi");
|
|
LLVMBasicBlockRef rhs_block = LLVMCreateBasicBlockInContext(context->context, op == BINARYOP_AND ? "and.rhs" : "or.rhs");
|
|
|
|
// Generate left-hand condition and conditional branch
|
|
LLVMValueRef lhs = gencontext_emit_expr(context, expr->binary_expr.left);
|
|
|
|
if (op == BINARYOP_AND)
|
|
{
|
|
gencontext_emit_cond_br(context, lhs, rhs_block, phi_block);
|
|
}
|
|
else
|
|
{
|
|
gencontext_emit_cond_br(context, lhs, phi_block, rhs_block);
|
|
}
|
|
|
|
gencontext_emit_block(context, rhs_block);
|
|
LLVMValueRef rhs = gencontext_emit_expr(context, expr->binary_expr.right);
|
|
gencontext_emit_br(context, phi_block);
|
|
|
|
// Generate phi
|
|
gencontext_emit_block(context, phi_block);
|
|
LLVMValueRef phi = LLVMBuildPhi(context->builder, type_bool->backend_type, "val");
|
|
|
|
// Simplify for LLVM by entering the constants we already know of.
|
|
LLVMValueRef result_on_skip = LLVMConstInt(LLVMInt1TypeInContext(context->context), op == BINARYOP_AND ? 0 : 1, false);
|
|
LLVMValueRef logicValues[2] = { result_on_skip, rhs };
|
|
LLVMBasicBlockRef blocks[2] = { start_block, rhs_block };
|
|
LLVMAddIncoming(phi, logicValues, blocks, 2);
|
|
|
|
return phi;
|
|
}
|
|
|
|
static LLVMValueRef gencontext_emit_binary(GenContext *context, Expr *expr, bool load_lhs_after_rhs, BinaryOp binary_op)
|
|
{
|
|
|
|
if (binary_op == BINARYOP_AND || binary_op == BINARYOP_OR)
|
|
{
|
|
return gencontext_emit_logical_and_or(context, expr, binary_op);
|
|
}
|
|
Type *type = expr->type->canonical;
|
|
Expr *lhs = expr->binary_expr.left;
|
|
Expr *rhs = expr->binary_expr.right;
|
|
|
|
LLVMValueRef lhs_value;
|
|
LLVMValueRef rhs_value;
|
|
if (load_lhs_after_rhs)
|
|
{
|
|
rhs_value = gencontext_emit_expr(context, rhs);
|
|
lhs_value = gencontext_emit_expr(context, lhs);
|
|
}
|
|
else
|
|
{
|
|
lhs_value = gencontext_emit_expr(context, lhs);
|
|
rhs_value = gencontext_emit_expr(context, rhs);
|
|
}
|
|
|
|
bool is_float = type_is_float(type);
|
|
|
|
switch (binary_op)
|
|
{
|
|
case BINARYOP_ERROR:
|
|
UNREACHABLE
|
|
case BINARYOP_MULT:
|
|
return is_float ? LLVMBuildFMul(context->builder, lhs_value, rhs_value, "fmul") : LLVMBuildMul(context->builder, lhs_value, rhs_value, "mul");
|
|
case BINARYOP_SUB:
|
|
if (lhs->type->canonical->type_kind == TYPE_POINTER)
|
|
{
|
|
if (lhs->type->canonical == rhs->type->canonical) return LLVMBuildPtrDiff(context->builder, lhs_value, rhs_value, "ptrdiff");
|
|
rhs_value = LLVMBuildNeg(context->builder, rhs_value, "");
|
|
return LLVMBuildGEP2(context->builder, BACKEND_TYPE(lhs->type), lhs_value, &rhs_value, 1, "ptrsub");
|
|
}
|
|
if (is_float) return LLVMBuildFSub(context->builder, lhs_value, rhs_value, "fsub");
|
|
// Consider UB version instead.
|
|
return LLVMBuildSub(context->builder, lhs_value, rhs_value, "sub");
|
|
case BINARYOP_ADD:
|
|
if (lhs->type->canonical->type_kind == TYPE_POINTER)
|
|
{
|
|
assert(type_is_integer(lhs->type->canonical));
|
|
return LLVMBuildGEP2(context->builder, BACKEND_TYPE(lhs->type), lhs_value, &rhs_value, 1, "ptradd");
|
|
}
|
|
if (is_float) return LLVMBuildFAdd(context->builder, lhs_value, rhs_value, "fadd");
|
|
// Consider UB version instead.
|
|
return LLVMBuildAdd(context->builder, lhs_value, rhs_value, "add");
|
|
case BINARYOP_DIV:
|
|
if (is_float) return LLVMBuildFDiv(context->builder, lhs_value, rhs_value, "fdiv");
|
|
return type_is_unsigned(type)
|
|
? LLVMBuildUDiv(context->builder, lhs_value, rhs_value, "udiv")
|
|
: LLVMBuildSDiv(context->builder, lhs_value, rhs_value, "sdiv");
|
|
case BINARYOP_MOD:
|
|
return type_is_unsigned(type)
|
|
? LLVMBuildURem(context->builder, lhs_value, rhs_value, "umod")
|
|
: LLVMBuildSRem(context->builder, lhs_value, rhs_value, "smod");
|
|
case BINARYOP_SHR:
|
|
return type_is_unsigned(type)
|
|
? LLVMBuildLShr(context->builder, lhs_value, rhs_value, "lshr")
|
|
: LLVMBuildAShr(context->builder, lhs_value, rhs_value, "ashr");
|
|
case BINARYOP_SHL:
|
|
return LLVMBuildShl(context->builder, lhs_value, rhs_value, "shr");
|
|
case BINARYOP_BIT_AND:
|
|
return LLVMBuildAnd(context->builder, lhs_value, rhs_value, "and");
|
|
case BINARYOP_BIT_OR:
|
|
return LLVMBuildOr(context->builder, lhs_value, rhs_value, "or");
|
|
case BINARYOP_BIT_XOR:
|
|
return LLVMBuildXor(context->builder, lhs_value, rhs_value, "xor");
|
|
case BINARYOP_EQ:
|
|
// Unordered?
|
|
if (type_is_float(type)) LLVMBuildFCmp(context->builder, LLVMRealUEQ, lhs_value, rhs_value, "eq");
|
|
return LLVMBuildICmp(context->builder, LLVMIntEQ, lhs_value, rhs_value, "eq");
|
|
case BINARYOP_NE:
|
|
// Unordered?
|
|
if (type_is_float(type)) LLVMBuildFCmp(context->builder, LLVMRealUNE, lhs_value, rhs_value, "neq");
|
|
return LLVMBuildICmp(context->builder, LLVMIntNE, lhs_value, rhs_value, "neq");
|
|
case BINARYOP_GE:
|
|
if (type_is_float(type)) LLVMBuildFCmp(context->builder, LLVMRealUGE, lhs_value, rhs_value, "ge");
|
|
return type_is_unsigned(type)
|
|
? LLVMBuildICmp(context->builder, LLVMIntUGE, lhs_value, rhs_value, "ge")
|
|
: LLVMBuildICmp(context->builder, LLVMIntSGE, lhs_value, rhs_value, "ge");
|
|
case BINARYOP_GT:
|
|
if (type_is_float(type)) LLVMBuildFCmp(context->builder, LLVMRealUGT, lhs_value, rhs_value, "gt");
|
|
return type_is_unsigned(type)
|
|
? LLVMBuildICmp(context->builder, LLVMIntUGT, lhs_value, rhs_value, "gt")
|
|
: LLVMBuildICmp(context->builder, LLVMIntSGT, lhs_value, rhs_value, "gt");
|
|
case BINARYOP_LE:
|
|
if (type_is_float(type)) LLVMBuildFCmp(context->builder, LLVMRealULE, lhs_value, rhs_value, "le");
|
|
return type_is_unsigned(type)
|
|
? LLVMBuildICmp(context->builder, LLVMIntULE, lhs_value, rhs_value, "le")
|
|
: LLVMBuildICmp(context->builder, LLVMIntSLE, lhs_value, rhs_value, "le");
|
|
case BINARYOP_LT:
|
|
if (type_is_float(type)) LLVMBuildFCmp(context->builder, LLVMRealULE, lhs_value, rhs_value, "lt");
|
|
return type_is_unsigned(type)
|
|
? LLVMBuildICmp(context->builder, LLVMIntULT, lhs_value, rhs_value, "lt")
|
|
: LLVMBuildICmp(context->builder, LLVMIntSLT, lhs_value, rhs_value, "lt");
|
|
case BINARYOP_AND:
|
|
case BINARYOP_OR:
|
|
UNREACHABLE
|
|
case BINARYOP_ASSIGN:
|
|
case BINARYOP_MULT_ASSIGN:
|
|
case BINARYOP_ADD_ASSIGN:
|
|
case BINARYOP_SUB_ASSIGN:
|
|
case BINARYOP_DIV_ASSIGN:
|
|
case BINARYOP_MOD_ASSIGN:
|
|
case BINARYOP_AND_ASSIGN:
|
|
case BINARYOP_OR_ASSIGN:
|
|
case BINARYOP_BIT_AND_ASSIGN:
|
|
case BINARYOP_BIT_OR_ASSIGN:
|
|
case BINARYOP_BIT_XOR_ASSIGN:
|
|
case BINARYOP_SHR_ASSIGN:
|
|
case BINARYOP_SHL_ASSIGN:
|
|
UNREACHABLE
|
|
}
|
|
}
|
|
|
|
LLVMValueRef gencontext_emit_post_unary_expr(GenContext *context, Expr *expr)
|
|
{
|
|
Expr *lhs = expr->unary_expr.expr;
|
|
LLVMValueRef value = gencontext_emit_expr(context, lhs);
|
|
bool is_add = expr->post_expr.operator == TOKEN_PLUSPLUS;
|
|
/* if (expr->type->canonical->type_kind == TYPE_POINTER)
|
|
{
|
|
LLVMValueRef offset = LLVMConstInt(is_add ? type_isize->backend_type : type_usize->backend_type, is_add ? 1 : -1, true);
|
|
LLVMBuildStore(context->builder, LLVMBuildGEP2(context->builder, gencontext_get_llvm_type(context, expr->type->canonical), value, &offset, 1, "postunary"), gencontext_emit_address(context, left);)
|
|
return ;
|
|
}
|
|
if (type_is_float(expr->type->canonical))
|
|
{
|
|
LLVMValueRef offset = LLVMConstReal(LLVMTypeOf(value), is_add ? 1);
|
|
LLVMBuildAdd(context->builder, value, offset, name);
|
|
}
|
|
if (lhs->type->canonical->type_kind == TYPE_POINTER)
|
|
{
|
|
rhs_value = LLVMBuildNeg(context->builder, rhs_value, "");
|
|
return LLVMBuildGEP2(context->builder, , lhs_value, &rhs_value, 1, "ptrsub");
|
|
}
|
|
*/
|
|
const char *name = is_add ? "add" : "sub";
|
|
LLVMValueRef constVal = LLVMConstInt(LLVMTypeOf(value), 1, !is_add);
|
|
LLVMValueRef result = is_add ? LLVMBuildAdd(context->builder, value, constVal, name)
|
|
: LLVMBuildSub(context->builder, value, constVal, name);
|
|
LLVMBuildStore(context->builder, result, gencontext_emit_address(context, lhs));
|
|
return value;
|
|
}
|
|
|
|
static LLVMValueRef gencontext_emit_binary_expr(GenContext *context, Expr *expr)
|
|
{
|
|
BinaryOp binary_op = binaryop_from_token(expr->binary_expr.operator);
|
|
if (binary_op > BINARYOP_ASSIGN)
|
|
{
|
|
BinaryOp base_op = binaryop_assign_base_op(binary_op);
|
|
assert(base_op != BINARYOP_ERROR);
|
|
LLVMValueRef value = gencontext_emit_binary(context, expr, true, base_op);
|
|
gencontext_emit_assign(context, expr->binary_expr.left, value);
|
|
return value;
|
|
}
|
|
if (binary_op == BINARYOP_ASSIGN)
|
|
{
|
|
LLVMValueRef value = gencontext_emit_expr(context, expr->binary_expr.right);
|
|
gencontext_emit_assign(context, expr->binary_expr.left, value);
|
|
return value;
|
|
}
|
|
return gencontext_emit_binary(context, expr, false, binary_op);
|
|
}
|
|
|
|
static LLVMValueRef gencontext_emit_identifier_expr(GenContext *context, Expr *expr)
|
|
{
|
|
return LLVMBuildLoad2(context->builder, expr->identifier_expr.decl->type->canonical->backend_type,
|
|
expr->identifier_expr.decl->var.backend_ref, expr->identifier_expr.decl->name.string);
|
|
}
|
|
|
|
LLVMValueRef gencontext_emit_const_expr(GenContext *context, Expr *expr)
|
|
{
|
|
LLVMTypeRef type = BACKEND_TYPE(expr->type);
|
|
switch (expr->const_expr.type)
|
|
{
|
|
case CONST_INT:
|
|
return LLVMConstInt(type, expr->const_expr.i, type_is_unsigned(expr->type->canonical) ? false : true);
|
|
case CONST_FLOAT:
|
|
return LLVMConstReal(type, (double) expr->const_expr.f);
|
|
case CONST_NIL:
|
|
return LLVMConstNull(type);
|
|
case CONST_BOOL:
|
|
return LLVMConstInt(type, expr->const_expr.b ? 1 : 0, false);
|
|
case CONST_STRING:
|
|
{
|
|
LLVMValueRef global_name = LLVMAddGlobal(context->module, type, "string");
|
|
LLVMSetLinkage(global_name, LLVMInternalLinkage);
|
|
LLVMSetGlobalConstant(global_name, 1);
|
|
LLVMSetInitializer(global_name, LLVMConstStringInContext(context->context,
|
|
expr->const_expr.string.chars,
|
|
expr->const_expr.string.len,
|
|
1));
|
|
return global_name;
|
|
}
|
|
}
|
|
UNREACHABLE
|
|
}
|
|
|
|
LLVMValueRef gencontext_emit_call_expr(GenContext *context, Expr *expr)
|
|
{
|
|
size_t args = vec_size(expr->call_expr.arguments);
|
|
LLVMValueRef *values = args ? malloc_arena(args * sizeof(LLVMValueRef)) : NULL;
|
|
VECEACH(expr->call_expr.arguments, i)
|
|
{
|
|
values[i] = gencontext_emit_expr(context, expr->call_expr.arguments[i]);
|
|
}
|
|
LLVMValueRef func = expr->call_expr.function->identifier_expr.decl->func.backend_value;
|
|
|
|
return LLVMBuildCall2(context->builder, LLVMTYPE(expr->call_expr.function->identifier_expr.decl->type), func, values, args, "call");
|
|
/*
|
|
if (fndcl->flags & FlagSystem) {
|
|
LLVMSetInstructionCallConv(fncallret, LLVMX86StdcallCallConv);
|
|
}*/
|
|
}
|
|
LLVMValueRef gencontext_emit_expr(GenContext *context, Expr *expr)
|
|
{
|
|
switch (expr->expr_kind)
|
|
{
|
|
case EXPR_POISONED:
|
|
UNREACHABLE
|
|
case EXPR_UNARY:
|
|
return gencontext_emit_unary_expr(context, expr);
|
|
case EXPR_TRY:
|
|
break;
|
|
case EXPR_CONST:
|
|
return gencontext_emit_const_expr(context, expr);
|
|
case EXPR_BINARY:
|
|
return gencontext_emit_binary_expr(context, expr);
|
|
case EXPR_CONDITIONAL:
|
|
break;
|
|
case EXPR_POST_UNARY:
|
|
return gencontext_emit_post_unary_expr(context, expr);
|
|
case EXPR_TYPE:
|
|
break;
|
|
case EXPR_IDENTIFIER:
|
|
return gencontext_emit_identifier_expr(context, expr);
|
|
case EXPR_TYPE_ACCESS:
|
|
break;
|
|
case EXPR_CALL:
|
|
return gencontext_emit_call_expr(context, expr);
|
|
case EXPR_SIZEOF:
|
|
break;
|
|
case EXPR_SUBSCRIPT:
|
|
break;
|
|
case EXPR_ACCESS:
|
|
break;
|
|
case EXPR_STRUCT_VALUE:
|
|
break;
|
|
case EXPR_STRUCT_INIT_VALUES:
|
|
break;
|
|
case EXPR_INITIALIZER_LIST:
|
|
break;
|
|
case EXPR_EXPRESSION_LIST:
|
|
break;
|
|
case EXPR_CAST:
|
|
return gencontext_emit_cast_expr(context, expr);
|
|
}
|
|
TODO
|
|
} |