From ae41c5034ad074228290407c0272c8b8035974f4 Mon Sep 17 00:00:00 2001 From: Joerg Henrichs Date: Mon, 13 Apr 2026 01:57:40 +1000 Subject: [PATCH 01/13] #390 Start to add support for linemarker. --- src/fparser/two/C99Preprocessor.py | 46 +++++++++++++++++++ src/fparser/two/tests/test_c99preprocessor.py | 13 ++++++ 2 files changed, 59 insertions(+) diff --git a/src/fparser/two/C99Preprocessor.py b/src/fparser/two/C99Preprocessor.py index 3b42a211..9a9e9204 100644 --- a/src/fparser/two/C99Preprocessor.py +++ b/src/fparser/two/C99Preprocessor.py @@ -57,6 +57,7 @@ "Cpp_Macro_Stmt", "Cpp_Undef_Stmt", "Cpp_Line_Stmt", + "Cpp_Linemarker_Stmt", "Cpp_Error_Stmt", "Cpp_Warning_Stmt", "Cpp_Null_Stmt", @@ -649,6 +650,51 @@ def tostr(self): return "{0} {1}".format(*self.items) +class Cpp_Linemarker_Stmt(WORDClsBase): # Linemarker + """ + Linemarker + + linemarker-stmt is # digit-sequence [ "s-char-sequence" ] [digit ...] + """ + + subclass_names = [] + use_names = ["", "Cpp_Pp_Tokens"] + + _pattern = pattern.Pattern("", + r"^\s*#", + value="#") + + @staticmethod + def match(string): + """Implements the matching for a linemarker. + The right hand side of the directive is not matched any further + but simply kept as a string. + + :param str string: the string to match with as a line statement. + + :return: a tuple of size 1 with the right hand side as a string, \ + or `None` if there is no match. + :rtype: (`str`) or `NoneType` + + """ + if not string: + return None + return WORDClsBase.match( + Cpp_Linemarker_Stmt._pattern, + Cpp_Pp_Tokens, + string, + colons=False, + require_cls=True, + ) + + def tostr(self): + """ + :return: this linemarker as a string. + :rtype: str + """ + return "{0} {1}".format(*self.items) + + class Cpp_Error_Stmt(WORDClsBase): # 6.10.5 Error directive """ C99 6.10.5 Error directive diff --git a/src/fparser/two/tests/test_c99preprocessor.py b/src/fparser/two/tests/test_c99preprocessor.py index 921796a6..606af895 100644 --- a/src/fparser/two/tests/test_c99preprocessor.py +++ b/src/fparser/two/tests/test_c99preprocessor.py @@ -57,6 +57,7 @@ Cpp_Macro_Identifier_List, Cpp_Undef_Stmt, Cpp_Line_Stmt, + Cpp_Linemarker_Stmt, Cpp_Error_Stmt, Cpp_Warning_Stmt, Cpp_Null_Stmt, @@ -451,6 +452,18 @@ def test_incorrect_line_stmt(line): assert "Cpp_Line_Stmt: '{0}'".format(line) in str(excinfo.value) +@pytest.mark.usefixtures("f2003_create") +@pytest.mark.parametrize("line_ref", + [('# 123 "file"', '# 123 "file"'), + (' # 123 "file" ', '# 123 "file"'), + ('# 123 "file" 1 3', '# 123 "file" 1 3')]) +def test_linemarker_statement(line_ref): + """Test that #line is recognized""" + line, ref = line_ref + result = Cpp_Linemarker_Stmt(line) + assert str(result) == ref + + @pytest.mark.usefixtures("f2003_create") @pytest.mark.parametrize("line", ["#error MSG", " # error MSG "]) def test_error_statement_with_msg(line): From 5e124e56c765709bdaf5c2212abd4ce18ffcdbc8 Mon Sep 17 00:00:00 2001 From: Joerg Henrichs Date: Mon, 13 Apr 2026 13:00:21 +1000 Subject: [PATCH 02/13] #390 Improve linermarker handling to support detection of invalid markers. --- src/fparser/two/C99Preprocessor.py | 22 ++++++++++++++---- src/fparser/two/tests/test_c99preprocessor.py | 23 +++++++++++++++---- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/fparser/two/C99Preprocessor.py b/src/fparser/two/C99Preprocessor.py index 9a9e9204..b2ab25b3 100644 --- a/src/fparser/two/C99Preprocessor.py +++ b/src/fparser/two/C99Preprocessor.py @@ -32,7 +32,11 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -"""C99 Preprocessor Syntax Rules.""" +"""C99 Preprocessor Syntax Rules. It also supports linemarker statements +(which are technically not preprocessor directives, but are very close +in their syntax, i.e. starting with `#`) + +""" # Author: Balthasar Reuter # Based on previous work by Martin Schlipf (https://github.com/martin-schlipf) @@ -658,11 +662,11 @@ class Cpp_Linemarker_Stmt(WORDClsBase): # Linemarker """ subclass_names = [] - use_names = ["", "Cpp_Pp_Tokens"] + use_names = ["Cpp_Pp_Tokens"] - _pattern = pattern.Pattern("", - r"^\s*#", - value="#") + # The match method will check that it is a valid linemarker, i.e. + # it has a line number, and file name in double quotes. + _pattern = pattern.Pattern("", r"^\s*#", value="#") @staticmethod def match(string): @@ -679,6 +683,14 @@ def match(string): """ if not string: return None + + # We can't fully rely on WORDClsBase, since it can't easily + # test if there is a line number following (it returns + # `value` for a match, but can't insert the matched line number + # in this value). + if not re.match(r"^\s*#\s+[0-9]+\s+\".*\"", string): + return + return WORDClsBase.match( Cpp_Linemarker_Stmt._pattern, Cpp_Pp_Tokens, diff --git a/src/fparser/two/tests/test_c99preprocessor.py b/src/fparser/two/tests/test_c99preprocessor.py index 606af895..7ed23629 100644 --- a/src/fparser/two/tests/test_c99preprocessor.py +++ b/src/fparser/two/tests/test_c99preprocessor.py @@ -453,17 +453,30 @@ def test_incorrect_line_stmt(line): @pytest.mark.usefixtures("f2003_create") -@pytest.mark.parametrize("line_ref", - [('# 123 "file"', '# 123 "file"'), - (' # 123 "file" ', '# 123 "file"'), - ('# 123 "file" 1 3', '# 123 "file" 1 3')]) -def test_linemarker_statement(line_ref): +@pytest.mark.parametrize( + "line_ref", + [ + ('# 123 "file"', '# 123 "file"'), + (' # 123 "file" ', '# 123 "file"'), + ('# 123 "file" 1 3', '# 123 "file" 1 3'), + ], +) +def test_linemarker(line_ref): """Test that #line is recognized""" line, ref = line_ref result = Cpp_Linemarker_Stmt(line) assert str(result) == ref +@pytest.mark.usefixtures("f2003_create") +@pytest.mark.parametrize("line", ["# abc", '# "bla"', "# 123 'wrong_quotes'"]) +def test_incorrect_linemarker(line): + """Test that incorrectly formed #line statements raise exception""" + with pytest.raises(NoMatchError) as excinfo: + _ = Cpp_Linemarker_Stmt(line) + assert "Cpp_Linemarker_Stmt: '{0}'".format(line) in str(excinfo.value) + + @pytest.mark.usefixtures("f2003_create") @pytest.mark.parametrize("line", ["#error MSG", " # error MSG "]) def test_error_statement_with_msg(line): From 7e482a225b2f7bf6f234f19fc0fa8e311c6a3976 Mon Sep 17 00:00:00 2001 From: Joerg Henrichs Date: Thu, 16 Apr 2026 22:41:05 +1000 Subject: [PATCH 03/13] #390 Simplified parameterization. --- src/fparser/two/tests/test_c99preprocessor.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/fparser/two/tests/test_c99preprocessor.py b/src/fparser/two/tests/test_c99preprocessor.py index 7ed23629..232491f4 100644 --- a/src/fparser/two/tests/test_c99preprocessor.py +++ b/src/fparser/two/tests/test_c99preprocessor.py @@ -454,16 +454,15 @@ def test_incorrect_line_stmt(line): @pytest.mark.usefixtures("f2003_create") @pytest.mark.parametrize( - "line_ref", + "line, ref", [ ('# 123 "file"', '# 123 "file"'), (' # 123 "file" ', '# 123 "file"'), ('# 123 "file" 1 3', '# 123 "file" 1 3'), ], ) -def test_linemarker(line_ref): +def test_linemarker(line, ref): """Test that #line is recognized""" - line, ref = line_ref result = Cpp_Linemarker_Stmt(line) assert str(result) == ref From 88a74ee0617eb3c543a3e453acb01e8672402b6c Mon Sep 17 00:00:00 2001 From: Joerg Henrichs Date: Thu, 16 Apr 2026 23:50:29 +1000 Subject: [PATCH 04/13] #390 Fix incorrect linemarker specification in comment. --- src/fparser/two/C99Preprocessor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fparser/two/C99Preprocessor.py b/src/fparser/two/C99Preprocessor.py index b2ab25b3..2f81d17b 100644 --- a/src/fparser/two/C99Preprocessor.py +++ b/src/fparser/two/C99Preprocessor.py @@ -658,7 +658,7 @@ class Cpp_Linemarker_Stmt(WORDClsBase): # Linemarker """ Linemarker - linemarker-stmt is # digit-sequence [ "s-char-sequence" ] [digit ...] + linemarker-stmt is # digit-sequence "s-char-sequence" [digit ...] """ subclass_names = [] From 8eb39542df43bc4ba10815250197ca5b3c6a1261 Mon Sep 17 00:00:00 2001 From: Joerg Henrichs Date: Thu, 16 Apr 2026 23:53:32 +1000 Subject: [PATCH 05/13] #390 Remove need for using an additional regex to verify the linemarker syntax. Extend match function to be able to return the fully matched string. --- src/fparser/two/C99Preprocessor.py | 16 ++++++---------- src/fparser/two/tests/test_c99preprocessor.py | 2 +- src/fparser/two/utils.py | 7 ++++++- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/fparser/two/C99Preprocessor.py b/src/fparser/two/C99Preprocessor.py index 2f81d17b..6fab5e62 100644 --- a/src/fparser/two/C99Preprocessor.py +++ b/src/fparser/two/C99Preprocessor.py @@ -666,7 +666,7 @@ class Cpp_Linemarker_Stmt(WORDClsBase): # Linemarker # The match method will check that it is a valid linemarker, i.e. # it has a line number, and file name in double quotes. - _pattern = pattern.Pattern("", r"^\s*#", value="#") + _pattern = pattern.Pattern("", r"^\s*#\s+\d+\s+\".*\".*$") @staticmethod def match(string): @@ -684,27 +684,23 @@ def match(string): if not string: return None - # We can't fully rely on WORDClsBase, since it can't easily - # test if there is a line number following (it returns - # `value` for a match, but can't insert the matched line number - # in this value). - if not re.match(r"^\s*#\s+[0-9]+\s+\".*\"", string): - return - return WORDClsBase.match( Cpp_Linemarker_Stmt._pattern, Cpp_Pp_Tokens, string, colons=False, - require_cls=True, + require_cls=False, ) def tostr(self): """ + Returns the line marker as string. Note that fparser accepts + spaces before the `#`, but it should remove the spaces, hence + we lstrip the result :return: this linemarker as a string. :rtype: str """ - return "{0} {1}".format(*self.items) + return self.items[0].lstrip() class Cpp_Error_Stmt(WORDClsBase): # 6.10.5 Error directive diff --git a/src/fparser/two/tests/test_c99preprocessor.py b/src/fparser/two/tests/test_c99preprocessor.py index 232491f4..00d55ad3 100644 --- a/src/fparser/two/tests/test_c99preprocessor.py +++ b/src/fparser/two/tests/test_c99preprocessor.py @@ -457,7 +457,7 @@ def test_incorrect_line_stmt(line): "line, ref", [ ('# 123 "file"', '# 123 "file"'), - (' # 123 "file" ', '# 123 "file"'), + (' # 123 "file"', '# 123 "file"'), ('# 123 "file" 1 3', '# 123 "file" 1 3'), ], ) diff --git a/src/fparser/two/utils.py b/src/fparser/two/utils.py index 7a179d2e..48a99653 100644 --- a/src/fparser/two/utils.py +++ b/src/fparser/two/utils.py @@ -1819,7 +1819,12 @@ def match(keyword, cls, string, colons=False, require_cls=False): if my_match is None: return None line = string[len(my_match.group()) :] - pattern_value = keyword.value + # If no constant return value is defined, + # return the matched string + if keyword.value: + pattern_value = keyword.value + else: + pattern_value = my_match.group() if not line: if require_cls: From fedc82c5419e0b10b996f50f666c26a6d797d940 Mon Sep 17 00:00:00 2001 From: Joerg Henrichs Date: Wed, 22 Apr 2026 10:38:20 +1000 Subject: [PATCH 06/13] #390 Updated manual. --- doc/source/fparser2.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/source/fparser2.rst b/doc/source/fparser2.rst index a7571db7..a827cd61 100644 --- a/doc/source/fparser2.rst +++ b/doc/source/fparser2.rst @@ -552,6 +552,12 @@ backslash character `\\` at the end of the line. __ http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf#page=157 +Added is the support for compiler linemarkers, i.e. lines in the format +``# line-number "filename"``, which indicates for a compiler the line number +and filename that the next line came from. While technically not a preprocessor +directive, these statements follow a very similar syntax so their handling +is combined with the preprocessor handling. + The implementation of directives is in the C99Preprocessor.py `file`__ with support for the following:: @@ -568,6 +574,7 @@ with support for the following:: #error #warning # + # line-number "filename" __ https://github.com/stfc/fparser/blob/master/src/fparser/two/C99Preprocessor.py From 8480ccf8c808e013c5d58bf31ba8870a37f370e5 Mon Sep 17 00:00:00 2001 From: Joerg Henrichs Date: Wed, 22 Apr 2026 10:40:16 +1000 Subject: [PATCH 07/13] #390 Updated comments and added proper typing. --- src/fparser/two/C99Preprocessor.py | 35 ++++++++++++++++++++---------- src/fparser/two/utils.py | 12 +++++++--- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/fparser/two/C99Preprocessor.py b/src/fparser/two/C99Preprocessor.py index 6fab5e62..bbd25585 100644 --- a/src/fparser/two/C99Preprocessor.py +++ b/src/fparser/two/C99Preprocessor.py @@ -44,6 +44,7 @@ import re import sys +from typing import Optional, Union from fparser.common.readfortran import FortranReaderBase, CppDirective from fparser.two import pattern_tools as pattern @@ -656,7 +657,12 @@ def tostr(self): class Cpp_Linemarker_Stmt(WORDClsBase): # Linemarker """ - Linemarker + This class represents a Linemarker. A linemarker indicates the + line number and file name the following line is coming from (e.g. + if a file has been inlined, this will allow the compiler to correctly + indicate the original source line). While linemarkers are technically + not preprocessor directives, their syntax is very similar, so they are + handled here. linemarker-stmt is # digit-sequence "s-char-sequence" [digit ...] """ @@ -665,20 +671,25 @@ class Cpp_Linemarker_Stmt(WORDClsBase): # Linemarker use_names = ["Cpp_Pp_Tokens"] # The match method will check that it is a valid linemarker, i.e. - # it has a line number, and file name in double quotes. - _pattern = pattern.Pattern("", r"^\s*#\s+\d+\s+\".*\".*$") + # it has a line number, and file name in double quotes. Setting value + # to None means that the pattern matching will return the matched + # string (i.e. `# linenumber "filename"`), any following flags will + # be stored as items of type Cpp_Pp_Tokens. + _pattern = pattern.Pattern("", r"^\s*#\s+\d+\s+\".*\".*$", + value=None) @staticmethod - def match(string): + def match( + string: Union[str, FortranReaderBase] + ) -> Optional[tuple[str, "Cpp_Linemarker_Stmt"]]: """Implements the matching for a linemarker. - The right hand side of the directive is not matched any further - but simply kept as a string. + The optional flag (digits) allowed after the file name are not matched + any further but simply kept as a string. - :param str string: the string to match with as a line statement. + :param string: the string to match with as a line statement. - :return: a tuple of size 1 with the right hand side as a string, \ - or `None` if there is no match. - :rtype: (`str`) or `NoneType` + :return: an instance of Cpp_Linemarker_Stmt or `None` if there is no + match. """ if not string: @@ -692,13 +703,13 @@ def match(string): require_cls=False, ) - def tostr(self): + def tostr(self) -> str: """ Returns the line marker as string. Note that fparser accepts spaces before the `#`, but it should remove the spaces, hence we lstrip the result + :return: this linemarker as a string. - :rtype: str """ return self.items[0].lstrip() diff --git a/src/fparser/two/utils.py b/src/fparser/two/utils.py index 48a99653..1fb5fc2a 100644 --- a/src/fparser/two/utils.py +++ b/src/fparser/two/utils.py @@ -1793,7 +1793,7 @@ def match(keyword, cls, string, colons=False, require_cls=False): 2-tuple containing a string matching the 'WORD' and an \ instance of 'cls' (or None if an instance of cls is not \ required and not provided). - :rtype: Optional[Tupe[Str, Optional[Cls]]] + :rtype: Optional[Tuple[Str, Optional[Cls]]] """ if isinstance(keyword, (tuple, list)): @@ -1819,8 +1819,14 @@ def match(keyword, cls, string, colons=False, require_cls=False): if my_match is None: return None line = string[len(my_match.group()) :] - # If no constant return value is defined, - # return the matched string + # Most patterns set a return value to be used, in order to remove + # white space (e.g. the pattern might be "^\s*(#\s*undef)\b", + # but the return value is `#undef`, meaning all optional white + # space will be removed. But in case of linemarkers, we need + # to match a non-constant expression (`# linenumber "filename"`). + # In this case, value is set to None, and we return the matched + # original string (i.e. the actual line number and filename + # specified) if keyword.value: pattern_value = keyword.value else: From b5e1f9f1afca3b228f553f695da37d02c0e91540 Mon Sep 17 00:00:00 2001 From: Joerg Henrichs Date: Wed, 22 Apr 2026 10:44:16 +1000 Subject: [PATCH 08/13] #390 Added test that preprocessor directives are indeed properly parsed when they are in a Fortran program. --- src/fparser/two/tests/test_c99preprocessor.py | 42 ++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/fparser/two/tests/test_c99preprocessor.py b/src/fparser/two/tests/test_c99preprocessor.py index 00d55ad3..11ca74fd 100644 --- a/src/fparser/two/tests/test_c99preprocessor.py +++ b/src/fparser/two/tests/test_c99preprocessor.py @@ -63,7 +63,8 @@ Cpp_Null_Stmt, Cpp_Pp_Tokens, ) -from fparser.two.utils import NoMatchError +from fparser.two.Fortran2003 import Program +from fparser.two.utils import NoMatchError, walk from fparser.api import get_reader @@ -550,3 +551,42 @@ def test_incorrect_null_stmt(line): with pytest.raises(NoMatchError) as excinfo: _ = Cpp_Null_Stmt(line) assert "Cpp_Null_Stmt: '{0}'".format(line) in str(excinfo.value) + + +@pytest.mark.usefixtures("f2003_create") +@pytest.mark.parametrize( + "cpp_class, cpp_directive", + [ + (Cpp_If_Stmt, "#if CONST"), + (Cpp_Elif_Stmt, "#elif CONST"), + (Cpp_Endif_Stmt, "#endif"), + (Cpp_Include_Stmt, '#include "test.inc"'), + (Cpp_Macro_Stmt, "#define a b"), + (Cpp_Undef_Stmt, "#undef a"), + (Cpp_Line_Stmt, "#line 123"), + (Cpp_Linemarker_Stmt, '# 123 "test.f90"'), + (Cpp_Error_Stmt, "#error 123"), + (Cpp_Warning_Stmt, "#warning 123"), + (Cpp_Null_Stmt, "#"), + ], +) +def test_cpp_in_fortran(cpp_class, cpp_directive): + """ + Verify that all cpp directives are correctly parsed as part of + a real program. + """ + code = f""" + program test + integer a + {cpp_directive} + a = 2 + end program + """ + reader = get_reader(code) + + obj = Program(reader) + all_cpp_nodes = walk(obj, cpp_class) + + # There must be exactly one cpp node + assert len(all_cpp_nodes) == 1 + assert str(all_cpp_nodes[0]) == cpp_directive From 76441b68436ab8a70a86d614de84a1f65341c043 Mon Sep 17 00:00:00 2001 From: Joerg Henrichs Date: Wed, 22 Apr 2026 11:20:27 +1000 Subject: [PATCH 09/13] #390 Moved location of preprocessor directive (which means it is now parsed in utils as part of classes, not as part of add_comments_includes_directives anymore). --- src/fparser/two/tests/test_c99preprocessor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fparser/two/tests/test_c99preprocessor.py b/src/fparser/two/tests/test_c99preprocessor.py index 11ca74fd..2301759c 100644 --- a/src/fparser/two/tests/test_c99preprocessor.py +++ b/src/fparser/two/tests/test_c99preprocessor.py @@ -577,8 +577,8 @@ def test_cpp_in_fortran(cpp_class, cpp_directive): """ code = f""" program test - integer a {cpp_directive} + integer a a = 2 end program """ From 099a8189503a9cbc82af27be327e58700bc299dd Mon Sep 17 00:00:00 2001 From: Joerg Henrichs Date: Wed, 22 Apr 2026 11:24:41 +1000 Subject: [PATCH 10/13] #390 Fixed black. --- src/fparser/two/C99Preprocessor.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/fparser/two/C99Preprocessor.py b/src/fparser/two/C99Preprocessor.py index bbd25585..5de8cdab 100644 --- a/src/fparser/two/C99Preprocessor.py +++ b/src/fparser/two/C99Preprocessor.py @@ -675,8 +675,7 @@ class Cpp_Linemarker_Stmt(WORDClsBase): # Linemarker # to None means that the pattern matching will return the matched # string (i.e. `# linenumber "filename"`), any following flags will # be stored as items of type Cpp_Pp_Tokens. - _pattern = pattern.Pattern("", r"^\s*#\s+\d+\s+\".*\".*$", - value=None) + _pattern = pattern.Pattern("", r"^\s*#\s+\d+\s+\".*\".*$", value=None) @staticmethod def match( From 1634379d6e28beb7da66551b77c4d84c07062451 Mon Sep 17 00:00:00 2001 From: Joerg Henrichs Date: Wed, 22 Apr 2026 11:29:14 +1000 Subject: [PATCH 11/13] #390 Fix for github black, my black does not need that comma. --- src/fparser/two/C99Preprocessor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fparser/two/C99Preprocessor.py b/src/fparser/two/C99Preprocessor.py index 5de8cdab..d7841699 100644 --- a/src/fparser/two/C99Preprocessor.py +++ b/src/fparser/two/C99Preprocessor.py @@ -679,7 +679,7 @@ class Cpp_Linemarker_Stmt(WORDClsBase): # Linemarker @staticmethod def match( - string: Union[str, FortranReaderBase] + string: Union[str, FortranReaderBase], ) -> Optional[tuple[str, "Cpp_Linemarker_Stmt"]]: """Implements the matching for a linemarker. The optional flag (digits) allowed after the file name are not matched From 27c7817a842eaf5d0eff79a49fe46165c0c026a0 Mon Sep 17 00:00:00 2001 From: Joerg Henrichs Date: Tue, 28 Apr 2026 11:46:29 +1000 Subject: [PATCH 12/13] #390 Fix missing ',' which resulted in incorrectly concatenating strings. --- src/fparser/two/tests/test_c99preprocessor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fparser/two/tests/test_c99preprocessor.py b/src/fparser/two/tests/test_c99preprocessor.py index 2301759c..be2a11f5 100644 --- a/src/fparser/two/tests/test_c99preprocessor.py +++ b/src/fparser/two/tests/test_c99preprocessor.py @@ -368,7 +368,8 @@ def test_macro_stmt_with_whitespace(line, ref): "#def", "#defnie", "#definex", - "#define 2a" "#define fail(...,test) test", + "#define 2a" + "#define fail(...,test) test", "#define", "#define fail(...,...)", ], From 773ff8aa5ac2614dab49fd70816deec988645837 Mon Sep 17 00:00:00 2001 From: Joerg Henrichs Date: Tue, 28 Apr 2026 11:49:55 +1000 Subject: [PATCH 13/13] #390 Fixed previous fix - oops. --- src/fparser/two/tests/test_c99preprocessor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fparser/two/tests/test_c99preprocessor.py b/src/fparser/two/tests/test_c99preprocessor.py index be2a11f5..37f4ef83 100644 --- a/src/fparser/two/tests/test_c99preprocessor.py +++ b/src/fparser/two/tests/test_c99preprocessor.py @@ -368,7 +368,7 @@ def test_macro_stmt_with_whitespace(line, ref): "#def", "#defnie", "#definex", - "#define 2a" + "#define 2a", "#define fail(...,test) test", "#define", "#define fail(...,...)",