xref: /openbsd/gnu/usr.bin/gcc/gcc/f/where.c (revision c87b03e5)
1 /* where.c -- Implementation File (module.c template V1.0)
2    Copyright (C) 1995, 2002 Free Software Foundation, Inc.
3    Contributed by James Craig Burley.
4 
5 This file is part of GNU Fortran.
6 
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)
10 any later version.
11 
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.
16 
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
20 02111-1307, USA.
21 
22    Related Modules:
23 
24    Description:
25       Simple data abstraction for Fortran source lines (called card images).
26 
27    Modifications:
28 */
29 
30 /* Include files. */
31 
32 #include "proj.h"
33 #include "where.h"
34 #include "lex.h"
35 #include "malloc.h"
36 #include "ggc.h"
37 
38 /* Externals defined here. */
39 
40 struct _ffewhere_line_ ffewhere_unknown_line_
41 =
42 {NULL, NULL, 0, 0, 0, {0}};
43 
44 /* Simple definitions and enumerations. */
45 
46 
47 /* Internal typedefs. */
48 
49 typedef struct _ffewhere_ll_ *ffewhereLL_;
50 
51 /* Private include files. */
52 
53 
54 /* Internal structure definitions. */
55 
56 struct _ffewhere_ll_ GTY (())
57   {
58     ffewhereLL_ next;
59     ffewhereLL_ previous;
60     ffewhereFile wf;
61     ffewhereLineNumber line_no;	/* ffelex_line_number() at time of creation. */
62     ffewhereLineNumber offset;	/* User-desired offset (usually 1). */
63   };
64 
65 struct _ffewhere_root_ll_ GTY (())
66   {
67     ffewhereLL_ first;
68     ffewhereLL_ last;
69   };
70 
71 struct _ffewhere_root_line_
72   {
73     ffewhereLine first;
74     ffewhereLine last;
75     ffewhereLineNumber none;
76   };
77 
78 /* Static objects accessed by functions in this module. */
79 
80 static GTY (()) struct _ffewhere_root_ll_ *ffewhere_root_ll_;
81 static struct _ffewhere_root_line_ ffewhere_root_line_;
82 
83 /* Static functions (internal). */
84 
85 static ffewhereLL_ ffewhere_ll_lookup_ (ffewhereLineNumber ln);
86 
87 /* Internal macros. */
88 
89 
90 /* Look up line-to-line object from absolute line num.  */
91 
92 static ffewhereLL_
ffewhere_ll_lookup_(ffewhereLineNumber ln)93 ffewhere_ll_lookup_ (ffewhereLineNumber ln)
94 {
95   ffewhereLL_ ll;
96 
97   if (ln == 0)
98     return ffewhere_root_ll_->first;
99 
100   for (ll = ffewhere_root_ll_->last;
101        ll != (ffewhereLL_) &ffewhere_root_ll_->first;
102        ll = ll->previous)
103     {
104       if (ll->line_no <= ln)
105 	return ll;
106     }
107 
108   assert ("no line num" == NULL);
109   return NULL;
110 }
111 
112 /* Create file object.  */
113 
114 ffewhereFile
ffewhere_file_new(const char * name,size_t length)115 ffewhere_file_new (const char *name, size_t length)
116 {
117   ffewhereFile wf;
118   wf = ggc_alloc (offsetof (struct _ffewhere_file_, text) + length + 1);
119   wf->length = length;
120   memcpy (&wf->text[0], name, length);
121   wf->text[length] = '\0';
122 
123   return wf;
124 }
125 
126 /* Set file and first line number.
127 
128    Pass FALSE if no line number is specified.  */
129 
130 void
ffewhere_file_set(ffewhereFile wf,bool have_num,ffewhereLineNumber ln)131 ffewhere_file_set (ffewhereFile wf, bool have_num, ffewhereLineNumber ln)
132 {
133   ffewhereLL_ ll;
134   ll = ggc_alloc (sizeof (*ll));
135   ll->next = (ffewhereLL_) &ffewhere_root_ll_->first;
136   ll->previous = ffewhere_root_ll_->last;
137   ll->next->previous = ll;
138   ll->previous->next = ll;
139   if (wf == NULL)
140     {
141       if (ll->previous == ll->next)
142 	ll->wf = NULL;
143       else
144 	ll->wf = ll->previous->wf;
145     }
146   else
147     ll->wf = wf;
148   ll->line_no = ffelex_line_number ();
149   if (have_num)
150     ll->offset = ln;
151   else
152     {
153       if (ll->previous == ll->next)
154 	ll->offset = 1;
155       else
156 	ll->offset
157 	  = ll->line_no - ll->previous->line_no + ll->previous->offset;
158     }
159 }
160 
161 /* Do initializations.  */
162 
163 void
ffewhere_init_1()164 ffewhere_init_1 ()
165 {
166   ffewhere_root_line_.first = ffewhere_root_line_.last
167   = (ffewhereLine) &ffewhere_root_line_.first;
168   ffewhere_root_line_.none = 0;
169 
170   /* The sentinel is (must be) GGC-allocated.  It is accessed as a
171      struct _ffewhere_ll_/ffewhereLL_ though its type contains just the
172      first two fields (layout-wise).  */
173   ffewhere_root_ll_ = ggc_alloc_cleared (sizeof (struct _ffewhere_ll_));
174   ffewhere_root_ll_->first = ffewhere_root_ll_->last
175     = (ffewhereLL_) &ffewhere_root_ll_->first;
176 }
177 
178 /* Return the textual content of the line.  */
179 
180 char *
ffewhere_line_content(ffewhereLine wl)181 ffewhere_line_content (ffewhereLine wl)
182 {
183   assert (wl != NULL);
184   return wl->content;
185 }
186 
187 /* Look up file object from line object.  */
188 
189 ffewhereFile
ffewhere_line_file(ffewhereLine wl)190 ffewhere_line_file (ffewhereLine wl)
191 {
192   ffewhereLL_ ll;
193 
194   assert (wl != NULL);
195   ll = ffewhere_ll_lookup_ (wl->line_num);
196   return ll->wf;
197 }
198 
199 /* Lookup file object from line object, calc line#.  */
200 
201 ffewhereLineNumber
ffewhere_line_filelinenum(ffewhereLine wl)202 ffewhere_line_filelinenum (ffewhereLine wl)
203 {
204   ffewhereLL_ ll;
205 
206   assert (wl != NULL);
207   ll = ffewhere_ll_lookup_ (wl->line_num);
208   return wl->line_num + ll->offset - ll->line_no;
209 }
210 
211 /* Decrement use count for line, deallocate if no uses left.  */
212 
213 void
ffewhere_line_kill(ffewhereLine wl)214 ffewhere_line_kill (ffewhereLine wl)
215 {
216 #if 0
217   if (!ffewhere_line_is_unknown (wl))
218     fprintf (dmpout, "; ffewhere_line_kill %" ffewhereLineNumber_f "u, uses=%"
219 	     ffewhereUses_f_ "u\n",
220 	     wl->line_num, wl->uses);
221 #endif
222   assert (ffewhere_line_is_unknown (wl) || (wl->uses != 0));
223   if (!ffewhere_line_is_unknown (wl) && (--wl->uses == 0))
224     {
225       wl->previous->next = wl->next;
226       wl->next->previous = wl->previous;
227       malloc_kill_ks (ffe_pool_file (), wl,
228 		      offsetof (struct _ffewhere_line_, content)
229 		      + wl->length + 1);
230     }
231 }
232 
233 /* Make a new line or increment use count of existing one.
234 
235    Find out where line object is, if anywhere.	If in lexer, it might also
236    be at the end of the list of lines, else put it on the end of the list.
237    Then, if in the list of lines, increment the use count and return the
238    line object.	 Else, make an empty line object (no line) and return
239    that.  */
240 
241 ffewhereLine
ffewhere_line_new(ffewhereLineNumber ln)242 ffewhere_line_new (ffewhereLineNumber ln)
243 {
244   ffewhereLine wl = ffewhere_root_line_.last;
245 
246   /* If this is the lexer's current line, see if it is already at the end of
247      the list, and if not, make it and return it. */
248 
249   if (((ln == 0)		/* Presumably asking for EOF pointer. */
250        || (wl->line_num != ln))
251       && (ffelex_line_number () == ln))
252     {
253 #if 0
254       fprintf (dmpout,
255 	       "; ffewhere_line_new %" ffewhereLineNumber_f "u, lexer\n",
256 	       ln);
257 #endif
258       wl = malloc_new_ks (ffe_pool_file (), "FFEWHERE line",
259 			  offsetof (struct _ffewhere_line_, content)
260 			  + (size_t) ffelex_line_length () + 1);
261       wl->next = (ffewhereLine) &ffewhere_root_line_;
262       wl->previous = ffewhere_root_line_.last;
263       wl->previous->next = wl;
264       wl->next->previous = wl;
265       wl->line_num = ln;
266       wl->uses = 1;
267       wl->length = ffelex_line_length ();
268       strcpy (wl->content, ffelex_line ());
269       return wl;
270     }
271 
272   /* See if line is on list already. */
273 
274   while (wl->line_num > ln)
275     wl = wl->previous;
276 
277   /* If line is there, increment its use count and return. */
278 
279   if (wl->line_num == ln)
280     {
281 #if 0
282       fprintf (dmpout, "; ffewhere_line_new %" ffewhereLineNumber_f "u, uses=%"
283 	       ffewhereUses_f_ "u\n", ln,
284 	       wl->uses);
285 #endif
286       wl->uses++;
287       return wl;
288     }
289 
290   /* Else, make a new one with a blank line (since we've obviously lost it,
291      which should never happen) and return it. */
292 
293   fprintf (stderr,
294 	   "(Cannot resurrect line %lu for error reporting purposes.)\n",
295 	   ln);
296 
297   wl = malloc_new_ks (ffe_pool_file (), "FFEWHERE line",
298 		      offsetof (struct _ffewhere_line_, content)
299 		      + 1);
300   wl->next = (ffewhereLine) &ffewhere_root_line_;
301   wl->previous = ffewhere_root_line_.last;
302   wl->previous->next = wl;
303   wl->next->previous = wl;
304   wl->line_num = ln;
305   wl->uses = 1;
306   wl->length = 0;
307   *(wl->content) = '\0';
308   return wl;
309 }
310 
311 /* Increment use count of line, as in a copy.  */
312 
313 ffewhereLine
ffewhere_line_use(ffewhereLine wl)314 ffewhere_line_use (ffewhereLine wl)
315 {
316 #if 0
317   fprintf (dmpout, "; ffewhere_line_use %" ffewhereLineNumber_f "u, uses=%" ffewhereUses_f_
318 	   "u\n", wl->line_num, wl->uses);
319 #endif
320   assert (ffewhere_line_is_unknown (wl) || (wl->uses != 0));
321   if (!ffewhere_line_is_unknown (wl))
322     ++wl->uses;
323   return wl;
324 }
325 
326 /* Set an ffewhere object based on a track index.
327 
328    Determines the absolute line and column number of a character at a given
329    index into an ffewhereTrack array.  wr* is the reference position, wt is
330    the tracking information, and i is the index desired.  wo* is set to wr*
331    plus the continual offsets described by wt[0...i-1], or unknown if any of
332    the continual offsets are not known.	 */
333 
334 void
ffewhere_set_from_track(ffewhereLine * wol,ffewhereColumn * woc,ffewhereLine wrl,ffewhereColumn wrc,ffewhereTrack wt,ffewhereIndex i)335 ffewhere_set_from_track (ffewhereLine *wol, ffewhereColumn *woc,
336 			 ffewhereLine wrl, ffewhereColumn wrc,
337 			 ffewhereTrack wt, ffewhereIndex i)
338 {
339   ffewhereLineNumber ln;
340   ffewhereColumnNumber cn;
341   ffewhereIndex j;
342   ffewhereIndex k;
343 
344   if ((i == 0) || (i >= FFEWHERE_indexMAX))
345     {
346       *wol = ffewhere_line_use (wrl);
347       *woc = ffewhere_column_use (wrc);
348     }
349   else
350     {
351       ln = ffewhere_line_number (wrl);
352       cn = ffewhere_column_number (wrc);
353       for (j = 0, k = 0; j < i; ++j, k += 2)
354 	{
355 	  if ((wt[k] == FFEWHERE_indexUNKNOWN)
356 	      || (wt[k + 1] == FFEWHERE_indexUNKNOWN))
357 	    {
358 	      *wol = ffewhere_line_unknown ();
359 	      *woc = ffewhere_column_unknown ();
360 	      return;
361 	    }
362 	  if (wt[k] == 0)
363 	    cn += wt[k + 1] + 1;
364 	  else
365 	    {
366 	      ln += wt[k];
367 	      cn = wt[k + 1] + 1;
368 	    }
369 	}
370       if (ln == ffewhere_line_number (wrl))
371 	{			/* Already have the line object, just use it
372 				   directly. */
373 	  *wol = ffewhere_line_use (wrl);
374 	}
375       else			/* Must search for the line object. */
376 	*wol = ffewhere_line_new (ln);
377       *woc = ffewhere_column_new (cn);
378     }
379 }
380 
381 /* Build next tracking index.
382 
383    Set wt[i-1] continual offset so that it offsets from w* to (ln,cn).	Update
384    w* to contain (ln,cn).  DO NOT call this routine if i >= FFEWHERE_indexMAX
385    or i == 0.  */
386 
387 void
ffewhere_track(ffewhereLine * wl,ffewhereColumn * wc,ffewhereTrack wt,ffewhereIndex i,ffewhereLineNumber ln,ffewhereColumnNumber cn)388 ffewhere_track (ffewhereLine *wl, ffewhereColumn *wc, ffewhereTrack wt,
389 		ffewhereIndex i, ffewhereLineNumber ln,
390 		ffewhereColumnNumber cn)
391 {
392   unsigned int lo;
393   unsigned int co;
394 
395   if ((ffewhere_line_is_unknown (*wl))
396       || (ffewhere_column_is_unknown (*wc))
397       || ((lo = ln - ffewhere_line_number (*wl)) >= FFEWHERE_indexUNKNOWN))
398     {
399       wt[i * 2 - 2] = wt[i * 2 - 1] = FFEWHERE_indexUNKNOWN;
400       ffewhere_line_kill (*wl);
401       ffewhere_column_kill (*wc);
402       *wl = FFEWHERE_lineUNKNOWN;
403       *wc = FFEWHERE_columnUNKNOWN;
404     }
405   else if (lo == 0)
406     {
407       wt[i * 2 - 2] = 0;
408       if ((co = cn - ffewhere_column_number (*wc)) > FFEWHERE_indexUNKNOWN)
409 	{
410 	  wt[i * 2 - 1] = FFEWHERE_indexUNKNOWN;
411 	  ffewhere_line_kill (*wl);
412 	  ffewhere_column_kill (*wc);
413 	  *wl = FFEWHERE_lineUNKNOWN;
414 	  *wc = FFEWHERE_columnUNKNOWN;
415 	}
416       else
417 	{
418 	  wt[i * 2 - 1] = co - 1;
419 	  ffewhere_column_kill (*wc);
420 	  *wc = ffewhere_column_use (ffewhere_column_new (cn));
421 	}
422     }
423   else
424     {
425       wt[i * 2 - 2] = lo;
426       wt[i * 2 - 1] = cn - 1;
427       ffewhere_line_kill (*wl);
428       ffewhere_column_kill (*wc);
429       *wl = ffewhere_line_use (ffewhere_line_new (ln));
430       *wc = ffewhere_column_use (ffewhere_column_new (cn));
431     }
432 }
433 
434 /* Clear tracking index for internally created track.
435 
436    Set the tracking information to indicate that the tracking is at its
437    simplest (no spaces or newlines within the tracking).  This means set
438    everything to zero in the current implementation.  Length is the total
439    length of the token; length must be 2 or greater, since length-1 tracking
440    characters are set.	*/
441 
442 void
ffewhere_track_clear(ffewhereTrack wt,ffewhereIndex length)443 ffewhere_track_clear (ffewhereTrack wt, ffewhereIndex length)
444 {
445   ffewhereIndex i;
446 
447   if (length > FFEWHERE_indexMAX)
448     length = FFEWHERE_indexMAX;
449 
450   for (i = 1; i < length; ++i)
451     wt[i * 2 - 2] = wt[i * 2 - 1] = 0;
452 }
453 
454 /* Copy tracking index from one place to another.
455 
456    Copy tracking information from swt[start] to dwt[0] and so on, presumably
457    after an ffewhere_set_from_track call.  Length is the total
458    length of the token; length must be 2 or greater, since length-1 tracking
459    characters are set.	*/
460 
461 void
ffewhere_track_copy(ffewhereTrack dwt,ffewhereTrack swt,ffewhereIndex start,ffewhereIndex length)462 ffewhere_track_copy (ffewhereTrack dwt, ffewhereTrack swt, ffewhereIndex start,
463 		     ffewhereIndex length)
464 {
465   ffewhereIndex i;
466   ffewhereIndex copy;
467 
468   if (length > FFEWHERE_indexMAX)
469     length = FFEWHERE_indexMAX;
470 
471   if (length + start > FFEWHERE_indexMAX)
472     copy = FFEWHERE_indexMAX - start;
473   else
474     copy = length;
475 
476   for (i = 1; i < copy; ++i)
477     {
478       dwt[i * 2 - 2] = swt[(i + start) * 2 - 2];
479       dwt[i * 2 - 1] = swt[(i + start) * 2 - 1];
480     }
481 
482   for (; i < length; ++i)
483     {
484       dwt[i * 2 - 2] = 0;
485       dwt[i * 2 - 1] = 0;
486     }
487 }
488 
489 /* Kill tracking data.
490 
491    Kill all the tracking information by killing incremented lines from the
492    first line number.  */
493 
494 void
ffewhere_track_kill(ffewhereLine wrl,ffewhereColumn wrc UNUSED,ffewhereTrack wt,ffewhereIndex length)495 ffewhere_track_kill (ffewhereLine wrl, ffewhereColumn wrc UNUSED,
496 		     ffewhereTrack wt, ffewhereIndex length)
497 {
498   ffewhereLineNumber ln;
499   unsigned int lo;
500   ffewhereIndex i;
501 
502   ln = ffewhere_line_number (wrl);
503 
504   if (length > FFEWHERE_indexMAX)
505     length = FFEWHERE_indexMAX;
506 
507   for (i = 0; i < length - 1; ++i)
508     {
509       if ((lo = wt[i * 2]) == FFEWHERE_indexUNKNOWN)
510 	break;
511       else if (lo != 0)
512 	{
513 	  ln += lo;
514 	  wrl = ffewhere_line_new (ln);
515 	  ffewhere_line_kill (wrl);
516 	}
517     }
518 }
519 
520 #include "gt-f-where.h"
521