aboutsummaryrefslogtreecommitdiffstats
path: root/awkgram.y
diff options
context:
space:
mode:
Diffstat (limited to 'awkgram.y')
-rw-r--r--awkgram.y205
1 files changed, 183 insertions, 22 deletions
diff --git a/awkgram.y b/awkgram.y
index 0f57b452..19ab4d68 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -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);