diff --git a/ase/awk/awk.h b/ase/awk/awk.h index 99604566..68673863 100644 --- a/ase/awk/awk.h +++ b/ase/awk/awk.h @@ -1,5 +1,5 @@ /* - * $Id: awk.h,v 1.76 2006-07-01 16:07:06 bacon Exp $ + * $Id: awk.h,v 1.77 2006-07-05 16:20:23 bacon Exp $ */ #ifndef _XP_AWK_AWK_H_ @@ -130,6 +130,7 @@ enum /* run time error */ XP_AWK_EDIVBYZERO, /* divide by zero */ XP_AWK_EOPERAND, /* invalid operand */ + XP_AWK_EPOSIDX, /* wrong position index */ XP_AWK_ENOSUCHFUNC, /* no such function */ XP_AWK_ENOTASSIGNABLE, /* value not assignable */ XP_AWK_ENOTINDEXABLE, /* not indexable variable */ diff --git a/ase/awk/awk_i.h b/ase/awk/awk_i.h index 96da18c6..8c66b716 100644 --- a/ase/awk/awk_i.h +++ b/ase/awk/awk_i.h @@ -1,5 +1,5 @@ /* - * $Id: awk_i.h,v 1.25 2006-07-03 04:09:56 bacon Exp $ + * $Id: awk_i.h,v 1.26 2006-07-05 16:20:23 bacon Exp $ */ #ifndef _XP_AWK_AWKI_H_ @@ -166,12 +166,13 @@ struct xp_awk_run_t xp_size_t buf_len; xp_bool_t eof; xp_str_t line; - /* - xp_awk_val_t** flds; - xp_size_t nflds; - */ - xp_char_t** flds; + xp_size_t nflds; + struct + { + xp_char_t* ptr; + xp_size_t len; + }* flds; } inrec; /* extio chain */ diff --git a/ase/awk/err.c b/ase/awk/err.c index 66f75f42..f2adc301 100644 --- a/ase/awk/err.c +++ b/ase/awk/err.c @@ -1,5 +1,5 @@ /* - * $Id: err.c,v 1.25 2006-07-01 16:07:06 bacon Exp $ + * $Id: err.c,v 1.26 2006-07-05 16:20:23 bacon Exp $ */ #include @@ -62,6 +62,7 @@ const xp_char_t* xp_awk_geterrstr (xp_awk_t* awk) XP_T("divide by zero"), XP_T("invalid operand"), + XP_T("wrong position index"), XP_T("no such function"), XP_T("value not assignable"), XP_T("variable not indexable"), diff --git a/ase/awk/run.c b/ase/awk/run.c index 8de106ae..596edbf3 100644 --- a/ase/awk/run.c +++ b/ase/awk/run.c @@ -1,5 +1,5 @@ /* - * $Id: run.c,v 1.122 2006-07-03 04:09:56 bacon Exp $ + * $Id: run.c,v 1.123 2006-07-05 16:20:23 bacon Exp $ */ #include @@ -155,6 +155,7 @@ static void __raw_pop (xp_awk_run_t* run); static void __raw_pop_times (xp_awk_run_t* run, xp_size_t times); static int __read_record (xp_awk_run_t* run); +static int __split_record (xp_awk_run_t* run); static int __val_to_num (xp_awk_val_t* v, xp_long_t* l, xp_real_t* r); static xp_char_t* __idxnde_to_str (xp_awk_run_t* run, xp_awk_nde_t* nde); @@ -297,7 +298,14 @@ static void __close_run (xp_awk_run_t* run) /* destroy named variables */ xp_awk_map_close (&run->named); - /* destroy input data */ + /* destroy input record */ + if (run->inrec.flds != XP_NULL) + { + xp_free (run->inrec.flds); + run->inrec.flds = XP_NULL; + run->inrec.nflds = 0; + } + xp_assert (run->inrec.nflds == 0); xp_str_close (&run->inrec.line); /* destroy values in free list */ @@ -508,7 +516,7 @@ static int __run_pattern_blocks (xp_awk_run_t* run) run->exit_level = EXIT_NONE; - x = __read_record(run); + x = __read_record (run); if (x == -1) { /* don't care about the result of input close */ @@ -3309,9 +3317,42 @@ static xp_awk_val_t* __eval_argidx (xp_awk_run_t* run, xp_awk_nde_t* nde) static xp_awk_val_t* __eval_pos (xp_awk_run_t* run, xp_awk_nde_t* nde) { - /* TODO: */ - xp_printf (XP_T("eval_pos not competed....\n")); - return XP_NULL; + xp_awk_nde_pos_t* pos = (xp_awk_nde_pos_t*)nde; + xp_awk_val_t* v; + xp_long_t lv; + xp_real_t rv; + int n; + + v = __eval_expression (run, pos->val); + if (v == XP_NULL) return XP_NULL; + + xp_awk_refupval (v); + n = __val_to_num (v, &lv, &rv); + xp_awk_refdownval (run, v); + + if (n == -1) PANIC (run, XP_AWK_EPOSIDX); + if (n == 1) lv = (xp_long_t)rv; + + if (lv == 0) + { + v = xp_awk_makestrval ( + XP_STR_BUF(&run->inrec.line), + XP_STR_LEN(&run->inrec.line)); + if (v == XP_NULL) PANIC (run, XP_AWK_ENOMEM); + } + else if (lv > 0 && lv <= run->inrec.nflds) + { + v = xp_awk_makestrval ( + run->inrec.flds[lv-1].ptr, + run->inrec.flds[lv-1].len); + if (v == XP_NULL) PANIC (run, XP_AWK_ENOMEM); + } + else + { + v = xp_awk_val_nil; + } + + return v; } static xp_awk_val_t* __eval_getline (xp_awk_run_t* run, xp_awk_nde_t* nde) @@ -3439,12 +3480,6 @@ static int __read_record (xp_awk_run_t* run) xp_char_t c; xp_str_clear (&run->inrec.line); - if (run->inrec.flds != XP_NULL) - { - xp_free (run->inrec.flds); - run->inrec.flds = XP_NULL; - } - run->inrec.nflds = 0; while (1) { @@ -3483,8 +3518,60 @@ static int __read_record (xp_awk_run_t* run) } } - /* TODO: compose each field */ - return 1; + if (__split_record (run) == -1) return -1; + + return 1; /* has read a record */ +} + +static int __split_record (xp_awk_run_t* run) +{ + /* TODO: support FS and regular expression */ + + xp_char_t* p, * tok; + xp_size_t len, tok_len, nflds; + + /* clear input record fields */ + if (run->inrec.flds != XP_NULL) + { + xp_free (run->inrec.flds); + run->inrec.flds = XP_NULL; + run->inrec.nflds = 0; + } + xp_assert (run->inrec.nflds == 0); + + /* scan the input record to count the fields */ + p = XP_STR_BUF(&run->inrec.line); + len = XP_STR_LEN(&run->inrec.line); + + nflds = 0; + while (p != XP_NULL) + { + p = xp_strxtok (p, len, XP_T(" \t"), &tok, &tok_len); + nflds++; + len = len - tok_len; + } + + /* allocate space */ + run->inrec.flds = xp_malloc (xp_sizeof(*run->inrec.flds) * nflds); + if (run->inrec.flds == XP_NULL) PANIC_I (run, XP_AWK_ENOMEM); + + /* scan again and split it */ + p = XP_STR_BUF(&run->inrec.line); + len = XP_STR_LEN(&run->inrec.line); + + while (p != XP_NULL) + { + p = xp_strxtok (p, len, XP_T(" \t"), &tok, &tok_len); + + run->inrec.flds[run->inrec.nflds].ptr = tok; + run->inrec.flds[run->inrec.nflds].len = tok_len; + + run->inrec.nflds++; + len = len - tok_len; + } + + xp_assert (nflds == run->inrec.nflds); + return 0; } static int __val_to_num (xp_awk_val_t* v, xp_long_t* l, xp_real_t* r) @@ -3498,13 +3585,13 @@ static int __val_to_num (xp_awk_val_t* v, xp_long_t* l, xp_real_t* r) if (v->type == XP_AWK_VAL_INT) { *l = ((xp_awk_val_int_t*)v)->val; - return 0; + return 0; /* long */ } if (v->type == XP_AWK_VAL_REAL) { *r = ((xp_awk_val_real_t*)v)->val; - return 1; + return 1; /* real */ } if (v->type == XP_AWK_VAL_STR) diff --git a/ase/awk/sa.c b/ase/awk/sa.c index 7159ff31..ec8c3abb 100644 --- a/ase/awk/sa.c +++ b/ase/awk/sa.c @@ -1,5 +1,5 @@ /* - * $Id: sa.c,v 1.23 2006-06-28 08:56:59 bacon Exp $ + * $Id: sa.c,v 1.24 2006-07-05 16:20:23 bacon Exp $ */ #include @@ -92,6 +92,148 @@ int xp_strxncmp ( return (*s1 > *s2)? 1: -1; } +xp_char_t* xp_strtok (const xp_char_t* s, + const xp_char_t* delim, xp_char_t** tok, xp_size_t* tok_len) +{ + const xp_char_t* p = s, *d; + const xp_char_t* sp = XP_NULL, * ep = XP_NULL; + xp_char_t c; + int delim_mode; + + /* skip preceding space xp_char_tacters */ + while (/* *p != XP_T('\0') && */ xp_isspace(*p)) p++; + + if (delim == XP_NULL) delim_mode = 0; + else { + delim_mode = 1; + for (d = delim; *d != XP_T('\0'); d++) + if (!xp_isspace(*d)) delim_mode = 2; + } + + if (delim_mode == 0) { + /* when XP_NULL is given as "delim", it has an effect of cutting + preceding and trailing space characters off "s". */ + while ((c = *p) != XP_T('\0')) { + if (!xp_isspace(c)) { + if (sp == XP_NULL) sp = p; + ep = p; + } + p++; + } + } + else if (delim_mode == 1) { + while ((c = *p) != XP_T('\0')) { + if (xp_isspace(c)) break; + + if (sp == XP_NULL) sp = p; + ep = p++; + } + } + else { /* if (delim_mode == 2) { */ + while ((c = *p) != XP_T('\0')) { + if (xp_isspace(c)) { + p++; + continue; + } + for (d = delim; *d; d++) { + if (c == *d) { + goto exit_loop; + } + } + if (sp == XP_NULL) sp = p; + ep = p++; + } + } + +exit_loop: + if (sp == XP_NULL) { + *tok = XP_NULL; + *tok_len = (xp_size_t)0; + } + else { + *tok = (xp_char_t*)sp; + *tok_len = ep - sp + 1; + } + return (c == XP_T('\0'))? XP_NULL: ((xp_char_t*)++p); +} + +xp_char_t* xp_strxtok (const xp_char_t* s, xp_size_t len, + const xp_char_t* delim, xp_char_t** tok, xp_size_t* tok_len) +{ + const xp_char_t* p = s, *d; + const xp_char_t* end = s + len; + const xp_char_t* sp = XP_NULL, * ep = XP_NULL; + xp_char_t c; + int delim_mode; + + /* skip preceding space xp_char_tacters */ + while (p < end && xp_isspace(*p)) p++; + + if (delim == XP_NULL) delim_mode = 0; + else + { + delim_mode = 1; + for (d = delim; *d != XP_T('\0'); d++) + if (!xp_isspace(*d)) delim_mode = 2; + } + + if (delim_mode == 0) + { + /* when XP_NULL is given as "delim", it has an effect of cutting + preceding and trailing space xp_char_tacters off "s". */ + while (p < end) { + c = *p; + if (!xp_isspace(c)) { + if (sp == XP_NULL) sp = p; + ep = p; + } + p++; + } + } + else if (delim_mode == 1) + { + while (p < end) + { + c = *p; + if (xp_isspace(c)) break; + if (sp == XP_NULL) sp = p; + ep = p++; + } + } + else /* if (delim_mode == 2) { */ + { + while (p < end) + { + c = *p; + if (xp_isspace(c)) + { + p++; + continue; + } + for (d = delim; *d != XP_T('\0'); d++) + { + if (c == *d) goto exit_loop; + } + if (sp == XP_NULL) sp = p; + ep = p++; + } + } + +exit_loop: + if (sp == XP_NULL) + { + *tok = XP_NULL; + *tok_len = (xp_size_t)0; + } + else + { + *tok = (xp_char_t*)sp; + *tok_len = ep - sp + 1; + } + + return (p >= end)? XP_NULL: ((xp_char_t*)++p); +} + int xp_printf (const xp_char_t* fmt, ...) { int n; diff --git a/ase/awk/sa.h b/ase/awk/sa.h index 07e8ab33..8e734483 100644 --- a/ase/awk/sa.h +++ b/ase/awk/sa.h @@ -1,5 +1,5 @@ /* - * $Id: sa.h,v 1.24 2006-06-16 07:35:07 bacon Exp $ + * $Id: sa.h,v 1.25 2006-07-05 16:20:23 bacon Exp $ */ #ifndef _XP_AWK_SA_H_ @@ -111,6 +111,14 @@ int xp_strxncmp ( const xp_char_t* s1, xp_size_t len1, const xp_char_t* s2, xp_size_t len2); +#define xp_strtok xp_awk_strtok +xp_char_t* xp_strtok (const xp_char_t* s, + const xp_char_t* delim, xp_char_t** tok, xp_size_t* tok_len); + +#define xp_strxtok xp_awk_strxtok +xp_char_t* xp_strxtok (const xp_char_t* s, xp_size_t len, + const xp_char_t* delim, xp_char_t** tok, xp_size_t* tok_len); + #define xp_printf xp_awk_printf int xp_printf (const xp_char_t* fmt, ...); diff --git a/ase/test/awk/t14.awk b/ase/test/awk/t14.awk index 66dd6ab5..f29859de 100644 --- a/ase/test/awk/t14.awk +++ b/ase/test/awk/t14.awk @@ -1,3 +1,4 @@ +/* { print "1111111111111"; } @@ -15,3 +16,8 @@ END { print "\a"; } +*/ +{ + $3 = "10"; + print $0, $2, $5; +}