Skip to content

Commit

Permalink
yacc: Correctly handle epilogue
Browse files Browse the repository at this point in the history
The change in mio_new_mio() exposed a problem in yacc parser where
epilogue parsing didn't work correctly and the reason it worked was
only thanks to the strange mio_new_mio() semantics.

First, in runYaccParser() the line shouldn't be read because this is
the first (and possibly last) line of epilogue and this way it gets
ignored and offsets for the promise API aren't calculated for it.
Because of this change, we have to add 1 to c_start and c_source_start
inside make_promise_for_epilogue() so we get real start of epilogue.

Second, the loop

while ((tmp = readLineFromInputFile ()))
	last = tmp;

didn't do what the author thought it was doing. The idea behind it
probably was to "remember" the last line and subsequently to compute
its length. This however doesn't work this way - because
readLineFromInputFile() returns a const pointer into an internal
buffer inside ctags main, the last time readLineFromInputFile()
is called and when it returns NULL this value is cleared so no matter
what the "last" variable contained, it would always be an empty string
after the loop finishes.

This patch just moves the calculation of endCharOffset inside the loop
where the line value is still valid. It means some unnecessary strlen()
calculation of all lines in the epilogue but I don't think it has a
big overall impact on the performance.

The unfortunate side-effect of this patch is that if a tag appears
on the last line of the file, we can't say whether the line ends with
\n or not because readLineFromInputFile() silently discards them. This
means that the test in which there's a tag at the last line doesn't
contain $ in the pattern. This problem didn't appear before the change
in MIO because thanks to the various bugs in the yacc parser, the start
line was equal to the end line and both offsets were 0 so the size
for mio_new_mio() was 0 and it was created till the end of the file.
  • Loading branch information
techee committed Dec 15, 2018
1 parent 915d697 commit ee887ea
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Units/parser-yacc.r/bom.d/expected.tags
@@ -1,2 +1,2 @@
x input.y /^int x;$/;" v line:2 typeref:typename:int
y input.y /^int y;$/;" v line:8 typeref:typename:int
y input.y /^int y;/;" v line:8 typeref:typename:int
20 changes: 11 additions & 9 deletions parsers/yacc.c
Expand Up @@ -102,22 +102,25 @@ static bool leave_union (const char *line CTAGS_ATTR_UNUSED,

static void make_promise_for_epilogue (void)
{
const unsigned char *tmp, *last;
const unsigned char *tmp;
long endCharOffset;
unsigned long c_start;
unsigned long c_source_start;
unsigned long c_end;

c_start = getInputLineNumber ();
c_source_start = getSourceLineNumber();
/* We are at line with %% so the next line is the start of epilogue */
c_start = getInputLineNumber () + 1;
c_source_start = getSourceLineNumber() + 1;

/* Skip the lines for finding the EOF. */
endCharOffset = 0;
last = NULL;
while ((tmp = readLineFromInputFile ()))
last = tmp;
if (last)
endCharOffset = strlen ((const char *)last);
{
/* We want to get strlen() of the last line only but because
* readLineFromInputFile() invalidates the previous value, get
* endCharOffset here while the tmp variable is valid. */
endCharOffset = strlen ((const char *)tmp);
}
/* If `last' is too long, strlen returns a too large value
for the positive area of `endCharOffset'. */
if (endCharOffset < 0)
Expand Down Expand Up @@ -199,8 +202,7 @@ static void runYaccParser (void)
}
else if (parserState.area == YACC_C_EPILOGUE)
{
if (readLineFromInputFile ())
make_promise_for_epilogue ();
make_promise_for_epilogue ();
}
last_area = parserState.area;
}
Expand Down

0 comments on commit ee887ea

Please sign in to comment.