Added QSE_AWK_TOLERANT

This commit is contained in:
hyung-hwan 2012-08-17 06:53:17 +00:00
parent ec5537a35f
commit 8f1e15366d
10 changed files with 582 additions and 175 deletions

View File

@ -421,6 +421,7 @@ struct opttab_t
{ QSE_T("ncmponstr"), QSE_AWK_NCMPONSTR, QSE_T("perform numeric comparsion on numeric strings") }, { QSE_T("ncmponstr"), QSE_AWK_NCMPONSTR, QSE_T("perform numeric comparsion on numeric strings") },
{ QSE_T("strictnaming"), QSE_AWK_STRICTNAMING, QSE_T("enable the strict naming rule") }, { QSE_T("strictnaming"), QSE_AWK_STRICTNAMING, QSE_T("enable the strict naming rule") },
{ QSE_T("include"), QSE_AWK_INCLUDE, QSE_T("enable 'include'") }, { QSE_T("include"), QSE_AWK_INCLUDE, QSE_T("enable 'include'") },
{ QSE_T("tolerant"), QSE_AWK_TOLERANT, QSE_T("make more I/O fault-tolerant") },
{ QSE_NULL, 0, QSE_NULL } { QSE_NULL, 0, QSE_NULL }
}; };
@ -479,6 +480,7 @@ static int comparg (int argc, qse_char_t* argv[], struct arg_t* arg)
{ QSE_T(":ncmponstr"), QSE_T('\0') }, { QSE_T(":ncmponstr"), QSE_T('\0') },
{ QSE_T(":strictnaming"), QSE_T('\0') }, { QSE_T(":strictnaming"), QSE_T('\0') },
{ QSE_T(":include"), QSE_T('\0') }, { QSE_T(":include"), QSE_T('\0') },
{ QSE_T(":tolerant"), QSE_T('\0') },
{ QSE_T(":call"), QSE_T('c') }, { QSE_T(":call"), QSE_T('c') },
{ QSE_T(":file"), QSE_T('f') }, { QSE_T(":file"), QSE_T('f') },

View File

@ -4,8 +4,10 @@
- @ref awk_intro "INTRODUCTION" - @ref awk_intro "INTRODUCTION"
- @ref awk_lang "AWK LANGUAGE" - @ref awk_lang "AWK LANGUAGE"
- @ref awk_ext "AWK LANGUAGE EXTENSIONS" - @ref awk_ext "AWK LANGUAGE EXTENSIONS"
- @ref awk_ext_vardecl " VARIABLE DECLARATION" - @ref awk_ext_vardecl "VARIABLE DECLARATION"
- @ref awk_ext_include "INCLUDE" - @ref awk_ext_include "INCLUDE"
- @ref awk_ext_print "EXTENDED PRINT/PRINTF"
- @ref awk_ext_exprgroup "GROUPED EXPRESSION"
- @ref awk_ext_rwpipe "TWO-WAY PIPE" - @ref awk_ext_rwpipe "TWO-WAY PIPE"
- @ref awk_ext_return "RETURN" - @ref awk_ext_return "RETURN"
- @ref awk_ext_comment "COMMENT" - @ref awk_ext_comment "COMMENT"
@ -289,6 +291,51 @@ blocks appear. To use \@include, you must turn on #QSE_AWK_INCLUDE.
BEGIN { func_in_abc (); } BEGIN { func_in_abc (); }
@endcode @endcode
@subsection awk_ext_print EXTENDED PRINT/PRINTF
When #QSE_AWK_TOLERANT is on, print and printf are treated as if
they are function calls. In this mode, they return a negative number
on failure and a zero on success and any I/O failure doesn't abort
a running program.
@code
BEGIN {
a = print "hello, world" > "/dev/null";
print a;
a = print ("hello, world") > "/dev/null";
print a;
}
@endcode
Since print and printf are like function calls, you can use them
in any context where a normal expression is allowed. For example,
printf is used as a conditional expression in an 'if' statement
in the sample code below.
@code
BEGIN {
if ((printf "hello, world\n" || "tcp://127.0.0.1:9999") <= -1)
print "FAILURE";
else
print "SUCCESS";
}
@endcode
@subsection awk_ext_exprgroup GROUPED EXPRESSION
When #QSE_AWK_TOLERANT is on, you can use a grouped expression without
the 'in' operator. A grouped expression is a parentheses-enclosed list
of expressions separated with a comma. Each expression in the group is
evaluated in the appearing order. The evaluation result of the last
expression in the group is returned as that of the group.
@code
BEGIN {
c = (1, 2, 9);
a=((1*c, 3*c), (3 - c), ((k = 6+(c+1, c+2)), (-7 * c)));
print c; # 9;
print a; # -63
print k; # 17
}
@endcode
@subsection awk_ext_rwpipe TWO-WAY PIPE @subsection awk_ext_rwpipe TWO-WAY PIPE
The two-way pipe indicated by @b || is supproted, in addition to the one-way The two-way pipe indicated by @b || is supproted, in addition to the one-way
@ -352,6 +399,77 @@ BEGIN {
} }
@endcode @endcode
Here is a more interesting example adopting Michael Sanders'
AWK web server, modified for QSEAWK.
@code
#
# Michael Sanders' AWK web server for QSEAWK.
# Orginal code in http://awk.info/?tools/server
#
# qseawk --tolerant=on --rwpipe=on webserver.awk
#
BEGIN {
x = 1 # script exits if x < 1
port = 8080 # port number
host = "tcpd://0.0.0.0:" port # host string
url = "http://localhost:" port # server url
status = 200 # 200 == OK
reason = "OK" # server response
RS = ORS = "\r\n" # header line terminators
doc = Setup() # html document
len = length(doc) + length(ORS) # length of document
while (x) {
if ($1 == "GET") RunApp(substr($2, 2))
if (! x) break
print "HTTP/1.0", status, reason || host
print "Connection: Close" || host
print "Pragma: no-cache" || host
print "Content-length:", len || host
print ORS doc || host
close(host) # close client connection
host || getline # wait for new client request
}
# server terminated...
doc = Bye()
len = length(doc) + length(ORS)
print "HTTP/1.0", status, reason || host
print "Connection: Close" || host
print "Pragma: no-cache" || host
print "Content-length:", len || host
print ORS doc || host
close(host)
}
function Setup() {
tmp = "<html>\
<head><title>Simple gawk server</title></head>\
<body>\
<p><a href=" url "/xterm>xterm</a>\
<p><a href=" url "/xcalc>xcalc</a>\
<p><a href=" url "/xload>xload</a>\
<p><a href=" url "/exit>terminate script</a>\
</body>\
</html>"
return tmp
}
function Bye() {
tmp = "<html>\
<head><title>Simple gawk server</title></head>\
<body><p>Script Terminated...</body>\
</html>"
return tmp
}
function RunApp(app) {
if (app == "xterm") {system("xterm&"); return}
if (app == "xcalc" ) {system("xcalc&"); return}
if (app == "xload" ) {system("xload&"); return}
if (app == "exit") {x = 0}
}
@endcode
@subsection awk_ext_return RETURN @subsection awk_ext_return RETURN
The return statement is valid in pattern-action blocks as well as in functions. The execution of a calling block is aborted once the return statement is executed. The return statement is valid in pattern-action blocks as well as in functions. The execution of a calling block is aborted once the return statement is executed.
@ -515,4 +633,5 @@ PEER: ?好!
Note that 你 has been converted to a question mark since the letter is Note that 你 has been converted to a question mark since the letter is
not supported by cp949. not supported by cp949.
*/ */

View File

@ -301,8 +301,6 @@ enum qse_awk_nde_type_t
QSE_AWK_NDE_NEXTFILE, QSE_AWK_NDE_NEXTFILE,
QSE_AWK_NDE_DELETE, QSE_AWK_NDE_DELETE,
QSE_AWK_NDE_RESET, QSE_AWK_NDE_RESET,
QSE_AWK_NDE_PRINT,
QSE_AWK_NDE_PRINTF,
/* expression */ /* expression */
/* if you change the following values including their order, /* if you change the following values including their order,
@ -336,7 +334,9 @@ enum qse_awk_nde_type_t
QSE_AWK_NDE_POS, QSE_AWK_NDE_POS,
/* ---------------------------------- */ /* ---------------------------------- */
QSE_AWK_NDE_GETLINE QSE_AWK_NDE_GETLINE,
QSE_AWK_NDE_PRINT,
QSE_AWK_NDE_PRINTF
}; };
typedef enum qse_awk_nde_type_t qse_awk_nde_type_t; typedef enum qse_awk_nde_type_t qse_awk_nde_type_t;
@ -835,6 +835,19 @@ enum qse_awk_option_t
*/ */
QSE_AWK_INCLUDE = (1 << 16), QSE_AWK_INCLUDE = (1 << 16),
/**
* makes AWK more fault-tolerant.
* - prevents termination due to print and printf failure.
* - achieves this by handling print and printf as if
* they are functions like getline.
* - allows an expression group in a normal context
* without the 'in' operator. the evaluation result
* of the last expression is returned as that of
* the expression group.
* - e.g.) a = (1, 3 * 3, 4, 5 + 1); # a is assigned 6.
*/
QSE_AWK_TOLERANT = (1 << 17),
/** /**
* makes #qse_awk_t to behave compatibly with classical AWK * makes #qse_awk_t to behave compatibly with classical AWK
* implementations * implementations

View File

@ -311,7 +311,7 @@ static global_t gtab[] =
{ QSE_T("OFILENAME"), 9, QSE_AWK_PABLOCK | QSE_AWK_NEXTOFILE }, { QSE_T("OFILENAME"), 9, QSE_AWK_PABLOCK | QSE_AWK_NEXTOFILE },
/* output real-to-str conversion format for 'print' */ /* output real-to-str conversion format for 'print' */
{ QSE_T("OFMT"), 4, QSE_AWK_RIO}, { QSE_T("OFMT"), 4, QSE_AWK_RIO },
/* output field separator for 'print' */ /* output field separator for 'print' */
{ QSE_T("OFS"), 3, QSE_AWK_RIO }, { QSE_T("OFS"), 3, QSE_AWK_RIO },
@ -2727,6 +2727,16 @@ static qse_awk_nde_t* parse_print (
qse_awk_nde_t* args_tail; qse_awk_nde_t* args_tail;
qse_awk_nde_t* tail_prev; qse_awk_nde_t* tail_prev;
/* print and printf provide weird syntaxs.
*
* 1. print 10, 20;
* 2. print (10, 20);
* 3. print (10,20,30) in a;
* 4. print ((10,20,30) in a);
*
* Due the case 3, i can't consume LPAREN
* here and expect RPAREN later.
*/
{ {
qse_awk_loc_t eloc = awk->tok.loc; qse_awk_loc_t eloc = awk->tok.loc;
args = parse_expr_dc (awk, &eloc); args = parse_expr_dc (awk, &eloc);
@ -2977,7 +2987,11 @@ static qse_awk_nde_t* parse_statement_nb (
if (get_token(awk) <= -1) return QSE_NULL; if (get_token(awk) <= -1) return QSE_NULL;
nde = parse_reset (awk, xloc); nde = parse_reset (awk, xloc);
} }
else if (MATCH(awk,TOK_PRINT)) else if (!(awk->option & QSE_AWK_TOLERANT))
{
/* in the non-tolerant mode, we treat print and printf
* as a separate statement */
if (MATCH(awk,TOK_PRINT))
{ {
if (get_token(awk) <= -1) return QSE_NULL; if (get_token(awk) <= -1) return QSE_NULL;
nde = parse_print (awk, xloc, QSE_AWK_NDE_PRINT); nde = parse_print (awk, xloc, QSE_AWK_NDE_PRINT);
@ -2987,6 +3001,8 @@ static qse_awk_nde_t* parse_statement_nb (
if (get_token(awk) <= -1) return QSE_NULL; if (get_token(awk) <= -1) return QSE_NULL;
nde = parse_print (awk, xloc, QSE_AWK_NDE_PRINTF); nde = parse_print (awk, xloc, QSE_AWK_NDE_PRINTF);
} }
else nde = parse_expr_dc (awk, xloc);
}
else else
{ {
nde = parse_expr_dc (awk, xloc); nde = parse_expr_dc (awk, xloc);
@ -3860,6 +3876,8 @@ static qse_awk_nde_t* parse_concat (
MATCH(awk,TOK_PLUSPLUS) || MATCH(awk,TOK_PLUSPLUS) ||
MATCH(awk,TOK_MINUSMINUS) || MATCH(awk,TOK_MINUSMINUS) ||
MATCH(awk,TOK_LNOT) || MATCH(awk,TOK_LNOT) ||
((awk->option & QSE_AWK_TOLERANT) &&
(awk->tok.type == TOK_PRINT || awk->tok.type == TOK_PRINTF)) ||
awk->tok.type >= TOK_GETLINE) awk->tok.type >= TOK_GETLINE)
{ {
/* TODO: is the check above sufficient? */ /* TODO: is the check above sufficient? */
@ -4514,9 +4532,9 @@ static qse_awk_nde_t* parse_primary_nogetline (
} }
/* check if it is a chained node */ /* check if it is a chained node */
if (nde->next != QSE_NULL) if (nde->next)
{ {
/* if so, it is a expression group */ /* if so, it is an expression group */
/* (expr1, expr2, expr2) */ /* (expr1, expr2, expr2) */
qse_awk_nde_grp_t* tmp; qse_awk_nde_grp_t* tmp;
@ -4525,7 +4543,8 @@ static qse_awk_nde_t* parse_primary_nogetline (
awk->parse.id.stmt != TOK_PRINTF) || awk->parse.id.stmt != TOK_PRINTF) ||
awk->parse.depth.cur.expr != 1) awk->parse.depth.cur.expr != 1)
{ {
if (!MATCH(awk,TOK_IN)) if (!(awk->option & QSE_AWK_TOLERANT) &&
!MATCH(awk,TOK_IN))
{ {
qse_awk_clrpt (awk, nde); qse_awk_clrpt (awk, nde);
SETERR_TOK (awk, QSE_AWK_EKWIN); SETERR_TOK (awk, QSE_AWK_EKWIN);
@ -4611,6 +4630,21 @@ static qse_awk_nde_t* parse_primary_nogetline (
return (qse_awk_nde_t*)nde; return (qse_awk_nde_t*)nde;
} }
else if (awk->option & QSE_AWK_TOLERANT)
{
/* in the tolerant mode, we treat print and printf
* as a function like getline */
if (MATCH(awk,TOK_PRINT))
{
if (get_token(awk) <= -1) return QSE_NULL;
return parse_print (awk, xloc, QSE_AWK_NDE_PRINT);
}
else if (MATCH(awk,TOK_PRINTF))
{
if (get_token(awk) <= -1) return QSE_NULL;
return parse_print (awk, xloc, QSE_AWK_NDE_PRINTF);
}
}
/* valid expression introducer is expected */ /* valid expression introducer is expected */
if (MATCH(awk,TOK_NEWLINE)) if (MATCH(awk,TOK_NEWLINE))

View File

@ -25,6 +25,8 @@
#include <qse/cmn/stdio.h> #include <qse/cmn/stdio.h>
#endif #endif
#define PRINT_IOERR -99
#define CMP_ERROR -99 #define CMP_ERROR -99
#define DEF_BUF_CAPA 256 #define DEF_BUF_CAPA 256
#define STACK_INCREMENT 512 #define STACK_INCREMENT 512
@ -242,6 +244,8 @@ static qse_awk_val_t* eval_lclidx (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_argidx (qse_awk_rtx_t* run, qse_awk_nde_t* nde); static qse_awk_val_t* eval_argidx (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_pos (qse_awk_rtx_t* run, qse_awk_nde_t* nde); static qse_awk_val_t* eval_pos (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_getline (qse_awk_rtx_t* run, qse_awk_nde_t* nde); static qse_awk_val_t* eval_getline (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_print (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static qse_awk_val_t* eval_printf (qse_awk_rtx_t* run, qse_awk_nde_t* nde);
static int __raw_push (qse_awk_rtx_t* run, void* val); static int __raw_push (qse_awk_rtx_t* run, void* val);
#define __raw_pop(run) \ #define __raw_pop(run) \
@ -1830,138 +1834,96 @@ static int run_block0 (qse_awk_rtx_t* rtx, qse_awk_nde_blk_t* nde)
static int run_statement (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde) static int run_statement (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde)
{ {
int xret;
qse_awk_val_t* tmp;
ON_STATEMENT (rtx, nde); ON_STATEMENT (rtx, nde);
switch (nde->type) switch (nde->type)
{ {
case QSE_AWK_NDE_NULL: case QSE_AWK_NDE_NULL:
{
/* do nothing */ /* do nothing */
xret = 0;
break; break;
}
case QSE_AWK_NDE_BLK: case QSE_AWK_NDE_BLK:
{ xret = run_block (rtx, (qse_awk_nde_blk_t*)nde);
if (run_block (rtx,
(qse_awk_nde_blk_t*)nde) == -1) return -1;
break; break;
}
case QSE_AWK_NDE_IF: case QSE_AWK_NDE_IF:
{ xret = run_if (rtx, (qse_awk_nde_if_t*)nde);
if (run_if (rtx,
(qse_awk_nde_if_t*)nde) == -1) return -1;
break; break;
}
case QSE_AWK_NDE_WHILE: case QSE_AWK_NDE_WHILE:
case QSE_AWK_NDE_DOWHILE: case QSE_AWK_NDE_DOWHILE:
{ xret = run_while (rtx, (qse_awk_nde_while_t*)nde);
if (run_while (rtx,
(qse_awk_nde_while_t*)nde) == -1) return -1;
break; break;
}
case QSE_AWK_NDE_FOR: case QSE_AWK_NDE_FOR:
{ xret = run_for (rtx, (qse_awk_nde_for_t*)nde);
if (run_for (rtx,
(qse_awk_nde_for_t*)nde) == -1) return -1;
break; break;
}
case QSE_AWK_NDE_FOREACH: case QSE_AWK_NDE_FOREACH:
{ xret = run_foreach (rtx, (qse_awk_nde_foreach_t*)nde);
if (run_foreach (rtx,
(qse_awk_nde_foreach_t*)nde) == -1) return -1;
break; break;
}
case QSE_AWK_NDE_BREAK: case QSE_AWK_NDE_BREAK:
{ xret = run_break (rtx, (qse_awk_nde_break_t*)nde);
if (run_break (rtx,
(qse_awk_nde_break_t*)nde) == -1) return -1;
break; break;
}
case QSE_AWK_NDE_CONTINUE: case QSE_AWK_NDE_CONTINUE:
{ xret = run_continue (rtx, (qse_awk_nde_continue_t*)nde);
if (run_continue (rtx,
(qse_awk_nde_continue_t*)nde) == -1) return -1;
break; break;
}
case QSE_AWK_NDE_RETURN: case QSE_AWK_NDE_RETURN:
{ xret = run_return (rtx, (qse_awk_nde_return_t*)nde);
if (run_return (rtx,
(qse_awk_nde_return_t*)nde) == -1) return -1;
break; break;
}
case QSE_AWK_NDE_EXIT: case QSE_AWK_NDE_EXIT:
{ xret = run_exit (rtx, (qse_awk_nde_exit_t*)nde);
if (run_exit (rtx,
(qse_awk_nde_exit_t*)nde) == -1) return -1;
break; break;
}
case QSE_AWK_NDE_NEXT: case QSE_AWK_NDE_NEXT:
{ xret = run_next (rtx, (qse_awk_nde_next_t*)nde);
if (run_next (rtx,
(qse_awk_nde_next_t*)nde) == -1) return -1;
break; break;
}
case QSE_AWK_NDE_NEXTFILE: case QSE_AWK_NDE_NEXTFILE:
{ xret = run_nextfile (rtx, (qse_awk_nde_nextfile_t*)nde);
if (run_nextfile (rtx,
(qse_awk_nde_nextfile_t*)nde) == -1) return -1;
break; break;
}
case QSE_AWK_NDE_DELETE: case QSE_AWK_NDE_DELETE:
{ xret = run_delete (rtx, (qse_awk_nde_delete_t*)nde);
if (run_delete (rtx,
(qse_awk_nde_delete_t*)nde) == -1) return -1;
break; break;
}
case QSE_AWK_NDE_RESET: case QSE_AWK_NDE_RESET:
{ xret = run_reset (rtx, (qse_awk_nde_reset_t*)nde);
if (run_reset (rtx,
(qse_awk_nde_reset_t*)nde) == -1) return -1;
break; break;
}
case QSE_AWK_NDE_PRINT: case QSE_AWK_NDE_PRINT:
{ if (rtx->awk->option & QSE_AWK_TOLERANT) goto __fallback__;
if (run_print (rtx, xret = run_print (rtx, (qse_awk_nde_print_t*)nde);
(qse_awk_nde_print_t*)nde) == -1) return -1;
break; break;
}
case QSE_AWK_NDE_PRINTF: case QSE_AWK_NDE_PRINTF:
{ if (rtx->awk->option & QSE_AWK_TOLERANT) goto __fallback__;
if (run_printf (rtx, xret = run_printf (rtx, (qse_awk_nde_print_t*)nde);
(qse_awk_nde_print_t*)nde) == -1) return -1;
break; break;
}
default: default:
__fallback__:
tmp = eval_expression (rtx, nde);
if (tmp == QSE_NULL) xret = -1;
else
{ {
qse_awk_val_t* v;
v = eval_expression (rtx, nde);
if (v == QSE_NULL) return -1;
/* destroy the value if not referenced */ /* destroy the value if not referenced */
qse_awk_rtx_refupval (rtx, v); qse_awk_rtx_refupval (rtx, tmp);
qse_awk_rtx_refdownval (rtx, v); qse_awk_rtx_refdownval (rtx, tmp);
xret = 1;
}
break; break;
} }
}
return 0; return xret;
} }
static int run_if (qse_awk_rtx_t* rtx, qse_awk_nde_if_t* nde) static int run_if (qse_awk_rtx_t* rtx, qse_awk_nde_if_t* nde)
@ -2738,7 +2700,7 @@ static int run_print (qse_awk_rtx_t* rtx, qse_awk_nde_print_t* nde)
qse_char_t* out = QSE_NULL; qse_char_t* out = QSE_NULL;
const qse_char_t* dst; const qse_char_t* dst;
qse_awk_val_t* v; qse_awk_val_t* v;
int n; int n, xret = 0;
QSE_ASSERT ( QSE_ASSERT (
(nde->out_type == QSE_AWK_OUT_PIPE && nde->out != QSE_NULL) || (nde->out_type == QSE_AWK_OUT_PIPE && nde->out != QSE_NULL) ||
@ -2812,12 +2774,19 @@ static int run_print (qse_awk_rtx_t* rtx, qse_awk_nde_print_t* nde)
QSE_STR_PTR(&rtx->inrec.line), QSE_STR_PTR(&rtx->inrec.line),
QSE_STR_LEN(&rtx->inrec.line)); QSE_STR_LEN(&rtx->inrec.line));
if (n <= -1 /*&& rtx->errinf.num != QSE_AWK_EIOIMPL*/) if (n <= -1 /*&& rtx->errinf.num != QSE_AWK_EIOIMPL*/)
{
if (rtx->awk->option & QSE_AWK_TOLERANT)
{
xret = PRINT_IOERR;
}
else
{ {
if (out) QSE_AWK_FREE (rtx->awk, out); if (out) QSE_AWK_FREE (rtx->awk, out);
ADJERR_LOC (rtx, &nde->loc); ADJERR_LOC (rtx, &nde->loc);
return -1; return -1;
} }
} }
}
else else
{ {
/* if it has any arguments, print the arguments separated by /* if it has any arguments, print the arguments separated by
@ -2841,12 +2810,19 @@ static int run_print (qse_awk_rtx_t* rtx, qse_awk_nde_print_t* nde)
rtx->gbl.ofs.ptr, rtx->gbl.ofs.ptr,
rtx->gbl.ofs.len); rtx->gbl.ofs.len);
if (n <= -1 /*&& rtx->errinf.num != QSE_AWK_EIOIMPL*/) if (n <= -1 /*&& rtx->errinf.num != QSE_AWK_EIOIMPL*/)
{
if (rtx->awk->option & QSE_AWK_TOLERANT)
{
xret = PRINT_IOERR;
}
else
{ {
if (out) QSE_AWK_FREE (rtx->awk, out); if (out) QSE_AWK_FREE (rtx->awk, out);
ADJERR_LOC (rtx, &nde->loc); ADJERR_LOC (rtx, &nde->loc);
return -1; return -1;
} }
} }
}
v = eval_expression (rtx, np); v = eval_expression (rtx, np);
if (v == QSE_NULL) if (v == QSE_NULL)
@ -2859,12 +2835,19 @@ static int run_print (qse_awk_rtx_t* rtx, qse_awk_nde_print_t* nde)
n = qse_awk_rtx_writeio_val ( n = qse_awk_rtx_writeio_val (
rtx, nde->out_type, dst, v); rtx, nde->out_type, dst, v);
if (n <= -1 /*&& rtx->errinf.num != QSE_AWK_EIOIMPL*/) if (n <= -1 /*&& rtx->errinf.num != QSE_AWK_EIOIMPL*/)
{
if (rtx->awk->option & QSE_AWK_TOLERANT)
{
xret = PRINT_IOERR;
}
else
{ {
if (out) QSE_AWK_FREE (rtx->awk, out); if (out) QSE_AWK_FREE (rtx->awk, out);
qse_awk_rtx_refdownval (rtx, v); qse_awk_rtx_refdownval (rtx, v);
ADJERR_LOC (rtx, &nde->loc); ADJERR_LOC (rtx, &nde->loc);
return -1; return -1;
} }
}
qse_awk_rtx_refdownval (rtx, v); qse_awk_rtx_refdownval (rtx, v);
} }
@ -2875,11 +2858,18 @@ static int run_print (qse_awk_rtx_t* rtx, qse_awk_nde_print_t* nde)
rtx, nde->out_type, dst, rtx, nde->out_type, dst,
rtx->gbl.ors.ptr, rtx->gbl.ors.len); rtx->gbl.ors.ptr, rtx->gbl.ors.len);
if (n <= -1 /*&& rtx->errinf.num != QSE_AWK_EIOIMPL*/) if (n <= -1 /*&& rtx->errinf.num != QSE_AWK_EIOIMPL*/)
{
if (rtx->awk->option & QSE_AWK_TOLERANT)
{
xret = PRINT_IOERR;
}
else
{ {
if (out) QSE_AWK_FREE (rtx->awk, out); if (out) QSE_AWK_FREE (rtx->awk, out);
ADJERR_LOC (rtx, &nde->loc); ADJERR_LOC (rtx, &nde->loc);
return -1; return -1;
} }
}
/* unlike printf, flushio() is not needed here as print /* unlike printf, flushio() is not needed here as print
* inserts <NL> that triggers auto-flush */ * inserts <NL> that triggers auto-flush */
@ -2887,7 +2877,7 @@ static int run_print (qse_awk_rtx_t* rtx, qse_awk_nde_print_t* nde)
if (out) QSE_AWK_FREE (rtx->awk, out); if (out) QSE_AWK_FREE (rtx->awk, out);
/*skip_write:*/ /*skip_write:*/
return 0; return xret;
} }
static int run_printf (qse_awk_rtx_t* rtx, qse_awk_nde_print_t* nde) static int run_printf (qse_awk_rtx_t* rtx, qse_awk_nde_print_t* nde)
@ -2896,7 +2886,7 @@ static int run_printf (qse_awk_rtx_t* rtx, qse_awk_nde_print_t* nde)
const qse_char_t* dst; const qse_char_t* dst;
qse_awk_val_t* v; qse_awk_val_t* v;
qse_awk_nde_t* head; qse_awk_nde_t* head;
int n; int n, xret = 0;
QSE_ASSERT ( QSE_ASSERT (
(nde->out_type == QSE_AWK_OUT_PIPE && nde->out != QSE_NULL) || (nde->out_type == QSE_AWK_OUT_PIPE && nde->out != QSE_NULL) ||
@ -2957,7 +2947,7 @@ static int run_printf (qse_awk_rtx_t* rtx, qse_awk_nde_print_t* nde)
dst = (out == QSE_NULL)? QSE_T(""): out; dst = (out == QSE_NULL)? QSE_T(""): out;
QSE_ASSERTX (nde->args != QSE_NULL, QSE_ASSERTX (nde->args != QSE_NULL,
"a valid printf statement should have at least one argument. the parser must ensure this."); "valid printf statement should have at least one argument. the parser must ensure this.");
if (nde->args->type == QSE_AWK_NDE_GRP) if (nde->args->type == QSE_AWK_NDE_GRP)
{ {
@ -2968,7 +2958,7 @@ static int run_printf (qse_awk_rtx_t* rtx, qse_awk_nde_print_t* nde)
else head = nde->args; else head = nde->args;
QSE_ASSERTX (head != QSE_NULL, QSE_ASSERTX (head != QSE_NULL,
"a valid printf statement should have at least one argument. the parser must ensure this."); "valid printf statement should have at least one argument. the parser must ensure this.");
v = eval_expression (rtx, head); v = eval_expression (rtx, head);
if (v == QSE_NULL) if (v == QSE_NULL)
@ -2984,6 +2974,12 @@ static int run_printf (qse_awk_rtx_t* rtx, qse_awk_nde_print_t* nde)
* contain any % characters */ * contain any % characters */
n = qse_awk_rtx_writeio_val (rtx, nde->out_type, dst, v); n = qse_awk_rtx_writeio_val (rtx, nde->out_type, dst, v);
if (n <= -1 /*&& rtx->errinf.num != QSE_AWK_EIOIMPL*/) if (n <= -1 /*&& rtx->errinf.num != QSE_AWK_EIOIMPL*/)
{
if (rtx->awk->option & QSE_AWK_TOLERANT)
{
xret = PRINT_IOERR;
}
else
{ {
if (out != QSE_NULL) QSE_AWK_FREE (rtx->awk, out); if (out != QSE_NULL) QSE_AWK_FREE (rtx->awk, out);
qse_awk_rtx_refdownval (rtx, v); qse_awk_rtx_refdownval (rtx, v);
@ -2991,14 +2987,19 @@ static int run_printf (qse_awk_rtx_t* rtx, qse_awk_nde_print_t* nde)
return -1; return -1;
} }
} }
}
else else
{ {
/* perform the formatted output */ /* perform the formatted output */
if (output_formatted ( n = output_formatted (
rtx, nde->out_type, dst, rtx, nde->out_type, dst,
((qse_awk_val_str_t*)v)->val.ptr, ((qse_awk_val_str_t*)v)->val.ptr,
((qse_awk_val_str_t*)v)->val.len, ((qse_awk_val_str_t*)v)->val.len,
head->next) == -1) head->next);
if (n <= -1)
{
if (n == PRINT_IOERR) xret = n;
else
{ {
if (out != QSE_NULL) QSE_AWK_FREE (rtx->awk, out); if (out != QSE_NULL) QSE_AWK_FREE (rtx->awk, out);
qse_awk_rtx_refdownval (rtx, v); qse_awk_rtx_refdownval (rtx, v);
@ -3006,15 +3007,26 @@ static int run_printf (qse_awk_rtx_t* rtx, qse_awk_nde_print_t* nde)
return -1; return -1;
} }
} }
}
qse_awk_rtx_refdownval (rtx, v); qse_awk_rtx_refdownval (rtx, v);
/*skip_write:*/ /*skip_write:*/
n = qse_awk_rtx_flushio (rtx, nde->out_type, dst); if (qse_awk_rtx_flushio (rtx, nde->out_type, dst) <= -1)
{
if (rtx->awk->option & QSE_AWK_TOLERANT)
{
xret = PRINT_IOERR;
}
else
{
if (out != QSE_NULL) QSE_AWK_FREE (rtx->awk, out);
return -1;
}
}
if (out != QSE_NULL) QSE_AWK_FREE (rtx->awk, out); if (out != QSE_NULL) QSE_AWK_FREE (rtx->awk, out);
return xret;
return n;
} }
static int output_formatted ( static int output_formatted (
@ -3030,7 +3042,17 @@ static int output_formatted (
if (ptr == QSE_NULL) return -1; if (ptr == QSE_NULL) return -1;
n = qse_awk_rtx_writeio_str (rtx, out_type, dst, ptr, len); n = qse_awk_rtx_writeio_str (rtx, out_type, dst, ptr, len);
if (n <= -1 /*&& rtx->errinf.num != QSE_AWK_EIOIMPL*/) return -1; if (n <= -1 /*&& rtx->errinf.num != QSE_AWK_EIOIMPL*/)
{
if (rtx->awk->option & QSE_AWK_TOLERANT)
{
return PRINT_IOERR;
}
else
{
return -1;
}
}
return 0; return 0;
} }
@ -3145,7 +3167,9 @@ static qse_awk_val_t* eval_expression0 (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
eval_lclidx, eval_lclidx,
eval_argidx, eval_argidx,
eval_pos, eval_pos,
eval_getline eval_getline,
eval_print,
eval_printf
}; };
qse_awk_val_t* v; qse_awk_val_t* v;
@ -3173,11 +3197,44 @@ static qse_awk_val_t* eval_expression0 (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
static qse_awk_val_t* eval_group (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde) static qse_awk_val_t* eval_group (qse_awk_rtx_t* rtx, qse_awk_nde_t* nde)
{ {
#if 0
/* eval_binop_in evaluates the QSE_AWK_NDE_GRP specially. /* eval_binop_in evaluates the QSE_AWK_NDE_GRP specially.
* so this function should never be reached. */ * so this function should never be reached. */
QSE_ASSERT (!"should never happen - NDE_GRP only for in"); QSE_ASSERT (!"should never happen - NDE_GRP only for in");
SETERR_LOC (rtx, QSE_AWK_EINTERN, &nde->loc); SETERR_LOC (rtx, QSE_AWK_EINTERN, &nde->loc);
return QSE_NULL; return QSE_NULL;
#endif
/* a group can be evauluated in a normal context
* if a program is parsed with QSE_AWK_TOLERANT on.
* before the introduction of this option, the grouped
* expression was valid only coerced with the 'in'
* operator.
* */
/* when a group is evaluated in a normal context,
* we return the last expression as a value. */
qse_awk_val_t* val;
qse_awk_nde_t* np;
np = ((qse_awk_nde_grp_t*)nde)->body;
QSE_ASSERT (np != QSE_NULL);
loop:
val = eval_expression (rtx, np);
if (val == QSE_NULL) return QSE_NULL;
np = np->next;
if (np)
{
qse_awk_rtx_refupval (rtx, val);
qse_awk_rtx_refdownval (rtx, val);
goto loop;
}
return val;
} }
static qse_awk_val_t* eval_assignment (qse_awk_rtx_t* run, qse_awk_nde_t* nde) static qse_awk_val_t* eval_assignment (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
@ -6304,6 +6361,22 @@ skip_read:
return res; return res;
} }
static qse_awk_val_t* eval_print (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
int n = run_print (run, (qse_awk_nde_print_t*)nde);
if (n == PRINT_IOERR) n = -1; /* let print return -1 */
else if (n <= -1) return QSE_NULL;
return qse_awk_rtx_makeintval (run, n);
}
static qse_awk_val_t* eval_printf (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
{
int n = run_printf (run, (qse_awk_nde_print_t*)nde);
if (n == PRINT_IOERR) n = -1; /* let print return -1 */
else if (n <= -1) return QSE_NULL;
return qse_awk_rtx_makeintval (run, n);
}
static int __raw_push (qse_awk_rtx_t* run, void* val) static int __raw_push (qse_awk_rtx_t* run, void* val)
{ {
if (run->stack_top >= run->stack_limit) if (run->stack_top >= run->stack_limit)

View File

@ -149,6 +149,38 @@ static int print_tabs (qse_awk_t* awk, int depth)
return 0; return 0;
} }
static int print_printx (qse_awk_t* awk, qse_awk_nde_print_t* px)
{
qse_cstr_t kw;
if (px->type == QSE_AWK_NDE_PRINT)
{
qse_awk_getkwname (awk, QSE_AWK_KWID_PRINT, &kw);
PUT_SRCSTRN (awk, kw.ptr, kw.len);
}
else
{
qse_awk_getkwname (awk, QSE_AWK_KWID_PRINTF, &kw);
PUT_SRCSTRN (awk, kw.ptr, kw.len);
}
if (px->args != QSE_NULL)
{
PUT_SRCSTR (awk, QSE_T(" "));
PRINT_EXPR_LIST (awk, px->args);
}
if (px->out != QSE_NULL)
{
PUT_SRCSTR (awk, QSE_T(" "));
PUT_SRCSTR (awk, print_outop_str[px->out_type]);
PUT_SRCSTR (awk, QSE_T(" "));
PRINT_EXPR (awk, px->out);
}
return 0;
}
static int print_expr (qse_awk_t* awk, qse_awk_nde_t* nde) static int print_expr (qse_awk_t* awk, qse_awk_nde_t* nde)
{ {
qse_cstr_t kw; qse_cstr_t kw;
@ -650,8 +682,18 @@ static int print_expr (qse_awk_t* awk, qse_awk_nde_t* nde)
break; break;
} }
case QSE_AWK_NDE_PRINT:
case QSE_AWK_NDE_PRINTF:
{
PUT_SRCSTR (awk, QSE_T("("));
if (print_printx (awk, (qse_awk_nde_print_t*)nde) <= -1) return -1;
PUT_SRCSTR (awk, QSE_T(")"));
break;
}
default: default:
{ {
qse_awk_seterrnum (awk, QSE_AWK_EINTERN, QSE_NULL);
return -1; return -1;
} }
} }
@ -998,35 +1040,8 @@ static int print_stmt (qse_awk_t* awk, qse_awk_nde_t* p, int depth)
case QSE_AWK_NDE_PRINT: case QSE_AWK_NDE_PRINT:
case QSE_AWK_NDE_PRINTF: case QSE_AWK_NDE_PRINTF:
{ {
qse_awk_nde_print_t* px = (qse_awk_nde_print_t*)p;
PRINT_TABS (awk, depth); PRINT_TABS (awk, depth);
if (print_printx (awk, (qse_awk_nde_print_t*)p) <= -1) return -1;
if (p->type == QSE_AWK_NDE_PRINT)
{
qse_awk_getkwname (awk, QSE_AWK_KWID_PRINT, &kw);
PUT_SRCSTRN (awk, kw.ptr, kw.len);
}
else
{
qse_awk_getkwname (awk, QSE_AWK_KWID_PRINTF, &kw);
PUT_SRCSTRN (awk, kw.ptr, kw.len);
}
if (px->args != QSE_NULL)
{
PUT_SRCSTR (awk, QSE_T(" "));
PRINT_EXPR_LIST (awk, px->args);
}
if (px->out != QSE_NULL)
{
PUT_SRCSTR (awk, QSE_T(" "));
PUT_SRCSTR (awk, print_outop_str[px->out_type]);
PUT_SRCSTR (awk, QSE_T(" "));
PRINT_EXPR (awk, px->out);
}
PUT_SRCSTR (awk, QSE_T(";")); PUT_SRCSTR (awk, QSE_T(";"));
PUT_NL (awk); PUT_NL (awk);
break; break;
@ -1038,6 +1053,7 @@ static int print_stmt (qse_awk_t* awk, qse_awk_nde_t* p, int depth)
PRINT_EXPR (awk, p); PRINT_EXPR (awk, p);
PUT_SRCSTR (awk, QSE_T(";")); PUT_SRCSTR (awk, QSE_T(";"));
PUT_NL (awk); PUT_NL (awk);
break;
} }
} }

View File

@ -0,0 +1,29 @@
BEGIN {
print print print print 10;
print (print 10 > "/tmp/should/not/be/creatable");
if ((print 10 > "/tmp/should/not/be/creatable") <= -1)
print "FAILURE";
else
print "SUCCESS";
print "------------------------------------";
a = 1 (print 10 > "/tmp/should/not/be/creatable");
print a;
print "------------------------------------";
b = ++a print 10;
printf "%d\n", b;
print "------------------------------------";
printf ("%d\n", b + (((print print print 30 + 50)) + 40));
print "------------------------------------";
printf ("%d\n", b + (((print print print 30 50)) + 40));
print "------------------------------------";
$(print 0 > "/dev/null") = "this is wonderful"; print $0;
print "------------------------------------";
$(getline dummy > "/dev/zero") = "that"; print $0;
print "------------------------------------";
x[0]=20; abc=(print ("hello", "world", (1, abc=20, abc=45))) in x; print abc
}

View File

@ -2361,6 +2361,66 @@ nan
2 DDDDDDDDDDDDDDDDDDDDDDDDD 2 DDDDDDDDDDDDDDDDDDDDDDDDD
1 DDDDDDDDDDDDDDDDDDDDDDDDD 1 DDDDDDDDDDDDDDDDDDDDDDDDD
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
[CMD] qseawk --newline=on --tolerant=on -d- -f lang-047.awk </dev/stdin 2>&1
--------------------------------------------------------------------------------
BEGIN {
print (print (print (print 10)));
print (print 10 > "/tmp/should/not/be/creatable");
if (((print 10 > "/tmp/should/not/be/creatable") <= -1))
print "FAILURE";
else
print "SUCCESS";
print "------------------------------------";
a = (1 (print 10 > "/tmp/should/not/be/creatable"));
print a;
print "------------------------------------";
b = (++(a) (print 10));
printf "%d\n",b;
print "------------------------------------";
printf ("%d\n",(b + ((print (print (print 80))) + 40)));
print "------------------------------------";
printf ("%d\n",(b + ((print (print (print (30 50)))) + 40)));
print "------------------------------------";
$(print 0 > "/dev/null") = "this is wonderful";
print $0;
print "------------------------------------";
$((getline dummy) > "/dev/zero") = "that";
print $0;
print "------------------------------------";
x[0] = 20;
abc = ((print ("hello","world",(1,abc = 20,abc = 45))) in x);
print abc;
}
10
0
0
0
-1
FAILURE
------------------------------------
1-1
------------------------------------
10
20
------------------------------------
80
0
0
60
------------------------------------
3050
0
0
60
------------------------------------
this is wonderful
------------------------------------
that is wonderful
------------------------------------
hello world 45
1
--------------------------------------------------------------------------------
[CMD] qseawk --newline=on -F: -f columnate.awk passwd.dat </dev/stdin 2>&1 [CMD] qseawk --newline=on -F: -f columnate.awk passwd.dat </dev/stdin 2>&1
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
root x 0 0 root /root /bin/bash root x 0 0 root /root /bin/bash

View File

@ -2361,6 +2361,66 @@ nan
2 DDDDDDDDDDDDDDDDDDDDDDDDD 2 DDDDDDDDDDDDDDDDDDDDDDDDD
1 DDDDDDDDDDDDDDDDDDDDDDDDD 1 DDDDDDDDDDDDDDDDDDDDDDDDD
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
[CMD] qseawk -m 500000 --newline=on --tolerant=on -d- -f lang-047.awk </dev/stdin 2>&1
--------------------------------------------------------------------------------
BEGIN {
print (print (print (print 10)));
print (print 10 > "/tmp/should/not/be/creatable");
if (((print 10 > "/tmp/should/not/be/creatable") <= -1))
print "FAILURE";
else
print "SUCCESS";
print "------------------------------------";
a = (1 (print 10 > "/tmp/should/not/be/creatable"));
print a;
print "------------------------------------";
b = (++(a) (print 10));
printf "%d\n",b;
print "------------------------------------";
printf ("%d\n",(b + ((print (print (print 80))) + 40)));
print "------------------------------------";
printf ("%d\n",(b + ((print (print (print (30 50)))) + 40)));
print "------------------------------------";
$(print 0 > "/dev/null") = "this is wonderful";
print $0;
print "------------------------------------";
$((getline dummy) > "/dev/zero") = "that";
print $0;
print "------------------------------------";
x[0] = 20;
abc = ((print ("hello","world",(1,abc = 20,abc = 45))) in x);
print abc;
}
10
0
0
0
-1
FAILURE
------------------------------------
1-1
------------------------------------
10
20
------------------------------------
80
0
0
60
------------------------------------
3050
0
0
60
------------------------------------
this is wonderful
------------------------------------
that is wonderful
------------------------------------
hello world 45
1
--------------------------------------------------------------------------------
[CMD] qseawk -m 500000 --newline=on -F: -f columnate.awk passwd.dat </dev/stdin 2>&1 [CMD] qseawk -m 500000 --newline=on -F: -f columnate.awk passwd.dat </dev/stdin 2>&1
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
root x 0 0 root /root /bin/bash root x 0 0 root /root /bin/bash

View File

@ -173,6 +173,7 @@ PROGS="
lang-044.awk!lang-044.dat!!--newline=on -d- lang-044.awk!lang-044.dat!!--newline=on -d-
lang-045.awk!!!--newline=on -d- lang-045.awk!!!--newline=on -d-
lang-046.awk!lang-046.dat2!!--newline=on -d- -vdatadir=@abs_srcdir@ -vdatafile=lang-046.dat1 lang-046.awk!lang-046.dat2!!--newline=on -d- -vdatadir=@abs_srcdir@ -vdatafile=lang-046.dat1
lang-047.awk!!!--newline=on --tolerant=on -d-
columnate.awk!passwd.dat!!--newline=on -F: columnate.awk!passwd.dat!!--newline=on -F:
levenshtein-utests.awk!!!--newline=on --include=on levenshtein-utests.awk!!!--newline=on --include=on