diff options
Diffstat (limited to 'awkgram.y')
-rw-r--r-- | awkgram.y | 205 |
1 files changed, 183 insertions, 22 deletions
@@ -87,6 +87,7 @@ 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); +void split_comment(void); static bool want_source = false; static bool want_regexp = false; /* lexical scanning kludge */ @@ -146,6 +147,12 @@ static INSTRUCTION *ip_end; static INSTRUCTION *ip_endfile; static INSTRUCTION *ip_beginfile; +static INSTRUCTION *comment = NULL; +static INSTRUCTION *comment0 = NULL; +static INSTRUCTION *commentf = NULL; + +static int func_first = 1; + 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); @@ -288,9 +295,22 @@ 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; @@ -320,6 +340,8 @@ pattern | LEX_BEGIN { static int begin_seen = 0; + func_first = 0; + INSTRUCTION *ip; if (do_lint_old && ++begin_seen == 2) warning_ln($1->source_line, _("old awk does not support multiple `BEGIN' or `END' rules")); @@ -331,6 +353,7 @@ pattern | LEX_END { static int end_seen = 0; + func_first = 0; if (do_lint_old && ++end_seen == 2) warning_ln($1->source_line, _("old awk does not support multiple `BEGIN' or `END' rules")); @@ -341,12 +364,14 @@ pattern } | LEX_BEGINFILE { + func_first = 0; $1->in_rule = rule = BEGINFILE; $1->source_file = source; $$ = $1; } | LEX_ENDFILE { + func_first = 0; $1->in_rule = rule = ENDFILE; $1->source_file = source; $$ = $1; @@ -356,10 +381,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; } ; @@ -386,6 +413,16 @@ lex_builtin function_prologue : LEX_FUNCTION func_name '(' 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 (comment != NULL && func_first && strstr(comment->memory->stptr, "\n\n") != NULL) + split_comment(); + /* save any other pre-function comment as function comment */ + if (comment != NULL){ + commentf = comment; + comment = NULL; + } + func_first = 0; $1->source_file = source; if (install_function($2->lextok, $1, $4) < 0) YYABORT; @@ -443,19 +480,39 @@ a_slash statements : /* empty */ - { $$ = NULL; } + { + if (comment != NULL){ + $$ = list_create(comment); + comment = NULL; + } else $$ = NULL; + } | statements statement { - if ($2 == NULL) - $$ = $1; - else { + if ($2 == NULL) { + if (comment == NULL) + $$ = $1; + else { + $$ = list_append($1, comment); + comment = NULL; + } + } else { add_lint($2, LINT_no_effect); - if ($1 == NULL) - $$ = $2; - else + if ($1 == NULL) { + if (comment == NULL) + $$ = $2; + else { + $$ = 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; } @@ -470,7 +527,7 @@ statement : semi opt_nls { $$ = NULL; } | l_brace statements r_brace - { $$ = $2; } + { $$ = $2; } | if_statement { if (do_pretty_print) @@ -2223,6 +2280,8 @@ mk_program() cp = end_block; else cp = list_merge(begin_block, end_block); + if (comment != NULL) + (void) list_append(cp, comment); (void) list_append(cp, ip_atexit); (void) list_append(cp, instruction(Op_stop)); @@ -2255,6 +2314,12 @@ mk_program() if (begin_block != NULL) cp = list_merge(begin_block, cp); + if (comment0 != NULL){ + (void) list_prepend(cp, comment0); + } + if (comment != NULL){ + (void) list_append(cp, comment); + } (void) list_append(cp, ip_atexit); (void) list_append(cp, instruction(Op_stop)); @@ -2928,6 +2993,78 @@ pushback(void) } +/* get_comment --- collect comment text */ + +int get_comment(void) +{ + int c; + int sl; + tok = tokstart; + tokadd('#'); + sl = sourceline; + + while (true){ + while ((c = nextc(false)) != '\n' && c != END_FILE){ + tokadd(c); + } + 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(); + break; + } else + tokadd(c); + } else + break; + } + comment = bcalloc(Op_comment, 1, sl); + comment->source_file = source; + comment->memory = make_str_node(tokstart, tok - tokstart, 0); + + return c; +} + +/* split_comment --- split initial comment text into program and function parts */ + +void split_comment(void) +{ + char *p; + int l; + int j; + NODE *n; + + p = comment->memory->stptr; + l = comment->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'){ + commentf = comment; + n = commentf->memory; + commentf->memory = make_str_node(p + l + 2, n->stlen - l - 2, 0); + /* create program comment */ + comment0 = bcalloc(Op_comment, 1, sourceline); + comment0->source_file = comment->source_file; + p[l + 2] = 0; + comment0->memory = make_str_node(p , l + 2, 0); + comment = NULL; + freenode(n); + break; + } + else l--; + } + +} + /* allow_newline --- allow newline after &&, ||, ? and : */ static void @@ -2942,8 +3079,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(); + } else { + while ((c = nextc(false)) != '\n' && c != END_FILE) + continue; + } if (c == END_FILE) { pushback(); break; @@ -3147,9 +3289,17 @@ 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. */ + c = get_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; @@ -3160,7 +3310,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. @@ -3177,9 +3327,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(); + else { + while ((c = nextc(false)) != '\n') + if (c == END_FILE) + break; + } } pushback(); } @@ -3391,7 +3545,7 @@ retry: lastline = sourceline; return lasttok = c; } - did_newline++; + did_newline = true; --lexptr; /* pick up } next time */ return lasttok = NEWLINE; @@ -4240,6 +4394,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 (commentf != NULL){ + commentf->source_line = 0; + (void) list_prepend(def, commentf); + commentf = NULL; + } + /* add an implicit return at end; * also used by 'return' command in debugger */ @@ -5059,7 +5221,6 @@ append_rule(INSTRUCTION *pattern, INSTRUCTION *action) action), tp); } - } list_append(rule_list, rp + 1); |