|
33 | 33 | static void output_init(void); |
34 | 34 | #define YY_USER_INIT output_init() |
35 | 35 |
|
| 36 | +static void handle_line_directive(void); |
| 37 | + |
36 | 38 | static void def_start(void); |
37 | 39 | static void def_add_arg(void); |
38 | 40 | static void def_finish(void); |
@@ -215,10 +217,17 @@ W [ \t\b\f]+ |
215 | 217 | * older versions of flex (at least 2.5.31); they are supposed to |
216 | 218 | * be implied, according to the flex manual. |
217 | 219 | */ |
218 | | -keywords (include|define|undef|ifdef|ifndef|else|elsif|endif) |
| 220 | +keywords (line|include|define|undef|ifdef|ifndef|else|elsif|endif) |
219 | 221 |
|
220 | 222 | %% |
221 | 223 |
|
| 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 | + */ |
222 | 231 | "//"[^\r\n]* { ECHO; } |
223 | 232 |
|
224 | 233 | /* detect multiline, c-style comments, passing them directly to the |
@@ -693,6 +702,87 @@ keywords (include|define|undef|ifdef|ifndef|else|elsif|endif) |
693 | 702 | <<EOF>> { if (!load_next_input()) yyterminate(); } |
694 | 703 |
|
695 | 704 | %% |
| 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 | + |
696 | 786 | /* Defined macros are kept in this table for convenient lookup. As |
697 | 787 | * `define directives are matched (and the do_define() function |
698 | 788 | * called) the tree is built up to match names with values. If a |
|
0 commit comments