implemented switch ... case .. default ..

This commit is contained in:
hyung-hwan 2025-06-18 23:45:34 +09:00
parent 846cbcf951
commit fac4aa7af5
24 changed files with 1909 additions and 1306 deletions

View File

@ -476,7 +476,9 @@ The following words are reserved and cannot be used as a variable name, a parame
- BEGIN
- END
- break
- case
- continue
- default
- delete
- do
- else
@ -494,6 +496,7 @@ The following words are reserved and cannot be used as a variable name, a parame
- printf
- return
- while
- switch
However, some of these words not beginning with `@` can be used as normal names in the context of a module call. For example, `mymod::break`. In practice, the predefined names used for built-in commands, functions, and variables are treated as if they are reserved since you can't create another definition with the same name.
@ -633,7 +636,7 @@ BEGIN {
Hawk supports various control structures for flow control and iteration, similar to those found in awk.
The `if` statement in Hawk follows the same syntax as in awk and other programming languages. It allows you to execute a block of code conditionally based on a specified condition.
The `if` statement follows the same syntax as in awk and other programming languages. It allows you to execute a block of code conditionally based on a specified condition.
```awk
if (condition) {
@ -645,7 +648,18 @@ if (condition) {
}
```
The `while` loop in Hawk is used to repeatedly execute a block of code as long as a specific condition is true.
The `switch` statement allows the result of an expression to be tested against a list of values.
```awk
switch (expression) {
case value:
## statements
...
default:
## statements
}
```
The `while` loop is used to repeatedly execute a block of code as long as a specific condition is true.
```awk
while (condition) {
# statements
@ -659,13 +673,13 @@ do {
} while (condition)
```
The `for` loop in Hawk follows the same syntax as in awk and allows you to iterate over a range of values or an array.
The `for` loop follows the same syntax as in awk and allows you to iterate over a range of values or an array.
```awk
for (initialization; condition; increment/decrement) {
## statements
}
```
You can also use the for loop to iterate over the elements of an array:
You can also use the `fo`r loop to iterate over the elements of an array:
```awk
for (index in array) {
## statements using array[index]

View File

@ -539,6 +539,15 @@ static void print_usage (FILE* out, const hawk_bch_t* argv0, const hawk_bch_t* r
{
fprintf (out, " --%-18s on/off %s\n", opttab[j].name, opttab[j].desc);
}
if (!real_argv0)
{
fprintf (out, "\n");
fprintf (out, "Special mode switching options(must be specified first to take effect):\n");
fprintf (out, " --hawk/--awk run in the hawk mode\n");
fprintf (out, " --cut run in the cut mode\n");
fprintf (out, " --sed run in the sed mode\n");
}
}
/* ---------------------------------------------------------------------- */

View File

@ -76,6 +76,7 @@ const hawk_ooch_t* hawk_dfl_errstr (hawk_errnum_t errnum)
HAWK_T("left brace expected"),
HAWK_T("left parenthesis expected"),
HAWK_T("right parenthesis expected"),
HAWK_T("right brace expected"),
HAWK_T("right bracket expected"),
HAWK_T("comma expected"),
HAWK_T("semicolon expected"),
@ -88,6 +89,8 @@ const hawk_ooch_t* hawk_dfl_errstr (hawk_errnum_t errnum)
HAWK_T("keyword 'function' expected"),
HAWK_T("keyword 'while' expected"),
HAWK_T("keyword 'case' expected"),
HAWK_T("multiple 'default' labels"),
HAWK_T("invalid assignment statement"),
HAWK_T("identifier expected"),
HAWK_T("not a valid function name"),

View File

@ -940,6 +940,7 @@ enum hawk_errnum_t
HAWK_ELBRACE, /**< left brace expected */
HAWK_ELPAREN, /**< left parenthesis expected */
HAWK_ERPAREN, /**< right parenthesis expected */
HAWK_ERBRACE, /**< right brace expected */
HAWK_ERBRACK, /**< right bracket expected */
HAWK_ECOMMA, /**< comma expected */
HAWK_ESCOLON, /**< semicolon expected */
@ -952,6 +953,8 @@ enum hawk_errnum_t
HAWK_EKWFNC, /**< keyword 'function' expected */
HAWK_EKWWHL, /**< keyword 'while' expected */
HAWK_EKWCASE, /**< keyword 'case' expected */
HAWK_EMULDFL, /**< multiple 'default' labels */
HAWK_EASSIGN, /**< assignment statement expected */
HAWK_EIDENT, /**< identifier expected */
HAWK_EFUNNAM, /**< not a valid function name */

View File

@ -278,6 +278,7 @@ struct hawk_t
hawk_oow_t loop;
hawk_oow_t expr; /* expression */
hawk_oow_t incl;
hawk_oow_t swtch; /* switch */
} depth;
/* current pragma values */

View File

@ -398,6 +398,8 @@ enum hawk_nde_type_t
/* statement */
HAWK_NDE_BLK,
HAWK_NDE_IF,
HAWK_NDE_SWITCH,
HAWK_NDE_CASE,
HAWK_NDE_WHILE,
HAWK_NDE_DOWHILE,
HAWK_NDE_FOR,

View File

@ -41,7 +41,9 @@ enum hawk_kwid_t
HAWK_KWID_BEGIN,
HAWK_KWID_END,
HAWK_KWID_BREAK,
HAWK_KWID_CASE,
HAWK_KWID_CONTINUE,
HAWK_KWID_DEFAULT,
HAWK_KWID_DELETE,
HAWK_KWID_DO,
HAWK_KWID_ELSE,
@ -58,6 +60,7 @@ enum hawk_kwid_t
HAWK_KWID_PRINT,
HAWK_KWID_PRINTF,
HAWK_KWID_RETURN,
HAWK_KWID_SWITCH,
HAWK_KWID_WHILE
};

View File

@ -35,10 +35,13 @@
#define FMT_EKWFNC HAWK_T("keyword 'function' expected in place of '%.*js'")
#define FMT_EKWIN HAWK_T("keyword 'in' expected in place of '%.*js'")
#define FMT_EKWWHL HAWK_T("keyword 'while' expected in place of '%.*js'")
#define FMT_EKWCASE HAWK_T("keyword 'case' expected in place of '%.*js'")
#define FMT_EMULDFL HAWK_T("multiple '%.*js' labels")
#define FMT_ELBRACE HAWK_T("left brace expected in place of '%.*js'")
#define FMT_ELPAREN HAWK_T("left parenthesis expected in place of '%.*js'")
#define FMT_ENOENT_GBL_HS HAWK_T("no such global variable - %.*hs")
#define FMT_ENOENT_GBL_LS HAWK_T("no such global variable - %.*ls")
#define FMT_ERBRACE HAWK_T("right brace expected in place of '%.*js'")
#define FMT_ERBRACK HAWK_T("right bracket expected in place of '%.*js'")
#define FMT_ERPAREN HAWK_T("right parenthesis expected in place of '%.*js'")
#define FMT_ESCOLON HAWK_T("semicolon expected in place of '%.*js'")
@ -48,6 +51,8 @@
#define TOK_FLAGS_LPAREN_CLOSER (1 << 0)
#define PARSE_BLOCK_FLAG_IS_TOP (1 << 0)
enum tok_t
{
TOK_EOF,
@ -140,6 +145,9 @@ enum tok_t
TOK_WHILE,
TOK_FOR,
TOK_DO,
TOK_SWITCH,
TOK_CASE,
TOK_DEFAULT,
TOK_BREAK,
TOK_CONTINUE,
TOK_RETURN,
@ -200,17 +208,15 @@ static int parse_progunit (hawk_t* hawk);
static hawk_t* collect_globals (hawk_t* hawk);
static void adjust_static_globals (hawk_t* hawk);
static hawk_oow_t find_global (hawk_t* hawk, const hawk_oocs_t* name);
static hawk_t* collect_locals (hawk_t* hawk, hawk_oow_t nlcls, int istop);
static hawk_t* collect_locals (hawk_t* hawk, hawk_oow_t nlcls, int flags);
static hawk_nde_t* parse_function (hawk_t* hawk);
static hawk_nde_t* parse_begin (hawk_t* hawk);
static hawk_nde_t* parse_end (hawk_t* hawk);
static hawk_chain_t* parse_action_block (hawk_t* hawk, hawk_nde_t* ptn, int blockless);
static hawk_nde_t* parse_block_dc (hawk_t* hawk, const hawk_loc_t* xloc, int istop);
static hawk_nde_t* parse_block_dc (hawk_t* hawk, const hawk_loc_t* xloc, int flags);
static hawk_nde_t* parse_statement (hawk_t* hawk, const hawk_loc_t* xloc);
static hawk_nde_t* parse_expr_withdc (hawk_t* hawk, const hawk_loc_t* xloc);
static hawk_nde_t* parse_logical_or (hawk_t* hawk, const hawk_loc_t* xloc);
@ -233,6 +239,7 @@ static hawk_nde_t* parse_unary_exp (hawk_t* hawk, const hawk_loc_t* xloc);
static hawk_nde_t* parse_increment (hawk_t* hawk, const hawk_loc_t* xloc);
static hawk_nde_t* parse_primary (hawk_t* hawk, const hawk_loc_t* xloc);
static hawk_nde_t* parse_primary_ident (hawk_t* hawk, const hawk_loc_t* xloc);
static hawk_nde_t* parse_primary_literal (hawk_t* hawk, const hawk_loc_t* xloc);
static hawk_nde_t* parse_hashidx (hawk_t* hawk, const hawk_oocs_t* name, const hawk_loc_t* xloc);
#define FNCALL_FLAG_NOARG (1 << 0) /* no argument */
@ -281,7 +288,9 @@ static kwent_t kwtab[] =
{ { HAWK_T("BEGIN"), 5 }, TOK_BEGIN, HAWK_PABLOCK },
{ { HAWK_T("END"), 3 }, TOK_END, HAWK_PABLOCK },
{ { HAWK_T("break"), 5 }, TOK_BREAK, 0 },
{ { HAWK_T("case"), 4 }, TOK_CASE, 0 },
{ { HAWK_T("continue"), 8 }, TOK_CONTINUE, 0 },
{ { HAWK_T("default"), 7 }, TOK_DEFAULT, 0 },
{ { HAWK_T("delete"), 6 }, TOK_DELETE, 0 },
{ { HAWK_T("do"), 2 }, TOK_DO, 0 },
{ { HAWK_T("else"), 4 }, TOK_ELSE, 0 },
@ -298,6 +307,7 @@ static kwent_t kwtab[] =
{ { HAWK_T("print"), 5 }, TOK_PRINT, HAWK_RIO },
{ { HAWK_T("printf"), 6 }, TOK_PRINTF, HAWK_RIO },
{ { HAWK_T("return"), 6 }, TOK_RETURN, 0 },
{ { HAWK_T("switch"), 6 }, TOK_SWITCH, 0 },
{ { HAWK_T("while"), 5 }, TOK_WHILE, 0 }
};
@ -1665,7 +1675,7 @@ static hawk_chain_t* parse_action_block (hawk_t* hawk, hawk_nde_t* ptn, int bloc
return chain;
}
static hawk_nde_t* parse_block (hawk_t* hawk, const hawk_loc_t* xloc, int istop)
static hawk_nde_t* parse_block (hawk_t* hawk, const hawk_loc_t* xloc, int flags)
{
hawk_nde_t* head, * curr, * nde;
hawk_nde_blk_t* block;
@ -1715,7 +1725,7 @@ static hawk_nde_t* parse_block (hawk_t* hawk, const hawk_loc_t* xloc, int istop)
return HAWK_NULL;
}
if (collect_locals(hawk, nlcls_outer, istop) == HAWK_NULL)
if (collect_locals(hawk, nlcls_outer, flags) == HAWK_NULL)
{
hawk_arr_delete (hawk->parse.lcls, nlcls_outer, HAWK_ARR_SIZE(hawk->parse.lcls) - nlcls_outer);
return HAWK_NULL;
@ -1761,8 +1771,7 @@ static hawk_nde_t* parse_block (hawk_t* hawk, const hawk_loc_t* xloc, int istop)
{
int once;
if (hawk->opt.depth.s.incl > 0 &&
hawk->parse.depth.incl >= hawk->opt.depth.s.incl)
if (hawk->opt.depth.s.incl > 0 && hawk->parse.depth.incl >= hawk->opt.depth.s.incl)
{
hawk_seterrnum(hawk, &hawk->ptok.loc, HAWK_EINCLTD);
return HAWK_NULL;
@ -1845,7 +1854,7 @@ static hawk_nde_t* parse_block (hawk_t* hawk, const hawk_loc_t* xloc, int istop)
and merged to top-level block */
/* migrate all block-local variables to the outermost block */
if (istop)
if (flags & PARSE_BLOCK_FLAG_IS_TOP)
{
HAWK_ASSERT (nlcls_outer == 0 && nlcls_max == 0);
block->nlcls = hawk->parse.nlcls_max - nlcls_outer;
@ -1863,7 +1872,7 @@ static hawk_nde_t* parse_block (hawk_t* hawk, const hawk_loc_t* xloc, int istop)
return (hawk_nde_t*)block;
}
static hawk_nde_t* parse_block_dc (hawk_t* hawk, const hawk_loc_t* xloc, int istop)
static hawk_nde_t* parse_block_dc (hawk_t* hawk, const hawk_loc_t* xloc, int flags)
{
hawk_nde_t* nde;
@ -1876,7 +1885,7 @@ static hawk_nde_t* parse_block_dc (hawk_t* hawk, const hawk_loc_t* xloc, int ist
}
hawk->parse.depth.block++;
nde = parse_block(hawk, xloc, istop);
nde = parse_block(hawk, xloc, flags);
hawk->parse.depth.block--;
return nde;
@ -2330,7 +2339,7 @@ static hawk_t* collect_globals (hawk_t* hawk)
return hawk;
}
static hawk_t* collect_locals (hawk_t* hawk, hawk_oow_t nlcls, int istop)
static hawk_t* collect_locals (hawk_t* hawk, hawk_oow_t nlcls, int flags)
{
if (MATCH(hawk,TOK_NEWLINE))
{
@ -2361,7 +2370,7 @@ static hawk_t* collect_locals (hawk_t* hawk, hawk_oow_t nlcls, int istop)
return HAWK_NULL;
}
if (istop)
if (flags & PARSE_BLOCK_FLAG_IS_TOP)
{
/* check if it conflicts with a parameter name.
* the first level declaration is treated as the same
@ -2525,6 +2534,214 @@ oops:
return HAWK_NULL;
}
static hawk_nde_case_t* alloc_nde_case (hawk_t* hawk, const hawk_loc_t* xloc)
{
hawk_nde_case_t* nde;
nde = (hawk_nde_case_t*)hawk_callocmem(hawk, HAWK_SIZEOF(*nde));
if (HAWK_UNLIKELY(!nde))
{
ADJERR_LOC(hawk, xloc);
goto oops;
}
nde->type = HAWK_NDE_CASE;
nde->loc = *xloc;
nde->val = HAWK_NULL;
nde->action = HAWK_NULL;
return nde;
oops:
return HAWK_NULL;
}
static hawk_nde_t* parse_switch (hawk_t* hawk, const hawk_loc_t* xloc)
{
hawk_nde_switch_t* nde;
hawk_nde_t* test = HAWK_NULL; /* test to switch */
hawk_nde_t* case_val = HAWK_NULL; /* value after case */
hawk_nde_t* case_first = HAWK_NULL;
hawk_nde_t* case_last = HAWK_NULL;
hawk_nde_t* default_part = HAWK_NULL;
hawk_loc_t eloc;
if (!MATCH(hawk,TOK_LPAREN))
{
hawk_seterrfmt(hawk, &hawk->tok.loc, HAWK_ELPAREN, FMT_ELPAREN, HAWK_OOECS_LEN(hawk->tok.name), HAWK_OOECS_PTR(hawk->tok.name));
return HAWK_NULL;
}
if (get_token(hawk) <= -1) return HAWK_NULL;
eloc = hawk->tok.loc;
test = parse_expr_withdc(hawk, &eloc);
if (HAWK_UNLIKELY(!test)) goto oops;
if (!MATCH(hawk,TOK_RPAREN))
{
hawk_seterrfmt(hawk, &hawk->tok.loc, HAWK_ERPAREN, FMT_ERPAREN, HAWK_OOECS_LEN(hawk->tok.name), HAWK_OOECS_PTR(hawk->tok.name));
goto oops;
}
if (get_token(hawk) <= -1) goto oops;
while (MATCH(hawk,TOK_NEWLINE))
{
if (get_token(hawk) <= -1) goto oops;
}
if (!MATCH(hawk,TOK_LBRACE))
{
hawk_seterrfmt(hawk, &hawk->tok.loc, HAWK_ELBRACE, FMT_ELBRACE, HAWK_OOECS_LEN(hawk->tok.name), HAWK_OOECS_PTR(hawk->tok.name));
goto oops;
}
if (get_token(hawk) <= -1) goto oops;
while (!MATCH(hawk, TOK_RBRACE))
{
while (MATCH(hawk,TOK_NEWLINE))
{
if (get_token(hawk) <= -1) goto oops;
}
if (MATCH(hawk, TOK_CASE) || MATCH(hawk, TOK_DEFAULT))
{
hawk_nde_case_t* vv;
hawk_nde_t* action_first = HAWK_NULL;
hawk_nde_t* action_last = HAWK_NULL;
if (MATCH(hawk, TOK_CASE))
{
if (get_token(hawk) <= -1) goto oops;
eloc = hawk->tok.loc;
case_val = parse_primary_literal(hawk, &eloc);
if (HAWK_UNLIKELY(!case_val)) goto oops;
}
else /* MATCH(hawk, TOK_DEFAULT) */
{
if (default_part)
{
hawk_seterrfmt(hawk, &hawk->tok.loc, HAWK_EMULDFL, FMT_EMULDFL, HAWK_OOECS_LEN(hawk->tok.name), HAWK_OOECS_PTR(hawk->tok.name));
goto oops;
}
case_val = HAWK_NULL;
if (get_token(hawk) <= -1) goto oops;
}
if (!MATCH(hawk, TOK_COLON))
{
hawk_seterrfmt(hawk, &hawk->tok.loc, HAWK_ECOLON, FMT_ECOLON, HAWK_OOECS_LEN(hawk->tok.name), HAWK_OOECS_PTR(hawk->tok.name));
goto oops;
}
if (get_token(hawk) <= -1) goto oops;
while (MATCH(hawk,TOK_NEWLINE))
{
if (get_token(hawk) <= -1) goto oops;
}
while (!MATCH(hawk, TOK_CASE) && !MATCH(hawk, TOK_DEFAULT) && !MATCH(hawk, TOK_RBRACE))
{
hawk_nde_t* v;
eloc = hawk->tok.loc;
hawk->parse.depth.swtch++;
v = parse_statement(hawk, &eloc);
hawk->parse.depth.swtch--;
if (!v) {
if (action_first) hawk_clrpt(hawk, action_first);
goto oops;
}
if (!action_first)
{
action_first = v;
action_last = v;
}
else if (v->type == HAWK_NDE_NULL && v->type == action_last->type)
{
/* skip a successive null statement */
hawk_freemem(hawk, v);
}
else
{
action_last->next = v;
action_last = v;
}
while (MATCH(hawk,TOK_NEWLINE))
{
if (get_token(hawk) <= -1) goto oops;
}
}
vv = alloc_nde_case(hawk, &eloc);
if (!vv)
{
if (action_first) hawk_clrpt(hawk, action_first);
goto oops;
}
vv->val = case_val;
vv->action = action_first;
if (!case_val) default_part = (hawk_nde_t*)vv;
else case_val = HAWK_NULL;
if (!case_first)
{
case_first = (hawk_nde_t*)vv;
case_last = (hawk_nde_t*)vv;
}
else
{
case_last->next = (hawk_nde_t*)vv;
case_last = (hawk_nde_t*)vv;
}
}
else
{
hawk_seterrfmt(hawk, &hawk->tok.loc, HAWK_EKWCASE, FMT_EKWCASE, HAWK_OOECS_LEN(hawk->tok.name), HAWK_OOECS_PTR(hawk->tok.name));
goto oops;
}
}
while (MATCH(hawk,TOK_NEWLINE))
{
if (get_token(hawk) <= -1) goto oops;
}
if (!MATCH(hawk, TOK_RBRACE))
{
hawk_seterrfmt(hawk, &hawk->tok.loc, HAWK_ERBRACE, FMT_ERBRACE, HAWK_OOECS_LEN(hawk->tok.name), HAWK_OOECS_PTR(hawk->tok.name));
goto oops;
}
if (get_token(hawk) <= -1) goto oops;
nde = (hawk_nde_switch_t*)hawk_callocmem(hawk, HAWK_SIZEOF(*nde));
if (HAWK_UNLIKELY(!nde))
{
ADJERR_LOC(hawk, xloc);
goto oops;
}
nde->type = HAWK_NDE_SWITCH;
nde->loc = *xloc;
nde->test = test;
nde->case_part = case_first;
nde->default_part = default_part;
return (hawk_nde_t*)nde;
oops:
if (case_val) hawk_clrpt(hawk, case_val);
if (case_first) hawk_clrpt(hawk, case_first);
/*if (default_part) hawk_clrpt(hawk, default_part); no need to crear it as it is in the case_first chanin */
if (test) hawk_clrpt(hawk, test);
return HAWK_NULL;
}
static hawk_nde_t* parse_while (hawk_t* hawk, const hawk_loc_t* xloc)
{
hawk_nde_t* test = HAWK_NULL;
@ -2676,7 +2893,6 @@ static hawk_nde_t* parse_for (hawk_t* hawk, const hawk_loc_t* xloc)
{
{
hawk_loc_t eloc;
eloc = hawk->tok.loc;
incr = parse_expr_withdc(hawk, &eloc);
if (HAWK_UNLIKELY(!incr)) goto oops;
@ -2791,7 +3007,7 @@ static hawk_nde_t* parse_break (hawk_t* hawk, const hawk_loc_t* xloc)
hawk_nde_break_t* nde;
HAWK_ASSERT (hawk->ptok.type == TOK_BREAK);
if (hawk->parse.depth.loop <= 0)
if (hawk->parse.depth.loop <= 0 && hawk->parse.depth.swtch <= 0)
{
hawk_seterrnum(hawk, xloc, HAWK_EBREAK);
return HAWK_NULL;
@ -3256,8 +3472,7 @@ oops:
return HAWK_NULL;
}
static hawk_nde_t* parse_statement_nb (
hawk_t* hawk, const hawk_loc_t* xloc)
static hawk_nde_t* parse_statement_nb (hawk_t* hawk, const hawk_loc_t* xloc)
{
/* parse a non-block statement */
hawk_nde_t* nde;
@ -3268,6 +3483,11 @@ static hawk_nde_t* parse_statement_nb (
if (get_token(hawk) <= -1) return HAWK_NULL;
return parse_if(hawk, xloc);
}
else if (MATCH(hawk, TOK_SWITCH))
{
if (get_token(hawk) <= -1) return HAWK_NULL;
return parse_switch(hawk, xloc);
}
else if (MATCH(hawk,TOK_WHILE))
{
if (get_token(hawk) <= -1) return HAWK_NULL;
@ -3485,7 +3705,6 @@ static hawk_nde_t* parse_expr_basic (hawk_t* hawk, const hawk_loc_t* xloc)
nde = parse_logical_or(hawk, xloc);
if (nde == HAWK_NULL) return HAWK_NULL;
if (MATCH(hawk,TOK_QUEST))
if (MATCH(hawk,TOK_QUEST))
{
hawk_loc_t eloc;
@ -5200,6 +5419,39 @@ oops:
return HAWK_NULL;
}
static hawk_nde_t* parse_primary_literal (hawk_t* hawk, const hawk_loc_t* xloc)
{
switch (hawk->tok.type)
{
case TOK_CHAR:
return parse_primary_char(hawk, xloc);
case TOK_BCHR:
return parse_primary_bchr(hawk, xloc);
case TOK_INT:
return parse_primary_int(hawk, xloc);
case TOK_FLT:
return parse_primary_flt(hawk, xloc);
case TOK_STR:
return parse_primary_str(hawk, xloc);
case TOK_MBS:
return parse_primary_mbs(hawk, xloc);
default:
{
hawk_tok_t* xtok;
xtok = MATCH(hawk,TOK_NEWLINE)? &hawk->ptok: &hawk->tok;
hawk_seterrfmt(hawk, &xtok->loc, HAWK_EEXPRNR, HAWK_T("literal expression not recognized around '%.*js'"), HAWK_OOECS_LEN(xtok->name), HAWK_OOECS_PTR(xtok->name));
return HAWK_NULL;
}
}
}
static hawk_nde_t* parse_primary_nopipe (hawk_t* hawk, const hawk_loc_t* xloc)
{
switch (hawk->tok.type)

193
lib/run.c
View File

@ -78,7 +78,7 @@ static int init_rtx (hawk_rtx_t* rtx, hawk_t* hawk, hawk_rio_cbs_t* rio);
static void fini_rtx (hawk_rtx_t* rtx, int fini_globals);
static int init_globals (hawk_rtx_t* rtx);
static void refdown_globals (hawk_rtx_t* run, int pop);
static void refdown_globals (hawk_rtx_t* rtx, int pop);
static int run_pblocks (hawk_rtx_t* rtx);
static int run_pblock_chain (hawk_rtx_t* rtx, hawk_chain_t* cha);
@ -86,6 +86,7 @@ static int run_pblock (hawk_rtx_t* rtx, hawk_chain_t* cha, hawk_oow_t bno);
static int run_block (hawk_rtx_t* rtx, hawk_nde_blk_t* nde);
static int run_statement (hawk_rtx_t* rtx, hawk_nde_t* nde);
static int run_if (hawk_rtx_t* rtx, hawk_nde_if_t* nde);
static int run_switch (hawk_rtx_t* rtx, hawk_nde_switch_t* nde);
static int run_while (hawk_rtx_t* rtx, hawk_nde_while_t* nde);
static int run_for (hawk_rtx_t* rtx, hawk_nde_for_t* nde);
static int run_forin (hawk_rtx_t* rtx, hawk_nde_forin_t* nde);
@ -1979,7 +1980,7 @@ static int run_pblocks (hawk_rtx_t* rtx)
{
int n;
#define ADJUST_ERROR(run) \
#define ADJUST_ERROR(rtx) \
if (rtx->hawk->tree.chain != HAWK_NULL) \
{ \
if (rtx->hawk->tree.chain->pattern != HAWK_NULL) \
@ -1989,7 +1990,7 @@ static int run_pblocks (hawk_rtx_t* rtx)
} \
else if (rtx->hawk->tree.end != HAWK_NULL) \
{ \
ADJERR_LOC (run, &rtx->hawk->tree.end->loc); \
ADJERR_LOC(rtx, &rtx->hawk->tree.end->loc); \
}
rtx->inrec.buf_pos = 0;
@ -2279,6 +2280,17 @@ static int run_statement (hawk_rtx_t* rtx, hawk_nde_t* nde)
xret = run_if(rtx, (hawk_nde_if_t*)nde);
break;
case HAWK_NDE_SWITCH:
xret = run_switch(rtx, (hawk_nde_switch_t*)nde);
break;
case HAWK_NDE_CASE:
/* this must never happen - run_swtich must handle this part */
HAWK_ASSERT (!"should never happen - HAWK_NDE_CASE must not be fed to run_statement");
hawk_rtx_seterrnum(rtx, &nde->loc, HAWK_EINTERN);
xret = -1;
break;
case HAWK_NDE_WHILE:
case HAWK_NDE_DOWHILE:
xret = run_while(rtx, (hawk_nde_while_t*)nde);
@ -2378,6 +2390,119 @@ static int run_if (hawk_rtx_t* rtx, hawk_nde_if_t* nde)
return n;
}
static int run_switch (hawk_rtx_t* rtx, hawk_nde_switch_t* nde)
{
hawk_val_t* test;
hawk_val_t* v;
hawk_nde_case_t* case_part;
hawk_nde_case_t* default_part;
int eval_true = 0;
int ret = 0;
/* the test expression for the if statement cannot have
* chained expressions. this should not be allowed by the
* parser first of all */
HAWK_ASSERT (nde->test->next == HAWK_NULL);
test = eval_expression(rtx, nde->test);
if (HAWK_UNLIKELY(!test)) return -1;
hawk_rtx_refupval(rtx, test);
HAWK_ASSERT(nde->type == HAWK_NDE_CASE);
case_part = (hawk_nde_case_t*)nde->case_part;
default_part = (hawk_nde_case_t*)nde->default_part;
while (case_part)
{
int x;
if (eval_true) goto skip_eval;
if (case_part->val) // skip the default part.
{
v = eval_expression(rtx, case_part->val);
hawk_rtx_refupval(rtx, v);
x = hawk_rtx_cmpval(rtx, test, v, &ret);
hawk_rtx_refdownval(rtx, v);
if (x <= -1)
{
hawk_rtx_refdownval(rtx, test);
return -1;
}
if (ret == 0)
{
skip_eval:
eval_true = 1;
if (case_part->action)
{
hawk_nde_t* action;
action = case_part->action;
do
{
if (run_statement(rtx, action) <= -1)
{
ret = -1;
goto done;
}
if (rtx->exit_level == EXIT_BREAK) /* if 'break' has been executed */
{
rtx->exit_level = EXIT_NONE;
goto done;
}
else if (rtx->exit_level != EXIT_NONE) goto done;
action = action->next;
}
while(action);
}
}
}
case_part = (hawk_nde_case_t*)case_part->next;
}
if (!eval_true && default_part)
{
case_part = default_part;
do
{
if (case_part->action)
{
hawk_nde_t* action;
action = case_part->action;
do
{
if (run_statement(rtx, action) <= -1)
{
ret = -1;
goto done;
}
if (rtx->exit_level == EXIT_BREAK) /* if 'break' has been executed */
{
rtx->exit_level = EXIT_NONE;
goto done;
}
else if (rtx->exit_level != EXIT_NONE) goto done;
action = action->next;
}
while (action);
}
case_part = (hawk_nde_case_t*)case_part->next;
}
while (case_part);
}
done:
hawk_rtx_refdownval(rtx, test);
return ret;
}
static int run_while (hawk_rtx_t* rtx, hawk_nde_while_t* nde)
{
hawk_val_t* test;
@ -2749,9 +2874,9 @@ done1:
return ret;
}
static int run_break (hawk_rtx_t* run, hawk_nde_break_t* nde)
static int run_break (hawk_rtx_t* rtx, hawk_nde_break_t* nde)
{
run->exit_level = EXIT_BREAK;
rtx->exit_level = EXIT_BREAK;
return 0;
}
@ -6200,60 +6325,60 @@ static hawk_val_t* eval_binop_match0 (
return res;
}
static hawk_val_t* eval_binop_ma (hawk_rtx_t* run, hawk_nde_t* left, hawk_nde_t* right)
static hawk_val_t* eval_binop_ma (hawk_rtx_t* rtx, hawk_nde_t* left, hawk_nde_t* right)
{
hawk_val_t* lv, * rv, * res;
HAWK_ASSERT (left->next == HAWK_NULL);
HAWK_ASSERT (right->next == HAWK_NULL);
lv = eval_expression(run, left);
lv = eval_expression(rtx, left);
if (HAWK_UNLIKELY(!lv)) return HAWK_NULL;
hawk_rtx_refupval(run, lv);
hawk_rtx_refupval(rtx, lv);
rv = eval_expression0(run, right);
rv = eval_expression0(rtx, right);
if (HAWK_UNLIKELY(!rv))
{
hawk_rtx_refdownval(run, lv);
hawk_rtx_refdownval(rtx, lv);
return HAWK_NULL;
}
hawk_rtx_refupval(run, rv);
hawk_rtx_refupval(rtx, rv);
res = eval_binop_match0(run, lv, rv, &left->loc, &right->loc, 1);
res = eval_binop_match0(rtx, lv, rv, &left->loc, &right->loc, 1);
hawk_rtx_refdownval(run, rv);
hawk_rtx_refdownval(run, lv);
hawk_rtx_refdownval(rtx, rv);
hawk_rtx_refdownval(rtx, lv);
return res;
}
static hawk_val_t* eval_binop_nm (hawk_rtx_t* run, hawk_nde_t* left, hawk_nde_t* right)
static hawk_val_t* eval_binop_nm (hawk_rtx_t* rtx, hawk_nde_t* left, hawk_nde_t* right)
{
hawk_val_t* lv, * rv, * res;
HAWK_ASSERT (left->next == HAWK_NULL);
HAWK_ASSERT (right->next == HAWK_NULL);
lv = eval_expression(run, left);
lv = eval_expression(rtx, left);
if (HAWK_UNLIKELY(!lv)) return HAWK_NULL;
hawk_rtx_refupval(run, lv);
hawk_rtx_refupval(rtx, lv);
rv = eval_expression0(run, right);
rv = eval_expression0(rtx, right);
if (HAWK_UNLIKELY(!rv))
{
hawk_rtx_refdownval(run, lv);
hawk_rtx_refdownval(rtx, lv);
return HAWK_NULL;
}
hawk_rtx_refupval(run, rv);
hawk_rtx_refupval(rtx, rv);
res = eval_binop_match0(run, lv, rv, &left->loc, &right->loc, 0);
res = eval_binop_match0(rtx, lv, rv, &left->loc, &right->loc, 0);
hawk_rtx_refdownval(run, rv);
hawk_rtx_refdownval(run, lv);
hawk_rtx_refdownval(rtx, rv);
hawk_rtx_refdownval(rtx, lv);
return res;
}
@ -6613,22 +6738,22 @@ static hawk_val_t* eval_incpst (hawk_rtx_t* rtx, hawk_nde_t* nde)
return res;
}
static hawk_val_t* eval_cnd (hawk_rtx_t* run, hawk_nde_t* nde)
static hawk_val_t* eval_cnd (hawk_rtx_t* rtx, hawk_nde_t* nde)
{
hawk_val_t* tv, * v;
hawk_nde_cnd_t* cnd = (hawk_nde_cnd_t*)nde;
HAWK_ASSERT (cnd->test->next == HAWK_NULL);
tv = eval_expression(run, cnd->test);
tv = eval_expression(rtx, cnd->test);
if (HAWK_UNLIKELY(!tv)) return HAWK_NULL;
hawk_rtx_refupval(run, tv);
hawk_rtx_refupval(rtx, tv);
HAWK_ASSERT (cnd->left->next == HAWK_NULL && cnd->right->next == HAWK_NULL);
v = (hawk_rtx_valtobool(run, tv))? eval_expression(run, cnd->left): eval_expression(run, cnd->right);
v = (hawk_rtx_valtobool(rtx, tv))? eval_expression(rtx, cnd->left): eval_expression(rtx, cnd->right);
hawk_rtx_refdownval(run, tv);
hawk_rtx_refdownval(rtx, tv);
return v;
}
@ -7984,20 +8109,20 @@ static hawk_val_t* eval_getline (hawk_rtx_t* rtx, hawk_nde_t* nde)
return ((hawk_nde_getline_t*)nde)->mbs? __eval_getbline(rtx, nde): __eval_getline(rtx, nde);
}
static hawk_val_t* eval_print (hawk_rtx_t* run, hawk_nde_t* nde)
static hawk_val_t* eval_print (hawk_rtx_t* rtx, hawk_nde_t* nde)
{
int n = run_print(run, (hawk_nde_print_t*)nde);
int n = run_print(rtx, (hawk_nde_print_t*)nde);
if (n == PRINT_IOERR) n = -1; /* let print return -1 */
else if (n <= -1) return HAWK_NULL;
return hawk_rtx_makeintval(run, n);
return hawk_rtx_makeintval(rtx, n);
}
static hawk_val_t* eval_printf (hawk_rtx_t* run, hawk_nde_t* nde)
static hawk_val_t* eval_printf (hawk_rtx_t* rtx, hawk_nde_t* nde)
{
int n = run_printf(run, (hawk_nde_print_t*)nde);
int n = run_printf(rtx, (hawk_nde_print_t*)nde);
if (n == PRINT_IOERR) n = -1; /* let print return -1 */
else if (n <= -1) return HAWK_NULL;
return hawk_rtx_makeintval(run, n);
return hawk_rtx_makeintval(rtx, n);
}
static int read_record (hawk_rtx_t* rtx)

View File

@ -75,6 +75,8 @@ typedef struct hawk_nde_fncall_t hawk_nde_fncall_t;
typedef struct hawk_nde_getline_t hawk_nde_getline_t;
typedef struct hawk_nde_if_t hawk_nde_if_t;
typedef struct hawk_nde_switch_t hawk_nde_switch_t;
typedef struct hawk_nde_case_t hawk_nde_case_t;
typedef struct hawk_nde_while_t hawk_nde_while_t;
typedef struct hawk_nde_for_t hawk_nde_for_t;
typedef struct hawk_nde_forin_t hawk_nde_forin_t;
@ -280,6 +282,23 @@ struct hawk_nde_if_t
hawk_nde_t* else_part; /* optional */
};
/* HAWK_NDE_SWITCH */
struct hawk_nde_switch_t
{
HAWK_NDE_HDR;
hawk_nde_t* test;
hawk_nde_t* case_part; /* optional */
hawk_nde_t* default_part; /* optional */
};
/* HAWK_NDE_CASE */
struct hawk_nde_case_t
{
HAWK_NDE_HDR;
hawk_nde_t* val;
hawk_nde_t* action;
};
/* HAWK_NDE_WHILE, HAWK_NDE_DOWHILE */
struct hawk_nde_while_t
{

View File

@ -969,6 +969,49 @@ static int print_stmt (hawk_t* hawk, hawk_nde_t* p, int depth)
break;
}
case HAWK_NDE_SWITCH:
{
hawk_nde_switch_t* px = (hawk_nde_switch_t*)p;
PRINT_TABS(hawk, depth);
hawk_getkwname(hawk, HAWK_KWID_SWITCH, &kw);
PUT_SRCSTRN(hawk, kw.ptr, kw.len);
PUT_SRCSTR(hawk, HAWK_T(" ("));
PRINT_EXPR(hawk, px->test);
PUT_SRCSTR(hawk, HAWK_T(")"));
PUT_NL(hawk);
PRINT_TABS(hawk, depth);
PUT_SRCSTR(hawk, HAWK_T("{"));
PUT_NL(hawk);
if (px->case_part) PRINT_STMTS(hawk, px->case_part, depth);
/* default_part is one of the case_parts. no explicit printing is needed */
/*if (px->default_part) PRINT_STMTS(hawk, px->default_part, depth);*/
PUT_NL(hawk);
PRINT_TABS(hawk, depth);
PUT_SRCSTR(hawk, HAWK_T("}"));
PUT_NL(hawk);
break;
}
case HAWK_NDE_CASE:
{
/* this is not a real statement and is subject to the owning switch statement. */
hawk_nde_case_t* px = (hawk_nde_case_t*)p;
PRINT_TABS(hawk, depth);
hawk_getkwname(hawk, (px->val? HAWK_KWID_CASE: HAWK_KWID_DEFAULT), &kw);
PUT_SRCSTRN(hawk, kw.ptr, kw.len);
if (px->val)
{
PUT_SRCSTR(hawk, HAWK_T(" "));
PRINT_EXPR(hawk, px->val);
}
PUT_SRCSTR(hawk, HAWK_T(":"));
PUT_NL(hawk);
if (px->action) PRINT_STMTS(hawk, px->action, depth + 1);
break;
}
case HAWK_NDE_WHILE:
{
hawk_nde_while_t* px = (hawk_nde_while_t*)p;
@ -988,6 +1031,7 @@ static int print_stmt (hawk_t* hawk, hawk_nde_t* p, int depth)
{
PRINT_STMTS(hawk, px->body, depth + 1);
}
PUT_NL(hawk);
break;
}
@ -1288,6 +1332,26 @@ void hawk_clrpt (hawk_t* hawk, hawk_nde_t* tree)
break;
}
case HAWK_NDE_SWITCH:
{
hawk_nde_switch_t* px = (hawk_nde_switch_t*)p;
hawk_clrpt(hawk, px->test);
if (px->case_part) hawk_clrpt(hawk, px->case_part);
/* px->default_part is one of the case parts. explicit clean up isn't required */
/*if (px->default_part) hawk_clrpt(hawk, px->default_part);*/
hawk_freemem(hawk, p);
break;
}
case HAWK_NDE_CASE:
{
hawk_nde_case_t* px = (hawk_nde_case_t*)p;
if (px->val) hawk_clrpt(hawk, px->val);
if (px->action) hawk_clrpt(hawk, px->action);
hawk_freemem(hawk, p);
break;
}
case HAWK_NDE_WHILE:
case HAWK_NDE_DOWHILE:
{

View File

@ -665,6 +665,29 @@ function main()
f = test10
tap_ensure (f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 55, @SCRIPTNAME, @SCRIPTLINE);
}
{
tap_ensure(test12(2,5), -3, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(test12(3,5), 8, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(test13(1), 1, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(test13(2), 2, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(test13(3), 3, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(test13(4), 4, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(test13(5), 5, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(test13(6), 1005, @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(test14("hello"), "world", @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(test14("donkey"), "rankey", @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(test14("speed"), "unknown", @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(test15("hello"), "world", @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(test15("donkey"), "[rankey012]", @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(test15("skunk"), "stinks", @SCRIPTNAME, @SCRIPTLINE);
tap_ensure(test15("speed"), "unknown", @SCRIPTNAME, @SCRIPTLINE);
}
tap_end ();
}
@ -709,3 +732,88 @@ function test10(...) {
function test11(...) {
return (3 in @argv);
}
function test12(...) {
switch(@argv[0] * @argv[1]) {
case 10:
return @argv[0] - @argv[1];
default:
return @argv[0] + @argv[1];
}
}
function test13(x) {
@local a;
a = 0;
switch(x) {
default:
a = 1000;
case 5:
a++;
case 4:
a++;
case 3:
a++;
case 2:
a++;
case 1:
a++;
break;
}
return a;
}
function test14(x) {
switch(x) {
case "hello":
return "world";
case "donkey":
return "rankey";
default:
return "unknown";
}
}
function test15(x) {
@local a, i;
switch(x) {
case "hello":
a = "world";
break;
case "donkey":
{
@local l;
a = "rankey";
l = length(a);
for (i = 0; i < l; i++) {
if (i == 3) break;
a = sprintf("%s%d", a, i);
}
a = sprintf("[%s]", a);
break;
}
default:
if (x == "skunk") a = "stinks";
else a = "unknown";
break;
}
return a;
}