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_INCPRE,
QSE_AWK_NDE_EXP_INCPST, QSE_AWK_NDE_EXP_INCPST,
QSE_AWK_NDE_CND, QSE_AWK_NDE_CND,
QSE_AWK_NDE_FNC, QSE_AWK_NDE_FNCALL_FNC,
QSE_AWK_NDE_FUN, QSE_AWK_NDE_FNCALL_FUN,
QSE_AWK_NDE_FCV, QSE_AWK_NDE_FNCALL_VAR,
QSE_AWK_NDE_INT, QSE_AWK_NDE_INT,
QSE_AWK_NDE_FLT, QSE_AWK_NDE_FLT,
QSE_AWK_NDE_STR, QSE_AWK_NDE_STR,
QSE_AWK_NDE_MBS, QSE_AWK_NDE_MBS,
QSE_AWK_NDE_REX, QSE_AWK_NDE_REX,
QSE_AWK_NDE_FUN,
/* keep this order for the following items otherwise, you may have /* keep this order for the following items otherwise, you may have
* to change eval_incpre and eval_incpst in run.c as well as * 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_EARGTF, /**< too few arguments */
QSE_AWK_EARGTM, /**< too many arguments */ QSE_AWK_EARGTM, /**< too many arguments */
QSE_AWK_EFUNNF, /**< function '${0}' not found */ QSE_AWK_EFUNNF, /**< function '${0}' not found */
QSE_AWK_ENOTFUN, /**< non-function value in '%{0}' */
QSE_AWK_ENOTDEL, /**< '${0}' not deletable */ QSE_AWK_ENOTDEL, /**< '${0}' not deletable */
QSE_AWK_ENOTMAP, /**< value not a map */ QSE_AWK_ENOTMAP, /**< value not a map */
QSE_AWK_ENOTMAPIN, /**< right-hand side of 'in' 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_UNIT 16
#define FEATURE_SCACHE_BLOCK_SIZE 128 #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_GBLS 9999
#define QSE_AWK_MAX_LCLS 9999 #define QSE_AWK_MAX_LCLS 9999
#define QSE_AWK_MAX_PARAMS 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 few arguments"),
QSE_T("too many arguments"), QSE_T("too many arguments"),
QSE_T("function '${0}' not found"), QSE_T("function '${0}' not found"),
QSE_T("non-function value in '${0}'"),
QSE_T("'${0}' not deletable"), QSE_T("'${0}' not deletable"),
QSE_T("value not a map"), QSE_T("value not a map"),
QSE_T("right-hand side of the 'in' operator 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_LS,
TOK_IN, TOK_IN,
TOK_EXP, TOK_EXP,
TOK_CONCAT, TOK_CONCAT, /* %% */
TOK_LPAREN, TOK_LPAREN,
TOK_RPAREN, TOK_RPAREN,
@ -111,7 +111,7 @@ enum tok_t
TOK_COLON, TOK_COLON,
TOK_DBLCOLON, TOK_DBLCOLON,
TOK_QUEST, TOK_QUEST,
TOK_DBLAT, /*TOK_DBLAT,*/
/* == begin reserved words == */ /* == begin reserved words == */
/* === extended 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); 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_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_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); 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() */ /* 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) if (name.ptr == QSE_NULL)
{ {
SETERR_LOC (awk, QSE_AWK_ENOMEM, &awk->tok.loc); ADJERR_LOC (awk, &awk->tok.loc);
return QSE_NULL; return QSE_NULL;
} }
/* get the next token */ /* get the next token */
if (get_token(awk) <= -1) if (get_token(awk) <= -1)
{ {
QSE_AWK_FREE (awk, name.ptr); qse_awk_freemem (awk, name.ptr);
return QSE_NULL; 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 */ /* a function name is not followed by a left parenthesis */
SETERR_TOK (awk, QSE_AWK_ELPAREN); SETERR_TOK (awk, QSE_AWK_ELPAREN);
QSE_AWK_FREE (awk, name.ptr); qse_awk_freemem (awk, name.ptr);
return QSE_NULL; return QSE_NULL;
} }
/* get the next token */ /* get the next token */
if (get_token(awk) <= -1) if (get_token(awk) <= -1)
{ {
QSE_AWK_FREE (awk, name.ptr); qse_awk_freemem (awk, name.ptr);
return QSE_NULL; 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 */ /* no function parameter found. get the next token */
if (get_token(awk) <= -1) if (get_token(awk) <= -1)
{ {
QSE_AWK_FREE (awk, name.ptr); qse_awk_freemem (awk, name.ptr);
return QSE_NULL; return QSE_NULL;
} }
} }
@ -1169,7 +1169,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
if (!MATCH(awk,TOK_IDENT)) if (!MATCH(awk,TOK_IDENT))
{ {
QSE_AWK_FREE (awk, name.ptr); qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params); qse_arr_clear (awk->parse.params);
SETERR_TOK (awk, QSE_AWK_EBADPAR); SETERR_TOK (awk, QSE_AWK_EBADPAR);
return QSE_NULL; 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_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_FREE (awk, name.ptr); qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params); qse_arr_clear (awk->parse.params);
SETERR_ARG_LOC ( SETERR_ARG_LOC (
awk, QSE_AWK_EDUPPAR, 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 */ /* 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_FREE (awk, name.ptr); qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params); 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; return QSE_NULL;
} }
if (qse_arr_insert ( if (qse_arr_insert(awk->parse.params, QSE_ARR_SIZE(awk->parse.params), pa, pal) == QSE_ARR_NIL)
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); 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; return QSE_NULL;
@ -1222,7 +1219,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
if (get_token (awk) <= -1) if (get_token (awk) <= -1)
{ {
QSE_AWK_FREE (awk, name.ptr); qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params); qse_arr_clear (awk->parse.params);
return QSE_NULL; return QSE_NULL;
} }
@ -1231,7 +1228,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
if (!MATCH(awk,TOK_COMMA)) if (!MATCH(awk,TOK_COMMA))
{ {
QSE_AWK_FREE (awk, name.ptr); qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params); qse_arr_clear (awk->parse.params);
SETERR_TOK (awk, QSE_AWK_ECOMMA); SETERR_TOK (awk, QSE_AWK_ECOMMA);
return QSE_NULL; return QSE_NULL;
@ -1241,7 +1238,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
{ {
if (get_token(awk) <= -1) if (get_token(awk) <= -1)
{ {
QSE_AWK_FREE (awk, name.ptr); qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params); qse_arr_clear (awk->parse.params);
return QSE_NULL; return QSE_NULL;
} }
@ -1251,7 +1248,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
if (get_token(awk) <= -1) if (get_token(awk) <= -1)
{ {
QSE_AWK_FREE (awk, name.ptr); qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params); qse_arr_clear (awk->parse.params);
return QSE_NULL; return QSE_NULL;
} }
@ -1265,7 +1262,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
{ {
if (get_token(awk) <= -1) if (get_token(awk) <= -1)
{ {
QSE_AWK_FREE (awk, name.ptr); qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params); qse_arr_clear (awk->parse.params);
return QSE_NULL; 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 */ /* check if the function body starts with a left brace */
if (!MATCH(awk,TOK_LBRACE)) if (!MATCH(awk,TOK_LBRACE))
{ {
QSE_AWK_FREE (awk, name.ptr); qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params); qse_arr_clear (awk->parse.params);
SETERR_TOK (awk, QSE_AWK_ELBRACE); SETERR_TOK (awk, QSE_AWK_ELBRACE);
return QSE_NULL; return QSE_NULL;
} }
if (get_token(awk) <= -1) if (get_token(awk) <= -1)
{ {
QSE_AWK_FREE (awk, name.ptr); qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params); qse_arr_clear (awk->parse.params);
return QSE_NULL; return QSE_NULL;
} }
@ -1302,7 +1298,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
if (body == QSE_NULL) if (body == QSE_NULL)
{ {
QSE_AWK_FREE (awk, name.ptr); qse_awk_freemem (awk, name.ptr);
qse_arr_clear (awk->parse.params); qse_arr_clear (awk->parse.params);
return QSE_NULL; 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)); fun = (qse_awk_fun_t*)qse_awk_callocmem(awk, QSE_SIZEOF(*fun));
if (fun == QSE_NULL) if (fun == QSE_NULL)
{ {
QSE_AWK_FREE (awk, name.ptr); qse_awk_freemem (awk, name.ptr);
qse_awk_clrpt (awk, body); qse_awk_clrpt (awk, body);
ADJERR_LOC (awk, &awk->tok.loc); ADJERR_LOC (awk, &awk->tok.loc);
return QSE_NULL; 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 /* 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_FREE (awk, name.ptr); qse_awk_freemem (awk, name.ptr);
qse_awk_clrpt (awk, body); qse_awk_clrpt (awk, body);
QSE_AWK_FREE (awk, fun); 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; return QSE_NULL;
} }
@ -1344,7 +1340,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk)
* of the pair */ * of the pair */
fun->name.ptr = QSE_HTB_KPTR(pair); fun->name.ptr = QSE_HTB_KPTR(pair);
fun->name.len = QSE_HTB_KLEN(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 */ /* 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);
@ -1419,12 +1415,11 @@ static qse_awk_chain_t* parse_action_block (
if (nde == QSE_NULL) return QSE_NULL; if (nde == QSE_NULL) return QSE_NULL;
} }
chain = (qse_awk_chain_t*) chain = (qse_awk_chain_t*)qse_awk_callocmem(awk, QSE_SIZEOF(*chain));
QSE_AWK_ALLOC (awk, QSE_SIZEOF(qse_awk_chain_t));
if (chain == QSE_NULL) if (chain == QSE_NULL)
{ {
qse_awk_clrpt (awk, nde); qse_awk_clrpt (awk, nde);
SETERR_LOC (awk, QSE_AWK_ENOMEM, &xloc); ADJERR_LOC (awk, &xloc);
return QSE_NULL; return QSE_NULL;
} }
@ -3052,8 +3047,7 @@ static qse_awk_nde_t* parse_statement_nb (
return nde; return nde;
} }
static qse_awk_nde_t* parse_statement ( static qse_awk_nde_t* parse_statement (qse_awk_t* awk, const qse_awk_loc_t* xloc)
qse_awk_t* awk, const qse_awk_loc_t* xloc)
{ {
qse_awk_nde_t* nde; qse_awk_nde_t* nde;
@ -3066,11 +3060,10 @@ static qse_awk_nde_t* parse_statement (
if (MATCH(awk,TOK_SEMICOLON)) if (MATCH(awk,TOK_SEMICOLON))
{ {
/* null statement */ /* null statement */
nde = (qse_awk_nde_t*) nde = (qse_awk_nde_t*)qse_awk_callocmem(awk, QSE_SIZEOF(*nde));
QSE_AWK_ALLOC (awk, QSE_SIZEOF(qse_awk_nde_t)); if (!nde)
if (nde == QSE_NULL)
{ {
SETERR_LOC (awk, QSE_AWK_ENOMEM, xloc); ADJERR_LOC (awk, xloc);
return QSE_NULL; return QSE_NULL;
} }
@ -3080,7 +3073,7 @@ static qse_awk_nde_t* parse_statement (
if (get_token(awk) <= -1) if (get_token(awk) <= -1)
{ {
QSE_AWK_FREE (awk, nde); qse_awk_freemem (awk, nde);
return QSE_NULL; return QSE_NULL;
} }
} }
@ -3150,8 +3143,7 @@ static int assign_to_opcode (qse_awk_t* awk)
return -1; return -1;
} }
static qse_awk_nde_t* parse_expr_basic ( static qse_awk_nde_t* parse_expr_basic (qse_awk_t* awk, const qse_awk_loc_t* xloc)
qse_awk_t* awk, const qse_awk_loc_t* xloc)
{ {
qse_awk_nde_t* nde, * n1, * n2; qse_awk_nde_t* nde, * n1, * n2;
@ -3201,14 +3193,13 @@ static qse_awk_nde_t* parse_expr_basic (
return QSE_NULL; return QSE_NULL;
} }
cnd = (qse_awk_nde_cnd_t*) QSE_AWK_ALLOC ( cnd = (qse_awk_nde_cnd_t*)qse_awk_callocmem(awk, QSE_SIZEOF(*cnd));
awk, QSE_SIZEOF(qse_awk_nde_cnd_t));
if (cnd == QSE_NULL) if (cnd == QSE_NULL)
{ {
qse_awk_clrpt (awk, nde); qse_awk_clrpt (awk, nde);
qse_awk_clrpt (awk, n1); qse_awk_clrpt (awk, n1);
qse_awk_clrpt (awk, n2); qse_awk_clrpt (awk, n2);
SETERR_LOC (awk, QSE_AWK_ENOMEM, xloc); ADJERR_LOC (awk, xloc);
return QSE_NULL; return QSE_NULL;
} }
@ -3225,8 +3216,7 @@ static qse_awk_nde_t* parse_expr_basic (
return nde; return nde;
} }
static qse_awk_nde_t* parse_expr ( static qse_awk_nde_t* parse_expr (qse_awk_t* awk, const qse_awk_loc_t* xloc)
qse_awk_t* awk, const qse_awk_loc_t* xloc)
{ {
qse_awk_nde_t* x, * y; qse_awk_nde_t* x, * y;
qse_awk_nde_ass_t* nde; qse_awk_nde_ass_t* nde;
@ -3258,7 +3248,6 @@ static qse_awk_nde_t* parse_expr (
{ {
qse_awk_loc_t eloc; qse_awk_loc_t eloc;
eloc = awk->tok.loc; eloc = awk->tok.loc;
y = parse_expr_withdc (awk, &eloc); y = parse_expr_withdc (awk, &eloc);
} }
@ -3268,14 +3257,12 @@ static qse_awk_nde_t* parse_expr (
return QSE_NULL; return QSE_NULL;
} }
nde = (qse_awk_nde_ass_t*) nde = (qse_awk_nde_ass_t*)qse_awk_callocmem(awk, QSE_SIZEOF(*nde));
QSE_AWK_ALLOC (awk, QSE_SIZEOF(qse_awk_nde_ass_t));
if (nde == QSE_NULL) if (nde == QSE_NULL)
{ {
qse_awk_clrpt (awk, x); qse_awk_clrpt (awk, x);
qse_awk_clrpt (awk, y); qse_awk_clrpt (awk, y);
ADJERR_LOC (awk, xloc);
SETERR_LOC (awk, QSE_AWK_ENOMEM, xloc);
return QSE_NULL; return QSE_NULL;
} }
@ -3289,8 +3276,7 @@ static qse_awk_nde_t* parse_expr (
return (qse_awk_nde_t*)nde; return (qse_awk_nde_t*)nde;
} }
static qse_awk_nde_t* parse_expr_withdc ( static qse_awk_nde_t* parse_expr_withdc (qse_awk_t* awk, const qse_awk_loc_t* xloc)
qse_awk_t* awk, const qse_awk_loc_t* xloc)
{ {
qse_awk_nde_t* nde; 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); return isfunname(awk, name);
} }
static qse_awk_nde_t* parse_primary_int (qse_awk_t* awk, const qse_awk_loc_t* xloc) static qse_awk_nde_t* parse_primary_int (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{ {
qse_awk_nde_int_t* nde; 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; intype = QSE_AWK_IN_PIPE;
} }
else if (MATCH(awk,TOK_LOR) && else if (MATCH(awk,TOK_LOR) && (awk->opt.trait & QSE_AWK_RWPIPE))
(awk->opt.trait & QSE_AWK_RWPIPE))
{ {
intype = QSE_AWK_IN_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 (intype == -1) break;
if (preget_token(awk) <= -1) goto oops; if (preget_token(awk) <= -1) goto oops;
if (awk->ntok.type != TOK_GETLINE) break; if (awk->ntok.type != TOK_GETLINE) break;
/* consume ntok('getline') */ /* 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 */ /* get the next token */
if (get_token(awk) <= -1) goto oops; 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) 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; 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) && if (MATCH(awk,TOK_LPAREN) &&
(!(awk->opt.trait & QSE_AWK_BLANKCONCAT) || (!(awk->opt.trait & QSE_AWK_BLANKCONCAT) ||
(awk->tok.loc.line == xloc->line && (awk->tok.loc.line == xloc->line &&
awk->tok.loc.colm == xloc->colm + name->len))) 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) 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 /* if concatenation by blanks is not allowed, the explicit
* concatenation operator(%%) must be used. so it is obvious * 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->id.idxa = idxa;
nde->idx = QSE_NULL; nde->idx = QSE_NULL;
if (!fcv) return (qse_awk_nde_t*)nde; #if defined(ENABLE_FEATURE_FUN_AS_VALUE)
return parse_fncall(awk, (const qse_cstr_t*)nde, QSE_NULL, xloc, FNCALL_FLAG_FCV); 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) 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); name[nsegs].len = QSE_STR_LEN(awk->tok.name);
/* duplicate the identifier */ /* 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) if (name[nsegs].ptr == QSE_NULL)
{ {
SETERR_LOC (awk, QSE_AWK_ENOMEM, xloc); ADJERR_LOC (awk, xloc);
goto oops; 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; return nsegs;
oops: oops:
while (nsegs > 0) QSE_AWK_FREE (awk, name[--nsegs].ptr); while (nsegs > 0) qse_awk_freemem (awk, name[--nsegs].ptr);
return -1; 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) 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; 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 else
{ {
/* function name appeared without () */ /* 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); SETERR_ARG_LOC (awk, QSE_AWK_EFUNRED, name->ptr, name->len, xloc);
#endif
} }
} }
else if (awk->opt.trait & QSE_AWK_IMPLICIT) 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 * by a left parenthesis if concatenation by blanks
* is not allowed. * is not allowed.
*/ */
int is_fncall_var = 0;
if (MATCH(awk,TOK_LPAREN) && if (MATCH(awk,TOK_LPAREN) &&
(!(awk->opt.trait & QSE_AWK_BLANKCONCAT) || (!(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))) awk->tok.loc.colm == xloc->colm + name->len)))
{ {
/* it is a function call to an undefined function yet */ /* it is a function call to an undefined function yet */
if (qse_htb_search(awk->parse.named, name->ptr, name->len) != QSE_NULL) if (qse_htb_search(awk->parse.named, name->ptr, name->len) != QSE_NULL)
{ {
/* the function call conflicts with a named variable */ /* 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); SETERR_ARG_LOC (awk, QSE_AWK_EVARRED, name->ptr, name->len, xloc);
#endif
} }
else 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; 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 /* if there is a space between the name and the left parenthesis
* while the name is not resolved to anything, we treat the space * while the name is not resolved to anything, we treat the space
* as concatention by blanks. so we handle the name as a named * 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.name.len = name->len;
tmp->id.idxa = (qse_size_t)-1; tmp->id.idxa = (qse_size_t)-1;
tmp->idx = QSE_NULL; tmp->idx = QSE_NULL;
nde = (qse_awk_nde_t*)tmp; 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; return nde;
} }
static qse_awk_nde_t* parse_primary_ident ( static qse_awk_nde_t* parse_primary_ident (qse_awk_t* awk, const qse_awk_loc_t* xloc)
qse_awk_t* awk, const qse_awk_loc_t* xloc)
{ {
qse_awk_nde_t* nde = QSE_NULL; qse_awk_nde_t* nde = QSE_NULL;
qse_cstr_t name[2]; /* TODO: support more than 2 segments??? */ 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) if (nsegs <= 1)
{ {
nde = parse_primary_ident_noseg (awk, xloc, &name[0]); 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 else
{ {
@ -5253,11 +5281,11 @@ static qse_awk_nde_t* parse_primary_ident (
full.len = capa; full.len = capa;
nde = parse_primary_ident_segs(awk, xloc, &full, name, nsegs); 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 /* the FNC node takes the full name but other
* nodes don't. so i need to free it. i know it's ugly. */ * 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 else
@ -5267,7 +5295,7 @@ static qse_awk_nde_t* parse_primary_ident (
} }
/* i don't need the name segments */ /* 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; 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: exit_func:
qse_awk_clrpt (awk, idx); qse_awk_clrpt (awk, idx);
QSE_AWK_FREE (awk, nde); qse_awk_freemem (awk, nde);
return QSE_NULL; return QSE_NULL;
} }
@ -5482,17 +5510,17 @@ make_node:
goto oops; 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->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->args = head;
call->nargs = nargs; call->nargs = nargs;
} }
else if (fnc) else if (fnc)
{ {
call->type = QSE_AWK_NDE_FNC; call->type = QSE_AWK_NDE_FNCALL_FNC;
call->loc = *xloc; call->loc = *xloc;
call->u.fnc.info.name.ptr = name->ptr; call->u.fnc.info.name.ptr = name->ptr;
@ -5516,7 +5544,7 @@ make_node:
} }
else else
{ {
call->type = QSE_AWK_NDE_FUN; call->type = QSE_AWK_NDE_FNCALL_FUN;
call->loc = *xloc; call->loc = *xloc;
call->u.fun.name.ptr = name->ptr; call->u.fun.name.ptr = name->ptr;
call->u.fun.name.len = name->len; call->u.fun.name.len = name->len;
@ -5534,7 +5562,7 @@ make_node:
return (qse_awk_nde_t*)call; return (qse_awk_nde_t*)call;
oops: oops:
if (call) QSE_AWK_FREE (awk, call); if (call) qse_awk_freemem (awk, call);
if (head) qse_awk_clrpt (awk, head); if (head) qse_awk_clrpt (awk, head);
return QSE_NULL; 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_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_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, qse_awk_rtx_t* run, qse_awk_nde_t* nde,
void(*errhandler)(void*), void* eharg); 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_fncall_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_fncall_fncall_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_var (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* __eval_call ( static qse_awk_val_t* __eval_call (
qse_awk_rtx_t* run, 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_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_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_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_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_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); 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 */ /* 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_FUN; call.type = QSE_AWK_NDE_FNCALL_FUN;
call.u.fun.name = fun->name; call.u.fun.name = fun->name;
call.nargs = nargs; 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_incpre,
eval_incpst, eval_incpst,
eval_cnd, eval_cnd,
eval_fnc, eval_fncall_fnc,
eval_fun, eval_fncall_fncall_fun,
eval_fcv, eval_fncall_var,
eval_int, eval_int,
eval_flt, eval_flt,
eval_str, eval_str,
eval_mbs, eval_mbs,
eval_rex, eval_rex,
eval_fun,
eval_named, eval_named,
eval_gbl, eval_gbl,
eval_lcl, 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_awk_val_t* v;
QSE_ASSERT (nde->type >= QSE_AWK_NDE_GRP && QSE_ASSERT (nde->type >= QSE_AWK_NDE_GRP && (nde->type - QSE_AWK_NDE_GRP) < QSE_COUNTOF(__evaluator));
(nde->type - QSE_AWK_NDE_GRP) < QSE_COUNTOF(__evaluator));
v = __evaluator[nde->type-QSE_AWK_NDE_GRP](run, nde); 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; 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 */ /* 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;
@ -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); 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_nde_fncall_t* call = (qse_awk_nde_fncall_t*)nde;
qse_awk_fun_t* fun; 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); 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_nde_fncall_t* call = (qse_awk_nde_fncall_t*)nde;
qse_awk_val_t* fv, * rv; 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; if (!fv) return QSE_NULL;
qse_awk_rtx_refupval (rtx, fv); qse_awk_rtx_refupval (rtx, fv);
if (QSE_AWK_RTX_GETVALTYPE(rtx, fv) != QSE_AWK_VAL_FUN) if (QSE_AWK_RTX_GETVALTYPE(rtx, fv) != QSE_AWK_VAL_FUN)
{ {
/*SETERR_ARGX_LOC (rtx, QSE_AWK_EFUNNF, &call->u.fun.name, &nde->loc);*/ SETERR_ARGX_LOC (rtx, QSE_AWK_ENOTFUN, &call->u.var.var->id.name, &nde->loc);
/*printf ("NOT FUNCTION VALUE\n");*/
rv = QSE_NULL; rv = QSE_NULL;
} }
else 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 ( v = qse_awk_rtx_makerefval (
rtx, p->type-QSE_AWK_NDE_NAMED, ref); rtx, p->type-QSE_AWK_NDE_NAMED, ref);
} }
else if (fnc_arg_spec && else if (fnc_arg_spec && fnc_arg_spec[nargs] == QSE_T('x'))
fnc_arg_spec[nargs] == QSE_T('x'))
{ {
/* a regular expression is passed to /* a regular expression is passed to
* the function as it is */ * 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); v = eval_expression(rtx, p);
} }
if (v == QSE_NULL) if (!v)
{ {
UNWIND_RTX_STACK_ARG (rtx, nargs); UNWIND_RTX_STACK_ARG (rtx, nargs);
return (qse_size_t)-1; 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; 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) static qse_awk_val_t* eval_named (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde)
{ {
qse_htb_pair_t* pair; 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; 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: case QSE_AWK_NDE_ARG:
{ {
qse_char_t tmp[QSE_SIZEOF(qse_awk_int_t)*8+2]; 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; break;
} }
case QSE_AWK_NDE_FNC: case QSE_AWK_NDE_FNCALL_FNC:
{ {
qse_awk_nde_fncall_t* px = (qse_awk_nde_fncall_t*)nde; 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); 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; break;
} }
case QSE_AWK_NDE_FUN: case QSE_AWK_NDE_FNCALL_FUN:
{ {
qse_awk_nde_fncall_t* px = (qse_awk_nde_fncall_t*)nde; 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); 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; break;
} }
case QSE_AWK_NDE_FCV: case QSE_AWK_NDE_FNCALL_VAR:
{ {
qse_awk_nde_fncall_t* px = (qse_awk_nde_fncall_t*)nde; 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("(")); PUT_SRCSTR (awk, QSE_T("("));
PRINT_EXPR_LIST (awk, px->args); PRINT_EXPR_LIST (awk, px->args);
PUT_SRCSTR (awk, QSE_T(")")); PUT_SRCSTR (awk, QSE_T(")"));
@ -1402,6 +1410,13 @@ void qse_awk_clrpt (qse_awk_t* awk, qse_awk_nde_t* tree)
break; 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_NAMED:
case QSE_AWK_NDE_GBL: case QSE_AWK_NDE_GBL:
case QSE_AWK_NDE_LCL: case QSE_AWK_NDE_LCL:
@ -1434,7 +1449,7 @@ void qse_awk_clrpt (qse_awk_t* awk, qse_awk_nde_t* tree)
break; 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_nde_fncall_t* px = (qse_awk_nde_fncall_t*)p;
/* QSE_AWK_FREE (awk, px->u.fnc); */ /* 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; 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_nde_fncall_t* px = (qse_awk_nde_fncall_t*)p;
QSE_AWK_FREE (awk, px->u.fun.name.ptr); 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; 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_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_clrpt (awk, px->args);
QSE_AWK_FREE (awk, p); QSE_AWK_FREE (awk, p);
break; 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_int_t qse_awk_nde_int_t;
typedef struct qse_awk_nde_flt_t qse_awk_nde_flt_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_str_t qse_awk_nde_str_t;
typedef struct qse_awk_nde_mbs_t qse_awk_nde_mbs_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_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_var_t qse_awk_nde_var_t;
typedef struct qse_awk_nde_fncall_t qse_awk_nde_fncall_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; 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 */ 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_NAMED, QSE_AWK_NDE_GBL,
* QSE_AWK_NDE_LCL, QSE_AWK_NDE_ARG * QSE_AWK_NDE_LCL, QSE_AWK_NDE_ARG
* QSE_AWK_NDE_NAMEDIDX, QSE_AWK_NDE_GBLIDX, * 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_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 struct qse_awk_nde_fncall_t
{ {
QSE_AWK_NDE_HDR; QSE_AWK_NDE_HDR;
@ -210,7 +219,7 @@ struct qse_awk_nde_fncall_t
struct struct
{ {
qse_awk_nde_var_t* var; qse_awk_nde_var_t* var;
} fcv; } var;
} u; } u;
qse_awk_nde_t* args; qse_awk_nde_t* args;
qse_size_t nargs; 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_awk_val_mbs_t* val = QSE_NULL;
qse_size_t xsz = len * QSE_SIZEOF(*ptr); 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) if (val == QSE_NULL)
{ {
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, 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. * the total size is just large enough for all these.
*/ */
totsz = QSE_SIZEOF(*val) + (QSE_SIZEOF(*str->ptr) * (str->len + 1)); 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) if (val == QSE_NULL)
{ {
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, 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 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) if (!val)
{ {
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL); 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; 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) if (!val)
{ {
qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOMEM, QSE_NULL); 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->v_type = QSE_AWK_VAL_FUN;
val->ref = 0;
val->stat = 0;
val->nstr = 0;
val->fun = (qse_awk_fun_t*)fun; val->fun = (qse_awk_fun_t*)fun;
return (qse_awk_val_t*)val; 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: case QSE_AWK_VAL_FUN:
/* nothing to do */ QSE_AWK_FREE (rtx->awk, val);
break; 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: 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: case QSE_AWK_VAL_FUN:
{ {
/* TODO: */ /* unable to convert a function to a number */
break; break;
} }
} }
@ -2163,7 +2166,7 @@ void qse_awk_dprintval (qse_awk_rtx_t* run, qse_awk_val_t* val)
break; break;
case QSE_AWK_VAL_FUN: 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; break;
default: default: