1 /* where.c -- Implementation File (module.c template V1.0)
2 Copyright (C) 1995 Free Software Foundation, Inc.
3 Contributed by James Craig Burley.
5 This file is part of GNU Fortran.
7 GNU Fortran is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Fortran is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Fortran; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 Simple data abstraction for Fortran source lines (called card images).
38 /* Externals defined here. */
40 struct _ffewhere_line_ ffewhere_unknown_line_
42 {NULL
, NULL
, 0, 0, 0, {0}};
44 /* Simple definitions and enumerations. */
47 /* Internal typedefs. */
49 typedef struct _ffewhere_ll_
*ffewhereLL_
;
51 /* Private include files. */
54 /* Internal structure definitions. */
61 ffewhereLineNumber line_no
; /* ffelex_line_number() at time of creation. */
62 ffewhereLineNumber offset
; /* User-desired offset (usually 1). */
65 struct _ffewhere_root_ll_
71 struct _ffewhere_root_line_
75 ffewhereLineNumber none
;
78 /* Static objects accessed by functions in this module. */
80 static struct _ffewhere_root_ll_ ffewhere_root_ll_
;
81 static struct _ffewhere_root_line_ ffewhere_root_line_
;
83 /* Static functions (internal). */
85 static ffewhereLL_
ffewhere_ll_lookup_ (ffewhereLineNumber ln
);
87 /* Internal macros. */
90 /* Look up line-to-line object from absolute line num. */
93 ffewhere_ll_lookup_ (ffewhereLineNumber ln
)
98 return ffewhere_root_ll_
.first
;
100 for (ll
= ffewhere_root_ll_
.last
;
101 ll
!= (ffewhereLL_
) &ffewhere_root_ll_
.first
;
104 if (ll
->line_no
<= ln
)
108 assert ("no line num" == NULL
);
112 /* A somewhat evil way to prevent the garbage collector
113 from collecting 'file' structures. */
114 #define NUM_FFEWHERE_HEAD_FILES 31
115 static struct ffewhere_ggc_tracker
117 struct ffewhere_ggc_tracker
*next
;
118 ffewhereFile files
[NUM_FFEWHERE_HEAD_FILES
];
119 } *ffewhere_head
= NULL
;
122 mark_ffewhere_head (void *arg
)
124 struct ffewhere_ggc_tracker
*head
;
127 for (head
= * (struct ffewhere_ggc_tracker
**) arg
;
132 for (i
= 0; i
< NUM_FFEWHERE_HEAD_FILES
; i
++)
133 ggc_mark (head
->files
[i
]);
140 Note that this object must not have been passed in a call
141 to any other ffewhere function except ffewhere_file_name and
142 ffewhere_file_namelen. */
145 ffewhere_file_kill (ffewhereFile wf
)
147 struct ffewhere_ggc_tracker
*head
;
150 for (head
= ffewhere_head
; head
!= NULL
; head
= head
->next
)
151 for (i
= 0; i
< NUM_FFEWHERE_HEAD_FILES
; i
++)
152 if (head
->files
[i
] == wf
)
154 head
->files
[i
] = NULL
;
157 /* Called on a file that has already been deallocated... */
161 /* Create file object. */
164 ffewhere_file_new (const char *name
, size_t length
)
169 wf
= ggc_alloc (offsetof (struct _ffewhere_file_
, text
)
172 memcpy (&wf
->text
[0], name
, length
);
173 wf
->text
[length
] = '\0';
175 if (ffewhere_head
== NULL
)
177 ggc_add_root (&ffewhere_head
, 1, sizeof ffewhere_head
,
179 filepos
= NUM_FFEWHERE_HEAD_FILES
;
183 for (filepos
= 0; filepos
< NUM_FFEWHERE_HEAD_FILES
; filepos
++)
184 if (ffewhere_head
->files
[filepos
] == NULL
)
186 ffewhere_head
->files
[filepos
] = wf
;
190 if (filepos
== NUM_FFEWHERE_HEAD_FILES
)
192 /* Need to allocate a new block. */
193 struct ffewhere_ggc_tracker
*old_head
= ffewhere_head
;
196 ffewhere_head
= ggc_alloc (sizeof (*ffewhere_head
));
197 ffewhere_head
->next
= old_head
;
198 ffewhere_head
->files
[0] = wf
;
199 for (i
= 1; i
< NUM_FFEWHERE_HEAD_FILES
; i
++)
200 ffewhere_head
->files
[i
] = NULL
;
206 /* Set file and first line number.
208 Pass FALSE if no line number is specified. */
211 ffewhere_file_set (ffewhereFile wf
, bool have_num
, ffewhereLineNumber ln
)
215 ll
= malloc_new_kp (ffe_pool_file (), "ffewhereLL_", sizeof (*ll
));
216 ll
->next
= (ffewhereLL_
) &ffewhere_root_ll_
.first
;
217 ll
->previous
= ffewhere_root_ll_
.last
;
218 ll
->next
->previous
= ll
;
219 ll
->previous
->next
= ll
;
222 if (ll
->previous
== ll
->next
)
225 ll
->wf
= ll
->previous
->wf
;
229 ll
->line_no
= ffelex_line_number ();
234 if (ll
->previous
== ll
->next
)
238 = ll
->line_no
- ll
->previous
->line_no
+ ll
->previous
->offset
;
242 /* Do initializations. */
247 ffewhere_root_line_
.first
= ffewhere_root_line_
.last
248 = (ffewhereLine
) &ffewhere_root_line_
.first
;
249 ffewhere_root_line_
.none
= 0;
251 ffewhere_root_ll_
.first
= ffewhere_root_ll_
.last
252 = (ffewhereLL_
) &ffewhere_root_ll_
.first
;
255 /* Return the textual content of the line. */
258 ffewhere_line_content (ffewhereLine wl
)
264 /* Look up file object from line object. */
267 ffewhere_line_file (ffewhereLine wl
)
272 ll
= ffewhere_ll_lookup_ (wl
->line_num
);
276 /* Lookup file object from line object, calc line#. */
279 ffewhere_line_filelinenum (ffewhereLine wl
)
284 ll
= ffewhere_ll_lookup_ (wl
->line_num
);
285 return wl
->line_num
+ ll
->offset
- ll
->line_no
;
288 /* Decrement use count for line, deallocate if no uses left. */
291 ffewhere_line_kill (ffewhereLine wl
)
294 if (!ffewhere_line_is_unknown (wl
))
295 fprintf (dmpout
, "; ffewhere_line_kill %" ffewhereLineNumber_f
"u, uses=%"
296 ffewhereUses_f_
"u\n",
297 wl
->line_num
, wl
->uses
);
299 assert (ffewhere_line_is_unknown (wl
) || (wl
->uses
!= 0));
300 if (!ffewhere_line_is_unknown (wl
) && (--wl
->uses
== 0))
302 wl
->previous
->next
= wl
->next
;
303 wl
->next
->previous
= wl
->previous
;
304 malloc_kill_ks (ffe_pool_file (), wl
,
305 offsetof (struct _ffewhere_line_
, content
)
310 /* Make a new line or increment use count of existing one.
312 Find out where line object is, if anywhere. If in lexer, it might also
313 be at the end of the list of lines, else put it on the end of the list.
314 Then, if in the list of lines, increment the use count and return the
315 line object. Else, make an empty line object (no line) and return
319 ffewhere_line_new (ffewhereLineNumber ln
)
321 ffewhereLine wl
= ffewhere_root_line_
.last
;
323 /* If this is the lexer's current line, see if it is already at the end of
324 the list, and if not, make it and return it. */
326 if (((ln
== 0) /* Presumably asking for EOF pointer. */
327 || (wl
->line_num
!= ln
))
328 && (ffelex_line_number () == ln
))
332 "; ffewhere_line_new %" ffewhereLineNumber_f
"u, lexer\n",
335 wl
= malloc_new_ks (ffe_pool_file (), "FFEWHERE line",
336 offsetof (struct _ffewhere_line_
, content
)
337 + (size_t) ffelex_line_length () + 1);
338 wl
->next
= (ffewhereLine
) &ffewhere_root_line_
;
339 wl
->previous
= ffewhere_root_line_
.last
;
340 wl
->previous
->next
= wl
;
341 wl
->next
->previous
= wl
;
344 wl
->length
= ffelex_line_length ();
345 strcpy (wl
->content
, ffelex_line ());
349 /* See if line is on list already. */
351 while (wl
->line_num
> ln
)
354 /* If line is there, increment its use count and return. */
356 if (wl
->line_num
== ln
)
359 fprintf (dmpout
, "; ffewhere_line_new %" ffewhereLineNumber_f
"u, uses=%"
360 ffewhereUses_f_
"u\n", ln
,
367 /* Else, make a new one with a blank line (since we've obviously lost it,
368 which should never happen) and return it. */
371 "(Cannot resurrect line %lu for error reporting purposes.)\n",
374 wl
= malloc_new_ks (ffe_pool_file (), "FFEWHERE line",
375 offsetof (struct _ffewhere_line_
, content
)
377 wl
->next
= (ffewhereLine
) &ffewhere_root_line_
;
378 wl
->previous
= ffewhere_root_line_
.last
;
379 wl
->previous
->next
= wl
;
380 wl
->next
->previous
= wl
;
384 *(wl
->content
) = '\0';
388 /* Increment use count of line, as in a copy. */
391 ffewhere_line_use (ffewhereLine wl
)
394 fprintf (dmpout
, "; ffewhere_line_use %" ffewhereLineNumber_f
"u, uses=%" ffewhereUses_f_
395 "u\n", wl
->line_num
, wl
->uses
);
397 assert (ffewhere_line_is_unknown (wl
) || (wl
->uses
!= 0));
398 if (!ffewhere_line_is_unknown (wl
))
403 /* Set an ffewhere object based on a track index.
405 Determines the absolute line and column number of a character at a given
406 index into an ffewhereTrack array. wr* is the reference position, wt is
407 the tracking information, and i is the index desired. wo* is set to wr*
408 plus the continual offsets described by wt[0...i-1], or unknown if any of
409 the continual offsets are not known. */
412 ffewhere_set_from_track (ffewhereLine
*wol
, ffewhereColumn
*woc
,
413 ffewhereLine wrl
, ffewhereColumn wrc
,
414 ffewhereTrack wt
, ffewhereIndex i
)
416 ffewhereLineNumber ln
;
417 ffewhereColumnNumber cn
;
421 if ((i
== 0) || (i
>= FFEWHERE_indexMAX
))
423 *wol
= ffewhere_line_use (wrl
);
424 *woc
= ffewhere_column_use (wrc
);
428 ln
= ffewhere_line_number (wrl
);
429 cn
= ffewhere_column_number (wrc
);
430 for (j
= 0, k
= 0; j
< i
; ++j
, k
+= 2)
432 if ((wt
[k
] == FFEWHERE_indexUNKNOWN
)
433 || (wt
[k
+ 1] == FFEWHERE_indexUNKNOWN
))
435 *wol
= ffewhere_line_unknown ();
436 *woc
= ffewhere_column_unknown ();
447 if (ln
== ffewhere_line_number (wrl
))
448 { /* Already have the line object, just use it
450 *wol
= ffewhere_line_use (wrl
);
452 else /* Must search for the line object. */
453 *wol
= ffewhere_line_new (ln
);
454 *woc
= ffewhere_column_new (cn
);
458 /* Build next tracking index.
460 Set wt[i-1] continual offset so that it offsets from w* to (ln,cn). Update
461 w* to contain (ln,cn). DO NOT call this routine if i >= FFEWHERE_indexMAX
465 ffewhere_track (ffewhereLine
*wl
, ffewhereColumn
*wc
, ffewhereTrack wt
,
466 ffewhereIndex i
, ffewhereLineNumber ln
,
467 ffewhereColumnNumber cn
)
472 if ((ffewhere_line_is_unknown (*wl
))
473 || (ffewhere_column_is_unknown (*wc
))
474 || ((lo
= ln
- ffewhere_line_number (*wl
)) >= FFEWHERE_indexUNKNOWN
))
476 wt
[i
* 2 - 2] = wt
[i
* 2 - 1] = FFEWHERE_indexUNKNOWN
;
477 ffewhere_line_kill (*wl
);
478 ffewhere_column_kill (*wc
);
479 *wl
= FFEWHERE_lineUNKNOWN
;
480 *wc
= FFEWHERE_columnUNKNOWN
;
485 if ((co
= cn
- ffewhere_column_number (*wc
)) > FFEWHERE_indexUNKNOWN
)
487 wt
[i
* 2 - 1] = FFEWHERE_indexUNKNOWN
;
488 ffewhere_line_kill (*wl
);
489 ffewhere_column_kill (*wc
);
490 *wl
= FFEWHERE_lineUNKNOWN
;
491 *wc
= FFEWHERE_columnUNKNOWN
;
495 wt
[i
* 2 - 1] = co
- 1;
496 ffewhere_column_kill (*wc
);
497 *wc
= ffewhere_column_use (ffewhere_column_new (cn
));
503 if (cn
> FFEWHERE_indexUNKNOWN
)
505 wt
[i
* 2 - 1] = FFEWHERE_indexUNKNOWN
;
506 ffewhere_line_kill (*wl
);
507 ffewhere_column_kill (*wc
);
508 *wl
= ffewhere_line_unknown ();
509 *wc
= ffewhere_column_unknown ();
513 wt
[i
* 2 - 1] = cn
- 1;
514 ffewhere_line_kill (*wl
);
515 ffewhere_column_kill (*wc
);
516 *wl
= ffewhere_line_use (ffewhere_line_new (ln
));
517 *wc
= ffewhere_column_use (ffewhere_column_new (cn
));
522 /* Clear tracking index for internally created track.
524 Set the tracking information to indicate that the tracking is at its
525 simplest (no spaces or newlines within the tracking). This means set
526 everything to zero in the current implementation. Length is the total
527 length of the token; length must be 2 or greater, since length-1 tracking
528 characters are set. */
531 ffewhere_track_clear (ffewhereTrack wt
, ffewhereIndex length
)
535 if (length
> FFEWHERE_indexMAX
)
536 length
= FFEWHERE_indexMAX
;
538 for (i
= 1; i
< length
; ++i
)
539 wt
[i
* 2 - 2] = wt
[i
* 2 - 1] = 0;
542 /* Copy tracking index from one place to another.
544 Copy tracking information from swt[start] to dwt[0] and so on, presumably
545 after an ffewhere_set_from_track call. Length is the total
546 length of the token; length must be 2 or greater, since length-1 tracking
547 characters are set. */
550 ffewhere_track_copy (ffewhereTrack dwt
, ffewhereTrack swt
, ffewhereIndex start
,
551 ffewhereIndex length
)
556 if (length
> FFEWHERE_indexMAX
)
557 length
= FFEWHERE_indexMAX
;
559 if (length
+ start
> FFEWHERE_indexMAX
)
560 copy
= FFEWHERE_indexMAX
- start
;
564 for (i
= 1; i
< copy
; ++i
)
566 dwt
[i
* 2 - 2] = swt
[(i
+ start
) * 2 - 2];
567 dwt
[i
* 2 - 1] = swt
[(i
+ start
) * 2 - 1];
570 for (; i
< length
; ++i
)
577 /* Kill tracking data.
579 Kill all the tracking information by killing incremented lines from the
580 first line number. */
583 ffewhere_track_kill (ffewhereLine wrl
, ffewhereColumn wrc UNUSED
,
584 ffewhereTrack wt
, ffewhereIndex length
)
586 ffewhereLineNumber ln
;
590 ln
= ffewhere_line_number (wrl
);
592 if (length
> FFEWHERE_indexMAX
)
593 length
= FFEWHERE_indexMAX
;
595 for (i
= 0; i
< length
- 1; ++i
)
597 if ((lo
= wt
[i
* 2]) == FFEWHERE_indexUNKNOWN
)
602 wrl
= ffewhere_line_new (ln
);
603 ffewhere_line_kill (wrl
);