have implemented the function-pointer-as-value feature experimentally

This commit is contained in:
hyung-hwan 2019-04-29 09:40:13 +00:00
parent d64d0a73b4
commit 3368c91834
8 changed files with 248 additions and 149 deletions

View File

@ -367,14 +367,15 @@ enum qse_awk_nde_type_t
QSE_AWK_NDE_EXP_INCPRE,
QSE_AWK_NDE_EXP_INCPST,
QSE_AWK_NDE_CND,
QSE_AWK_NDE_FNC,
QSE_AWK_NDE_FUN,
QSE_AWK_NDE_FCV,
QSE_AWK_NDE_FNCALL_FNC,
QSE_AWK_NDE_FNCALL_FUN,
QSE_AWK_NDE_FNCALL_VAR,
QSE_AWK_NDE_INT,
QSE_AWK_NDE_FLT,
QSE_AWK_NDE_STR,
QSE_AWK_NDE_MBS,
QSE_AWK_NDE_REX,
QSE_AWK_NDE_FUN,
/* keep this order for the following items otherwise, you may have
* to change eval_incpre and eval_incpst in run.c as well as
@ -1276,6 +1277,7 @@ enum qse_awk_errnum_t
QSE_AWK_EARGTF, /**< too few arguments */
QSE_AWK_EARGTM, /**< too many arguments */
QSE_AWK_EFUNNF, /**< function '${0}' not found */
QSE_AWK_ENOTFUN, /**< non-function value in '%{0}' */
QSE_AWK_ENOTDEL, /**< '${0}' not deletable */
QSE_AWK_ENOTMAP, /**< value not a map */
QSE_AWK_ENOTMAPIN, /**< right-hand side of 'in' not a map */

View File

@ -54,6 +54,22 @@ typedef struct qse_awk_tree_t qse_awk_tree_t;
#define FEATURE_SCACHE_BLOCK_UNIT 16
#define FEATURE_SCACHE_BLOCK_SIZE 128
/* [NOTE] the function value support implemented is very limited.
* it supports very primitive way to call a function via a variable.
* only user-defined functions are supported. neither builtin functions
* nor module functions are not supported yet.
* -----------------------------------------------------
* function x(a,b,c) { print a, b, c; }
* BEGIN { q = x; q(1, 2, 3); } # this works
* BEGIN { q[1]=x; q[1](1,2,3); } # this doesn't work. same as q[1] %% (1, 2, 3) or q[1] %% 3
* BEGIN { q[1]=x; y=q[1]; y(1,2,3); } # this works.
* -----------------------------------------------------
* function __printer(a,b,c) { print a, b, c; }
* function show(printer, a,b,c) { printer(a, b, c); }
* BEGIN { show(__printer, 10, 20, 30); } ## passing the function value as an argumnet is ok.
*/
#define ENABLE_FEATURE_FUN_AS_VALUE
#define QSE_AWK_MAX_GBLS 9999
#define QSE_AWK_MAX_LCLS 9999
#define QSE_AWK_MAX_PARAMS 9999

View File

@ -119,6 +119,7 @@ const qse_char_t* qse_awk_dflerrstr (const qse_awk_t* awk, qse_awk_errnum_t errn
QSE_T("too few arguments"),
QSE_T("too many arguments"),
QSE_T("function '${0}' not found"),
QSE_T("non-function value in '${0}'"),
QSE_T("'${0}' not deletable"),
QSE_T("value not a map"),
QSE_T("right-hand side of the 'in' operator not a map"),

View File

@ -96,7 +96,7 @@ enum tok_t
TOK_LS,
TOK_IN,
TOK_EXP,
TOK_CONCAT,
TOK_CONCAT, /* %% */
TOK_LPAREN,
TOK_RPAREN,
@ -111,7 +111,7 @@ enum tok_t
TOK_COLON,
TOK_DBLCOLON,
TOK_QUEST,
TOK_DBLAT,
/*TOK_DBLAT,*/
/* == begin reserved words == */
/* === extended reserved words === */
@ -223,7 +223,7 @@ static qse_awk_nde_t* parse_primary_ident (qse_awk_t* awk, const qse_awk_loc_t*
static qse_awk_nde_t* parse_hashidx (qse_awk_t* awk, const qse_cstr_t* name, const qse_awk_loc_t* xloc);
#define FNCALL_FLAG_NOARG (1 << 0) /* no argument */
#define FNCALL_FLAG_FCV (1 << 1)
#define FNCALL_FLAG_VAR (1 << 1)
static qse_awk_nde_t* parse_fncall (qse_awk_t* awk, const qse_cstr_t* name, qse_awk_fnc_t* fnc, const qse_awk_loc_t* xloc, int flags);
static qse_awk_nde_t* parse_primary_ident_segs (qse_awk_t* awk, const qse_awk_loc_t* xloc, const qse_cstr_t* full, const qse_cstr_t segs[], int nsegs);
@ -1117,17 +1117,17 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
}
/* duplicate the name before it's overridden by get_token() */
name.ptr = qse_strxdup (name.ptr, name.len, awk->mmgr);
name.ptr = qse_awk_strxdup(awk, name.ptr, name.len);
if (name.ptr == QSE_NULL)
{
SETERR_LOC (awk, QSE_AWK_ENOMEM, &awk->tok.loc);
ADJERR_LOC (awk, &awk->tok.loc);
return QSE_NULL;
}
/* get the next token */
if (get_token(awk) <= -1)
{
QSE_AWK_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
return QSE_NULL;
}
@ -1136,14 +1136,14 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
{
/* a function name is not followed by a left parenthesis */
SETERR_TOK (awk, QSE_AWK_ELPAREN);
QSE_AWK_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
return QSE_NULL;
}
/* get the next token */
if (get_token(awk) <= -1)
{
QSE_AWK_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
return QSE_NULL;
}
@ -1156,7 +1156,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
/* no function parameter found. get the next token */
if (get_token(awk) <= -1)
{
QSE_AWK_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
return QSE_NULL;
}
}
@ -1169,7 +1169,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
if (!MATCH(awk,TOK_IDENT))
{
QSE_AWK_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
SETERR_TOK (awk, QSE_AWK_EBADPAR);
return QSE_NULL;
@ -1192,7 +1192,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
qse_strxncmp (pa, pal, name.ptr, name.len) == 0) ||
qse_arr_search (awk->parse.params, 0, pa, pal) != QSE_ARR_NIL)
{
QSE_AWK_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
SETERR_ARG_LOC (
awk, QSE_AWK_EDUPPAR,
@ -1203,18 +1203,15 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
/* push the parameter to the parameter list */
if (QSE_ARR_SIZE(awk->parse.params) >= QSE_AWK_MAX_PARAMS)
{
QSE_AWK_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
SETERR_LOC (awk, QSE_AWK_EPARTM, &awk->tok.loc);
return QSE_NULL;
}
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_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
SETERR_LOC (awk, QSE_AWK_ENOMEM, &awk->tok.loc);
return QSE_NULL;
@ -1222,7 +1219,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
if (get_token (awk) <= -1)
{
QSE_AWK_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
return QSE_NULL;
}
@ -1231,7 +1228,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
if (!MATCH(awk,TOK_COMMA))
{
QSE_AWK_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
SETERR_TOK (awk, QSE_AWK_ECOMMA);
return QSE_NULL;
@ -1241,7 +1238,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
{
if (get_token(awk) <= -1)
{
QSE_AWK_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
return QSE_NULL;
}
@ -1251,7 +1248,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
if (get_token(awk) <= -1)
{
QSE_AWK_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
return QSE_NULL;
}
@ -1265,7 +1262,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
{
if (get_token(awk) <= -1)
{
QSE_AWK_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
return QSE_NULL;
}
@ -1274,15 +1271,14 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
/* check if the function body starts with a left brace */
if (!MATCH(awk,TOK_LBRACE))
{
QSE_AWK_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
SETERR_TOK (awk, QSE_AWK_ELBRACE);
return QSE_NULL;
}
if (get_token(awk) <= -1)
{
QSE_AWK_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
return QSE_NULL;
}
@ -1302,7 +1298,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
if (body == QSE_NULL)
{
QSE_AWK_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params);
return QSE_NULL;
}
@ -1316,7 +1312,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
fun = (qse_awk_fun_t*)qse_awk_callocmem(awk, QSE_SIZEOF(*fun));
if (fun == QSE_NULL)
{
QSE_AWK_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
qse_awk_clrpt (awk, body);
ADJERR_LOC (awk, &awk->tok.loc);
return QSE_NULL;
@ -1333,9 +1329,9 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
/* if qse_htb_insert() fails for other reasons than memory
* shortage, there should be implementaion errors as duplicate
* functions are detected earlier in this function */
QSE_AWK_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
qse_awk_clrpt (awk, body);
QSE_AWK_FREE (awk, fun);
qse_awk_freemem (awk, fun);
SETERR_LOC (awk, QSE_AWK_ENOMEM, &awk->tok.loc);
return QSE_NULL;
}
@ -1344,7 +1340,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
* of the pair */
fun->name.ptr = QSE_HTB_KPTR(pair);
fun->name.len = QSE_HTB_KLEN(pair);
QSE_AWK_FREE (awk, name.ptr);
qse_awk_freemem (awk, name.ptr);
/* remove an undefined function call entry from the parse.fun table */
qse_htb_delete (awk->parse.funs, fun->name.ptr, name.len);
@ -1419,12 +1415,11 @@ static qse_awk_chain_t* parse_action_block (
if (nde == QSE_NULL) return QSE_NULL;
}
chain = (qse_awk_chain_t*)
QSE_AWK_ALLOC (awk, QSE_SIZEOF(qse_awk_chain_t));
chain = (qse_awk_chain_t*)qse_awk_callocmem(awk, QSE_SIZEOF(*chain));
if (chain == QSE_NULL)
{
qse_awk_clrpt (awk, nde);
SETERR_LOC (awk, QSE_AWK_ENOMEM, &xloc);
ADJERR_LOC (awk, &xloc);
return QSE_NULL;
}
@ -3052,8 +3047,7 @@ static qse_awk_nde_t* parse_statement_nb (
return nde;
}
static qse_awk_nde_t* parse_statement (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_statement (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
qse_awk_nde_t* nde;
@ -3066,11 +3060,10 @@ static qse_awk_nde_t* parse_statement (
if (MATCH(awk,TOK_SEMICOLON))
{
/* null statement */
nde = (qse_awk_nde_t*)
QSE_AWK_ALLOC (awk, QSE_SIZEOF(qse_awk_nde_t));
if (nde == QSE_NULL)
nde = (qse_awk_nde_t*)qse_awk_callocmem(awk, QSE_SIZEOF(*nde));
if (!nde)
{
SETERR_LOC (awk, QSE_AWK_ENOMEM, xloc);
ADJERR_LOC (awk, xloc);
return QSE_NULL;
}
@ -3080,7 +3073,7 @@ static qse_awk_nde_t* parse_statement (
if (get_token(awk) <= -1)
{
QSE_AWK_FREE (awk, nde);
qse_awk_freemem (awk, nde);
return QSE_NULL;
}
}
@ -3150,8 +3143,7 @@ static int assign_to_opcode (qse_awk_t* awk)
return -1;
}
static qse_awk_nde_t* parse_expr_basic (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_expr_basic (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
qse_awk_nde_t* nde, * n1, * n2;
@ -3201,14 +3193,13 @@ static qse_awk_nde_t* parse_expr_basic (
return QSE_NULL;
}
cnd = (qse_awk_nde_cnd_t*) QSE_AWK_ALLOC (
awk, QSE_SIZEOF(qse_awk_nde_cnd_t));
cnd = (qse_awk_nde_cnd_t*)qse_awk_callocmem(awk, QSE_SIZEOF(*cnd));
if (cnd == QSE_NULL)
{
qse_awk_clrpt (awk, nde);
qse_awk_clrpt (awk, n1);
qse_awk_clrpt (awk, n2);
SETERR_LOC (awk, QSE_AWK_ENOMEM, xloc);
ADJERR_LOC (awk, xloc);
return QSE_NULL;
}
@ -3225,8 +3216,7 @@ static qse_awk_nde_t* parse_expr_basic (
return nde;
}
static qse_awk_nde_t* parse_expr (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_expr (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
qse_awk_nde_t* x, * y;
qse_awk_nde_ass_t* nde;
@ -3258,7 +3248,6 @@ static qse_awk_nde_t* parse_expr (
{
qse_awk_loc_t eloc;
eloc = awk->tok.loc;
y = parse_expr_withdc (awk, &eloc);
}
@ -3268,14 +3257,12 @@ static qse_awk_nde_t* parse_expr (
return QSE_NULL;
}
nde = (qse_awk_nde_ass_t*)
QSE_AWK_ALLOC (awk, QSE_SIZEOF(qse_awk_nde_ass_t));
nde = (qse_awk_nde_ass_t*)qse_awk_callocmem(awk, QSE_SIZEOF(*nde));
if (nde == QSE_NULL)
{
qse_awk_clrpt (awk, x);
qse_awk_clrpt (awk, y);
SETERR_LOC (awk, QSE_AWK_ENOMEM, xloc);
ADJERR_LOC (awk, xloc);
return QSE_NULL;
}
@ -3289,8 +3276,7 @@ static qse_awk_nde_t* parse_expr (
return (qse_awk_nde_t*)nde;
}
static qse_awk_nde_t* parse_expr_withdc (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_expr_withdc (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
qse_awk_nde_t* nde;
@ -4306,7 +4292,6 @@ static QSE_INLINE int isfnname (qse_awk_t* awk, const qse_cstr_t* name)
return isfunname(awk, name);
}
static qse_awk_nde_t* parse_primary_int (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
qse_awk_nde_int_t* nde;
@ -4800,8 +4785,7 @@ static qse_awk_nde_t* parse_primary (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
intype = QSE_AWK_IN_PIPE;
}
else if (MATCH(awk,TOK_LOR) &&
(awk->opt.trait & QSE_AWK_RWPIPE))
else if (MATCH(awk,TOK_LOR) && (awk->opt.trait & QSE_AWK_RWPIPE))
{
intype = QSE_AWK_IN_RWPIPE;
}
@ -4810,11 +4794,10 @@ static qse_awk_nde_t* parse_primary (qse_awk_t* awk, const qse_awk_loc_t* xloc)
if (intype == -1) break;
if (preget_token(awk) <= -1) goto oops;
if (awk->ntok.type != TOK_GETLINE) break;
/* consume ntok('getline') */
get_token (awk);
get_token(awk); /* no error check needed as it's guaranteeded to succeed for preget_token() above */
/* get the next token */
if (get_token(awk) <= -1) goto oops;
@ -4890,22 +4873,24 @@ oops:
static qse_awk_nde_t* parse_variable (qse_awk_t* awk, const qse_awk_loc_t* xloc, qse_awk_nde_type_t type, const qse_cstr_t* name, qse_size_t idxa)
{
qse_awk_nde_var_t* nde;
int fcv = 0;
int is_fcv = 0;
if (MATCH(awk,TOK_LPAREN))
{
#if defined(ENABLE_FEATURE_FUN_AS_VALUE)
/*
if (MATCH(awk,TOK_LPAREN) &&
(!(awk->opt.trait & QSE_AWK_BLANKCONCAT) ||
(awk->tok.loc.line == xloc->line &&
awk->tok.loc.colm == xloc->colm + name->len)))
*/
if (MATCH(awk,TOK_LPAREN))
{
if (awk->tok.loc.line == xloc->line && awk->tok.loc.colm == xloc->colm + name->len)
{
fcv = 1;
is_fcv = 1;
}
else if (!(awk->opt.trait & QSE_AWK_BLANKCONCAT))
else
#endif
if (!(awk->opt.trait & QSE_AWK_BLANKCONCAT))
{
/* if concatenation by blanks is not allowed, the explicit
* concatenation operator(%%) must be used. so it is obvious
@ -4934,8 +4919,12 @@ static qse_awk_nde_t* parse_variable (qse_awk_t* awk, const qse_awk_loc_t* xloc,
nde->id.idxa = idxa;
nde->idx = QSE_NULL;
if (!fcv) return (qse_awk_nde_t*)nde;
return parse_fncall(awk, (const qse_cstr_t*)nde, QSE_NULL, xloc, FNCALL_FLAG_FCV);
#if defined(ENABLE_FEATURE_FUN_AS_VALUE)
if (!is_fcv) return (qse_awk_nde_t*)nde;
return parse_fncall(awk, (const qse_cstr_t*)nde, QSE_NULL, xloc, FNCALL_FLAG_VAR);
#else
return (qse_awk_nde_t*)nde;
#endif
}
static int dup_ident_and_get_next (qse_awk_t* awk, const qse_awk_loc_t* xloc, qse_cstr_t* name, int max)
@ -4950,10 +4939,10 @@ static int dup_ident_and_get_next (qse_awk_t* awk, const qse_awk_loc_t* xloc, qs
name[nsegs].len = QSE_STR_LEN(awk->tok.name);
/* duplicate the identifier */
name[nsegs].ptr = qse_strxdup (name[nsegs].ptr, name[nsegs].len, awk->mmgr);
name[nsegs].ptr = qse_awk_strxdup(awk, name[nsegs].ptr, name[nsegs].len);
if (name[nsegs].ptr == QSE_NULL)
{
SETERR_LOC (awk, QSE_AWK_ENOMEM, xloc);
ADJERR_LOC (awk, xloc);
goto oops;
}
@ -4987,10 +4976,33 @@ static int dup_ident_and_get_next (qse_awk_t* awk, const qse_awk_loc_t* xloc, qs
return nsegs;
oops:
while (nsegs > 0) QSE_AWK_FREE (awk, name[--nsegs].ptr);
while (nsegs > 0) qse_awk_freemem (awk, name[--nsegs].ptr);
return -1;
}
#if defined(ENABLE_FEATURE_FUN_AS_VALUE)
static qse_awk_nde_t* parse_fun_as_value (qse_awk_t* awk, const qse_cstr_t* name, const qse_awk_loc_t* xloc)
{
qse_awk_nde_fun_t* nde;
/* create the node for the literal */
nde = (qse_awk_nde_fun_t*)qse_awk_callocmem(awk, QSE_SIZEOF(*nde));
if (nde == QSE_NULL)
{
ADJERR_LOC (awk, xloc);
return QSE_NULL;
}
nde->type = QSE_AWK_NDE_FUN;
nde->loc = *xloc;
nde->name.ptr = name->ptr;
nde->name.len = name->len;
return (qse_awk_nde_t*)nde;
}
#endif
static qse_awk_nde_t* parse_primary_ident_noseg (qse_awk_t* awk, const qse_awk_loc_t* xloc, const qse_cstr_t* name)
{
qse_awk_fnc_t* fnc;
@ -5071,7 +5083,11 @@ static qse_awk_nde_t* parse_primary_ident_noseg (qse_awk_t* awk, const qse_awk_l
else
{
/* function name appeared without () */
#if defined(ENABLE_FEATURE_FUN_AS_VALUE)
nde = parse_fun_as_value(awk, name, xloc);
#else
SETERR_ARG_LOC (awk, QSE_AWK_EFUNRED, name->ptr, name->len, xloc);
#endif
}
}
else if (awk->opt.trait & QSE_AWK_IMPLICIT)
@ -5084,6 +5100,7 @@ static qse_awk_nde_t* parse_primary_ident_noseg (qse_awk_t* awk, const qse_awk_l
* by a left parenthesis if concatenation by blanks
* is not allowed.
*/
int is_fncall_var = 0;
if (MATCH(awk,TOK_LPAREN) &&
(!(awk->opt.trait & QSE_AWK_BLANKCONCAT) ||
@ -5091,11 +5108,15 @@ static qse_awk_nde_t* parse_primary_ident_noseg (qse_awk_t* awk, const qse_awk_l
awk->tok.loc.colm == xloc->colm + name->len)))
{
/* it is a function call to an undefined function yet */
if (qse_htb_search(awk->parse.named, name->ptr, name->len) != QSE_NULL)
{
/* the function call conflicts with a named variable */
#if defined(ENABLE_FEATURE_FUN_AS_VALUE)
is_fncall_var = 1;
goto named_var;
#else
SETERR_ARG_LOC (awk, QSE_AWK_EVARRED, name->ptr, name->len, xloc);
#endif
}
else
{
@ -5106,6 +5127,10 @@ static qse_awk_nde_t* parse_primary_ident_noseg (qse_awk_t* awk, const qse_awk_l
{
qse_awk_nde_var_t* tmp;
#if defined(ENABLE_FEATURE_FUN_AS_VALUE)
named_var:
#endif
/* if there is a space between the name and the left parenthesis
* while the name is not resolved to anything, we treat the space
* as concatention by blanks. so we handle the name as a named
@ -5129,8 +5154,12 @@ static qse_awk_nde_t* parse_primary_ident_noseg (qse_awk_t* awk, const qse_awk_l
tmp->id.name.len = name->len;
tmp->id.idxa = (qse_size_t)-1;
tmp->idx = QSE_NULL;
nde = (qse_awk_nde_t*)tmp;
#if defined(ENABLE_FEATURE_FUN_AS_VALUE)
if (is_fncall_var)
nde = parse_fncall(awk, (const qse_cstr_t*)nde, QSE_NULL, xloc, FNCALL_FLAG_VAR);
#endif
}
}
}
@ -5216,8 +5245,7 @@ static qse_awk_nde_t* parse_primary_ident_segs (qse_awk_t* awk, const qse_awk_lo
return nde;
}
static qse_awk_nde_t* parse_primary_ident (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_primary_ident (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
qse_awk_nde_t* nde = QSE_NULL;
qse_cstr_t name[2]; /* TODO: support more than 2 segments??? */
@ -5231,7 +5259,7 @@ static qse_awk_nde_t* parse_primary_ident (
if (nsegs <= 1)
{
nde = parse_primary_ident_noseg (awk, xloc, &name[0]);
if (!nde) QSE_AWK_FREE (awk, name[0].ptr);
if (!nde) qse_awk_freemem (awk, name[0].ptr);
}
else
{
@ -5253,11 +5281,11 @@ static qse_awk_nde_t* parse_primary_ident (
full.len = capa;
nde = parse_primary_ident_segs(awk, xloc, &full, name, nsegs);
if (!nde || nde->type != QSE_AWK_NDE_FNC)
if (!nde || nde->type != QSE_AWK_NDE_FNCALL_FNC)
{
/* the FNC node takes the full name but other
* nodes don't. so i need to free it. i know it's ugly. */
QSE_AWK_FREE (awk, full.ptr);
qse_awk_freemem (awk, full.ptr);
}
}
else
@ -5267,7 +5295,7 @@ static qse_awk_nde_t* parse_primary_ident (
}
/* i don't need the name segments */
while (nsegs > 0) QSE_AWK_FREE (awk, name[--nsegs].ptr);
while (nsegs > 0) qse_awk_freemem (awk, name[--nsegs].ptr);
}
return nde;
@ -5414,7 +5442,7 @@ static qse_awk_nde_t* parse_hashidx (qse_awk_t* awk, const qse_cstr_t* name, con
exit_func:
qse_awk_clrpt (awk, idx);
QSE_AWK_FREE (awk, nde);
qse_awk_freemem (awk, nde);
return QSE_NULL;
}
@ -5482,17 +5510,17 @@ make_node:
goto oops;
}
if (flags & FNCALL_FLAG_FCV)
if (flags & FNCALL_FLAG_VAR)
{
call->type = QSE_AWK_NDE_FCV;
call->type = QSE_AWK_NDE_FNCALL_VAR;
call->loc = *xloc;
call->u.fcv.var = (qse_awk_nde_var_t*)name; /* name is a pointer to a variable node */
call->u.var.var = (qse_awk_nde_var_t*)name; /* name is a pointer to a variable node */
call->args = head;
call->nargs = nargs;
}
else if (fnc)
{
call->type = QSE_AWK_NDE_FNC;
call->type = QSE_AWK_NDE_FNCALL_FNC;
call->loc = *xloc;
call->u.fnc.info.name.ptr = name->ptr;
@ -5516,7 +5544,7 @@ make_node:
}
else
{
call->type = QSE_AWK_NDE_FUN;
call->type = QSE_AWK_NDE_FNCALL_FUN;
call->loc = *xloc;
call->u.fun.name.ptr = name->ptr;
call->u.fun.name.len = name->len;
@ -5534,7 +5562,7 @@ make_node:
return (qse_awk_nde_t*)call;
oops:
if (call) QSE_AWK_FREE (awk, call);
if (call) qse_awk_freemem (awk, call);
if (head) qse_awk_clrpt (awk, head);
return QSE_NULL;
}

View File

@ -224,13 +224,13 @@ static qse_awk_val_t* eval_incpre (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_incpst (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_cnd (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_fun_ex (
static qse_awk_val_t* eval_fncall_fncall_fun_ex (
qse_awk_rtx_t* run, qse_awk_nde_t* nde,
void(*errhandler)(void*), void* eharg);
static qse_awk_val_t* eval_fnc (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_fun (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_fcv (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
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_fncall_fun (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_fncall_var (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* __eval_call (
qse_awk_rtx_t* run,
@ -257,6 +257,7 @@ static qse_awk_val_t* eval_flt (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_str (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_mbs (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_rex (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_fun (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_named (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_gbl (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_lcl (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
@ -1630,7 +1631,7 @@ qse_awk_val_t* qse_awk_rtx_callfun (
/* forge a fake node containing a function call */
QSE_MEMSET (&call, 0, QSE_SIZEOF(call));
call.type = QSE_AWK_NDE_FUN;
call.type = QSE_AWK_NDE_FNCALL_FUN;
call.u.fun.name = fun->name;
call.nargs = nargs;
@ -3326,14 +3327,15 @@ static qse_awk_val_t* eval_expression0 (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
eval_incpre,
eval_incpst,
eval_cnd,
eval_fnc,
eval_fun,
eval_fcv,
eval_fncall_fnc,
eval_fncall_fncall_fun,
eval_fncall_var,
eval_int,
eval_flt,
eval_str,
eval_mbs,
eval_rex,
eval_fun,
eval_named,
eval_gbl,
eval_lcl,
@ -3350,8 +3352,7 @@ static qse_awk_val_t* eval_expression0 (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
qse_awk_val_t* v;
QSE_ASSERT (nde->type >= QSE_AWK_NDE_GRP &&
(nde->type - QSE_AWK_NDE_GRP) < QSE_COUNTOF(__evaluator));
QSE_ASSERT (nde->type >= QSE_AWK_NDE_GRP && (nde->type - QSE_AWK_NDE_GRP) < QSE_COUNTOF(__evaluator));
v = __evaluator[nde->type-QSE_AWK_NDE_GRP](run, nde);
@ -5602,7 +5603,7 @@ static qse_awk_val_t* eval_cnd (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
return v;
}
static qse_awk_val_t* eval_fnc (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
static qse_awk_val_t* eval_fncall_fnc (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
/* intrinsic function */
qse_awk_nde_fncall_t* call = (qse_awk_nde_fncall_t*)nde;
@ -5612,7 +5613,7 @@ static qse_awk_val_t* eval_fnc (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
return eval_call(run, nde, call->u.fnc.spec.arg.spec, QSE_NULL, QSE_NULL, QSE_NULL);
}
static QSE_INLINE qse_awk_val_t* eval_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_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_fun_t* fun;
@ -5639,24 +5640,23 @@ static QSE_INLINE qse_awk_val_t* eval_fun_ex (qse_awk_rtx_t* rtx, qse_awk_nde_t*
return eval_call(rtx, nde, QSE_NULL, fun, errhandler, eharg);
}
static qse_awk_val_t* eval_fun (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)
{
return eval_fun_ex(rtx, nde, QSE_NULL, QSE_NULL);
return eval_fncall_fncall_fun_ex(rtx, nde, QSE_NULL, QSE_NULL);
}
static qse_awk_val_t* eval_fcv (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)
{
qse_awk_nde_fncall_t* call = (qse_awk_nde_fncall_t*)nde;
qse_awk_val_t* fv, * rv;
fv = eval_expression(rtx, (qse_awk_nde_t*)call->u.fcv.var);
fv = eval_expression(rtx, (qse_awk_nde_t*)call->u.var.var);
if (!fv) return QSE_NULL;
qse_awk_rtx_refupval (rtx, fv);
if (QSE_AWK_RTX_GETVALTYPE(rtx, fv) != QSE_AWK_VAL_FUN)
{
/*SETERR_ARGX_LOC (rtx, QSE_AWK_EFUNNF, &call->u.fun.name, &nde->loc);*/
/*printf ("NOT FUNCTION VALUE\n");*/
SETERR_ARGX_LOC (rtx, QSE_AWK_ENOTFUN, &call->u.var.var->id.name, &nde->loc);
rv = QSE_NULL;
}
else
@ -6002,8 +6002,7 @@ static qse_size_t push_arg_from_nde (qse_awk_rtx_t* rtx, qse_awk_nde_fncall_t* c
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'))
{
/* a regular expression is passed to
* the function as it is */
@ -6014,7 +6013,7 @@ static qse_size_t push_arg_from_nde (qse_awk_rtx_t* rtx, qse_awk_nde_fncall_t* c
v = eval_expression(rtx, p);
}
if (v == QSE_NULL)
if (!v)
{
UNWIND_RTX_STACK_ARG (rtx, nargs);
return (qse_size_t)-1;
@ -6264,6 +6263,32 @@ static qse_awk_val_t* eval_rex (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde)
return val;
}
static qse_awk_val_t* eval_fun (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde)
{
qse_awk_val_t* val;
qse_awk_fun_t* fun;
qse_htb_pair_t* pair;
fun = ((qse_awk_nde_fun_t*)nde)->ptr;
if (!fun)
{
/* TODO: support bultin functions?, support module functions? */
pair = qse_htb_search(rtx->awk->tree.funs, ((qse_awk_nde_fun_t*)nde)->name.ptr, ((qse_awk_nde_fun_t*)nde)->name.len);
if (!pair)
{
SETERR_ARGX_LOC (rtx, QSE_AWK_EFUNNF, &((qse_awk_nde_fun_t*)nde)->name, &nde->loc);
return QSE_NULL;
}
fun = (qse_awk_fun_t*)QSE_HTB_VPTR(pair);
QSE_ASSERT (fun != QSE_NULL);
}
val = qse_awk_rtx_makefunval(rtx, fun);
if (!val) ADJERR_LOC (rtx, &nde->loc);
return val;
}
static qse_awk_val_t* eval_named (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde)
{
qse_htb_pair_t* pair;

View File

@ -497,6 +497,14 @@ static int print_expr (qse_awk_t* awk, qse_awk_nde_t* nde)
break;
}
case QSE_AWK_NDE_FUN:
{
PUT_SRCSTRN (awk,
((qse_awk_nde_fun_t*)nde)->name.ptr,
((qse_awk_nde_fun_t*)nde)->name.len);
break;
}
case QSE_AWK_NDE_ARG:
{
qse_char_t tmp[QSE_SIZEOF(qse_awk_int_t)*8+2];
@ -710,7 +718,7 @@ static int print_expr (qse_awk_t* awk, qse_awk_nde_t* nde)
break;
}
case QSE_AWK_NDE_FNC:
case QSE_AWK_NDE_FNCALL_FNC:
{
qse_awk_nde_fncall_t* px = (qse_awk_nde_fncall_t*)nde;
PUT_SRCSTRN (awk, px->u.fnc.info.name.ptr, px->u.fnc.info.name.len);
@ -720,7 +728,7 @@ static int print_expr (qse_awk_t* awk, qse_awk_nde_t* nde)
break;
}
case QSE_AWK_NDE_FUN:
case QSE_AWK_NDE_FNCALL_FUN:
{
qse_awk_nde_fncall_t* px = (qse_awk_nde_fncall_t*)nde;
PUT_SRCSTRN (awk, px->u.fun.name.ptr, px->u.fun.name.len);
@ -730,10 +738,10 @@ static int print_expr (qse_awk_t* awk, qse_awk_nde_t* nde)
break;
}
case QSE_AWK_NDE_FCV:
case QSE_AWK_NDE_FNCALL_VAR:
{
qse_awk_nde_fncall_t* px = (qse_awk_nde_fncall_t*)nde;
PRINT_EXPR (awk, (qse_awk_nde_t*)px->u.fcv.var);
PRINT_EXPR (awk, (qse_awk_nde_t*)px->u.var.var);
PUT_SRCSTR (awk, QSE_T("("));
PRINT_EXPR_LIST (awk, px->args);
PUT_SRCSTR (awk, QSE_T(")"));
@ -1402,6 +1410,13 @@ void qse_awk_clrpt (qse_awk_t* awk, qse_awk_nde_t* tree)
break;
}
case QSE_AWK_NDE_FUN:
{
QSE_AWK_FREE (awk, ((qse_awk_nde_fun_t*)p)->name.ptr);
QSE_AWK_FREE (awk, p);
break;
}
case QSE_AWK_NDE_NAMED:
case QSE_AWK_NDE_GBL:
case QSE_AWK_NDE_LCL:
@ -1434,7 +1449,7 @@ void qse_awk_clrpt (qse_awk_t* awk, qse_awk_nde_t* tree)
break;
}
case QSE_AWK_NDE_FNC:
case QSE_AWK_NDE_FNCALL_FNC:
{
qse_awk_nde_fncall_t* px = (qse_awk_nde_fncall_t*)p;
/* QSE_AWK_FREE (awk, px->u.fnc); */
@ -1444,7 +1459,7 @@ void qse_awk_clrpt (qse_awk_t* awk, qse_awk_nde_t* tree)
break;
}
case QSE_AWK_NDE_FUN:
case QSE_AWK_NDE_FNCALL_FUN:
{
qse_awk_nde_fncall_t* px = (qse_awk_nde_fncall_t*)p;
QSE_AWK_FREE (awk, px->u.fun.name.ptr);
@ -1453,10 +1468,10 @@ void qse_awk_clrpt (qse_awk_t* awk, qse_awk_nde_t* tree)
break;
}
case QSE_AWK_NDE_FCV:
case QSE_AWK_NDE_FNCALL_VAR:
{
qse_awk_nde_fncall_t* px = (qse_awk_nde_fncall_t*)p;
qse_awk_clrpt (awk, px->u.fcv.var);
qse_awk_clrpt (awk, (qse_awk_nde_t*)px->u.var.var);
qse_awk_clrpt (awk, px->args);
QSE_AWK_FREE (awk, p);
break;

View File

@ -59,10 +59,11 @@ typedef struct qse_awk_nde_pos_t qse_awk_nde_pos_t;
typedef struct qse_awk_nde_int_t qse_awk_nde_int_t;
typedef struct qse_awk_nde_flt_t qse_awk_nde_flt_t;
typedef struct qse_awk_nde_str_t qse_awk_nde_str_t;
typedef struct qse_awk_nde_mbs_t qse_awk_nde_mbs_t;
typedef struct qse_awk_nde_rex_t qse_awk_nde_rex_t;
typedef struct qse_awk_nde_fun_t qse_awk_nde_fun_t;
typedef struct qse_awk_nde_var_t qse_awk_nde_var_t;
typedef struct qse_awk_nde_fncall_t qse_awk_nde_fncall_t;
typedef struct qse_awk_nde_getline_t qse_awk_nde_getline_t;
@ -173,6 +174,14 @@ struct qse_awk_nde_rex_t
void* code[2]; /* [0]: case sensitive, [1]: case insensitive */
};
/* QSE_AWK_NDE_FUN - function as a value */
struct qse_awk_nde_fun_t
{
QSE_AWK_NDE_HDR;
qse_cstr_t name; /* function name */
qse_awk_fun_t* ptr; /* QSE_NULL or actual pointer */
};
/* QSE_AWK_NDE_NAMED, QSE_AWK_NDE_GBL,
* QSE_AWK_NDE_LCL, QSE_AWK_NDE_ARG
* QSE_AWK_NDE_NAMEDIDX, QSE_AWK_NDE_GBLIDX,
@ -188,7 +197,7 @@ struct qse_awk_nde_var_t
qse_awk_nde_t* idx; /* QSE_NULL for non-XXXXIDX */
};
/* QSE_AWK_NDE_FNC, QSE_AWK_NDE_FUN */
/* QSE_AWK_NDE_FNCALL_FNC, QSE_AWK_NDE_FNCALL_FUN, QSE_AWK_NDE_FNCALL_VAR */
struct qse_awk_nde_fncall_t
{
QSE_AWK_NDE_HDR;
@ -210,7 +219,7 @@ struct qse_awk_nde_fncall_t
struct
{
qse_awk_nde_var_t* var;
} fcv;
} var;
} u;
qse_awk_nde_t* args;
qse_size_t nargs;

View File

@ -402,7 +402,7 @@ qse_awk_val_t* qse_awk_rtx_makembsval (qse_awk_rtx_t* rtx, const qse_mchar_t* pt
qse_awk_val_mbs_t* val = QSE_NULL;
qse_size_t xsz = len * QSE_SIZEOF(*ptr);
val = (qse_awk_val_mbs_t*)QSE_AWK_ALLOC(rtx->awk, QSE_SIZEOF(qse_awk_val_mbs_t) + xsz + QSE_SIZEOF(*ptr));
val = (qse_awk_val_mbs_t*)qse_awk_callocmem(rtx->awk, QSE_SIZEOF(qse_awk_val_mbs_t) + xsz + QSE_SIZEOF(*ptr));
if (val == QSE_NULL)
{
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
@ -437,7 +437,7 @@ qse_awk_val_t* qse_awk_rtx_makerexval (qse_awk_rtx_t* rtx, const qse_cstr_t* str
* the total size is just large enough for all these.
*/
totsz = QSE_SIZEOF(*val) + (QSE_SIZEOF(*str->ptr) * (str->len + 1));
val = (qse_awk_val_rex_t*) QSE_AWK_ALLOC (rtx->awk, totsz);
val = (qse_awk_val_rex_t*)qse_awk_callocmem(rtx->awk, totsz);
if (val == QSE_NULL)
{
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
@ -702,7 +702,7 @@ qse_awk_val_t* qse_awk_rtx_makerefval (
}
else
{
val = (qse_awk_val_ref_t*)QSE_AWK_ALLOC(rtx->awk, QSE_SIZEOF(qse_awk_val_ref_t));
val = (qse_awk_val_ref_t*)qse_awk_callocmem(rtx->awk, QSE_SIZEOF(*val));
if (!val)
{
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
@ -723,7 +723,7 @@ qse_awk_val_t* qse_awk_rtx_makefunval (qse_awk_rtx_t* rtx, const qse_awk_fun_t*
{
qse_awk_val_fun_t* val;
val = (qse_awk_val_fun_t*)QSE_AWK_ALLOC(rtx->awk, QSE_SIZEOF(qse_awk_val_fun_t));
val = (qse_awk_val_fun_t*)qse_awk_callocmem(rtx->awk, QSE_SIZEOF(*val));
if (!val)
{
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL);
@ -731,6 +731,9 @@ qse_awk_val_t* qse_awk_rtx_makefunval (qse_awk_rtx_t* rtx, const qse_awk_fun_t*
}
val->v_type = QSE_AWK_VAL_FUN;
val->ref = 0;
val->stat = 0;
val->nstr = 0;
val->fun = (qse_awk_fun_t*)fun;
return (qse_awk_val_t*)val;
@ -869,7 +872,7 @@ void qse_awk_rtx_freeval (qse_awk_rtx_t* rtx, qse_awk_val_t* val, int cache)
}
case QSE_AWK_VAL_FUN:
/* nothing to do */
QSE_AWK_FREE (rtx->awk, val);
break;
}
@ -1519,7 +1522,7 @@ int qse_awk_rtx_valtostr (qse_awk_rtx_t* rtx, const qse_awk_val_t* v, qse_awk_rt
case QSE_AWK_VAL_FUN:
{
return qse_awk_rtx_makestrval2(rtx, QSE_T("@@"), 1, ((qse_awk_val_fun_t*)v)->fun->name.ptr, ((qse_awk_val_fun_t*)v)->fun->name.len);
return str_to_str(rtx, ((qse_awk_val_fun_t*)v)->fun->name.ptr, ((qse_awk_val_fun_t*)v)->fun->name.len, out);
}
}
@ -1823,7 +1826,7 @@ int qse_awk_rtx_valtonum (qse_awk_rtx_t* rtx, const qse_awk_val_t* v, qse_awk_in
case QSE_AWK_VAL_FUN:
{
/* TODO: */
/* unable to convert a function to a number */
break;
}
}
@ -2163,7 +2166,7 @@ void qse_awk_dprintval (qse_awk_rtx_t* run, qse_awk_val_t* val)
break;
case QSE_AWK_VAL_FUN:
qse_errputstrf (QSE_T("@@%.*s"), (int)((qse_awk_val_fun_t*)val)->fun->name.len, ((qse_awk_val_fun_t*)val)->fun->name.ptr);
qse_errputstrf (QSE_T("%.*s"), (int)((qse_awk_val_fun_t*)val)->fun->name.len, ((qse_awk_val_fun_t*)val)->fun->name.ptr);
break;
default: