From 2bc122f23a9ba25adef88711da93e12877f942e6 Mon Sep 17 00:00:00 2001 From: hyung-hwan Date: Sat, 4 Oct 2025 01:39:25 +0900 Subject: [PATCH] added @pragma rwpipe changed || to |& for bidirectional piping --- README.md | 8 ++++-- lib/fnc.c | 17 +++++++++++-- lib/hawk.c | 59 ++++++++++++++++++++++----------------------- lib/parse.c | 50 +++++++++++++++++++++++--------------- lib/std.c | 4 +-- lib/tree.c | 4 +-- t/Makefile.am | 3 ++- t/Makefile.in | 3 ++- t/h-003.hawk | 1 + t/two-way-pipe.hawk | 10 ++++++++ t/two-way-pipe.out | 4 +++ 11 files changed, 104 insertions(+), 59 deletions(-) create mode 100644 t/two-way-pipe.hawk create mode 100644 t/two-way-pipe.out diff --git a/README.md b/README.md index 4439312a..39e51736 100644 --- a/README.md +++ b/README.md @@ -1350,12 +1350,16 @@ BEGIN { } ``` -## Positional variable expression +### Positional variable expression There are subtle differences in handling expressions for positional variables. In Hawk, many of the ambiguity issues can be resolved by enclosing the expression in parentheses. - | Expression | Hawk | AWK | |--------------|---------------|-----------------| | `$++$++i` | syntax error | OK | | `$(++$(++i))`| OK | syntax error | + +### Return value of getline + +### Others +- `return` is allowed in `BEGIN` blocks, `END` blocks, and pattern-action blocks. diff --git a/lib/fnc.c b/lib/fnc.c index 2222d7af..1f9788c3 100644 --- a/lib/fnc.c +++ b/lib/fnc.c @@ -352,12 +352,12 @@ static int fnc_close (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) HAWK_ASSERT (a0 != HAWK_NULL); name = hawk_rtx_getvaloocstr(rtx, a0, &len); - if (!name) return -1; + if (HAWK_UNLIKELY(!name)) return -1; if (a1) { opt = hawk_rtx_getvaloocstr(rtx, a1, &optlen); - if (!opt) + if (HAWK_UNLIKELY(!opt)) { hawk_rtx_freevaloocstr(rtx, a0, name); return -1; @@ -391,6 +391,19 @@ static int fnc_close (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi) if (opt) { + /* r and w are the input and the output from the child process perspective + * to and from are the intput and the output in terms of main process */ + if (hawk_comp_oochars_oocstr(opt, optlen, HAWK_T("to"), 0) == 0) + { + optlen = 1; + opt[0] = 'r'; /* close the input to the pipe */ + } + else if (hawk_comp_oochars_oocstr(opt, optlen, HAWK_T("from"), 0) == 0) + { + optlen = 1; + opt[0] = 'w'; /* close the output from the pipe */ + } + if (optlen != 1 || (opt[0] != HAWK_T('r') && opt[0] != HAWK_T('w'))) { n = -1; diff --git a/lib/hawk.c b/lib/hawk.c index e93420f8..05f2368a 100644 --- a/lib/hawk.c +++ b/lib/hawk.c @@ -61,7 +61,7 @@ static void fini_token (hawk_tok_t* tok) { if (tok->name) { - hawk_ooecs_close (tok->name); + hawk_ooecs_close(tok->name); tok->name = HAWK_NULL; } } @@ -268,14 +268,14 @@ int hawk_init (hawk_t* hawk, hawk_mmgr_t* mmgr, hawk_cmgr_t* cmgr, const hawk_pr return 0; oops: - if (hawk->modtab) hawk_rbt_close (hawk->modtab); - if (hawk->fnc.user) hawk_htb_close (hawk->fnc.user); - if (hawk->parse.params) hawk_arr_close (hawk->parse.params); - if (hawk->parse.lcls) hawk_arr_close (hawk->parse.lcls); - if (hawk->parse.gbls) hawk_arr_close (hawk->parse.gbls); - if (hawk->parse.named) hawk_htb_close (hawk->parse.named); - if (hawk->parse.funs) hawk_htb_close (hawk->parse.funs); - if (hawk->tree.funs) hawk_htb_close (hawk->tree.funs); + if (hawk->modtab) hawk_rbt_close(hawk->modtab); + if (hawk->fnc.user) hawk_htb_close(hawk->fnc.user); + if (hawk->parse.params) hawk_arr_close(hawk->parse.params); + if (hawk->parse.lcls) hawk_arr_close(hawk->parse.lcls); + if (hawk->parse.gbls) hawk_arr_close(hawk->parse.gbls); + if (hawk->parse.named) hawk_htb_close(hawk->parse.named); + if (hawk->parse.funs) hawk_htb_close(hawk->parse.funs); + if (hawk->tree.funs) hawk_htb_close(hawk->tree.funs); fini_token (&hawk->ntok); fini_token (&hawk->tok); fini_token (&hawk->ptok); @@ -311,23 +311,23 @@ void hawk_fini (hawk_t* hawk) HAWK_ASSERT (hawk->ecb == (hawk_ecb_t*)hawk); - hawk_rbt_close (hawk->modtab); - hawk_htb_close (hawk->fnc.user); + hawk_rbt_close(hawk->modtab); + hawk_htb_close(hawk->fnc.user); - hawk_arr_close (hawk->parse.params); - hawk_arr_close (hawk->parse.lcls); - hawk_arr_close (hawk->parse.gbls); - hawk_htb_close (hawk->parse.named); - hawk_htb_close (hawk->parse.funs); + hawk_arr_close(hawk->parse.params); + hawk_arr_close(hawk->parse.lcls); + hawk_arr_close(hawk->parse.gbls); + hawk_htb_close(hawk->parse.named); + hawk_htb_close(hawk->parse.funs); - hawk_htb_close (hawk->tree.funs); + hawk_htb_close(hawk->tree.funs); - fini_token (&hawk->ntok); - fini_token (&hawk->tok); - fini_token (&hawk->ptok); + fini_token(&hawk->ntok); + fini_token(&hawk->tok); + fini_token(&hawk->ptok); if (hawk->parse.incl_hist.ptr) hawk_freemem(hawk, hawk->parse.incl_hist.ptr); - hawk_clearsionames (hawk); + hawk_clearsionames(hawk); /* destroy dynamically allocated options */ for (i = 0; i < HAWK_COUNTOF(hawk->opt.mod); i++) @@ -375,7 +375,7 @@ static hawk_rbt_walk_t unload_module (hawk_rbt_t* rbt, hawk_rbt_pair_t* pair, vo hawk_mod_data_t* md; md = HAWK_RBT_VPTR(pair); - if (md->mod.unload) md->mod.unload (&md->mod, hawk); + if (md->mod.unload) md->mod.unload(&md->mod, hawk); if (md->handle) hawk->prm.modclose(hawk, md->handle); return HAWK_RBT_WALK_FORWARD; @@ -404,21 +404,21 @@ void hawk_clear (hawk_t* hawk) HAWK_ASSERT (HAWK_ARR_SIZE(hawk->parse.gbls) == hawk->tree.ngbls); /* delete all non-builtin global variables */ - hawk_arr_delete ( + hawk_arr_delete( hawk->parse.gbls, hawk->tree.ngbls_base, HAWK_ARR_SIZE(hawk->parse.gbls) - hawk->tree.ngbls_base); - hawk_arr_clear (hawk->parse.lcls); - hawk_arr_clear (hawk->parse.params); - hawk_htb_clear (hawk->parse.named); - hawk_htb_clear (hawk->parse.funs); + hawk_arr_clear(hawk->parse.lcls); + hawk_arr_clear(hawk->parse.params); + hawk_htb_clear(hawk->parse.named); + hawk_htb_clear(hawk->parse.funs); hawk->parse.nlcls_max = 0; hawk->parse.depth.block = 0; hawk->parse.depth.loop = 0; hawk->parse.depth.expr = 0; hawk->parse.depth.incl = 0; - hawk->parse.pragma.trait = (hawk->opt.trait & (HAWK_IMPLICIT | HAWK_MULTILINESTR | HAWK_STRIPRECSPC | HAWK_STRIPSTRSPC)); /* implicit on if you didn't mask it off in hawk->opt.trait with hawk_setopt */ + hawk->parse.pragma.trait = (hawk->opt.trait & (HAWK_IMPLICIT | HAWK_MULTILINESTR | HAWK_RWPIPE | HAWK_STRIPRECSPC | HAWK_STRIPSTRSPC)); /* implicit on if you didn't mask it off in hawk->opt.trait with hawk_setopt */ hawk->parse.pragma.rtx_stack_limit = 0; hawk->parse.pragma.entry[0] = '\0'; @@ -431,7 +431,7 @@ void hawk_clear (hawk_t* hawk) hawk->tree.cur_fun.ptr = HAWK_NULL; hawk->tree.cur_fun.len = 0; - hawk_htb_clear (hawk->tree.funs); + hawk_htb_clear(hawk->tree.funs); if (hawk->tree.begin) { @@ -549,7 +549,6 @@ int hawk_setopt (hawk_t* hawk, hawk_opt_t id, const void* value) case HAWK_OPT_LOG_MAXCAPA: hawk->opt.log_maxcapa = *(hawk_oow_t*)value; return 0; - } hawk_seterrnum(hawk, HAWK_NULL, HAWK_EINVAL); diff --git a/lib/parse.c b/lib/parse.c index 6159721a..b7182105 100644 --- a/lib/parse.c +++ b/lib/parse.c @@ -69,8 +69,8 @@ enum tok_t TOK_MOD_ASSN, TOK_EXP_ASSN, /* ^ - exponentiation */ TOK_CONCAT_ASSN, - TOK_RS_ASSN, - TOK_LS_ASSN, + TOK_RS_ASSN, /* >> */ + TOK_LS_ASSN, /* << */ TOK_BAND_ASSN, TOK_BXOR_ASSN, TOK_BOR_ASSN, @@ -95,11 +95,12 @@ enum tok_t TOK_DIV, TOK_IDIV, TOK_MOD, - TOK_LOR, - TOK_LAND, - TOK_BOR, + TOK_LOR, /* || */ + TOK_LAND, /* && */ + TOK_BOR, /* | */ + TOK_PIPE_BD, /* |& - bidirectional pipe */ TOK_BXOR, /* ^^ - bitwise-xor */ - TOK_BAND, + TOK_BAND, /* & */ TOK_RS, TOK_LS, TOK_IN, @@ -1018,12 +1019,18 @@ static int parse_progunit (hawk_t* hawk) } /* NOTE: trait = is an intended assignment */ else if (((trait = HAWK_IMPLICIT) && hawk_comp_oochars_oocstr(name.ptr, name.len, HAWK_T("implicit"), 0) == 0) || - ((trait = HAWK_MULTILINESTR) && hawk_comp_oochars_oocstr(name.ptr, name.len, HAWK_T("multilinestr"), 0) == 0)) + ((trait = HAWK_MULTILINESTR) && hawk_comp_oochars_oocstr(name.ptr, name.len, HAWK_T("multilinestr"), 0) == 0) || + ((trait = HAWK_RWPIPE) && hawk_comp_oochars_oocstr(name.ptr, name.len, HAWK_T("rwpipe"), 0) == 0)) { /* @pragma implicit on * @pragma implicit off * @pragma multilinestr on - * @pragma multilinestr off */ + * @pragma multilinestr off + * @pragma rwpipe on + * @pragma rwpipe off + * + * The initial values of these pragmas are set in hawk_clear() + */ hawk_oocs_t value; if (get_token(hawk) <= -1) return -1; @@ -1061,6 +1068,8 @@ static int parse_progunit (hawk_t* hawk) * @pragma numstrdetect on * @pragma numstrdetect off * + * The initial values of these pragmas are set in hawk_clear() + * * Take note the global STRIPRECSPC is available for context based change. * STRIPRECSPC takes precedence over this pragma. */ @@ -1272,7 +1281,7 @@ static int parse_progunit (hawk_t* hawk) { /* 'ptn' has been added to the chain. * it doesn't have to be cleared here - * as hawk_clear does it */ + * as hawk_clear() does it */ /*hawk_clrpt(hawk, ptn);*/ return -1; } @@ -3290,7 +3299,7 @@ static hawk_nde_t* parse_print (hawk_t* hawk, const hawk_loc_t* xloc) type = (hawk->ptok.type == TOK_PRINT)? HAWK_NDE_PRINT: HAWK_NDE_PRINTF; if (!MATCH_TERMINATOR(hawk) && !MATCH(hawk,TOK_GT) && - !MATCH(hawk,TOK_RS) && !MATCH(hawk,TOK_BOR) && !MATCH(hawk,TOK_LOR)) + !MATCH(hawk,TOK_RS) && !MATCH(hawk,TOK_BOR) && !MATCH(hawk,TOK_PIPE_BD)) { hawk_nde_t* args_tail; hawk_nde_t* tail_prev; @@ -3422,11 +3431,13 @@ static hawk_nde_t* parse_print (hawk_t* hawk, const hawk_loc_t* xloc) HAWK_OUT_PIPE, 0 }, + /* |& doesn't oeverlap with other binary operators. { - HAWK_BINOP_LOR, + HAWK_BINOP_PIPE_BD, HAWK_OUT_RWPIPE, HAWK_RWPIPE } + */ }; for (i = 0; i < HAWK_COUNTOF(tab); i++) @@ -3453,12 +3464,12 @@ static hawk_nde_t* parse_print (hawk_t* hawk, const hawk_loc_t* xloc) if (!out) { - out_type = MATCH(hawk,TOK_GT)? HAWK_OUT_FILE: - MATCH(hawk,TOK_RS)? HAWK_OUT_APFILE: - MATCH(hawk,TOK_BOR)? HAWK_OUT_PIPE: + out_type = MATCH(hawk,TOK_GT)? HAWK_OUT_FILE: + MATCH(hawk,TOK_RS)? HAWK_OUT_APFILE: + MATCH(hawk,TOK_BOR)? HAWK_OUT_PIPE: ((hawk->opt.trait & HAWK_RWPIPE) && - MATCH(hawk,TOK_LOR))? HAWK_OUT_RWPIPE: - HAWK_OUT_CONSOLE; + MATCH(hawk,TOK_PIPE_BD))? HAWK_OUT_RWPIPE: + HAWK_OUT_CONSOLE; if (out_type != HAWK_OUT_CONSOLE) { @@ -3804,7 +3815,7 @@ static hawk_nde_t* parse_expr (hawk_t* hawk, const hawk_loc_t* xloc) x = parse_expr_basic(hawk, xloc); if (x == HAWK_NULL) return HAWK_NULL; - opcode = assign_to_opcode (hawk); + opcode = assign_to_opcode(hawk); if (opcode <= -1) { /* no assignment operator found. */ @@ -5568,7 +5579,7 @@ static hawk_nde_t* parse_primary (hawk_t* hawk, const hawk_loc_t* xloc) { intype = HAWK_IN_PIPE; } - else if (MATCH(hawk,TOK_LOR) && (hawk->opt.trait & HAWK_RWPIPE)) + else if (MATCH(hawk,TOK_PIPE_BD) && (hawk->parse.pragma.trait & HAWK_RWPIPE)) { intype = HAWK_IN_RWPIPE; } @@ -5617,7 +5628,7 @@ static hawk_nde_t* parse_primary (hawk_t* hawk, const hawk_loc_t* xloc) ploc = hawk->tok.loc; var = parse_primary(hawk, &ploc); - if (var == HAWK_NULL) goto oops; + if (!var) goto oops; if (!is_var(var) && var->type != HAWK_NDE_POS) { @@ -6940,6 +6951,7 @@ static int get_symbols (hawk_t* hawk, hawk_ooci_t c, hawk_tok_t* tok) { HAWK_T("<<"), 2, TOK_LS, 0 }, { HAWK_T("<="), 2, TOK_LE, 0 }, { HAWK_T("<"), 1, TOK_LT, 0 }, + { HAWK_T("|&"), 2, TOK_PIPE_BD, 0 }, { HAWK_T("||"), 2, TOK_LOR, 0 }, { HAWK_T("|="), 2, TOK_BOR_ASSN, 0 }, { HAWK_T("|"), 1, TOK_BOR, 0 }, diff --git a/lib/std.c b/lib/std.c index b08ff426..1c5b770a 100644 --- a/lib/std.c +++ b/lib/std.c @@ -2101,12 +2101,12 @@ static hawk_ooi_t pio_handler_rest (hawk_rtx_t* rtx, hawk_rio_cmd_t cmd, hawk_ri * requested. */ if (riod->rwcmode == HAWK_RIO_CMD_CLOSE_READ) { - hawk_pio_end (pio, HAWK_PIO_IN); + hawk_pio_end(pio, HAWK_PIO_IN); return 0; } if (riod->rwcmode == HAWK_RIO_CMD_CLOSE_WRITE) { - hawk_pio_end (pio, HAWK_PIO_OUT); + hawk_pio_end(pio, HAWK_PIO_OUT); return 0; } } diff --git a/lib/tree.c b/lib/tree.c index 6b6107ac..d00b002a 100644 --- a/lib/tree.c +++ b/lib/tree.c @@ -97,7 +97,7 @@ static const hawk_ooch_t* incop_str[] = static const hawk_ooch_t* getline_inop_str[] = { HAWK_T("|"), - HAWK_T("||"), + HAWK_T("|&"), HAWK_T("<"), HAWK_T("") }; @@ -105,7 +105,7 @@ static const hawk_ooch_t* getline_inop_str[] = static const hawk_ooch_t* print_outop_str[] = { HAWK_T("|"), - HAWK_T("||"), + HAWK_T("|&"), HAWK_T(">"), HAWK_T(">>"), HAWK_T("") diff --git a/t/Makefile.am b/t/Makefile.am index fb717f74..94538c30 100644 --- a/t/Makefile.am +++ b/t/Makefile.am @@ -25,7 +25,8 @@ check_ERRORS = e-001.err EXTRA_DIST = $(check_SCRIPTS) $(check_ERRORS) tap.inc err.sh \ journal-toc.hawk journal-toc.in journal-toc.out journal-toc-html.out \ bibtex-to-html.hawk bibtex-to-html.out \ - fs-test.hawk fs-test.in fs-test.out + fs-test.hawk fs-test.in fs-test.out \ + two-way-pipe.hawk two-way-pipe.out check_PROGRAMS = t-001 t-002 t-003 t-004 t-005 t-006 t-007 t-008 t-009 diff --git a/t/Makefile.in b/t/Makefile.in index 3ae0c674..52f8f821 100644 --- a/t/Makefile.in +++ b/t/Makefile.in @@ -649,7 +649,8 @@ check_ERRORS = e-001.err EXTRA_DIST = $(check_SCRIPTS) $(check_ERRORS) tap.inc err.sh \ journal-toc.hawk journal-toc.in journal-toc.out journal-toc-html.out \ bibtex-to-html.hawk bibtex-to-html.out \ - fs-test.hawk fs-test.in fs-test.out + fs-test.hawk fs-test.in fs-test.out \ + two-way-pipe.hawk two-way-pipe.out t_001_SOURCES = t-001.c tap.h t_001_CPPFLAGS = $(CPPFLAGS_COMMON) diff --git a/t/h-003.hawk b/t/h-003.hawk index b681ea2d..410d2b6b 100644 --- a/t/h-003.hawk +++ b/t/h-003.hawk @@ -81,6 +81,7 @@ function main() run_test("journal-toc", "-vHTML=1", "journal-toc", 0, "journal-toc-html"); run_test("bibtex-to-html", "", "journal-toc", 1, "bibtex-to-html"); run_test("fs-test", "", "fs-test", 0, "fs-test"); + run_test("two-way-pipe", "", @nil, 0, "two-way-pipe"); tap_end (); } diff --git a/t/two-way-pipe.hawk b/t/two-way-pipe.hawk new file mode 100644 index 00000000..c1779b5c --- /dev/null +++ b/t/two-way-pipe.hawk @@ -0,0 +1,10 @@ +BEGIN { + cmd = "sort"; + data = hawk::array("hello", "world", "two-way pipe", "testing"); + + for (i = 1; i <= length(data); i++) print data[i] |& cmd; + close(cmd, "to"); + + while ((cmd |& getline line) > 0) print line; + close(cmd); +} diff --git a/t/two-way-pipe.out b/t/two-way-pipe.out new file mode 100644 index 00000000..a9ee0e12 --- /dev/null +++ b/t/two-way-pipe.out @@ -0,0 +1,4 @@ +hello +testing +two-way pipe +world