mirror of
https://github.com/Zeal-Operating-System/ZealOS.git
synced 2025-04-27 05:50:09 +01:00
1358 lines
34 KiB
HolyC
Executable file
1358 lines
34 KiB
HolyC
Executable file
#define PE_UNARY_TERM1 0
|
|
#define PE_UNARY_TERM2 1
|
|
#define PE_MAYBE_MODIFIERS 2
|
|
#define PE_UNARY_MODIFIERS 3
|
|
#define PE_DEREFERENCE 4
|
|
#define PE_CHECK_BINARY_OPS1 5
|
|
#define PE_CHECK_BINARY_OPS2 6
|
|
#define PE_DO_UNARY_OP 7
|
|
#define PE_DO_BINARY_OP 8
|
|
#define PE_POP_HIGHER 9
|
|
#define PE_PUSH_LOWER 10
|
|
#define PE_POP_ALL1 11
|
|
#define PE_POP_ALL2 12
|
|
|
|
CIntermediateCode *ParseAddOp(CCompCtrl *cc, I64 stack_op, CHashClass *tmpc)
|
|
{
|
|
CIntermediateCode *tmpi = cc->coc.coc_head.last;
|
|
Bool div_sizeof = FALSE;
|
|
|
|
switch (stack_op.u16[0])
|
|
{
|
|
case IC_ADD:
|
|
if (tmpc->ptr_stars_count && !tmpi->ic_class->ptr_stars_count && tmpi->ic_class->raw_type != RT_F64)
|
|
{
|
|
ICAdd(cc, IC_SIZEOF, 1, cmp.internal_types[RT_I64]);
|
|
ICAdd(cc, IC_MUL, 0, cmp.internal_types[RT_I64]);
|
|
}
|
|
break;
|
|
|
|
case IC_SUB:
|
|
if (tmpc->ptr_stars_count && tmpi->ic_class->raw_type != RT_F64)
|
|
{
|
|
if (!tmpi->ic_class->ptr_stars_count)
|
|
{
|
|
ICAdd(cc, IC_SIZEOF, 1, cmp.internal_types[RT_I64]);
|
|
ICAdd(cc, IC_MUL, 0, cmp.internal_types[RT_I64]);
|
|
}
|
|
else
|
|
div_sizeof = TRUE;
|
|
}
|
|
break;
|
|
|
|
case IC_AND_AND:
|
|
case IC_OR_OR:
|
|
ICAdd(cc, IC_NOP1, 0, cmp.internal_types[RT_I64]);
|
|
break;
|
|
|
|
case IC_ADD_EQU:
|
|
case IC_SUB_EQU:
|
|
if (tmpc->ptr_stars_count)
|
|
{
|
|
ICAdd(cc, IC_SIZEOF, 1, cmp.internal_types[RT_I64]);
|
|
ICAdd(cc, IC_MUL, 0, cmp.internal_types[RT_I64]);
|
|
}
|
|
break;
|
|
}
|
|
tmpi = ICAdd(cc, stack_op, 0, tmpc);
|
|
if (stack_op.u8[3] & ECF_HAS_PUSH_CMP)
|
|
{
|
|
tmpi->ic_flags |= ICF_POP_CMP;
|
|
ICAdd(cc, IC_NOP1, 0, cmp.internal_types[RT_I64]);
|
|
ICAdd(cc, IC_AND_AND, 0, cmp.internal_types[RT_I64], ICF_POP_CMP);
|
|
}
|
|
if (div_sizeof)
|
|
{
|
|
tmpc--;
|
|
if (tmpc->size != 1)
|
|
{
|
|
ICAdd(cc, IC_IMM_I64, tmpc->size, cmp.internal_types[RT_I64]);
|
|
ICAdd(cc, IC_DIV, 0, cmp.internal_types[RT_I64]);
|
|
tmpc = cmp.internal_types[RT_I64];
|
|
}
|
|
}
|
|
|
|
return tmpi;
|
|
}
|
|
|
|
U0 ParseExpression2(CCompCtrl *cc, I64 *_max_prec, CParseStack *ps)
|
|
{
|
|
I64 i, cur_op, stack_op, state,
|
|
max_prec = PREC_NULL, unary_pre_prec, paren_prec, unary_post_prec, left_prec = PREC_MAX;
|
|
CIntermediateCode *tmpi;
|
|
CHashClass *tmpc;
|
|
CMemberList *local_var;
|
|
CArrayDim *tmpad = NULL;
|
|
|
|
goto pe_unary_term1;
|
|
while (TRUE)
|
|
{
|
|
switch [state]
|
|
{
|
|
case PE_UNARY_TERM1:
|
|
pe_unary_term1:
|
|
unary_pre_prec = PREC_NULL;
|
|
unary_post_prec = PREC_NULL;
|
|
cc->flags &= ~(CCF_PAREN + CCF_PREINC + CCF_PREDEC + CCF_POSTINC + CCF_POSTDEC + CCF_FUN_EXP);
|
|
|
|
case PE_UNARY_TERM2:
|
|
state = ParseUnaryTerm(cc, ps, &local_var, &tmpad, &max_prec, &unary_pre_prec, &paren_prec);
|
|
break;
|
|
|
|
case PE_UNARY_MODIFIERS:
|
|
state = ParseUnaryModifier(cc, ps, &local_var, &tmpad, &unary_post_prec);
|
|
break;
|
|
|
|
case PE_MAYBE_MODIFIERS:
|
|
if (cc->token == '(')
|
|
{ //Typecast or fun_ptr
|
|
cc->flags |= CCF_RAX;
|
|
state = ParseUnaryModifier(cc, ps, &local_var, &tmpad, &unary_post_prec);
|
|
}
|
|
else
|
|
goto pe_check_binary_ops1;
|
|
break;
|
|
|
|
case PE_DEREFERENCE:
|
|
if (!(cc->flags & (CCF_PREINC | CCF_PREDEC | CCF_POSTINC | CCF_POSTDEC)))
|
|
i = IC_DEREF + PREC_UNARY_PRE << 16;
|
|
else
|
|
{
|
|
if (cc->flags & CCF_POSTINC)
|
|
i = IC__PP + PREC_UNARY_POST << 16;
|
|
else if (cc->flags & CCF_POSTDEC)
|
|
i = IC__MM + PREC_UNARY_POST << 16;
|
|
else if (cc->flags & CCF_PREDEC)
|
|
i = IC_MM_ + PREC_UNARY_PRE << 16;
|
|
else
|
|
i = IC_PP_+PREC_UNARY_PRE << 16;
|
|
cc->flags &= ~(CCF_PREINC | CCF_PREDEC | CCF_POSTINC | CCF_POSTDEC);
|
|
}
|
|
tmpi = cc->coc.coc_head.last;
|
|
if (cc->flags & (CCF_RAX | CCF_ARRAY))
|
|
{
|
|
if (tmpi->ic_code == IC_DEREF)
|
|
tmpi->ic_code = i;
|
|
}
|
|
else
|
|
{
|
|
tmpc = OptClassFwd(tmpi->ic_class - 1);
|
|
ICAdd(cc, i, 0, tmpc);
|
|
}
|
|
|
|
case PE_CHECK_BINARY_OPS1:
|
|
pe_check_binary_ops1:
|
|
if (paren_prec)
|
|
{
|
|
if (unary_pre_prec || unary_post_prec)
|
|
{
|
|
if (paren_prec <= unary_pre_prec && !unary_post_prec)
|
|
ParenWarning(cc);
|
|
paren_prec = PREC_NULL;
|
|
}
|
|
else if (paren_prec <= PREC_UNARY_PRE + ASSOC_MASK)
|
|
ParenWarning(cc);
|
|
}
|
|
cur_op = cmp.binary_ops[cc->token];
|
|
|
|
|
|
case PE_CHECK_BINARY_OPS2:
|
|
pe_check_binary_ops2:
|
|
stack_op = ParsePop(ps);
|
|
tmpc = ParsePop(ps);
|
|
if (!(0 < stack_op.u8[2] <= PREC_UNARY_PRE + ASSOC_MASK))
|
|
goto pe_do_binary_op;
|
|
|
|
case PE_DO_UNARY_OP:
|
|
if (cur_op.u16[0] == IC_POWER && stack_op.u16[0] == IC_UNARY_MINUS)
|
|
{
|
|
Lex(cc); //skip ` op
|
|
left_prec = cur_op.i8[2];
|
|
ParsePush(ps, tmpc);
|
|
ParsePush(ps, stack_op);
|
|
ParsePush(ps, cc->coc.coc_head.last->ic_class);
|
|
ParsePush(ps, cur_op);
|
|
goto pe_unary_term1;
|
|
}
|
|
else
|
|
{
|
|
tmpi = cc->coc.coc_head.last;
|
|
tmpc = tmpi->ic_class;
|
|
if (stack_op.u16[0] == IC_DEREF && tmpc->ptr_stars_count)
|
|
tmpc--;
|
|
else if (stack_op.u16[0] == IC_ADDR)
|
|
{
|
|
cc->abs_counts.c_address++;
|
|
if (intermediate_code_table[tmpi->ic_code].type == IST_DEREF)
|
|
OptFree(tmpi);
|
|
tmpc++;
|
|
}
|
|
tmpc = OptClassFwd(tmpc);
|
|
if (stack_op)
|
|
ICAdd(cc, stack_op, 0, tmpc);
|
|
goto pe_check_binary_ops2;
|
|
}
|
|
|
|
case PE_DO_BINARY_OP:
|
|
pe_do_binary_op:
|
|
ParsePush(ps, tmpc);
|
|
ParsePush(ps, stack_op);
|
|
if (!cur_op)
|
|
goto pe_pop_all1;
|
|
|
|
switch (cur_op.u16[0])
|
|
{
|
|
case IC_ADD:
|
|
case IC_SUB:
|
|
tmpi = cc->coc.coc_head.last;
|
|
if (!tmpi->ic_class->ptr_stars_count && tmpi->ic_class->raw_type != RT_F64)
|
|
{
|
|
ICAdd(cc, IC_SIZEOF, 1, cmp.internal_types[RT_I64]);
|
|
ICAdd(cc, IC_MUL, 0, cmp.internal_types[RT_I64]);
|
|
}
|
|
break;
|
|
|
|
case IC_AND_AND:
|
|
case IC_OR_OR:
|
|
ICAdd(cc, IC_NOP1, 0, cmp.internal_types[RT_I64]);
|
|
break;
|
|
}
|
|
if (cc->flags & CCF_FUN_EXP)
|
|
{
|
|
ps->ptr2--;
|
|
cc->flags &= ~CCF_FUN_EXP;
|
|
}
|
|
Lex(cc); //skip op
|
|
if (paren_prec > PREC_UNARY_PRE + ASSOC_MASK &&
|
|
paren_prec & ~ASSOC_MASK < left_prec & ~ASSOC_MASK + paren_prec & ASSOCF_RIGHT &&
|
|
paren_prec & ~ASSOC_MASK < cur_op.u8[2] & ~ASSOC_MASK + !(paren_prec & ASSOCF_RIGHT))
|
|
ParenWarning(cc);
|
|
if (cur_op.u8[2] > max_prec)
|
|
max_prec = cur_op.u8[2];
|
|
left_prec = cur_op.u8[2];
|
|
if (intermediate_code_table[cur_op.u16[0]].type == IST_ASSIGN)
|
|
{
|
|
tmpi = cc->coc.coc_head.last;
|
|
tmpc = OptClassFwd(tmpi->ic_class);
|
|
if (intermediate_code_table[tmpi->ic_code].type != IST_DEREF || !tmpc->ptr_stars_count &&
|
|
!Bt(&tmpc->flags, Cf_INTERNAL_TYPE))
|
|
LexExcept(cc, "Invalid lval at ");
|
|
tmpi->ic_code = IC_NOP1; //Important for setting class (pretty sure)
|
|
cur_op.u8[2] = PREC_ASSIGN | ASSOCF_RIGHT;
|
|
}
|
|
|
|
case PE_POP_HIGHER:
|
|
pe_pop_higher:
|
|
stack_op = ParsePop(ps); //pop ops of higher prec
|
|
tmpc = ParsePop(ps);
|
|
if (!stack_op)
|
|
goto pe_push_lower;
|
|
else if (cur_op.u8[2] & ~ASSOC_MASK == stack_op.u8[2] & ~ASSOC_MASK)
|
|
{
|
|
if (cur_op.u8[2] & ASSOCF_RIGHT)
|
|
goto pe_push_lower;
|
|
}
|
|
else if (cur_op.u8[2] & ~ASSOC_MASK <= stack_op.u8[2] & ~ASSOC_MASK)
|
|
goto pe_push_lower;
|
|
|
|
tmpi = ParseAddOp(cc, stack_op, tmpc);
|
|
|
|
if (intermediate_code_table[cur_op.u16[0]].type == IST_CMP &&
|
|
intermediate_code_table[stack_op.u16[0]].type == IST_CMP)
|
|
{
|
|
tmpi->ic_flags |= ICF_PUSH_CMP;
|
|
ICAdd(cc, IC_NOP1, 0, cmp.internal_types[RT_I64]);
|
|
ICAdd(cc, IC_PUSH_CMP, 0, tmpc);
|
|
cur_op.u8[3] |= ECF_HAS_PUSH_CMP;
|
|
}
|
|
else if (cur_op.u16[0] == IC_AND_AND || cur_op.u16[0] == IC_OR_OR)
|
|
ICAdd(cc, IC_NOP1, 0, cmp.internal_types[RT_I64]);
|
|
goto pe_pop_higher;
|
|
|
|
case PE_PUSH_LOWER:
|
|
pe_push_lower:
|
|
ParsePush(ps, tmpc);
|
|
ParsePush(ps, stack_op);
|
|
ParsePush(ps, cc->coc.coc_head.last->ic_class);
|
|
ParsePush(ps, cur_op);
|
|
goto pe_unary_term1;
|
|
|
|
case PE_POP_ALL1:
|
|
pe_pop_all1:
|
|
if (paren_prec > PREC_UNARY_PRE + ASSOC_MASK &&
|
|
paren_prec & ~ASSOC_MASK <= left_prec & ~ASSOC_MASK -
|
|
paren_prec & ASSOCF_LEFT - left_prec & ASSOCF_LEFT)
|
|
ParenWarning(cc);
|
|
|
|
case PE_POP_ALL2:
|
|
pe_pop_all2:
|
|
stack_op = ParsePop(ps);
|
|
tmpc = ParsePop(ps);
|
|
if (!stack_op.u16[0])
|
|
goto pe_done;
|
|
ParseAddOp(cc, stack_op, tmpc);
|
|
goto pe_pop_all2;
|
|
}
|
|
}
|
|
pe_done:
|
|
if (_max_prec)
|
|
*_max_prec = max_prec;
|
|
}
|
|
|
|
Bool ParseExpression(CCompCtrl *cc, I64 *_max_prec, Bool end_exp, CParseStack *_ps=NULL)
|
|
{
|
|
Bool res = TRUE;
|
|
I64 old_flags = cc->flags;
|
|
CParseStack *ps;
|
|
|
|
if (_ps)
|
|
ps = _ps;
|
|
else
|
|
{
|
|
ps = MAlloc(sizeof(CParseStack));
|
|
ps->ptr = 0;
|
|
ps->ptr2 = 0;
|
|
}
|
|
ParsePush(ps, 0); //terminate
|
|
ParsePush(ps, 0); //terminate
|
|
try
|
|
//try catch causes noreg variables in function
|
|
ParseExpression2(cc, _max_prec, ps);
|
|
catch
|
|
{
|
|
if (Fs->except_ch == 'Compiler')
|
|
{
|
|
res = FALSE;
|
|
Fs->catch_except = TRUE;
|
|
}
|
|
}
|
|
if (!_ps)
|
|
{
|
|
if (ps->ptr)
|
|
LexExcept(cc, "Compiler Parse Error at ");
|
|
Free(ps);
|
|
}
|
|
if (res)
|
|
{
|
|
if (end_exp)
|
|
ICAdd(cc, IC_END_EXP, 0, 0, ICF_RES_NOT_USED);
|
|
if (cc->coc.coc_head.last->ic_class == cmp.internal_types[RT_U0])
|
|
LexWarn(cc, "U0 Expression ");
|
|
}
|
|
cc->flags |= old_flags & (CCF_PREINC | CCF_PREDEC);
|
|
|
|
return res;
|
|
}
|
|
|
|
U0 ParseSizeOf(CCompCtrl *cc)
|
|
{
|
|
CHashClass *tmpc;
|
|
CMemberList *tmpm;
|
|
CDebugInfo *debug_info;
|
|
I64 i;
|
|
|
|
if (cc->token != TK_IDENT)
|
|
LexExcept(cc, "Invalid class at ");
|
|
if (tmpm = cc->local_var_entry)
|
|
{
|
|
tmpc = tmpm->member_class;
|
|
i = tmpc->size * tmpm->dim.total_count;
|
|
if (Lex(cc) == '.')
|
|
goto pu_sizeof_member;
|
|
}
|
|
else
|
|
{
|
|
if (!(tmpc = cc->hash_entry) ||
|
|
!(tmpc->type & (HTT_CLASS | HTT_INTERNAL_TYPE | HTT_GLOBAL_VAR | HTT_FUN | HTT_EXPORT_SYS_SYM)))
|
|
LexExcept(cc, "Invalid class at ");
|
|
if (tmpc->type & (HTT_FUN | HTT_EXPORT_SYS_SYM))
|
|
{
|
|
if (!(debug_info = tmpc(CHashFun *)->debug_info))
|
|
LexExcept(cc, "Size not defined at ");
|
|
i = debug_info->body[debug_info->max_line + 1 - debug_info->min_line] - debug_info->body[0];
|
|
Lex(cc);
|
|
}
|
|
else
|
|
{
|
|
i = tmpc->size;
|
|
while (Lex(cc) == '.')
|
|
{
|
|
pu_sizeof_member:
|
|
if (!(tmpc->type & (HTT_CLASS | HTT_GLOBAL_VAR)))
|
|
LexExcept(cc, "Invalid class at ");
|
|
else if (tmpc->type & HTT_GLOBAL_VAR)
|
|
tmpc = tmpc(CHashGlobalVar *)->var_class;
|
|
if (Lex(cc) != TK_IDENT || !(tmpm = MemberFind(cc->cur_str, tmpc)))
|
|
LexExcept(cc, "Invalid member at ");
|
|
else if (cc->local_var_entry)
|
|
cc->local_var_entry->use_count--;
|
|
tmpc = tmpm->member_class;
|
|
//Probably others like this:
|
|
#assert offset(CHashClass.size) == offset(CHashGlobalVar.size)
|
|
i = tmpc->size * tmpm->dim.total_count;
|
|
}
|
|
}
|
|
}
|
|
if (cc->token == '*')
|
|
{
|
|
while (Lex(cc) == '*');
|
|
i = sizeof(U8 *);
|
|
}
|
|
ICAdd(cc, IC_IMM_I64, i, cmp.internal_types[RT_I64]);
|
|
}
|
|
|
|
U0 ParseOffsetOf(CCompCtrl *cc)
|
|
{
|
|
CHashClass *tmpc;
|
|
CMemberList *tmpm;
|
|
I64 i;
|
|
|
|
if (cc->token != TK_IDENT)
|
|
LexExcept(cc, "Invalid class at ");
|
|
if (tmpm = cc->local_var_entry)
|
|
tmpc = tmpm->member_class;
|
|
else
|
|
{
|
|
tmpc = cc->hash_entry;
|
|
if (!tmpc || !(tmpc->type & (HTT_CLASS | HTT_GLOBAL_VAR)))
|
|
LexExcept(cc, "Invalid class at ");
|
|
else if (tmpc->type & HTT_GLOBAL_VAR)
|
|
tmpc = tmpc(CHashGlobalVar *)->var_class;
|
|
}
|
|
if (Lex(cc) != '.')
|
|
LexExcept(cc, "Expecting '.' at ");
|
|
i = 0;
|
|
do
|
|
{
|
|
if (Lex(cc) != TK_IDENT || !(tmpm = MemberFind(cc->cur_str, tmpc)))
|
|
LexExcept(cc, "Invalid member at ");
|
|
else if (cc->local_var_entry)
|
|
cc->local_var_entry->use_count--;
|
|
i += tmpm->offset;
|
|
tmpc = tmpm->member_class;
|
|
}
|
|
while (Lex(cc) == '.');
|
|
|
|
ICAdd(cc, IC_IMM_I64, i, cmp.internal_types[RT_I64]);
|
|
}
|
|
|
|
I64 ParseFunCall(CCompCtrl *cc, CParseStack *ps, Bool indirect, CHashFun *tmpf)
|
|
{
|
|
I64 i, argc_count, default_val;
|
|
Bool is_first_arg = TRUE, needs_right_paren, is_print, is_putchars, is_template_fun;
|
|
CHashClass *tmpc2, *last_class = NULL;
|
|
CMemberList *tmpm;
|
|
CCodeCtrl *tmpcbh, *tmpcbh1;
|
|
CCodeMisc *cm;
|
|
CIntermediateCode *tmpi;
|
|
|
|
if (!tmpf)
|
|
{
|
|
if (cc->token == TK_CHAR_CONST)
|
|
{
|
|
if (!(tmpf = HashFind("PutChars", cc->htc.hash_table_list, HTT_FUN)))
|
|
LexExcept(cc, "Missing header for Print() and PutChars() at ");
|
|
if (!cc->cur_i64) //empty char signals PutChars with variable
|
|
Lex(cc);
|
|
is_print = FALSE;
|
|
is_putchars = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (!(tmpf = HashFind("Print", cc->htc.hash_table_list, HTT_FUN)))
|
|
LexExcept(cc, "Missing header for Print() and PutChars() at ");
|
|
if (!*cc->cur_str) //empty string signals Print with variable format_str
|
|
Lex(cc);
|
|
is_putchars = FALSE;
|
|
is_print = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
is_print = FALSE;
|
|
is_putchars = FALSE;
|
|
}
|
|
|
|
if (Bt(&tmpf->flags, Ff_INTERNAL) && IC_SQR <= tmpf->exe_addr <= IC_ATAN)
|
|
is_template_fun = TRUE;
|
|
else
|
|
is_template_fun = FALSE;
|
|
|
|
if (indirect)
|
|
{
|
|
if (!(cc->flags & (CCF_RAX | CCF_ARRAY)))
|
|
ICAdd(cc, IC_DEREF, 0, cmp.internal_types[RT_PTR]);
|
|
cc->coc.coc_head.last->ic_class = cmp.internal_types[RT_PTR];
|
|
ICAdd(cc, IC_RAX_SET, 0, cmp.internal_types[RT_PTR]);
|
|
ICAdd(cc, IC_NOP2, 1, cmp.internal_types[RT_PTR]); //balance the books
|
|
}
|
|
COCPush(cc);
|
|
tmpcbh = cc->coc.coc_next;
|
|
cc->coc.coc_next = NULL;
|
|
i = tmpf->arg_count;
|
|
tmpm = tmpf->member_list_and_root;
|
|
argc_count = 0;
|
|
if (cc->token == '(')
|
|
{
|
|
Lex(cc);
|
|
needs_right_paren = TRUE;
|
|
}
|
|
else
|
|
needs_right_paren = FALSE;
|
|
while (i--)
|
|
{
|
|
COCInit(cc);
|
|
if (!is_first_arg)
|
|
{
|
|
if (is_print)
|
|
{
|
|
if (cc->token == ',')
|
|
Lex(cc);
|
|
else if (cc->token != ';')
|
|
LexExcept(cc, "Expecting ',' at ");
|
|
}
|
|
else
|
|
{
|
|
if (needs_right_paren)
|
|
{
|
|
if (cc->token == ',')
|
|
Lex(cc);
|
|
else if (cc->token != ')')
|
|
LexExcept(cc, "Expecting ',' at ");
|
|
}
|
|
}
|
|
}
|
|
if (tmpm->flags & MLF_DEFAULT_AVAILABLE && (cc->token == ')' || cc->token == ',' || !needs_right_paren))
|
|
{
|
|
default_val = tmpm->default_val;
|
|
if (tmpm->flags & MLF_LASTCLASS && last_class)
|
|
default_val = (last_class - last_class->ptr_stars_count)->str;
|
|
if (tmpm->flags & (MLF_STR_DEFAULT_AVAILABLE | MLF_LASTCLASS) && cc->flags & CCF_AOT_COMPILE)
|
|
{
|
|
cm = COCMiscNew(cc, CMT_STR_CONST);
|
|
ICAdd(cc, IC_STR_CONST, cm, cmp.internal_types[RT_U8] + 1);
|
|
cm->st_len = StrLen(default_val) + 1;
|
|
cm->str = StrNew(default_val);
|
|
cc->flags |= CCF_HAS_MISC_DATA;
|
|
}
|
|
else
|
|
ICAdd(cc, IC_IMM_I64, default_val, tmpm->member_class);
|
|
}
|
|
else
|
|
{
|
|
if (!ParseExpression(cc, NULL, FALSE, ps))
|
|
throw('Compiler');
|
|
else
|
|
{
|
|
COCPush(cc);
|
|
cc->pass = 0;
|
|
OptPass012(cc);
|
|
cc->pass = 1;
|
|
tmpi = OptPass012(cc);
|
|
COCPop(cc);
|
|
last_class = OptClassFwd(tmpi->ic_class);
|
|
tmpc2 = OptClassFwd(tmpm->member_class);
|
|
if (tmpc2->raw_type == RT_F64 && !tmpm->dim.next && last_class->raw_type != RT_F64)
|
|
tmpi->ic_flags |= ICF_RES_TO_F64;
|
|
else
|
|
if (tmpc2->raw_type != RT_F64 && last_class->raw_type == RT_F64)
|
|
tmpi->ic_flags |= ICF_RES_TO_INT;
|
|
}
|
|
}
|
|
COCPush(cc);
|
|
is_first_arg = FALSE;
|
|
tmpm = tmpm->next;
|
|
}
|
|
if (tmpm && tmpm->flags & MLF_DOT_DOT_DOT)
|
|
{
|
|
COCInit(cc);
|
|
tmpi = ICAdd(cc, IC_IMM_I64, 0, tmpm->member_class);
|
|
COCPush(cc);
|
|
if (is_print)
|
|
{
|
|
if (cc->token != ';')
|
|
{
|
|
do
|
|
{
|
|
if (!is_first_arg)
|
|
{
|
|
if (cc->token == ',')
|
|
Lex(cc);
|
|
else
|
|
LexExcept(cc, "Expecting ',' at ");
|
|
}
|
|
COCInit(cc);
|
|
if (!ParseExpression(cc, NULL, FALSE, ps))
|
|
throw('Compiler');
|
|
COCPush(cc);
|
|
is_first_arg = FALSE;
|
|
argc_count++;
|
|
}
|
|
while (cc->token == ',');
|
|
}
|
|
}
|
|
else if (needs_right_paren)
|
|
{
|
|
if (cc->token != ')')
|
|
{
|
|
do
|
|
{
|
|
if (!is_first_arg)
|
|
{
|
|
if (cc->token == ',')
|
|
Lex(cc);
|
|
else
|
|
LexExcept(cc, "Expecting ',' at ");
|
|
}
|
|
COCInit(cc);
|
|
if (!ParseExpression(cc, NULL, FALSE, ps))
|
|
throw('Compiler');
|
|
COCPush(cc);
|
|
is_first_arg = FALSE;
|
|
argc_count++;
|
|
}
|
|
while (cc->token == ',');
|
|
}
|
|
}
|
|
tmpi->ic_data = argc_count++; //++ so add_esp latter works
|
|
}
|
|
if (needs_right_paren)
|
|
{
|
|
if (cc->token == ')')
|
|
Lex(cc);
|
|
else
|
|
LexExcept(cc, "Missing ')' at ");
|
|
}
|
|
tmpcbh1 = tmpcbh->coc_next;
|
|
tmpcbh->coc_next = cc->coc.coc_next;
|
|
cc->coc.coc_next = tmpcbh;
|
|
COCPop(cc);
|
|
tmpcbh = cc->coc.coc_next;
|
|
cc->coc.coc_next = tmpcbh1;
|
|
if (!is_template_fun)
|
|
ICAdd(cc, IC_CALL_START, tmpf, 0);
|
|
if (indirect)
|
|
ICAdd(cc, IC_PUSH_REGS, 1 << REG_RAX, tmpf->return_class);
|
|
while (tmpcbh)
|
|
{
|
|
tmpcbh1 = tmpcbh->coc_next;
|
|
COCAppend(cc, tmpcbh);
|
|
if (!Bt(&tmpf->flags, Ff_INTERNAL))
|
|
cc->coc.coc_head.last->ic_flags |= ICF_PUSH_RES;
|
|
tmpcbh = tmpcbh1;
|
|
}
|
|
if (Bt(&tmpf->flags, Ff_INTERNAL))
|
|
ICAdd(cc, tmpf->exe_addr, 0, tmpf->return_class);
|
|
else
|
|
{
|
|
if (indirect)
|
|
ICAdd(cc, IC_CALL_INDIRECT, (argc_count + tmpf->arg_count) << 3, tmpf->return_class);
|
|
else if (Bt(&tmpf->flags, Cf_EXTERN))
|
|
{
|
|
cc->abs_counts.externs++;
|
|
if (cc->flags & CCF_AOT_COMPILE)
|
|
{
|
|
if (tmpf->type & HTF_IMPORT)
|
|
ICAdd(cc, IC_CALL_IMPORT, tmpf, tmpf->return_class);
|
|
else
|
|
ICAdd(cc, IC_CALL_EXTERN, tmpf, tmpf->return_class);
|
|
}
|
|
else
|
|
ICAdd(cc, IC_CALL_INDIRECT2, &tmpf->exe_addr, tmpf->return_class);
|
|
}
|
|
else
|
|
ICAdd(cc, IC_CALL, tmpf->exe_addr, tmpf->return_class);
|
|
if ((Bt(&tmpf->flags, Ff_RET1) || Bt(&tmpf->flags, Ff_ARGPOP)) && !Bt(&tmpf->flags, Ff_NOARGPOP))
|
|
{
|
|
if (indirect)
|
|
{
|
|
ICAdd(cc, IC_ADD_RSP1, (argc_count + tmpf->arg_count) << 3, tmpf->return_class);
|
|
ICAdd(cc, IC_ADD_RSP, 8, tmpf->return_class);
|
|
}
|
|
else
|
|
ICAdd(cc, IC_ADD_RSP1, (argc_count + tmpf->arg_count) << 3, tmpf->return_class);
|
|
}
|
|
else
|
|
{
|
|
if (indirect)
|
|
argc_count++;
|
|
ICAdd(cc, IC_ADD_RSP, (argc_count + tmpf->arg_count) << 3, tmpf->return_class);
|
|
}
|
|
}
|
|
if (!is_template_fun)
|
|
ICAdd(cc, IC_CALL_END, tmpf, tmpf->return_class);
|
|
if (is_print || is_putchars)
|
|
ICAdd(cc, IC_END_EXP, 0, 0, ICF_RES_NOT_USED);
|
|
cc->flags = (cc->flags | CCF_RAX) & ~(CCF_ARRAY | CCF_FUN_EXP);
|
|
|
|
return PE_UNARY_MODIFIERS;
|
|
}
|
|
|
|
I64 ParseUnaryTerm(CCompCtrl *cc, CParseStack *ps, CMemberList **_local_var, CArrayDim **_tmpad,
|
|
I64 *max_prec, I64 *unary_pre_prec, I64 *paren_prec)
|
|
{
|
|
I64 i, j;
|
|
CHashExport *tmpex;
|
|
CHashClass *tmpc;
|
|
CHashFun *tmpf;
|
|
CHashGlobalVar *tmpg;
|
|
CMemberList *tmpm;
|
|
CAsmUndefHash *tmpauh;
|
|
CCodeMisc *cm;
|
|
Bool paren_warn;
|
|
|
|
*_local_var = NULL;
|
|
*paren_prec = PREC_NULL;
|
|
switch (cc->token)
|
|
{
|
|
start:
|
|
if (PREC_UNARY_PRE > *max_prec)
|
|
*max_prec = PREC_UNARY_PRE;
|
|
*unary_pre_prec = PREC_UNARY_PRE;
|
|
start:
|
|
case '~': i = IC_COM; break;
|
|
case '!': i = IC_NOT; break;
|
|
case '-': i = IC_UNARY_MINUS; break;
|
|
case '*': i = IC_DEREF; break;
|
|
end:
|
|
Lex(cc); //Skip op
|
|
break;
|
|
|
|
case '&':
|
|
if (Lex(cc) == TK_IDENT)
|
|
{
|
|
if (tmpc = cc->hash_entry)
|
|
{
|
|
if (tmpc->type & HTT_FUN)
|
|
{
|
|
tmpf = tmpc;
|
|
if (!Bt(&tmpf->flags, Ff_INTERNAL))
|
|
{
|
|
if (Bt(&tmpf->flags, Cf_EXTERN))
|
|
{
|
|
if (cc->flags & CCF_AOT_COMPILE)
|
|
{
|
|
if (cc->flags & CCF_ASM_EXPRESSIONS)
|
|
{
|
|
if (tmpex = HashFind(tmpf->str, cc->htc.hash_table_list, HTT_EXPORT_SYS_SYM))
|
|
goto pu_export_sys_sym;
|
|
else
|
|
goto pu_new_sys_sym;
|
|
}
|
|
LexExcept(cc, "Can't take address of extern function");
|
|
}
|
|
cc->abs_counts.externs++;
|
|
ICAdd(cc, IC_IMM_I64, &tmpf->exe_addr, cmp.internal_types[RT_PTR]);
|
|
ICAdd(cc, IC_DEREF, 0, cmp.internal_types[RT_PTR]);
|
|
}
|
|
else
|
|
{
|
|
if (cc->flags & CCF_AOT_COMPILE)
|
|
{
|
|
ICAdd(cc, IC_ABS_ADDR, tmpf->exe_addr, cmp.internal_types[RT_PTR]);
|
|
if (cc->flags & CCF_ASM_EXPRESSIONS)
|
|
cc->abs_counts.abs_address++;
|
|
}
|
|
else
|
|
ICAdd(cc, IC_IMM_I64, tmpf->exe_addr, cmp.internal_types[RT_PTR]);
|
|
}
|
|
cc->abs_counts.c_address++;
|
|
Lex(cc);
|
|
return PE_MAYBE_MODIFIERS;
|
|
}
|
|
}
|
|
else if (tmpc->type & HTT_EXPORT_SYS_SYM)
|
|
{
|
|
tmpex = tmpc;
|
|
if (cc->flags & CCF_ASM_EXPRESSIONS && !(cc->flags & CCF_AOT_COMPILE) && tmpex->type & HTF_IMM)
|
|
{
|
|
cc->abs_counts.c_address++;
|
|
ICAdd(cc, IC_IMM_I64, tmpex->val, cmp.internal_types[RT_PTR]);
|
|
Lex(cc);
|
|
return PE_MAYBE_MODIFIERS;
|
|
}
|
|
else
|
|
goto pu_export_sys_sym;
|
|
}
|
|
}
|
|
else if (cc->flags & CCF_ASM_EXPRESSIONS && !cc->local_var_entry)
|
|
goto pu_ident_but_not_local_var;
|
|
}
|
|
i = IC_ADDR;
|
|
break;
|
|
end:
|
|
ParsePush(ps, tmpc);
|
|
ParsePush(ps, PREC_UNARY_PRE << 16 + i);
|
|
return PE_UNARY_TERM2;
|
|
|
|
start:
|
|
case TK_I64:
|
|
case TK_CHAR_CONST:
|
|
case TK_INS_BIN_SIZE:
|
|
if (cc->cur_i64 < 0)
|
|
ICAdd(cc, IC_IMM_I64, cc->cur_i64, cmp.internal_types[RT_U64]);
|
|
else
|
|
ICAdd(cc, IC_IMM_I64, cc->cur_i64, cmp.internal_types[RT_I64]);
|
|
Lex(cc);
|
|
break;
|
|
|
|
case TK_F64:
|
|
ICAdd(cc, IC_IMM_F64, cc->cur_f64(I64), cmp.internal_types[RT_F64]);
|
|
Lex(cc);
|
|
break;
|
|
|
|
case TK_STR:
|
|
cm = COCMiscNew(cc, CMT_STR_CONST);
|
|
ICAdd(cc, IC_STR_CONST, cm, cmp.internal_types[RT_U8] + 1);
|
|
cm->str = LexExtStr(cc, &cm->st_len);
|
|
cc->flags |= CCF_HAS_MISC_DATA;
|
|
break;
|
|
|
|
case TK_INS_BIN:
|
|
cm = COCMiscNew(cc, CMT_STR_CONST);
|
|
ICAdd(cc, IC_STR_CONST, cm, cmp.internal_types[RT_U8] + 1);
|
|
cm->str = cc->cur_str;
|
|
cm->st_len = cc->cur_str_len;
|
|
cc->cur_str = NULL;
|
|
cc->flags |= CCF_HAS_MISC_DATA;
|
|
Lex(cc);
|
|
break;
|
|
|
|
case '$$':
|
|
if (cc->flags & CCF_ASM_EXPRESSIONS)
|
|
{
|
|
cc->abs_counts.abs_address++;
|
|
if (cc->flags &CCF_AOT_COMPILE)
|
|
ICAdd(cc, IC_ABS_ADDR, cc->aotc->rip, cmp.internal_types[RT_PTR]);
|
|
else
|
|
ICAdd(cc, IC_IMM_I64, cc->aotc->rip, cmp.internal_types[RT_PTR]);
|
|
}
|
|
else
|
|
{
|
|
if (cc->flags & CCF_CLASS_DOL_OFFSET)
|
|
ICAdd(cc, IC_IMM_I64, cc->class_dol_offset, cmp.internal_types[RT_I64]);
|
|
else
|
|
ICAdd(cc, IC_RIP, 0, cmp.internal_types[RT_PTR]);
|
|
}
|
|
Lex(cc);
|
|
break;
|
|
end:
|
|
if (PREC_TERM > *max_prec)
|
|
*max_prec = PREC_TERM;
|
|
return PE_MAYBE_MODIFIERS;
|
|
|
|
case '(':
|
|
if (Lex(cc) == TK_IDENT && cc->hash_entry && cc->hash_entry->type & (HTT_CLASS | HTT_INTERNAL_TYPE))
|
|
LexExcept(cc, "Use ZealOS postfix typecasting at ");
|
|
else
|
|
{
|
|
if (PREC_TERM > *max_prec)
|
|
*max_prec = PREC_TERM;
|
|
if (cc->lex_include_stack->flags & LFSF_DEFINE)
|
|
paren_warn = FALSE;
|
|
else
|
|
paren_warn = TRUE;
|
|
if (!ParseExpression(cc, paren_prec, FALSE, ps))
|
|
throw('Compiler');
|
|
if (!paren_warn)
|
|
*paren_prec = PREC_NULL;
|
|
if (cc->token != ')')
|
|
LexExcept(cc, "Missing ')' at ");
|
|
Lex(cc); //skip )
|
|
cc->flags = cc->flags & ~CCF_ARRAY | CCF_RAX | CCF_PAREN;
|
|
return PE_UNARY_MODIFIERS;
|
|
}
|
|
|
|
start:
|
|
case '+': break;
|
|
case TK_PLUS_PLUS: cc->flags |= CCF_PREINC; break;
|
|
case TK_MINUS_MINUS: cc->flags |= CCF_PREDEC; break;
|
|
end:
|
|
if (PREC_UNARY_PRE > *max_prec)
|
|
*max_prec = PREC_UNARY_PRE;
|
|
*unary_pre_prec = PREC_UNARY_PRE;
|
|
Lex(cc);
|
|
return PE_UNARY_TERM2;
|
|
|
|
case TK_IDENT:
|
|
if (tmpm = cc->local_var_entry)
|
|
{
|
|
if (PREC_TERM > *max_prec)
|
|
*max_prec = PREC_TERM;
|
|
cc->flags &= ~(CCF_RAX | CCF_ARRAY | CCF_FUN_EXP);
|
|
tmpc = tmpm->member_class + 1;
|
|
if (tmpm->flags & MLF_FUN && !(cc->flags & CCF_ASM_EXPRESSIONS))
|
|
{
|
|
ParsePopDeref(ps);
|
|
cc->flags |= CCF_FUN_EXP;
|
|
ParsePush2(ps, tmpm->fun_ptr - tmpm->fun_ptr->ptr_stars_count);
|
|
}
|
|
if (tmpm->dim.next)
|
|
{
|
|
*_tmpad = tmpm->dim.next;
|
|
cc->flags |= CCF_ARRAY;
|
|
}
|
|
if (tmpm->flags & MLF_STATIC)
|
|
{
|
|
if (cc->flags & CCF_AOT_COMPILE)
|
|
{
|
|
// if (tmpg->flags&GVF_DATA_HEAP) //TODO
|
|
// ICAdd(cc,IC_HEAP_GLOBAL,tmpm->static_data,tmpc);
|
|
// else
|
|
ICAdd(cc, IC_ABS_ADDR, tmpm->static_data_rip, tmpc);
|
|
}
|
|
else
|
|
ICAdd(cc, IC_IMM_I64, tmpm->static_data, tmpc);
|
|
}
|
|
else
|
|
{
|
|
if (cc->flags & CCF_ASM_EXPRESSIONS)
|
|
{
|
|
i = ParsePop(ps);
|
|
ps->ptr--;
|
|
if (i.u16[0] != IC_ADDR)
|
|
LexExcept(cc, "Expecting '&' at ");
|
|
ICAdd(cc, IC_IMM_I64, tmpm->offset, cmp.internal_types[RT_PTR]);
|
|
*_local_var = tmpm;
|
|
Lex(cc);
|
|
return PE_MAYBE_MODIFIERS;
|
|
}
|
|
else
|
|
{
|
|
if (tmpm->dim.next && tmpm->offset > 0 && StrCompare(tmpm->str, "argv"))
|
|
{
|
|
tmpc++;
|
|
cc->flags &= ~CCF_ARRAY;
|
|
}
|
|
ICAdd(cc, IC_RBP, 0, tmpc);
|
|
ICAdd(cc, IC_IMM_I64, tmpm->offset, tmpc);
|
|
ICAdd(cc, IC_ADD, 0, tmpc);
|
|
}
|
|
}
|
|
Lex(cc); //skip variable name
|
|
*_local_var = tmpm;
|
|
return PE_UNARY_MODIFIERS;
|
|
}
|
|
pu_ident_but_not_local_var:
|
|
if (!(tmpex = cc->hash_entry))
|
|
{
|
|
if (!(cc->flags & CCF_ASM_EXPRESSIONS))
|
|
LexExcept(cc, "Invalid lval at ");
|
|
tmpc = NULL;
|
|
pu_new_sys_sym:
|
|
tmpex = CAlloc(sizeof(CHashExport), Fs->code_heap);
|
|
tmpex->str = cc->cur_str;
|
|
cc->cur_str = NULL;
|
|
if (!cc->htc.local_var_list && *tmpex->str == '@' && tmpex->str[1] == '@')
|
|
{
|
|
tmpex->type = HTT_EXPORT_SYS_SYM | HTF_UNRESOLVED | HTF_LOCAL;
|
|
HashAdd(tmpex, cc->htc.local_hash_table);
|
|
}
|
|
else
|
|
{
|
|
tmpex->type = HTT_EXPORT_SYS_SYM | HTF_UNRESOLVED;
|
|
if (tmpc)
|
|
HashAddAfter(tmpex, tmpc, cc->htc.global_hash_table);
|
|
else
|
|
HashAdd(tmpex, cc->htc.global_hash_table);
|
|
}
|
|
}
|
|
switch (Bsf(tmpex->type))
|
|
{
|
|
case HTt_EXPORT_SYS_SYM:
|
|
pu_export_sys_sym:
|
|
if (PREC_TERM > *max_prec)
|
|
*max_prec = PREC_TERM;
|
|
if (!(tmpex->type & (HTF_IMM | HTF_IMPORT)))
|
|
cc->abs_counts.abs_address++;
|
|
if (tmpex->type & HTF_UNRESOLVED)
|
|
{
|
|
if (!(cc->flags & CCF_ASM_EXPRESSIONS))
|
|
LexExcept(cc, "Illegal forward ref at ");
|
|
tmpauh = MAlloc(sizeof(CAsmUndefHash));
|
|
tmpauh->hash = tmpex;
|
|
tmpauh->next = cc->asm_undef_hash;
|
|
cc->asm_undef_hash = tmpauh;
|
|
if (tmpex->type & HTF_LOCAL)
|
|
cc->flags |= CCF_UNRESOLVED | CCF_LOCAL;
|
|
else
|
|
cc->flags |= CCF_UNRESOLVED;
|
|
ICAdd(cc, IC_IMM_I64, &tmpex->val, cmp.internal_types[RT_PTR], ICF_NO_RIP);
|
|
ICAdd(cc, IC_DEREF, 0, cmp.internal_types[RT_PTR]);
|
|
}
|
|
else
|
|
{
|
|
if (cc->flags & CCF_AOT_COMPILE && !(tmpex->type & HTF_IMM))
|
|
ICAdd(cc, IC_ABS_ADDR, tmpex->val, cmp.internal_types[RT_PTR]);
|
|
else
|
|
{
|
|
if (tmpex->type & HTF_IMM)
|
|
cc->abs_counts.c_address++;
|
|
ICAdd(cc, IC_IMM_I64, tmpex->val, cmp.internal_types[RT_PTR]);
|
|
}
|
|
}
|
|
Lex(cc);
|
|
return PE_MAYBE_MODIFIERS;
|
|
|
|
case HTt_FUN:
|
|
if (PREC_TERM > *max_prec)
|
|
*max_prec = PREC_TERM;
|
|
Lex(cc); //skip fun name
|
|
return ParseFunCall(cc, ps, FALSE, tmpex);
|
|
|
|
case HTt_GLOBAL_VAR:
|
|
if (PREC_TERM > *max_prec)
|
|
*max_prec = PREC_TERM;
|
|
tmpg = tmpex;
|
|
tmpc = tmpg->var_class + 1;
|
|
cc->flags &= ~(CCF_RAX | CCF_ARRAY | CCF_FUN_EXP);
|
|
if (tmpg->flags & GVF_ARRAY)
|
|
{
|
|
*_tmpad = tmpg->dim.next;
|
|
cc->flags |= CCF_ARRAY;
|
|
}
|
|
if (cc->flags & CCF_AOT_COMPILE)
|
|
{
|
|
if (tmpg->flags & GVF_EXTERN) //TODO
|
|
LexExcept(cc, "Feature not implemented ");
|
|
else
|
|
{
|
|
if (tmpg->flags & GVF_IMPORT)
|
|
ICAdd(cc, IC_ADDR_IMPORT, tmpg, tmpc);
|
|
else
|
|
{
|
|
if (tmpg->flags & GVF_DATA_HEAP)
|
|
ICAdd(cc, IC_HEAP_GLOBAL, tmpg->heap_global, tmpc);
|
|
else
|
|
ICAdd(cc, IC_ABS_ADDR, tmpg->data_addr_rip, tmpc);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (tmpg->flags & GVF_EXTERN)
|
|
{
|
|
cc->abs_counts.externs++;
|
|
ICAdd(cc, IC_IMM_I64, &tmpg->data_addr, tmpc);
|
|
ICAdd(cc, IC_DEREF, 0, tmpc);
|
|
}
|
|
else
|
|
ICAdd(cc, IC_IMM_I64, tmpg->data_addr, tmpc);
|
|
}
|
|
Lex(cc);
|
|
if (tmpg->flags & GVF_FUN)
|
|
{
|
|
ParsePopDeref(ps);
|
|
cc->flags |= CCF_FUN_EXP;
|
|
ParsePush2(ps, tmpg->fun_ptr - tmpg->fun_ptr->ptr_stars_count);
|
|
}
|
|
return PE_UNARY_MODIFIERS;
|
|
|
|
case HTt_CLASS:
|
|
ParseOffsetOf(cc);
|
|
return PE_MAYBE_MODIFIERS;
|
|
|
|
case HTt_KEYWORD:
|
|
switch (tmpex(CHashGeneric *)->user_data0)
|
|
{
|
|
case KW_SIZEOF:
|
|
if (PREC_TERM > *max_prec)
|
|
*max_prec = PREC_TERM;
|
|
j = 0;
|
|
while (Lex(cc) == '(')
|
|
j++;
|
|
ParseSizeOf(cc);
|
|
while (j--)
|
|
{
|
|
if (cc->token != ')')
|
|
LexExcept(cc, "Missing ')' at ");
|
|
Lex(cc);
|
|
}
|
|
return PE_MAYBE_MODIFIERS;
|
|
|
|
case KW_OFFSET:
|
|
if (PREC_TERM > *max_prec)
|
|
*max_prec = PREC_TERM;
|
|
j = 0;
|
|
while (Lex(cc) == '(')
|
|
j++;
|
|
ParseOffsetOf(cc);
|
|
while (j--)
|
|
{
|
|
if (cc->token != ')')
|
|
LexExcept(cc, "Missing ')' at ");
|
|
Lex(cc);
|
|
}
|
|
return PE_MAYBE_MODIFIERS;
|
|
|
|
case KW_DEFINED:
|
|
if (PREC_TERM > *max_prec)
|
|
*max_prec = PREC_TERM;
|
|
j = 0;
|
|
while (Lex(cc) == '(')
|
|
j++;
|
|
if (cc->token == TK_IDENT && (cc->hash_entry || cc->local_var_entry))
|
|
ICAdd(cc, IC_IMM_I64, TRUE, cmp.internal_types[RT_I64]);
|
|
else
|
|
ICAdd(cc, IC_IMM_I64, FALSE, cmp.internal_types[RT_I64]);
|
|
Lex(cc);
|
|
while (j--)
|
|
{
|
|
if (cc->token != ')')
|
|
LexExcept(cc, "Missing ')' at ");
|
|
Lex(cc);
|
|
}
|
|
return PE_MAYBE_MODIFIERS;
|
|
}
|
|
}
|
|
}
|
|
LexExcept(cc, "Missing expression at ");
|
|
}
|
|
|
|
I64 ParseUnaryModifier(CCompCtrl *cc, CParseStack *ps, CMemberList **_local_var, CArrayDim **_tmpad, I64 *unary_post_prec)
|
|
{
|
|
CHashClass *tmpc, *tmpc1;
|
|
CHashFun *fun_ptr;
|
|
CMemberList *tmpm = *_local_var;
|
|
CIntermediateCode *tmpi, *tmpi1;
|
|
CArrayDim *tmpad1, tmpad2;
|
|
CCodeMisc *cm;
|
|
I64 mode, old_flags;
|
|
Bool was_paren = Btr(&cc->flags, CCf_PAREN);
|
|
|
|
*_local_var = NULL;
|
|
switch (cc->token)
|
|
{
|
|
case '.':
|
|
if (tmpm)
|
|
tmpm->reg = REG_NONE;
|
|
goto um_join;
|
|
|
|
case TK_DEREFERENCE:
|
|
tmpi = cc->coc.coc_head.last;
|
|
if (!(cc->flags & (CCF_RAX | CCF_ARRAY)))
|
|
ICAdd(cc, IC_DEREF + PREC_UNARY_PRE << 16, 0, tmpi->ic_class - 1);
|
|
else
|
|
tmpi->ic_class--;
|
|
|
|
um_join:
|
|
if (!*unary_post_prec)
|
|
*unary_post_prec = PREC_TERM;
|
|
tmpc = cc->coc.coc_head.last->ic_class;
|
|
if ((!tmpc->ptr_stars_count || cc->flags & CCF_ARRAY) && cc->token == '.')
|
|
LexExcept(cc, "Must be address, not value ");
|
|
if (!(cc->flags & CCF_RAX))
|
|
tmpc--;
|
|
if (!(tmpc->type & HTT_CLASS))
|
|
LexExcept(cc, "Invalid class at ");
|
|
if (Lex(cc) != TK_IDENT || !(tmpm = MemberFind(cc->cur_str, tmpc)))
|
|
LexExcept(cc, "Invalid member at ");
|
|
else if (cc->local_var_entry)
|
|
cc->local_var_entry->use_count--;
|
|
Lex(cc); //skip member name
|
|
tmpc1 = tmpm->member_class + 1;
|
|
ICAdd(cc, IC_IMM_I64, tmpm->offset, tmpc1);
|
|
cc->flags &= ~(CCF_RAX | CCF_ARRAY | CCF_FUN_EXP);
|
|
if (tmpm->dim.next)
|
|
{
|
|
*_tmpad = tmpm->dim.next;
|
|
cc->flags |= CCF_ARRAY;
|
|
}
|
|
if (tmpm->flags & MLF_FUN)
|
|
{
|
|
ParsePopDeref(ps);
|
|
ParsePush2(ps, tmpm->fun_ptr - tmpm->fun_ptr->ptr_stars_count);
|
|
cc->flags |= CCF_FUN_EXP;
|
|
}
|
|
ICAdd(cc, IC_ADD, 0, tmpc1);
|
|
return PE_UNARY_MODIFIERS;
|
|
|
|
case '(':
|
|
if (cc->flags & CCF_FUN_EXP)
|
|
{
|
|
if (!*unary_post_prec)
|
|
*unary_post_prec = PREC_TERM;
|
|
return ParseFunCall(cc, ps, TRUE, ParsePop2(ps));
|
|
}
|
|
if (!*unary_post_prec)
|
|
*unary_post_prec = PREC_TERM;
|
|
if (Lex(cc) != TK_IDENT)
|
|
LexExcept(cc, "Invalid class at ");
|
|
if (Btr(&cc->flags, CCf_FUN_EXP))
|
|
ps->ptr2--;
|
|
cc->flags &= ~CCF_ARRAY;
|
|
tmpc = cc->hash_entry;
|
|
Lex(cc);
|
|
mode = PRS0_TYPECAST | PRS1_NULL;
|
|
tmpc = ParseType(cc, &tmpc, &mode, NULL, NULL, &fun_ptr, NULL, &tmpad2, 0);
|
|
if (fun_ptr)
|
|
{
|
|
ParsePopDeref(ps);
|
|
Bts(&cc->flags, CCf_FUN_EXP);
|
|
ParsePush2(ps, fun_ptr);
|
|
cm=COCMiscNew(cc, CMT_HASH_ENTRY);
|
|
cm->h = fun_ptr;
|
|
}
|
|
if (*_tmpad = tmpad2.next)
|
|
{
|
|
cc->flags |= CCF_ARRAY;
|
|
tmpc++;
|
|
cm = COCMiscNew(cc, CMT_ARRAY_DIM);
|
|
cm->dim = *_tmpad;
|
|
}
|
|
if (!(cc->flags & (CCF_RAX | CCF_ARRAY)))
|
|
tmpc++;
|
|
tmpi = cc->coc.coc_head.last;
|
|
tmpi->ic_class = tmpc;
|
|
ICAdd(cc, IC_POSTFIX_TYPECAST, was_paren, tmpc);
|
|
if (cc->token != ')')
|
|
LexExcept(cc, "Missing ')' at ");
|
|
Lex(cc);
|
|
return PE_UNARY_MODIFIERS;
|
|
|
|
case '[':
|
|
if (!*unary_post_prec)
|
|
*unary_post_prec = PREC_TERM;
|
|
Lex(cc);
|
|
tmpc = OptClassFwd(cc->coc.coc_head.last->ic_class);
|
|
if (!tmpc->ptr_stars_count)
|
|
LexExcept(cc, "Not array or pointer ");
|
|
if (!(cc->flags & (CCF_ARRAY | CCF_RAX)))
|
|
{
|
|
tmpc = OptClassFwd(tmpc - 1);
|
|
if (!tmpc->ptr_stars_count)
|
|
LexExcept(cc, "Not array or pointer ");
|
|
ICAdd(cc, IC_DEREF + PREC_UNARY_PRE << 16, 0, tmpc);
|
|
}
|
|
tmpc1 = tmpc - 1;
|
|
if (tmpad1 = *_tmpad)
|
|
{
|
|
ICAdd(cc, IC_IMM_I64, tmpad1->total_count * tmpc1->size, tmpc);
|
|
if (*_tmpad = tmpad1->next)
|
|
{
|
|
old_flags = cc->flags;
|
|
if (!ParseExpression(cc, NULL, FALSE, ps))
|
|
throw('Compiler');
|
|
cc->flags = cc->flags & ~CCF_FUN_EXP | old_flags & CCF_FUN_EXP;
|
|
if (cc->token != ']')
|
|
LexExcept(cc, "Missing ']' at ");
|
|
Lex(cc); //skip ]
|
|
tmpi1 = cc->coc.coc_head.last;
|
|
tmpi1->ic_flags |= ICF_RES_TO_INT;
|
|
ICAdd(cc, IC_MUL, 0, tmpc);
|
|
ICAdd(cc, IC_ADD, 0, tmpc);
|
|
cc->flags |= CCF_RAX;
|
|
return PE_UNARY_MODIFIERS;
|
|
}
|
|
}
|
|
else
|
|
ICAdd(cc, IC_IMM_I64, tmpc1->size, tmpc);
|
|
old_flags = cc->flags;
|
|
if (!ParseExpression(cc, NULL, FALSE, ps))
|
|
throw('Compiler');
|
|
cc->flags = cc->flags & ~CCF_FUN_EXP | old_flags & CCF_FUN_EXP;
|
|
if (cc->token != ']')
|
|
LexExcept(cc,"Missing ']' at ");
|
|
Lex(cc); //skip ]
|
|
tmpi1 = cc->coc.coc_head.last;
|
|
tmpi1->ic_flags |= ICF_RES_TO_INT;
|
|
ICAdd(cc, IC_MUL, 0, tmpc);
|
|
ICAdd(cc, IC_ADD, 0, tmpc);
|
|
cc->flags &= ~(CCF_RAX | CCF_ARRAY);
|
|
return PE_UNARY_MODIFIERS;
|
|
start:
|
|
case TK_PLUS_PLUS:
|
|
cc->flags |= CCF_POSTINC;
|
|
break;
|
|
|
|
case TK_MINUS_MINUS:
|
|
cc->flags |= CCF_POSTDEC;
|
|
break;
|
|
end:
|
|
if (!*unary_post_prec)
|
|
*unary_post_prec = PREC_UNARY_POST;
|
|
Lex(cc);
|
|
return PE_DEREFERENCE;
|
|
}
|
|
|
|
return PE_DEREFERENCE;
|
|
}
|
|
|
|
U8 *LexExpression2Bin(CCompCtrl *cc, I64 *_type=NULL)
|
|
{//Compile cc expression. You call the code.
|
|
U8 *res;
|
|
I64 size;
|
|
Bool old_trace = Btr(&cc->flags, CCf_PASS_TRACE_PRESENT);
|
|
|
|
COCPush(cc);
|
|
COCInit(cc);
|
|
if (ParseExpression(cc, NULL, FALSE))
|
|
{
|
|
ICAdd(cc, IC_RETURN_VAL, 0, 0);
|
|
ICAdd(cc, IC_RET, 0, 0);
|
|
res = COCCompile(cc, &size, NULL, _type);
|
|
}
|
|
else
|
|
res = NULL;
|
|
COCPop(cc);
|
|
BEqual(&cc->flags, CCf_PASS_TRACE_PRESENT, old_trace);
|
|
|
|
return res;
|
|
}
|
|
|
|
Bool IsLexExpression2Bin(CCompCtrl *cc, U8 **_machine_code)
|
|
{//Compile cc expression to bin. Return error status.
|
|
return ToBool(*_machine_code = LexExpression2Bin(cc));
|
|
}
|
|
|
|
I64 LexExpressionI64(CCompCtrl *cc)
|
|
{//Compile cc expression, forcing to I64 and eval.
|
|
U8 *machine_code;
|
|
I64 res, type;
|
|
|
|
if (machine_code = LexExpression2Bin(cc, &type))
|
|
{
|
|
res = Call(machine_code);
|
|
Free(machine_code);
|
|
if (type == RT_F64)
|
|
res = ToI64(res(F64));
|
|
}
|
|
else
|
|
res = 0;
|
|
|
|
return res;
|
|
}
|
|
|
|
F64 LexExpressionF64(CCompCtrl *cc)
|
|
{//Compile cc expression, forcing to F64 and eval.
|
|
U8 *machine_code;
|
|
I64 res, type;
|
|
|
|
if (machine_code = LexExpression2Bin(cc, &type))
|
|
{
|
|
res = Call(machine_code);
|
|
Free(machine_code);
|
|
if (type != RT_F64)
|
|
res(F64) = ToF64(res);
|
|
}
|
|
else
|
|
res = 0;
|
|
|
|
return res(F64);
|
|
}
|
|
|
|
I64 LexExpression(CCompCtrl *cc)
|
|
{//Compile cc expression and eval. Might be I64 or F64.
|
|
U8 *machine_code;
|
|
I64 res;
|
|
|
|
if (machine_code = LexExpression2Bin(cc))
|
|
{
|
|
res = Call(machine_code);
|
|
Free(machine_code);
|
|
}
|
|
else
|
|
res = 0;
|
|
|
|
return res;
|
|
}
|