From e66a3721196fc70b9e00a4529d817a3b38a0a0d4 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sun, 21 Jun 2009 06:47:34 +0000 Subject: [PATCH] added -v var=val to cmd/awk/awk.c --- qse/cmd/awk/awk.c | 328 +++++++++++++++++++++--------------- qse/include/qse/awk/Awk.hpp | 3 +- qse/include/qse/awk/awk.h | 96 +++++------ qse/include/qse/awk/std.h | 23 +-- qse/include/qse/cmn/map.h | 149 ++++++---------- qse/lib/awk/err.c | 3 +- qse/lib/awk/parse.c | 24 ++- qse/lib/awk/rec.c | 38 +---- qse/lib/awk/std.c | 4 +- qse/lib/awk/val.c | 26 ++- 10 files changed, 348 insertions(+), 346 deletions(-) diff --git a/qse/cmd/awk/awk.c b/qse/cmd/awk/awk.c index 1c1ff826..6c9de0be 100644 --- a/qse/cmd/awk/awk.c +++ b/qse/cmd/awk/awk.c @@ -1,5 +1,5 @@ /* - * $Id: awk.c 204 2009-06-18 12:08:06Z hyunghwan.chung $ + * $Id: awk.c 205 2009-06-20 12:47:34Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -42,10 +42,10 @@ # include #endif -static qse_awk_rtx_t* app_rtx = NULL; +static qse_awk_rtx_t* app_rtx = QSE_NULL; static int app_debug = 0; -struct argout_t +struct arg_t { qse_awk_parsestd_type_t ist; /* input source type */ union @@ -58,14 +58,19 @@ struct argout_t qse_awk_parsestd_type_t ost; /* output source type */ qse_char_t* osf; /* output source file */ - - qse_char_t** arg; qse_char_t** icf; /* input console files */ qse_size_t icfl; /* the number of input console files */ - qse_map_t* vm; /* global variable map */ + qse_map_t* gvm; /* global variable map */ qse_char_t* fs; /* field separator */ }; +struct gvmv_t +{ + int idx; + qse_char_t* ptr; + qse_size_t len; +}; + static void dprint (const qse_char_t* fmt, ...) { if (app_debug) @@ -185,16 +190,33 @@ static void on_run_statement ( /*dprint (L"running %d\n", (int)line);*/ } +static qse_map_walk_t set_global ( + qse_map_t* map, qse_map_pair_t* pair, void* arg) +{ + qse_awk_val_t* v; + qse_awk_rtx_t* rtx = (qse_awk_rtx_t*)arg; + struct gvmv_t* gvmv = (struct gvmv_t*)QSE_MAP_VPTR(pair); + + v = qse_awk_rtx_makenstrval (rtx, gvmv->ptr, gvmv->len); + if (v == QSE_NULL) return QSE_MAP_WALK_STOP; + + qse_awk_rtx_refupval (rtx, v); + qse_awk_rtx_setgbl (rtx, gvmv->idx, v); + qse_awk_rtx_refdownval (rtx, v); + + return QSE_MAP_WALK_FORWARD; +} + static int on_run_enter (qse_awk_rtx_t* rtx, void* data) { - struct argout_t* ao = (struct argout_t*)data; + struct arg_t* arg = (struct arg_t*)data; - if (ao->fs != QSE_NULL) + if (arg->fs != QSE_NULL) { qse_awk_val_t* fs; /* compose a string value to use to set FS to */ - fs = qse_awk_rtx_makestrval0 (rtx, ao->fs); + fs = qse_awk_rtx_makestrval0 (rtx, arg->fs); if (fs == QSE_NULL) return -1; /* change FS according to the command line argument */ @@ -203,6 +225,15 @@ static int on_run_enter (qse_awk_rtx_t* rtx, void* data) qse_awk_rtx_refdownval (rtx, fs); } + if (arg->gvm != QSE_NULL) + { + /* set the value of user-defined global variables + * to a runtime context */ + qse_awk_rtx_seterrnum (rtx, QSE_AWK_ENOERR); + qse_map_walk (arg->gvm, set_global, rtx); + if (qse_awk_rtx_geterrnum(rtx) != QSE_AWK_ENOERR) return -1; + } + return 0; } @@ -270,11 +301,12 @@ static void print_usage (const qse_char_t* argv0) qse_printf (QSE_T(" -f/--file sourcefile set the source script file\n")); qse_printf (QSE_T(" -o/--deparsed-file deparsedfile set the deparsing output file\n")); qse_printf (QSE_T(" -F/--field-separator string set a field separator(FS)\n")); + qse_printf (QSE_T(" -v/--assign var=value add a global variable with a value\n")); qse_printf (QSE_T("\nYou may specify the following options to change the behavior of the interpreter.\n")); for (j = 0; j < QSE_COUNTOF(otab); j++) { - qse_printf (QSE_T(" -%-20s -no%-20s\n"), otab[j].name, otab[j].name); + qse_printf (QSE_T(" --%-20s --no%-20s\n"), otab[j].name, otab[j].name); } } @@ -320,7 +352,7 @@ static void out_of_memory (void) qse_fprintf (QSE_STDERR, QSE_T("Error: out of memory\n")); } -static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao) +static int comparg (int argc, qse_char_t* argv[], struct arg_t* arg) { static qse_opt_lng_t lng[] = { @@ -331,11 +363,9 @@ static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao) { QSE_T("idiv"), 0 }, { QSE_T("extio"), 0 }, { QSE_T("newline"), 0 }, - { QSE_T("baseone"), 0 }, { QSE_T("stripspaces"), 0 }, { QSE_T("nextofile"), 0 }, { QSE_T("crlf"), 0 }, - { QSE_T("argstomain"), 0 }, { QSE_T("reset"), 0 }, { QSE_T("maptovar"), 0 }, { QSE_T("pablock"), 0 }, @@ -368,42 +398,43 @@ static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao) qse_char_t* osf = QSE_NULL; /* output source file */ qse_char_t** icf = QSE_NULL; /* input console files */ - qse_map_t* vm = QSE_NULL; /* global variable map */ + qse_map_t* gvm = QSE_NULL; /* global variable map */ qse_char_t* fs = QSE_NULL; /* field separator */ - memset (ao, 0, QSE_SIZEOF(*ao)); + memset (arg, 0, QSE_SIZEOF(*arg)); isf = (qse_char_t**) malloc (QSE_SIZEOF(*isf) * isfc); if (isf == QSE_NULL) { out_of_memory (); - ABORT (oops); + goto oops; } - vm = qse_map_open (QSE_NULL, 0, 30, 70); - if (vm == QSE_NULL) + gvm = qse_map_open (QSE_NULL, 0, 30, 70); + if (gvm == QSE_NULL) { out_of_memory (); - ABORT (oops); + goto oops; } - qse_map_setcopier (vm, QSE_MAP_KEY, QSE_MAP_COPIER_INLINE); - qse_map_setcopier (vm, QSE_MAP_VAL, QSE_MAP_COPIER_INLINE); - qse_map_setscale (vm, QSE_MAP_KEY, QSE_SIZEOF(qse_char_t)); - qse_map_setscale (vm, QSE_MAP_VAL, QSE_SIZEOF(qse_char_t)); + /*qse_map_setcopier (gvm, QSE_MAP_KEY, QSE_MAP_COPIER_INLINE);*/ + qse_map_setscale (gvm, QSE_MAP_KEY, QSE_SIZEOF(qse_char_t)); + qse_map_setcopier (gvm, QSE_MAP_VAL, QSE_MAP_COPIER_INLINE); + qse_map_setscale (gvm, QSE_MAP_VAL, QSE_SIZEOF(struct gvmv_t)); while ((c = qse_getopt (argc, argv, &opt)) != QSE_CHAR_EOF) { switch (c) { case 0: + /* TODO: handle long options ... */ qse_printf (QSE_T(">>> [%s] [%s]\n"), opt.lngopt, opt.arg); break; case QSE_T('h'): print_usage (argv[0]); if (isf != QSE_NULL) free (isf); - if (vm != QSE_NULL) qse_map_close (vm); - return 1; + if (gvm != QSE_NULL) qse_map_close (gvm); + return 0; case QSE_T('d'): { @@ -420,7 +451,7 @@ static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao) if (tmp == QSE_NULL) { out_of_memory (); - ABORT (oops); + goto oops; } isf = tmp; @@ -445,19 +476,26 @@ static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao) case QSE_T('v'): { - qse_char_t* eq = qse_strchr(opt.arg, QSE_T('=')); + struct gvmv_t gvmv; + qse_char_t* eq; + + eq = qse_strchr(opt.arg, QSE_T('=')); if (eq == QSE_NULL) { /* INVALID VALUE... */ - ABORT (oops); + goto oops; } *eq = QSE_T('\0'); - if (qse_map_upsert (vm, opt.arg, qse_strlen(opt.arg)+1, eq, qse_strlen(eq)+1) == QSE_NULL) + gvmv.idx = -1; + gvmv.ptr = ++eq; + gvmv.len = qse_strlen(eq); + + if (qse_map_upsert (gvm, opt.arg, qse_strlen(opt.arg), &gvmv, 1) == QSE_NULL) { out_of_memory (); - ABORT (oops); + goto oops; } break; } @@ -473,7 +511,7 @@ static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao) qse_printf (QSE_T("Error: illegal option - %c\n"), opt.opt); } - ABORT (oops); + goto oops; } case QSE_T(':'): @@ -487,11 +525,11 @@ static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao) qse_printf (QSE_T("Error: bad argument for %c\n"), opt.opt); } - ABORT (oops); + goto oops; } default: - ABORT (oops); + goto oops; } } @@ -502,19 +540,19 @@ static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao) if (opt.ind >= argc) { /* no source code specified */ - ABORT (oops); + goto oops; } /* the source code is the string, not from the file */ - ao->ist = QSE_AWK_PARSESTD_CP; - ao->isp.str = argv[opt.ind++]; + arg->ist = QSE_AWK_PARSESTD_CP; + arg->isp.str = argv[opt.ind++]; free (isf); } else { - ao->ist = QSE_AWK_PARSESTD_FILE; - ao->isp.files = isf; + arg->ist = QSE_AWK_PARSESTD_FILE; + arg->isp.files = isf; } if (opt.ind < argc) @@ -526,7 +564,7 @@ static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao) if (icf == QSE_NULL) { out_of_memory (); - ABORT (oops); + goto oops; } if (opt.ind >= argc) @@ -542,34 +580,107 @@ static int handle_args (int argc, qse_char_t* argv[], struct argout_t* ao) icf[icfl] = QSE_NULL; } - ao->ost = QSE_AWK_PARSESTD_FILE; - ao->osf = osf; + arg->ost = QSE_AWK_PARSESTD_FILE; + arg->osf = osf; - ao->icf = icf; - ao->icfl = icfl; - ao->vm = vm; - ao->fs = fs; + arg->icf = icf; + arg->icfl = icfl; + arg->gvm = gvm; + arg->fs = fs; - return 0; + return 1; oops: - if (vm != QSE_NULL) qse_map_close (vm); + if (gvm != QSE_NULL) qse_map_close (gvm); if (icf != QSE_NULL) free (icf); if (isf != QSE_NULL) free (isf); return -1; } -static qse_awk_t* open_awk (void) +static void freearg (struct arg_t* arg) +{ + if (arg->ist == QSE_AWK_PARSESTD_FILE && + arg->isp.files != QSE_NULL) free (arg->isp.files); + /*if (arg->osf != QSE_NULL) free (arg->osf);*/ + if (arg->icf != QSE_NULL) free (arg->icf); + if (arg->gvm != QSE_NULL) qse_map_close (arg->gvm); +} + +static void print_awkerr (qse_awk_t* awk) +{ + qse_printf ( + QSE_T("ERROR: CODE [%d] LINE [%u] %s\n"), + qse_awk_geterrnum(awk), + (unsigned int)qse_awk_geterrlin(awk), + qse_awk_geterrmsg(awk) + ); +} + +static void print_rtxerr (qse_awk_rtx_t* rtx) +{ + qse_printf ( + QSE_T("ERROR: CODE [%d] LINE [%u] %s\n"), + qse_awk_rtx_geterrnum(rtx), + (unsigned int)qse_awk_rtx_geterrlin(rtx), + qse_awk_rtx_geterrmsg(rtx) + ); +} + +qse_map_walk_t add_global (qse_map_t* map, qse_map_pair_t* pair, void* arg) +{ + qse_awk_t* awk = (qse_awk_t*)arg; + struct gvmv_t* gvmv = (struct gvmv_t*)QSE_MAP_VPTR(pair); + + gvmv->idx = qse_awk_addgbl (awk, QSE_MAP_KPTR(pair), QSE_MAP_KLEN(pair)); + if (gvmv->idx <= -1) + { + return QSE_MAP_WALK_STOP; + } + + return QSE_MAP_WALK_FORWARD; +} + +static int awk_main (int argc, qse_char_t* argv[]) { qse_awk_t* awk; + qse_awk_rtx_t* rtx; + qse_awk_rcb_t rcb; + + int i; + struct arg_t arg; + int ret = -1; + + /* TODO: change it to support multiple source files */ + qse_awk_parsestd_in_t psin; + qse_awk_parsestd_out_t psout; + + qse_memset (&arg, 0, QSE_SIZEOF(arg)); + + i = comparg (argc, argv, &arg); + if (i <= -1) + { + print_usage (argv[0]); + return -1; + } + if (i == 0) return 0; + + psin.type = arg.ist; + if (arg.ist == QSE_AWK_PARSESTD_CP) psin.u.cp = arg.isp.str; + else psin.u.file = arg.isp.files[0]; + + if (arg.osf != QSE_NULL) + { + psout.type = arg.ost; + psout.u.file = arg.osf; + } awk = qse_awk_openstd (0); if (awk == QSE_NULL) { qse_printf (QSE_T("ERROR: cannot open awk\n")); - return QSE_NULL; + goto oops; } - + /* TODO: get depth from command line */ qse_awk_setmaxdepth ( awk, QSE_AWK_DEPTH_BLOCK_PARSE | QSE_AWK_DEPTH_EXPR_PARSE, 50); @@ -580,118 +691,55 @@ static qse_awk_t* open_awk (void) QSE_T("sleep"), 5, 0, 1, 1, QSE_NULL, fnc_sleep) == QSE_NULL) { - qse_awk_close (awk); - qse_printf (QSE_T("ERROR: cannot add function 'sleep'\n")); - return QSE_NULL; + print_awkerr (awk); + goto oops; } - return awk; -} - -static int awk_main (int argc, qse_char_t* argv[]) -{ - qse_awk_t* awk; - qse_awk_rtx_t* rtx; - qse_awk_rcb_t rcb; - - int i; - int runarg_count = 0; - qse_cstr_t runarg[128]; - struct argout_t ao; - int ret = 0; - - /* TODO: change it to support multiple source files */ - qse_awk_parsestd_in_t psin; - qse_awk_parsestd_out_t psout; - - qse_memset (&ao, 0, QSE_SIZEOF(ao)); - - i = handle_args (argc, argv, &ao); - if (i == -1) + qse_awk_seterrnum (awk, QSE_AWK_ENOERR); + qse_map_walk (arg.gvm, add_global, awk); + if (qse_awk_geterrnum(awk) != QSE_AWK_ENOERR) { - print_usage (argv[0]); - return -1; + print_awkerr (awk); + goto oops; } - if (i == 1) return 0; - - runarg[runarg_count].ptr = NULL; - runarg[runarg_count].len = 0; - - awk = open_awk (); - if (awk == QSE_NULL) return -1; - psin.type = ao.ist; - if (ao.ist == QSE_AWK_PARSESTD_CP) psin.u.cp = ao.isp.str; - else psin.u.file = ao.isp.files[0]; - - if (ao.osf != QSE_NULL) - { - psout.type = ao.ost; - psout.u.file = ao.osf; - } - if (qse_awk_parsestd (awk, &psin, - ((ao.osf == QSE_NULL)? QSE_NULL: &psout)) == -1) + ((arg.osf == QSE_NULL)? QSE_NULL: &psout)) == -1) { - qse_printf ( - QSE_T("PARSE ERROR: CODE [%d] LINE [%u] %s\n"), - qse_awk_geterrnum(awk), - (unsigned int)qse_awk_geterrlin(awk), - qse_awk_geterrmsg(awk) - ); - - ret = -1; + print_awkerr (awk); goto oops; } rcb.on_enter = on_run_enter; rcb.on_statement = on_run_statement; rcb.on_exit = on_run_exit; - rcb.data = &ao; + rcb.data = &arg; - rtx = qse_awk_rtx_openstd (awk, 0, QSE_T("qseawk"), ao.icf, QSE_NULL); + rtx = qse_awk_rtx_openstd (awk, 0, QSE_T("qseawk"), arg.icf, QSE_NULL); if (rtx == QSE_NULL) { - qse_printf ( - QSE_T("PARSE ERROR: CODE [%d] LINE [%u] %s\n"), - qse_awk_geterrnum(awk), - (unsigned int)qse_awk_geterrlin(awk), - qse_awk_geterrmsg(awk) - ); - - ret = -1; + print_awkerr (awk); + goto oops; } - else + + app_rtx = rtx; + qse_awk_rtx_setrcb (rtx, &rcb); + + set_intr_run (); + ret = qse_awk_rtx_loop (rtx); + unset_intr_run (); + + if (ret == -1) { - app_rtx = rtx; - set_intr_run (); - - qse_awk_rtx_setrcb (rtx, &rcb); - ret = qse_awk_rtx_loop (rtx); - - unset_intr_run (); - - if (ret == -1) - { - qse_printf (QSE_T("RUN ERROR: CODE [%d] LINE [%u] %s\n"), - (unsigned int)qse_awk_rtx_geterrnum(rtx), - (unsigned int)qse_awk_rtx_geterrlin(rtx), - qse_awk_rtx_geterrmsg(rtx) - ); - } - - qse_awk_rtx_close (rtx); + print_rtxerr (rtx); + goto oops; } oops: - qse_awk_close (awk); - - if (ao.ist == QSE_AWK_PARSESTD_FILE && - ao.isp.files != QSE_NULL) free (ao.isp.files); - /*if (ao.osf != QSE_NULL) free (ao.osf);*/ - if (ao.icf != QSE_NULL) free (ao.icf); - if (ao.vm != QSE_NULL) qse_map_close (ao.vm); + if (rtx != QSE_NULL) qse_awk_rtx_close (rtx); + if (awk != QSE_NULL) qse_awk_close (awk); + freearg (&arg); return ret; } diff --git a/qse/include/qse/awk/Awk.hpp b/qse/include/qse/awk/Awk.hpp index 3d079d7a..fd5a8218 100644 --- a/qse/include/qse/awk/Awk.hpp +++ b/qse/include/qse/awk/Awk.hpp @@ -1,5 +1,5 @@ /* - * $Id: Awk.hpp 204 2009-06-18 12:08:06Z hyunghwan.chung $ + * $Id: Awk.hpp 205 2009-06-20 12:47:34Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -462,6 +462,7 @@ public: ERR_BLKEND = QSE_AWK_EBLKEND, ERR_DUPBEG = QSE_AWK_EDUPBEG, ERR_DUPEND = QSE_AWK_EDUPEND, + ERR_KWRED = QSE_AWK_EKWRED, ERR_FNCRED = QSE_AWK_EFNCRED, ERR_FUNRED = QSE_AWK_EFUNRED, ERR_GBLRED = QSE_AWK_EGBLRED, diff --git a/qse/include/qse/awk/awk.h b/qse/include/qse/awk/awk.h index 3c4bbb73..cbc645f1 100644 --- a/qse/include/qse/awk/awk.h +++ b/qse/include/qse/awk/awk.h @@ -1,5 +1,5 @@ /* - * $Id: awk.h 204 2009-06-18 12:08:06Z hyunghwan.chung $ + * $Id: awk.h 205 2009-06-20 12:47:34Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -495,6 +495,7 @@ enum qse_awk_errnum_t QSE_AWK_EBLKEND, /* END requires an action block */ QSE_AWK_EDUPBEG, /* duplicate BEGIN */ QSE_AWK_EDUPEND, /* duplicate END */ + QSE_AWK_EKWRED, /* keyword redefined */ QSE_AWK_EFNCRED, /* intrinsic function redefined */ QSE_AWK_EFUNRED, /* function redefined */ QSE_AWK_EGBLRED, /* global variable redefined */ @@ -1026,78 +1027,59 @@ void qse_awk_clrfnc ( /*****/ -/****f* AWK/qse_awk_parse - * NAME - * qse_awk_parse - parse source code - * SYNOPSIS +/** + * The qse_awk_parse() function parses the source script. + * @return 0 on success, -1 on failure. */ int qse_awk_parse ( - qse_awk_t* awk, - qse_awk_sio_t* sio + qse_awk_t* awk, /**< an awk object */ + qse_awk_sio_t* sio /**< source stream I/O handler */ ); -/******/ -/****f* AWK/qse_awk_alloc - * NAME - * qse_awk_alloc - allocate dynamic memory - * RETURN - * the pointer to the memory space allocated on success, QSE_NULL on failure - * SYNOPSIS +/** + * The qse_awk_alloc() function allocates dynamic memory. + * @return a pointer to memory space allocated on success, QSE_NULL on failure */ void* qse_awk_alloc ( - qse_awk_t* awk /* the pointer to a qse_awk_t instance */, - qse_size_t size /* the size of memory to allocate in bytes */ + qse_awk_t* awk, /**< an awk object */ + qse_size_t size /**< size of memory to allocate in bytes */ ); -/******/ -/****f* AWK/qse_awk_free - * NAME - * qse_awk_free - free dynamic memory - * SYNOPSIS +/** + * The qse_awk_free() function frees dynamic memory allocated. */ void qse_awk_free ( - qse_awk_t* awk /* the pointer to a qse_awk_t instance */, - void* ptr /* the pointer to the memory space to free */ + qse_awk_t* awk, /**< an awk object */ + void* ptr /**< memory space to free */ ); -/******/ -/****f* AWK/qse_awk_strdup - * NAME - * qse_awk_strdup - duplicate a null-terminated string - * DESCRIPTION - * The qse_awk_strdup() function is used to duplicate a string using - * the memory manager used by the associated qse_awk_t instance. - * The new string should be freed using the qse_awk_free() function. - * RETURN - * The qse_awk_strdup() function returns the pointer to a new string which - * is a duplicate of the string s. It returns QSE_NULL on failure. - * SYNOPSIS +/** + * The qse_awk_strdup() function is used to duplicate a string using + * the memory manager used by the associated qse_awk_t instance. + * The new string should be freed using the qse_awk_free() function. + * + * @return a pointer to a new string duplicated of @a s on success, + * QSE_NULL on failure. */ qse_char_t* qse_awk_strdup ( - qse_awk_t* awk /* the pointer to a qse_awk_t instance */, - const qse_char_t* str /* the pointer to a string */ + qse_awk_t* awk, /**< an awk object */ + const qse_char_t* str /**< a string pointer */ ); -/******/ -/****f* AWK/qse_awk_strxdup - * NAME - * qse_awk_strxdup - duplicate a length-delimited string - * DESCRIPTION - * The qse_awk_strxdup() function is used to duplicate a string whose length - * is as long as len characters using the memory manager used by the - * qse_awk_t instance. The new string should be freed using the qse_awk_free() - * function. - * RETURN - * The qse_awk_strxdup() function returns the pointer to a new string which - * is a duplicate of the string s on success. It returns QSE_NULL on failure. - * SYNOPSIS +/** + * The qse_awk_strxdup() function is used to duplicate a string whose length + * is as long as len characters using the memory manager used by the + * qse_awk_t instance. The new string should be freed using the qse_awk_free() + * function. + * + * @return a pointer to a new string duplicated of @a s on success, + * QSE_NULL on failure. */ qse_char_t* qse_awk_strxdup ( - qse_awk_t* awk, - const qse_char_t* str, - qse_size_t len + qse_awk_t* awk, /**< an awk object */ + const qse_char_t* str, /**< a string pointer */ + qse_size_t len /**< the number of character in a string */ ); -/******/ qse_long_t qse_awk_strxtolong ( qse_awk_t* awk, @@ -1476,6 +1458,12 @@ qse_awk_val_t* qse_awk_rtx_makestrval2 ( qse_size_t len2 ); +qse_awk_val_t* qse_awk_rtx_makenstrval ( + qse_awk_rtx_t* rtx, + const qse_char_t* str, + qse_size_t len +); + qse_awk_val_t* qse_awk_rtx_makerexval ( qse_awk_rtx_t* rtx, const qse_char_t* buf, diff --git a/qse/include/qse/awk/std.h b/qse/include/qse/awk/std.h index fea5f4e4..80612841 100644 --- a/qse/include/qse/awk/std.h +++ b/qse/include/qse/awk/std.h @@ -1,5 +1,5 @@ /* - * $Id: std.h 196 2009-06-11 07:44:44Z hyunghwan.chung $ + * $Id: std.h 205 2009-06-20 12:47:34Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -22,9 +22,15 @@ #include /** @file - * Standard AWK Interpreter + * This file defines functions and data types that help you create + * an awk interpreter with less effort. It is designed to be as close + * to conventional awk implementations as possible. + * + * The source script handler does not evaluate a file name of the "var=val" + * form as an assignment expression. Instead, it just treats it as a + * normal file name. + * * @todo - * - console name handling an empty string("") and assignment (v=yyyy) * - StdAwk ARGV and console name handling */ @@ -121,8 +127,8 @@ int qse_awk_parsestd ( /** * The qse_awk_rtx_openstd() function creates a standard runtime context. - * The caller should keep the contents of icf and ocf valid throughout - * the lifetime of the runtime context created. The runtime context + * The caller should keep the contents of @a icf and @a ocf valid throughout + * the lifetime of the runtime context created. */ qse_awk_rtx_t* qse_awk_rtx_openstd ( qse_awk_t* awk, @@ -132,15 +138,12 @@ qse_awk_rtx_t* qse_awk_rtx_openstd ( const qse_char_t*const* ocf ); -/****f* AWK/qse_awk_rtx_getxtnstd - * NAME - * qse_awk_rtx_getxtnstd - get the pointer to extension space - * SYNOPSIS +/** + * The qse_awk_rtx_getxtnstd() gets the pointer to extension space. */ void* qse_awk_rtx_getxtnstd ( qse_awk_rtx_t* rtx ); -/******/ #ifdef __cplusplus } diff --git a/qse/include/qse/cmn/map.h b/qse/include/qse/cmn/map.h index c1e2bd0d..6b420b3c 100644 --- a/qse/include/qse/cmn/map.h +++ b/qse/include/qse/cmn/map.h @@ -1,5 +1,5 @@ /* - * $Id: map.h 101 2009-03-15 14:36:05Z hyunghwan.chung $ + * $Id: map.h 205 2009-06-20 12:47:34Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -22,13 +22,9 @@ #include #include -/****o* Common/Hash Map - * DESCRIPTION - * A hash map maintains buckets for key/value pairs with the same key hash - * chained under the same bucket. - * - * #include - ****** +/**@file + * A hash map maintains buckets for key/value pairs with the same key hash + * chained under the same bucket. */ /* values that can be returned by qse_map_walker_t */ @@ -49,29 +45,23 @@ typedef struct qse_map_pair_t qse_map_pair_t; typedef enum qse_map_walk_t qse_map_walk_t; typedef enum qse_map_id_t qse_map_id_t; -/****t* Common/qse_map_copier_t - * NAME - * qse_map_copier_t - define a pair contruction callback - * SYNOPSIS +/** + * The qse_map_copier_t type defines a pair contruction callback */ typedef void* (*qse_map_copier_t) ( qse_map_t* map /* a map */, void* dptr /* the pointer to a key or a value */, qse_size_t dlen /* the length of a key or a value */ ); -/******/ -/****t* Common/qse_map_freeer_t - * NAME - * qse_map_freeer_t - define a key/value destruction callback - * SYNOPSIS +/** + * The qse_map_freeer_t defines a key/value destruction callback */ typedef void (*qse_map_freeer_t) ( qse_map_t* map /* a map */, void* dptr /* the pointer to a key or a value */, qse_size_t dlen /* the length of a key or a value */ ); -/******/ /* key hasher */ typedef qse_size_t (*qse_map_hasher_t) ( @@ -80,108 +70,70 @@ typedef qse_size_t (*qse_map_hasher_t) ( qse_size_t klen /* the length of a key in bytes */ ); -/****t* Common/qse_map_comper_t - * NAME - * qse_map_comper_t - define a key comparator +/** + * The qse_map_comper_t type defines a key comparator that is called when + * the map needs to compare keys. A map is created with a default comparator + * which performs bitwise comparison between two keys. * - * DESCRIPTION - * The qse_map_comper_t type defines a key comparator that is called when - * the map needs to compare keys. A map is created with a default comparator - * which performs bitwise comparison between two keys. - * - * The comparator should return 0 if the keys are the same and a non-zero - * integer otherwise. - * - * SYNOPSIS + * The comparator should return 0 if the keys are the same and a non-zero + * integer otherwise. */ typedef int (*qse_map_comper_t) ( - qse_map_t* map /* a map */, - const void* kptr1 /* the pointer to a key */, - qse_size_t klen1 /* the length of a key */, - const void* kptr2 /* the pointer to a key */, - qse_size_t klen2 /* the length of a key */ + qse_map_t* map, /**< a map */ + const void* kptr1, /**< the pointer to a key */ + qse_size_t klen1, /**< the length of a key */ + const void* kptr2, /**< the pointer to a key */ + qse_size_t klen2 /**< the length of a key */ ); -/******/ -/****t* Common/qse_map_keeper_t - * NAME - * qse_map_keeper_t - define a value keeper - * - * DESCRIPTION - * The qse_map_keeper_t type defines a value keeper that is called when - * a value is retained in the context that it should be destroyed because - * it is identical to a new value. Two values are identical if their beginning - * pointers and their lengths are equal. - * - * SYNOPSIS +/** + * The qse_map_keeper_t type defines a value keeper that is called when + * a value is retained in the context that it should be destroyed because + * it is identical to a new value. Two values are identical if their beginning + * pointers and their lengths are equal. */ typedef void (*qse_map_keeper_t) ( - qse_map_t* map /* a map */, - void* vptr /* the pointer to a value */, - qse_size_t vlen /* the length of a value */ + qse_map_t* map, /**< a map */ + void* vptr, /**< value pointer */ + qse_size_t vlen /**< value length */ ); -/******/ -/****t* Common/qse_map_sizer_t - * NAME - * qse_map_sizer_t - define a bucket size calculator - * - * DESCRIPTION - * The qse_map_sizer_T type defines a bucket size claculator that is called - * when a map should resize the bucket. The current bucket size +1 is passed - * as the hint. - * - * SYNOPSIS +/** + * The qse_map_sizer_T type defines a bucket size claculator that is called + * when a map should resize the bucket. The current bucket size +1 is passed + * as the hint. */ typedef qse_size_t (*qse_map_sizer_t) ( - qse_map_t* map, /* a map */ - qse_size_t hint /* a sizing hint */ + qse_map_t* map, /**< a map */ + qse_size_t hint /**< a sizing hint */ ); -/******/ -/****t* Common/qse_map_walker_t - * NAME - * qse_map_walker_t - define a pair visitor - * - * SYNOPSIS +/** + * The qse_map_walker_t defines a pair visitor. */ typedef qse_map_walk_t (*qse_map_walker_t) ( - qse_map_t* map /* a map */, - qse_map_pair_t* pair /* the pointer to a key/value pair */, - void* arg /* the pointer to user-defined data */ + qse_map_t* map, /**< a map */ + qse_map_pair_t* pair, /**< the pointer to a key/value pair */ + void* arg /**< the pointer to user-defined data */ ); -/******/ -/****s* Common/qse_map_pair_t - * NAME - * qse_map_pair_t - define a pair - * - * DESCRIPTION - * A pair is composed of a key and a value. It maintains pointers to the - * beginning of a key and a value plus their length. The length is scaled - * down with the scale factor specified in an owning map. Use macros defined - * in the SEE ALSO section below to access individual fields. - * - * SEE ALSO - * QSE_MAP_KPTR, QSE_MAP_KLEN, QSE_MAP_VPTR, QSE_MAP_VLEN - * - * SYNOPSIS +/** + * The qse_map_pair_t type defines a map pair. A pair is composed of a key + * and a value. It maintains pointers to the beginning of a key and a value + * plus their length. The length is scaled down with the scale factor + * specified in an owning map. Use macros defined in the */ struct qse_map_pair_t { - void* kptr; /* the pointer to a key */ - qse_size_t klen; /* the length of a key */ - void* vptr; /* the pointer to a value */ - qse_size_t vlen; /* the length of a value */ - qse_map_pair_t* next; /* the next pair under the same slot */ + void* kptr; /**< the pointer to a key */ + qse_size_t klen; /**< the length of a key */ + void* vptr; /**< the pointer to a value */ + qse_size_t vlen; /**< the length of a value */ + qse_map_pair_t* next; /**< the next pair under the same slot */ }; -/*****/ -/****s* Common/qse_map_t - * NAME - * qse_map_t - define a hash map - * - * SYNOPSIS +/** + * The qse_map_t type defines a hash map. */ struct qse_map_t { @@ -201,7 +153,6 @@ struct qse_map_t qse_size_t threshold; qse_map_pair_t** bucket; }; -/******/ #define QSE_MAP_COPIER_SIMPLE ((qse_map_copier_t)1) #define QSE_MAP_COPIER_INLINE ((qse_map_copier_t)2) diff --git a/qse/lib/awk/err.c b/qse/lib/awk/err.c index 99c489d7..6a6a513b 100644 --- a/qse/lib/awk/err.c +++ b/qse/lib/awk/err.c @@ -1,5 +1,5 @@ /* - * $Id: err.c 199 2009-06-14 08:40:52Z hyunghwan.chung $ + * $Id: err.c 205 2009-06-20 12:47:34Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -88,6 +88,7 @@ const qse_char_t* qse_awk_dflerrstr (qse_awk_t* awk, qse_awk_errnum_t errnum) QSE_T("END not followed by a left bracket on the same line"), QSE_T("duplicate BEGIN"), QSE_T("duplicate END"), + QSE_T("keyword '${0}' redefined"), QSE_T("intrinsic function '${0}' redefined"), QSE_T("function '${0}' redefined"), QSE_T("global variable '${0}' redefined"), diff --git a/qse/lib/awk/parse.c b/qse/lib/awk/parse.c index 904b63d3..1cd781f1 100644 --- a/qse/lib/awk/parse.c +++ b/qse/lib/awk/parse.c @@ -1,5 +1,5 @@ /* - * $Id: parse.c 204 2009-06-18 12:08:06Z hyunghwan.chung $ + * $Id: parse.c 205 2009-06-20 12:47:34Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -1403,12 +1403,10 @@ static void adjust_static_globals (qse_awk_t* awk) if (gtab[id].valid != 0 && (awk->option & gtab[id].valid) != gtab[id].valid) { - /*awk->parse.gbls.buf[id].name.len = 0;*/ QSE_LDA_DLEN(awk->parse.gbls,id) = 0; } else { - /*awk->parse.gbls.buf[id].name.len = gtab[id].name_len;*/ QSE_LDA_DLEN(awk->parse.gbls,id) = gtab[id].name_len; } } @@ -1487,6 +1485,15 @@ static int add_global ( { qse_size_t ngbls; + /* check if it is a keyword */ + if (classify_ident (awk, name, len) != TOKEN_IDENT) + { + SETERRARG ( + awk, QSE_AWK_EKWRED, awk->token.line, + name, len); + return -1; + } + /* check if it conflict with a builtin function name */ if (qse_awk_getfnc (awk, name, len) != QSE_NULL) { @@ -1563,14 +1570,14 @@ int qse_awk_addgbl ( if (awk->tree.ngbls > awk->tree.ngbls_base) { - /* this function is not allow after qse_awk_parse is called */ + /* this function is not allowed after qse_awk_parse is called */ SETERR (awk, QSE_AWK_ENOPER); return -1; } n = add_global (awk, name, len, 0, 0); - /* update the count of the static gbls. + /* update the count of the static globals. * the total global count has been updated inside add_global. */ if (n >= 0) awk->tree.ngbls_base++; @@ -4662,7 +4669,7 @@ static int get_token (qse_awk_t* awk) } */ } - else if (QSE_AWK_ISALPHA (awk, c) || c == QSE_T('_')) + else if (c == QSE_T('_') || QSE_AWK_ISALPHA (awk, c)) { int type; @@ -4672,8 +4679,9 @@ static int get_token (qse_awk_t* awk) ADD_TOKEN_CHAR (awk, c); GET_CHAR_TO (awk, c); } - while (QSE_AWK_ISALPHA (awk, c) || - c == QSE_T('_') || QSE_AWK_ISDIGIT(awk,c)); + while (c == QSE_T('_') || + QSE_AWK_ISALPHA (awk, c) || + QSE_AWK_ISDIGIT (awk, c)); type = classify_ident (awk, QSE_STR_PTR(awk->token.name), diff --git a/qse/lib/awk/rec.c b/qse/lib/awk/rec.c index cdd034ed..1e5b70b1 100644 --- a/qse/lib/awk/rec.c +++ b/qse/lib/awk/rec.c @@ -1,5 +1,5 @@ /* - * $Id: rec.c 200 2009-06-14 13:22:00Z hyunghwan.chung $ + * $Id: rec.c 205 2009-06-20 12:47:34Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -31,10 +31,6 @@ int qse_awk_rtx_setrec ( if (idx == 0) { - qse_long_t l; - qse_real_t r; - int x; - if (str == QSE_STR_PTR(&run->inrec.line) && len == QSE_STR_LEN(&run->inrec.line)) { @@ -53,8 +49,7 @@ int qse_awk_rtx_setrec ( } } - x = qse_awk_rtx_strtonum (run, 1, str, len, &l, &r); - v = qse_awk_rtx_makestrval (run, str, len); + v = qse_awk_rtx_makenstrval (run, str, len); if (v == QSE_NULL) { @@ -62,14 +57,6 @@ int qse_awk_rtx_setrec ( return -1; } - if (x >= 0) - { - /* set the numeric string flag if a string - * can be converted to a number */ - QSE_ASSERT (x == 0 || x == 1); - v->nstr = x + 1; /* long -> 1, real -> 2 */ - } - QSE_ASSERT (run->inrec.d0->type == QSE_AWK_VAL_NIL); /* d0 should be cleared before the next line is reached * as it doesn't call qse_awk_rtx_refdownval on run->inrec.d0 */ @@ -215,10 +202,6 @@ static int split_record (qse_awk_rtx_t* run) while (p != QSE_NULL) { - qse_long_t l; - qse_real_t r; - int x; - if (fs_len <= 1) { p = qse_awk_rtx_strxntok ( @@ -247,25 +230,18 @@ static int split_record (qse_awk_rtx_t* run) run->inrec.flds[run->inrec.nflds].ptr = tok; run->inrec.flds[run->inrec.nflds].len = tok_len; - x = qse_awk_rtx_strtonum (run, 1, tok, tok_len, &l, &r); run->inrec.flds[run->inrec.nflds].val = - qse_awk_rtx_makestrval (run, tok, tok_len); + qse_awk_rtx_makenstrval (run, tok, tok_len); if (run->inrec.flds[run->inrec.nflds].val == QSE_NULL) { - if (fs_free != QSE_NULL) QSE_AWK_FREE (run->awk, fs_free); + if (fs_free != QSE_NULL) + QSE_AWK_FREE (run->awk, fs_free); return -1; } - if (x >= 0) - { - /* set the numeric string flags if a string - * can be converted to a number */ - QSE_ASSERT (x == 0 || x == 1); - run->inrec.flds[run->inrec.nflds].val->nstr = x + 1; - } - - qse_awk_rtx_refupval (run, run->inrec.flds[run->inrec.nflds].val); + qse_awk_rtx_refupval ( + run, run->inrec.flds[run->inrec.nflds].val); run->inrec.nflds++; len = QSE_STR_LEN(&run->inrec.line) - diff --git a/qse/lib/awk/std.c b/qse/lib/awk/std.c index ace40cd6..16ef899d 100644 --- a/qse/lib/awk/std.c +++ b/qse/lib/awk/std.c @@ -1,5 +1,5 @@ /* - * $Id: std.c 204 2009-06-18 12:08:06Z hyunghwan.chung $ + * $Id: std.c 205 2009-06-20 12:47:34Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -599,6 +599,7 @@ static int open_rio_console (qse_awk_rtx_t* rtx, qse_awk_rio_arg_t* riod) qse_sio_t* sio; const qse_char_t* file; + retry: file = rxtn->c.in.files[rxtn->c.in.index]; if (file == QSE_NULL) @@ -726,6 +727,7 @@ static qse_ssize_t awk_rio_console ( qse_sio_t* sio; const qse_char_t* file; + retry: /* it has reached the end of the current file. * open the next file if available */ if (rxtn->c.in.files == QSE_NULL || diff --git a/qse/lib/awk/val.c b/qse/lib/awk/val.c index 672bd43a..89a52b7a 100644 --- a/qse/lib/awk/val.c +++ b/qse/lib/awk/val.c @@ -1,5 +1,5 @@ /* - * $Id: val.c 200 2009-06-14 13:22:00Z hyunghwan.chung $ + * $Id: val.c 205 2009-06-20 12:47:34Z hyunghwan.chung $ * Copyright 2006-2009 Chung, Hyung-Hwan. @@ -348,6 +348,30 @@ init: return (qse_awk_val_t*)val; } +qse_awk_val_t* qse_awk_rtx_makenstrval ( + qse_awk_rtx_t* run, const qse_char_t* str, qse_size_t len) +{ + int x; + qse_awk_val_t* v; + qse_long_t l; + qse_real_t r; + + x = qse_awk_rtx_strtonum (run, 1, str, len, &l, &r); + v = qse_awk_rtx_makestrval (run, str, len); + + if (v == QSE_NULL) return QSE_NULL; + + if (x >= 0) + { + /* set the numeric string flag if a string + * can be converted to a number */ + QSE_ASSERT (x == 0 || x == 1); + v->nstr = x + 1; /* long -> 1, real -> 2 */ + } + + return v; +} + qse_awk_val_t* qse_awk_rtx_makerexval ( qse_awk_rtx_t* run, const qse_char_t* buf, qse_size_t len, void* code) {