enhanced Awk and StdAwk to be able to handle argument reference

This commit is contained in:
hyung-hwan 2013-01-07 08:33:48 +00:00
parent d9f961c6c3
commit 2624acb308
7 changed files with 108 additions and 98 deletions

View File

@ -1085,7 +1085,7 @@ public:
typedef int (Awk::*FunctionHandler) ( typedef int (Awk::*FunctionHandler) (
Run& run, Run& run,
Value& ret, Value& ret,
const Value* args, Value* args,
size_t nargs, size_t nargs,
const fnc_info_t* fi const fnc_info_t* fi
); );
@ -1098,6 +1098,7 @@ public:
const char_t* name, ///< function name const char_t* name, ///< function name
size_t minArgs, ///< minimum numbers of arguments size_t minArgs, ///< minimum numbers of arguments
size_t maxArgs, ///< maximum numbers of arguments size_t maxArgs, ///< maximum numbers of arguments
const char_t* argSpec, ///< argument specification
FunctionHandler handler, ///< function handler FunctionHandler handler, ///< function handler
int validOpts = 0 ///< valid if these options are set int validOpts = 0 ///< valid if these options are set
); );

View File

@ -142,18 +142,18 @@ protected:
int __build_environ (Run* run, void* envptr); int __build_environ (Run* run, void* envptr);
// intrinsic functions // intrinsic functions
int rand (Run& run, Value& ret, const Value* args, size_t nargs, int rand (Run& run, Value& ret, Value* args, size_t nargs,
const char_t* name, size_t len); const char_t* name, size_t len);
int srand (Run& run, Value& ret, const Value* args, size_t nargs, int srand (Run& run, Value& ret, Value* args, size_t nargs,
const char_t* name, size_t len); const char_t* name, size_t len);
int system (Run& run, Value& ret, const Value* args, size_t nargs, int system (Run& run, Value& ret, Value* args, size_t nargs,
const char_t* name, size_t len); const char_t* name, size_t len);
qse_cmgr_t* getcmgr (const char_t* ioname); qse_cmgr_t* getcmgr (const char_t* ioname);
int setioattr (Run& run, Value& ret, const Value* args, size_t nargs, int setioattr (Run& run, Value& ret, Value* args, size_t nargs,
const char_t* name, size_t len); const char_t* name, size_t len);
int getioattr (Run& run, Value& ret, const Value* args, size_t nargs, int getioattr (Run& run, Value& ret, Value* args, size_t nargs,
const char_t* name, size_t len); const char_t* name, size_t len);
// pipe io handlers // pipe io handlers

View File

@ -23,9 +23,6 @@
#include "../cmn/mem.h" #include "../cmn/mem.h"
#include "awk.h" #include "awk.h"
// enable this once addFunction() is extended with argument spec (rxv...).
//#define PASS_BY_REFERENCE
///////////////////////////////// /////////////////////////////////
QSE_BEGIN_NAMESPACE(QSE) QSE_BEGIN_NAMESPACE(QSE)
///////////////////////////////// /////////////////////////////////
@ -1359,6 +1356,7 @@ void Awk::setMaxDepth (depth_t id, size_t depth)
int Awk::dispatch_function (Run* run, const fnc_info_t* fi) int Awk::dispatch_function (Run* run, const fnc_info_t* fi)
{ {
pair_t* pair; pair_t* pair;
bool has_ref_arg = false;
pair = qse_htb_search (functionMap, fi->name.ptr, fi->name.len); pair = qse_htb_search (functionMap, fi->name.ptr, fi->name.len);
if (pair == QSE_NULL) if (pair == QSE_NULL)
@ -1387,24 +1385,51 @@ int Awk::dispatch_function (Run* run, const fnc_info_t* fi)
for (i = 0; i < nargs; i++) for (i = 0; i < nargs; i++)
{ {
int xx;
val_t* v = qse_awk_rtx_getarg (run->rtx, i); val_t* v = qse_awk_rtx_getarg (run->rtx, i);
#ifdef PASS_BY_REFERENCE
QSE_ASSERT (v->type == QSE_AWK_VAL_REF); if (v->type == QSE_AWK_VAL_REF)
val_t** ref = (val_t**)((qse_awk_val_ref_t*)v)->adr; {
if (args[i].setVal (run, *ref) == -1) qse_awk_val_ref_t* ref = (qse_awk_val_ref_t*)v;
if (ref->id == qse_awk_val_ref_t::QSE_AWK_VAL_REF_POS)
{
qse_size_t idx = (qse_size_t)ref->adr;
if (idx == 0)
{
xx = args[i].setStr (run,
QSE_STR_PTR(&run->rtx->inrec.line),
QSE_STR_LEN(&run->rtx->inrec.line));
}
else if (idx <= run->rtx->inrec.nflds)
{
xx = args[i].setStr (run,
run->rtx->inrec.flds[idx-1].ptr,
run->rtx->inrec.flds[idx-1].len);
}
else
{
xx = args[i].setStr (run, QSE_T(""), 0);
}
}
else
{
xx = args[i].setVal (run, *(ref->adr));
}
has_ref_arg = true;
}
else
{
xx = args[i].setVal (run, v);
}
if (xx <= -1)
{ {
run->setError (QSE_AWK_ENOMEM); run->setError (QSE_AWK_ENOMEM);
if (args != buf) delete[] args; if (args != buf) delete[] args;
return -1; return -1;
} }
#else
if (args[i].setVal (run, v) == -1)
{
run->setError (QSE_AWK_ENOMEM);
if (args != buf) delete[] args;
return -1;
}
#endif
} }
Value ret (run); Value ret (run);
@ -1414,28 +1439,25 @@ int Awk::dispatch_function (Run* run, const fnc_info_t* fi)
try { n = (this->*handler) (*run, ret, args, nargs, fi); } try { n = (this->*handler) (*run, ret, args, nargs, fi); }
catch (...) { n = -1; } catch (...) { n = -1; }
#ifdef PASS_BY_REFERENCE if (n >= 0 && has_ref_arg)
if (n >= 0)
{ {
for (i = 0; i < nargs; i++) for (i = 0; i < nargs; i++)
{ {
QSE_ASSERTX (args[i].run == run, QSE_ASSERTX (args[i].run == run,
"Do NOT change Run from function handler"); "Do NOT change the run field from function handler");
val_t* v = qse_awk_rtx_getarg (run->rtx, i); val_t* v = qse_awk_rtx_getarg (run->rtx, i);
val_t* nv = args[i].toVal(); if (v->type == QSE_AWK_VAL_REF)
{
if (nv == v) continue; if (qse_awk_rtx_setrefval (run->rtx, (qse_awk_val_ref_t*)v, args[i].toVal()) <= -1)
{
QSE_ASSERT (v->type == QSE_AWK_VAL_REF); n = -1;
val_t** ref = (val_t**)((qse_awk_val_ref_t*)v)->adr; break;
}
qse_awk_rtx_refdownval (run->rtx, *ref); }
*ref = nv;
qse_awk_rtx_refupval (run->rtx, *ref);
} }
} }
#endif
if (args != buf) delete[] args; if (args != buf) delete[] args;
if (n <= -1) if (n <= -1)
@ -1559,7 +1581,7 @@ int Awk::getGlobal (int id, Value& v)
int Awk::addFunction ( int Awk::addFunction (
const char_t* name, size_t minArgs, size_t maxArgs, const char_t* name, size_t minArgs, size_t maxArgs,
FunctionHandler handler, int validOpts) const char_t* argSpec, FunctionHandler handler, int validOpts)
{ {
QSE_ASSERT (awk != QSE_NULL); QSE_ASSERT (awk != QSE_NULL);
@ -1578,9 +1600,7 @@ int Awk::addFunction (
QSE_MEMSET (&spec, 0, QSE_SIZEOF(spec)); QSE_MEMSET (&spec, 0, QSE_SIZEOF(spec));
spec.arg.min = minArgs; spec.arg.min = minArgs;
spec.arg.max = maxArgs; spec.arg.max = maxArgs;
#ifdef PASS_BY_REFERENCE spec.arg.spec = argSpec;
spec.arg.spec = QSE_T("R"); // pass all arguments by reference
#endif
spec.impl = functionHandler; spec.impl = functionHandler;
spec.trait = validOpts; spec.trait = validOpts;

View File

@ -73,17 +73,6 @@
QSE_BEGIN_NAMESPACE(QSE) QSE_BEGIN_NAMESPACE(QSE)
///////////////////////////////// /////////////////////////////////
#define ADDFNC(name,min,max,impl,vopts) \
do { \
if (addFunction (name, min, max, \
(FunctionHandler)impl, vopts) == -1) \
{ \
Awk::close (); \
return -1; \
} \
} while (0)
StdAwk::ioattr_t StdAwk::default_ioattr; StdAwk::ioattr_t StdAwk::default_ioattr;
static qse_sio_t* open_sio (Awk* awk, StdAwk::Run* run, const qse_char_t* file, int flags) static qse_sio_t* open_sio (Awk* awk, StdAwk::Run* run, const qse_char_t* file, int flags)
@ -141,11 +130,11 @@ int StdAwk::open ()
goto oops; goto oops;
} }
if (addFunction (QSE_T("rand"), 0, 0, (FunctionHandler)&StdAwk::rand, 0) <= -1 || if (addFunction (QSE_T("rand"), 0, 0, QSE_NULL, (FunctionHandler)&StdAwk::rand, 0) <= -1 ||
addFunction (QSE_T("srand"), 0, 1, (FunctionHandler)&StdAwk::srand, 0) <= -1 || addFunction (QSE_T("srand"), 0, 1, QSE_NULL, (FunctionHandler)&StdAwk::srand, 0) <= -1 ||
addFunction (QSE_T("system"), 1, 1, (FunctionHandler)&StdAwk::system, 0) <= -1 || addFunction (QSE_T("system"), 1, 1, QSE_NULL, (FunctionHandler)&StdAwk::system, 0) <= -1 ||
addFunction (QSE_T("setioattr"), 3, 3, (FunctionHandler)&StdAwk::setioattr, QSE_AWK_RIO) <= -1 || addFunction (QSE_T("setioattr"), 3, 3, QSE_NULL, (FunctionHandler)&StdAwk::setioattr, QSE_AWK_RIO) <= -1 ||
addFunction (QSE_T("getioattr"), 2, 2, (FunctionHandler)&StdAwk::getioattr, QSE_AWK_RIO) <= -1) addFunction (QSE_T("getioattr"), 3, 3, QSE_T("vvr"), (FunctionHandler)&StdAwk::getioattr, QSE_AWK_RIO) <= -1)
{ {
goto oops; goto oops;
} }
@ -348,7 +337,7 @@ int StdAwk::make_additional_globals (Run* run)
return 0; return 0;
} }
int StdAwk::rand (Run& run, Value& ret, const Value* args, size_t nargs, int StdAwk::rand (Run& run, Value& ret, Value* args, size_t nargs,
const char_t* name, size_t len) const char_t* name, size_t len)
{ {
#define RANDV_MAX QSE_TYPE_MAX(long_t) #define RANDV_MAX QSE_TYPE_MAX(long_t)
@ -358,7 +347,7 @@ int StdAwk::rand (Run& run, Value& ret, const Value* args, size_t nargs,
#undef RANDV_MAX #undef RANDV_MAX
} }
int StdAwk::srand (Run& run, Value& ret, const Value* args, size_t nargs, int StdAwk::srand (Run& run, Value& ret, Value* args, size_t nargs,
const char_t* name, size_t len) const char_t* name, size_t len)
{ {
long_t prevSeed = (long_t)this->seed; long_t prevSeed = (long_t)this->seed;
@ -384,7 +373,7 @@ int StdAwk::srand (Run& run, Value& ret, const Value* args, size_t nargs,
return ret.setInt ((long_t)prevSeed); return ret.setInt ((long_t)prevSeed);
} }
int StdAwk::system (Run& run, Value& ret, const Value* args, size_t nargs, int StdAwk::system (Run& run, Value& ret, Value* args, size_t nargs,
const char_t* name, size_t len) const char_t* name, size_t len)
{ {
size_t l; size_t l;
@ -457,7 +446,7 @@ static int timeout_code (const qse_char_t* name)
} }
int StdAwk::setioattr ( int StdAwk::setioattr (
Run& run, Value& ret, const Value* args, size_t nargs, Run& run, Value& ret, Value* args, size_t nargs,
const char_t* name, size_t len) const char_t* name, size_t len)
{ {
QSE_ASSERT (this->cmgrtab_inited == true); QSE_ASSERT (this->cmgrtab_inited == true);
@ -531,7 +520,7 @@ int StdAwk::setioattr (
} }
int StdAwk::getioattr ( int StdAwk::getioattr (
Run& run, Value& ret, const Value* args, size_t nargs, Run& run, Value& ret, Value* args, size_t nargs,
const char_t* name, size_t len) const char_t* name, size_t len)
{ {
QSE_ASSERT (this->cmgrtab_inited == true); QSE_ASSERT (this->cmgrtab_inited == true);
@ -541,34 +530,33 @@ int StdAwk::getioattr (
ptr[0] = args[0].toStr(&l[0]); ptr[0] = args[0].toStr(&l[0]);
ptr[1] = args[1].toStr(&l[1]); ptr[1] = args[1].toStr(&l[1]);
if (qse_strxchr (ptr[0], l[0], QSE_T('\0')) || int xx = -1;
qse_strxchr (ptr[1], l[1], QSE_T('\0')))
/* ionames must not contains a null character */
if (qse_strxchr (ptr[0], l[0], QSE_T('\0')) == QSE_NULL &&
qse_strxchr (ptr[1], l[1], QSE_T('\0')) == QSE_NULL)
{ {
return ret.setInt ((long_t)-1); ioattr_t* ioattr = get_ioattr (ptr[0], l[0]);
if (ioattr == QSE_NULL) ioattr = &StdAwk::default_ioattr;
int tmout;
if ((tmout = timeout_code(ptr[1])) >= 0)
{
if (ioattr->tmout[tmout].nsec == 0)
xx = args[2].setInt ((long_t)ioattr->tmout[tmout].sec);
else
xx = args[2].setFlt ((qse_flt_t)ioattr->tmout[tmout].sec + QSE_NSEC_TO_SEC((qse_flt_t)ioattr->tmout[tmout].nsec));
}
#if defined(QSE_CHAR_IS_WCHAR)
else if (qse_strcasecmp (ptr[1], QSE_T("codepage")) == 0)
{
xx = args[2].setStr (ioattr->cmgr_name);
}
#endif
} }
ioattr_t* ioattr = get_ioattr (ptr[0], l[0]); // unknown attribute name or errors
if (ioattr == QSE_NULL) ioattr = &StdAwk::default_ioattr; return ret.setInt ((long_t)xx);
int tmout;
if ((tmout = timeout_code(ptr[1])) >= 0)
{
if (ioattr->tmout[tmout].nsec == 0)
return ret.setInt ((long_t)ioattr->tmout[tmout].sec);
else
return ret.setFlt ((qse_flt_t)ioattr->tmout[tmout].sec + QSE_NSEC_TO_SEC((qse_flt_t)ioattr->tmout[tmout].nsec));
}
#if defined(QSE_CHAR_IS_WCHAR)
else if (qse_strcasecmp (ptr[1], QSE_T("codepage")) == 0)
{
return ret.setStr (ioattr->cmgr_name);
}
#endif
else
{
// unknown attribute name
return ret.setInt ((long_t)-1);
}
} }
int StdAwk::open_nwio (Pipe& io, int flags, void* nwad) int StdAwk::open_nwio (Pipe& io, int flags, void* nwad)

View File

@ -2520,15 +2520,13 @@ done:
while (i > 0) while (i > 0)
{ {
i--; i--;
if (v[i]->type != QSE_AWK_VAL_STR) if (v[i]->type != QSE_AWK_VAL_STR) QSE_AWK_FREE (rtx->awk, ptr[i]);
QSE_AWK_FREE (rtx->awk, ptr[i]);
} }
if (ret >= 0) if (ret >= 0)
{ {
if (rv) if (rv && qse_awk_rtx_setrefval (rtx, qse_awk_rtx_getarg (rtx, 2), rv) >= 0)
{ {
qse_awk_rtx_setrefval (rtx, qse_awk_rtx_getarg (rtx, 2), rv);
qse_awk_rtx_setretval (rtx, qse_awk_val_zero); qse_awk_rtx_setretval (rtx, qse_awk_val_zero);
} }
else else

View File

@ -1703,9 +1703,12 @@ but is this really necessary? i feel all these awk quarkiness is nasty..
*/ */
rref = (qse_awk_val_t**)ref->adr; rref = (qse_awk_val_t**)ref->adr;
qse_awk_rtx_refdownval (rtx, *rref); if (*rref != val)
*rref = val; {
qse_awk_rtx_refupval (rtx, *rref); qse_awk_rtx_refdownval (rtx, *rref);
*rref = val;
qse_awk_rtx_refupval (rtx, *rref);
}
return 0; return 0;
} }
} }

View File

@ -58,13 +58,13 @@ public:
/* this is for demonstration only. /* this is for demonstration only.
* you can use sys::sleep() instead */ * you can use sys::sleep() instead */
if (addFunction (QSE_T("sleep"), 1, 1, if (addFunction (QSE_T("sleep"), 1, 1, QSE_NULL,
(FunctionHandler)&MyAwk::sleep) <= -1) goto oops; (FunctionHandler)&MyAwk::sleep) <= -1) goto oops;
if (addFunction (QSE_T("sumintarray"), 1, 1, if (addFunction (QSE_T("sumintarray"), 1, 1, QSE_NULL,
(FunctionHandler)&MyAwk::sumintarray) <= -1) goto oops; (FunctionHandler)&MyAwk::sumintarray) <= -1) goto oops;
if (addFunction (QSE_T("arrayindices"), 1, 1, if (addFunction (QSE_T("arrayindices"), 1, 1, QSE_NULL,
(FunctionHandler)&MyAwk::arrayindices) <= -1) goto oops; (FunctionHandler)&MyAwk::arrayindices) <= -1) goto oops;
return 0; return 0;
@ -75,7 +75,7 @@ public:
} }
int sleep ( int sleep (
Run& run, Value& ret, const Value* args, size_t nargs, Run& run, Value& ret, Value* args, size_t nargs,
const char_t* name, size_t len) const char_t* name, size_t len)
{ {
if (args[0].isIndexed()) if (args[0].isIndexed())
@ -106,7 +106,7 @@ public:
} }
int sumintarray ( int sumintarray (
Run& run, Value& ret, const Value* args, size_t nargs, Run& run, Value& ret, Value* args, size_t nargs,
const char_t* name, size_t len) const char_t* name, size_t len)
{ {
// BEGIN { // BEGIN {
@ -138,7 +138,7 @@ public:
int arrayindices ( int arrayindices (
Run& run, Run& run,
Value& ret, Value& ret,
const Value* args, Value* args,
size_t nargs, size_t nargs,
const char_t* name, const char_t* name,
size_t len) size_t len)