[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] Improve compatibility between M4 and CPP.
From: |
Raphael 'kena' Poss |
Subject: |
[PATCH] Improve compatibility between M4 and CPP. |
Date: |
Wed, 8 Jul 2009 11:16:03 +0200 |
* src/m4.c: Add new option `--synclines-cpp'.
* src/output.c: Change syncline format when --synclines-cpp is set.
* src/input.c: Allow to change input line number and file name.
* src/m4.h: Expose new primitives from input.c.
* src/builtin.c: Use them in __file__ and __line__.
* doc/m4.texinfo: Document the new features.
* NEWS: Announce them.
---
Hi Eric,
as you suggested I reworked the patch from 1.6, and included documentation
with example and test code. Let me know if there is anything else to improve.
Cheers,
k
NEWS | 6 ++++++
doc/m4.texinfo | 48 +++++++++++++++++++++++++++++++++++++++++++-----
src/builtin.c | 26 ++++++++++++++++++++------
src/input.c | 19 +++++++++++++++++++
src/m4.c | 8 ++++++++
src/m4.h | 5 +++++
src/output.c | 2 +-
7 files changed, 102 insertions(+), 12 deletions(-)
diff --git a/NEWS b/NEWS
index f1d641a..72f0d50 100644
--- a/NEWS
+++ b/NEWS
@@ -147,6 +147,12 @@ contains the following beta features that were deemed
worth deferring until
algorithms based on `$@' operate in linear, rather than quadratic, time
and memory.
+** Enhance the `__file__' and `__line__' builtins so that the input
+ line number and file name can be reset.
+
+** A new `--synclines-cpp' option changes the format of synchronization
+ lines to mimic the C preprocessor.
+
** A number of portability improvements inherited from gnulib.
* Noteworthy changes in Version 1.4.13 (2009-04-01) [stable]
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index 0182979..0a4305f 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -780,6 +780,15 @@
@result{}goodbye
@end example
address@hidden --synclines-cpp
+
+This provides identical behavior to @option{-s} or @option{--synclines},
+but with a different synchronization line format suitable for a C
+compiler without a C preprocessor. With this option synchronization
+lines are of the form @samp{# @var{line} "@var{file}"}. This format is
+suitable when M4 is used as a substitute to the C preprocessor or as a
+filter between preprocessing and compilation.
+
@item -U @var{name}
@itemx address@hidden
This deletes any predefined meaning @var{name} might have. Obviously,
@@ -7711,11 +7720,12 @@
Line numbers start at 1 for each file. If the file was found due to the
@option{-I} option or @env{M4PATH} environment variable, that is
reflected in the file name. The syncline option (@option{-s},
address@hidden features, , Invoking m4}), and the
address@hidden and @samp{l} flags of @code{debugmode} (@pxref{Debugmode}),
-also use this notion of current file and line. Redefining the three
-location macros has no effect on syncline, debug, warning, or error
-message output.
address@hidden features, , Invoking m4}), and the @samp{f} and
address@hidden flags of @code{debugmode} (@pxref{Debugmode}), also use this
+notion of current file and line. Redefining the three location macros
+has no effect on syncline, debug, warning, or error message output,
+although the line numbers and file names can be reset as described
+below.
This example reuses the file @file{incl.m4} mentioned earlier
(@pxref{Include}):
@@ -7773,6 +7783,34 @@
@result{}12
@end example
+The @address@hidden and @address@hidden macros take an optional
+argument which allow to reset the current input file name and line
+number, respectively. If @option{-s} is enabled, a synchronization line
+will be emitted at the next newline in the input. Input line numbers
+will autoincrement from the new value, and the file name will stay
+active for the current input source until the input source is exhausted
+or the name is reset again. This feature can be used when the input to
+M4 already contains synchronization information, as when M4 is used as a
+filter between a preprocessor and a compiler.
+
address@hidden options: -s
address@hidden
+$ @kbd{m4 -s}
+foo __line__(42)bar __line__
+baz __line__
+__line__
address@hidden 1 "stdin"
address@hidden bar 42
address@hidden 43
address@hidden 43
address@hidden
+foo __file__(`newname')bar __file__
+baz __file__
address@hidden bar newname
address@hidden 46 "newname"
address@hidden newname
address@hidden example
+
The @address@hidden macro behaves like @samp{$0} in shell
terminology. If you invoke @code{m4} through an absolute path or a link
with a different spelling, rather than by relying on a @env{PATH} search
diff --git a/src/builtin.c b/src/builtin.c
index 191e05d..f9f35a6 100644
--- a/src/builtin.c
+++ b/src/builtin.c
@@ -1700,17 +1700,31 @@ m4_errprint (struct obstack *obs, int argc,
macro_arguments *argv)
static void
m4___file__ (struct obstack *obs, int argc, macro_arguments *argv)
{
- bad_argc (arg_info (argv), argc, 0, 0);
- obstack_grow (obs, curr_quote.str1, curr_quote.len1);
- obstack_grow (obs, current_file, strlen (current_file));
- obstack_grow (obs, curr_quote.str2, curr_quote.len2);
+ bad_argc (arg_info (argv), argc, 0, 1);
+ if (argc > 1)
+ reset_file (ARG (1));
+ else
+ {
+ obstack_grow (obs, curr_quote.str1, curr_quote.len1);
+ obstack_grow (obs, current_file, strlen (current_file));
+ obstack_grow (obs, curr_quote.str2, curr_quote.len2);
+ }
}
static void
m4___line__ (struct obstack *obs, int argc, macro_arguments *argv)
{
- bad_argc (arg_info (argv), argc, 0, 0);
- shipout_int (obs, current_line);
+ int line;
+
+ bad_argc (arg_info (argv), argc, 0, 1);
+ if (argc > 1)
+ {
+ if (!numeric_arg (arg_info (argv), ARG (1), ARG_LEN (1), &line))
+ return;
+ reset_line (line);
+ }
+ else
+ shipout_int (obs, current_line);
}
static void
diff --git a/src/input.c b/src/input.c
index 129a5f2..940f975 100644
--- a/src/input.c
+++ b/src/input.c
@@ -2301,3 +2301,22 @@ lex_debug (void)
print_token ("lex", t, &td);
}
#endif /* DEBUG_INPUT */
+
+/*---------------------------------.
+ | Reset the current line counter. |
+ `--------------------------------*/
+void reset_line(int line)
+{
+ isp->line = line;
+ input_change = true;
+}
+
+/*-------------------------------.
+ | Reset the current file title. |
+ `------------------------------*/
+void reset_file(const char *title)
+{
+ isp->file = (char *) obstack_copy0 (&file_names, title, strlen (title));
+ output_current_line = -1;
+ input_change = true;
+}
diff --git a/src/m4.c b/src/m4.c
index 0caf868..9189298 100644
--- a/src/m4.c
+++ b/src/m4.c
@@ -237,6 +237,7 @@ Preprocessor features:\n\
-D, --define=NAME[=VALUE] define NAME as having VALUE, or empty\n\
-I, --include=DIRECTORY append DIRECTORY to include path\n\
-s, --synclines generate `#line NUM \"FILE\"' lines\n\
+ --synclines-cpp generate `# NUM \"FILE\" lines\n\
-U, --undefine=NAME undefine NAME\n\
"), stdout);
puts ("");
@@ -307,6 +308,7 @@ enum
{
DEBUGFILE_OPTION = CHAR_MAX + 1, /* no short opt */
WARN_MACRO_SEQUENCE_OPTION, /* no short opt */
+ SYNCLINES_CPP_OPTION, /* no short opt */
HELP_OPTION, /* no short opt */
VERSION_OPTION /* no short opt */
@@ -331,6 +333,7 @@ static const struct option long_options[] =
{"reload-state", required_argument, NULL, 'R'},
{"silent", no_argument, NULL, 'Q'},
{"synclines", no_argument, NULL, 's'},
+ {"synclines-cpp", no_argument, NULL, SYNCLINES_CPP_OPTION},
{"trace", required_argument, NULL, 't'},
{"traditional", no_argument, NULL, 'G'},
{"undefine", required_argument, NULL, 'U'},
@@ -463,6 +466,7 @@ main (int argc, char *const *argv, char *const *envp)
case 's':
case 't':
case DEBUGFILE_OPTION:
+ case SYNCLINES_CPP_OPTION:
defer:
/* Arguments that cannot be handled until later are accumulated. */
@@ -652,6 +656,10 @@ main (int argc, char *const *argv, char *const *envp)
sync_output = 1;
break;
+ case SYNCLINES_CPP_OPTION:
+ sync_output = 2;
+ break;
+
case '\1':
process_file (arg);
break;
diff --git a/src/m4.h b/src/m4.h
index 17184b2..6ed671d 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -562,6 +562,11 @@ void expand_format (struct obstack *, int, macro_arguments
*);
void produce_frozen_state (const char *);
void reload_frozen_state (const char *);
+/* File: input.c --- input sources. */
+
+void reset_line (int);
+void reset_file (const char *);
+
/* Debugging the memory allocator. */
#ifdef WITH_DMALLOC
diff --git a/src/output.c b/src/output.c
index e31f94b..0c09c5b 100644
--- a/src/output.c
+++ b/src/output.c
@@ -665,7 +665,7 @@ divert_text (struct obstack *obs, const char *text, int
length, int line)
if (output_current_line != line)
{
static char line_buf[sizeof "#line " + INT_BUFSIZE_BOUND (line)];
- sprintf (line_buf, "#line %d", line);
+ sprintf (line_buf, (sync_output == 1) ? "#line %d" : "# %d",
line);
output_text (line_buf, strlen (line_buf));
assert (strlen (line_buf) < sizeof line_buf);
if (output_current_line < 1 && current_file[0] != '\0')
--
1.6.3.2