1111 ParserError ,
1212)
1313from dissect .cstruct .expression import Expression
14- from dissect .cstruct .lexer import _IDENTIFIER_TYPES , TokenCursor , TokenType , tokenize
14+ from dissect .cstruct .lexer import IDENTIFIER_TYPES , TokenCursor , TokenType , tokenize
1515from dissect .cstruct .types import BaseArray , BaseType , Field , Structure
1616
1717if TYPE_CHECKING :
@@ -74,12 +74,7 @@ def parse(self, data: str) -> None:
7474
7575 data = _join_line_continuations (data )
7676
77- # Tokenize and preprocess the input, then parse top-level definitions
7877 self ._reset_tokens (tokenize (data ))
79- preprocessed_tokens = self ._preprocess ()
80- self .reset ()
81-
82- self ._reset_tokens (preprocessed_tokens )
8378 self ._parse ()
8479
8580 def _match (self , * types : TokenType ) -> Token | None :
@@ -95,46 +90,41 @@ def _at(self, *types: TokenType) -> bool:
9590 def _error (self , msg : str , * , token : Token | None = None ) -> ParserError :
9691 return ParserError (f"line { (token if token is not None else self ._tokens [self ._pos ]).line } : { msg } " )
9792
98- def _preprocess (self ) -> list [ Token ] :
99- """Handle preprocessor directives and return a new list of tokens with directives processed ."""
100- result = [ ]
93+ def _in_false_branch (self ) -> bool :
94+ """Return whether we're currently in a false conditional branch ."""
95+ return bool ( self . _conditional_stack ) and not self . _conditional_stack [ - 1 ][ 1 ]
10196
102- while self . _tokens [ self . _pos ]. type != TokenType . EOF :
103- token = self . _tokens [ self . _pos ]
97+ def _handle_preprocessor ( self ) -> bool :
98+ """Handle preprocessor directives.
10499
105- # Always handle conditional directives first (even in false branches)
106- if token .type in (TokenType .PP_IFDEF , TokenType .PP_IFNDEF , TokenType .PP_ELSE , TokenType .PP_ENDIF ):
107- self ._handle_conditional ()
108- continue
100+ Returns ``True`` if a directive was processed, indicating the caller should continue its loop.
101+ """
102+ token = self ._current ()
109103
110- # If we're in a false conditional branch, skip this token
111- if self ._conditional_stack and not self ._conditional_stack [- 1 ][1 ]:
112- self ._pos += 1
113- continue
104+ if token .type in (TokenType .PP_IFDEF , TokenType .PP_IFNDEF , TokenType .PP_ELSE , TokenType .PP_ENDIF ):
105+ self ._handle_conditional ()
106+ return True
114107
115- if token .type == TokenType .PP_DEFINE :
116- self ._parse_define ()
117- elif token .type == TokenType .PP_UNDEF :
118- self ._parse_undef ()
119- elif token .type == TokenType .PP_INCLUDE :
120- self ._parse_include ()
121- else :
122- # Not a preprocessor directive, just add it to the result
123- result .append (token )
124- self ._pos += 1
108+ if token .type == TokenType .PP_DEFINE :
109+ self ._parse_define ()
110+ return True
125111
126- # Append EOF token
127- result . append ( self ._tokens [ self . _pos ] )
128- self . _pos += 1
112+ if token . type == TokenType . PP_UNDEF :
113+ self ._parse_undef ( )
114+ return True
129115
130- if self ._conditional_stack :
131- raise self ._error ("unclosed conditional statement" , token = self ._conditional_stack [- 1 ][0 ])
116+ if token .type == TokenType .PP_INCLUDE :
117+ self ._parse_include ()
118+ return True
132119
133- return result
120+ return False
134121
135122 def _parse (self ) -> None :
136123 """Parse top-level definitions from the token stream."""
137124 while (token := self ._current ()).type != TokenType .EOF :
125+ if self ._handle_preprocessor ():
126+ continue
127+
138128 if token .type == TokenType .PP_FLAGS :
139129 self ._parse_config_flags ()
140130 elif token .type == TokenType .TYPEDEF :
@@ -158,6 +148,9 @@ def _parse(self) -> None:
158148 else :
159149 raise self ._error (f"unexpected token { token .value !r} " )
160150
151+ if self ._conditional_stack :
152+ raise self ._error ("unclosed conditional statement" , token = self ._conditional_stack [- 1 ][0 ])
153+
161154 # Preprocessor directives
162155
163156 def _parse_define (self ) -> None :
@@ -246,6 +239,34 @@ def _handle_conditional(self) -> None:
246239 raise self ._error ("#endif without matching #ifdef/#ifndef" , token = token )
247240 self ._conditional_stack .pop ()
248241
242+ # If we ended up in a false branch, skip ahead to the matching #else/#endif
243+ if self ._in_false_branch ():
244+ self ._skip_false_branch ()
245+
246+ def _skip_false_branch (self ) -> None :
247+ """Skip all tokens in a false conditional branch until the matching ``#else`` or ``#endif``."""
248+ depth = 0
249+ while self ._current ().type != TokenType .EOF :
250+ token_type = self ._current ().type
251+
252+ if token_type in (TokenType .PP_IFDEF , TokenType .PP_IFNDEF ):
253+ depth += 1
254+ self ._pos += 1
255+ # Skip the identifier argument
256+ if self ._current ().type != TokenType .EOF :
257+ self ._pos += 1
258+ elif token_type == TokenType .PP_ENDIF :
259+ if depth == 0 :
260+ return
261+ depth -= 1
262+ self ._pos += 1
263+ elif token_type == TokenType .PP_ELSE :
264+ if depth == 0 :
265+ return
266+ self ._pos += 1
267+ else :
268+ self ._pos += 1
269+
249270 # Type definitions
250271
251272 def _parse_typedef (self ) -> None :
@@ -347,6 +368,8 @@ def _parse_enum_or_flag(self) -> type[Enum | Flag]:
347368 values : dict [str , int ] = {}
348369
349370 while not self ._at (TokenType .RBRACE ):
371+ if self ._handle_preprocessor ():
372+ continue
350373 self ._assert_not_eof ()
351374
352375 member_name = self ._expect (TokenType .IDENTIFIER ).value
@@ -385,6 +408,8 @@ def _parse_field_list(self) -> list[Field]:
385408 fields : list [Field ] = []
386409
387410 while not self ._at (TokenType .RBRACE ):
411+ if self ._handle_preprocessor ():
412+ continue
388413 self ._assert_not_eof ()
389414
390415 fields .append (self ._parse_field ())
@@ -419,7 +444,7 @@ def _parse_field_name(self, base_type: type[BaseType]) -> tuple[type[BaseType],
419444 type_ = self .cs ._make_pointer (type_ )
420445
421446 # Field name
422- name = self ._expect (* _IDENTIFIER_TYPES ).value
447+ name = self ._expect (* IDENTIFIER_TYPES ).value
423448
424449 # Array dimensions
425450 type_ = self ._parse_array_dimensions (type_ )
0 commit comments