diff --git a/ase/awk/awk.c b/ase/awk/awk.c index f1f7d83f..a4500b22 100644 --- a/ase/awk/awk.c +++ b/ase/awk/awk.c @@ -1,5 +1,5 @@ /* - * $Id: awk.c,v 1.62 2006-07-30 15:53:42 bacon Exp $ + * $Id: awk.c,v 1.63 2006-08-01 15:57:42 bacon Exp $ */ #include @@ -123,6 +123,7 @@ void xp_awk_clear (xp_awk_t* awk) xp_awk_tab_clear (&awk->parse.params); awk->parse.nlocals_max = 0; + awk->parse.depth.loop = 0; /* clear parse trees */ awk->tree.nglobals = 0; diff --git a/ase/awk/awk.h b/ase/awk/awk.h index 59dfb818..eb57cf76 100644 --- a/ase/awk/awk.h +++ b/ase/awk/awk.h @@ -1,5 +1,5 @@ /* - * $Id: awk.h,v 1.84 2006-07-30 15:53:42 bacon Exp $ + * $Id: awk.h,v 1.85 2006-08-01 15:57:42 bacon Exp $ */ #ifndef _XP_AWK_AWK_H_ @@ -148,6 +148,10 @@ enum XP_AWK_ELVALUE, /* l-value required */ XP_AWK_ETOOFEWARGS, /* too few arguments */ XP_AWK_ETOOMANYARGS, /* too many arguments */ + XP_AWK_EBREAK, /* break outside a loop */ + XP_AWK_ECONTINUE, /* continue outside a loop */ + XP_AWK_ENEXT, /* next illegal in BEGIN or END block */ + XP_AWK_ENEXTFILE, /* nextfile illegal in BEGIN or END block */ XP_AWK_EGETLINE, /* getline expected */ XP_AWK_EREXBUILD, /* cannot build regexp */ XP_AWK_EREXMATCH, /* an error occurred in matching regexp */ diff --git a/ase/awk/awk_i.h b/ase/awk/awk_i.h index 37c3ea1d..347f4c58 100644 --- a/ase/awk/awk_i.h +++ b/ase/awk/awk_i.h @@ -1,5 +1,5 @@ /* - * $Id: awk_i.h,v 1.35 2006-07-27 16:50:28 bacon Exp $ + * $Id: awk_i.h,v 1.36 2006-08-01 15:57:42 bacon Exp $ */ #ifndef _XP_AWK_AWKI_H_ @@ -93,10 +93,22 @@ struct xp_awk_t /* parse tree */ xp_awk_tree_t tree; + int state; /* temporary information that the parser needs */ struct { + struct + { + int block; + int loop; + } id; + + struct + { + xp_size_t loop; + } depth; + xp_awk_tab_t globals; xp_awk_tab_t locals; xp_awk_tab_t params; diff --git a/ase/awk/err.c b/ase/awk/err.c index bc361271..474a823b 100644 --- a/ase/awk/err.c +++ b/ase/awk/err.c @@ -1,5 +1,5 @@ /* - * $Id: err.c,v 1.28 2006-07-26 16:43:35 bacon Exp $ + * $Id: err.c,v 1.29 2006-08-01 15:57:42 bacon Exp $ */ #include @@ -69,6 +69,10 @@ const xp_char_t* xp_awk_geterrstr (xp_awk_t* awk) XP_T("l-value required"), XP_T("too few arguments"), XP_T("too many arguments"), + XP_T("break outside a loop"), + XP_T("continue outside a loop"), + XP_T("next illegal in BEGIN or END block"), + XP_T("nextfile illegal in BEGIN or END block"), XP_T("getline expected"), XP_T("cannot build the regular expression"), XP_T("an error occurred in the regular expression match"), diff --git a/ase/awk/extio.c b/ase/awk/extio.c index 15cb88a9..df0b73dd 100644 --- a/ase/awk/extio.c +++ b/ase/awk/extio.c @@ -1,5 +1,5 @@ /* - * $Id: extio.c,v 1.22 2006-07-30 15:53:42 bacon Exp $ + * $Id: extio.c,v 1.23 2006-08-01 15:57:42 bacon Exp $ */ #include @@ -415,7 +415,8 @@ int xp_awk_nextextio_read ( return n; } -int xp_awk_closeextio (xp_awk_run_t* run, const xp_char_t* name, int* errnum) +int xp_awk_closeextio ( + xp_awk_run_t* run, const xp_char_t* name, int* errnum) { xp_awk_extio_t* p = run->extio, * px = XP_NULL; diff --git a/ase/awk/parse.c b/ase/awk/parse.c index 520fcf77..cc1d82e5 100644 --- a/ase/awk/parse.c +++ b/ase/awk/parse.c @@ -1,5 +1,5 @@ /* - * $Id: parse.c,v 1.147 2006-08-01 04:40:14 bacon Exp $ + * $Id: parse.c,v 1.148 2006-08-01 15:57:42 bacon Exp $ */ #include @@ -97,6 +97,23 @@ enum __TOKEN_COUNT__ }; +enum +{ + PARSE_BLOCK_GLOBAL, + PARSE_BLOCK_FUNCTION, + PARSE_BLOCK_BEGIN, + PARSE_BLOCK_END, + PARSE_BLOCK_PATTERN +}; + +enum +{ + PARSE_LOOP_NONE, + PARSE_LOOP_WHILE, + PARSE_LOOP_FOR, + PARSE_LOOP_DOWHILE +}; + typedef struct __binmap_t __binmap_t; struct __binmap_t @@ -415,10 +432,14 @@ static xp_awk_t* __parse_progunit (xp_awk_t* awk) function name (parameter-list) { statement } */ + xp_assert (awk->parse.depth.loop == 0); + if ((awk->opt.parse & XP_AWK_EXPLICIT) && MATCH(awk,TOKEN_GLOBAL)) { xp_size_t nglobals; + awk->parse.id.block = PARSE_BLOCK_GLOBAL; + if (__get_token(awk) == -1) return XP_NULL; nglobals = xp_awk_tab_getsize(&awk->parse.globals); @@ -432,19 +453,23 @@ static xp_awk_t* __parse_progunit (xp_awk_t* awk) } else if (MATCH(awk,TOKEN_FUNCTION)) { + awk->parse.id.block = PARSE_BLOCK_FUNCTION; if (__parse_function(awk) == XP_NULL) return XP_NULL; } else if (MATCH(awk,TOKEN_BEGIN)) { + awk->parse.id.block = PARSE_BLOCK_BEGIN; if (__parse_begin(awk) == XP_NULL) return XP_NULL; } else if (MATCH(awk,TOKEN_END)) { + awk->parse.id.block = PARSE_BLOCK_END; if (__parse_end(awk) == XP_NULL) return XP_NULL; } else if (MATCH(awk,TOKEN_LBRACE)) { /* pattern less block */ + awk->parse.id.block = PARSE_BLOCK_PATTERN; if (__parse_ptnblock(awk,XP_NULL) == XP_NULL) return XP_NULL; } else @@ -460,6 +485,8 @@ static xp_awk_t* __parse_progunit (xp_awk_t* awk) */ xp_awk_nde_t* ptn; + awk->parse.id.block = PARSE_BLOCK_PATTERN; + ptn = __parse_expression (awk); if (ptn == XP_NULL) return XP_NULL; @@ -1083,12 +1110,22 @@ static xp_awk_nde_t* __parse_statement_nb (xp_awk_t* awk) else if (MATCH(awk,TOKEN_WHILE)) { if (__get_token(awk) == -1) return XP_NULL; - return __parse_while (awk); + + awk->parse.depth.loop++; + nde = __parse_while (awk); + awk->parse.depth.loop--; + + return nde; } else if (MATCH(awk,TOKEN_FOR)) { if (__get_token(awk) == -1) return XP_NULL; - return __parse_for (awk); + + awk->parse.depth.loop++; + nde = __parse_for (awk); + awk->parse.depth.loop--; + + return nde; } /* @@ -1097,7 +1134,12 @@ static xp_awk_nde_t* __parse_statement_nb (xp_awk_t* awk) if (MATCH(awk,TOKEN_DO)) { if (__get_token(awk) == -1) return XP_NULL; + + awk->parse.depth.loop++; nde = __parse_dowhile (awk); + awk->parse.depth.loop--; + + return nde; } else if (MATCH(awk,TOKEN_BREAK)) { @@ -2815,6 +2857,8 @@ static xp_awk_nde_t* __parse_break (xp_awk_t* awk) { xp_awk_nde_break_t* nde; + if (awk->parse.depth.loop <= 0) PANIC (awk, XP_AWK_EBREAK); + nde = (xp_awk_nde_break_t*) xp_malloc (xp_sizeof(xp_awk_nde_break_t)); if (nde == XP_NULL) PANIC (awk, XP_AWK_ENOMEM); nde->type = XP_AWK_NDE_BREAK; @@ -2827,6 +2871,8 @@ static xp_awk_nde_t* __parse_continue (xp_awk_t* awk) { xp_awk_nde_continue_t* nde; + if (awk->parse.depth.loop <= 0) PANIC (awk, XP_AWK_ECONTINUE); + nde = (xp_awk_nde_continue_t*)xp_malloc(xp_sizeof(xp_awk_nde_continue_t)); if (nde == XP_NULL) PANIC (awk, XP_AWK_ENOMEM); nde->type = XP_AWK_NDE_CONTINUE; @@ -3047,6 +3093,12 @@ static xp_awk_nde_t* __parse_next (xp_awk_t* awk) { xp_awk_nde_next_t* nde; + if (awk->parse.id.block == PARSE_BLOCK_BEGIN || + awk->parse.id.block == PARSE_BLOCK_END) + { + PANIC (awk, XP_AWK_ENEXT); + } + nde = (xp_awk_nde_next_t*) xp_malloc (xp_sizeof(xp_awk_nde_next_t)); if (nde == XP_NULL) PANIC (awk, XP_AWK_ENOMEM); nde->type = XP_AWK_NDE_NEXT; @@ -3059,6 +3111,12 @@ static xp_awk_nde_t* __parse_nextfile (xp_awk_t* awk) { xp_awk_nde_nextfile_t* nde; + if (awk->parse.id.block == PARSE_BLOCK_BEGIN || + awk->parse.id.block == PARSE_BLOCK_END) + { + PANIC (awk, XP_AWK_ENEXTFILE); + } + nde = (xp_awk_nde_nextfile_t*) xp_malloc (xp_sizeof(xp_awk_nde_nextfile_t)); if (nde == XP_NULL) PANIC (awk, XP_AWK_ENOMEM); diff --git a/ase/awk/run.c b/ase/awk/run.c index 5f41912a..b5e1114b 100644 --- a/ase/awk/run.c +++ b/ase/awk/run.c @@ -1,5 +1,5 @@ /* - * $Id: run.c,v 1.148 2006-08-01 04:40:14 bacon Exp $ + * $Id: run.c,v 1.149 2006-08-01 15:57:43 bacon Exp $ */ #include @@ -528,6 +528,7 @@ xp_printf (XP_T("-[END VARIABLES]--------------------------\n")); static int __run_pattern_blocks (xp_awk_run_t* run) { xp_ssize_t n; + xp_bool_t need_to_close = xp_false; int errnum; run->inrec.buf_pos = 0; @@ -549,6 +550,7 @@ static int __run_pattern_blocks (xp_awk_run_t* run) return -1; } + need_to_close = xp_true; if (x == 0) break; /* end of input */ if (__run_pattern_block_chain (run, run->awk->tree.chain) == -1) @@ -565,13 +567,16 @@ static int __run_pattern_blocks (xp_awk_run_t* run) * pattern-block loop, which is totally different from getline. * So it just returns -1 as long as closeextio returns -1 regardless * of the value of errnum */ - n = xp_awk_closeextio (run, XP_T(""), &errnum); - if (n == -1) + if (need_to_close) { - if (errnum == XP_AWK_ENOERR) - PANIC_I (run, XP_AWK_ETXTINCLOSE); - else - PANIC_I (run, errnum); + n = xp_awk_closeextio (run, XP_T(""), &errnum); + if (n == -1) + { + if (errnum == XP_AWK_ENOERR) + PANIC_I (run, XP_AWK_ETXTINCLOSE); + else + PANIC_I (run, errnum); + } } return 0; @@ -2824,6 +2829,7 @@ static xp_awk_val_t* __eval_binop_ma ( if (lv == XP_NULL) return XP_NULL; xp_awk_refupval (lv); + rv = __eval_expression0 (run, right); if (rv == XP_NULL) { @@ -2853,6 +2859,7 @@ static xp_awk_val_t* __eval_binop_nm ( if (lv == XP_NULL) return XP_NULL; xp_awk_refupval (lv); + rv = __eval_expression0 (run, right); if (rv == XP_NULL) { diff --git a/ase/test/awk/t20.awk b/ase/test/awk/t20.awk index ccede072..41df5047 100644 --- a/ase/test/awk/t20.awk +++ b/ase/test/awk/t20.awk @@ -2,7 +2,7 @@ /a\/b/ { print $0 ~ /abc/; print $0 !~ /abc/; - print $0 ~ "abc[[:space]]"; + print $0 ~ "abc[[:space:]]"; print $0 !~ "abc"; print /abc/; } diff --git a/ase/test/awk/t21.awk b/ase/test/awk/t21.awk new file mode 100644 index 00000000..f84643e9 --- /dev/null +++ b/ase/test/awk/t21.awk @@ -0,0 +1,7 @@ +BEGIN { exit 10; } + +{ + print $0; +} + +END { print "== END OF PROGRAM =="; } diff --git a/ase/test/awk/t22.awk b/ase/test/awk/t22.awk new file mode 100644 index 00000000..4a6242d3 --- /dev/null +++ b/ase/test/awk/t22.awk @@ -0,0 +1,15 @@ +//BEGIN { exit 10; } + +//{ while (1) {if (x == 20) continue; if (a) break; while (10) break; }} +//END { while (1) {if (x == 20) continue; if (a) break; while (10) break; }} + +{ + //return 20; + + print getline abc < ""; + print "[[" abc "]]"; + print close(""); + //exit 20; +} + +END { print "end";