Skip to content

Commit 9a2c43e

Browse files
Recognise and obey `line directives in the preprocessor (issue #488)
To correctly restore the file name and line number after including a file or expanding a macro, the preprocessor needs to be aware of the changes introduced by `line directives. The `line directive still needs to be passed on to the main compiler so it can track the changes too. To avoid duplicate error messages, the preprocessor silently ignores invalid `line directives, relying on the main compiler to report the errors.
1 parent 45db0db commit 9a2c43e

File tree

1 file changed

+91
-1
lines changed

1 file changed

+91
-1
lines changed

ivlpp/lexor.lex

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
static void output_init(void);
3434
#define YY_USER_INIT output_init()
3535

36+
static void handle_line_directive(void);
37+
3638
static void def_start(void);
3739
static void def_add_arg(void);
3840
static void def_finish(void);
@@ -215,10 +217,17 @@ W [ \t\b\f]+
215217
* older versions of flex (at least 2.5.31); they are supposed to
216218
* be implied, according to the flex manual.
217219
*/
218-
keywords (include|define|undef|ifdef|ifndef|else|elsif|endif)
220+
keywords (line|include|define|undef|ifdef|ifndef|else|elsif|endif)
219221

220222
%%
221223

224+
/* Recognize and handle the `line directive. Also pass it through to
225+
* the output so the main compiler is aware of the change.
226+
*/
227+
^[ \t]?"`line"[ \t]+.+ { handle_line_directive(); ECHO; }
228+
229+
/* Detect single line comments, passing them directly to the output.
230+
*/
222231
"//"[^\r\n]* { ECHO; }
223232

224233
/* detect multiline, c-style comments, passing them directly to the
@@ -693,6 +702,87 @@ keywords (include|define|undef|ifdef|ifndef|else|elsif|endif)
693702
<<EOF>> { if (!load_next_input()) yyterminate(); }
694703

695704
%%
705+
/*
706+
* Parse a `line directive and set the current file name and line
707+
* number accordingly. This ensures we restore the correct name
708+
* and line number when returning from an include file or macro
709+
* expansion. Ignore an invalid directive - the main compiler
710+
* will report the error.
711+
*/
712+
static void handle_line_directive(void)
713+
{
714+
char *cp;
715+
char *cpr;
716+
unsigned long lineno;
717+
char*fn_start;
718+
char*fn_end;
719+
720+
/* Skip any leading space. */
721+
cp = strchr(yytext, '`');
722+
/* Skip the `line directive. */
723+
assert(strncmp(cp, "`line", 5) == 0);
724+
cp += 5;
725+
726+
/* strtoul skips leading space. */
727+
lineno = strtoul(cp, &cpr, 10);
728+
if (cp == cpr || lineno == 0) {
729+
return;
730+
}
731+
cp = cpr;
732+
733+
/* Skip the space between the line number and the file name. */
734+
cpr += strspn(cp, " \t");
735+
if (cp == cpr) {
736+
return;
737+
}
738+
cp = cpr;
739+
740+
/* Find the starting " and skip it. */
741+
fn_start = strchr(cp, '"');
742+
if (cp != fn_start) {
743+
return;
744+
}
745+
fn_start += 1;
746+
747+
/* Find the last ". */
748+
fn_end = strrchr(fn_start, '"');
749+
if (!fn_end) {
750+
return;
751+
}
752+
753+
/* Skip the space after the file name. */
754+
cp = fn_end + 1;
755+
cpr = cp;
756+
cpr += strspn(cp, " \t");
757+
if (cp == cpr) {
758+
return;
759+
}
760+
cp = cpr;
761+
762+
/* Check that the level is correct, we do not need the level. */
763+
if (strspn(cp, "012") != 1) {
764+
return;
765+
}
766+
cp += 1;
767+
768+
/* Verify that only space is left. */
769+
cp += strspn(cp, " \t");
770+
if ((size_t)(cp-yytext) != strlen(yytext)) {
771+
return;
772+
}
773+
774+
/* Update the current file name and line number. Subtract 1 from
775+
the line number because `line sets the number for the next
776+
line, and 1 because our line numbers are zero-based. This
777+
will underflow on line 1, but that's OK because we are using
778+
unsigned arithmetic. */
779+
assert(istack);
780+
realloc(istack->path, fn_end-fn_start+1);
781+
strncpy(istack->path, fn_start, fn_end-fn_start);
782+
istack->path[fn_end-fn_start] = '\0';
783+
istack->lineno = lineno - 2;
784+
}
785+
696786
/* Defined macros are kept in this table for convenient lookup. As
697787
* `define directives are matched (and the do_define() function
698788
* called) the tree is built up to match names with values. If a

0 commit comments

Comments
 (0)