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 - BEGIN
- END - END
- break - break
- case
- continue - continue
- default
- delete - delete
- do - do
- else - else
@ -494,6 +496,7 @@ The following words are reserved and cannot be used as a variable name, a parame
- printf - printf
- return - return
- while - 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. 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. 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 ```awk
if (condition) { 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 ```awk
while (condition) { while (condition) {
# statements # statements
@ -659,13 +673,13 @@ do {
} while (condition) } 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 ```awk
for (initialization; condition; increment/decrement) { for (initialization; condition; increment/decrement) {
## statements ## 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 ```awk
for (index in array) { for (index in array) {
## statements using array[index] ## 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); 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 brace expected"),
HAWK_T("left parenthesis expected"), HAWK_T("left parenthesis expected"),
HAWK_T("right parenthesis expected"), HAWK_T("right parenthesis expected"),
HAWK_T("right brace expected"),
HAWK_T("right bracket expected"), HAWK_T("right bracket expected"),
HAWK_T("comma expected"), HAWK_T("comma expected"),
HAWK_T("semicolon 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 'function' expected"),
HAWK_T("keyword 'while' expected"), HAWK_T("keyword 'while' expected"),
HAWK_T("keyword 'case' expected"),
HAWK_T("multiple 'default' labels"),
HAWK_T("invalid assignment statement"), HAWK_T("invalid assignment statement"),
HAWK_T("identifier expected"), HAWK_T("identifier expected"),
HAWK_T("not a valid function name"), HAWK_T("not a valid function name"),

View File

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

View File

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

View File

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

View File

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

View File

@ -35,10 +35,13 @@
#define FMT_EKWFNC HAWK_T("keyword 'function' expected in place of '%.*js'") #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_EKWIN HAWK_T("keyword 'in' expected in place of '%.*js'")
#define FMT_EKWWHL HAWK_T("keyword 'while' 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_ELBRACE HAWK_T("left brace expected in place of '%.*js'")
#define FMT_ELPAREN HAWK_T("left parenthesis 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_HS HAWK_T("no such global variable - %.*hs")
#define FMT_ENOENT_GBL_LS HAWK_T("no such global variable - %.*ls") #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_ERBRACK HAWK_T("right bracket expected in place of '%.*js'")
#define FMT_ERPAREN HAWK_T("right parenthesis 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'") #define FMT_ESCOLON HAWK_T("semicolon expected in place of '%.*js'")
@ -48,6 +51,8 @@
#define TOK_FLAGS_LPAREN_CLOSER (1 << 0) #define TOK_FLAGS_LPAREN_CLOSER (1 << 0)
#define PARSE_BLOCK_FLAG_IS_TOP (1 << 0)
enum tok_t enum tok_t
{ {
TOK_EOF, TOK_EOF,
@ -140,6 +145,9 @@ enum tok_t
TOK_WHILE, TOK_WHILE,
TOK_FOR, TOK_FOR,
TOK_DO, TOK_DO,
TOK_SWITCH,
TOK_CASE,
TOK_DEFAULT,
TOK_BREAK, TOK_BREAK,
TOK_CONTINUE, TOK_CONTINUE,
TOK_RETURN, TOK_RETURN,
@ -200,17 +208,15 @@ static int parse_progunit (hawk_t* hawk);
static hawk_t* collect_globals (hawk_t* hawk); static hawk_t* collect_globals (hawk_t* hawk);
static void adjust_static_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_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_function (hawk_t* hawk);
static hawk_nde_t* parse_begin (hawk_t* hawk); static hawk_nde_t* parse_begin (hawk_t* hawk);
static hawk_nde_t* parse_end (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_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_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_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); 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_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 (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_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); 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 */ #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("BEGIN"), 5 }, TOK_BEGIN, HAWK_PABLOCK },
{ { HAWK_T("END"), 3 }, TOK_END, HAWK_PABLOCK }, { { HAWK_T("END"), 3 }, TOK_END, HAWK_PABLOCK },
{ { HAWK_T("break"), 5 }, TOK_BREAK, 0 }, { { HAWK_T("break"), 5 }, TOK_BREAK, 0 },
{ { HAWK_T("case"), 4 }, TOK_CASE, 0 },
{ { HAWK_T("continue"), 8 }, TOK_CONTINUE, 0 }, { { HAWK_T("continue"), 8 }, TOK_CONTINUE, 0 },
{ { HAWK_T("default"), 7 }, TOK_DEFAULT, 0 },
{ { HAWK_T("delete"), 6 }, TOK_DELETE, 0 }, { { HAWK_T("delete"), 6 }, TOK_DELETE, 0 },
{ { HAWK_T("do"), 2 }, TOK_DO, 0 }, { { HAWK_T("do"), 2 }, TOK_DO, 0 },
{ { HAWK_T("else"), 4 }, TOK_ELSE, 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("print"), 5 }, TOK_PRINT, HAWK_RIO },
{ { HAWK_T("printf"), 6 }, TOK_PRINTF, HAWK_RIO }, { { HAWK_T("printf"), 6 }, TOK_PRINTF, HAWK_RIO },
{ { HAWK_T("return"), 6 }, TOK_RETURN, 0 }, { { HAWK_T("return"), 6 }, TOK_RETURN, 0 },
{ { HAWK_T("switch"), 6 }, TOK_SWITCH, 0 },
{ { HAWK_T("while"), 5 }, TOK_WHILE, 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; 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_t* head, * curr, * nde;
hawk_nde_blk_t* block; 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; 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); hawk_arr_delete (hawk->parse.lcls, nlcls_outer, HAWK_ARR_SIZE(hawk->parse.lcls) - nlcls_outer);
return HAWK_NULL; 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; int once;
if (hawk->opt.depth.s.incl > 0 && if (hawk->opt.depth.s.incl > 0 && hawk->parse.depth.incl >= hawk->opt.depth.s.incl)
hawk->parse.depth.incl >= hawk->opt.depth.s.incl)
{ {
hawk_seterrnum(hawk, &hawk->ptok.loc, HAWK_EINCLTD); hawk_seterrnum(hawk, &hawk->ptok.loc, HAWK_EINCLTD);
return HAWK_NULL; 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 */ and merged to top-level block */
/* migrate all block-local variables to the outermost 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); HAWK_ASSERT (nlcls_outer == 0 && nlcls_max == 0);
block->nlcls = hawk->parse.nlcls_max - nlcls_outer; 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; 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; 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++; hawk->parse.depth.block++;
nde = parse_block(hawk, xloc, istop); nde = parse_block(hawk, xloc, flags);
hawk->parse.depth.block--; hawk->parse.depth.block--;
return nde; return nde;
@ -2330,7 +2339,7 @@ static hawk_t* collect_globals (hawk_t* hawk)
return 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)) 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; return HAWK_NULL;
} }
if (istop) if (flags & PARSE_BLOCK_FLAG_IS_TOP)
{ {
/* check if it conflicts with a parameter name. /* check if it conflicts with a parameter name.
* the first level declaration is treated as the same * the first level declaration is treated as the same
@ -2525,6 +2534,214 @@ oops:
return HAWK_NULL; 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) static hawk_nde_t* parse_while (hawk_t* hawk, const hawk_loc_t* xloc)
{ {
hawk_nde_t* test = HAWK_NULL; 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; hawk_loc_t eloc;
eloc = hawk->tok.loc; eloc = hawk->tok.loc;
incr = parse_expr_withdc(hawk, &eloc); incr = parse_expr_withdc(hawk, &eloc);
if (HAWK_UNLIKELY(!incr)) goto oops; 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_nde_break_t* nde;
HAWK_ASSERT (hawk->ptok.type == TOK_BREAK); 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); hawk_seterrnum(hawk, xloc, HAWK_EBREAK);
return HAWK_NULL; return HAWK_NULL;
@ -3256,8 +3472,7 @@ oops:
return HAWK_NULL; return HAWK_NULL;
} }
static hawk_nde_t* parse_statement_nb ( static hawk_nde_t* parse_statement_nb (hawk_t* hawk, const hawk_loc_t* xloc)
hawk_t* hawk, const hawk_loc_t* xloc)
{ {
/* parse a non-block statement */ /* parse a non-block statement */
hawk_nde_t* nde; hawk_nde_t* nde;
@ -3268,6 +3483,11 @@ static hawk_nde_t* parse_statement_nb (
if (get_token(hawk) <= -1) return HAWK_NULL; if (get_token(hawk) <= -1) return HAWK_NULL;
return parse_if(hawk, xloc); 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)) else if (MATCH(hawk,TOK_WHILE))
{ {
if (get_token(hawk) <= -1) return HAWK_NULL; 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); nde = parse_logical_or(hawk, xloc);
if (nde == HAWK_NULL) return HAWK_NULL; if (nde == HAWK_NULL) return HAWK_NULL;
if (MATCH(hawk,TOK_QUEST))
if (MATCH(hawk,TOK_QUEST)) if (MATCH(hawk,TOK_QUEST))
{ {
hawk_loc_t eloc; hawk_loc_t eloc;
@ -5200,6 +5419,39 @@ oops:
return HAWK_NULL; 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) static hawk_nde_t* parse_primary_nopipe (hawk_t* hawk, const hawk_loc_t* xloc)
{ {
switch (hawk->tok.type) 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 void fini_rtx (hawk_rtx_t* rtx, int fini_globals);
static int init_globals (hawk_rtx_t* rtx); 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_pblocks (hawk_rtx_t* rtx);
static int run_pblock_chain (hawk_rtx_t* rtx, hawk_chain_t* cha); 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_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_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_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_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_for (hawk_rtx_t* rtx, hawk_nde_for_t* nde);
static int run_forin (hawk_rtx_t* rtx, hawk_nde_forin_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; int n;
#define ADJUST_ERROR(run) \ #define ADJUST_ERROR(rtx) \
if (rtx->hawk->tree.chain != HAWK_NULL) \ if (rtx->hawk->tree.chain != HAWK_NULL) \
{ \ { \
if (rtx->hawk->tree.chain->pattern != 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) \ 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; 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); xret = run_if(rtx, (hawk_nde_if_t*)nde);
break; 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_WHILE:
case HAWK_NDE_DOWHILE: case HAWK_NDE_DOWHILE:
xret = run_while(rtx, (hawk_nde_while_t*)nde); 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; 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) static int run_while (hawk_rtx_t* rtx, hawk_nde_while_t* nde)
{ {
hawk_val_t* test; hawk_val_t* test;
@ -2749,9 +2874,9 @@ done1:
return ret; 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; return 0;
} }
@ -6200,60 +6325,60 @@ static hawk_val_t* eval_binop_match0 (
return res; 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_val_t* lv, * rv, * res;
HAWK_ASSERT (left->next == HAWK_NULL); HAWK_ASSERT (left->next == HAWK_NULL);
HAWK_ASSERT (right->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; 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)) if (HAWK_UNLIKELY(!rv))
{ {
hawk_rtx_refdownval(run, lv); hawk_rtx_refdownval(rtx, lv);
return HAWK_NULL; 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(rtx, rv);
hawk_rtx_refdownval(run, lv); hawk_rtx_refdownval(rtx, lv);
return res; 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_val_t* lv, * rv, * res;
HAWK_ASSERT (left->next == HAWK_NULL); HAWK_ASSERT (left->next == HAWK_NULL);
HAWK_ASSERT (right->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; 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)) if (HAWK_UNLIKELY(!rv))
{ {
hawk_rtx_refdownval(run, lv); hawk_rtx_refdownval(rtx, lv);
return HAWK_NULL; 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(rtx, rv);
hawk_rtx_refdownval(run, lv); hawk_rtx_refdownval(rtx, lv);
return res; return res;
} }
@ -6613,22 +6738,22 @@ static hawk_val_t* eval_incpst (hawk_rtx_t* rtx, hawk_nde_t* nde)
return res; 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_val_t* tv, * v;
hawk_nde_cnd_t* cnd = (hawk_nde_cnd_t*)nde; hawk_nde_cnd_t* cnd = (hawk_nde_cnd_t*)nde;
HAWK_ASSERT (cnd->test->next == HAWK_NULL); 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; 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); 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; 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); 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 */ if (n == PRINT_IOERR) n = -1; /* let print return -1 */
else if (n <= -1) return HAWK_NULL; 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 */ if (n == PRINT_IOERR) n = -1; /* let print return -1 */
else if (n <= -1) return HAWK_NULL; 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) 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_getline_t hawk_nde_getline_t;
typedef struct hawk_nde_if_t hawk_nde_if_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_while_t hawk_nde_while_t;
typedef struct hawk_nde_for_t hawk_nde_for_t; typedef struct hawk_nde_for_t hawk_nde_for_t;
typedef struct hawk_nde_forin_t hawk_nde_forin_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_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 */ /* HAWK_NDE_WHILE, HAWK_NDE_DOWHILE */
struct hawk_nde_while_t 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; 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: case HAWK_NDE_WHILE:
{ {
hawk_nde_while_t* px = (hawk_nde_while_t*)p; 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); PRINT_STMTS(hawk, px->body, depth + 1);
} }
PUT_NL(hawk);
break; break;
} }
@ -1288,6 +1332,26 @@ void hawk_clrpt (hawk_t* hawk, hawk_nde_t* tree)
break; 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_WHILE:
case HAWK_NDE_DOWHILE: case HAWK_NDE_DOWHILE:
{ {

View File

@ -665,6 +665,29 @@ function main()
f = test10 f = test10
tap_ensure (f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), 55, @SCRIPTNAME, @SCRIPTLINE); 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 (); tap_end ();
} }
@ -709,3 +732,88 @@ function test10(...) {
function test11(...) { function test11(...) {
return (3 in @argv); 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;
}