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.
@ -609,6 +609,7 @@ enum qse_awk_errnum_t
QSE_AWK_EDUPLCL, /* duplicate local variable name */
QSE_AWK_EBADPAR, /* not a valid parameter name */
QSE_AWK_EBADVAR, /* not a valid variable name */
QSE_AWK_EVARMS, /* variable name missing */
QSE_AWK_EUNDEF, /* undefined identifier */
QSE_AWK_ELVALUE, /* l-value required */
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.
@ -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("'${0}' not a valid parameter name"),
QSE_T("'${0}' not a valid variable name"),
QSE_T("variable name missing"),
QSE_T("undefined identifier '${0}'"),
QSE_T("l-value required"),
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.
@ -387,10 +387,14 @@ static global_t gtab[] =
qse_awk_seterror ((awk), (code), (line), &errarg); \
} 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) \
(MATCH((awk),TOKEN_SEMICOLON) || \
MATCH((awk),TOKEN_NEWLINE) || \
((awk->option & QSE_AWK_NEWLINE) && MATCH((awk),TOKEN_RBRACE)))
(MATCH_TERMINATOR_NORMAL(awk) || MATCH_TERMINATOR_RBRACE(awk))
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)
{
/*
gbl xxx, xxxx;
global xxx, xxxx;
BEGIN { action }
END { action }
pattern { action }
@ -1204,6 +1208,12 @@ static qse_awk_nde_t* parse_block (
{
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 (get_token(awk) <= -1)
@ -1624,6 +1634,14 @@ int qse_awk_delgbl (
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)
{
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 (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))
{
@ -1648,11 +1678,13 @@ static qse_awk_t* collect_globals (qse_awk_t* awk)
return QSE_NULL;
}
if (get_token(awk) <= -1) return QSE_NULL;
do
{
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;
}
@ -1660,11 +1692,19 @@ static qse_awk_t* collect_globals (qse_awk_t* awk)
static qse_awk_t* collect_locals (
qse_awk_t* awk, qse_size_t nlcls, qse_bool_t istop)
{
qse_xstr_t lcl;
qse_size_t n;
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)
{
qse_xstr_t lcl;
qse_size_t n;
if (!MATCH(awk,TOKEN_IDENT))
{
SETERRTOK (awk, QSE_AWK_EBADVAR);
@ -1741,7 +1781,18 @@ static qse_awk_t* collect_locals (
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))
{
@ -1749,12 +1800,13 @@ static qse_awk_t* collect_locals (
return QSE_NULL;
}
if (get_token(awk) <= -1) return QSE_NULL;
do
{
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;
}
@ -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;
/* check if a statement ends with a semicolon */
if (MATCH_TERMINATOR(awk))
if (MATCH_TERMINATOR_NORMAL(awk))
{
/* eat up the semicolon or a new line and read in the next token
* when QSE_AWK_NEWLINE is set, a statement may end with }.
* it should not be eaten up here. */
if (!MATCH(awk,TOKEN_RBRACE) && get_token(awk) <= -1)
/* check if a statement ends with a semicolon or <NL> */
if (get_token(awk) <= -1)
{
if (nde != QSE_NULL) qse_awk_clrpt (awk, nde);
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
{
if (nde != QSE_NULL) qse_awk_clrpt (awk, nde);
@ -5992,4 +6046,3 @@ int qse_awk_putsrcstrx (
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}
TMPFILE="${TMPFILE:=./regress.temp}"
PROGS="
cou-001.awk/cou.dat//
@ -81,6 +82,16 @@ PROGS="
emp-026.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//
quicksort2.awk/quicksort2.dat//
asm.awk/asm.s/asm.dat/
@ -96,13 +107,24 @@ PROGS="
exit 1;
}
for prog in ${PROGS}
echo "${PROGS}" > "${TMPFILE}"
while read prog
do
[ -z "${prog}" ] && continue
script="`echo ${prog} | cut -d/ -f1`"
datafile="`echo ${prog} | cut -d/ -f2`"
redinfile="`echo ${prog} | cut -d/ -f3`"
awkopts="`echo ${prog} | cut -d/ -f4`"
[ -z "${script}" ] && continue
[ -f "${script}" ] ||
{
echo_so "${script} not found"
continue
}
if [ -n "${redinfile}" ]
then
echo_so "${QSEAWK} ${awkopts} -f ${script} ${datafile} < ${redinfile}"
@ -111,6 +133,9 @@ do
echo_so "${QSEAWK} ${awkopts} -f ${script} ${datafile}"
${QSEAWK} ${awkopts} -f ${script} ${datafile}
fi
done
done < "${TMPFILE}"
rm -f "${TMPFILE}"
exit 0