implemented call-by-reference parameters of normal awk functions partially. it has yet to be refined further

This commit is contained in:
hyung-hwan 2019-06-07 09:26:50 +00:00
parent 040ee69eb7
commit 4255f9599f
7 changed files with 238 additions and 257 deletions

View File

@ -448,7 +448,7 @@ struct qse_awk_fun_t
{ {
qse_cstr_t name; qse_cstr_t name;
qse_size_t nargs; qse_size_t nargs;
qse_char_t* argspec; /* similar to the argument spec of qse_awk_fnc_arg_t. supports v & r only */ qse_char_t* argspec; /* similar to the argument spec of qse_awk_fnc_arg_t. supports v & r only. */
qse_awk_nde_t* body; qse_awk_nde_t* body;
}; };
typedef struct qse_awk_fun_t qse_awk_fun_t; typedef struct qse_awk_fun_t qse_awk_fun_t;

View File

@ -1301,9 +1301,7 @@ int Awk::loop (Value* ret)
return 0; return 0;
} }
int Awk::call ( int Awk::call (const char_t* name, Value* ret, const Value* args, size_t nargs)
const char_t* name, Value* ret,
const Value* args, size_t nargs)
{ {
QSE_ASSERT (this->awk != QSE_NULL); QSE_ASSERT (this->awk != QSE_NULL);
QSE_ASSERT (this->runctx.rtx != QSE_NULL); QSE_ASSERT (this->runctx.rtx != QSE_NULL);
@ -1329,7 +1327,7 @@ int Awk::call (
for (size_t i = 0; i < nargs; i++) ptr[i] = (val_t*)args[i]; for (size_t i = 0; i < nargs; i++) ptr[i] = (val_t*)args[i];
} }
val_t* rv = qse_awk_rtx_call (this->runctx.rtx, name, ptr, nargs); val_t* rv = qse_awk_rtx_call(this->runctx.rtx, name, ptr, nargs);
if (ptr != QSE_NULL && ptr != buf) qse_awk_freemem (awk, ptr); if (ptr != QSE_NULL && ptr != buf) qse_awk_freemem (awk, ptr);

View File

@ -35,6 +35,7 @@ static void free_fun (qse_htb_t* map, void* vptr, qse_size_t vlen)
/* f->name doesn't have to be freed */ /* f->name doesn't have to be freed */
/*qse_awk_freemem (awk, f->name);*/ /*qse_awk_freemem (awk, f->name);*/
if (f->argspec) qse_awk_freemem (awk, f->argspec);
qse_awk_clrpt (awk, f->body); qse_awk_clrpt (awk, f->body);
qse_awk_freemem (awk, f); qse_awk_freemem (awk, f);
} }

View File

@ -1180,8 +1180,10 @@ static int parse_progunit (qse_awk_t* awk)
static qse_awk_nde_t* parse_function (qse_awk_t* awk) static qse_awk_nde_t* parse_function (qse_awk_t* awk)
{ {
qse_cstr_t name; qse_cstr_t name;
qse_awk_nde_t* body; qse_awk_nde_t* body = QSE_NULL;
qse_awk_fun_t* fun; qse_awk_fun_t* fun = QSE_NULL;
qse_char_t* argspec = QSE_NULL;
qse_size_t argspeccapa = 0;
qse_size_t nargs, g; qse_size_t nargs, g;
qse_htb_pair_t* pair; qse_htb_pair_t* pair;
qse_awk_loc_t xloc; qse_awk_loc_t xloc;
@ -1226,27 +1228,18 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
} }
/* get the next token */ /* get the next token */
if (get_token(awk) <= -1) if (get_token(awk) <= -1) goto oops;
{
qse_awk_freemem (awk, name.ptr);
return QSE_NULL;
}
/* match a left parenthesis */ /* match a left parenthesis */
if (!MATCH(awk,TOK_LPAREN)) if (!MATCH(awk,TOK_LPAREN))
{ {
/* a function name is not followed by a left parenthesis */ /* a function name is not followed by a left parenthesis */
SETERR_TOK (awk, QSE_AWK_ELPAREN); SETERR_TOK (awk, QSE_AWK_ELPAREN);
qse_awk_freemem (awk, name.ptr); goto oops;
return QSE_NULL;
} }
/* get the next token */ /* get the next token */
if (get_token(awk) <= -1) if (get_token(awk) <= -1) goto oops;
{
qse_awk_freemem (awk, name.ptr);
return QSE_NULL;
}
/* make sure that parameter table is empty */ /* make sure that parameter table is empty */
QSE_ASSERT (QSE_ARR_SIZE(awk->parse.params) == 0); QSE_ASSERT (QSE_ARR_SIZE(awk->parse.params) == 0);
@ -1255,11 +1248,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
if (MATCH(awk,TOK_RPAREN)) if (MATCH(awk,TOK_RPAREN))
{ {
/* no function parameter found. get the next token */ /* no function parameter found. get the next token */
if (get_token(awk) <= -1) if (get_token(awk) <= -1) goto oops;
{
qse_awk_freemem (awk, name.ptr);
return QSE_NULL;
}
} }
else else
{ {
@ -1268,12 +1257,26 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
qse_char_t* pa; qse_char_t* pa;
qse_size_t pal; qse_size_t pal;
if (MATCH(awk, TOK_BAND))
{
/* pass-by-reference argument */
nargs = QSE_ARR_SIZE(awk->parse.params);
if (nargs >= argspeccapa)
{
qse_size_t i, newcapa = QSE_ALIGNTO_POW2(nargs + 1, 64);
argspec = qse_awk_reallocmem(awk, argspec, newcapa * QSE_SIZEOF(*argspec));
if (!argspec) goto oops;
for (i = argspeccapa; i < newcapa; i++) argspec[i] = QSE_T(' ');
argspeccapa = newcapa;
}
argspec[nargs] = QSE_T('r');
if (get_token(awk) <= -1) goto oops;
}
if (!MATCH(awk,TOK_IDENT)) if (!MATCH(awk,TOK_IDENT))
{ {
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
SETERR_TOK (awk, QSE_AWK_EBADPAR); SETERR_TOK (awk, QSE_AWK_EBADPAR);
return QSE_NULL; goto oops;
} }
pa = QSE_STR_PTR(awk->tok.name); pa = QSE_STR_PTR(awk->tok.name);
@ -1291,68 +1294,43 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
* name or other parameters */ * name or other parameters */
if (((awk->opt.trait & QSE_AWK_STRICTNAMING) && if (((awk->opt.trait & QSE_AWK_STRICTNAMING) &&
qse_strxncmp (pa, pal, name.ptr, name.len) == 0) || qse_strxncmp (pa, pal, name.ptr, name.len) == 0) ||
qse_arr_search (awk->parse.params, 0, pa, pal) != QSE_ARR_NIL) qse_arr_search(awk->parse.params, 0, pa, pal) != QSE_ARR_NIL)
{ {
qse_awk_freemem (awk, name.ptr); SETERR_ARG_LOC (awk, QSE_AWK_EDUPPAR, pa, pal, &awk->tok.loc);
qse_arr_clear (awk->parse.params); goto oops;
SETERR_ARG_LOC (
awk, QSE_AWK_EDUPPAR,
pa, pal, &awk->tok.loc);
return QSE_NULL;
} }
/* push the parameter to the parameter list */ /* push the parameter to the parameter list */
if (QSE_ARR_SIZE(awk->parse.params) >= QSE_AWK_MAX_PARAMS) if (QSE_ARR_SIZE(awk->parse.params) >= QSE_AWK_MAX_PARAMS)
{ {
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
SETERR_LOC (awk, QSE_AWK_EPARTM, &awk->tok.loc); SETERR_LOC (awk, QSE_AWK_EPARTM, &awk->tok.loc);
return QSE_NULL; goto oops;
} }
if (qse_arr_insert(awk->parse.params, QSE_ARR_SIZE(awk->parse.params), pa, pal) == QSE_ARR_NIL) if (qse_arr_insert(awk->parse.params, QSE_ARR_SIZE(awk->parse.params), pa, pal) == QSE_ARR_NIL)
{ {
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
SETERR_LOC (awk, QSE_AWK_ENOMEM, &awk->tok.loc); SETERR_LOC (awk, QSE_AWK_ENOMEM, &awk->tok.loc);
return QSE_NULL; goto oops;
} }
if (get_token (awk) <= -1) if (get_token(awk) <= -1) goto oops;
{
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
return QSE_NULL;
}
if (MATCH(awk,TOK_RPAREN)) break; if (MATCH(awk,TOK_RPAREN)) break;
if (!MATCH(awk,TOK_COMMA)) if (!MATCH(awk,TOK_COMMA))
{ {
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
SETERR_TOK (awk, QSE_AWK_ECOMMA); SETERR_TOK (awk, QSE_AWK_ECOMMA);
return QSE_NULL; goto oops;
} }
do do
{ {
if (get_token(awk) <= -1) if (get_token(awk) <= -1) goto oops;
{
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
return QSE_NULL;
}
} }
while (MATCH(awk,TOK_NEWLINE)); while (MATCH(awk,TOK_NEWLINE));
} }
if (get_token(awk) <= -1) if (get_token(awk) <= -1) goto oops;
{
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
return QSE_NULL;
}
} }
/* function body can be placed on a different line /* function body can be placed on a different line
@ -1361,28 +1339,16 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
* available only when the option is set. */ * available only when the option is set. */
while (MATCH(awk,TOK_NEWLINE)) while (MATCH(awk,TOK_NEWLINE))
{ {
if (get_token(awk) <= -1) if (get_token(awk) <= -1) goto oops;
{
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
return QSE_NULL;
}
} }
/* check if the function body starts with a left brace */ /* check if the function body starts with a left brace */
if (!MATCH(awk,TOK_LBRACE)) if (!MATCH(awk,TOK_LBRACE))
{ {
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
SETERR_TOK (awk, QSE_AWK_ELBRACE); SETERR_TOK (awk, QSE_AWK_ELBRACE);
return QSE_NULL; goto oops;
}
if (get_token(awk) <= -1)
{
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
return QSE_NULL;
} }
if (get_token(awk) <= -1) goto oops;
/* remember the current function name so that the body parser /* remember the current function name so that the body parser
* can know the name of the current function being parsed */ * can know the name of the current function being parsed */
@ -1391,18 +1357,13 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
/* actual function body */ /* actual function body */
xloc = awk->ptok.loc; xloc = awk->ptok.loc;
body = parse_block_dc (awk, &xloc, 1); body = parse_block_dc(awk, &xloc, 1);
/* clear the current function name remembered */ /* clear the current function name remembered */
awk->tree.cur_fun.ptr = QSE_NULL; awk->tree.cur_fun.ptr = QSE_NULL;
awk->tree.cur_fun.len = 0; awk->tree.cur_fun.len = 0;
if (body == QSE_NULL) if (!body) goto oops;
{
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
return QSE_NULL;
}
/* TODO: study furthur if the parameter names should be saved /* TODO: study furthur if the parameter names should be saved
* for some reasons - might be needed for better deparsing output */ * for some reasons - might be needed for better deparsing output */
@ -1413,15 +1374,14 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
fun = (qse_awk_fun_t*)qse_awk_callocmem(awk, QSE_SIZEOF(*fun)); fun = (qse_awk_fun_t*)qse_awk_callocmem(awk, QSE_SIZEOF(*fun));
if (fun == QSE_NULL) if (fun == QSE_NULL)
{ {
qse_awk_freemem (awk, name.ptr);
qse_awk_clrpt (awk, body);
ADJERR_LOC (awk, &awk->tok.loc); ADJERR_LOC (awk, &awk->tok.loc);
return QSE_NULL; goto oops;
} }
/*fun->name.ptr = QSE_NULL;*/ /* function name is set below */ /*fun->name.ptr = QSE_NULL;*/ /* function name is set below */
fun->name.len = 0; fun->name.len = 0;
fun->nargs = nargs; fun->nargs = nargs;
fun->argspec = argspec;
fun->body = body; fun->body = body;
pair = qse_htb_insert(awk->tree.funs, name.ptr, name.len, fun, 0); pair = qse_htb_insert(awk->tree.funs, name.ptr, name.len, fun, 0);
@ -1430,11 +1390,8 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
/* if qse_htb_insert() fails for other reasons than memory /* if qse_htb_insert() fails for other reasons than memory
* shortage, there should be implementaion errors as duplicate * shortage, there should be implementaion errors as duplicate
* functions are detected earlier in this function */ * functions are detected earlier in this function */
qse_awk_freemem (awk, name.ptr);
qse_awk_clrpt (awk, body);
qse_awk_freemem (awk, fun);
SETERR_LOC (awk, QSE_AWK_ENOMEM, &awk->tok.loc); SETERR_LOC (awk, QSE_AWK_ENOMEM, &awk->tok.loc);
return QSE_NULL; goto oops;
} }
/* do some trick to save a string. make it back-point at the key part /* do some trick to save a string. make it back-point at the key part
@ -1446,6 +1403,14 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
/* remove an undefined function call entry from the parse.fun table */ /* remove an undefined function call entry from the parse.fun table */
qse_htb_delete (awk->parse.funs, fun->name.ptr, name.len); qse_htb_delete (awk->parse.funs, fun->name.ptr, name.len);
return body; return body;
oops:
if (body) qse_awk_clrpt (awk, body);
if (argspec) qse_awk_freemem (awk, argspec);
if (fun) qse_awk_freemem (awk, fun);
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
return QSE_NULL;
} }
static qse_awk_nde_t* parse_begin (qse_awk_t* awk) static qse_awk_nde_t* parse_begin (qse_awk_t* awk)
@ -5109,7 +5074,6 @@ static qse_awk_nde_t* parse_fun_as_value (qse_awk_t* awk, const qse_cstr_t* nam
nde->name.len = name->len; nde->name.len = name->len;
nde->funptr = funptr; nde->funptr = funptr;
return (qse_awk_nde_t*)nde; return (qse_awk_nde_t*)nde;
} }
#endif #endif
@ -6690,10 +6654,10 @@ static int deparse (qse_awk_t* awk)
if (awk->opt.trait & QSE_AWK_CRLF) if (awk->opt.trait & QSE_AWK_CRLF)
{ {
if (put_char (awk, QSE_T('\r')) <= -1) EXIT_DEPARSE (); if (put_char(awk, QSE_T('\r')) <= -1) EXIT_DEPARSE ();
} }
if (put_char (awk, QSE_T('\n')) <= -1) EXIT_DEPARSE (); if (put_char(awk, QSE_T('\n')) <= -1) EXIT_DEPARSE ();
} }
chain = awk->tree.chain; chain = awk->tree.chain;
@ -6701,7 +6665,7 @@ static int deparse (qse_awk_t* awk)
{ {
if (chain->pattern != QSE_NULL) if (chain->pattern != QSE_NULL)
{ {
if (qse_awk_prnptnpt (awk, chain->pattern) <= -1) EXIT_DEPARSE (); if (qse_awk_prnptnpt(awk, chain->pattern) <= -1) EXIT_DEPARSE ();
} }
if (chain->action == QSE_NULL) if (chain->action == QSE_NULL)
@ -6709,26 +6673,26 @@ static int deparse (qse_awk_t* awk)
/* blockless pattern */ /* blockless pattern */
if (awk->opt.trait & QSE_AWK_CRLF) if (awk->opt.trait & QSE_AWK_CRLF)
{ {
if (put_char (awk, QSE_T('\r')) <= -1) EXIT_DEPARSE (); if (put_char(awk, QSE_T('\r')) <= -1) EXIT_DEPARSE ();
} }
if (put_char (awk, QSE_T('\n')) <= -1) EXIT_DEPARSE (); if (put_char(awk, QSE_T('\n')) <= -1) EXIT_DEPARSE ();
} }
else else
{ {
if (chain->pattern != QSE_NULL) if (chain->pattern != QSE_NULL)
{ {
if (put_char (awk, QSE_T(' ')) <= -1) EXIT_DEPARSE (); if (put_char(awk, QSE_T(' ')) <= -1) EXIT_DEPARSE ();
} }
if (qse_awk_prnpt (awk, chain->action) <= -1) EXIT_DEPARSE (); if (qse_awk_prnpt(awk, chain->action) <= -1) EXIT_DEPARSE ();
} }
if (awk->opt.trait & QSE_AWK_CRLF) if (awk->opt.trait & QSE_AWK_CRLF)
{ {
if (put_char (awk, QSE_T('\r')) <= -1) EXIT_DEPARSE (); if (put_char(awk, QSE_T('\r')) <= -1) EXIT_DEPARSE ();
} }
if (put_char (awk, QSE_T('\n')) <= -1) EXIT_DEPARSE (); if (put_char(awk, QSE_T('\n')) <= -1) EXIT_DEPARSE ();
chain = chain->next; chain = chain->next;
} }
@ -6739,9 +6703,9 @@ static int deparse (qse_awk_t* awk)
qse_awk_getkwname (awk, QSE_AWK_KWID_END, &kw); qse_awk_getkwname (awk, QSE_AWK_KWID_END, &kw);
if (qse_awk_putsrcstrn (awk, kw.ptr, kw.len) <= -1) EXIT_DEPARSE (); if (qse_awk_putsrcstrn(awk, kw.ptr, kw.len) <= -1) EXIT_DEPARSE ();
if (qse_awk_putsrcstr (awk, QSE_T(" ")) <= -1) EXIT_DEPARSE (); if (qse_awk_putsrcstr(awk, QSE_T(" ")) <= -1) EXIT_DEPARSE ();
if (qse_awk_prnnde (awk, nde) <= -1) EXIT_DEPARSE (); if (qse_awk_prnnde(awk, nde) <= -1) EXIT_DEPARSE ();
/* /*
if (awk->opt.trait & QSE_AWK_CRLF) if (awk->opt.trait & QSE_AWK_CRLF)
@ -6802,9 +6766,8 @@ static qse_htb_walk_t deparse_func (qse_htb_t* map, qse_htb_pair_t* pair, void*
for (i = 0; i < fun->nargs; ) for (i = 0; i < fun->nargs; )
{ {
n = qse_awk_inttostr ( if (fun->argspec && fun->argspec[i] == 'r') PUT_S (df, QSE_T("&"));
df->awk, i++, 10, n = qse_awk_inttostr (df->awk, i++, 10, QSE_T("__p"), df->tmp, df->tmp_len);
QSE_T("__p"), df->tmp, df->tmp_len);
QSE_ASSERT (n != (qse_size_t)-1); QSE_ASSERT (n != (qse_size_t)-1);
PUT_SX (df, df->tmp, n); PUT_SX (df, df->tmp, n);
@ -6817,7 +6780,7 @@ static qse_htb_walk_t deparse_func (qse_htb_t* map, qse_htb_pair_t* pair, void*
PUT_C (df, QSE_T('\n')); PUT_C (df, QSE_T('\n'));
if (qse_awk_prnpt (df->awk, fun->body) <= -1) return -1; if (qse_awk_prnpt(df->awk, fun->body) <= -1) return -1;
if (df->awk->opt.trait & QSE_AWK_CRLF) if (df->awk->opt.trait & QSE_AWK_CRLF)
{ {
PUT_C (df, QSE_T('\r')); PUT_C (df, QSE_T('\r'));

View File

@ -110,8 +110,8 @@ struct pafv
#define ADJERR_LOC(rtx,l) do { (rtx)->errinf.loc = *(l); } while (0) #define ADJERR_LOC(rtx,l) do { (rtx)->errinf.loc = *(l); } while (0)
static qse_size_t push_arg_from_vals ( static qse_size_t push_arg_from_vals (qse_awk_rtx_t* rtx, qse_awk_nde_fncall_t* call, void* data);
qse_awk_rtx_t* rtx, qse_awk_nde_fncall_t* call, void* data); static qse_size_t push_arg_from_nde (qse_awk_rtx_t* rtx, qse_awk_nde_fncall_t* call, void* data);
static int init_rtx (qse_awk_rtx_t* rtx, qse_awk_t* awk, qse_awk_rio_t* rio); static int init_rtx (qse_awk_rtx_t* rtx, qse_awk_t* awk, qse_awk_rio_t* rio);
static void fini_rtx (qse_awk_rtx_t* rtx, int fini_globals); static void fini_rtx (qse_awk_rtx_t* rtx, int fini_globals);
@ -192,27 +192,21 @@ static qse_awk_val_t* eval_incpre (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_incpst (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde); static qse_awk_val_t* eval_incpst (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_cnd (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde); static qse_awk_val_t* eval_cnd (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_fncall_fncall_fun_ex (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde, void(*errhandler)(void*), void* eharg); static qse_awk_val_t* eval_fncall_fun_ex (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde, void(*errhandler)(void*), void* eharg);
static qse_awk_val_t* eval_fncall_fnc (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde); static qse_awk_val_t* eval_fncall_fnc (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_fncall_fncall_fun (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde); static qse_awk_val_t* eval_fncall_fun (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_fncall_var (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde); static qse_awk_val_t* eval_fncall_var (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde);
static qse_awk_val_t* __eval_call ( static qse_awk_val_t* __eval_call (
qse_awk_rtx_t* rtx, qse_awk_rtx_t* rtx,
qse_awk_nde_t* nde, qse_awk_nde_t* nde,
const qse_char_t* fnc_arg_spec,
qse_awk_fun_t* fun, qse_awk_fun_t* fun,
qse_size_t(*argpusher)(qse_awk_rtx_t*,qse_awk_nde_fncall_t*,void*), qse_size_t(*argpusher)(qse_awk_rtx_t*,qse_awk_nde_fncall_t*,void*),
void* apdata, void* apdata, /* data to argpusher */
void(*errhandler)(void*), void(*errhandler)(void*),
void* eharg); void* eharg);
static qse_awk_val_t* eval_call (
qse_awk_rtx_t* rtx, qse_awk_nde_t* nde,
const qse_char_t* fnc_arg_spec, qse_awk_fun_t* fun,
void(*errhandler)(void*), void* eharg);
static int get_reference (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde, qse_awk_val_t*** ref); static int get_reference (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde, qse_awk_val_t*** ref);
static qse_awk_val_t** get_reference_indexed (qse_awk_rtx_t* rtx, qse_awk_nde_var_t* nde, qse_awk_val_t** val); static qse_awk_val_t** get_reference_indexed (qse_awk_rtx_t* rtx, qse_awk_nde_var_t* nde, qse_awk_val_t** val);
@ -1557,6 +1551,14 @@ qse_awk_val_t* qse_awk_rtx_callfun (qse_awk_rtx_t* rtx, qse_awk_fun_t* fun, qse_
} }
/*rtx->exit_level = EXIT_NONE;*/ /*rtx->exit_level = EXIT_NONE;*/
if (fun->argspec)
{
/* this function contains call-by-reference parameters.
* i don't support the call here as it requires variables */
qse_awk_rtx_seterrfmt (rtx, QSE_AWK_EPERM, QSE_NULL, QSE_T("not allowed to call '%.*js' with call-by-reference parameters"), (int)fun->name.len, fun->name.ptr);
return QSE_NULL;
}
/* forge a fake node containing a function call */ /* forge a fake node containing a function call */
QSE_MEMSET (&call, 0, QSE_SIZEOF(call)); QSE_MEMSET (&call, 0, QSE_SIZEOF(call));
call.type = QSE_AWK_NDE_FNCALL_FUN; call.type = QSE_AWK_NDE_FNCALL_FUN;
@ -1577,12 +1579,7 @@ qse_awk_val_t* qse_awk_rtx_callfun (qse_awk_rtx_t* rtx, qse_awk_fun_t* fun, qse_
crdata.rtx = rtx; crdata.rtx = rtx;
crdata.val = QSE_NULL; crdata.val = QSE_NULL;
v = __eval_call ( v = __eval_call(rtx, (qse_awk_nde_t*)&call, fun, push_arg_from_vals, (void*)&pafv, capture_retval_on_exit, &crdata);
rtx, (qse_awk_nde_t*)&call, QSE_NULL, fun,
push_arg_from_vals, (void*)&pafv,
capture_retval_on_exit,
&crdata
);
if (!v) if (!v)
{ {
@ -1606,32 +1603,28 @@ qse_awk_val_t* qse_awk_rtx_callfun (qse_awk_rtx_t* rtx, qse_awk_fun_t* fun, qse_
} }
/* call an AWK function by name */ /* call an AWK function by name */
qse_awk_val_t* qse_awk_rtx_call ( qse_awk_val_t* qse_awk_rtx_call (qse_awk_rtx_t* rtx, const qse_char_t* name, qse_awk_val_t* args[], qse_size_t nargs)
qse_awk_rtx_t* rtx, const qse_char_t* name,
qse_awk_val_t* args[], qse_size_t nargs)
{ {
qse_awk_fun_t* fun; qse_awk_fun_t* fun;
fun = qse_awk_rtx_findfun (rtx, name); fun = qse_awk_rtx_findfun(rtx, name);
if (fun == QSE_NULL) return QSE_NULL; if (!fun) return QSE_NULL;
return qse_awk_rtx_callfun (rtx, fun, args, nargs); return qse_awk_rtx_callfun(rtx, fun, args, nargs);
} }
qse_awk_val_t* qse_awk_rtx_callwithstrs ( qse_awk_val_t* qse_awk_rtx_callwithstrs (qse_awk_rtx_t* rtx, const qse_char_t* name, const qse_char_t* args[], qse_size_t nargs)
qse_awk_rtx_t* rtx, const qse_char_t* name,
const qse_char_t* args[], qse_size_t nargs)
{ {
qse_size_t i; qse_size_t i;
qse_awk_val_t** v, * ret; qse_awk_val_t** v, * ret;
v = qse_awk_rtx_allocmem (rtx, QSE_SIZEOF(*v) * nargs); v = qse_awk_rtx_allocmem (rtx, QSE_SIZEOF(*v) * nargs);
if (v == QSE_NULL) return QSE_NULL; if (!v) return QSE_NULL;
for (i = 0; i < nargs; i++) for (i = 0; i < nargs; i++)
{ {
v[i] = qse_awk_rtx_makestrvalwithstr (rtx, args[i]); v[i] = qse_awk_rtx_makestrvalwithstr (rtx, args[i]);
if (v[i] == QSE_NULL) if (!v[i])
{ {
ret = QSE_NULL; ret = QSE_NULL;
goto oops; goto oops;
@ -1640,7 +1633,7 @@ qse_awk_val_t* qse_awk_rtx_callwithstrs (
qse_awk_rtx_refupval (rtx, v[i]); qse_awk_rtx_refupval (rtx, v[i]);
} }
ret = qse_awk_rtx_call (rtx, name, v, nargs); ret = qse_awk_rtx_call(rtx, name, v, nargs);
oops: oops:
while (i > 0) while (i > 0)
@ -2225,14 +2218,12 @@ struct foreach_walker_t
int ret; int ret;
}; };
static qse_htb_walk_t walk_foreach ( static qse_htb_walk_t walk_foreach (qse_htb_t* map, qse_htb_pair_t* pair, void* arg)
qse_htb_t* map, qse_htb_pair_t* pair, void* arg)
{ {
struct foreach_walker_t* w = (struct foreach_walker_t*)arg; struct foreach_walker_t* w = (struct foreach_walker_t*)arg;
qse_awk_val_t* str; qse_awk_val_t* str;
str = (qse_awk_val_t*) qse_awk_rtx_makestrval ( str = (qse_awk_val_t*)qse_awk_rtx_makestrval(w->rtx, QSE_HTB_KPTR(pair), QSE_HTB_KLEN(pair));
w->rtx, QSE_HTB_KPTR(pair), QSE_HTB_KLEN(pair));
if (str == QSE_NULL) if (str == QSE_NULL)
{ {
ADJERR_LOC (w->rtx, &w->var->loc); ADJERR_LOC (w->rtx, &w->var->loc);
@ -2241,14 +2232,14 @@ static qse_htb_walk_t walk_foreach (
} }
qse_awk_rtx_refupval (w->rtx, str); qse_awk_rtx_refupval (w->rtx, str);
if (do_assignment (w->rtx, w->var, str) == QSE_NULL) if (do_assignment(w->rtx, w->var, str) == QSE_NULL)
{ {
qse_awk_rtx_refdownval (w->rtx, str); qse_awk_rtx_refdownval (w->rtx, str);
w->ret = -1; w->ret = -1;
return QSE_HTB_WALK_STOP; return QSE_HTB_WALK_STOP;
} }
if (run_statement (w->rtx, w->body) == -1) if (run_statement(w->rtx, w->body) == -1)
{ {
qse_awk_rtx_refdownval (w->rtx, str); qse_awk_rtx_refdownval (w->rtx, str);
w->ret = -1; w->ret = -1;
@ -2283,19 +2274,17 @@ static int run_foreach (qse_awk_rtx_t* rtx, qse_awk_nde_foreach_t* nde)
qse_awk_val_type_t rvtype; qse_awk_val_type_t rvtype;
test = (qse_awk_nde_exp_t*)nde->test; test = (qse_awk_nde_exp_t*)nde->test;
QSE_ASSERT ( QSE_ASSERT (test->type == QSE_AWK_NDE_EXP_BIN && test->opcode == QSE_AWK_BINOP_IN);
test->type == QSE_AWK_NDE_EXP_BIN &&
test->opcode == QSE_AWK_BINOP_IN);
/* chained expressions should not be allowed /* chained expressions should not be allowed
* by the parser first of all */ * by the parser first of all */
QSE_ASSERT (test->right->next == QSE_NULL); QSE_ASSERT (test->right->next == QSE_NULL);
rv = eval_expression (rtx, test->right); rv = eval_expression(rtx, test->right);
if (rv == QSE_NULL) return -1; if (rv == QSE_NULL) return -1;
qse_awk_rtx_refupval (rtx, rv); qse_awk_rtx_refupval (rtx, rv);
rvtype = QSE_AWK_RTX_GETVALTYPE (rtx, rv); rvtype = QSE_AWK_RTX_GETVALTYPE(rtx, rv);
if (rvtype == QSE_AWK_VAL_NIL) if (rvtype == QSE_AWK_VAL_NIL)
{ {
/* just return without excuting the loop body */ /* just return without excuting the loop body */
@ -3256,7 +3245,7 @@ static qse_awk_val_t* eval_expression0 (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
eval_incpst, eval_incpst,
eval_cnd, eval_cnd,
eval_fncall_fnc, eval_fncall_fnc,
eval_fncall_fncall_fun, eval_fncall_fun,
eval_fncall_var, eval_fncall_var,
eval_int, eval_int,
eval_flt, eval_flt,
@ -3424,7 +3413,7 @@ static qse_awk_val_t* do_assignment (qse_awk_rtx_t* rtx, qse_awk_nde_t* var, qse
case QSE_AWK_NDE_GBL: case QSE_AWK_NDE_GBL:
case QSE_AWK_NDE_LCL: case QSE_AWK_NDE_LCL:
case QSE_AWK_NDE_ARG: case QSE_AWK_NDE_ARG:
ret = do_assignment_nonidx (rtx, (qse_awk_nde_var_t*)var, val); ret = do_assignment_nonidx(rtx, (qse_awk_nde_var_t*)var, val);
break; break;
case QSE_AWK_NDE_NAMEDIDX: case QSE_AWK_NDE_NAMEDIDX:
@ -3438,7 +3427,7 @@ static qse_awk_val_t* do_assignment (qse_awk_rtx_t* rtx, qse_awk_nde_t* var, qse
goto exit_on_error; goto exit_on_error;
} }
ret = do_assignment_idx (rtx, (qse_awk_nde_var_t*)var, val); ret = do_assignment_idx(rtx, (qse_awk_nde_var_t*)var, val);
break; break;
case QSE_AWK_NDE_POS: case QSE_AWK_NDE_POS:
@ -3449,7 +3438,7 @@ static qse_awk_val_t* do_assignment (qse_awk_rtx_t* rtx, qse_awk_nde_t* var, qse
goto exit_on_error; goto exit_on_error;
} }
ret = do_assignment_pos (rtx, (qse_awk_nde_pos_t*)var, val); ret = do_assignment_pos(rtx, (qse_awk_nde_pos_t*)var, val);
break; break;
default: default:
@ -3506,9 +3495,7 @@ static qse_awk_val_t* do_assignment_nonidx (qse_awk_rtx_t* run, qse_awk_nde_var_
} }
} }
if (qse_htb_upsert (run->named, var->id.name.ptr, var->id.name.len, val, 0) == QSE_NULL)
if (qse_htb_upsert (run->named,
var->id.name.ptr, var->id.name.len, val, 0) == QSE_NULL)
{ {
SETERR_LOC (run, QSE_AWK_ENOMEM, &var->loc); SETERR_LOC (run, QSE_AWK_ENOMEM, &var->loc);
return QSE_NULL; return QSE_NULL;
@ -5748,24 +5735,31 @@ static qse_awk_val_t* eval_cnd (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
return v; return v;
} }
static qse_awk_val_t* eval_fncall_fnc (qse_awk_rtx_t* run, qse_awk_nde_t* nde) static qse_awk_val_t* eval_fncall_fnc (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde)
{ {
/* intrinsic function */ /* intrinsic function */
qse_awk_nde_fncall_t* call = (qse_awk_nde_fncall_t*)nde; qse_awk_nde_fncall_t* call = (qse_awk_nde_fncall_t*)nde;
/* the parser must make sure taht the number of arguments /* the parser must make sure that the number of arguments is proper */
* is proper */
QSE_ASSERT (call->nargs >= call->u.fnc.spec.arg.min && call->nargs <= call->u.fnc.spec.arg.max); QSE_ASSERT (call->nargs >= call->u.fnc.spec.arg.min && call->nargs <= call->u.fnc.spec.arg.max);
return eval_call(run, nde, call->u.fnc.spec.arg.spec, QSE_NULL, QSE_NULL, QSE_NULL); return __eval_call(rtx, nde, QSE_NULL, push_arg_from_nde, (void*)call->u.fnc.spec.arg.spec, QSE_NULL, QSE_NULL);
} }
static QSE_INLINE qse_awk_val_t* eval_fncall_fncall_fun_ex (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde, void(*errhandler)(void*), void* eharg) static QSE_INLINE qse_awk_val_t* eval_fncall_fun_ex (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde, void(*errhandler)(void*), void* eharg)
{ {
qse_awk_nde_fncall_t* call = (qse_awk_nde_fncall_t*)nde; qse_awk_nde_fncall_t* call = (qse_awk_nde_fncall_t*)nde;
qse_awk_fun_t* fun; qse_awk_fun_t* fun;
qse_htb_pair_t* pair; qse_htb_pair_t* pair;
if (!call->u.fun.fun)
{
/* there can be multiple runtime instances for a single awk object.
* changing the parse tree from one runtime instance can affect
* other instances. however i do change the parse tree without protection
* hoping that the pointer assignment is atomic. (call->u.fun.fun = fun).
* i don't mind each instance performs a search duplicately for a short while */
pair = qse_htb_search(rtx->awk->tree.funs, call->u.fun.name.ptr, call->u.fun.name.len); pair = qse_htb_search(rtx->awk->tree.funs, call->u.fun.name.ptr, call->u.fun.name.len);
if (pair == QSE_NULL) if (!pair)
{ {
SETERR_ARGX_LOC (rtx, QSE_AWK_EFUNNF, &call->u.fun.name, &nde->loc); SETERR_ARGX_LOC (rtx, QSE_AWK_EFUNNF, &call->u.fun.name, &nde->loc);
return QSE_NULL; return QSE_NULL;
@ -5774,6 +5768,15 @@ static QSE_INLINE qse_awk_val_t* eval_fncall_fncall_fun_ex (qse_awk_rtx_t* rtx,
fun = (qse_awk_fun_t*)QSE_HTB_VPTR(pair); fun = (qse_awk_fun_t*)QSE_HTB_VPTR(pair);
QSE_ASSERT (fun != QSE_NULL); QSE_ASSERT (fun != QSE_NULL);
/* cache the search result */
call->u.fun.fun = fun;
}
else
{
/* use the cached function */
fun = call->u.fun.fun;
}
if (call->nargs > fun->nargs) if (call->nargs > fun->nargs)
{ {
/* TODO: is this correct? what if i want to /* TODO: is this correct? what if i want to
@ -5782,12 +5785,12 @@ static QSE_INLINE qse_awk_val_t* eval_fncall_fncall_fun_ex (qse_awk_rtx_t* rtx,
return QSE_NULL; return QSE_NULL;
} }
return eval_call(rtx, nde, QSE_NULL, fun, errhandler, eharg); return __eval_call(rtx, nde, fun, push_arg_from_nde, QSE_NULL, errhandler, eharg);
} }
static qse_awk_val_t* eval_fncall_fncall_fun (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde) static qse_awk_val_t* eval_fncall_fun (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde)
{ {
return eval_fncall_fncall_fun_ex(rtx, nde, QSE_NULL, QSE_NULL); return eval_fncall_fun_ex(rtx, nde, QSE_NULL, QSE_NULL);
} }
static qse_awk_val_t* eval_fncall_var (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde) static qse_awk_val_t* eval_fncall_var (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde)
@ -5806,7 +5809,8 @@ static qse_awk_val_t* eval_fncall_var (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde)
} }
else else
{ {
rv = eval_call(rtx, nde, QSE_NULL, ((qse_awk_val_fun_t*)fv)->fun, QSE_NULL, QSE_NULL); qse_awk_fun_t* fun = ((qse_awk_val_fun_t*)fv)->fun;
rv = __eval_call(rtx, nde, fun, push_arg_from_nde, QSE_NULL, QSE_NULL, QSE_NULL);
} }
qse_awk_rtx_refdownval (rtx, fv); qse_awk_rtx_refdownval (rtx, fv);
@ -5841,14 +5845,9 @@ static qse_awk_val_t* eval_fncall_var (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde)
} while (0) } while (0)
static qse_awk_val_t* __eval_call ( static qse_awk_val_t* __eval_call (
qse_awk_rtx_t* run, qse_awk_rtx_t* rtx, qse_awk_nde_t* nde, qse_awk_fun_t* fun,
qse_awk_nde_t* nde, qse_size_t(*argpusher)(qse_awk_rtx_t*,qse_awk_nde_fncall_t*,void*), void* apdata,
const qse_char_t* fnc_arg_spec, void(*errhandler)(void*), void* eharg)
qse_awk_fun_t* fun,
qse_size_t(*argpusher)(qse_awk_rtx_t*,qse_awk_nde_fncall_t*,void*),
void* apdata,
void(*errhandler)(void*),
void* eharg)
{ {
qse_awk_nde_fncall_t* call = (qse_awk_nde_fncall_t*)nde; qse_awk_nde_fncall_t* call = (qse_awk_nde_fncall_t*)nde;
qse_size_t saved_stack_top; qse_size_t saved_stack_top;
@ -5896,68 +5895,67 @@ static qse_awk_val_t* __eval_call (
* --------------------- * ---------------------
*/ */
QSE_ASSERT (QSE_SIZEOF(void*) >= QSE_SIZEOF(run->stack_top)); QSE_ASSERT (QSE_SIZEOF(void*) >= QSE_SIZEOF(rtx->stack_top));
QSE_ASSERT (QSE_SIZEOF(void*) >= QSE_SIZEOF(run->stack_base)); QSE_ASSERT (QSE_SIZEOF(void*) >= QSE_SIZEOF(rtx->stack_base));
saved_stack_top = run->stack_top; saved_stack_top = rtx->stack_top;
#ifdef DEBUG_RUN #ifdef DEBUG_RUN
qse_errputstrf (QSE_T("setting up function stack frame top=%zd base=%zd\n"), qse_errputstrf (QSE_T("setting up function stack frame top=%zd base=%zd\n"), (qse_size_t)rtx->stack_top, (qse_size_t)rtx->stack_base);
(qse_size_t)run->stack_top, (qse_size_t)run->stack_base);
#endif #endif
if (__raw_push(run,(void*)run->stack_base) == -1) if (__raw_push(rtx,(void*)rtx->stack_base) == -1)
{ {
SETERR_LOC (run, QSE_AWK_ENOMEM, &nde->loc); SETERR_LOC (rtx, QSE_AWK_ENOMEM, &nde->loc);
return QSE_NULL; return QSE_NULL;
} }
if (__raw_push(run,(void*)saved_stack_top) == -1) if (__raw_push(rtx,(void*)saved_stack_top) == -1)
{ {
__raw_pop (run); __raw_pop (rtx);
SETERR_LOC (run, QSE_AWK_ENOMEM, &nde->loc); SETERR_LOC (rtx, QSE_AWK_ENOMEM, &nde->loc);
return QSE_NULL; return QSE_NULL;
} }
/* secure space for a return value. */ /* secure space for a return value. */
if (__raw_push(run,qse_awk_val_nil) == -1) if (__raw_push(rtx,qse_awk_val_nil) == -1)
{ {
__raw_pop (run); __raw_pop (rtx);
__raw_pop (run); __raw_pop (rtx);
SETERR_LOC (run, QSE_AWK_ENOMEM, &nde->loc); SETERR_LOC (rtx, QSE_AWK_ENOMEM, &nde->loc);
return QSE_NULL; return QSE_NULL;
} }
/* secure space for nargs */ /* secure space for nargs */
if (__raw_push(run,qse_awk_val_nil) == -1) if (__raw_push(rtx,qse_awk_val_nil) == -1)
{ {
__raw_pop (run); __raw_pop (rtx);
__raw_pop (run); __raw_pop (rtx);
__raw_pop (run); __raw_pop (rtx);
SETERR_LOC (run, QSE_AWK_ENOMEM, &nde->loc); SETERR_LOC (rtx, QSE_AWK_ENOMEM, &nde->loc);
return QSE_NULL; return QSE_NULL;
} }
/* push all arguments onto the stack */ /* push all arguments onto the stack */
nargs = argpusher(run, call, apdata); nargs = argpusher(rtx, call, apdata);
if (nargs == (qse_size_t)-1) if (nargs == (qse_size_t)-1)
{ {
UNWIND_RTX_STACK_BASE (run); UNWIND_RTX_STACK_BASE (rtx);
return QSE_NULL; return QSE_NULL;
} }
QSE_ASSERT (nargs == call->nargs); QSE_ASSERT (nargs == call->nargs);
if (fun != QSE_NULL) if (fun)
{ {
/* extra step for normal awk functions */ /* extra step for normal awk functions */
while (nargs < fun->nargs) while (nargs < fun->nargs)
{ {
/* push as many nils as the number of missing actual arguments */ /* push as many nils as the number of missing actual arguments */
if (__raw_push(run,qse_awk_val_nil) == -1) if (__raw_push(rtx,qse_awk_val_nil) == -1)
{ {
UNWIND_RTX_STACK (run, nargs); UNWIND_RTX_STACK (rtx, nargs);
SETERR_LOC (run, QSE_AWK_ENOMEM, &nde->loc); SETERR_LOC (rtx, QSE_AWK_ENOMEM, &nde->loc);
return QSE_NULL; return QSE_NULL;
} }
@ -5965,18 +5963,18 @@ static qse_awk_val_t* __eval_call (
} }
} }
run->stack_base = saved_stack_top; rtx->stack_base = saved_stack_top;
RTX_STACK_NARGS(run) = (void*)nargs; RTX_STACK_NARGS(rtx) = (void*)nargs;
#ifdef DEBUG_RUN #ifdef DEBUG_RUN
qse_errputstrf (QSE_T("running function body\n")); qse_errputstrf (QSE_T("rtxning function body\n"));
#endif #endif
if (fun != QSE_NULL) if (fun)
{ {
/* normal awk function */ /* normal awk function */
QSE_ASSERT (fun->body->type == QSE_AWK_NDE_BLK); QSE_ASSERT (fun->body->type == QSE_AWK_NDE_BLK);
n = run_block(run,(qse_awk_nde_blk_t*)fun->body); n = run_block(rtx,(qse_awk_nde_blk_t*)fun->body);
} }
else else
{ {
@ -5989,24 +5987,24 @@ static qse_awk_val_t* __eval_call (
if (call->u.fnc.spec.impl) if (call->u.fnc.spec.impl)
{ {
run->errinf.num = QSE_AWK_ENOERR; rtx->errinf.num = QSE_AWK_ENOERR;
n = call->u.fnc.spec.impl(run, &call->u.fnc.info); n = call->u.fnc.spec.impl(rtx, &call->u.fnc.info);
if (n <= -1) if (n <= -1)
{ {
if (run->errinf.num == QSE_AWK_ENOERR) if (rtx->errinf.num == QSE_AWK_ENOERR)
{ {
/* the handler has not set the error. /* the handler has not set the error.
* fix it */ * fix it */
SETERR_ARGX_LOC ( SETERR_ARGX_LOC (
run, QSE_AWK_EFNCIMPL, rtx, QSE_AWK_EFNCIMPL,
&call->u.fnc.info.name, &nde->loc &call->u.fnc.info.name, &nde->loc
); );
} }
else else
{ {
ADJERR_LOC (run, &nde->loc); ADJERR_LOC (rtx, &nde->loc);
} }
/* correct the return code just in case */ /* correct the return code just in case */
@ -6015,43 +6013,76 @@ static qse_awk_val_t* __eval_call (
} }
} }
/* refdown args in the run.stack */ /* refdown args in the rtx.stack */
nargs = (qse_size_t)RTX_STACK_NARGS(run); nargs = (qse_size_t)RTX_STACK_NARGS(rtx);
#ifdef DEBUG_RUN #ifdef DEBUG_RUN
qse_errputstrf (QSE_T("block run complete nargs = %d\n"), (int)nargs); qse_errputstrf (QSE_T("block rtx complete nargs = %d\n"), (int)nargs);
#endif #endif
if (fun && fun->argspec)
{
/* set back the values for call-by-reference parameters of normal functions.
* the intrinsic functions are not handled here but their implementation would
* call qse_awk_rtx_setrefval() */
qse_awk_nde_t* p;
p = call->args;
for (i = 0; i < nargs; i++) for (i = 0; i < nargs; i++)
{ {
qse_awk_rtx_refdownval (run, RTX_STACK_ARG(run,i)); if (fun->argspec[i] == QSE_T('r'))
{
/* TODO: change this part.. */
qse_awk_val_t** ref;
qse_awk_val_ref_t* refv;
/* TODO: ERROR CHECK. no extra memory set */
get_reference (rtx, p, &ref);
refv = qse_awk_rtx_makerefval(rtx, p->type - QSE_AWK_NDE_NAMED, ref);
qse_awk_rtx_refupval (rtx, refv);
qse_awk_rtx_setrefval (rtx, refv, RTX_STACK_ARG(rtx, i));
qse_awk_rtx_refdownval (rtx, refv);
}
qse_awk_rtx_refdownval (rtx, RTX_STACK_ARG(rtx,i));
p = p->next;
}
}
else
{
for (i = 0; i < nargs; i++)
{
qse_awk_rtx_refdownval (rtx, RTX_STACK_ARG(rtx,i));
}
} }
#ifdef DEBUG_RUN #ifdef DEBUG_RUN
qse_errputstrf (QSE_T("got return value\n")); qse_errputstrf (QSE_T("got return value\n"));
#endif #endif
v = RTX_STACK_RETVAL(run); v = RTX_STACK_RETVAL(rtx);
if (n == -1) if (n == -1)
{ {
if (run->errinf.num == QSE_AWK_ENOERR && errhandler != QSE_NULL) if (rtx->errinf.num == QSE_AWK_ENOERR && errhandler != QSE_NULL)
{ {
/* errhandler is passed only when __eval_call() is /* errhandler is passed only when __eval_call() is
* invoked from qse_awk_rtx_call(). Under this * invoked from qse_awk_rtx_call(). Under this
* circumstance, this stack frame is the first * circumstance, this stack frame is the first
* activated and the stack base is the first element * activated and the stack base is the first element
* after the global variables. so RTX_STACK_RETVAL(run) * after the global variables. so RTX_STACK_RETVAL(rtx)
* effectively becomes RTX_STACK_RETVAL_GBL(run). * effectively becomes RTX_STACK_RETVAL_GBL(rtx).
* As __eval_call() returns QSE_NULL on error and * As __eval_call() returns QSE_NULL on error and
* the reference count of RTX_STACK_RETVAL(run) should be * the reference count of RTX_STACK_RETVAL(rtx) should be
* decremented, it can't get the return value * decremented, it can't get the return value
* if it turns out to be terminated by exit(). * if it turns out to be terminated by exit().
* The return value could be destroyed by then. * The return value could be destroyed by then.
* Unlikely, run_bpae_loop() just checks if run->errinf.num * Unlikely, rtx_bpae_loop() just checks if rtx->errinf.num
* is QSE_AWK_ENOERR and gets RTX_STACK_RETVAL_GBL(run) * is QSE_AWK_ENOERR and gets RTX_STACK_RETVAL_GBL(rtx)
* to determine if it is terminated by exit(). * to determine if it is terminated by exit().
* *
* The handler capture_retval_on_exit() * The handler capture_retval_on_exit()
* increments the reference of RTX_STACK_RETVAL(run) * increments the reference of RTX_STACK_RETVAL(rtx)
* and stores the pointer into accompanying space. * and stores the pointer into accompanying space.
* This way, the return value is preserved upon * This way, the return value is preserved upon
* termination by exit() out to the caller. * termination by exit() out to the caller.
@ -6062,28 +6093,27 @@ static qse_awk_val_t* __eval_call (
/* if the earlier operations failed and this function /* if the earlier operations failed and this function
* has to return a error, the return value is just * has to return a error, the return value is just
* destroyed and replaced by nil */ * destroyed and replaced by nil */
qse_awk_rtx_refdownval (run, v); qse_awk_rtx_refdownval (rtx, v);
RTX_STACK_RETVAL(run) = qse_awk_val_nil; RTX_STACK_RETVAL(rtx) = qse_awk_val_nil;
} }
else else
{ {
/* this trick has been mentioned in run_return. /* this trick has been mentioned in rtx_return.
* adjust the reference count of the return value. * adjust the reference count of the return value.
* the value must not be freed even if the reference count * the value must not be freed even if the reference count
* reached zero because its reference has been incremented * reached zero because its reference has been incremented
* in run_return or directly by qse_awk_rtx_setretval() * in rtx_return or directly by qse_awk_rtx_setretval()
* regardless of its reference count. */ * regardless of its reference count. */
qse_awk_rtx_refdownval_nofree (run, v); qse_awk_rtx_refdownval_nofree (rtx, v);
} }
run->stack_top = (qse_size_t)run->stack[run->stack_base+1]; rtx->stack_top = (qse_size_t)rtx->stack[rtx->stack_base+1];
run->stack_base = (qse_size_t)run->stack[run->stack_base+0]; rtx->stack_base = (qse_size_t)rtx->stack[rtx->stack_base+0];
if (run->exit_level == EXIT_FUNCTION) run->exit_level = EXIT_NONE; if (rtx->exit_level == EXIT_FUNCTION) rtx->exit_level = EXIT_NONE;
#ifdef DEBUG_RUN #ifdef DEBUG_RUN
qse_errputstrf (QSE_T("returning from function top=%zd, base=%zd\n"), qse_errputstrf (QSE_T("returning from function top=%zd, base=%zd\n"), (qse_size_t)rtx->stack_top, (qse_size_t)rtx->stack_base);
(qse_size_t)run->stack_top, (qse_size_t)run->stack_base);
#endif #endif
return (n == -1)? QSE_NULL: v; return (n == -1)? QSE_NULL: v;
} }
@ -6125,27 +6155,20 @@ static qse_size_t push_arg_from_nde (qse_awk_rtx_t* rtx, qse_awk_nde_fncall_t* c
for (p = call->args, nargs = 0; p != QSE_NULL; p = p->next, nargs++) for (p = call->args, nargs = 0; p != QSE_NULL; p = p->next, nargs++)
{ {
QSE_ASSERT ( /* if fnc_arg_spec is to be provided, it must contain as many characters as nargs */
fnc_arg_spec == QSE_NULL ||
(fnc_arg_spec != QSE_NULL &&
qse_strlen(fnc_arg_spec) > nargs));
if (fnc_arg_spec && if (fnc_arg_spec && (fnc_arg_spec[nargs] == QSE_T('r') || fnc_arg_spec[0] == QSE_T('R')))
(fnc_arg_spec[nargs] == QSE_T('r') ||
fnc_arg_spec[0] == QSE_T('R')))
{ {
qse_awk_val_t** ref; qse_awk_val_t** ref;
if (get_reference (rtx, p, &ref) == -1) if (get_reference(rtx, p, &ref) == -1)
{ {
UNWIND_RTX_STACK_ARG (rtx, nargs); UNWIND_RTX_STACK_ARG (rtx, nargs);
return (qse_size_t)-1; return (qse_size_t)-1;
} }
/* p->type-QSE_AWK_NDE_NAMED assumes that the /* 'p->type - QSE_AWK_NDE_NAMED' must produce a relevant QSE_AWK_VAL_REF_XXX value. */
* derived value matches QSE_AWK_VAL_REF_XXX */ v = qse_awk_rtx_makerefval(rtx, p->type - QSE_AWK_NDE_NAMED, ref);
v = qse_awk_rtx_makerefval (
rtx, p->type-QSE_AWK_NDE_NAMED, ref);
} }
else if (fnc_arg_spec && fnc_arg_spec[nargs] == QSE_T('x')) else if (fnc_arg_spec && fnc_arg_spec[nargs] == QSE_T('x'))
{ {
@ -6185,11 +6208,6 @@ static qse_size_t push_arg_from_nde (qse_awk_rtx_t* rtx, qse_awk_nde_fncall_t* c
return nargs; return nargs;
} }
static qse_awk_val_t* eval_call (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde, const qse_char_t* fnc_arg_spec, qse_awk_fun_t* fun, void(*errhandler)(void*), void* eharg)
{
return __eval_call(rtx, nde, fnc_arg_spec, fun, push_arg_from_nde, (void*)fnc_arg_spec, errhandler, eharg);
}
static int get_reference (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde, qse_awk_val_t*** ref) static int get_reference (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde, qse_awk_val_t*** ref)
{ {
qse_awk_nde_var_t* tgt = (qse_awk_nde_var_t*)nde; qse_awk_nde_var_t* tgt = (qse_awk_nde_var_t*)nde;

View File

@ -206,6 +206,7 @@ struct qse_awk_nde_fncall_t
struct struct
{ {
qse_cstr_t name; qse_cstr_t name;
qse_awk_fun_t* fun; /* cache it */
} fun; } fun;
/* minimum information of a intrinsic function /* minimum information of a intrinsic function

View File

@ -700,7 +700,7 @@ reswitch:
const qse_wchar_t* usp; const qse_wchar_t* usp;
qse_size_t uwid; qse_size_t uwid;
if (flagc & FLAGC_ZEROPAD) padc = ' '; if (flagc & FLAGC_ZEROPAD) padc = T(' ');
usp = va_arg(ap, qse_wchar_t*); usp = va_arg(ap, qse_wchar_t*);
if (flagc & FLAGC_DOT) if (flagc & FLAGC_DOT)