From 11b9829c9b0aeb756cb8cfc8f1b0c713ed3342b5 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sat, 20 Oct 2012 15:58:20 +0000 Subject: [PATCH] added some code to support module calls using module-name::function-name syntax to awk. reorganized a few awk error code --- qse/include/qse/awk/awk.h | 94 +++-- qse/include/qse/awk/std.h | 2 +- qse/include/qse/cmn/glob.h | 24 +- qse/include/qse/cmn/tio.h | 10 +- qse/include/qse/sed/sed.h | 12 +- qse/include/qse/stx/stx.h | 8 +- qse/lib/awk/Makefile.am | 2 +- qse/lib/awk/Makefile.in | 2 +- qse/lib/awk/awk.c | 8 +- qse/lib/awk/awk.h | 9 +- qse/lib/awk/err.c | 14 +- qse/lib/awk/fnc.c | 6 +- qse/lib/awk/fnc.h | 3 +- qse/lib/awk/parse.c | 667 ++++++++++++++++++-------------- qse/lib/awk/rio.c | 26 +- qse/lib/awk/run.c | 15 +- qse/lib/awk/std.c | 137 ++++++- qse/lib/awk/tree.h | 2 +- qse/lib/cmn/glob.c | 14 +- qse/lib/cmn/tio.c | 4 +- qse/lib/net/httpd-std.c | 10 +- qse/lib/sed/sed.c | 5 +- qse/lib/sed/sed.h | 6 +- qse/lib/sed/std.c | 13 +- qse/regress/awk/lang-049.awk | 2 + qse/regress/awk/regress.out | 6 +- qse/regress/awk/regress.out.xma | 6 +- qse/regress/awk/regress.sh.in | 1 + qse/samples/awk/awk11.c | 2 +- 29 files changed, 670 insertions(+), 440 deletions(-) create mode 100644 qse/regress/awk/lang-049.awk diff --git a/qse/include/qse/awk/awk.h b/qse/include/qse/awk/awk.h index 2a5cca33..789ccb6b 100644 --- a/qse/include/qse/awk/awk.h +++ b/qse/include/qse/awk/awk.h @@ -418,9 +418,9 @@ typedef qse_bool_t (*qse_awk_isemptyrex_t) ( ); /** - * The qse_awk_fnc_fun_t type defines a intrinsic function handler. + * The qse_awk_fnc_impl_t type defines a intrinsic function handler. */ -typedef int (*qse_awk_fnc_fun_t) ( +typedef int (*qse_awk_fnc_impl_t) ( qse_awk_rtx_t* rtx, /**< runtime context */ const qse_cstr_t* name /**< function name */ ); @@ -472,9 +472,9 @@ struct qse_awk_sio_arg_t typedef struct qse_awk_sio_arg_t qse_awk_sio_arg_t; /** - * The qse_awk_sio_fun_t type defines a source IO function + * The qse_awk_sio_impl_t type defines a source IO function */ -typedef qse_ssize_t (*qse_awk_sio_fun_t) ( +typedef qse_ssize_t (*qse_awk_sio_impl_t) ( qse_awk_t* awk, qse_awk_sio_cmd_t cmd, qse_awk_sio_arg_t* arg, @@ -571,9 +571,9 @@ struct qse_awk_rio_arg_t typedef struct qse_awk_rio_arg_t qse_awk_rio_arg_t; /** - * The qse_awk_rio_fun_t type defines a runtime I/O handler. + * The qse_awk_rio_impl_t type defines a runtime I/O handler. */ -typedef qse_ssize_t (*qse_awk_rio_fun_t) ( +typedef qse_ssize_t (*qse_awk_rio_impl_t) ( qse_awk_rtx_t* rtx, qse_awk_rio_cmd_t cmd, qse_awk_rio_arg_t* riod, @@ -661,8 +661,8 @@ typedef struct qse_awk_prm_t qse_awk_prm_t; */ struct qse_awk_sio_t { - qse_awk_sio_fun_t in; /**< input script stream handler */ - qse_awk_sio_fun_t out; /**< output script stream handler */ + qse_awk_sio_impl_t in; /**< input script stream handler */ + qse_awk_sio_impl_t out; /**< output script stream handler */ }; typedef struct qse_awk_sio_t qse_awk_sio_t; @@ -674,14 +674,56 @@ typedef struct qse_awk_sio_t qse_awk_sio_t; */ struct qse_awk_rio_t { - qse_awk_rio_fun_t pipe; /**< pipe handler */ - qse_awk_rio_fun_t file; /**< file handler */ - qse_awk_rio_fun_t console; /**< console handler */ + qse_awk_rio_impl_t pipe; /**< pipe handler */ + qse_awk_rio_impl_t file; /**< file handler */ + qse_awk_rio_impl_t console; /**< console handler */ }; typedef struct qse_awk_rio_t qse_awk_rio_t; /* ------------------------------------------------------------------------ */ +typedef struct qse_awk_mod_t qse_awk_mod_t; +typedef struct qse_awk_mod_info_t qse_awk_mod_info_t; + +enum qse_awk_mod_type_t +{ + QSE_AWK_MOD_FNC = 0 /*, + QSE_AWK_MOD_VAR */ +}; +typedef enum qse_awk_mod_type_t qse_awk_mod_type_t; + +struct qse_awk_mod_info_t +{ + qse_awk_mod_type_t type; + union + { + struct + { + struct + { + int min; /* min. numbers of argument for a function */ + int max; /* max. numbers of argument for a function */ + } arg; + qse_awk_fnc_impl_t impl; + } f; + } u; +}; + +typedef int (*qse_awk_mod_query_t) ( + qse_awk_t* awk, + const qse_char_t* name, + qse_awk_mod_info_t* info +); + +struct qse_awk_mod_t +{ + qse_awk_mod_query_t query; + int (*init) (qse_awk_t* awk, qse_awk_rtx_t* rtx); + void (*fini) (qse_awk_t* awk, qse_awk_rtx_t* rtx); +}; + +/* ------------------------------------------------------------------------ */ + /** * The qse_awk_ecb_close_t type defines the callback function * called when an awk object is closed. @@ -973,15 +1015,15 @@ enum qse_awk_errnum_t QSE_AWK_EGBLTM, /**< too many global variables */ QSE_AWK_ELCLTM, /**< too many local variables */ QSE_AWK_EPARTM, /**< too many parameters */ - QSE_AWK_EDELETE, /**< 'delete' not followed by variable */ - QSE_AWK_ERESET, /**< 'reset' not followed by variable */ + QSE_AWK_ESEGTM, /**< too many identifier segments */ + QSE_AWK_EBADARG, /**< bad argument */ + QSE_AWK_ENOARG, /**< no argument */ QSE_AWK_EBREAK, /**< 'break' outside a loop */ QSE_AWK_ECONTINUE, /**< 'continue' outside a loop */ QSE_AWK_ENEXTBEG, /**< 'next' illegal in BEGIN block */ QSE_AWK_ENEXTEND, /**< 'next' illegal in END block */ QSE_AWK_ENEXTFBEG, /**< 'nextfile' illegal in BEGIN block */ QSE_AWK_ENEXTFEND, /**< 'nextfile' illegal in END block */ - QSE_AWK_EPRINTFARG,/**< 'printf' not followed by argument */ QSE_AWK_EPREPST, /**< both prefix and postfix incr/decr operator present */ QSE_AWK_EINCDECOPR,/**< illegal operand for incr/decr operator */ QSE_AWK_EINCLSTR, /**< 'include' not followed by a string */ @@ -1008,8 +1050,6 @@ enum qse_awk_errnum_t QSE_AWK_ESCALARTOMAP, /**< cannot change a scalar value to a map */ QSE_AWK_EMAPNA, /**< map not allowed */ QSE_AWK_EVALTYPE, /**< invalid value type */ - QSE_AWK_ERDELETE, /**< 'delete' called with wrong target */ - QSE_AWK_ERRESET, /**< 'reset' called with wrong target */ QSE_AWK_ERNEXTBEG, /**< 'next' called from BEGIN block */ QSE_AWK_ERNEXTEND, /**< 'next' called from END block */ QSE_AWK_ERNEXTFBEG, /**< 'nextfile' called from BEGIN block */ @@ -1247,9 +1287,9 @@ extern qse_awk_val_t* qse_awk_val_one; * @return a pointer to a qse_awk_t object on success, #QSE_NULL on failure. */ qse_awk_t* qse_awk_open ( - qse_mmgr_t* mmgr, /**< memory manager */ - qse_size_t xtn, /**< extension size in bytes */ - qse_awk_prm_t* prm /**< pointer to a primitive function structure */ + qse_mmgr_t* mmgr, /**< memory manager */ + qse_size_t xtnsize, /**< extension size in bytes */ + qse_awk_prm_t* prm /**< pointer to a primitive function structure */ ); /** @@ -1484,14 +1524,14 @@ int qse_awk_findgbl ( * The qse_awk_addfnc() function adds an intrinsic function. */ void* qse_awk_addfnc ( - qse_awk_t* awk, - const qse_char_t* name, - qse_size_t name_len, - int when_valid, - qse_size_t min_args, - qse_size_t max_args, - const qse_char_t* arg_spec, - qse_awk_fnc_fun_t handler + qse_awk_t* awk, + const qse_char_t* name, + qse_size_t name_len, + int when_valid, + qse_size_t min_args, + qse_size_t max_args, + const qse_char_t* arg_spec, + qse_awk_fnc_impl_t handler ); /** diff --git a/qse/include/qse/awk/std.h b/qse/include/qse/awk/std.h index 6c8d0eb2..7ee3a93e 100644 --- a/qse/include/qse/awk/std.h +++ b/qse/include/qse/awk/std.h @@ -163,7 +163,7 @@ int qse_awk_parsestd ( */ qse_awk_rtx_t* qse_awk_rtx_openstd ( qse_awk_t* awk, - qse_size_t xtn, + qse_size_t xtnsize, const qse_char_t* id, const qse_char_t* icf[], const qse_char_t* ocf[], diff --git a/qse/include/qse/cmn/glob.h b/qse/include/qse/cmn/glob.h index 355f56b4..6a3136fd 100644 --- a/qse/include/qse/cmn/glob.h +++ b/qse/include/qse/cmn/glob.h @@ -29,7 +29,7 @@ * in a path name. */ -typedef int (*qse_glob_cbfun_t) ( +typedef int (*qse_glob_cbimpl_t) ( const qse_cstr_t* path, void* cbctx ); @@ -54,24 +54,24 @@ extern "C" { /** * The qse_glob() function finds path names matchin the @a pattern. - * It calls the call-back function @a cbfun for each path name found. + * It calls the call-back function @a cbimpl for each path name found. * * @return -1 on failure, 0 on no match, 1 if matches are found. */ int qse_glob ( - const qse_char_t* pattern, - qse_glob_cbfun_t cbfun, - void* cbctx, - int flags, - qse_mmgr_t* mmgr + const qse_char_t* pattern, + qse_glob_cbimpl_t cbimpl, + void* cbctx, + int flags, + qse_mmgr_t* mmgr ); int qse_globwithcmgr ( - const qse_char_t* pattern, - qse_glob_cbfun_t cbfun, - void* cbctx, - int flags, - qse_mmgr_t* mmgr, + const qse_char_t* pattern, + qse_glob_cbimpl_t cbimpl, + void* cbctx, + int flags, + qse_mmgr_t* mmgr, qse_cmgr_t* cmgr ); diff --git a/qse/include/qse/cmn/tio.h b/qse/include/qse/cmn/tio.h index 39dc3213..9f2e3369 100644 --- a/qse/include/qse/cmn/tio.h +++ b/qse/include/qse/cmn/tio.h @@ -81,9 +81,9 @@ enum qse_tio_misc_t typedef struct qse_tio_t qse_tio_t; /** - * The qse_tio_io_fun_t types define a text I/O handler. + * The qse_tio_io_impl_t types define a text I/O handler. */ -typedef qse_ssize_t (*qse_tio_io_fun_t) ( +typedef qse_ssize_t (*qse_tio_io_impl_t) ( qse_tio_t* tio, qse_tio_cmd_t cmd, void* data, @@ -92,7 +92,7 @@ typedef qse_ssize_t (*qse_tio_io_fun_t) ( struct qse_tio_io_t { - qse_tio_io_fun_t fun; + qse_tio_io_impl_t fun; struct { qse_size_t capa; @@ -200,7 +200,7 @@ void qse_tio_setcmgr ( */ int qse_tio_attachin ( qse_tio_t* tio, - qse_tio_io_fun_t input, + qse_tio_io_impl_t input, qse_mchar_t* bufptr, qse_size_t bufcapa ); @@ -219,7 +219,7 @@ int qse_tio_detachin ( */ int qse_tio_attachout ( qse_tio_t* tio, - qse_tio_io_fun_t output, + qse_tio_io_impl_t output, qse_mchar_t* bufptr, qse_size_t bufcapa ); diff --git a/qse/include/qse/sed/sed.h b/qse/include/qse/sed/sed.h index d4620b2b..fc85539b 100644 --- a/qse/include/qse/sed/sed.h +++ b/qse/include/qse/sed/sed.h @@ -61,7 +61,7 @@ * * The input and output streams needed by qse_sed_exec() are implemented in * the form of callback functions. You should implement two functions - * conforming to the ::qse_sed_io_fun_t type. + * conforming to the ::qse_sed_io_impl_t type. */ typedef struct qse_sed_t qse_sed_t; @@ -324,10 +324,10 @@ struct qse_sed_io_arg_t typedef struct qse_sed_io_arg_t qse_sed_io_arg_t; /** - * The qse_sed_io_fun_t type defines an I/O handler. I/O handlers are called by + * The qse_sed_io_impl_t type defines an I/O handler. I/O handlers are called by * qse_sed_exec(). */ -typedef qse_ssize_t (*qse_sed_io_fun_t) ( +typedef qse_ssize_t (*qse_sed_io_impl_t) ( qse_sed_t* sed, qse_sed_io_cmd_t cmd, qse_sed_io_arg_t* arg, @@ -564,7 +564,7 @@ void qse_sed_pushecb ( */ int qse_sed_comp ( qse_sed_t* sed, /**< stream editor */ - qse_sed_io_fun_t inf /**< script stream reader */ + qse_sed_io_impl_t inf /**< script stream reader */ ); /** @@ -573,8 +573,8 @@ int qse_sed_comp ( */ int qse_sed_exec ( qse_sed_t* sed, /**< stream editor */ - qse_sed_io_fun_t inf, /**< stream reader */ - qse_sed_io_fun_t outf /**< stream writer */ + qse_sed_io_impl_t inf, /**< stream reader */ + qse_sed_io_impl_t outf /**< stream writer */ ); /** diff --git a/qse/include/qse/stx/stx.h b/qse/include/qse/stx/stx.h index a77202a1..ede3c714 100644 --- a/qse/include/qse/stx/stx.h +++ b/qse/include/qse/stx/stx.h @@ -64,9 +64,9 @@ struct qse_stx_io_arg_t typedef struct qse_stx_io_arg_t qse_stx_io_arg_t; /** - * The qse_stx_io_fun_t type defines an I/O handler function. + * The qse_stx_io_impl_t type defines an I/O handler function. */ -typedef qse_ssize_t (*qse_stx_io_fun_t) ( +typedef qse_ssize_t (*qse_stx_io_impl_t) ( qse_stx_t* stx, qse_stx_io_cmd_t cmd, qse_stx_io_arg_t* arg, @@ -79,8 +79,8 @@ typedef qse_ssize_t (*qse_stx_io_fun_t) ( */ struct qse_stx_io_t { - qse_stx_io_fun_t in; - qse_stx_io_fun_t out; + qse_stx_io_impl_t in; + qse_stx_io_impl_t out; }; typedef struct qse_stx_io_t qse_stx_io_t; diff --git a/qse/lib/awk/Makefile.am b/qse/lib/awk/Makefile.am index 3d305b50..8085e5ce 100644 --- a/qse/lib/awk/Makefile.am +++ b/qse/lib/awk/Makefile.am @@ -8,7 +8,7 @@ AM_CPPFLAGS = \ lib_LTLIBRARIES = libqseawk.la libqseawk_la_SOURCES = awk.c err.c tree.c parse.c run.c rec.c val.c fnc.c misc.c rio.c std.c awk.h err.h rio.h val.h fnc.h misc.h parse.h run.h tree.h libqseawk_la_LDFLAGS = -L../cmn -L$(libdir) -version-info 1:0:0 -no-undefined -libqseawk_la_LIBADD = -lqsecmn $(LIBM) +libqseawk_la_LIBADD = -lqsecmn $(LIBM) -lltdl if ENABLE_CXX lib_LTLIBRARIES += libqseawkxx.la diff --git a/qse/lib/awk/Makefile.in b/qse/lib/awk/Makefile.in index 25e0f145..fa356a53 100644 --- a/qse/lib/awk/Makefile.in +++ b/qse/lib/awk/Makefile.in @@ -295,7 +295,7 @@ AM_CPPFLAGS = \ lib_LTLIBRARIES = libqseawk.la $(am__append_1) $(am__append_2) libqseawk_la_SOURCES = awk.c err.c tree.c parse.c run.c rec.c val.c fnc.c misc.c rio.c std.c awk.h err.h rio.h val.h fnc.h misc.h parse.h run.h tree.h libqseawk_la_LDFLAGS = -L../cmn -L$(libdir) -version-info 1:0:0 -no-undefined -libqseawk_la_LIBADD = -lqsecmn $(LIBM) +libqseawk_la_LIBADD = -lqsecmn $(LIBM) -lltdl @ENABLE_CXX_TRUE@libqseawkxx_la_SOURCES = Awk.cpp StdAwk.cpp @ENABLE_CXX_TRUE@libqseawkxx_la_LDFLAGS = -L. -L../cmn -L$(libdir) -version-info 1:0:0 -no-undefined @ENABLE_CXX_TRUE@libqseawkxx_la_LIBADD = -lqseawk -lqsecmn $(LIBM) diff --git a/qse/lib/awk/awk.c b/qse/lib/awk/awk.c index bd7be116..4c510d82 100644 --- a/qse/lib/awk/awk.c +++ b/qse/lib/awk/awk.c @@ -72,7 +72,7 @@ static void clear_token (qse_awk_tok_t* tok) tok->loc.colm = 0; } -qse_awk_t* qse_awk_open (qse_mmgr_t* mmgr, qse_size_t xtn, qse_awk_prm_t* prm) +qse_awk_t* qse_awk_open (qse_mmgr_t* mmgr, qse_size_t xtnsize, qse_awk_prm_t* prm) { qse_awk_t* awk; @@ -109,11 +109,11 @@ qse_awk_t* qse_awk_open (qse_mmgr_t* mmgr, qse_size_t xtn, qse_awk_prm_t* prm) }; /* allocate the object */ - awk = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_awk_t) + xtn); + awk = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(qse_awk_t) + xtnsize); if (awk == QSE_NULL) return QSE_NULL; - /* zero out the object */ - QSE_MEMSET (awk, 0, QSE_SIZEOF(qse_awk_t) + xtn); + /* zero out the object + extension area */ + QSE_MEMSET (awk, 0, QSE_SIZEOF(qse_awk_t) + xtnsize); /* remember the memory manager */ awk->mmgr = mmgr; diff --git a/qse/lib/awk/awk.h b/qse/lib/awk/awk.h index 2dd0c373..13b9ccbe 100644 --- a/qse/lib/awk/awk.h +++ b/qse/lib/awk/awk.h @@ -174,8 +174,8 @@ struct qse_awk_t /* source code management */ struct { - qse_awk_sio_fun_t inf; - qse_awk_sio_fun_t outf; + qse_awk_sio_impl_t inf; + qse_awk_sio_impl_t outf; qse_awk_sio_lxc_t last; @@ -236,6 +236,7 @@ struct qse_awk_t qse_bool_t stopall; qse_awk_ecb_t* ecb; + qse_awk_mod_t* mod; }; struct qse_awk_chain_t @@ -340,7 +341,7 @@ struct qse_awk_rtx_t /* rio chain */ struct { - qse_awk_rio_fun_t handler[QSE_AWK_RIO_NUM]; + qse_awk_rio_impl_t handler[QSE_AWK_RIO_NUM]; qse_awk_rio_arg_t* chain; } rio; @@ -352,7 +353,7 @@ struct qse_awk_rtx_t struct { qse_char_t* ptr; - qse_size_t len; /* length */ + qse_size_t len; /* length */ qse_size_t inc; /* increment */ } tmp; } format; diff --git a/qse/lib/awk/err.c b/qse/lib/awk/err.c index 24831efe..2e8cf8c3 100644 --- a/qse/lib/awk/err.c +++ b/qse/lib/awk/err.c @@ -88,15 +88,15 @@ const qse_char_t* qse_awk_dflerrstr (const qse_awk_t* awk, qse_awk_errnum_t errn QSE_T("too many global variables"), QSE_T("too many local variables"), QSE_T("too many parameters"), - QSE_T("'delete' not followed by variable"), - QSE_T("'reset' not followed by variable"), + QSE_T("too many identifier segments"), + QSE_T("bad argument"), + QSE_T("no argument provided"), QSE_T("'break' outside a loop"), QSE_T("'continue' outside a loop"), QSE_T("'next' illegal in the BEGIN block"), QSE_T("'next' illegal in the END block"), QSE_T("'nextfile' illegal in the BEGIN block"), QSE_T("'nextfile' illegal in the END block"), - QSE_T("'printf' not followed by argument"), QSE_T("both prefix and postfix increment/decrement operator present"), QSE_T("illegal operand for increment/decrement operator"), QSE_T("'include' not followed by a string"), @@ -116,20 +116,18 @@ const qse_char_t* qse_awk_dflerrstr (const qse_awk_t* awk, qse_awk_errnum_t errn QSE_T("right-hand side of the 'in' operator not a map nor nil"), QSE_T("value not referenceable"), QSE_T("value not assignable"), - QSE_T("an indexed value cannot be assigned a map"), - QSE_T("a positional value cannot be assigned a map"), + QSE_T("indexed value cannot be assigned a map"), + QSE_T("positional value cannot be assigned a map"), QSE_T("map '${0}' not assignable with a scalar"), QSE_T("cannot change a scalar value to a map"), QSE_T("map not allowed"), QSE_T("invalid value type"), - QSE_T("'delete' called with wrong target"), - QSE_T("'reset' called with wrong target"), QSE_T("'next' called from BEGIN block"), QSE_T("'next' called from END block"), QSE_T("'nextfile' called from BEGIN block"), QSE_T("'nextfile' called from END block"), QSE_T("intrinsic function handler for '${0}' failed"), - QSE_T("wrong implementation of user-defined io handler"), + QSE_T("wrong implementation of user-defined I/O handler"), QSE_T("I/O handler returned an error"), QSE_T("no such I/O name found"), QSE_T("I/O name empty"), diff --git a/qse/lib/awk/fnc.c b/qse/lib/awk/fnc.c index f7faa601..bf5bb257 100644 --- a/qse/lib/awk/fnc.c +++ b/qse/lib/awk/fnc.c @@ -99,7 +99,7 @@ void* qse_awk_addfnc ( int when_valid, qse_size_t min_args, qse_size_t max_args, const qse_char_t* arg_spec, - qse_awk_fnc_fun_t handler) + qse_awk_fnc_impl_t handler) { qse_awk_fnc_t* fnc; qse_size_t fnc_size; @@ -111,6 +111,10 @@ void* qse_awk_addfnc ( return QSE_NULL; } + /* Note it doesn't check if it conflicts with a keyword. + * such a function registered won't take effect because + * the word is treated as a keyword */ + if (qse_awk_getfnc (awk, name, name_len) != QSE_NULL) { qse_cstr_t errarg; diff --git a/qse/lib/awk/fnc.h b/qse/lib/awk/fnc.h index 03641290..427e6742 100644 --- a/qse/lib/awk/fnc.h +++ b/qse/lib/awk/fnc.h @@ -22,7 +22,6 @@ #define _QSE_LIB_AWK_FNC_H_ typedef struct qse_awk_fnc_t qse_awk_fnc_t; - struct qse_awk_fnc_t { struct @@ -42,7 +41,7 @@ struct qse_awk_fnc_t qse_char_t* spec; } arg; - qse_awk_fnc_fun_t handler; + qse_awk_fnc_impl_t handler; /*qse_awk_fnc_t* next;*/ }; diff --git a/qse/lib/awk/parse.c b/qse/lib/awk/parse.c index a902e595..e14db459 100644 --- a/qse/lib/awk/parse.c +++ b/qse/lib/awk/parse.c @@ -28,7 +28,7 @@ enum tok_t /* special token to direct the parser to include a file specified */ TOK_INCLUDE, - /* TOK_XXX_ASSNs should in sync + /* TOK_XXX_ASSNs should be in sync * with assop in assign_to_opcode */ TOK_ASSN, TOK_PLUS_ASSN, @@ -44,6 +44,7 @@ enum tok_t TOK_BAND_ASSN, TOK_BXOR_ASSN, TOK_BOR_ASSN, + /* end of TOK_XXX_ASSN */ TOK_EQ, TOK_NE, @@ -84,9 +85,11 @@ enum tok_t TOK_COMMA, TOK_SEMICOLON, TOK_COLON, + TOK_DBLCOLON, TOK_QUEST, TOK_ATSIGN, + /* == begin reserved words == */ TOK_BEGIN, TOK_END, TOK_FUNCTION, @@ -113,6 +116,8 @@ enum tok_t TOK_PRINTF, TOK_GETLINE, + /* == end reserved words == */ + TOK_IDENT, TOK_INT, TOK_FLT, @@ -217,7 +222,7 @@ static qse_awk_nde_t* parse_hashidx ( qse_awk_t* awk, qse_char_t* name, qse_size_t namelen, const qse_awk_loc_t* xloc); static qse_awk_nde_t* parse_fncall ( - qse_awk_t* awk, qse_char_t* name, qse_size_t namelen, + qse_awk_t* awk, const qse_xstr_t* name, qse_awk_fnc_t* fnc, const qse_awk_loc_t* xloc, int noarg); static int get_token (qse_awk_t* awk); @@ -359,6 +364,7 @@ static global_t gtab[] = } while (0) #define MATCH(awk,tok_type) ((awk)->tok.type == (tok_type)) +#define MATCH_RANGE(awk,tok_type_start,tok_type_end) ((awk)->tok.type >= (tok_type_start) && (awk)->tok.type <= (tok_type_end)) #define MATCH_TERMINATOR_NORMAL(awk) \ (MATCH((awk),TOK_SEMICOLON) || MATCH((awk),TOK_NEWLINE)) @@ -1043,19 +1049,18 @@ retry: static qse_awk_nde_t* parse_function (qse_awk_t* awk) { - qse_char_t* name; - qse_char_t* namedup; - qse_size_t namelen; + qse_xstr_t name; qse_awk_nde_t* body; qse_awk_fun_t* fun; qse_size_t nargs, g; qse_htb_pair_t* pair; + int rederr; /* eat up the keyword 'function' and get the next token */ QSE_ASSERT (MATCH(awk,TOK_FUNCTION)); if (get_token(awk) <= -1) return QSE_NULL; - /* match a function name */ + /* check if an identifier is in place */ if (!MATCH(awk,TOK_IDENT)) { /* cannot find a valid identifier for a function name */ @@ -1063,46 +1068,27 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk) return QSE_NULL; } - name = QSE_STR_PTR(awk->tok.name); - namelen = QSE_STR_LEN(awk->tok.name); - - /* check if it is a builtin function */ - if (qse_awk_getfnc (awk, name, namelen) != QSE_NULL) + name.len = QSE_STR_LEN(awk->tok.name); + name.ptr = QSE_STR_PTR(awk->tok.name); + + /* note that i'm assigning to rederr in the 'if' conditions below. + * i'm not checking equality */ + /* check if it is a builtin function */ + if ((qse_awk_getfnc (awk, name.ptr, name.len) != QSE_NULL && (rederr = QSE_AWK_EFNCRED)) || + /* check if it has already been defined as a function */ + (qse_htb_search (awk->tree.funs, name.ptr, name.len) != QSE_NULL && (rederr = QSE_AWK_EFUNRED)) || + /* check if it conflicts with a named variable */ + (qse_htb_search (awk->parse.named, name.ptr, name.len) != QSE_NULL && (rederr = QSE_AWK_EVARRED)) || + /* check if it coincides to be a global variable name */ + (((g = find_global (awk, name.ptr, name.len)) != QSE_LDA_NIL) && (rederr = QSE_AWK_EGBLRED))) { - SETERR_ARG_LOC ( - awk, QSE_AWK_EFNCRED, name, namelen, &awk->tok.loc); + SETERR_ARG_LOC (awk, rederr, name.ptr, name.len, &awk->tok.loc); return QSE_NULL; } - /* check if it has already been defined as a function */ - if (qse_htb_search (awk->tree.funs, name, namelen) != QSE_NULL) - { - /* the function is defined previously */ - SETERR_ARG_LOC ( - awk, QSE_AWK_EFUNRED, name, namelen, &awk->tok.loc); - return QSE_NULL; - } - - /* check if it conflicts with a named variable */ - if (qse_htb_search (awk->parse.named, name, namelen) != QSE_NULL) - { - SETERR_ARG_LOC ( - awk, QSE_AWK_EVARRED, name, namelen, &awk->tok.loc); - return QSE_NULL; - } - - /* check if it coincides to be a global variable name */ - g = find_global (awk, name, namelen); - if (g != QSE_LDA_NIL) - { - SETERR_ARG_LOC ( - awk, QSE_AWK_EGBLRED, name, namelen, &awk->tok.loc); - return QSE_NULL; - } - - /* clone the function name before it is overwritten */ - namedup = QSE_AWK_STRXDUP (awk, name, namelen); - if (namedup == QSE_NULL) + /* duplicate the name before it's overridden by get_token() */ + name.ptr = qse_strxdup (name.ptr, name.len, awk->mmgr); + if (name.ptr == QSE_NULL) { SETERR_LOC (awk, QSE_AWK_ENOMEM, &awk->tok.loc); return QSE_NULL; @@ -1111,7 +1097,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk) /* get the next token */ if (get_token(awk) <= -1) { - QSE_AWK_FREE (awk, namedup); + QSE_AWK_FREE (awk, name.ptr); return QSE_NULL; } @@ -1119,15 +1105,15 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk) if (!MATCH(awk,TOK_LPAREN)) { /* a function name is not followed by a left parenthesis */ - QSE_AWK_FREE (awk, namedup); SETERR_TOK (awk, QSE_AWK_ELPAREN); + QSE_AWK_FREE (awk, name.ptr); return QSE_NULL; } /* get the next token */ if (get_token(awk) <= -1) { - QSE_AWK_FREE (awk, namedup); + QSE_AWK_FREE (awk, name.ptr); return QSE_NULL; } @@ -1140,7 +1126,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, namedup); + QSE_AWK_FREE (awk, name.ptr); return QSE_NULL; } } @@ -1153,7 +1139,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk) if (!MATCH(awk,TOK_IDENT)) { - QSE_AWK_FREE (awk, namedup); + QSE_AWK_FREE (awk, name.ptr); qse_lda_clear (awk->parse.params); SETERR_TOK (awk, QSE_AWK_EBADPAR); return QSE_NULL; @@ -1173,12 +1159,10 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk) /* check if a parameter conflicts with the function * name or other parameters */ if (((awk->option & QSE_AWK_STRICTNAMING) && - qse_strxncmp ( - pa, pal, namedup, namelen) == 0) || - qse_lda_search (awk->parse.params, - 0, pa, pal) != QSE_LDA_NIL) + qse_strxncmp (pa, pal, name.ptr, name.len) == 0) || + qse_lda_search (awk->parse.params, 0, pa, pal) != QSE_LDA_NIL) { - QSE_AWK_FREE (awk, namedup); + QSE_AWK_FREE (awk, name.ptr); qse_lda_clear (awk->parse.params); SETERR_ARG_LOC ( awk, QSE_AWK_EDUPPAR, @@ -1189,7 +1173,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk) /* push the parameter to the parameter list */ if (QSE_LDA_SIZE(awk->parse.params) >= QSE_AWK_MAX_PARAMS) { - QSE_AWK_FREE (awk, namedup); + QSE_AWK_FREE (awk, name.ptr); qse_lda_clear (awk->parse.params); SETERR_LOC (awk, QSE_AWK_EPARTM, &awk->tok.loc); return QSE_NULL; @@ -1200,7 +1184,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk) QSE_LDA_SIZE(awk->parse.params), pa, pal) == QSE_LDA_NIL) { - QSE_AWK_FREE (awk, namedup); + QSE_AWK_FREE (awk, name.ptr); qse_lda_clear (awk->parse.params); SETERR_LOC (awk, QSE_AWK_ENOMEM, &awk->tok.loc); return QSE_NULL; @@ -1208,7 +1192,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk) if (get_token (awk) <= -1) { - QSE_AWK_FREE (awk, namedup); + QSE_AWK_FREE (awk, name.ptr); qse_lda_clear (awk->parse.params); return QSE_NULL; } @@ -1217,7 +1201,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk) if (!MATCH(awk,TOK_COMMA)) { - QSE_AWK_FREE (awk, namedup); + QSE_AWK_FREE (awk, name.ptr); qse_lda_clear (awk->parse.params); SETERR_TOK (awk, QSE_AWK_ECOMMA); return QSE_NULL; @@ -1227,7 +1211,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk) { if (get_token(awk) <= -1) { - QSE_AWK_FREE (awk, namedup); + QSE_AWK_FREE (awk, name.ptr); qse_lda_clear (awk->parse.params); return QSE_NULL; } @@ -1237,7 +1221,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk) if (get_token(awk) <= -1) { - QSE_AWK_FREE (awk, namedup); + QSE_AWK_FREE (awk, name.ptr); qse_lda_clear (awk->parse.params); return QSE_NULL; } @@ -1251,7 +1235,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk) { if (get_token(awk) <= -1) { - QSE_AWK_FREE (awk, namedup); + QSE_AWK_FREE (awk, name.ptr); qse_lda_clear (awk->parse.params); return QSE_NULL; } @@ -1260,7 +1244,7 @@ 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, namedup); + QSE_AWK_FREE (awk, name.ptr); qse_lda_clear (awk->parse.params); SETERR_TOK (awk, QSE_AWK_ELBRACE); @@ -1268,15 +1252,15 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk) } if (get_token(awk) <= -1) { - QSE_AWK_FREE (awk, namedup); + QSE_AWK_FREE (awk, name.ptr); qse_lda_clear (awk->parse.params); return QSE_NULL; } /* remember the current function name so that the body parser * can know the name of the current function being parsed */ - awk->tree.cur_fun.ptr = namedup; - awk->tree.cur_fun.len = namelen; + awk->tree.cur_fun.ptr = name.ptr; + awk->tree.cur_fun.len = name.len; /* actual function body */ { @@ -1290,7 +1274,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk) if (body == QSE_NULL) { - QSE_AWK_FREE (awk, namedup); + QSE_AWK_FREE (awk, name.ptr); qse_lda_clear (awk->parse.params); return QSE_NULL; } @@ -1304,7 +1288,7 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk) fun = (qse_awk_fun_t*) QSE_AWK_ALLOC (awk, QSE_SIZEOF(qse_awk_fun_t)); if (fun == QSE_NULL) { - QSE_AWK_FREE (awk, namedup); + QSE_AWK_FREE (awk, name.ptr); qse_awk_clrpt (awk, body); SETERR_LOC (awk, QSE_AWK_ENOMEM, &awk->tok.loc); return QSE_NULL; @@ -1315,13 +1299,13 @@ static qse_awk_nde_t* parse_function (qse_awk_t* awk) fun->nargs = nargs; fun->body = body; - pair = qse_htb_insert (awk->tree.funs, namedup, namelen, fun, 0); + pair = qse_htb_insert (awk->tree.funs, name.ptr, name.len, fun, 0); if (pair == QSE_NULL) { /* 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, namedup); + QSE_AWK_FREE (awk, name.ptr); qse_awk_clrpt (awk, body); QSE_AWK_FREE (awk, fun); SETERR_LOC (awk, QSE_AWK_ENOMEM, &awk->tok.loc); @@ -1332,10 +1316,10 @@ 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, namedup); + QSE_AWK_FREE (awk, name.ptr); /* remove an undefined function call entry from the parse.fun table */ - qse_htb_delete (awk->parse.funs, fun->name.ptr, namelen); + qse_htb_delete (awk->parse.funs, fun->name.ptr, name.len); return body; } @@ -2633,26 +2617,49 @@ static qse_awk_nde_t* parse_nextfile ( static qse_awk_nde_t* parse_delete (qse_awk_t* awk, const qse_awk_loc_t* xloc) { qse_awk_nde_delete_t* nde; - qse_awk_nde_t* var; + qse_awk_nde_t* var = QSE_NULL; qse_awk_loc_t dloc; + qse_awk_nde_type_t type; + int inparen = 0; + + QSE_ASSERT (awk->ptok.type == TOK_DELETE || + awk->ptok.type == TOK_RESET); + + type = (awk->ptok.type == TOK_DELETE)? + QSE_AWK_NDE_DELETE: QSE_AWK_NDE_RESET; + + if (MATCH(awk,TOK_LPAREN)) + { + if (get_token(awk) <= -1) goto oops; + inparen = 1; + } - QSE_ASSERT (awk->ptok.type == TOK_DELETE); if (!MATCH(awk,TOK_IDENT)) { SETERR_TOK (awk, QSE_AWK_EIDENT); - return QSE_NULL; + goto oops; } dloc = awk->tok.loc; var = parse_primary_ident (awk, &dloc); - if (var == QSE_NULL) return QSE_NULL; + if (var == QSE_NULL) goto oops; - if (!is_var (var)) + if ((type == QSE_AWK_NDE_DELETE && !is_var (var)) || + (type == QSE_AWK_NDE_RESET && !is_plain_var (var))) { - /* a normal identifier is expected */ - qse_awk_clrpt (awk, var); - SETERR_LOC (awk, QSE_AWK_EDELETE, &dloc); - return QSE_NULL; + SETERR_LOC (awk, QSE_AWK_EBADARG, &dloc); + goto oops; + } + + if (inparen) + { + if (!MATCH(awk,TOK_RPAREN)) + { + SETERR_TOK (awk, QSE_AWK_ERPAREN); + goto oops; + } + + if (get_token(awk) <= -1) goto oops; } nde = (qse_awk_nde_delete_t*) QSE_AWK_ALLOC ( @@ -2660,66 +2667,35 @@ static qse_awk_nde_t* parse_delete (qse_awk_t* awk, const qse_awk_loc_t* xloc) if (nde == QSE_NULL) { SETERR_LOC (awk, QSE_AWK_ENOMEM, xloc); - return QSE_NULL; + goto oops; } - nde->type = QSE_AWK_NDE_DELETE; + nde->type = type; nde->loc = *xloc; nde->next = QSE_NULL; nde->var = var; return (qse_awk_nde_t*)nde; + +oops: + if (var) qse_awk_clrpt (awk, var); + return QSE_NULL; } -static qse_awk_nde_t* parse_reset (qse_awk_t* awk, const qse_awk_loc_t* xloc) -{ - qse_awk_nde_reset_t* nde; - qse_awk_nde_t* var; - qse_awk_loc_t rloc; - - QSE_ASSERT (awk->ptok.type == TOK_RESET); - if (!MATCH(awk,TOK_IDENT)) - { - SETERR_TOK (awk, QSE_AWK_EIDENT); - return QSE_NULL; - } - - rloc = awk->tok.loc; - var = parse_primary_ident (awk, &rloc); - if (var == QSE_NULL) return QSE_NULL; - - /* unlike delete, it must be followed by a plain variable only */ - if (!is_plain_var (var)) - { - /* a normal identifier is expected */ - qse_awk_clrpt (awk, var); - SETERR_LOC (awk, QSE_AWK_ERESET, &rloc); - return QSE_NULL; - } - - nde = (qse_awk_nde_reset_t*) QSE_AWK_ALLOC ( - awk, QSE_SIZEOF(qse_awk_nde_reset_t)); - if (nde == QSE_NULL) - { - SETERR_LOC (awk, QSE_AWK_ENOMEM, xloc); - return QSE_NULL; - } - - nde->type = QSE_AWK_NDE_RESET; - nde->loc = *xloc; - nde->next = QSE_NULL; - nde->var = var; - - return (qse_awk_nde_t*)nde; -} - -static qse_awk_nde_t* parse_print ( - qse_awk_t* awk, const qse_awk_loc_t* xloc, int type) +static qse_awk_nde_t* parse_print (qse_awk_t* awk, const qse_awk_loc_t* xloc) { qse_awk_nde_print_t* nde; qse_awk_nde_t* args = QSE_NULL; qse_awk_nde_t* out = QSE_NULL; int out_type; + qse_awk_nde_type_t type; + qse_awk_loc_t eloc; + + QSE_ASSERT (awk->ptok.type == TOK_PRINT || + awk->ptok.type == TOK_PRINTF); + + type = (awk->ptok.type == TOK_PRINT)? + QSE_AWK_NDE_PRINT: QSE_AWK_NDE_PRINTF; if (!MATCH_TERMINATOR(awk) && !MATCH(awk,TOK_GT) && @@ -2740,11 +2716,9 @@ static qse_awk_nde_t* parse_print ( * Due the case 3, i can't consume LPAREN * here and expect RPAREN later. */ - { - qse_awk_loc_t eloc = awk->tok.loc; - args = parse_expr_dc (awk, &eloc); - } - if (args == QSE_NULL) return QSE_NULL; + eloc = awk->tok.loc; + args = parse_expr_dc (awk, &eloc); + if (args == QSE_NULL) goto oops; args_tail = args; tail_prev = QSE_NULL; @@ -2756,24 +2730,15 @@ static qse_awk_nde_t* parse_print ( while (MATCH(awk,TOK_COMMA)) { - do { - if (get_token(awk) <= -1) - { - qse_awk_clrpt (awk, args); - return QSE_NULL; - } + do + { + if (get_token(awk) <= -1) goto oops; } while (MATCH(awk,TOK_NEWLINE)); - { - qse_awk_loc_t eloc = awk->tok.loc; - args_tail->next = parse_expr_dc (awk, &eloc); - } - if (args_tail->next == QSE_NULL) - { - qse_awk_clrpt (awk, args); - return QSE_NULL; - } + eloc = awk->tok.loc; + args_tail->next = parse_expr_dc (awk, &eloc); + if (args_tail->next == QSE_NULL) goto oops; tail_prev = args_tail; args_tail = args_tail->next; @@ -2841,7 +2806,7 @@ static qse_awk_nde_t* parse_print ( } } - if (out == QSE_NULL) + if (!out) { out_type = MATCH(awk,TOK_GT)? QSE_AWK_OUT_FILE: MATCH(awk,TOK_RS)? QSE_AWK_OUT_APFILE: @@ -2852,43 +2817,26 @@ static qse_awk_nde_t* parse_print ( if (out_type != QSE_AWK_OUT_CONSOLE) { - if (get_token(awk) <= -1) - { - if (args != QSE_NULL) qse_awk_clrpt (awk, args); - return QSE_NULL; - } + if (get_token(awk) <= -1) goto oops; - { - qse_awk_loc_t eloc = awk->tok.loc; - out = parse_expr_dc (awk, &eloc); - } - if (out == QSE_NULL) - { - if (args != QSE_NULL) qse_awk_clrpt (awk, args); - return QSE_NULL; - } + eloc = awk->tok.loc; + out = parse_expr_dc (awk, &eloc); + if (out == QSE_NULL) goto oops; } } + if (type == QSE_AWK_NDE_PRINTF && !args) + { + SETERR_LOC (awk, QSE_AWK_ENOARG, xloc); + goto oops; + } + nde = (qse_awk_nde_print_t*) QSE_AWK_ALLOC (awk, QSE_SIZEOF(qse_awk_nde_print_t)); if (nde == QSE_NULL) { - if (args != QSE_NULL) qse_awk_clrpt (awk, args); - if (out != QSE_NULL) qse_awk_clrpt (awk, out); SETERR_LOC (awk, QSE_AWK_ENOMEM, xloc); - return QSE_NULL; - } - - QSE_ASSERTX ( - type == QSE_AWK_NDE_PRINT || type == QSE_AWK_NDE_PRINTF, - "the node type should be either QSE_AWK_NDE_PRINT or QSE_AWK_NDE_PRINTF"); - - if (type == QSE_AWK_NDE_PRINTF && args == QSE_NULL) - { - if (out != QSE_NULL) qse_awk_clrpt (awk, out); - SETERR_LOC (awk, QSE_AWK_EPRINTFARG, xloc); - return QSE_NULL; + goto oops; } nde->type = type; @@ -2899,6 +2847,11 @@ static qse_awk_nde_t* parse_print ( nde->out = out; return (qse_awk_nde_t*)nde; + +oops: + if (args) qse_awk_clrpt (awk, args); + if (out) qse_awk_clrpt (awk, out); + return QSE_NULL; } static qse_awk_nde_t* parse_statement_nb ( @@ -2980,29 +2933,19 @@ static qse_awk_nde_t* parse_statement_nb ( if (get_token(awk) <= -1) return QSE_NULL; nde = parse_nextfile (awk, xloc, 1); } - else if (MATCH(awk,TOK_DELETE)) + else if (MATCH(awk,TOK_DELETE) || MATCH(awk,TOK_RESET)) { if (get_token(awk) <= -1) return QSE_NULL; nde = parse_delete (awk, xloc); } - else if (MATCH(awk,TOK_RESET)) - { - if (get_token(awk) <= -1) return QSE_NULL; - nde = parse_reset (awk, xloc); - } else if (!(awk->option & QSE_AWK_TOLERANT)) { /* in the non-tolerant mode, we treat print and printf * as a separate statement */ - if (MATCH(awk,TOK_PRINT)) + if (MATCH(awk,TOK_PRINT) || MATCH(awk,TOK_PRINTF)) { if (get_token(awk) <= -1) return QSE_NULL; - nde = parse_print (awk, xloc, QSE_AWK_NDE_PRINT); - } - else if (MATCH(awk,TOK_PRINTF)) - { - if (get_token(awk) <= -1) return QSE_NULL; - nde = parse_print (awk, xloc, QSE_AWK_NDE_PRINTF); + nde = parse_print (awk, xloc); } else nde = parse_expr_dc (awk, xloc); } @@ -4637,15 +4580,10 @@ static qse_awk_nde_t* parse_primary_nogetline ( { /* in the tolerant mode, we treat print and printf * as a function like getline */ - if (MATCH(awk,TOK_PRINT)) + if (MATCH(awk,TOK_PRINT) || MATCH(awk,TOK_PRINTF)) { if (get_token(awk) <= -1) return QSE_NULL; - return parse_print (awk, xloc, QSE_AWK_NDE_PRINT); - } - else if (MATCH(awk,TOK_PRINTF)) - { - if (get_token(awk) <= -1) return QSE_NULL; - return parse_print (awk, xloc, QSE_AWK_NDE_PRINTF); + return parse_print (awk, xloc); } } @@ -4800,7 +4738,7 @@ static QSE_INLINE int isfnname (qse_awk_t* awk, const qse_char_t* name, qse_size static qse_awk_nde_t* parse_variable ( qse_awk_t* awk, const qse_awk_loc_t* xloc, qse_awk_nde_type_t type, - qse_char_t* nameptr, qse_size_t namelen, qse_size_t idxa) + const qse_xstr_t* name, qse_size_t idxa) { qse_awk_nde_var_t* nde; @@ -4818,7 +4756,7 @@ static qse_awk_nde_t* parse_variable ( /* a variable is not a function */ SETERR_ARG_LOC ( awk, QSE_AWK_EFUNNAM, - nameptr, namelen, xloc); + name->ptr, name->len, xloc); return QSE_NULL; } } @@ -4835,48 +4773,77 @@ static qse_awk_nde_t* parse_variable ( nde->loc = *xloc; nde->next = QSE_NULL; /*nde->id.name.ptr = QSE_NULL;*/ - nde->id.name.ptr = nameptr; - nde->id.name.len = namelen; + nde->id.name.ptr = name->ptr; + nde->id.name.len = name->len; nde->id.idxa = idxa; nde->idx = QSE_NULL; return (qse_awk_nde_t*)nde; } -static qse_awk_nde_t* parse_primary_ident ( - qse_awk_t* awk, const qse_awk_loc_t* xloc) +static int dup_ident_and_get_next ( + qse_awk_t* awk, const qse_awk_loc_t* xloc, qse_xstr_t* name, int max) { - qse_awk_nde_t* nde = QSE_NULL; - qse_char_t* namedup; - qse_size_t namelen; - qse_awk_fnc_t* fnc; - qse_size_t idxa; + int nsegs = 0; QSE_ASSERT (MATCH(awk,TOK_IDENT)); - namedup = QSE_AWK_STRXDUP (awk, - QSE_STR_PTR(awk->tok.name), - QSE_STR_LEN(awk->tok.name)); - if (namedup == QSE_NULL) + do { - SETERR_LOC (awk, QSE_AWK_ENOMEM, xloc); - return QSE_NULL; - } - namelen = QSE_STR_LEN(awk->tok.name); + name[nsegs].ptr = QSE_STR_PTR(awk->tok.name); + name[nsegs].len = QSE_STR_LEN(awk->tok.name); - if (get_token(awk) <= -1) - { - QSE_AWK_FREE (awk, namedup); - return QSE_NULL; - } + /* duplicate the identifier */ + name[nsegs].ptr = qse_strxdup (name[nsegs].ptr, name[nsegs].len, awk->mmgr); + if (name[nsegs].ptr == QSE_NULL) + { + SETERR_LOC (awk, QSE_AWK_ENOMEM, xloc); + goto oops; + } - /* check if namedup is an intrinsic function name */ - fnc = qse_awk_getfnc (awk, namedup, namelen); + nsegs++; + + if (get_token(awk) <= -1) goto oops; + + if (!MATCH(awk,TOK_DBLCOLON)) break; + + if (get_token(awk) <= -1) goto oops; + + if (!MATCH(awk, TOK_IDENT) && !(MATCH_RANGE(awk, TOK_BEGIN, TOK_GETLINE))) + { + SETERR_TOK (awk, QSE_AWK_EIDENT); + goto oops; + } + + if (nsegs >= max) + { + SETERR_LOC (awk, QSE_AWK_ESEGTM, xloc); + goto oops; + } + } + while (1); + + return nsegs; + +oops: + while (nsegs > 0) QSE_AWK_FREE (awk, name[--nsegs].ptr); + return -1; +} + +static qse_awk_nde_t* parse_primary_ident_noseg ( + qse_awk_t* awk, const qse_awk_loc_t* xloc, const qse_xstr_t* name) +{ + qse_awk_fnc_t* fnc; + qse_size_t idxa; + qse_awk_nde_t* nde = QSE_NULL; + + /* check if name is an intrinsic function name */ + fnc = qse_awk_getfnc (awk, name->ptr, name->len); if (fnc) { if (MATCH(awk,TOK_LPAREN)) { - nde = parse_fncall (awk, namedup, namelen, fnc, xloc, 0); + nde = parse_fncall (awk, name, fnc, xloc, 0); } else { @@ -4884,8 +4851,7 @@ static qse_awk_nde_t* parse_primary_ident ( { /* handles a function that assumes () * when () is missing. i.e. length */ - nde = parse_fncall ( - awk, namedup, namelen, fnc, xloc, 1); + nde = parse_fncall (awk, name, fnc, xloc, 1); } else { @@ -4895,35 +4861,31 @@ static qse_awk_nde_t* parse_primary_ident ( } } } - /* now we know that namedup is a normal identifier. */ + /* now we know that name is a normal identifier. */ else if (MATCH(awk,TOK_LBRACK)) { - nde = parse_hashidx (awk, namedup, namelen, xloc); + nde = parse_hashidx (awk, name->ptr, name->len, xloc); } - else if ((idxa = qse_lda_rsearch (awk->parse.lcls, QSE_LDA_SIZE(awk->parse.lcls), namedup, namelen)) != QSE_LDA_NIL) + else if ((idxa = qse_lda_rsearch (awk->parse.lcls, QSE_LDA_SIZE(awk->parse.lcls), name->ptr, name->len)) != QSE_LDA_NIL) { /* local variable */ - nde = parse_variable ( - awk, xloc, QSE_AWK_NDE_LCL, - namedup, namelen, idxa); + nde = parse_variable (awk, xloc, QSE_AWK_NDE_LCL, name, idxa); } - else if ((idxa = qse_lda_search (awk->parse.params, 0, namedup, namelen)) != QSE_LDA_NIL) + else if ((idxa = qse_lda_search (awk->parse.params, 0, name->ptr, name->len)) != QSE_LDA_NIL) { /* parameter */ - nde = parse_variable ( - awk, xloc, QSE_AWK_NDE_ARG, - namedup, namelen, idxa); + nde = parse_variable (awk, xloc, QSE_AWK_NDE_ARG, name, idxa); } - else if ((idxa = get_global (awk, namedup, namelen)) != QSE_LDA_NIL) + else if ((idxa = get_global (awk, name->ptr, name->len)) != QSE_LDA_NIL) { /* global variable */ - nde = parse_variable ( - awk, xloc, QSE_AWK_NDE_GBL, - namedup, namelen, idxa); + nde = parse_variable (awk, xloc, QSE_AWK_NDE_GBL, name, idxa); } else { - int fntype = isfunname (awk, namedup, namelen); + int fntype; + + fntype = isfunname (awk, name->ptr, name->len); if (fntype) { @@ -4933,17 +4895,16 @@ static qse_awk_nde_t* parse_primary_ident ( { /* must be a function name */ QSE_ASSERT (qse_htb_search ( - awk->parse.named, namedup, namelen) == QSE_NULL); + awk->parse.named, name->ptr, name->len) == QSE_NULL); - nde = parse_fncall ( - awk, namedup, namelen, QSE_NULL, xloc, 0); + nde = parse_fncall (awk, name, QSE_NULL, xloc, 0); } else { /* function name appeared without () */ SETERR_ARG_LOC ( awk, QSE_AWK_EFUNRED, - namedup, namelen, xloc + name->ptr, name->len, xloc ); } } @@ -4955,23 +4916,22 @@ static qse_awk_nde_t* parse_primary_ident ( if (MATCH(awk,TOK_LPAREN) && awk->tok.loc.line == xloc->line && - awk->tok.loc.colm == xloc->colm + namelen) + awk->tok.loc.colm == xloc->colm + name->len) { /* a function call to a yet undefined function */ if (qse_htb_search ( - awk->parse.named, namedup, namelen) != QSE_NULL) + awk->parse.named, name->ptr, name->len) != QSE_NULL) { /* a function call conflicts with a named variable */ SETERR_ARG_LOC ( awk, QSE_AWK_EVARRED, - namedup, namelen, xloc + name->ptr, name->len, xloc ); } else { - nde = parse_fncall ( - awk, namedup, namelen, QSE_NULL, xloc, 0); + nde = parse_fncall (awk, name, QSE_NULL, xloc, 0); } } else @@ -4991,7 +4951,7 @@ static qse_awk_nde_t* parse_primary_ident ( * for reference */ if (qse_htb_upsert ( awk->parse.named, - namedup, namelen, QSE_NULL, 0) == QSE_NULL) + name->ptr, name->len, QSE_NULL, 0) == QSE_NULL) { SETERR_LOC (awk, QSE_AWK_ENOMEM, xloc); QSE_AWK_FREE (awk, tmp); @@ -5001,8 +4961,8 @@ static qse_awk_nde_t* parse_primary_ident ( tmp->type = QSE_AWK_NDE_NAMED; tmp->loc = *xloc; tmp->next = QSE_NULL; - tmp->id.name.ptr = namedup; - tmp->id.name.len = namelen; + tmp->id.name.ptr = name->ptr; + tmp->id.name.len = name->len; tmp->id.idxa = (qse_size_t)-1; tmp->idx = QSE_NULL; @@ -5017,20 +4977,109 @@ static qse_awk_nde_t* parse_primary_ident ( { /* it is a function call as the name is followed * by ( and implicit variables are disabled. */ - nde = parse_fncall ( - awk, namedup, namelen, QSE_NULL, xloc, 0); + nde = parse_fncall (awk, name, QSE_NULL, xloc, 0); } else { /* undefined variable */ - SETERR_ARG_LOC ( - awk, QSE_AWK_EUNDEF, namedup, namelen, xloc - ); + SETERR_ARG_LOC (awk, QSE_AWK_EUNDEF, name->ptr, name->len, xloc); } } } - if (nde == QSE_NULL) QSE_AWK_FREE (awk, namedup); + return nde; +} + +static qse_awk_nde_t* parse_primary_ident_segs ( + qse_awk_t* awk, const qse_awk_loc_t* xloc, const qse_xstr_t* full) +{ + qse_awk_nde_t* nde = QSE_NULL; + qse_awk_mod_info_t info; + qse_awk_fnc_t fnc; + + CLRERR (awk); + if (!awk->mod || awk->mod->query (awk, full->ptr, &info) <= -1) + { + if (ISNOERR(awk)) SETERR_LOC (awk, QSE_AWK_ENOSUP, xloc); + } + else + { + if (info.type == QSE_AWK_MOD_FNC) + { + if (MATCH(awk,TOK_LPAREN)) + { + QSE_MEMSET (&fnc, 0, QSE_SIZEOF(fnc)); + fnc.name.ptr = full->ptr; + fnc.name.len = full->len; + fnc.arg.min = info.u.f.arg.min; + fnc.arg.max = info.u.f.arg.max; + fnc.handler = info.u.f.impl; + + nde = parse_fncall (awk, full, &fnc, xloc, 0); + } + else + { + SETERR_TOK (awk, QSE_AWK_ELPAREN); + } + } + else + { + /* TODO: support MOD_VAR */ + SETERR_ARG_LOC (awk, QSE_AWK_EUNDEF, full->ptr, full->len, xloc); + } + } + + return nde; +} + +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_xstr_t name[2]; /* TODO: support more than 2 segments??? */ + int nsegs; + + QSE_ASSERT (MATCH(awk,TOK_IDENT)); + + nsegs = dup_ident_and_get_next (awk, xloc, name, QSE_COUNTOF(name)); + if (nsegs <= -1) return QSE_NULL; + + if (nsegs <= 1) + { + nde = parse_primary_ident_noseg (awk, xloc, &name[0]); + if (!nde) QSE_AWK_FREE (awk, name[0].ptr); + } + else + { + qse_xstr_t full; /* full name including :: */ + qse_size_t capa; + int i; + + for (capa = 0, i = 0; i < nsegs; i++) capa += name[i].len + 2; /* +2 for :: */ + full.ptr = QSE_MMGR_ALLOC (awk->mmgr, QSE_SIZEOF(*full.ptr) * (capa + 1)); + if (full.ptr) + { + capa = qse_strncpy (&full.ptr[0], name[0].ptr, name[0].len); + for (i = 1; i < nsegs; i++) + { + capa += qse_strcpy (&full.ptr[capa], QSE_T("::")); + capa += qse_strncpy (&full.ptr[capa], name[i].ptr, name[i].len); + } + full.ptr[capa] = QSE_T('\0'); + full.len = capa; + + nde = parse_primary_ident_segs (awk, xloc, &full); + if (!nde) QSE_MMGR_FREE (awk->mmgr, full.ptr); + } + else + { + SETERR_LOC (awk, QSE_AWK_ENOMEM, xloc); + } + + /* i don't need the name segments */ + while (nsegs > 0) QSE_AWK_FREE (awk, name[--nsegs].ptr); + } + return nde; } @@ -5193,23 +5242,24 @@ exit_func: } static qse_awk_nde_t* parse_fncall ( - qse_awk_t* awk, qse_char_t* name, qse_size_t namelen, + qse_awk_t* awk, const qse_xstr_t* name, qse_awk_fnc_t* fnc, const qse_awk_loc_t* xloc, int noarg) { qse_awk_nde_t* head, * curr, * nde; qse_awk_nde_fncall_t* call; qse_size_t nargs; + qse_awk_loc_t eloc; head = curr = QSE_NULL; nargs = 0; if (noarg) goto make_node; - if (get_token(awk) <= -1) return QSE_NULL; + if (get_token(awk) <= -1) goto oops; if (MATCH(awk,TOK_RPAREN)) { /* no parameters to the function call */ - if (get_token(awk) <= -1) return QSE_NULL; + if (get_token(awk) <= -1) goto oops; } else { @@ -5217,15 +5267,9 @@ static qse_awk_nde_t* parse_fncall ( while (1) { - { - qse_awk_loc_t eloc = awk->tok.loc; - nde = parse_expr_dc (awk, &eloc); - } - if (nde == QSE_NULL) - { - if (head != QSE_NULL) qse_awk_clrpt (awk, head); - return QSE_NULL; - } + eloc = awk->tok.loc; + nde = parse_expr_dc (awk, &eloc); + if (nde == QSE_NULL) goto oops; if (head == QSE_NULL) head = nde; else curr->next = nde; @@ -5235,31 +5279,19 @@ static qse_awk_nde_t* parse_fncall ( if (MATCH(awk,TOK_RPAREN)) { - if (get_token(awk) <= -1) - { - if (head != QSE_NULL) - qse_awk_clrpt (awk, head); - return QSE_NULL; - } + if (get_token(awk) <= -1) goto oops; break; } if (!MATCH(awk,TOK_COMMA)) { - if (head != QSE_NULL) - qse_awk_clrpt (awk, head); SETERR_TOK (awk, QSE_AWK_ECOMMA); - return QSE_NULL; + goto oops; } do { - if (get_token(awk) <= -1) - { - if (head != QSE_NULL) - qse_awk_clrpt (awk, head); - return QSE_NULL; - } + if (get_token(awk) <= -1) goto oops; } while (MATCH(awk,TOK_NEWLINE)); } @@ -5271,20 +5303,19 @@ make_node: QSE_AWK_ALLOC (awk, QSE_SIZEOF(qse_awk_nde_fncall_t)); if (call == QSE_NULL) { - if (head != QSE_NULL) qse_awk_clrpt (awk, head); SETERR_LOC (awk, QSE_AWK_ENOMEM, xloc); - return QSE_NULL; + goto oops; } - if (fnc != QSE_NULL) + if (fnc) { call->type = QSE_AWK_NDE_FNC; call->loc = *xloc; call->next = QSE_NULL; /*call->u.fnc = fnc; */ - call->u.fnc.name.ptr = name; - call->u.fnc.name.len = namelen; + call->u.fnc.name.ptr = name->ptr; + call->u.fnc.name.len = name->len; call->u.fnc.arg.min = fnc->arg.min; call->u.fnc.arg.max = fnc->arg.max; call->u.fnc.arg.spec = fnc->arg.spec; @@ -5298,24 +5329,27 @@ make_node: call->type = QSE_AWK_NDE_FUN; call->loc = *xloc; call->next = QSE_NULL; - call->u.fun.name.ptr = name; - call->u.fun.name.len = namelen; + call->u.fun.name.ptr = name->ptr; + call->u.fun.name.len = name->len; call->args = head; call->nargs = nargs; /* store a non-builtin function call into the awk->parse.funs * table */ if (qse_htb_upsert ( - awk->parse.funs, name, namelen, call, 0) == QSE_NULL) + awk->parse.funs, name->ptr, name->len, call, 0) == QSE_NULL) { - QSE_AWK_FREE (awk, call); - if (head != QSE_NULL) qse_awk_clrpt (awk, head); SETERR_LOC (awk, QSE_AWK_ENOMEM, xloc); - return QSE_NULL; + QSE_AWK_FREE (awk, call); + goto oops; } } return (qse_awk_nde_t*)call; + +oops: + if (head) qse_awk_clrpt (awk, head); + return QSE_NULL; } static int get_number (qse_awk_t* awk, qse_awk_tok_t* tok) @@ -5814,6 +5848,7 @@ static int get_symbols (qse_awk_t* awk, qse_cint_t c, qse_awk_tok_t* tok) { QSE_T("$"), 1, TOK_DOLLAR, 0 }, { QSE_T(","), 1, TOK_COMMA, 0 }, { QSE_T(";"), 1, TOK_SEMICOLON, 0 }, + { QSE_T("::"), 2, TOK_DBLCOLON, 0 }, { QSE_T(":"), 1, TOK_COLON, 0 }, { QSE_T("?"), 1, TOK_QUEST, 0 }, { QSE_T("@"), 1, TOK_ATSIGN, 0 }, @@ -5934,6 +5969,50 @@ retry: QSE_STR_PTR(tok->name), QSE_STR_LEN(tok->name)); SET_TOKEN_TYPE (awk, tok, type); + +#if 0 + if (type == TOK_IDENT) + { + qse_awk_sio_lxc_t lc; + + while (c == QSE_T(':')); + { + lc = awk->sio.last; + GET_CHAR_TO (awk, c); + if (c == QSE_T(':')) + { + GET_CHAR_TO (awk, c); + if (c == QSE_T('_') || QSE_AWK_ISALPHA (awk, c)) + { + do + { + ADD_TOKEN_CHAR (awk, tok, c); + GET_CHAR_TO (awk, c); + } + while (c == QSE_T('_') || + QSE_AWK_ISALPHA (awk, c) || + QSE_AWK_ISDIGIT (awk, c)); + + /* this set_token_type may get executed + * more than necessary if there are many + * segments. but never mind */ + SET_TOKEN_TYPE (awk, tok, TOK_SEGIDENT); + } + else + { + /* TODO: return an error for the + * incomplete segmented identifier */ + } + } + else + { + unget_char (awk, &awk->sio.last); + awk->sio.last = lc; + break; + } + } + } +#endif } else if (c == QSE_T('\"')) { @@ -6001,7 +6080,7 @@ static int classify_ident ( { /* perform binary search */ - /* declaring left, right, mid to be of int is ok + /* declaring left, right, mid to be the int type is ok * because we know kwtab is small enough. */ int left = 0, right = QSE_COUNTOF(kwtab) - 1, mid; diff --git a/qse/lib/awk/rio.c b/qse/lib/awk/rio.c index 32879237..e99d7155 100644 --- a/qse/lib/awk/rio.c +++ b/qse/lib/awk/rio.c @@ -89,10 +89,10 @@ static int out_mask_map[] = static int find_rio_in ( qse_awk_rtx_t* run, int in_type, const qse_char_t* name, - qse_awk_rio_arg_t** rio, qse_awk_rio_fun_t* fun) + qse_awk_rio_arg_t** rio, qse_awk_rio_impl_t* fun) { qse_awk_rio_arg_t* p = run->rio.chain; - qse_awk_rio_fun_t handler; + qse_awk_rio_impl_t handler; int io_type, io_mode, io_mask; QSE_ASSERT (in_type >= 0 && in_type <= QSE_COUNTOF(in_type_map)); @@ -297,7 +297,7 @@ int qse_awk_rtx_readio ( const qse_char_t* name, qse_str_t* buf) { qse_awk_rio_arg_t* p; - qse_awk_rio_fun_t handler; + qse_awk_rio_impl_t handler; int ret; qse_awk_val_t* rs; @@ -673,7 +673,7 @@ int qse_awk_rtx_writeio_str ( const qse_char_t* name, qse_char_t* str, qse_size_t len) { qse_awk_rio_arg_t* p = run->rio.chain; - qse_awk_rio_fun_t handler; + qse_awk_rio_impl_t handler; int io_type, io_mode, io_mask; qse_ssize_t n; @@ -816,7 +816,7 @@ int qse_awk_rtx_flushio ( qse_awk_rtx_t* run, int out_type, const qse_char_t* name) { qse_awk_rio_arg_t* p = run->rio.chain; - qse_awk_rio_fun_t handler; + qse_awk_rio_impl_t handler; int io_type, /*io_mode,*/ io_mask; qse_ssize_t n; int ok = 0; @@ -871,7 +871,7 @@ int qse_awk_rtx_nextio_read ( qse_awk_rtx_t* run, int in_type, const qse_char_t* name) { qse_awk_rio_arg_t* p = run->rio.chain; - qse_awk_rio_fun_t handler; + qse_awk_rio_impl_t handler; int io_type, /*io_mode,*/ io_mask; qse_ssize_t n; @@ -949,7 +949,7 @@ int qse_awk_rtx_nextio_write ( qse_awk_rtx_t* run, int out_type, const qse_char_t* name) { qse_awk_rio_arg_t* p = run->rio.chain; - qse_awk_rio_fun_t handler; + qse_awk_rio_impl_t handler; int io_type, /*io_mode,*/ io_mask; qse_ssize_t n; @@ -1022,7 +1022,7 @@ int qse_awk_rtx_closio_read ( qse_awk_rtx_t* run, int in_type, const qse_char_t* name) { qse_awk_rio_arg_t* p = run->rio.chain, * px = QSE_NULL; - qse_awk_rio_fun_t handler; + qse_awk_rio_impl_t handler; int io_type, /*io_mode,*/ io_mask; QSE_ASSERT (in_type >= 0 && in_type <= QSE_COUNTOF(in_type_map)); @@ -1047,7 +1047,7 @@ int qse_awk_rtx_closio_read ( if (p->type == (io_type | io_mask) && qse_strcmp (p->name, name) == 0) { - qse_awk_rio_fun_t handler; + qse_awk_rio_impl_t handler; handler = run->rio.handler[p->type & IO_MASK_CLEAR]; if (handler != QSE_NULL) @@ -1081,7 +1081,7 @@ int qse_awk_rtx_closio_write ( qse_awk_rtx_t* run, int out_type, const qse_char_t* name) { qse_awk_rio_arg_t* p = run->rio.chain, * px = QSE_NULL; - qse_awk_rio_fun_t handler; + qse_awk_rio_impl_t handler; int io_type, /*io_mode,*/ io_mask; QSE_ASSERT (out_type >= 0 && out_type <= QSE_COUNTOF(out_type_map)); @@ -1106,7 +1106,7 @@ int qse_awk_rtx_closio_write ( if (p->type == (io_type | io_mask) && qse_strcmp (p->name, name) == 0) { - qse_awk_rio_fun_t handler; + qse_awk_rio_impl_t handler; handler = run->rio.handler[p->type & IO_MASK_CLEAR]; if (handler != QSE_NULL) @@ -1147,7 +1147,7 @@ int qse_awk_rtx_closeio ( * regardless of the io type */ if (qse_strcmp (p->name, name) == 0) { - qse_awk_rio_fun_t handler; + qse_awk_rio_impl_t handler; qse_awk_rio_rwcmode_t rwcmode = QSE_AWK_RIO_CLOSE_FULL; if (opt != QSE_NULL) @@ -1232,7 +1232,7 @@ int qse_awk_rtx_closeio ( void qse_awk_rtx_cleario (qse_awk_rtx_t* run) { qse_awk_rio_arg_t* next; - qse_awk_rio_fun_t handler; + qse_awk_rio_impl_t handler; qse_ssize_t n; while (run->rio.chain != QSE_NULL) diff --git a/qse/lib/awk/run.c b/qse/lib/awk/run.c index a991716b..4c8c577f 100644 --- a/qse/lib/awk/run.c +++ b/qse/lib/awk/run.c @@ -695,7 +695,7 @@ qse_htb_t* qse_awk_rtx_getnvmap (qse_awk_rtx_t* rtx) } qse_awk_rtx_t* qse_awk_rtx_open ( - qse_awk_t* awk, qse_size_t xtn, qse_awk_rio_t* rio) + qse_awk_t* awk, qse_size_t xtnsize, qse_awk_rio_t* rio) { qse_awk_rtx_t* rtx; @@ -718,7 +718,7 @@ qse_awk_rtx_t* qse_awk_rtx_open ( /* allocate the storage for the rtx object */ rtx = (qse_awk_rtx_t*) QSE_AWK_ALLOC ( - awk, QSE_SIZEOF(qse_awk_rtx_t) + xtn); + awk, QSE_SIZEOF(qse_awk_rtx_t) + xtnsize); if (rtx == QSE_NULL) { /* if it fails, the failure is reported thru @@ -727,7 +727,8 @@ qse_awk_rtx_t* qse_awk_rtx_open ( return QSE_NULL; } - /* initialize the run object */ + /* initialize the rtx object */ + QSE_MEMSET (rtx, 0, QSE_SIZEOF(qse_awk_rtx_t) + xtnsize); if (init_rtx (rtx, awk, rio) <= -1) { QSE_AWK_FREE (awk, rtx); @@ -830,9 +831,6 @@ static int init_rtx (qse_awk_rtx_t* rtx, qse_awk_t* awk, qse_awk_rio_t* rio) QSE_HTB_HASHER_DEFAULT }; - /* zero out the runtime context excluding the extension */ - QSE_MEMSET (rtx, 0, QSE_SIZEOF(qse_awk_rtx_t)); - rtx->awk = awk; CLRERR (rtx); @@ -2629,14 +2627,13 @@ static int run_delete (qse_awk_rtx_t* rtx, qse_awk_nde_delete_t* nde) case QSE_AWK_NDE_LCLIDX: case QSE_AWK_NDE_ARGIDX: return run_delete_nonnamed (rtx, var); - } QSE_ASSERTX ( !"should never happen - wrong target for delete", "the delete statement cannot be called with other nodes than the variables such as a named variable, a named indexed variable, etc"); - SETERR_LOC (rtx, QSE_AWK_ERDELETE, &var->loc); + SETERR_LOC (rtx, QSE_AWK_EBADARG, &var->loc); return -1; } @@ -2687,7 +2684,7 @@ static int run_reset (qse_awk_rtx_t* rtx, qse_awk_nde_reset_t* nde) !"should never happen - wrong target for reset", "the reset statement can only be called with plain variables"); - SETERR_LOC (rtx, QSE_AWK_ERRESET, &var->loc); + SETERR_LOC (rtx, QSE_AWK_EBADARG, &var->loc); return -1; } diff --git a/qse/lib/awk/std.c b/qse/lib/awk/std.c index f93b92c6..340691f9 100644 --- a/qse/lib/awk/std.c +++ b/qse/lib/awk/std.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include /* TODO: remove dependency on qse_vsprintf */ @@ -48,6 +49,7 @@ /* anything ? */ #else # include +# include #endif #ifndef QSE_HAVE_CONFIG_H @@ -109,6 +111,9 @@ typedef struct xtn_t int gbl_argv; int gbl_environ; int gbl_procinfo; + + qse_rbt_t modtab; + qse_awk_ecb_t ecb; } xtn_t; typedef struct rxtn_t @@ -136,6 +141,8 @@ typedef struct rxtn_t int cmgrtab_inited; qse_htb_t cmgrtab; + + qse_awk_rtx_ecb_t ecb; } rxtn_t; typedef struct ioattr_t @@ -307,11 +314,37 @@ static int custom_awk_sprintf ( static int add_globals (qse_awk_t* awk); static int add_functions (qse_awk_t* awk); +static int query_module ( + qse_awk_t* awk, const qse_char_t* name, qse_awk_mod_info_t* info); +static int init_module (qse_awk_t* awk, qse_awk_rtx_t* rtx); +static void fini_module (qse_awk_t* awk, qse_awk_rtx_t* rtx); + +static qse_awk_mod_t awk_mod = +{ + query_module, + init_module, + fini_module +}; + qse_awk_t* qse_awk_openstd (qse_size_t xtnsize) { return qse_awk_openstdwithmmgr (QSE_MMGR_GETDFL(), xtnsize); } +static void fini_xtn (qse_awk_t* awk) +{ + xtn_t* xtn; + xtn = (xtn_t*) QSE_XTN (awk); + qse_rbt_fini (&xtn->modtab); +} + +static void clear_xtn (qse_awk_t* awk) +{ + xtn_t* xtn; + xtn = (xtn_t*) QSE_XTN (awk); + qse_rbt_clear (&xtn->modtab); +} + qse_awk_t* qse_awk_openstdwithmmgr (qse_mmgr_t* mmgr, qse_size_t xtnsize) { qse_awk_t* awk; @@ -338,7 +371,6 @@ qse_awk_t* qse_awk_openstdwithmmgr (qse_mmgr_t* mmgr, qse_size_t xtnsize) /* initialize extension */ xtn = (xtn_t*) QSE_XTN (awk); - QSE_MEMSET (xtn, 0, QSE_SIZEOF(xtn_t)); /* add intrinsic global variables and functions */ if (add_globals(awk) <= -1 || @@ -348,6 +380,19 @@ qse_awk_t* qse_awk_openstdwithmmgr (qse_mmgr_t* mmgr, qse_size_t xtnsize) return QSE_NULL; } +/* TODO: change the way to set this... */ + awk->mod = &awk_mod; + + if (qse_rbt_init (&xtn->modtab, mmgr, QSE_SIZEOF(qse_char_t), 0) <= -1) + { + qse_awk_close (awk); + return QSE_NULL; + } + + xtn->ecb.close = fini_xtn; + xtn->ecb.clear = clear_xtn; + qse_awk_pushecb (awk, &xtn->ecb); + return awk; } @@ -1874,12 +1919,6 @@ qse_awk_rtx_t* qse_awk_rtx_openstd ( const qse_char_t* ocf[], qse_cmgr_t* cmgr) { - static qse_awk_rtx_ecb_t ecb = - { - QSE_FV (.close, fini_rxtn), - QSE_FV (.stmt, QSE_NULL) - }; - qse_awk_rtx_t* rtx; qse_awk_rio_t rio; rxtn_t* rxtn; @@ -1897,11 +1936,9 @@ qse_awk_rtx_t* qse_awk_rtx_openstd ( QSE_SIZEOF(rxtn_t) + xtnsize, &rio ); - if (rtx == QSE_NULL) return QSE_NULL; rxtn = (rxtn_t*) QSE_XTN (rtx); - QSE_MEMSET (rxtn, 0, QSE_SIZEOF(rxtn_t)); if (rtx->awk->option & QSE_AWK_RIO) { @@ -1918,7 +1955,8 @@ qse_awk_rtx_t* qse_awk_rtx_openstd ( rxtn->cmgrtab_inited = 1; } - qse_awk_rtx_pushecb (rtx, &ecb); + rxtn->ecb.close = fini_rxtn; + qse_awk_rtx_pushecb (rtx, &rxtn->ecb); rxtn->seed = (qse_gettime (&now) <= -1)? 0u: (qse_long_t)now; /* i don't care if the seed becomes negative or overflows. @@ -2432,3 +2470,82 @@ static int add_functions (qse_awk_t* awk) qse_awk_addfnc (awk, QSE_T("getioattr"), 9, QSE_AWK_RIO, 2, 2, QSE_NULL, fnc_getioattr) == QSE_NULL) return -1; return 0; } + + +static int query_module ( + qse_awk_t* awk, const qse_char_t* name, qse_awk_mod_info_t* info) +{ + const qse_char_t* dc; + qse_awk_mod_query_t query; + xtn_t* xtn; + qse_rbt_pair_t* pair; + + xtn = (xtn_t*)QSE_XTN(awk); + + /* TODO: support module calls with deeper levels ... */ + dc = qse_strstr (name, QSE_T("::")); + QSE_ASSERT (dc != QSE_NULL); + +#if defined(_WIN32) + /*TODO: implemente this */ + qse_awk_seterrnum (awk, QSE_AWK_ENOIMPL, QSE_NULL); + return -1; +#elif defined(__OS2__) + /*TODO: implemente this */ + qse_awk_seterrnum (awk, QSE_AWK_ENOIMPL, QSE_NULL); + return -1; +#elif defined(__DOS__) + qse_awk_seterrnum (awk, QSE_AWK_ENOIMPL, QSE_NULL); + return -1; +#else + + pair = qse_rbt_search (&xtn->modtab, name, dc - name); + if (pair) + { + /*query = QSE_RBT_VPTR(pair)->query;*/ + } + else + { + void* dh; + const qse_mchar_t* mod; + + #if defined(QSE_CHAR_IS_MCHAR) + mod = qse_mbsxdup (name, dc - name, QSE_NULL, awk->mmgr); + #else + mod = qse_wcsntombsdup (name, dc - name, QSE_NULL, awk->mmgr); + #endif + if (!mod) + { + qse_awk_seterrnum (awk, QSE_AWK_ENOMEM, QSE_NULL); + return -1; + } + + dh = lt_dlopen (mod); + QSE_MMGR_FREE (awk->mmgr, mod); + + if (!dh) + { + return -1; + } + + query = lt_dlsym (dh, QSE_MT("query")); + if (!query) + { + lt_dlclose (dh); + return -1; + } + } + + return query (awk, dc + 2, info); +#endif + +} + +static int init_module (qse_awk_t* awk, qse_awk_rtx_t* rtx) +{ + return 0; +} + +static void fini_module (qse_awk_t* awk, qse_awk_rtx_t* rtx) +{ +} diff --git a/qse/lib/awk/tree.h b/qse/lib/awk/tree.h index 088ef432..098cd7bf 100644 --- a/qse/lib/awk/tree.h +++ b/qse/lib/awk/tree.h @@ -198,7 +198,7 @@ struct qse_awk_nde_fncall_t const qse_char_t* spec; } arg; - qse_awk_fnc_fun_t handler; + qse_awk_fnc_impl_t handler; } fnc; } u; qse_awk_nde_t* args; diff --git a/qse/lib/cmn/glob.c b/qse/lib/cmn/glob.c index 18dca22a..578eb540 100644 --- a/qse/lib/cmn/glob.c +++ b/qse/lib/cmn/glob.c @@ -79,7 +79,7 @@ typedef struct stack_node_t stack_node_t; struct glob_t { - qse_glob_cbfun_t cbfun; + qse_glob_cbimpl_t cbimpl; void* cbctx; qse_mmgr_t* mmgr; @@ -707,7 +707,7 @@ static int handle_non_wild_segments (glob_t* g, segment_t* seg) if (!seg->next && path_exists(g, QSE_STR_PTR(&g->path)) > 0) { /* reached the last segment. match if the path exists */ - if (g->cbfun (QSE_STR_CSTR(&g->path), g->cbctx) <= -1) return -1; + if (g->cbimpl (QSE_STR_CSTR(&g->path), g->cbctx) <= -1) return -1; g->expanded = 1; } } @@ -803,7 +803,7 @@ entry: } else { - if (g->cbfun (QSE_STR_CSTR(&g->path), g->cbctx) <= -1) goto oops; + if (g->cbimpl (QSE_STR_CSTR(&g->path), g->cbctx) <= -1) goto oops; g->expanded = 1; } } @@ -871,14 +871,14 @@ oops: return -1; } -int qse_globwithcmgr (const qse_char_t* pattern, qse_glob_cbfun_t cbfun, void* cbctx, int flags, qse_mmgr_t* mmgr, qse_cmgr_t* cmgr) +int qse_globwithcmgr (const qse_char_t* pattern, qse_glob_cbimpl_t cbimpl, void* cbctx, int flags, qse_mmgr_t* mmgr, qse_cmgr_t* cmgr) { segment_t seg; glob_t g; int x; QSE_MEMSET (&g, 0, QSE_SIZEOF(g)); - g.cbfun = cbfun; + g.cbimpl = cbimpl; g.cbctx = cbctx; g.mmgr = mmgr; g.cmgr = cmgr; @@ -928,8 +928,8 @@ int qse_globwithcmgr (const qse_char_t* pattern, qse_glob_cbfun_t cbfun, void* c return g.expanded; } -int qse_glob (const qse_char_t* pattern, qse_glob_cbfun_t cbfun, void* cbctx, int flags, qse_mmgr_t* mmgr) +int qse_glob (const qse_char_t* pattern, qse_glob_cbimpl_t cbimpl, void* cbctx, int flags, qse_mmgr_t* mmgr) { - return qse_globwithcmgr (pattern, cbfun, cbctx, flags, mmgr, qse_getdflcmgr()); + return qse_globwithcmgr (pattern, cbimpl, cbctx, flags, mmgr, qse_getdflcmgr()); } diff --git a/qse/lib/cmn/tio.c b/qse/lib/cmn/tio.c index 59263ba3..db99e2cf 100644 --- a/qse/lib/cmn/tio.c +++ b/qse/lib/cmn/tio.c @@ -113,7 +113,7 @@ void qse_tio_setcmgr (qse_tio_t* tio, qse_cmgr_t* cmgr) } int qse_tio_attachin ( - qse_tio_t* tio, qse_tio_io_fun_t input, + qse_tio_t* tio, qse_tio_io_impl_t input, qse_mchar_t* bufptr, qse_size_t bufcapa) { qse_mchar_t* xbufptr; @@ -206,7 +206,7 @@ int qse_tio_detachin (qse_tio_t* tio) } int qse_tio_attachout ( - qse_tio_t* tio, qse_tio_io_fun_t output, + qse_tio_t* tio, qse_tio_io_impl_t output, qse_mchar_t* bufptr, qse_size_t bufcapa) { qse_mchar_t* xbufptr; diff --git a/qse/lib/net/httpd-std.c b/qse/lib/net/httpd-std.c index da4adbb8..f089a3e3 100644 --- a/qse/lib/net/httpd-std.c +++ b/qse/lib/net/httpd-std.c @@ -345,6 +345,7 @@ struct httpd_xtn_t #if defined(HAVE_SSL) SSL_CTX* ssl_ctx; #endif + qse_httpd_ecb_t ecb; }; #if defined(HAVE_SSL) @@ -412,22 +413,17 @@ qse_httpd_t* qse_httpd_openstdwithmmgr (qse_mmgr_t* mmgr, qse_size_t xtnsize) qse_httpd_t* httpd; httpd_xtn_t* xtn; - static qse_httpd_ecb_t std_ecb = - { - QSE_FV(.close, cleanup_standard_httpd) - }; - httpd = qse_httpd_open (mmgr, QSE_SIZEOF(httpd_xtn_t) + xtnsize); if (httpd == QSE_NULL) return QSE_NULL; xtn = (httpd_xtn_t*)qse_httpd_getxtn (httpd); - QSE_MEMSET (xtn, 0, QSE_SIZEOF(httpd_xtn_t) + xtnsize); #if defined(HAVE_SSL) /*init_xtn_ssl (xtn, "http01.pem", "http01.key");*/ #endif - qse_httpd_pushecb (httpd, &std_ecb); + xtn->ecb.close = cleanup_standard_httpd; + qse_httpd_pushecb (httpd, &xtn->ecb); return httpd; } diff --git a/qse/lib/sed/sed.c b/qse/lib/sed/sed.c index 5781049c..30bed201 100644 --- a/qse/lib/sed/sed.c +++ b/qse/lib/sed/sed.c @@ -1965,7 +1965,7 @@ static int get_command (qse_sed_t* sed, qse_sed_cmd_t* cmd) return 0; } -int qse_sed_comp (qse_sed_t* sed, qse_sed_io_fun_t inf) +int qse_sed_comp (qse_sed_t* sed, qse_sed_io_impl_t inf) { qse_cint_t c; qse_sed_cmd_t* cmd = QSE_NULL; @@ -3902,8 +3902,7 @@ static int emit_output (qse_sed_t* sed, int skipline) return 0; } - -int qse_sed_exec (qse_sed_t* sed, qse_sed_io_fun_t inf, qse_sed_io_fun_t outf) +int qse_sed_exec (qse_sed_t* sed, qse_sed_io_impl_t inf, qse_sed_io_impl_t outf) { qse_ssize_t n; int ret = 0; diff --git a/qse/lib/sed/sed.h b/qse/lib/sed/sed.h index 8012f1d3..79a4c3b1 100644 --- a/qse/lib/sed/sed.h +++ b/qse/lib/sed/sed.h @@ -104,7 +104,7 @@ struct qse_sed_t /** source text pointers */ struct { - qse_sed_io_fun_t fun; /**< input stream handler */ + qse_sed_io_impl_t fun; /**< input stream handler */ qse_sed_io_arg_t arg; qse_char_t buf[1024]; int eof; @@ -156,7 +156,7 @@ struct qse_sed_t /** data needed for output streams and files */ struct { - qse_sed_io_fun_t fun; /**< an output handler */ + qse_sed_io_impl_t fun; /**< an output handler */ qse_sed_io_arg_t arg; /**< output handling data */ qse_char_t buf[2048]; @@ -174,7 +174,7 @@ struct qse_sed_t /** data needed for input streams */ struct { - qse_sed_io_fun_t fun; /**< an input handler */ + qse_sed_io_impl_t fun; /**< an input handler */ qse_sed_io_arg_t arg; /**< input handling data */ qse_char_t xbuf[1]; /**< a read-ahead buffer */ diff --git a/qse/lib/sed/std.c b/qse/lib/sed/std.c index b439f643..4b3910ad 100644 --- a/qse/lib/sed/std.c +++ b/qse/lib/sed/std.c @@ -101,18 +101,7 @@ qse_sed_t* qse_sed_openstd (qse_size_t xtnsize) qse_sed_t* qse_sed_openstdwithmmgr (qse_mmgr_t* mmgr, qse_size_t xtnsize) { - qse_sed_t* sed; - xtn_t* xtn; - - /* create an object */ - sed = qse_sed_open (mmgr, QSE_SIZEOF(xtn_t) + xtnsize); - if (sed == QSE_NULL) return QSE_NULL; - - /* initialize extension */ - xtn = (xtn_t*) QSE_XTN (sed); - QSE_MEMSET (xtn, 0, QSE_SIZEOF(xtn_t)); - - return sed; + return qse_sed_open (mmgr, QSE_SIZEOF(xtn_t) + xtnsize); } void* qse_sed_getxtnstd (qse_sed_t* sed) diff --git a/qse/regress/awk/lang-049.awk b/qse/regress/awk/lang-049.awk new file mode 100644 index 00000000..fbc6d2f5 --- /dev/null +++ b/qse/regress/awk/lang-049.awk @@ -0,0 +1,2 @@ +# this should cause a syntax error since printf requries an argument +BEGIN { printf; } diff --git a/qse/regress/awk/regress.out b/qse/regress/awk/regress.out index a5886adc..0f129e98 100644 --- a/qse/regress/awk/regress.out +++ b/qse/regress/awk/regress.out @@ -1352,7 +1352,7 @@ BEGIN { printf ("%s\n",10.34); } -ERROR: CODE 104 LINE 3 COLUMN 2 - recursion detected in format conversion +ERROR: CODE 102 LINE 3 COLUMN 2 - recursion detected in format conversion -------------------------------------------------------------------------------- [CMD] qseawk --newline=on -d- -f lang-014.awk &1 -------------------------------------------------------------------------------- @@ -2454,6 +2454,10 @@ BEGIN { 127.0.0.1 192.168.1.1 -------------------------------------------------------------------------------- +[CMD] qseawk --newline=on -d- -f lang-049.awk &1 +-------------------------------------------------------------------------------- +ERROR: CODE 60 LINE 2 COLUMN 9 - no argument provided +-------------------------------------------------------------------------------- [CMD] qseawk --newline=on -F: -f columnate.awk passwd.dat &1 -------------------------------------------------------------------------------- root x 0 0 root /root /bin/bash diff --git a/qse/regress/awk/regress.out.xma b/qse/regress/awk/regress.out.xma index fe92c53b..fb069136 100644 --- a/qse/regress/awk/regress.out.xma +++ b/qse/regress/awk/regress.out.xma @@ -1352,7 +1352,7 @@ BEGIN { printf ("%s\n",10.34); } -ERROR: CODE 104 LINE 3 COLUMN 2 - recursion detected in format conversion +ERROR: CODE 102 LINE 3 COLUMN 2 - recursion detected in format conversion -------------------------------------------------------------------------------- [CMD] qseawk -m 500000 --newline=on -d- -f lang-014.awk &1 -------------------------------------------------------------------------------- @@ -2454,6 +2454,10 @@ BEGIN { 127.0.0.1 192.168.1.1 -------------------------------------------------------------------------------- +[CMD] qseawk -m 500000 --newline=on -d- -f lang-049.awk &1 +-------------------------------------------------------------------------------- +ERROR: CODE 60 LINE 2 COLUMN 9 - no argument provided +-------------------------------------------------------------------------------- [CMD] qseawk -m 500000 --newline=on -F: -f columnate.awk passwd.dat &1 -------------------------------------------------------------------------------- root x 0 0 root /root /bin/bash diff --git a/qse/regress/awk/regress.sh.in b/qse/regress/awk/regress.sh.in index 927c413c..fc7a4ab9 100755 --- a/qse/regress/awk/regress.sh.in +++ b/qse/regress/awk/regress.sh.in @@ -175,6 +175,7 @@ PROGS=" lang-046.awk!lang-046.dat2!!--newline=on -d- -vdatadir=@abs_srcdir@ -vdatafile=lang-046.dat1 lang-047.awk!!!--newline=on --tolerant=on -d- lang-048.awk!!!--newline=on --extraops=on -d- + lang-049.awk!!!--newline=on -d- columnate.awk!passwd.dat!!--newline=on -F: levenshtein-utests.awk!!!--newline=on --include=on diff --git a/qse/samples/awk/awk11.c b/qse/samples/awk/awk11.c index f086da24..fd904a60 100644 --- a/qse/samples/awk/awk11.c +++ b/qse/samples/awk/awk11.c @@ -25,7 +25,7 @@ const qse_char_t* src = QSE_T("BEGIN { print \"hello, world\" | \"dir\"; }"); struct rtx_xtn_t { - qse_awk_rio_fun_t old_pipe_handler; + qse_awk_rio_impl_t old_pipe_handler; }; static qse_ssize_t new_pipe_handler (