0
# Advanced Parser Configuration
1
2
Configurable parsing engine for handling Fortran syntax variations, custom comment tokens, and complex array indexing. The Parser class provides fine-grained control over how namelist files are interpreted and processed.
3
4
## Capabilities
5
6
### Parser Class
7
8
Advanced parser with configurable options for handling diverse Fortran namelist dialects and edge cases.
9
10
```python { .api }
11
class Parser:
12
"""
13
Fortran namelist parser with extensive configuration options.
14
15
Provides control over parsing behavior, indexing conventions,
16
comment handling, and data structure organization.
17
"""
18
19
def __init__(self):
20
"""Create parser object with default configuration."""
21
```
22
23
**Usage Examples:**
24
25
```python
26
# Create parser with custom configuration
27
parser = f90nml.Parser()
28
29
# Configure parser options
30
parser.comment_tokens = '!#' # Support both ! and # comments
31
parser.default_start_index = 0 # Use 0-based indexing
32
parser.strict_logical = False # Relaxed logical parsing
33
34
# Use parser
35
nml = parser.read('config.nml')
36
```
37
38
### Parsing Methods
39
40
Core methods for processing namelist data from files and strings.
41
42
```python { .api }
43
def read(self, nml_fname, nml_patch_in=None, patch_fname=None):
44
"""
45
Parse a Fortran namelist file and store the contents.
46
47
Args:
48
nml_fname: str or file-like object - Input file path or file object
49
nml_patch_in: dict, optional - Patch data to apply during parsing
50
patch_fname: str, optional - Output file for patch results
51
52
Returns:
53
Namelist: Parsed namelist data
54
55
Raises:
56
ValueError: If namelist syntax is invalid
57
IOError: If file cannot be read
58
"""
59
60
def reads(self, nml_string):
61
"""
62
Parse a namelist string and return equivalent Namelist object.
63
64
Args:
65
nml_string: str - String containing Fortran namelist data
66
67
Returns:
68
Namelist: Parsed namelist data
69
70
Raises:
71
ValueError: If namelist syntax is invalid
72
"""
73
```
74
75
**Usage Examples:**
76
77
```python
78
parser = f90nml.Parser()
79
80
# Basic parsing
81
nml = parser.read('input.nml')
82
83
# Parse with simultaneous patching
84
patch_data = {'config': {'modified_param': 100}}
85
nml = parser.read('input.nml', patch_data, 'patched_output.nml')
86
87
# Parse string
88
nml_str = '&data x=1, y=2 /'
89
nml = parser.reads(nml_str)
90
```
91
92
### Comment Token Configuration
93
94
Customize which characters are treated as comment delimiters.
95
96
```python { .api }
97
comment_tokens: str
98
"""
99
String of single-character comment tokens (default: '!').
100
101
Fortran standard uses '!' but some programs support additional
102
tokens like '#' for preprocessing compatibility.
103
"""
104
```
105
106
**Usage Examples:**
107
108
```python
109
parser = f90nml.Parser()
110
111
# Support multiple comment types
112
parser.comment_tokens = '!#'
113
114
# Parse file with mixed comments
115
nml_content = '''
116
&config
117
! Standard Fortran comment
118
param1 = 10
119
# Preprocessor-style comment
120
param2 = 20
121
/
122
'''
123
nml = parser.reads(nml_content)
124
125
# Add custom comment token
126
parser.comment_tokens += '%' # Now supports !, #, and %
127
```
128
129
### Array Indexing Configuration
130
131
Control how array indices are interpreted and handled.
132
133
```python { .api }
134
default_start_index: int
135
"""
136
Assumed starting index for vectors without explicit indexing (default: 1).
137
138
Fortran allows arbitrary start indices. When not specified,
139
this value determines the assumed starting position.
140
"""
141
142
global_start_index: int
143
"""
144
Explicit start index for all vectors (default: None).
145
146
When set, forces all arrays to use this starting index,
147
overriding any explicit indices in the namelist.
148
"""
149
```
150
151
**Usage Examples:**
152
153
```python
154
parser = f90nml.Parser()
155
156
# Use 0-based indexing (Python-style)
157
parser.default_start_index = 0
158
159
# Parse namelist with ambiguous indexing
160
nml_content = '''
161
&data
162
array1(3:5) = 10, 20, 30 ! Explicit indices
163
array2 = 1, 2, 3 ! Uses default_start_index
164
/
165
'''
166
nml = parser.reads(nml_content)
167
print(nml['data']['array2']) # [1, 2, 3] starting at index 0
168
169
# Force global indexing
170
parser.global_start_index = 1
171
nml = parser.reads(nml_content)
172
# Now array2 will be treated as starting at index 1
173
```
174
175
### Data Structure Configuration
176
177
Control how multidimensional arrays and sparse data are organized.
178
179
```python { .api }
180
row_major: bool
181
"""
182
Read multidimensional arrays in row-major format (default: False).
183
184
By default, preserves Fortran column-major ordering.
185
When True, converts to row-major (C-style) ordering.
186
"""
187
188
sparse_arrays: bool
189
"""
190
Store unset rows of multidimensional arrays as empty lists (default: False).
191
192
Provides more compact representation for sparse data structures.
193
"""
194
```
195
196
**Usage Examples:**
197
198
```python
199
parser = f90nml.Parser()
200
201
# Configure for row-major arrays
202
parser.row_major = True
203
204
# Parse multidimensional data
205
nml_content = '''
206
&matrix
207
data(1:2, 1:3) = 1, 2, 3, 4, 5, 6
208
/
209
'''
210
nml = parser.reads(nml_content)
211
# Array will be organized in row-major order
212
213
# Enable sparse array handling
214
parser.sparse_arrays = True
215
sparse_content = '''
216
&sparse
217
matrix(1, 1) = 10
218
matrix(5, 5) = 20
219
/
220
'''
221
nml = parser.reads(sparse_content)
222
# Unset rows will be empty lists instead of None-filled
223
```
224
225
### Logical Value Parsing
226
227
Control how logical (boolean) values are interpreted.
228
229
```python { .api }
230
strict_logical: bool
231
"""
232
Use strict rules for logical value parsing (default: True).
233
234
When True: Only standard forms (.true., .t., true, t, .false., .f., false, f)
235
When False: Any string starting with 't' or 'f' is interpreted as boolean
236
"""
237
```
238
239
**Usage Examples:**
240
241
```python
242
parser = f90nml.Parser()
243
244
# Strict logical parsing (default)
245
parser.strict_logical = True
246
try:
247
nml = parser.reads('&data flag = totally_true /')
248
except ValueError:
249
print("Invalid logical value in strict mode")
250
251
# Relaxed logical parsing
252
parser.strict_logical = False
253
nml = parser.reads('&data flag = totally_true /') # Interprets as True
254
print(nml['data']['flag']) # True
255
256
# Standard logical values work in both modes
257
standard_content = '''
258
&flags
259
flag1 = .true.
260
flag2 = .false.
261
flag3 = T
262
flag4 = F
263
/
264
'''
265
nml = parser.reads(standard_content)
266
```
267
268
### Advanced Parsing Features
269
270
Handle complex Fortran namelist features and edge cases.
271
272
**Derived Types:**
273
```python
274
# Parse Fortran derived types
275
derived_content = '''
276
&particles
277
particle(1)%x = 1.0
278
particle(1)%y = 2.0
279
particle(2)%x = 3.0
280
particle(2)%y = 4.0
281
/
282
'''
283
parser = f90nml.Parser()
284
nml = parser.reads(derived_content)
285
print(nml['particles']['particle'][0]['x']) # 1.0
286
```
287
288
**Complex Numbers:**
289
```python
290
# Parse complex number literals
291
complex_content = '''
292
&physics
293
impedance = (1.0, 2.0)
294
frequency_response = (3.14, -1.57), (2.71, 0.0)
295
/
296
'''
297
nml = parser.reads(complex_content)
298
print(nml['physics']['impedance']) # (1.0+2.0j)
299
```
300
301
**Vector Indexing:**
302
```python
303
# Handle explicit vector indices
304
indexed_content = '''
305
&arrays
306
pressure(0:2) = 1013.25, 850.0, 700.0
307
temperature(5:7) = 273.15, 283.15, 293.15
308
/
309
'''
310
parser = f90nml.Parser()
311
parser.default_start_index = 0
312
nml = parser.reads(indexed_content)
313
314
# Access start index information
315
print(nml['arrays'].start_index) # {'pressure': [0], 'temperature': [5]}
316
```
317
318
## Error Handling and Diagnostics
319
320
```python
321
parser = f90nml.Parser()
322
323
# Handle invalid syntax
324
try:
325
nml = parser.reads('&invalid syntax without end')
326
except ValueError as e:
327
print(f"Parse error: {e}")
328
329
# Handle file access errors
330
try:
331
nml = parser.read('/nonexistent/file.nml')
332
except IOError as e:
333
print(f"File error: {e}")
334
335
# Validate configuration
336
try:
337
parser.default_start_index = "invalid"
338
except TypeError as e:
339
print(f"Configuration error: {e}")
340
```
341
342
## Integration with Core Functions
343
344
Parser objects can be used instead of the module-level functions for full control:
345
346
```python
347
# Module-level functions (use default parser)
348
nml = f90nml.read('input.nml')
349
350
# Equivalent using custom parser
351
parser = f90nml.Parser()
352
parser.comment_tokens = '!#'
353
parser.default_start_index = 0
354
nml = parser.read('input.nml')
355
356
# Parser configuration persists across multiple files
357
nml1 = parser.read('file1.nml')
358
nml2 = parser.read('file2.nml') # Uses same configuration
359
```