fixed bugs of not handling <NL> properly in local/global variable declarations.

This commit is contained in:
hyung-hwan 2009-06-27 20:50:54 +00:00
parent e337e01d46
commit c31adc3f7c
13 changed files with 162 additions and 28 deletions

View File

@ -1,5 +1,5 @@
/* /*
* $Id: awk.h 213 2009-06-26 13:05:19Z hyunghwan.chung $ * $Id: awk.h 214 2009-06-27 02:50:54Z hyunghwan.chung $
* *
Copyright 2006-2009 Chung, Hyung-Hwan. Copyright 2006-2009 Chung, Hyung-Hwan.
@ -609,6 +609,7 @@ enum qse_awk_errnum_t
QSE_AWK_EDUPLCL, /* duplicate local variable name */ QSE_AWK_EDUPLCL, /* duplicate local variable name */
QSE_AWK_EBADPAR, /* not a valid parameter name */ QSE_AWK_EBADPAR, /* not a valid parameter name */
QSE_AWK_EBADVAR, /* not a valid variable name */ QSE_AWK_EBADVAR, /* not a valid variable name */
QSE_AWK_EVARMS, /* variable name missing */
QSE_AWK_EUNDEF, /* undefined identifier */ QSE_AWK_EUNDEF, /* undefined identifier */
QSE_AWK_ELVALUE, /* l-value required */ QSE_AWK_ELVALUE, /* l-value required */
QSE_AWK_EGBLTM, /* too many global variables */ QSE_AWK_EGBLTM, /* too many global variables */

View File

@ -1,5 +1,5 @@
/* /*
* $Id: err.c 213 2009-06-26 13:05:19Z hyunghwan.chung $ * $Id: err.c 214 2009-06-27 02:50:54Z hyunghwan.chung $
* *
Copyright 2006-2009 Chung, Hyung-Hwan. Copyright 2006-2009 Chung, Hyung-Hwan.
@ -99,6 +99,7 @@ const qse_char_t* qse_awk_dflerrstr (qse_awk_t* awk, qse_awk_errnum_t errnum)
QSE_T("duplicate local variable '${0}'"), QSE_T("duplicate local variable '${0}'"),
QSE_T("'${0}' not a valid parameter name"), QSE_T("'${0}' not a valid parameter name"),
QSE_T("'${0}' not a valid variable name"), QSE_T("'${0}' not a valid variable name"),
QSE_T("variable name missing"),
QSE_T("undefined identifier '${0}'"), QSE_T("undefined identifier '${0}'"),
QSE_T("l-value required"), QSE_T("l-value required"),
QSE_T("too many global variables"), QSE_T("too many global variables"),

View File

@ -1,5 +1,5 @@
/* /*
* $Id: parse.c 213 2009-06-26 13:05:19Z hyunghwan.chung $ * $Id: parse.c 214 2009-06-27 02:50:54Z hyunghwan.chung $
* *
Copyright 2006-2009 Chung, Hyung-Hwan. Copyright 2006-2009 Chung, Hyung-Hwan.
@ -387,10 +387,14 @@ static global_t gtab[] =
qse_awk_seterror ((awk), (code), (line), &errarg); \ qse_awk_seterror ((awk), (code), (line), &errarg); \
} while (0) } while (0)
#define MATCH_TERMINATOR_NORMAL(awk) \
(MATCH((awk),TOKEN_SEMICOLON) || MATCH((awk),TOKEN_NEWLINE))
#define MATCH_TERMINATOR_RBRACE(awk) \
((awk->option & QSE_AWK_NEWLINE) && MATCH((awk),TOKEN_RBRACE))
#define MATCH_TERMINATOR(awk) \ #define MATCH_TERMINATOR(awk) \
(MATCH((awk),TOKEN_SEMICOLON) || \ (MATCH_TERMINATOR_NORMAL(awk) || MATCH_TERMINATOR_RBRACE(awk))
MATCH((awk),TOKEN_NEWLINE) || \
((awk->option & QSE_AWK_NEWLINE) && MATCH((awk),TOKEN_RBRACE)))
qse_size_t qse_awk_getmaxdepth (qse_awk_t* awk, int type) qse_size_t qse_awk_getmaxdepth (qse_awk_t* awk, int type)
{ {
@ -592,7 +596,7 @@ exit_parse:
static qse_awk_t* parse_progunit (qse_awk_t* awk) static qse_awk_t* parse_progunit (qse_awk_t* awk)
{ {
/* /*
gbl xxx, xxxx; global xxx, xxxx;
BEGIN { action } BEGIN { action }
END { action } END { action }
pattern { action } pattern { action }
@ -1204,6 +1208,12 @@ static qse_awk_nde_t* parse_block (
{ {
while (1) while (1)
{ {
/* skip new lines before local declaration in a block*/
while (MATCH(awk,TOKEN_NEWLINE))
{
if (get_token(awk) <= -1) return QSE_NULL;
}
if (!MATCH(awk,TOKEN_LOCAL)) break; if (!MATCH(awk,TOKEN_LOCAL)) break;
if (get_token(awk) <= -1) if (get_token(awk) <= -1)
@ -1624,6 +1634,14 @@ int qse_awk_delgbl (
static qse_awk_t* collect_globals (qse_awk_t* awk) static qse_awk_t* collect_globals (qse_awk_t* awk)
{ {
if (MATCH(awk,TOKEN_NEWLINE))
{
/* special check if the first name is on the
* same line when QSE_AWK_NEWLINE is on */
SETERR (awk, QSE_AWK_EVARMS);
return QSE_NULL;
}
while (1) while (1)
{ {
if (!MATCH(awk,TOKEN_IDENT)) if (!MATCH(awk,TOKEN_IDENT))
@ -1640,7 +1658,19 @@ static qse_awk_t* collect_globals (qse_awk_t* awk)
if (get_token(awk) <= -1) return QSE_NULL; if (get_token(awk) <= -1) return QSE_NULL;
if (MATCH_TERMINATOR(awk)) break; if (MATCH_TERMINATOR_NORMAL(awk))
{
/* skip a terminator (;, <NL>) */
if (get_token(awk) <= -1) return QSE_NULL;
break;
}
/*
* unlike collect_locals(), the right brace cannot
* terminate a global declaration as it can never be
* placed within a block.
* so do not perform MATCH_TERMINATOR_RBRACE(awk))
*/
if (!MATCH(awk,TOKEN_COMMA)) if (!MATCH(awk,TOKEN_COMMA))
{ {
@ -1648,11 +1678,13 @@ static qse_awk_t* collect_globals (qse_awk_t* awk)
return QSE_NULL; return QSE_NULL;
} }
do
{
if (get_token(awk) <= -1) return QSE_NULL; if (get_token(awk) <= -1) return QSE_NULL;
} }
while (MATCH(awk,TOKEN_NEWLINE));
}
/* skip a semicolon */
if (get_token(awk) <= -1) return QSE_NULL;
return awk; return awk;
} }
@ -1660,11 +1692,19 @@ static qse_awk_t* collect_globals (qse_awk_t* awk)
static qse_awk_t* collect_locals ( static qse_awk_t* collect_locals (
qse_awk_t* awk, qse_size_t nlcls, qse_bool_t istop) qse_awk_t* awk, qse_size_t nlcls, qse_bool_t istop)
{ {
qse_xstr_t lcl; if (MATCH(awk,TOKEN_NEWLINE))
qse_size_t n; {
/* special check if the first name is on the
* same line when QSE_AWK_NEWLINE is on */
SETERR (awk, QSE_AWK_EVARMS);
return QSE_NULL;
}
while (1) while (1)
{ {
qse_xstr_t lcl;
qse_size_t n;
if (!MATCH(awk,TOKEN_IDENT)) if (!MATCH(awk,TOKEN_IDENT))
{ {
SETERRTOK (awk, QSE_AWK_EBADVAR); SETERRTOK (awk, QSE_AWK_EBADVAR);
@ -1741,7 +1781,18 @@ static qse_awk_t* collect_locals (
if (get_token(awk) <= -1) return QSE_NULL; if (get_token(awk) <= -1) return QSE_NULL;
if (MATCH_TERMINATOR(awk)) break; if (MATCH_TERMINATOR_NORMAL(awk))
{
/* skip the terminator (;, <NL>) */
if (get_token(awk) <= -1) return QSE_NULL;
break;
}
if (MATCH_TERMINATOR_RBRACE(awk))
{
/* should not skip } */
break;
}
if (!MATCH(awk,TOKEN_COMMA)) if (!MATCH(awk,TOKEN_COMMA))
{ {
@ -1749,11 +1800,12 @@ static qse_awk_t* collect_locals (
return QSE_NULL; return QSE_NULL;
} }
do
{
if (get_token(awk) <= -1) return QSE_NULL; if (get_token(awk) <= -1) return QSE_NULL;
} }
while (MATCH(awk,TOKEN_NEWLINE));
/* skip a semicolon */ }
if (get_token(awk) <= -1) return QSE_NULL;
return awk; return awk;
} }
@ -1924,18 +1976,20 @@ static qse_awk_nde_t* parse_statement_nb (qse_awk_t* awk, qse_size_t line)
if (nde == QSE_NULL) return QSE_NULL; if (nde == QSE_NULL) return QSE_NULL;
/* check if a statement ends with a semicolon */ if (MATCH_TERMINATOR_NORMAL(awk))
if (MATCH_TERMINATOR(awk))
{ {
/* eat up the semicolon or a new line and read in the next token /* check if a statement ends with a semicolon or <NL> */
* when QSE_AWK_NEWLINE is set, a statement may end with }. if (get_token(awk) <= -1)
* it should not be eaten up here. */
if (!MATCH(awk,TOKEN_RBRACE) && get_token(awk) <= -1)
{ {
if (nde != QSE_NULL) qse_awk_clrpt (awk, nde); if (nde != QSE_NULL) qse_awk_clrpt (awk, nde);
return QSE_NULL; return QSE_NULL;
} }
} }
else if (MATCH_TERMINATOR_RBRACE(awk))
{
/* do not skip the right brace as a statement terminator.
* is there anything to do here? */
}
else else
{ {
if (nde != QSE_NULL) qse_awk_clrpt (awk, nde); if (nde != QSE_NULL) qse_awk_clrpt (awk, nde);
@ -5992,4 +6046,3 @@ int qse_awk_putsrcstrx (
return 0; return 0;
} }

View File

@ -0,0 +1,3 @@
# cannot use function name as a parameter name
function f(f) { print f; }
BEGIN { f("hello"); }

View File

@ -0,0 +1,7 @@
function f(f)
{
print f;
f("my hello");
}
BEGIN { f(10); }

View File

@ -0,0 +1,3 @@
# should print 50
function fn(f) { f = 20; }
BEGIN { f = 50; fn(100); print f; }

View File

@ -0,0 +1,3 @@
# A function and a named variable cannot have the same name.
function a () { }
BEGIN { a = 20; }

View File

@ -0,0 +1,7 @@
function a (a) { print a; }
BEGIN {
local a;
a = 20;
a (1000);
}

View File

@ -0,0 +1,2 @@
global a;
function a () { }

View File

@ -0,0 +1,4 @@
function fn () { a = 20; return a;}
global a;
BEGIN { a = 30; print fn (); print a; }

View File

@ -0,0 +1,16 @@
global x;
BEGIN {
x = 1;
{
local x;
x = 2;
{
local x;
x = 3;
print x;
}
print x;
}
print x;
}

View File

@ -0,0 +1,9 @@
function a (a) { print a; }
BEGIN {
local a;
a = 20;
}
END { a (1000); }

View File

@ -23,6 +23,7 @@ print_usage()
################### ###################
QSEAWK=${QSEAWK:=../../cmd/awk/qseawk} QSEAWK=${QSEAWK:=../../cmd/awk/qseawk}
TMPFILE="${TMPFILE:=./regress.temp}"
PROGS=" PROGS="
cou-001.awk/cou.dat// cou-001.awk/cou.dat//
@ -81,6 +82,16 @@ PROGS="
emp-026.awk/emp.dat// emp-026.awk/emp.dat//
emp-027.awk/emp.dat// emp-027.awk/emp.dat//
lang-001.awk///--implicit=off --explicit=on --newline=on -o-
lang-002.awk///--implicit=off --explicit=on --newline=on -o-
lang-003.awk///--implicit=off --explicit=on --newline=on -o-
lang-004.awk///--implicit=off --explicit=on --newline=on -o-
lang-005.awk///--implicit=off --explicit=on --newline=on -o-
lang-006.awk///--implicit=off --explicit=on --newline=on -o-
lang-007.awk///--implicit=off --explicit=on --newline=on -o-
lang-008.awk///--implicit=off --explicit=on --newline=on -o-
lang-009.awk/lang-009.awk//--implicit=off --explicit=on --newline=on -o-
quicksort.awk/quicksort.dat// quicksort.awk/quicksort.dat//
quicksort2.awk/quicksort2.dat// quicksort2.awk/quicksort2.dat//
asm.awk/asm.s/asm.dat/ asm.awk/asm.s/asm.dat/
@ -96,13 +107,24 @@ PROGS="
exit 1; exit 1;
} }
for prog in ${PROGS} echo "${PROGS}" > "${TMPFILE}"
while read prog
do do
[ -z "${prog}" ] && continue
script="`echo ${prog} | cut -d/ -f1`" script="`echo ${prog} | cut -d/ -f1`"
datafile="`echo ${prog} | cut -d/ -f2`" datafile="`echo ${prog} | cut -d/ -f2`"
redinfile="`echo ${prog} | cut -d/ -f3`" redinfile="`echo ${prog} | cut -d/ -f3`"
awkopts="`echo ${prog} | cut -d/ -f4`" awkopts="`echo ${prog} | cut -d/ -f4`"
[ -z "${script}" ] && continue
[ -f "${script}" ] ||
{
echo_so "${script} not found"
continue
}
if [ -n "${redinfile}" ] if [ -n "${redinfile}" ]
then then
echo_so "${QSEAWK} ${awkopts} -f ${script} ${datafile} < ${redinfile}" echo_so "${QSEAWK} ${awkopts} -f ${script} ${datafile} < ${redinfile}"
@ -111,6 +133,9 @@ do
echo_so "${QSEAWK} ${awkopts} -f ${script} ${datafile}" echo_so "${QSEAWK} ${awkopts} -f ${script} ${datafile}"
${QSEAWK} ${awkopts} -f ${script} ${datafile} ${QSEAWK} ${awkopts} -f ${script} ${datafile}
fi fi
done
done < "${TMPFILE}"
rm -f "${TMPFILE}"
exit 0 exit 0