aboutsummaryrefslogtreecommitdiffstats
path: root/awkgram.y
diff options
context:
space:
mode:
Diffstat (limited to 'awkgram.y')
-rw-r--r--awkgram.y788
1 files changed, 619 insertions, 169 deletions
diff --git a/awkgram.y b/awkgram.y
index 4eab3d6f..4ed1e78b 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -2,7 +2,7 @@
* awkgram.y --- yacc/bison parser
*/
-/*
+/*
* Copyright (C) 1986, 1988, 1989, 1991-2016 the Free Software Foundation, Inc.
*
* This file is part of GAWK, the GNU implementation of the
@@ -40,7 +40,7 @@ static void lintwarn_ln(int line, const char *m, ...) ATTRIBUTE_PRINTF_2;
static void warning_ln(int line, const char *m, ...) ATTRIBUTE_PRINTF_2;
static char *get_src_buf(void);
static int yylex(void);
-int yyparse(void);
+int yyparse(void);
static INSTRUCTION *snode(INSTRUCTION *subn, INSTRUCTION *op);
static char **check_params(char *fname, int pcount, INSTRUCTION *list);
static int install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist);
@@ -57,6 +57,7 @@ static int include_source(INSTRUCTION *file);
static int load_library(INSTRUCTION *file);
static void next_sourcefile(void);
static char *tokexpand(void);
+static NODE *make_profile_number(double d, const char *str, size_t len);
#define instruction(t) bcalloc(t, 1, 0)
@@ -83,10 +84,18 @@ static void check_funcs(void);
static ssize_t read_one_line(int fd, void *buffer, size_t count);
static int one_line_close(int fd);
+static void split_comment(void);
+static void check_comment(void);
+static void add_sign_to_num(NODE *n, char sign);
static bool at_seen = false;
static bool want_source = false;
static bool want_regexp = false; /* lexical scanning kludge */
+static enum {
+ FUNC_HEADER,
+ FUNC_BODY,
+ DONT_CHECK
+} want_param_names = DONT_CHECK; /* ditto */
static char *in_function; /* parsing kludge */
static int rule = 0;
@@ -106,7 +115,7 @@ static char *lexptr; /* pointer to next char during parsing */
static char *lexend; /* end of buffer */
static char *lexptr_begin; /* keep track of where we were for error msgs */
static char *lexeme; /* beginning of lexeme for debugging */
-static bool lexeof; /* seen EOF for current source? */
+static bool lexeof; /* seen EOF for current source? */
static char *thisline = NULL;
static int in_braces = 0; /* count braces for firstline, lastline in an 'action' */
static int lastline = 0;
@@ -141,11 +150,23 @@ static INSTRUCTION *ip_atexit = NULL;
static INSTRUCTION *ip_end;
static INSTRUCTION *ip_endfile;
static INSTRUCTION *ip_beginfile;
+INSTRUCTION *main_beginfile;
+
+static INSTRUCTION *comment = NULL;
+static INSTRUCTION *prior_comment = NULL;
+static INSTRUCTION *comment_to_save = NULL;
+static INSTRUCTION *program_comment = NULL;
+static INSTRUCTION *function_comment = NULL;
+static INSTRUCTION *block_comment = NULL;
+
+static bool func_first = true;
+static bool first_rule = true;
static inline INSTRUCTION *list_create(INSTRUCTION *x);
static inline INSTRUCTION *list_append(INSTRUCTION *l, INSTRUCTION *x);
static inline INSTRUCTION *list_prepend(INSTRUCTION *l, INSTRUCTION *x);
static inline INSTRUCTION *list_merge(INSTRUCTION *l1, INSTRUCTION *l2);
+static inline INSTRUCTION *add_pending_comment(INSTRUCTION *stmt);
extern double fmod(double x, double y);
@@ -160,7 +181,7 @@ extern double fmod(double x, double y);
%token LEX_BEGIN LEX_END LEX_IF LEX_ELSE LEX_RETURN LEX_DELETE
%token LEX_SWITCH LEX_CASE LEX_DEFAULT LEX_WHILE LEX_DO LEX_FOR LEX_BREAK LEX_CONTINUE
%token LEX_PRINT LEX_PRINTF LEX_NEXT LEX_EXIT LEX_FUNCTION
-%token LEX_BEGINFILE LEX_ENDFILE
+%token LEX_BEGINFILE LEX_ENDFILE
%token LEX_GETLINE LEX_NEXTFILE
%token LEX_IN
%token LEX_AND LEX_OR INCREMENT DECREMENT
@@ -218,6 +239,7 @@ rule
: pattern action
{
(void) append_rule($1, $2);
+ first_rule = false;
}
| pattern statement_term
{
@@ -234,6 +256,7 @@ rule
{
in_function = NULL;
(void) mk_function($1, $2);
+ want_param_names = DONT_CHECK;
yyerrok;
}
| '@' LEX_INCLUDE source statement_term
@@ -282,9 +305,24 @@ library
pattern
: /* empty */
- { $$ = NULL; rule = Rule; }
+ {
+ rule = Rule;
+ if (comment != NULL) {
+ $$ = list_create(comment);
+ comment = NULL;
+ } else
+ $$ = NULL;
+ }
| exp
- { $$ = $1; rule = Rule; }
+ {
+ rule = Rule;
+ if (comment != NULL) {
+ $$ = list_prepend($1, comment);
+ comment = NULL;
+ } else
+ $$ = $1;
+ }
+
| exp ',' opt_nls exp
{
INSTRUCTION *tp;
@@ -308,41 +346,55 @@ pattern
($1->nexti + 1)->condpair_left = $1->lasti;
($1->nexti + 1)->condpair_right = $4->lasti;
}
- $$ = list_append(list_merge($1, $4), tp);
+ if (comment != NULL) {
+ $$ = list_append(list_merge(list_prepend($1, comment), $4), tp);
+ comment = NULL;
+ } else
+ $$ = list_append(list_merge($1, $4), tp);
rule = Rule;
}
| LEX_BEGIN
{
static int begin_seen = 0;
+
+ func_first = false;
if (do_lint_old && ++begin_seen == 2)
warning_ln($1->source_line,
_("old awk does not support multiple `BEGIN' or `END' rules"));
$1->in_rule = rule = BEGIN;
$1->source_file = source;
+ check_comment();
$$ = $1;
}
| LEX_END
{
static int end_seen = 0;
+
+ func_first = false;
if (do_lint_old && ++end_seen == 2)
warning_ln($1->source_line,
_("old awk does not support multiple `BEGIN' or `END' rules"));
$1->in_rule = rule = END;
$1->source_file = source;
+ check_comment();
$$ = $1;
}
| LEX_BEGINFILE
{
+ func_first = false;
$1->in_rule = rule = BEGINFILE;
$1->source_file = source;
+ check_comment();
$$ = $1;
}
| LEX_ENDFILE
{
+ func_first = false;
$1->in_rule = rule = ENDFILE;
$1->source_file = source;
+ check_comment();
$$ = $1;
}
;
@@ -350,10 +402,12 @@ pattern
action
: l_brace statements r_brace opt_semi opt_nls
{
+ INSTRUCTION *ip;
if ($2 == NULL)
- $$ = list_create(instruction(Op_no_op));
+ ip = list_create(instruction(Op_no_op));
else
- $$ = $2;
+ ip = $2;
+ $$ = ip;
}
;
@@ -379,18 +433,45 @@ lex_builtin
: LEX_BUILTIN
| LEX_LENGTH
;
-
+
function_prologue
- : LEX_FUNCTION func_name '(' opt_param_list r_paren opt_nls
+ : LEX_FUNCTION func_name '(' { want_param_names = FUNC_HEADER; } opt_param_list r_paren opt_nls
{
+ /*
+ * treat any comments between BOF and the first function
+ * definition (with no intervening BEGIN etc block) as
+ * program comments. Special kludge: iff there are more
+ * than one such comments, treat the last as a function
+ * comment.
+ */
+ if (prior_comment != NULL) {
+ comment_to_save = prior_comment;
+ prior_comment = NULL;
+ } else if (comment != NULL) {
+ comment_to_save = comment;
+ comment = NULL;
+ } else
+ comment_to_save = NULL;
+
+ if (comment_to_save != NULL && func_first
+ && strstr(comment_to_save->memory->stptr, "\n\n") != NULL)
+ split_comment();
+
+ /* save any other pre-function comment as function comment */
+ if (comment_to_save != NULL) {
+ function_comment = comment_to_save;
+ comment_to_save = NULL;
+ }
+ func_first = false;
$1->source_file = source;
- if (install_function($2->lextok, $1, $4) < 0)
+ if (install_function($2->lextok, $1, $5) < 0)
YYABORT;
in_function = $2->lextok;
$2->lextok = NULL;
bcfree($2);
- /* $4 already free'd in install_function */
+ /* $5 already free'd in install_function */
$$ = $1;
+ want_param_names = FUNC_BODY;
}
;
@@ -440,19 +521,62 @@ a_slash
statements
: /* empty */
- { $$ = NULL; }
+ {
+ if (prior_comment != NULL) {
+ $$ = list_create(prior_comment);
+ prior_comment = NULL;
+ } else if (comment != NULL) {
+ $$ = list_create(comment);
+ comment = NULL;
+ } else
+ $$ = NULL;
+ }
| statements statement
{
- if ($2 == NULL)
- $$ = $1;
- else {
+ if ($2 == NULL) {
+ if (prior_comment != NULL) {
+ $$ = list_append($1, prior_comment);
+ prior_comment = NULL;
+ if (comment != NULL) {
+ $$ = list_append($$, comment);
+ comment = NULL;
+ }
+ } else if (comment != NULL) {
+ $$ = list_append($1, comment);
+ comment = NULL;
+ } else
+ $$ = $1;
+ } else {
add_lint($2, LINT_no_effect);
- if ($1 == NULL)
- $$ = $2;
- else
+ if ($1 == NULL) {
+ if (prior_comment != NULL) {
+ $$ = list_append($2, prior_comment);
+ prior_comment = NULL;
+ if (comment != NULL) {
+ $$ = list_append($$, comment);
+ comment = NULL;
+ }
+ } else if (comment != NULL) {
+ $$ = list_append($2, comment);
+ comment = NULL;
+ } else
+ $$ = $2;
+ } else {
+ if (prior_comment != NULL) {
+ list_append($2, prior_comment);
+ prior_comment = NULL;
+ if (comment != NULL) {
+ list_append($2, comment);
+ comment = NULL;
+ }
+ } else if (comment != NULL) {
+ list_append($2, comment);
+ comment = NULL;
+ }
$$ = list_merge($1, $2);
+ }
}
- yyerrok;
+ yyerrok;
}
| statements error
{ $$ = NULL; }
@@ -484,7 +608,7 @@ statement
int case_count = 0;
int i;
- tbreak = instruction(Op_no_op);
+ tbreak = instruction(Op_no_op);
cstmt = list_create(tbreak);
cexp = list_create(instruction(Op_pop));
dflt = instruction(Op_jmp);
@@ -496,7 +620,7 @@ statement
} /* else
curr = NULL; */
- for(; curr != NULL; curr = nextc) {
+ for (; curr != NULL; curr = nextc) {
INSTRUCTION *caseexp = curr->case_exp;
INSTRUCTION *casestmt = curr->case_stmt;
@@ -511,7 +635,7 @@ statement
error_ln(curr->source_line,
_("duplicate case values in switch body: %s"), caseval);
}
-
+
if (case_values == NULL)
emalloc(case_values, const char **, sizeof(char *) * maxcount, "statement");
else if (case_count >= maxcount) {
@@ -562,18 +686,18 @@ statement
(void) list_merge(ip, cexp);
$$ = list_merge(ip, cstmt);
- break_allowed--;
+ break_allowed--;
fix_break_continue(ip, tbreak, NULL);
}
| LEX_WHILE '(' exp r_paren opt_nls statement
- {
+ {
/*
* -----------------
* tc:
* cond
* -----------------
* [Op_jmp_false tb ]
- * -----------------
+ * -----------------
* body
* -----------------
* [Op_jmp tc ]
@@ -614,7 +738,7 @@ statement
* z:
* body
* -----------------
- * tc:
+ * tc:
* cond
* -----------------
* [Op_jmp_true | z ]
@@ -661,7 +785,7 @@ statement
&& ($8->nexti->memory->type != Node_var || !($8->nexti->memory->var_update))
&& strcmp($8->nexti->memory->vname, var_name) == 0
) {
-
+
/* Efficiency hack. Recognize the special case of
*
* for (iggy in foo)
@@ -673,10 +797,10 @@ statement
*
* Check that the body is a `delete a[i]' statement,
* and that both the loop var and array names match.
- */
+ */
NODE *arr = NULL;
- ip = $8->nexti->nexti;
+ ip = $8->nexti->nexti;
if ($5->nexti->opcode == Op_push && $5->lasti == $5->nexti)
arr = $5->nexti->memory;
if (arr != NULL
@@ -702,7 +826,7 @@ statement
/* [ Op_push_array a ]
* [ Op_arrayfor_init | ib ]
- * ic:[ Op_arrayfor_incr | ib ]
+ * ic:[ Op_arrayfor_incr | ib ]
* [ Op_var_assign if any ]
*
* body
@@ -731,7 +855,7 @@ regular_loop:
} /* else
$1 is NULL */
- /* add update_FOO instruction if necessary */
+ /* add update_FOO instruction if necessary */
if ($4->array_var->type == Node_var && $4->array_var->var_update) {
(void) list_append(ip, instruction(Op_var_update));
ip->lasti->update_var = $4->array_var->var_update;
@@ -747,7 +871,7 @@ regular_loop:
if (do_pretty_print) {
(void) list_append(ip, instruction(Op_exec_count));
($1 + 1)->forloop_cond = $4;
- ($1 + 1)->forloop_body = ip->lasti;
+ ($1 + 1)->forloop_body = ip->lasti;
}
if ($8 != NULL)
@@ -757,7 +881,7 @@ regular_loop:
ip->lasti->target_jmp = $4;
$$ = list_append(ip, tbreak);
fix_break_continue(ip, tbreak, tcont);
- }
+ }
break_allowed--;
continue_allowed--;
@@ -782,17 +906,19 @@ regular_loop:
$$ = list_prepend($1, instruction(Op_exec_count));
else
$$ = $1;
+ $$ = add_pending_comment($$);
}
;
non_compound_stmt
: LEX_BREAK statement_term
- {
+ {
if (! break_allowed)
error_ln($1->source_line,
_("`break' is not allowed outside a loop or switch"));
$1->target_jmp = NULL;
$$ = list_create($1);
+ $$ = add_pending_comment($$);
}
| LEX_CONTINUE statement_term
@@ -802,6 +928,7 @@ non_compound_stmt
_("`continue' is not allowed outside a loop"));
$1->target_jmp = NULL;
$$ = list_create($1);
+ $$ = add_pending_comment($$);
}
| LEX_NEXT statement_term
@@ -812,6 +939,7 @@ non_compound_stmt
_("`next' used in %s action"), ruletab[rule]);
$1->target_jmp = ip_rec;
$$ = list_create($1);
+ $$ = add_pending_comment($$);
}
| LEX_NEXTFILE statement_term
{
@@ -823,11 +951,12 @@ non_compound_stmt
$1->target_newfile = ip_newfile;
$1->target_endfile = ip_endfile;
$$ = list_create($1);
+ $$ = add_pending_comment($$);
}
| LEX_EXIT opt_exp statement_term
{
/* Initialize the two possible jump targets, the actual target
- * is resolved at run-time.
+ * is resolved at run-time.
*/
$1->target_end = ip_end; /* first instruction in end_block */
$1->target_atexit = ip_atexit; /* cleanup and go home */
@@ -838,6 +967,7 @@ non_compound_stmt
$$->nexti->memory = dupnode(Nnull_string);
} else
$$ = list_append($2, $1);
+ $$ = add_pending_comment($$);
}
| LEX_RETURN
{
@@ -862,6 +992,7 @@ non_compound_stmt
$$ = list_append($3, $1);
}
+ $$ = add_pending_comment($$);
}
| simple_stmt statement_term
;
@@ -943,7 +1074,7 @@ simple_stmt
* [$1 | NULL | redir_type | expr_count]
*
*/
-regular_print:
+regular_print:
if ($4 == NULL) { /* no redirection */
if ($3 == NULL) { /* printf without arg */
$1->expr_count = 0;
@@ -971,6 +1102,7 @@ regular_print:
}
}
}
+ $$ = add_pending_comment($$);
}
| LEX_DELETE NAME { sub_counter = 0; } delete_subscript_list
@@ -1005,7 +1137,8 @@ regular_print:
$1->expr_count = sub_counter;
$$ = list_append(list_append($4, $2), $1);
}
- }
+ $$ = add_pending_comment($$);
+ }
| LEX_DELETE '(' NAME ')'
/*
* this is for tawk compatibility. maybe the warnings
@@ -1035,9 +1168,13 @@ regular_print:
else if ($3->memory == func_table)
fatal(_("`delete' is not allowed with FUNCTAB"));
}
+ $$ = add_pending_comment($$);
}
| exp
- { $$ = optimize_assignment($1); }
+ {
+ $$ = optimize_assignment($1);
+ $$ = add_pending_comment($$);
+ }
;
opt_simple_stmt
@@ -1066,7 +1203,7 @@ case_statement
{
INSTRUCTION *casestmt = $5;
if ($5 == NULL)
- casestmt = list_create(instruction(Op_no_op));
+ casestmt = list_create(instruction(Op_no_op));
if (do_pretty_print)
(void) list_prepend(casestmt, instruction(Op_exec_count));
$1->case_exp = $2;
@@ -1091,7 +1228,7 @@ case_value
: YNUMBER
{ $$ = $1; }
| '-' YNUMBER %prec UNARY
- {
+ {
NODE *n = $2->memory;
(void) force_number(n);
negate_num(n);
@@ -1100,14 +1237,19 @@ case_value
}
| '+' YNUMBER %prec UNARY
{
+ NODE *n = $2->lasti->memory;
bcfree($1);
+ add_sign_to_num(n, '+');
$$ = $2;
}
- | YSTRING
+ | YSTRING
{ $$ = $1; }
- | regexp
+ | regexp
{
- $1->opcode = Op_push_re;
+ if ($1->memory->type == Node_regex)
+ $1->opcode = Op_push_re;
+ else
+ $1->opcode = Op_push;
$$ = $1;
}
;
@@ -1184,7 +1326,7 @@ opt_param_list
: /* empty */
{ $$ = NULL; }
| param_list
- { $$ = $1 ; }
+ { $$ = $1; }
;
param_list
@@ -1255,6 +1397,47 @@ expression_list
}
;
+opt_fcall_expression_list
+ : /* empty */
+ { $$ = NULL; }
+ | fcall_expression_list
+ { $$ = $1; }
+ ;
+
+fcall_expression_list
+ : fcall_exp
+ { $$ = mk_expression_list(NULL, $1); }
+ | fcall_expression_list comma fcall_exp
+ {
+ $$ = mk_expression_list($1, $3);
+ yyerrok;
+ }
+ | error
+ { $$ = NULL; }
+ | fcall_expression_list error
+ {
+ /*
+ * Returning the expression list instead of NULL lets
+ * snode get a list of arguments that it can count.
+ */
+ $$ = $1;
+ }
+ | fcall_expression_list error fcall_exp
+ {
+ /* Ditto */
+ $$ = mk_expression_list($1, $3);
+ }
+ | fcall_expression_list comma error
+ {
+ /* Ditto */
+ $$ = $1;
+ }
+ ;
+
+fcall_exp
+ : exp { $$ = $1; }
+ ;
+
/* Expressions, not including the comma operator. */
exp
: variable assign_operator exp %prec ASSIGNOP
@@ -1275,6 +1458,7 @@ exp
_("regular expression on left of `~' or `!~' operator"));
if ($3->lasti == $3->nexti && $3->nexti->opcode == Op_match_rec) {
+ /* RHS is /.../ */
$2->memory = $3->nexti->memory;
bcfree($3->nexti); /* Op_match_rec */
bcfree($3); /* Op_list */
@@ -1313,7 +1497,7 @@ assign_operator
| ASSIGNOP
{ $$ = $1; }
| SLASH_BEFORE_EQUAL ASSIGN /* `/=' */
- {
+ {
$2->opcode = Op_assign_quotient;
$$ = $2;
}
@@ -1364,10 +1548,15 @@ common_exp
NODE *n2 = $2->nexti->memory;
size_t nlen;
+ // 1.5 "" # can't fold this if program mucks with CONVFMT.
+ // See test #12 in test/posix.awk.
+ if ((n1->flags & (NUMBER|NUMINT)) != 0 || (n2->flags & (NUMBER|NUMINT)) != 0)
+ goto plain_concat;
+
n1 = force_string(n1);
n2 = force_string(n2);
nlen = n1->stlen + n2->stlen;
- erealloc(n1->stptr, char *, nlen + 2, "constant fold");
+ erealloc(n1->stptr, char *, nlen + 1, "constant fold");
memcpy(n1->stptr + n1->stlen, n2->stptr, n2->stlen);
n1->stlen = nlen;
n1->stptr[nlen] = '\0';
@@ -1378,6 +1567,7 @@ common_exp
bcfree($2);
$$ = $1;
} else {
+ plain_concat:
$$ = list_append(list_merge($1, $2), instruction(Op_concat));
$$->lasti->concat_flag = (is_simple_var ? CSVAR : 0);
$$->lasti->expr_count = count;
@@ -1481,7 +1671,7 @@ non_post_simp_exp
if ($2->opcode == Op_match_rec) {
$2->opcode = Op_nomatch;
$1->opcode = Op_push_i;
- $1->memory = make_number(0.0);
+ $1->memory = make_profile_number(0.0, "0", 1);
$$ = list_append(list_append(list_create($1),
instruction(Op_field_spec)), $2);
} else {
@@ -1490,7 +1680,7 @@ non_post_simp_exp
&& ($2->nexti->memory->flags & (MPFN|MPZN)) == 0
) {
NODE *n = $2->nexti->memory;
- if ((n->flags & (STRCUR|STRING)) != 0) {
+ if ((n->flags & STRING) != 0) {
n->numbr = (AWKNUM) (n->stlen == 0);
n->flags &= ~(STRCUR|STRING);
n->flags |= (NUMCUR|NUMBER);
@@ -1510,13 +1700,13 @@ non_post_simp_exp
}
| '(' exp r_paren
{ $$ = $2; }
- | LEX_BUILTIN '(' opt_expression_list r_paren
+ | LEX_BUILTIN '(' opt_fcall_expression_list r_paren
{
$$ = snode($3, $1);
if ($$ == NULL)
YYABORT;
}
- | LEX_LENGTH '(' opt_expression_list r_paren
+ | LEX_LENGTH '(' opt_fcall_expression_list r_paren
{
$$ = snode($3, $1);
if ($$ == NULL)
@@ -1558,11 +1748,11 @@ non_post_simp_exp
| '-' simp_exp %prec UNARY
{
if ($2->lasti->opcode == Op_push_i
- && ($2->lasti->memory->flags & (STRCUR|STRING)) == 0
+ && ($2->lasti->memory->flags & STRING) == 0
) {
NODE *n = $2->lasti->memory;
(void) force_number(n);
- negate_num(n);
+ negate_num(n);
$$ = $2;
bcfree($1);
} else {
@@ -1572,13 +1762,21 @@ non_post_simp_exp
}
| '+' simp_exp %prec UNARY
{
- /*
- * was: $$ = $2
- * POSIX semantics: force a conversion to numeric type
- */
- $1->opcode = Op_plus_i;
- $1->memory = make_number(0.0);
- $$ = list_append($2, $1);
+ if ($2->lasti->opcode == Op_push_i
+ && ($2->lasti->memory->flags & STRING) == 0
+ && ($2->lasti->memory->flags & NUMCONSTSTR) != 0) {
+ NODE *n = $2->lasti->memory;
+ add_sign_to_num(n, '+');
+ $$ = $2;
+ bcfree($1);
+ } else {
+ /*
+ * was: $$ = $2
+ * POSIX semantics: force a conversion to numeric type
+ */
+ $1->opcode = Op_unary_plus;
+ $$ = list_append($2, $1);
+ }
}
;
@@ -1603,7 +1801,7 @@ func_call
warned = true;
lintwarn("%s", msg);
}
-
+
f = $2->lasti;
f->opcode = Op_indirect_func_call;
name = estrdup(f->func_name, strlen(f->func_name));
@@ -1625,14 +1823,14 @@ func_call
;
direct_func_call
- : FUNC_CALL '(' opt_expression_list r_paren
+ : FUNC_CALL '(' opt_fcall_expression_list r_paren
{
NODE *n;
if (! at_seen) {
n = lookup($1->func_name);
if (n != NULL && n->type != Node_func
- && n->type != Node_ext_func && n->type != Node_old_ext_func) {
+ && n->type != Node_ext_func) {
error_ln($1->source_line,
_("attempt to use non-function `%s' in function call"),
$1->func_name);
@@ -1646,7 +1844,7 @@ direct_func_call
$$ = list_create($1);
} else {
INSTRUCTION *t = $3;
- ($1 + 1)->expr_count = count_expressions(&t, true);
+ ($1 + 1)->expr_count = count_expressions(&t, true);
$$ = list_append(t, $1);
}
}
@@ -1678,7 +1876,7 @@ delete_subscript
delete_exp_list
: bracketed_exp_list
{
- INSTRUCTION *ip = $1->lasti;
+ INSTRUCTION *ip = $1->lasti;
int count = ip->sub_count; /* # of SUBSEP-seperated expressions */
if (count > 1) {
/* change Op_subscript or Op_sub_array to Op_concat */
@@ -1702,7 +1900,7 @@ bracketed_exp_list
/* install Null string as subscript. */
t = list_create(instruction(Op_push_i));
t->nexti->memory = dupnode(Nnull_string);
- $3->sub_count = 1;
+ $3->sub_count = 1;
} else
$3->sub_count = count_expressions(&t, false);
$$ = list_append(t, $3);
@@ -1818,7 +2016,7 @@ struct token {
# define BREAK 0x0800 /* break allowed inside */
# define CONTINUE 0x1000 /* continue allowed inside */
# define DEBUG_USE 0x2000 /* for use by developers */
-
+
NODE *(*ptr)(int); /* function that implements this keyword */
NODE *(*ptr2)(int); /* alternate arbitrary-precision function */
};
@@ -1878,9 +2076,6 @@ static const struct token tokentab[] = {
{"eval", Op_symbol, LEX_EVAL, 0, 0, 0},
{"exit", Op_K_exit, LEX_EXIT, 0, 0, 0},
{"exp", Op_builtin, LEX_BUILTIN, A(1), do_exp, MPF(exp)},
-#ifdef DYNAMIC
-{"extension", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2)|A(3), do_ext, 0},
-#endif
{"fflush", Op_builtin, LEX_BUILTIN, A(0)|A(1), do_fflush, 0},
{"for", Op_K_for, LEX_FOR, BREAK|CONTINUE, 0, 0},
{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0, 0},
@@ -1893,6 +2088,7 @@ static const struct token tokentab[] = {
{"include", Op_symbol, LEX_INCLUDE, GAWKX, 0, 0},
{"index", Op_builtin, LEX_BUILTIN, A(2), do_index, 0},
{"int", Op_builtin, LEX_BUILTIN, A(1), do_int, MPF(int)},
+{"intdiv", Op_builtin, LEX_BUILTIN, GAWKX|A(3), do_intdiv, MPF(intdiv)},
{"isarray", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_isarray, 0},
{"length", Op_builtin, LEX_LENGTH, A(0)|A(1), do_length, 0},
{"load", Op_symbol, LEX_LOAD, GAWKX, 0, 0},
@@ -1926,6 +2122,7 @@ static const struct token tokentab[] = {
{"systime", Op_builtin, LEX_BUILTIN, GAWKX|A(0), do_systime, 0},
{"tolower", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_tolower, 0},
{"toupper", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_toupper, 0},
+{"typeof", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_typeof, 0},
{"while", Op_K_while, LEX_WHILE, BREAK|CONTINUE, 0, 0},
{"xor", Op_builtin, LEX_BUILTIN, GAWKX, do_xor, MPF(xor)},
};
@@ -1951,7 +2148,7 @@ getfname(NODE *(*fptr)(int))
j = sizeof(tokentab) / sizeof(tokentab[0]);
/* linear search, no other way to do it */
- for (i = 0; i < j; i++)
+ for (i = 0; i < j; i++)
if (tokentab[i].ptr == fptr || tokentab[i].ptr2 == fptr)
return tokentab[i].operator;
@@ -1967,6 +2164,8 @@ negate_num(NODE *n)
int tval = 0;
#endif
+ add_sign_to_num(n, '-');
+
if (! is_mpg_number(n)) {
n->numbr = -n->numbr;
return;
@@ -1999,6 +2198,21 @@ negate_num(NODE *n)
#endif
}
+/* add_sign_to_num --- make a constant unary plus or minus for profiling */
+
+static void
+add_sign_to_num(NODE *n, char sign)
+{
+ if ((n->flags & NUMCONSTSTR) != 0) {
+ char *s;
+
+ s = n->stptr;
+ memmove(& s[1], & s[0], n->stlen + 1);
+ s[0] = sign;
+ n->stlen++;
+ }
+}
+
/* print_included_from --- print `Included from ..' file names and locations */
static void
@@ -2007,7 +2221,7 @@ print_included_from()
int saveline, line;
SRCFILE *s;
- /* suppress current file name, line # from `.. included from ..' msgs */
+ /* suppress current file name, line # from `.. included from ..' msgs */
saveline = sourceline;
sourceline = 0;
@@ -2101,7 +2315,6 @@ yyerror(const char *m, ...)
char *buf;
int count;
static char end_of_file_line[] = "(END OF FILE)";
- char save;
print_included_from();
@@ -2132,25 +2345,17 @@ yyerror(const char *m, ...)
bp = thisline + strlen(thisline);
}
- /*
- * Saving and restoring *bp keeps valgrind happy,
- * since the guts of glibc uses strlen, even though
- * we're passing an explict precision. Sigh.
- *
- * 8/2003: We may not need this anymore.
- */
- save = *bp;
- *bp = '\0';
-
msg("%.*s", (int) (bp - thisline), thisline);
- *bp = save;
va_start(args, m);
if (mesg == NULL)
mesg = m;
- count = (bp - thisline) + strlen(mesg) + 2 + 1;
- emalloc(buf, char *, count, "yyerror");
+ count = strlen(mesg) + 1;
+ if (lexptr != NULL)
+ count += (lexeme - thisline) + 2;
+ emalloc(buf, char *, count+1, "yyerror");
+ memset(buf, 0, count+1);
bp = buf;
@@ -2217,7 +2422,7 @@ mk_program()
if (prog_block == NULL) {
if (end_block->nexti == end_block->lasti
- && beginfile_block->nexti == beginfile_block->lasti
+ && beginfile_block->nexti == beginfile_block->lasti
&& endfile_block->nexti == endfile_block->lasti
) {
/* no pattern-action and (real) end, beginfile or endfile blocks */
@@ -2232,6 +2437,11 @@ mk_program()
cp = end_block;
else
cp = list_merge(begin_block, end_block);
+ if (program_comment != NULL) {
+ (void) list_prepend(cp, program_comment);
+ }
+ if (comment != NULL)
+ (void) list_append(cp, comment);
(void) list_append(cp, ip_atexit);
(void) list_append(cp, instruction(Op_stop));
@@ -2254,7 +2464,7 @@ mk_program()
(void) list_prepend(prog_block, ip_rec);
(void) list_append(prog_block, instruction(Op_jmp));
prog_block->lasti->target_jmp = ip_rec;
-
+
list_append(beginfile_block, instruction(Op_after_beginfile));
cp = list_merge(beginfile_block, prog_block);
@@ -2264,6 +2474,12 @@ mk_program()
if (begin_block != NULL)
cp = list_merge(begin_block, cp);
+ if (program_comment != NULL) {
+ (void) list_prepend(cp, program_comment);
+ }
+ if (comment != NULL) {
+ (void) list_append(cp, comment);
+ }
(void) list_append(cp, ip_atexit);
(void) list_append(cp, instruction(Op_stop));
@@ -2271,13 +2487,17 @@ out:
/* delete the Op_list, not needed */
tmp = cp->nexti;
bcfree(cp);
+ /* these variables are not used again but zap them anyway. */
+ comment = NULL;
+ function_comment = NULL;
+ program_comment = NULL;
return tmp;
#undef begin_block
#undef end_block
#undef prog_block
#undef beginfile_block
-#undef endfile_block
+#undef endfile_block
}
/* parse_program --- read in the program and convert into a list of instructions */
@@ -2297,7 +2517,7 @@ parse_program(INSTRUCTION **pcode)
ip_newfile = ip_rec = ip_atexit = ip_beginfile = ip_endfile = NULL;
else {
ip_endfile = instruction(Op_no_op);
- ip_beginfile = instruction(Op_no_op);
+ main_beginfile = ip_beginfile = instruction(Op_no_op);
ip_rec = instruction(Op_get_record); /* target for `next', also ip_newfile */
ip_newfile = bcalloc(Op_newfile, 2, 0); /* target for `nextfile' */
ip_newfile->target_jmp = ip_end;
@@ -2428,7 +2648,7 @@ add_srcfile(enum srctype stype, char *src, SRCFILE *thisfile, bool *already_incl
*already_included = true;
return NULL;
} else {
- /* duplicates are allowed for -f */
+ /* duplicates are allowed for -f */
if (s->stype == SRC_INC)
fatal(_("can't include `%s' and use it as a program file"), src);
/* no need to scan for further matches, since
@@ -2479,11 +2699,11 @@ include_source(INSTRUCTION *file)
sourcefile->srclines = sourceline;
sourcefile->lexptr = lexptr;
sourcefile->lexend = lexend;
- sourcefile->lexptr_begin = lexptr_begin;
+ sourcefile->lexptr_begin = lexptr_begin;
sourcefile->lexeme = lexeme;
sourcefile->lasttok = lasttok;
- /* included file becomes the current source */
+ /* included file becomes the current source */
sourcefile = s;
lexptr = NULL;
sourceline = 0;
@@ -2768,7 +2988,7 @@ get_src_buf()
lexend = lexptr + n;
if (n == 0) {
static bool warned = false;
- if (do_lint && newfile && ! warned){
+ if (do_lint && newfile && ! warned) {
warned = true;
sourceline = 0;
lintwarn(_("source file `%s' is empty"), source);
@@ -2790,7 +3010,7 @@ tokexpand()
{
static int toksize;
int tokoffset;
-
+
if (tokstart != NULL) {
tokoffset = tok - tokstart;
toksize *= 2;
@@ -2858,8 +3078,8 @@ again:
int idx, work_ring_idx = cur_ring_idx;
mbstate_t tmp_state;
size_t mbclen;
-
- for (idx = 0 ; lexptr + idx < lexend ; idx++) {
+
+ for (idx = 0; lexptr + idx < lexend; idx++) {
tmp_state = cur_mbstate;
mbclen = mbrlen(lexptr, idx + 1, &tmp_state);
@@ -2916,6 +3136,122 @@ pushback(void)
(! lexeof && lexptr && lexptr > lexptr_begin ? lexptr-- : lexptr);
}
+/* check_comment --- check for block comment */
+
+void
+check_comment(void)
+{
+ if (comment != NULL) {
+ if (first_rule) {
+ program_comment = comment;
+ } else
+ block_comment = comment;
+ comment = NULL;
+ }
+ first_rule = false;
+}
+
+/*
+ * get_comment --- collect comment text.
+ * Flag = EOL_COMMENT for end-of-line comments.
+ * Flag = FULL_COMMENT for self-contained comments.
+ */
+
+int
+get_comment(int flag)
+{
+ int c;
+ int sl;
+ tok = tokstart;
+ tokadd('#');
+ sl = sourceline;
+ char *p1;
+ char *p2;
+
+ while (true) {
+ while ((c = nextc(false)) != '\n' && c != END_FILE) {
+ /* ignore \r characters */
+ if (c != '\r')
+ tokadd(c);
+ }
+ if (flag == EOL_COMMENT) {
+ /* comment at end of line. */
+ if (c == '\n')
+ tokadd(c);
+ break;
+ }
+ if (c == '\n') {
+ tokadd(c);
+ sourceline++;
+ do {
+ c = nextc(false);
+ if (c == '\n') {
+ sourceline++;
+ tokadd(c);
+ }
+ } while (isspace(c) && c != END_FILE);
+ if (c == END_FILE)
+ break;
+ else if (c != '#') {
+ pushback();
+ sourceline--;
+ break;
+ } else
+ tokadd(c);
+ } else
+ break;
+ }
+
+ if (comment != NULL)
+ prior_comment = comment;
+
+ /* remove any trailing blank lines (consecutive \n) from comment */
+ p1 = tok - 1;
+ p2 = tok - 2;
+ while (*p1 == '\n' && *p2 == '\n') {
+ p1--;
+ p2--;
+ tok--;
+ }
+
+ comment = bcalloc(Op_comment, 1, sl);
+ comment->source_file = source;
+ comment->memory = make_str_node(tokstart, tok - tokstart, 0);
+ comment->memory->comment_type = flag;
+
+ return c;
+}
+
+/* split_comment --- split initial comment text into program and function parts */
+
+static void
+split_comment(void)
+{
+ char *p;
+ int l;
+ NODE *n;
+
+ p = comment_to_save->memory->stptr;
+ l = comment_to_save->memory->stlen - 3;
+ /* have at least two comments so split at last blank line (\n\n) */
+ while (l >= 0) {
+ if (p[l] == '\n' && p[l+1] == '\n') {
+ function_comment = comment_to_save;
+ n = function_comment->memory;
+ function_comment->memory = make_str_node(p + l + 2, n->stlen - l - 2, 0);
+ /* create program comment */
+ program_comment = bcalloc(Op_comment, 1, sourceline);
+ program_comment->source_file = comment_to_save->source_file;
+ p[l + 2] = 0;
+ program_comment->memory = make_str_node(p, l + 2, 0);
+ comment_to_save = NULL;
+ freenode(n);
+ break;
+ }
+ else
+ l--;
+ }
+}
/* allow_newline --- allow newline after &&, ||, ? and : */
@@ -2931,8 +3267,13 @@ allow_newline(void)
break;
}
if (c == '#') {
- while ((c = nextc(false)) != '\n' && c != END_FILE)
- continue;
+ if (do_pretty_print && ! do_profile) {
+ /* collect comment byte code iff doing pretty print but not profiling. */
+ c = get_comment(EOL_COMMENT);
+ } else {
+ while ((c = nextc(false)) != '\n' && c != END_FILE)
+ continue;
+ }
if (c == END_FILE) {
pushback();
break;
@@ -2955,7 +3296,8 @@ allow_newline(void)
* removes the warnings.
*/
-static int newline_eof()
+static int
+newline_eof()
{
/* NB: a newline at end does not start a source line. */
if (lasttok != NEWLINE) {
@@ -3003,7 +3345,7 @@ yylex(void)
lasttok = 0;
return SUBSCRIPT;
}
-
+
if (lasttok == LEX_EOF) /* error earlier in current source, must give up !! */
return 0;
@@ -3027,6 +3369,7 @@ yylex(void)
lexeme = lexptr;
thisline = NULL;
+
if (want_regexp) {
int in_brack = 0; /* count brackets, [[:alnum:]] allowed */
int b_index = -1;
@@ -3037,7 +3380,7 @@ yylex(void)
*
* [..[..] []] [^]] [.../...]
* [...\[...] [...\]...] [...\/...]
- *
+ *
* (Remember that all of the above are inside /.../)
*
* The code for \ handles \[, \] and \/.
@@ -3066,7 +3409,7 @@ yylex(void)
break;
case ']':
if (in_brack > 0
- && (cur_index == b_index + 1
+ && (cur_index == b_index + 1
|| (cur_index == b_index + 2 && tok[-1] == '^')))
; /* do nothing */
else {
@@ -3113,7 +3456,9 @@ end_regexp:
peek);
}
}
- return lasttok = REGEXP;
+ lasttok = REGEXP;
+
+ return lasttok;
case '\n':
pushback();
yyerror(_("unterminated regexp"));
@@ -3149,9 +3494,23 @@ retry:
return lasttok = NEWLINE;
case '#': /* it's a comment */
- while ((c = nextc(false)) != '\n') {
+ if (do_pretty_print && ! do_profile) {
+ /*
+ * Collect comment byte code iff doing pretty print
+ * but not profiling.
+ */
+ if (lasttok == NEWLINE || lasttok == 0)
+ c = get_comment(FULL_COMMENT);
+ else
+ c = get_comment(EOL_COMMENT);
+
if (c == END_FILE)
return lasttok = NEWLINE_EOF;
+ } else {
+ while ((c = nextc(false)) != '\n') {
+ if (c == END_FILE)
+ return lasttok = NEWLINE_EOF;
+ }
}
sourceline++;
return lasttok = NEWLINE;
@@ -3163,7 +3522,7 @@ retry:
case '\\':
#ifdef RELAXED_CONTINUATION
/*
- * This code puports to allow comments and/or whitespace
+ * This code purports to allow comments and/or whitespace
* after the `\' at the end of a line used for continuation.
* Use it at your own risk. We think it's a bad idea, which
* is why it's not on by default.
@@ -3180,9 +3539,13 @@ retry:
lintwarn(
_("use of `\\ #...' line continuation is not portable"));
}
- while ((c = nextc(false)) != '\n')
- if (c == END_FILE)
- break;
+ if (do_pretty_print && ! do_profile)
+ c = get_comment(EOL_COMMENT);
+ else {
+ while ((c = nextc(false)) != '\n')
+ if (c == END_FILE)
+ break;
+ }
}
pushback();
}
@@ -3214,7 +3577,7 @@ retry:
in_parens--;
return lasttok = c;
- case '(':
+ case '(':
in_parens++;
return lasttok = c;
case '$':
@@ -3317,7 +3680,7 @@ retry:
did_warn_op = true;
warning(_("operator `^' is not supported in old awk"));
}
- yylval = GET_INSTRUCTION(Op_exp);
+ yylval = GET_INSTRUCTION(Op_exp);
return lasttok = '^';
}
@@ -3398,7 +3761,7 @@ retry:
lastline = sourceline;
return lasttok = c;
}
- did_newline++;
+ did_newline = true;
--lexptr; /* pick up } next time */
return lasttok = NEWLINE;
@@ -3440,7 +3803,7 @@ retry:
yylval->lextok = estrdup(tokstart, tok - tokstart);
return lasttok = FILENAME;
}
-
+
yylval->opcode = Op_push_i;
yylval->memory = make_str_node(tokstart,
tok - tokstart, esc_seen ? SCAN : 0);
@@ -3606,14 +3969,19 @@ retry:
IEEE_FMT(r->mpg_numbr, tval);
}
yylval->memory = r;
+ if (do_pretty_print) {
+ yylval->memory->stptr = estrdup(tokstart, strlen(tokstart)-1);
+ yylval->memory->stlen = strlen(tokstart)-1;
+ yylval->memory->flags |= NUMCONSTSTR;
+ }
return lasttok = YNUMBER;
}
#endif
if (base != 10)
- d = nondec2awknum(tokstart, strlen(tokstart));
+ d = nondec2awknum(tokstart, strlen(tokstart), NULL);
else
d = atof(tokstart);
- yylval->memory = make_number(d);
+ yylval->memory = make_profile_number(d, tokstart, strlen(tokstart) - 1);
if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d)
yylval->memory->flags |= NUMINT;
return lasttok = YNUMBER;
@@ -3696,6 +4064,33 @@ retry:
&& lasttok != '@')
goto out;
+ /* allow parameter names to shadow the names of gawk extension built-ins */
+ if ((tokentab[mid].flags & GAWKX) != 0) {
+ NODE *f;
+
+ switch (want_param_names) {
+ case FUNC_HEADER:
+ /* in header, defining parameter names */
+ goto out;
+ case FUNC_BODY:
+ /* in body, name must be in symbol table for it to be a parameter */
+ if ((f = lookup(tokstart)) != NULL) {
+ if (f->type == Node_builtin_func)
+ break;
+ else
+ goto out;
+ }
+ /* else
+ fall through */
+ case DONT_CHECK:
+ /* regular code */
+ break;
+ default:
+ cant_happen();
+ break;
+ }
+ }
+
if (do_lint) {
if ((tokentab[mid].flags & GAWKX) != 0 && (warntab[mid] & GAWKX) == 0) {
lintwarn(_("`%s' is a gawk extension"),
@@ -3740,7 +4135,7 @@ retry:
case LEX_BEGIN:
case LEX_END:
case LEX_BEGINFILE:
- case LEX_ENDFILE:
+ case LEX_ENDFILE:
yylval = bcalloc(tokentab[mid].value, 3, sourceline);
break;
@@ -3789,7 +4184,7 @@ out:
tokkey = estrdup(tokstart, tok - tokstart);
if (*lexptr == '(') {
yylval = bcalloc(Op_token, 2, sourceline);
- yylval->lextok = tokkey;
+ yylval->lextok = tokkey;
return lasttok = FUNC_CALL;
} else {
static bool goto_warned = false;
@@ -3865,7 +4260,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
nexp++;
}
assert(nexp > 0);
- }
+ }
/* check against how many args. are allowed for this builtin */
args_allowed = tokentab[idx].flags & ARGS;
@@ -3896,7 +4291,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
INSTRUCTION *expr;
expr = list_create(instruction(Op_push_i));
- expr->nexti->memory = make_number(0.0);
+ expr->nexti->memory = make_profile_number(0.0, "0", 1);
(void) mk_expression_list(subn,
list_append(expr, instruction(Op_field_spec)));
}
@@ -3936,7 +4331,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
subn->lasti->assign_ctxt = Op_sub_builtin;
}
- return subn;
+ return subn;
} else {
/* gensub */
@@ -3944,7 +4339,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
r->sub_flags |= GENSUB;
if (nexp == 3) {
ip = instruction(Op_push_i);
- ip->memory = make_number(0.0);
+ ip->memory = make_profile_number(0.0, "0", 1);
(void) mk_expression_list(subn,
list_append(list_create(ip), instruction(Op_field_spec)));
}
@@ -3955,7 +4350,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
}
#ifdef HAVE_MPFR
- /* N.B.: There isn't any special processing for an alternate function below */
+ /* N.B.: If necessary, add special processing for alternate builtin, below */
if (do_mpfr && tokentab[idx].ptr2)
r->builtin = tokentab[idx].ptr2;
else
@@ -3965,25 +4360,34 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
/* special case processing for a few builtins */
if (r->builtin == do_length) {
- if (nexp == 0) {
+ if (nexp == 0) {
/* no args. Use $0 */
INSTRUCTION *list;
- r->expr_count = 1;
+ r->expr_count = 1;
list = list_create(r);
(void) list_prepend(list, instruction(Op_field_spec));
(void) list_prepend(list, instruction(Op_push_i));
- list->nexti->memory = make_number(0.0);
- return list;
+ list->nexti->memory = make_profile_number(0.0, "0", 1);
+ return list;
} else {
arg = subn->nexti;
if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push)
arg->nexti->opcode = Op_push_arg; /* argument may be array */
}
- } else if (r->builtin == do_isarray) {
+ } else if (r->builtin == do_isarray || r->builtin == do_typeof) {
arg = subn->nexti;
if (arg->nexti == arg->lasti && arg->nexti->opcode == Op_push)
- arg->nexti->opcode = Op_push_arg; /* argument may be array */
+ arg->nexti->opcode = Op_push_arg_untyped; /* argument may be untyped */
+ } else if (r->builtin == do_intdiv
+#ifdef HAVE_MPFR
+ || r->builtin == MPF(intdiv)
+#endif
+ ) {
+ arg = subn->nexti->lasti->nexti->lasti->nexti; /* 3rd arg list */
+ ip = arg->lasti;
+ if (ip->opcode == Op_push)
+ ip->opcode = Op_push_array;
} else if (r->builtin == do_match) {
static bool warned = false;
@@ -4060,7 +4464,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
} else if (do_intl /* --gen-po */
&& r->builtin == do_dcgettext /* dcgettext(...) */
&& subn->nexti->lasti->opcode == Op_push_i /* 1st arg is constant */
- && (subn->nexti->lasti->memory->flags & STRCUR) != 0) { /* it's a string constant */
+ && (subn->nexti->lasti->memory->flags & STRING) != 0) { /* it's a string constant */
/* ala xgettext, dcgettext("some string" ...) dumps the string */
NODE *str = subn->nexti->lasti->memory;
@@ -4072,9 +4476,9 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
} else if (do_intl /* --gen-po */
&& r->builtin == do_dcngettext /* dcngettext(...) */
&& subn->nexti->lasti->opcode == Op_push_i /* 1st arg is constant */
- && (subn->nexti->lasti->memory->flags & STRCUR) != 0 /* it's a string constant */
+ && (subn->nexti->lasti->memory->flags & STRING) != 0 /* it's a string constant */
&& subn->nexti->lasti->nexti->lasti->opcode == Op_push_i /* 2nd arg is constant too */
- && (subn->nexti->lasti->nexti->lasti->memory->flags & STRCUR) != 0) { /* it's a string constant */
+ && (subn->nexti->lasti->nexti->lasti->memory->flags & STRING) != 0) { /* it's a string constant */
/* ala xgettext, dcngettext("some string", "some plural" ...) dumps the string */
NODE *str1 = subn->nexti->lasti->memory;
NODE *str2 = subn->nexti->lasti->nexti->lasti->memory;
@@ -4181,18 +4585,6 @@ valinfo(NODE *n, Func_print print_func, FILE *fp)
else
#endif
print_func(fp, "%.17g\n", n->numbr);
- } else if ((n->flags & STRCUR) != 0) {
- pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', false);
- print_func(fp, "\n");
- } else if ((n->flags & NUMCUR) != 0) {
-#ifdef HAVE_MPFR
- if (is_mpg_float(n))
- print_func(fp, "%s\n", mpg_fmt("%.17R*g", ROUND_MODE, n->mpg_numbr));
- else if (is_mpg_integer(n))
- print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i));
- else
-#endif
- print_func(fp, "%.17g\n", n->numbr);
} else
print_func(fp, "?? flags %s\n", flags2str(n->flags));
}
@@ -4281,6 +4673,14 @@ mk_function(INSTRUCTION *fi, INSTRUCTION *def)
(t + 1)->tail_call = true;
}
+ /* add any pre-function comment to start of action for profile.c */
+
+ if (function_comment != NULL) {
+ function_comment->source_line = 0;
+ (void) list_prepend(def, function_comment);
+ function_comment = NULL;
+ }
+
/* add an implicit return at end;
* also used by 'return' command in debugger
*/
@@ -4310,7 +4710,7 @@ mk_function(INSTRUCTION *fi, INSTRUCTION *def)
return fi;
}
-/*
+/*
* install_function:
* install function name in the symbol table.
* Extra work, build up and install a list of the parameter names.
@@ -4334,7 +4734,7 @@ install_function(char *fname, INSTRUCTION *fi, INSTRUCTION *plist)
fi->func_body = f;
f->param_cnt = pcount;
f->code_ptr = fi;
- f->fparms = NULL;
+ f->fparms = NULL;
if (pcount > 0) {
char **pnames;
pnames = check_params(fname, pcount, plist); /* frees plist */
@@ -4391,7 +4791,7 @@ check_params(char *fname, int pcount, INSTRUCTION *list)
}
bcfree(list);
- return pnames;
+ return pnames;
}
@@ -4399,7 +4799,7 @@ check_params(char *fname, int pcount, INSTRUCTION *list)
undef HASHSIZE
#endif
#define HASHSIZE 1021
-
+
static struct fdesc {
char *name;
short used;
@@ -4461,7 +4861,7 @@ check_funcs()
if (! in_main_context())
goto free_mem;
-
+
for (i = 0; i < HASHSIZE; i++) {
for (fp = ftable[i]; fp != NULL; fp = fp->next) {
#ifdef REALLYMEAN
@@ -4555,6 +4955,7 @@ make_regnode(int type, NODE *exp)
}
n->re_exp = exp;
n->re_flags = CONSTANT;
+ n->valref = 1;
}
return n;
}
@@ -4570,6 +4971,8 @@ mk_rexp(INSTRUCTION *list)
ip = list->nexti;
if (ip == list->lasti && ip->opcode == Op_match_rec)
ip->opcode = Op_push_re;
+ else if (ip == list->lasti && ip->opcode == Op_push_re)
+ ; /* do nothing --- @/.../ */
else {
ip = instruction(Op_push_re);
ip->memory = make_regnode(Node_dynregex, NULL);
@@ -4764,6 +5167,8 @@ mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op)
}
op->opcode = Op_push_i;
+ // We don't need to call make_profile_number() here since
+ // optimizing is disabled when doing pretty printing.
op->memory = make_number(res);
unref(n1);
unref(n2);
@@ -4796,7 +5201,7 @@ mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op)
break;
default:
goto regular;
- }
+ }
op->memory = ip2->memory;
bcfree(ip2);
@@ -4812,7 +5217,7 @@ regular:
}
/* mk_boolean --- instructions for boolean and, or */
-
+
static INSTRUCTION *
mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op)
{
@@ -4840,7 +5245,7 @@ mk_boolean(INSTRUCTION *left, INSTRUCTION *right, INSTRUCTION *op)
right->lasti->target_stmt = left->lasti;
} else { /* optimization for x || y || z || ... */
INSTRUCTION *ip;
-
+
op->opcode = final_opc;
(void) list_append(right, op);
op->target_stmt = tp;
@@ -4877,7 +5282,7 @@ mk_condition(INSTRUCTION *cond, INSTRUCTION *ifp, INSTRUCTION *true_branch,
*
* ----------------
* [Op_jmp y]
- * ----------------
+ * ----------------
* f:
* false_branch
* ----------------
@@ -4985,7 +5390,11 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action)
(rp + 1)->lasti = action->lasti;
(rp + 2)->first_line = pattern->source_line;
(rp + 2)->last_line = lastline;
- ip = list_prepend(action, rp);
+ if (block_comment != NULL) {
+ ip = list_prepend(list_prepend(action, block_comment), rp);
+ block_comment = NULL;
+ } else
+ ip = list_prepend(action, rp);
} else {
rp = bcalloc(Op_rule, 3, 0);
@@ -5027,7 +5436,6 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action)
action),
tp);
}
-
}
list_append(rule_list, rp + 1);
@@ -5036,7 +5444,7 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action)
rule_block[rule] = ip;
else
(void) list_merge(rule_block[rule], ip);
-
+
return rule_block[rule];
}
@@ -5058,7 +5466,7 @@ mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, INSTRUCTION *op)
break;
case Op_push:
case Op_push_array:
- tp->opcode = Op_push_lhs;
+ tp->opcode = Op_push_lhs;
break;
case Op_field_assign:
yyerror(_("cannot assign a value to the result of a field post-increment expression"));
@@ -5113,7 +5521,7 @@ optimize_assignment(INSTRUCTION *exp)
* Replaces Op_push_array + Op_subscript_lhs + Op_assign + Op_pop
* with single instruction Op_store_sub.
* Limitation: 1 dimension and sub is simple var/value.
- *
+ *
* 2) Simple variable assignment var = x:
* Replaces Op_push_lhs + Op_assign + Op_pop with Op_store_var.
*
@@ -5137,7 +5545,7 @@ optimize_assignment(INSTRUCTION *exp)
i1 = exp->lasti;
if ( i1->opcode != Op_assign
- && i1->opcode != Op_field_assign)
+ && i1->opcode != Op_field_assign)
return list_append(exp, instruction(Op_pop));
for (i2 = exp->nexti; i2 != i1; i2 = i2->nexti) {
@@ -5212,7 +5620,7 @@ optimize_assignment(INSTRUCTION *exp)
* so use expr_count instead.
*/
i3->nexti = NULL;
- i2->opcode = Op_no_op;
+ i2->opcode = Op_no_op;
bcfree(i1); /* Op_assign */
exp->lasti = i3; /* update Op_list */
return exp;
@@ -5235,7 +5643,7 @@ optimize_assignment(INSTRUCTION *exp)
&& (i3->memory->flags & INTLSTR) == 0
&& i3->nexti == i2
) {
- /* constant initializer */
+ /* constant initializer */
i2->initval = i3->memory;
bcfree(i3);
exp->nexti = i2;
@@ -5271,7 +5679,7 @@ mk_getline(INSTRUCTION *op, INSTRUCTION *var, INSTRUCTION *redir, int redirtype)
* [ file (simp_exp)]
* [ [ var ] ]
* [ Op_K_getline_redir|NULL|redir_type|into_var]
- * [ [var_assign] ]
+ * [ [var_assign] ]
*
*/
@@ -5280,7 +5688,7 @@ mk_getline(INSTRUCTION *op, INSTRUCTION *var, INSTRUCTION *redir, int redirtype)
bcfree(op);
op = bcalloc(Op_K_getline, 2, sline);
(op + 1)->target_endfile = ip_endfile;
- (op + 1)->target_beginfile = ip_beginfile;
+ (op + 1)->target_beginfile = ip_beginfile;
}
if (var != NULL) {
@@ -5338,11 +5746,11 @@ mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond,
* ------------------------
* body (may be NULL)
* ------------------------
- * tc:
+ * tc:
* incr (may be NULL)
- * [ Op_jmp x ]
+ * [ Op_jmp x ]
* ------------------------
- * tb:[ Op_no_op ]
+ * tb:[ Op_no_op ]
*/
INSTRUCTION *ip, *tbreak, *tcont;
@@ -5454,7 +5862,7 @@ mk_expression_list(INSTRUCTION *list, INSTRUCTION *s1)
/* we can't just combine all bytecodes, since we need to
* process individual expressions for a few builtins in snode() (-:
*/
-
+
/* -- list of lists */
/* [Op_list| ... ]------
* |
@@ -5510,7 +5918,7 @@ count_expressions(INSTRUCTION **list, bool isarg)
(void) list_merge(r, expr);
expr = t2->nexti;
}
-
+
assert(count > 0);
if (! isarg && count > max_args)
max_args = count;
@@ -5597,6 +6005,26 @@ list_merge(INSTRUCTION *l1, INSTRUCTION *l2)
return l1;
}
+/* add_pending_comment --- add a pending comment to a statement */
+
+static inline INSTRUCTION *
+add_pending_comment(INSTRUCTION *stmt)
+{
+ INSTRUCTION *ret = stmt;
+
+ if (prior_comment != NULL) {
+ if (function_comment != prior_comment)
+ ret = list_append(stmt, prior_comment);
+ prior_comment = NULL;
+ } else if (comment != NULL && comment->memory->comment_type == EOL_COMMENT) {
+ if (function_comment != comment)
+ ret = list_append(stmt, comment);
+ comment = NULL;
+ }
+
+ return ret;
+}
+
/* See if name is a special token. */
int
@@ -5756,7 +6184,7 @@ install_builtins(void)
* The scene of the murder was grisly to look upon. When the inspector
* arrived, the sergeant turned to him and said, "Another programmer stabbed
* in the back. He never knew what happened."
- *
+ *
* The inspector replied, "Looks like the MO of isalpha, and his even meaner
* big brother, isalnum. The Locale brothers." The sergeant merely
* shuddered in horror.
@@ -5802,3 +6230,25 @@ is_identchar(int c)
{
return (is_alnum(c) || c == '_');
}
+
+/* make_profile_number --- make a number that can be printed when profiling */
+
+static NODE *
+make_profile_number(double d, const char *str, size_t len)
+{
+ NODE *n = make_number(d);
+ if (do_pretty_print) {
+ // extra byte in case need to add minus sign in negate_num
+ n->stptr = estrdup(str, len + 1);
+ n->stptr[len] = '\0';
+ n->stlen = len;
+ // Set STRCUR and n->stfmt for use when profiling
+ // (i.e., actually running the program) so that
+ // force_string() on this item will work ok.
+ // Thanks and a tip of the hatlo to valgrind.
+ n->flags |= (NUMCONSTSTR|STRCUR);
+ n->stfmt = STFMT_UNUSED;
+ }
+
+ return n;
+}