aboutsummaryrefslogtreecommitdiffstats
path: root/awkgram.y
diff options
context:
space:
mode:
Diffstat (limited to 'awkgram.y')
-rw-r--r--awkgram.y727
1 files changed, 437 insertions, 290 deletions
diff --git a/awkgram.y b/awkgram.y
index 1afad27e..af2c326e 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -1,3 +1,24 @@
+/* working on statement_term and opt_nls */
+/*
+TODO:
+-- Handle comments outside blocks
+-- Handle EOL comments on a closing right brace
+-- Get comments from all instances of opt_nls
+-- Get comments from all instances of l_brace
+-- Get comments from all instances of r_brace
+-- Review statement lists and handling of statement_term
+DONE:
+-- Get comments from all instances of nls
+-- After , in parameter list
+-- After ? and :
+-- switch statement
+-- After , in a range expression in a pattern
+-- After && and ||
+-- case part of switch statement
+-- for(;;) statement
+-- for(iggy in fo) statement
+-- Comments after commas in expressions lists in print/f and function calls
+*/
/*
* awkgram.y --- yacc/bison parser
*/
@@ -53,8 +74,8 @@ static int isnoeffect(OPCODE type);
static INSTRUCTION *make_assignable(INSTRUCTION *ip);
static void dumpintlstr(const char *str, size_t len);
static void dumpintlstr2(const char *str1, size_t len1, const char *str2, size_t len2);
-static int include_source(INSTRUCTION *file);
-static int load_library(INSTRUCTION *file);
+static bool include_source(INSTRUCTION *file, void **srcfile_p);
+static bool load_library(INSTRUCTION *file, void **srcfile_p);
static void next_sourcefile(void);
static char *tokexpand(void);
static NODE *set_profile_text(NODE *n, const char *str, size_t len);
@@ -84,8 +105,8 @@ 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 merge_comments(INSTRUCTION *c1, INSTRUCTION *c2);
+static INSTRUCTION *make_braced_statements(INSTRUCTION *lbrace, INSTRUCTION *stmts, INSTRUCTION *rbrace);
static void add_sign_to_num(NODE *n, char sign);
static bool at_seen = false;
@@ -152,21 +173,13 @@ 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 func_first = true; // can nuke
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);
@@ -214,12 +227,20 @@ extern double fmod(double x, double y);
program
: /* empty */
+ { $$ = NULL; }
| program rule
{
rule = 0;
yyerrok;
}
| program nls
+ {
+ if ($2 != NULL) {
+ merge_comments($2, NULL);
+ $$ = list_append(rule_list, $2);
+ } else
+ $$ = $1;
+ }
| program LEX_EOF
{
next_sourcefile();
@@ -249,8 +270,11 @@ rule
} else if ($1 == NULL) {
msg(_("each rule must have a pattern or an action part"));
errcount++;
- } else /* pattern rule with non-empty pattern */
+ } else { /* pattern rule with non-empty pattern */
+ if ($2 != NULL)
+ list_append($1, $2);
(void) append_rule($1, NULL);
+ }
}
| function_prologue action
{
@@ -263,12 +287,20 @@ rule
{
want_source = false;
at_seen = false;
+ if ($3 != NULL && $4 != NULL) {
+ SRCFILE *s = (SRCFILE *) $3;
+ s->comment = $4;
+ }
yyerrok;
}
| '@' LEX_LOAD library statement_term
{
want_source = false;
at_seen = false;
+ if ($3 != NULL && $4 != NULL) {
+ SRCFILE *s = (SRCFILE *) $3;
+ s->comment = $4;
+ }
yyerrok;
}
;
@@ -276,11 +308,13 @@ rule
source
: FILENAME
{
- if (include_source($1) < 0)
+ void *srcfile = NULL;
+
+ if (! include_source($1, & srcfile))
YYABORT;
efree($1->lextok);
bcfree($1);
- $$ = NULL;
+ $$ = (INSTRUCTION *) srcfile;
}
| FILENAME error
{ $$ = NULL; }
@@ -291,11 +325,13 @@ source
library
: FILENAME
{
- if (load_library($1) < 0)
+ void *srcfile;
+
+ if (! load_library($1, & srcfile))
YYABORT;
efree($1->lextok);
bcfree($1);
- $$ = NULL;
+ $$ = (INSTRUCTION *) srcfile;
}
| FILENAME error
{ $$ = NULL; }
@@ -307,20 +343,11 @@ pattern
: /* empty */
{
rule = Rule;
- if (comment != NULL) {
- $$ = list_create(comment);
- comment = NULL;
- } else
- $$ = NULL;
+ $$ = NULL;
}
| exp
{
rule = Rule;
- if (comment != NULL) {
- $$ = list_prepend($1, comment);
- comment = NULL;
- } else
- $$ = $1;
}
| exp ',' opt_nls exp
@@ -346,10 +373,10 @@ pattern
($1->nexti + 1)->condpair_left = $1->lasti;
($1->nexti + 1)->condpair_right = $4->lasti;
}
- if (comment != NULL) {
- $$ = list_append(list_merge(list_prepend($1, comment), $4), tp);
- comment = NULL;
- } else
+ /* Put any comments in front of the range expression */
+ if ($3 != NULL)
+ $$ = list_append(list_merge(list_prepend($1, $3), $4), tp);
+ else
$$ = list_append(list_merge($1, $4), tp);
rule = Rule;
}
@@ -364,7 +391,6 @@ pattern
$1->in_rule = rule = BEGIN;
$1->source_file = source;
- check_comment();
$$ = $1;
}
| LEX_END
@@ -378,7 +404,6 @@ pattern
$1->in_rule = rule = END;
$1->source_file = source;
- check_comment();
$$ = $1;
}
| LEX_BEGINFILE
@@ -386,7 +411,6 @@ pattern
func_first = false;
$1->in_rule = rule = BEGINFILE;
$1->source_file = source;
- check_comment();
$$ = $1;
}
| LEX_ENDFILE
@@ -394,7 +418,6 @@ pattern
func_first = false;
$1->in_rule = rule = ENDFILE;
$1->source_file = source;
- check_comment();
$$ = $1;
}
;
@@ -402,11 +425,11 @@ pattern
action
: l_brace statements r_brace opt_semi opt_nls
{
- INSTRUCTION *ip;
- if ($2 == NULL)
- ip = list_create(instruction(Op_no_op));
- else
- ip = $2;
+ INSTRUCTION *ip = make_braced_statements($1, $2, $3);
+
+ if ($5 != NULL)
+ ip = list_append(ip, $5);
+
$$ = ip;
}
;
@@ -437,33 +460,21 @@ lex_builtin
function_prologue
: 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;
+ INSTRUCTION *func_comment = NULL;
+ // Merge any comments found in the parameter list with those
+ // following the function header, associate the whole shebang
+ // with the function as one block comment.
+ if ($5 != NULL && $5->comment != NULL) {
+ if ($7 != NULL) {
+ merge_comments($5->comment, $7);
+ }
+ func_comment = $5->comment;
+ } else if ($7 != NULL) {
+ func_comment = $7;
}
- func_first = false;
+
$1->source_file = source;
+ $1->comment = func_comment;
if (install_function($2->lextok, $1, $5) < 0)
YYABORT;
in_function = $2->lextok;
@@ -536,58 +547,16 @@ a_slash
statements
: /* empty */
- {
- if (prior_comment != NULL) {
- $$ = list_create(prior_comment);
- prior_comment = NULL;
- } else if (comment != NULL) {
- $$ = list_create(comment);
- comment = NULL;
- } else
- $$ = NULL;
- }
+ { $$ = NULL; }
| statements statement
{
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;
+ $$ = $1;
} else {
add_lint($2, LINT_no_effect);
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;
+ $$ = $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);
}
}
@@ -598,15 +567,26 @@ statements
;
statement_term
- : nls
- | semi opt_nls
+ : nls { $$ = $1; }
+ | semi opt_nls { $$ = $2; }
;
statement
: semi opt_nls
- { $$ = NULL; }
+ {
+ if ($2 != NULL) {
+ INSTRUCTION *ip;
+
+ merge_comments($2, NULL);
+ ip = list_create(instruction(Op_no_op));
+ $$ = list_append(ip, $2);
+ } else
+ $$ = NULL;
+ }
| l_brace statements r_brace
- { $$ = $2; }
+ {
+ $$ = make_braced_statements($1, $2, $3);
+ }
| if_statement
{
if (do_pretty_print)
@@ -632,8 +612,9 @@ statement
if ($7 != NULL) {
curr = $7->nexti;
bcfree($7); /* Op_list */
- } /* else
- curr = NULL; */
+ }
+ /* else
+ curr = NULL; */
for (; curr != NULL; curr = nextc) {
INSTRUCTION *caseexp = curr->case_exp;
@@ -689,16 +670,33 @@ statement
ip = $3;
if (do_pretty_print) {
+ // first merge comments
+ INSTRUCTION *head_comment = NULL;
+
+ if ($5 != NULL && $6 != NULL) {
+ merge_comments($5, $6);
+ head_comment = $5;
+ } else if ($5 != NULL)
+ head_comment = $5;
+ else
+ head_comment = $6;
+
+ $1->comment = head_comment;
+
(void) list_prepend(ip, $1);
(void) list_prepend(ip, instruction(Op_exec_count));
$1->target_break = tbreak;
($1 + 1)->switch_start = cexp->nexti;
($1 + 1)->switch_end = cexp->lasti;
- }/* else
- $1 is NULL */
+ ($1 + 1)->switch_end->comment = $9;
+ }
+ /* else
+ $1 is NULL */
(void) list_append(cexp, dflt);
(void) list_merge(ip, cexp);
+ if ($8 != NULL)
+ (void) list_append(cstmt, $8);
$$ = list_merge(ip, cstmt);
break_allowed--;
@@ -733,8 +731,17 @@ statement
$1->target_continue = tcont;
($1 + 1)->while_body = ip->lasti;
(void) list_prepend(ip, $1);
- }/* else
- $1 is NULL */
+ }
+ /* else
+ $1 is NULL */
+
+ if ($5 != NULL) {
+ if ($6 == NULL)
+ $6 = list_create(instruction(Op_no_op));
+
+ $5->memory->comment_type = BLOCK_COMMENT;
+ $6 = list_prepend($6, $5);
+ }
if ($6 != NULL)
(void) list_merge(ip, $6);
@@ -769,8 +776,13 @@ statement
ip = list_merge($3, $6);
else
ip = list_prepend($6, instruction(Op_no_op));
+
+ if ($2 != NULL)
+ (void) list_prepend(ip, $2);
+
if (do_pretty_print)
(void) list_prepend(ip, instruction(Op_exec_count));
+
(void) list_append(ip, instruction(Op_jmp_true));
ip->lasti->target_jmp = ip->nexti;
$$ = list_append(ip, tbreak);
@@ -785,7 +797,10 @@ statement
($1 + 1)->doloop_cond = tcont;
$$ = list_prepend(ip, $1);
bcfree($4);
- } /* else
+ if ($8 != NULL)
+ $1->comment = $8;
+ }
+ /* else
$1 and $4 are NULLs */
}
| LEX_FOR '(' NAME LEX_IN simple_variable r_paren opt_nls statement
@@ -801,7 +816,8 @@ statement
&& strcmp($8->nexti->memory->vname, var_name) == 0
) {
- /* Efficiency hack. Recognize the special case of
+ /*
+ * Efficiency hack. Recognize the special case of
*
* for (iggy in foo)
* delete foo[iggy]
@@ -833,6 +849,10 @@ statement
bcfree($3);
bcfree($4);
bcfree($5);
+ if ($7 != NULL) {
+ merge_comments($7, NULL);
+ $8 = list_prepend($8, $7);
+ }
$$ = $8;
} else
goto regular_loop;
@@ -867,8 +887,9 @@ regular_loop:
$1->target_continue = tcont;
$1->target_break = tbreak;
(void) list_append(ip, $1);
- } /* else
- $1 is NULL */
+ }
+ /* else
+ $1 is NULL */
/* add update_FOO instruction if necessary */
if ($4->array_var->type == Node_var && $4->array_var->var_update) {
@@ -889,8 +910,15 @@ regular_loop:
($1 + 1)->forloop_body = ip->lasti;
}
- if ($8 != NULL)
+ if ($7 != NULL)
+ merge_comments($7, NULL);
+
+ if ($8 != NULL) {
+ if ($7 != NULL)
+ $8 = list_prepend($8, $7);
(void) list_merge(ip, $8);
+ } else if ($7 != NULL)
+ (void) list_append(ip, $7);
(void) list_append(ip, instruction(Op_jmp));
ip->lasti->target_jmp = $4;
@@ -903,6 +931,20 @@ regular_loop:
}
| LEX_FOR '(' opt_simple_stmt semi opt_nls exp semi opt_nls opt_simple_stmt r_paren opt_nls statement
{
+ if ($5 != NULL) {
+ merge_comments($5, NULL);
+ $1->comment = $5;
+ }
+ if ($8 != NULL) {
+ merge_comments($8, NULL);
+ if ($1->comment == NULL) {
+ $8->memory->comment_type = FOR_COMMENT;
+ $1->comment = $8;
+ } else
+ $1->comment->comment = $8;
+ }
+ if ($11 != NULL)
+ $12 = list_prepend($12, $11);
$$ = mk_for_loop($1, $3, $6, $9, $12);
break_allowed--;
@@ -910,6 +952,20 @@ regular_loop:
}
| LEX_FOR '(' opt_simple_stmt semi opt_nls semi opt_nls opt_simple_stmt r_paren opt_nls statement
{
+ if ($5 != NULL) {
+ merge_comments($5, NULL);
+ $1->comment = $5;
+ }
+ if ($7 != NULL) {
+ merge_comments($7, NULL);
+ if ($1->comment == NULL) {
+ $7->memory->comment_type = FOR_COMMENT;
+ $1->comment = $7;
+ } else
+ $1->comment->comment = $7;
+ }
+ if ($10 != NULL)
+ $11 = list_prepend($11, $10);
$$ = mk_for_loop($1, $3, (INSTRUCTION *) NULL, $8, $11);
break_allowed--;
@@ -921,7 +977,6 @@ regular_loop:
$$ = list_prepend($1, instruction(Op_exec_count));
else
$$ = $1;
- $$ = add_pending_comment($$);
}
;
@@ -933,8 +988,8 @@ non_compound_stmt
_("`break' is not allowed outside a loop or switch"));
$1->target_jmp = NULL;
$$ = list_create($1);
- $$ = add_pending_comment($$);
-
+ if ($2 != NULL)
+ $$ = list_append($$, $2);
}
| LEX_CONTINUE statement_term
{
@@ -943,8 +998,8 @@ non_compound_stmt
_("`continue' is not allowed outside a loop"));
$1->target_jmp = NULL;
$$ = list_create($1);
- $$ = add_pending_comment($$);
-
+ if ($2 != NULL)
+ $$ = list_append($$, $2);
}
| LEX_NEXT statement_term
{
@@ -954,7 +1009,8 @@ non_compound_stmt
_("`next' used in %s action"), ruletab[rule]);
$1->target_jmp = ip_rec;
$$ = list_create($1);
- $$ = add_pending_comment($$);
+ if ($2 != NULL)
+ $$ = list_append($$, $2);
}
| LEX_NEXTFILE statement_term
{
@@ -966,7 +1022,8 @@ non_compound_stmt
$1->target_newfile = ip_newfile;
$1->target_endfile = ip_endfile;
$$ = list_create($1);
- $$ = add_pending_comment($$);
+ if ($2 != NULL)
+ $$ = list_append($$, $2);
}
| LEX_EXIT opt_exp statement_term
{
@@ -982,7 +1039,8 @@ non_compound_stmt
$$->nexti->memory = dupnode(Nnull_string);
} else
$$ = list_append($2, $1);
- $$ = add_pending_comment($$);
+ if ($3 != NULL)
+ $$ = list_append($$, $3);
}
| LEX_RETURN
{
@@ -995,10 +1053,16 @@ non_compound_stmt
$$->nexti->memory = dupnode(Nnull_string);
} else
$$ = list_append($3, $1);
-
- $$ = add_pending_comment($$);
+ if ($4 != NULL)
+ $$ = list_append($$, $4);
}
| simple_stmt statement_term
+ {
+ if ($2 != NULL)
+ $$ = list_append($1, $2);
+ else
+ $$ = $1;
+ }
;
/*
@@ -1018,7 +1082,7 @@ simple_stmt
* which is faster for these two cases.
*/
- if ($1->opcode == Op_K_print &&
+ if (do_optimize && $1->opcode == Op_K_print &&
($3 == NULL
|| ($3->lasti->opcode == Op_field_spec
&& $3->nexti->nexti->nexti == $3->lasti
@@ -1106,7 +1170,6 @@ regular_print:
}
}
}
- $$ = add_pending_comment($$);
}
| LEX_DELETE NAME { sub_counter = 0; } delete_subscript_list
@@ -1141,7 +1204,6 @@ regular_print:
$1->expr_count = sub_counter;
$$ = list_append(list_append($4, $2), $1);
}
- $$ = add_pending_comment($$);
}
| LEX_DELETE '(' NAME ')'
/*
@@ -1172,12 +1234,10 @@ regular_print:
else if ($3->memory == func_table)
fatal(_("`delete' is not allowed with FUNCTAB"));
}
- $$ = add_pending_comment($$);
}
| exp
{
$$ = optimize_assignment($1);
- $$ = add_pending_comment($$);
}
;
@@ -1212,6 +1272,7 @@ case_statement
(void) list_prepend(casestmt, instruction(Op_exec_count));
$1->case_exp = $2;
$1->case_stmt = casestmt;
+ $1->comment = $4;
bcfree($3);
$$ = $1;
}
@@ -1224,6 +1285,7 @@ case_statement
(void) list_prepend(casestmt, instruction(Op_exec_count));
bcfree($2);
$1->case_stmt = casestmt;
+ $1->comment = $3;
$$ = $1;
}
;
@@ -1305,23 +1367,48 @@ output_redir
if_statement
: LEX_IF '(' exp r_paren opt_nls statement
{
+ if ($5 != NULL)
+ $1->comment = $5;
$$ = mk_condition($3, $1, $6, NULL, NULL);
}
| LEX_IF '(' exp r_paren opt_nls statement
LEX_ELSE opt_nls statement
{
+ if ($5 != NULL)
+ $1->comment = $5;
+ if ($8 != NULL)
+ $7->comment = $8;
$$ = mk_condition($3, $1, $6, $7, $9);
}
;
nls
- : NEWLINE
+ : NEWLINE { $$ = $1; }
| nls NEWLINE
+ {
+ if ($1 != NULL && $2 != NULL) {
+ if ($1->memory->comment_type == EOL_COMMENT) {
+ assert($2->memory->comment_type == BLOCK_COMMENT);
+ $1->comment = $2; // chain them
+ } else {
+ merge_comments($1, $2);
+ }
+
+ $$ = $1;
+ } else if ($1 != NULL) {
+ $$ = $1;
+ } else if ($2 != NULL) {
+ $$ = $2;
+ } else
+ $$ = NULL;
+ }
;
opt_nls
: /* empty */
+ { $$ = NULL; }
| nls
+ { $$ = $1; }
;
input_redir
@@ -1350,9 +1437,17 @@ param_list
| param_list comma NAME
{
if ($1 != NULL && $3 != NULL) {
- $3->param_count = $1->lasti->param_count + 1;
+ $3->param_count = $1->lasti->param_count + 1;
$$ = list_append($1, $3);
yyerrok;
+
+ // newlines are allowed after commas, catch any comments
+ if ($2 != NULL) {
+ if ($1->comment != NULL)
+ merge_comments($1->comment, $2);
+ else
+ $1->comment = $2;
+ }
} else
$$ = NULL;
}
@@ -1384,6 +1479,8 @@ expression_list
{ $$ = mk_expression_list(NULL, $1); }
| expression_list comma exp
{
+ if ($2 != NULL)
+ $1->lasti->comment = $2;
$$ = mk_expression_list($1, $3);
yyerrok;
}
@@ -1405,6 +1502,8 @@ expression_list
| expression_list comma error
{
/* Ditto */
+ if ($2 != NULL)
+ $1->lasti->comment = $2;
$$ = $1;
}
;
@@ -1421,6 +1520,8 @@ fcall_expression_list
{ $$ = mk_expression_list(NULL, $1); }
| fcall_expression_list comma fcall_exp
{
+ if ($2 != NULL)
+ $1->lasti->comment = $2;
$$ = mk_expression_list($1, $3);
yyerrok;
}
@@ -1442,6 +1543,8 @@ fcall_expression_list
| fcall_expression_list comma error
{
/* Ditto */
+ if ($2 != NULL)
+ $1->comment = $2;
$$ = $1;
}
;
@@ -2006,15 +2109,16 @@ opt_incdec
{
$1->opcode = Op_postdecrement;
}
- | /* empty */ { $$ = NULL; }
+ | /* empty */
+ { $$ = NULL; }
;
l_brace
- : '{' opt_nls
+ : '{' opt_nls { $$ = $2; }
;
r_brace
- : '}' opt_nls { yyerrok; }
+ : '}' opt_nls { $$ = $2; yyerrok; }
;
r_paren
@@ -2023,6 +2127,7 @@ r_paren
opt_semi
: /* empty */
+ { $$ = NULL; }
| semi
;
@@ -2035,7 +2140,7 @@ colon
;
comma
- : ',' opt_nls { yyerrok; }
+ : ',' opt_nls { $$ = $2; yyerrok; }
;
%%
@@ -2115,8 +2220,8 @@ static const struct token tokentab[] = {
{"exp", Op_builtin, LEX_BUILTIN, A(1), do_exp, MPF(exp)},
{"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},
-{"function",Op_func, LEX_FUNCTION, NOT_OLD, 0, 0},
+{"func", Op_func, LEX_FUNCTION, NOT_POSIX|NOT_OLD, 0, 0},
+{"function", Op_func, LEX_FUNCTION, NOT_OLD, 0, 0},
{"gensub", Op_sub_builtin, LEX_BUILTIN, GAWKX|A(3)|A(4), 0, 0},
{"getline", Op_K_getline_redir, LEX_GETLINE, NOT_OLD, 0, 0},
{"gsub", Op_sub_builtin, LEX_BUILTIN, NOT_OLD|A(2)|A(3), 0, 0},
@@ -2475,11 +2580,6 @@ 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));
@@ -2512,12 +2612,6 @@ 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));
@@ -2525,10 +2619,6 @@ 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
@@ -2703,33 +2793,35 @@ add_srcfile(enum srctype stype, char *src, SRCFILE *thisfile, bool *already_incl
/* include_source --- read program from source included using `@include' */
-static int
-include_source(INSTRUCTION *file)
+static bool
+include_source(INSTRUCTION *file, void **srcfile_p)
{
SRCFILE *s;
char *src = file->lextok;
int errcode;
bool already_included;
+ *srcfile_p = NULL;
+
if (do_traditional || do_posix) {
error_ln(file->source_line, _("@include is a gawk extension"));
- return -1;
+ return false;
}
if (strlen(src) == 0) {
if (do_lint)
lintwarn_ln(file->source_line, _("empty filename after @include"));
- return 0;
+ return true;
}
s = add_srcfile(SRC_INC, src, sourcefile, &already_included, &errcode);
if (s == NULL) {
if (already_included)
- return 0;
+ return true;
error_ln(file->source_line,
_("can't open source file `%s' for reading (%s)"),
src, errcode ? strerror(errcode) : _("reason unknown"));
- return -1;
+ return false;
}
/* save scanner state for the current sourcefile */
@@ -2748,42 +2840,46 @@ include_source(INSTRUCTION *file)
lasttok = 0;
lexeof = false;
eof_warned = false;
- return 0;
+ *srcfile_p = (void *) s;
+ return true;
}
/* load_library --- load a shared library */
-static int
-load_library(INSTRUCTION *file)
+static bool
+load_library(INSTRUCTION *file, void **srcfile_p)
{
SRCFILE *s;
char *src = file->lextok;
int errcode;
bool already_included;
+ *srcfile_p = NULL;
+
if (do_traditional || do_posix) {
error_ln(file->source_line, _("@load is a gawk extension"));
- return -1;
+ return false;
}
if (strlen(src) == 0) {
if (do_lint)
lintwarn_ln(file->source_line, _("empty filename after @load"));
- return 0;
+ return true;
}
s = add_srcfile(SRC_EXTLIB, src, sourcefile, &already_included, &errcode);
if (s == NULL) {
if (already_included)
- return 0;
+ return true;
error_ln(file->source_line,
_("can't open shared library `%s' for reading (%s)"),
src, errcode ? strerror(errcode) : _("reason unknown"));
- return -1;
+ return false;
}
load_ext(s->fullpath);
- return 0;
+ *srcfile_p = (void *) s;
+ return true;
}
/* next_sourcefile --- read program from the next source in srcfiles */
@@ -3191,37 +3287,23 @@ 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.
+ * Flag = BLOCK_COMMENT for self-contained comments.
*/
-int
-get_comment(int flag)
+static int
+get_comment(enum commenttype flag, INSTRUCTION **comment_instruction)
{
int c;
int sl;
+ char *p1;
+ char *p2;
+
tok = tokstart;
tokadd('#');
sl = sourceline;
- char *p1;
- char *p2;
while (true) {
while ((c = nextc(false)) != '\n' && c != END_FILE) {
@@ -3257,9 +3339,6 @@ get_comment(int flag)
break;
}
- if (comment != NULL)
- prior_comment = comment;
-
/* remove any trailing blank lines (consecutive \n) from comment */
p1 = tok - 1;
p2 = tok - 2;
@@ -3269,49 +3348,18 @@ get_comment(int flag)
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;
+ (*comment_instruction) = bcalloc(Op_comment, 1, sl);
+ (*comment_instruction)->source_file = source;
+ (*comment_instruction)->memory = make_str_node(tokstart, tok - tokstart, 0);
+ (*comment_instruction)->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_string(p + l + 2, n->stlen - l - 2);
- /* 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 : */
static void
-allow_newline(void)
+allow_newline(INSTRUCTION **new_comment)
{
int c;
@@ -3323,8 +3371,8 @@ allow_newline(void)
}
if (c == '#') {
if (do_pretty_print && ! do_profile) {
- /* collect comment byte code iff doing pretty print but not profiling. */
- c = get_comment(EOL_COMMENT);
+ /* collect comment byte code iff doing pretty print but not profiling. */
+ c = get_comment(EOL_COMMENT, new_comment);
} else {
while ((c = nextc(false)) != '\n' && c != END_FILE)
continue;
@@ -3391,6 +3439,7 @@ yylex(void)
bool intlstr = false;
AWKNUM d;
bool collecting_typed_regexp = false;
+ static int qm_col_count = 0;
#define GET_INSTRUCTION(op) bcalloc(op, 1, sourceline)
@@ -3555,18 +3604,25 @@ retry:
return lasttok = NEWLINE;
case '#': /* it's a comment */
+ yylval = NULL;
if (do_pretty_print && ! do_profile) {
/*
* Collect comment byte code iff doing pretty print
* but not profiling.
*/
+ INSTRUCTION *new_comment;
+
if (lasttok == NEWLINE || lasttok == 0)
- c = get_comment(FULL_COMMENT);
+ c = get_comment(BLOCK_COMMENT, & new_comment);
else
- c = get_comment(EOL_COMMENT);
+ c = get_comment(EOL_COMMENT, & new_comment);
- if (c == END_FILE)
- return lasttok = NEWLINE_EOF;
+ yylval = new_comment;
+
+ if (c == END_FILE) {
+ pushback();
+ return lasttok = NEWLINE;
+ }
} else {
while ((c = nextc(false)) != '\n') {
if (c == END_FILE)
@@ -3595,7 +3651,10 @@ retry:
* Use it at your own risk. We think it's a bad idea, which
* is why it's not on by default.
*/
+ yylval = NULL;
if (! do_traditional) {
+ INSTRUCTION *new_comment;
+
/* strip trailing white-space and/or comment */
while ((c = nextc(true)) == ' ' || c == '\t' || c == '\r')
continue;
@@ -3607,9 +3666,11 @@ retry:
lintwarn(
_("use of `\\ #...' line continuation is not portable"));
}
- if (do_pretty_print && ! do_profile)
- c = get_comment(EOL_COMMENT);
- else {
+ if (do_pretty_print && ! do_profile) {
+ c = get_comment(EOL_COMMENT, & new_comment);
+ yylval = new_comment;
+ return lasttok = c;
+ } else {
while ((c = nextc(false)) != '\n')
if (c == END_FILE)
break;
@@ -3630,11 +3691,19 @@ retry:
}
break;
- case ':':
case '?':
+ qm_col_count++;
+ // fall through
+ case ':':
yylval = GET_INSTRUCTION(Op_cond_exp);
- if (! do_posix)
- allow_newline();
+ if (c == ':' && qm_col_count > 0) {
+ if (do_posix) {
+ INSTRUCTION *new_comment = NULL;
+ allow_newline(& new_comment);
+ yylval->comment = new_comment;
+ }
+ qm_col_count--;
+ }
return lasttok = c;
/*
@@ -4056,7 +4125,10 @@ retry:
case '&':
if ((c = nextc(true)) == '&') {
yylval = GET_INSTRUCTION(Op_and);
- allow_newline();
+ INSTRUCTION *new_comment = NULL;
+ allow_newline(& new_comment);
+ yylval->comment = new_comment;
+
return lasttok = LEX_AND;
}
pushback();
@@ -4066,11 +4138,15 @@ retry:
case '|':
if ((c = nextc(true)) == '|') {
yylval = GET_INSTRUCTION(Op_or);
- allow_newline();
+ INSTRUCTION *new_comment = NULL;
+ allow_newline(& new_comment);
+ yylval->comment = new_comment;
+
return lasttok = LEX_OR;
} else if (! do_traditional && c == '&') {
yylval = GET_INSTRUCTION(Op_symbol);
yylval->redir_type = redirect_twoway;
+
return lasttok = (in_print && in_parens == 0 ? IO_OUT : IO_IN);
}
pushback();
@@ -4260,8 +4336,11 @@ out:
yylval->lextok = tokkey;
#define SMART_ALECK 1
- if (SMART_ALECK && do_lint
- && ! goto_warned && strcasecmp(tokkey, "goto") == 0) {
+ if (SMART_ALECK
+ && do_lint
+ && ! goto_warned
+ && tolower(tokkey[0]) == 'g'
+ && strcasecmp(tokkey, "goto") == 0) {
goto_warned = true;
lintwarn(_("`goto' considered harmful!"));
}
@@ -4732,15 +4811,8 @@ mk_function(INSTRUCTION *fi, INSTRUCTION *def)
thisfunc = fi->func_body;
assert(thisfunc != NULL);
- /* 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;
+ /*
+ * Add an implicit return at end;
* also used by 'return' command in debugger
*/
@@ -5451,12 +5523,7 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action)
(rp + 1)->lasti = action->lasti;
(rp + 2)->first_line = pattern->source_line;
(rp + 2)->last_line = lastline;
- if (block_comment != NULL) {
- ip = list_prepend(list_prepend(action, block_comment), rp);
- block_comment = NULL;
- } else
- ip = list_prepend(action, rp);
-
+ ip = list_prepend(action, rp);
} else {
rp = bcalloc(Op_rule, 3, 0);
rp->in_rule = Rule;
@@ -5861,8 +5928,9 @@ mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, INSTRUCTION *cond,
forp->target_break = tbreak;
forp->target_continue = tcont;
ret = list_prepend(ret, forp);
- } /* else
- forp is NULL */
+ }
+ /* else
+ forp is NULL */
return ret;
}
@@ -6076,26 +6144,6 @@ 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
@@ -6335,3 +6383,102 @@ set_profile_text(NODE *n, const char *str, size_t len)
return n;
}
+
+/*
+ * merge_comments --- merge c2 into c1 and free c2 if successful.
+ * Allow c2 to be NULL, in which case just merged chained
+ * comments in c1.
+ */
+
+static void
+merge_comments(INSTRUCTION *c1, INSTRUCTION *c2)
+{
+ assert(c1->opcode == Op_comment);
+
+ if (c1->comment == NULL && c2 == NULL) // nothing to do
+ return;
+
+ size_t total = c1->memory->stlen;
+ if (c1->comment != NULL)
+ total += 1 /* \n */ + c1->comment->memory->stlen;
+
+ if (c2 != NULL) {
+ assert(c2->opcode == Op_comment);
+ total += 1 /* \n */ + c2->memory->stlen;
+ if (c2->comment != NULL)
+ total += c2->comment->memory->stlen + 1;
+ }
+
+ char *buffer;
+ emalloc(buffer, char *, total + 1, "merge_comments");
+
+ strcpy(buffer, c1->memory->stptr);
+ if (c1->comment != NULL) {
+ strcat(buffer, "\n");
+ strcat(buffer, c1->comment->memory->stptr);
+ }
+
+ if (c2 != NULL) {
+ strcat(buffer, "\n");
+ strcat(buffer, c2->memory->stptr);
+ if (c2->comment != NULL) {
+ strcat(buffer, "\n");
+ strcat(buffer, c2->comment->memory->stptr);
+ }
+
+ unref(c2->memory);
+ if (c2->comment != NULL) {
+ unref(c2->comment->memory);
+ bcfree(c2->comment);
+ c2->comment = NULL;
+ }
+ bcfree(c2);
+ }
+
+ c1->memory->comment_type = BLOCK_COMMENT;
+ free(c1->memory->stptr);
+ c1->memory->stptr = buffer;
+ c1->memory->stlen = strlen(buffer);
+
+ // now free everything else
+ if (c1->comment != NULL) {
+ unref(c1->comment->memory);
+ bcfree(c1->comment);
+ c1->comment = NULL;
+ }
+}
+
+/* make_braced_statements --- handle `l_brace statements r_brace' with comments */
+
+static INSTRUCTION *
+make_braced_statements(INSTRUCTION *lbrace, INSTRUCTION *stmts, INSTRUCTION *rbrace)
+{
+ INSTRUCTION *ip;
+
+ if (stmts == NULL)
+ ip = list_create(instruction(Op_no_op));
+ else
+ ip = stmts;
+
+ if (lbrace != NULL) {
+ INSTRUCTION *comment2 = lbrace->comment;
+ if (comment2 != NULL) {
+ ip = list_prepend(ip, comment2);
+ lbrace->comment = NULL;
+ }
+ ip = list_prepend(ip, lbrace);
+ }
+
+ /* Tack any comment onto the end. */
+ if (rbrace != NULL) {
+ INSTRUCTION *comment2 = rbrace->comment;
+ rbrace->comment = NULL;
+ if (rbrace->memory->comment_type == EOL_COMMENT)
+ rbrace->memory->comment_type = BLOCK_COMMENT;
+ ip = list_append(ip, rbrace);
+ if (comment2 != NULL)
+ ip = list_append(ip, comment2);
+ }
+
+ return ip;
+}