aboutsummaryrefslogtreecommitdiffstats
path: root/awk.y
diff options
context:
space:
mode:
Diffstat (limited to 'awk.y')
-rw-r--r--awk.y246
1 files changed, 180 insertions, 66 deletions
diff --git a/awk.y b/awk.y
index 175cea90..006b3df1 100644
--- a/awk.y
+++ b/awk.y
@@ -3,7 +3,7 @@
*/
/*
- * Copyright (C) 1986, 1988, 1989, 1991, 1992, 1993 the Free Software Foundation, Inc.
+ * Copyright (C) 1986, 1988, 1989, 1991-1995 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
* AWK Progamming Language.
@@ -43,6 +43,7 @@ static void pop_var P((NODE *np, int freeit));
static void pop_params P((NODE *params));
static NODE *make_param P((char *name));
static NODE *mk_rexp P((NODE *exp));
+static int dup_parms P((NODE *func));
static int want_assign; /* lexical scanning kludge */
static int want_regexp; /* lexical scanning kludge */
@@ -264,6 +265,9 @@ function_prologue
{
$$ = append_right(make_param($3), $5);
can_return = 1;
+ /* check for duplicate parameter names */
+ if (dup_parms($$))
+ errcount++;
}
;
@@ -273,6 +277,11 @@ function_body
$$ = $2;
can_return = 0;
}
+ | l_brace r_brace opt_semi opt_nls
+ {
+ $$ = node((NODE *) NULL, Node_K_return, (NODE *) NULL);
+ can_return = 0;
+ }
;
@@ -373,13 +382,22 @@ statement
{ $$ = node ($3, $1, $5); }
| print opt_rexpression_list output_redir statement_term
{
- if ($1 == Node_K_print && $2 == NULL)
+ if ($1 == Node_K_print && $2 == NULL) {
+ static int warned = 0;
+
$2 = node(node(make_number(0.0),
Node_field_spec,
(NODE *) NULL),
Node_expression_list,
(NODE *) NULL);
+ if (do_lint && ! io_allowed && ! warned) {
+ warned = 1;
+ warning(
+ "plain `print' in BEGIN or END rule should probably be `print \"\"'");
+ }
+ }
+
$$ = node ($2, $1, $3);
}
| LEX_NEXT opt_exp statement_term
@@ -394,12 +412,12 @@ statement
* the source line
*/
errcount++;
- msg("`next file' is a gawk extension");
+ error("`next file' is a gawk extension");
}
if (! io_allowed) {
/* same thing */
errcount++;
- msg("`next file' used in BEGIN or END action");
+ error("`next file' used in BEGIN or END action");
}
type = Node_K_nextfile;
} else {
@@ -427,7 +445,7 @@ statement
* the source line
*/
errcount++;
- msg("`delete array' is a gawk extension");
+ error("`delete array' is a gawk extension");
}
$$ = node (variable($2,1), Node_K_delete, (NODE *) NULL);
}
@@ -596,7 +614,15 @@ exp : variable ASSIGNOP
$$ = node ($1, $2, mk_rexp($3));
}
| regexp
- { $$ = $1; }
+ {
+ $$ = $1;
+ if (do_lint && tokstart[0] == '*') {
+ /* possible C comment */
+ int n = strlen(tokstart) - 1;
+ if (tokstart[n] == '*')
+ warning("regexp looks like a C comment, but is not");
+ }
+ }
| '!' regexp %prec UNARY
{
$$ = node(node(make_number(0.0),
@@ -700,6 +726,7 @@ non_post_simp_exp
| FUNC_CALL '(' opt_expression_list r_paren
{
$$ = node ($3, Node_func_call, make_string($1, strlen($1)));
+ free($1);
}
| variable
| INCREMENT variable
@@ -1014,9 +1041,10 @@ again:
if (n == 0) {
samefile = 0;
nextfile++;
- *lexeme = '\0';
+ if (lexeme)
+ *lexeme = '\0';
len = 0;
- return get_src_buf();
+ goto again;
}
lexptr = buf + SLOP;
lexend = lexptr + n;
@@ -1045,12 +1073,16 @@ tokexpand()
#if DEBUG
char
nextc() {
+ int c;
+
if (lexptr && lexptr < lexend)
- return *lexptr++;
+ c = *lexptr++;
else if (get_src_buf())
- return *lexptr++;
+ c = *lexptr++;
else
- return '\0';
+ c = '\0';
+
+ return c;
}
#else
#define nextc() ((lexptr && lexptr < lexend) ? \
@@ -1074,9 +1106,19 @@ yylex()
int low, mid, high;
static int did_newline = 0;
char *tokkey;
-
- if (!nextc())
+ static int lasttok = 0, eof_warned = 0;
+
+ if (!nextc()) {
+ if (lasttok != NEWLINE) {
+ lasttok = NEWLINE;
+ if (do_lint && ! eof_warned) {
+ warning("source file does not end in newline");
+ eof_warned = 1;
+ }
+ return NEWLINE; /* fake it */
+ }
return 0;
+ }
pushback();
#ifdef OS2
/*
@@ -1119,7 +1161,7 @@ yylex()
pushback();
tokadd('\0');
yylval.sval = tokstart;
- return REGEXP;
+ return lasttok = REGEXP;
case '\n':
pushback();
yyerror("unterminated regexp");
@@ -1140,19 +1182,37 @@ retry:
switch (c) {
case 0:
+ if (lasttok != NEWLINE) {
+ lasttok = NEWLINE;
+ if (do_lint && ! eof_warned) {
+ warning("source file does not end in newline");
+ eof_warned = 1;
+ }
+ return NEWLINE; /* fake it */
+ }
return 0;
case '\n':
sourceline++;
- return NEWLINE;
+ return lasttok = NEWLINE;
case '#': /* it's a comment */
while ((c = nextc()) != '\n') {
- if (c == '\0')
+ if (c == '\0') {
+ if (lasttok != NEWLINE) {
+ lasttok = NEWLINE;
+ if (do_lint && ! eof_warned) {
+ warning(
+ "source file does not end in newline");
+ eof_warned = 1;
+ }
+ return NEWLINE; /* fake it */
+ }
return 0;
+ }
}
sourceline++;
- return NEWLINE;
+ return lasttok = NEWLINE;
case '\\':
#ifdef RELAXED_CONTINUATION
@@ -1182,7 +1242,7 @@ retry:
case '$':
want_assign = 1;
- return '$';
+ return lasttok = '$';
case ')':
case ']':
@@ -1193,15 +1253,15 @@ retry:
case '?':
case '{':
case ',':
- return c;
+ return lasttok = c;
case '*':
if ((c = nextc()) == '=') {
yylval.nodetypeval = Node_assign_times;
- return ASSIGNOP;
+ return lasttok = ASSIGNOP;
} else if (do_posix) {
pushback();
- return '*';
+ return lasttok = '*';
} else if (c == '*') {
/* make ** and **= aliases for ^ and ^= */
static int did_warn_op = 0, did_warn_assgn = 0;
@@ -1212,36 +1272,36 @@ retry:
warning("**= is not allowed by POSIX");
}
yylval.nodetypeval = Node_assign_exp;
- return ASSIGNOP;
+ return lasttok = ASSIGNOP;
} else {
pushback();
if (do_lint && ! did_warn_op) {
did_warn_op = 1;
warning("** is not allowed by POSIX");
}
- return '^';
+ return lasttok = '^';
}
}
pushback();
- return '*';
+ return lasttok = '*';
case '/':
if (want_assign) {
if (nextc() == '=') {
yylval.nodetypeval = Node_assign_quotient;
- return ASSIGNOP;
+ return lasttok = ASSIGNOP;
}
pushback();
}
- return '/';
+ return lasttok = '/';
case '%':
if (nextc() == '=') {
yylval.nodetypeval = Node_assign_mod;
- return ASSIGNOP;
+ return lasttok = ASSIGNOP;
}
pushback();
- return '%';
+ return lasttok = '%';
case '^':
{
@@ -1254,73 +1314,73 @@ retry:
warning("operator `^=' is not supported in old awk");
}
yylval.nodetypeval = Node_assign_exp;
- return ASSIGNOP;
+ return lasttok = ASSIGNOP;
}
pushback();
if (do_lint && ! did_warn_op) {
did_warn_op = 1;
warning("operator `^' is not supported in old awk");
}
- return '^';
+ return lasttok = '^';
}
case '+':
if ((c = nextc()) == '=') {
yylval.nodetypeval = Node_assign_plus;
- return ASSIGNOP;
+ return lasttok = ASSIGNOP;
}
if (c == '+')
- return INCREMENT;
+ return lasttok = INCREMENT;
pushback();
- return '+';
+ return lasttok = '+';
case '!':
if ((c = nextc()) == '=') {
yylval.nodetypeval = Node_notequal;
- return RELOP;
+ return lasttok = RELOP;
}
if (c == '~') {
yylval.nodetypeval = Node_nomatch;
want_assign = 0;
- return MATCHOP;
+ return lasttok = MATCHOP;
}
pushback();
- return '!';
+ return lasttok = '!';
case '<':
if (nextc() == '=') {
yylval.nodetypeval = Node_leq;
- return RELOP;
+ return lasttok = RELOP;
}
yylval.nodetypeval = Node_less;
pushback();
- return '<';
+ return lasttok = '<';
case '=':
if (nextc() == '=') {
yylval.nodetypeval = Node_equal;
- return RELOP;
+ return lasttok = RELOP;
}
yylval.nodetypeval = Node_assign;
pushback();
- return ASSIGNOP;
+ return lasttok = ASSIGNOP;
case '>':
if ((c = nextc()) == '=') {
yylval.nodetypeval = Node_geq;
- return RELOP;
+ return lasttok = RELOP;
} else if (c == '>') {
yylval.nodetypeval = Node_redirect_append;
- return APPEND_OP;
+ return lasttok = APPEND_OP;
}
yylval.nodetypeval = Node_greater;
pushback();
- return '>';
+ return lasttok = '>';
case '~':
yylval.nodetypeval = Node_match;
want_assign = 0;
- return MATCHOP;
+ return lasttok = MATCHOP;
case '}':
/*
@@ -1329,11 +1389,11 @@ retry:
*/
if (did_newline) {
did_newline = 0;
- return c;
+ return lasttok = c;
}
did_newline++;
--lexptr; /* pick up } next time */
- return NEWLINE;
+ return lasttok = NEWLINE;
case '"':
esc_seen = 0;
@@ -1360,23 +1420,23 @@ retry:
yylval.nodeval = make_str_node(tokstart,
tok - tokstart, esc_seen ? SCAN : 0);
yylval.nodeval->flags |= PERM;
- return YSTRING;
+ return lasttok = YSTRING;
case '-':
if ((c = nextc()) == '=') {
yylval.nodetypeval = Node_assign_minus;
- return ASSIGNOP;
+ return lasttok = ASSIGNOP;
}
if (c == '-')
- return DECREMENT;
+ return lasttok = DECREMENT;
pushback();
- return '-';
+ return lasttok = '-';
case '.':
c = nextc();
pushback();
if (!isdigit(c))
- return '.';
+ return lasttok = '.';
else
c = '.'; /* FALL THROUGH */
case '0':
@@ -1432,10 +1492,16 @@ retry:
break;
c = nextc();
}
- pushback();
+ if (c != 0)
+ pushback();
+ else if (do_lint && ! eof_warned) {
+ warning("source file does not end in newline");
+ eof_warned = 1;
+ }
+ tokadd('\0');
yylval.nodeval = make_number(atof(tokstart));
yylval.nodeval->flags |= PERM;
- return YNUMBER;
+ return lasttok = YNUMBER;
case '&':
if ((c = nextc()) == '&') {
@@ -1458,10 +1524,10 @@ retry:
}
}
want_assign = 0;
- return LEX_AND;
+ return lasttok = LEX_AND;
}
pushback();
- return '&';
+ return lasttok = '&';
case '|':
if ((c = nextc()) == '|') {
@@ -1484,10 +1550,10 @@ retry:
}
}
want_assign = 0;
- return LEX_OR;
+ return lasttok = LEX_OR;
}
pushback();
- return '|';
+ return lasttok = '|';
}
if (c != '_' && ! isalpha(c))
@@ -1502,7 +1568,12 @@ retry:
tokadd('\0');
emalloc(tokkey, char *, tok - tokstart, "yylex");
memcpy(tokkey, tokstart, tok - tokstart);
- pushback();
+ if (c != 0)
+ pushback();
+ else if (do_lint && ! eof_warned) {
+ warning("source file does not end in newline");
+ eof_warned = 1;
+ }
/* See if it is a special token. */
low = 0;
@@ -1541,16 +1612,16 @@ retry:
yylval.nodetypeval = tokentab[mid].value;
free(tokkey);
- return tokentab[mid].class;
+ return lasttok = tokentab[mid].class;
}
}
yylval.sval = tokkey;
if (*lexptr == '(')
- return FUNC_CALL;
+ return lasttok = FUNC_CALL;
else {
want_assign = 1;
- return NAME;
+ return lasttok = NAME;
}
}
@@ -1758,6 +1829,45 @@ NODE *list, *new;
return oldlist;
}
+/* return 1 if there are duplicate parameters, 0 means all ok */
+static int
+dup_parms(func)
+NODE *func;
+{
+ register NODE *np;
+ char *fname, **names;
+ int count, i, j, dups;
+ NODE *params;
+
+ fname = func->param;
+ count = func->param_cnt;
+ params = func->rnode;
+
+ if (count == 0) /* no args, no problem */
+ return 0;
+
+ emalloc(names, char **, count * sizeof(char *), "dup_parms");
+
+ i = 0;
+ for (np = params; np != NULL; np = np->rnode)
+ names[i++] = np->param;
+
+ dups = 0;
+ for (i = 1; i < count; i++) {
+ for (j = 0; j < i; j++) {
+ if (strcmp(names[i], names[j]) == 0) {
+ dups++;
+ error(
+ "function `%s': parameter #%d, `%s', duplicates parameter #%d",
+ fname, i+1, names[j], j+1);
+ }
+ }
+ }
+
+ free(names);
+ return (dups > 0);
+}
+
/*
* check if name is already installed; if so, it had better have Null value,
* in which case def is added as the value. Otherwise, install name with def
@@ -1803,14 +1913,18 @@ int freeit;
}
}
+/*
+ * pop parameters out of the symbol table. do this in reverse order to
+ * avoid reading freed memory if there were duplicated parameters.
+ */
static void
pop_params(params)
NODE *params;
{
- register NODE *np;
-
- for (np = params; np != NULL; np = np->rnode)
- pop_var(np, 1);
+ if (params == NULL)
+ return;
+ pop_params(params->rnode);
+ pop_var(params, 1);
}
static NODE *
@@ -1827,7 +1941,7 @@ char *name;
return (install(name, r));
}
-/* Name points to a variable name. Make sure its in the symbol table */
+/* Name points to a variable name. Make sure it's in the symbol table */
NODE *
variable(name, can_free)
char *name;