1 /*
2 ** Splint - annotation-assisted static program checker
3 ** Copyright (C) 1994-2003 University of Virginia,
4 **         Massachusetts Institute of Technology
5 **
6 ** This program is free software; you can redistribute it and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation; either version 2 of the License, or (at your
9 ** option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 ** General Public License for more details.
15 **
16 ** The GNU General Public License is available from http://www.gnu.org/ or
17 ** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18 ** MA 02111-1307, USA.
19 **
20 ** For information on splint: info@splint.org
21 ** To report a bug: splint-bug@splint.org
22 ** For more information: http://www.splint.org
23 */
24 /*
25 ** cscannerHelp.c - procedures for scanning C
26 **
27 ** Most of this code was in cscanner.l, but moved here to separate it
28 ** from the flex-generated code.
29 */
30 
31 # include "splintMacros.nf"
32 # include "basic.h"
33 # include "cscannerHelp.h"
34 # include "cscanner.h"
35 # include "cgrammar_tokens.h"
36 # include "osd.h"
37 
38 static int lminput (void);
39 static int s_tokLength = 0;
40 
41 static /*@owned@*/ cstring s_lastidprocessed = cstring_undefined;
42 static bool s_inSpecPart = FALSE;
43 static int s_whichSpecPart;
44 static char s_savechar = '\0';
45 static bool s_expectingMetaStateName = FALSE;
46 static bool s_lastWasString = FALSE;
47 static bool s_expectingTypeName = TRUE;
48 
49 struct skeyword
50 {
51   /*@null@*/ /*@observer@*/ char *name;
52   int token;
53 } ;
54 
55 /*
56 ** These tokens are followed by syntax that is parsed by the
57 ** grammar proper.
58 */
59 
60 static struct skeyword s_parsetable[] = {
61   { "modifies", QMODIFIES } ,
62   { "globals", QGLOBALS } ,
63   { "alt", QALT } ,
64   { "warn", QWARN } ,
65   { "constant", QCONSTANT } ,
66   { "function", QFUNCTION } ,
67   { "iter", QITER } ,
68   { "defines", QDEFINES } ,
69   { "uses", QUSES } ,
70   { "allocates", QALLOCATES } ,
71   { "sets", QSETS } ,
72   { "releases", QRELEASES } ,
73   { "pre", QPRECLAUSE } ,
74   { "post", QPOSTCLAUSE } ,
75   { "setBufferSize", QSETBUFFERSIZE},
76   { "setStringLength", QSETSTRINGLENGTH},
77   { "testinRange", QTESTINRANGE},
78   { "requires", QPRECLAUSE } ,
79   { "ensures", QPOSTCLAUSE } ,
80   { "invariant", QINVARIANT} ,
81   { NULL, BADTOK }
82 } ;
83 
84 /*
85 ** These tokens are either stand-alone tokens, or followed by
86 ** token-specific text.
87 */
88 
89 static struct skeyword s_keytable[] = {
90   { "anytype", QANYTYPE } ,
91   { "integraltype", QINTEGRALTYPE } ,
92   { "unsignedintegraltype", QUNSIGNEDINTEGRALTYPE } ,
93   { "signedintegraltype", QSIGNEDINTEGRALTYPE } ,
94   { "out", QOUT } ,
95   { "in", QIN } ,
96   { "only", QONLY } ,
97   { "owned", QOWNED } ,
98   { "dependent", QDEPENDENT } ,
99   { "partial", QPARTIAL } ,
100   { "special", QSPECIAL } ,
101   { "truenull", QTRUENULL } ,
102   { "falsenull", QFALSENULL } ,
103   { "nullwhentrue", QTRUENULL } ,
104   { "falsewhennull", QFALSENULL } ,
105   { "keep", QKEEP } ,
106   { "kept", QKEPT } ,
107   { "notnull", QNOTNULL } ,
108   { "abstract", QABSTRACT } ,
109   { "numabstract", QNUMABSTRACT } ,
110   { "concrete", QCONCRETE } ,
111   { "mutable", QMUTABLE } ,
112   { "immutable", QIMMUTABLE } ,
113   { "unused", QUNUSED } ,
114   { "external", QEXTERNAL } ,
115   { "sef", QSEF } ,
116   { "unique", QUNIQUE } ,
117   { "returned", QRETURNED } ,
118   { "exposed", QEXPOSED } ,
119   { "refcounted", QREFCOUNTED } ,
120   { "refs", QREFS } ,
121   { "newref", QNEWREF } ,
122   { "tempref", QTEMPREF } ,
123   { "killref", QKILLREF } ,
124   { "null", QNULL } ,
125   { "relnull", QRELNULL } ,
126   { "nullterminated", QNULLTERMINATED },
127   { "setBufferSize", QSETBUFFERSIZE },
128   { "testInRange", QTESTINRANGE},
129   { "isnull", QISNULL },
130   { "MaxSet", QMAXSET},
131   { "MaxRead", QMAXREAD},
132   { "maxSet", QMAXSET},
133   { "maxRead", QMAXREAD},
134   { "reldef", QRELDEF } ,
135   { "observer", QOBSERVER } ,
136   { "exits", QEXITS } ,
137   { "noreturn", QEXITS } ,
138   { "mayexit", QMAYEXIT } ,
139   { "maynotreturn", QMAYEXIT } ,
140   { "trueexit", QTRUEEXIT } ,
141   { "falseexit", QFALSEEXIT } ,
142   { "noreturnwhentrue", QTRUEEXIT } ,
143   { "noreturnwhenfalse", QFALSEEXIT } ,
144   { "neverexit", QNEVEREXIT } ,
145   { "alwaysreturns", QNEVEREXIT } ,
146   { "temp", QTEMP } ,
147   { "shared", QSHARED } ,
148   { "ref", QREF } ,
149   { "unchecked", QUNCHECKED } ,
150   { "checked", QCHECKED } ,
151   { "checkmod", QCHECKMOD } ,
152   { "checkedstrict", QCHECKEDSTRICT } ,
153   { "innercontinue", QINNERCONTINUE } ,
154   { "innerbreak", QINNERBREAK } ,
155   { "loopbreak", QLOOPBREAK } ,
156   { "switchbreak", QSWITCHBREAK } ,
157   { "safebreak", QSAFEBREAK } ,
158   { "fallthrough", QFALLTHROUGH } ,
159   { "l_fallthrou", QLINTFALLTHROUGH } ,
160   { "l_fallth", QLINTFALLTHRU } ,
161   { "notreached", QNOTREACHED } ,
162   { "l_notreach", QLINTNOTREACHED } ,
163   { "printflike", QPRINTFLIKE } ,
164   { "l_printfli", QLINTPRINTFLIKE } ,
165   { "scanflike", QSCANFLIKE } ,
166   { "messagelike", QMESSAGELIKE } ,
167   { "l_argsus", QARGSUSED } ,
168   { NULL, BADTOK }
169 } ;
170 
171 /*
172 ** would be better if these weren't hard coded...
173 */
174 
isArtificial(cstring s)175 static bool isArtificial (cstring s)
176 {
177   return (cstring_equalLit (s, "modifies")
178 	  || cstring_equalLit (s, "globals")
179 	  || cstring_equalLit (s, "warn")
180 	  || cstring_equalLit (s, "alt"));
181 }
182 
cscannerHelp_swallowMacro(void)183 void cscannerHelp_swallowMacro (void)
184 {
185   int i;
186   bool skipnext = FALSE;
187 
188   while ((i = lminput ()) != EOF)
189     {
190       char c = (char) i;
191 
192       if (c == '\\')
193 	{
194 	  skipnext = TRUE;
195 	}
196       else if (c == '\n')
197 	{
198 	  if (skipnext)
199 	    {
200 	      skipnext = FALSE;
201 	    }
202 	  else
203 	    {
204 	      reader_checkUngetc (i, yyin);
205 	      return;
206 	    }
207 	}
208       else
209 	{
210 	  ;
211 	}
212     }
213 
214   if (i != EOF)
215     {
216       reader_checkUngetc (i, yyin);
217     }
218 }
219 
commentMarkerToken(cstring s)220 static int commentMarkerToken (cstring s)
221 {
222   int i = 0;
223 
224   while (s_parsetable[i].name != NULL)
225     {
226       DPRINTF (("Try :%s:%s:", s, s_parsetable[i].name));
227 
228       if (cstring_equalLit (s, s_parsetable[i].name))
229 	{
230 	  return s_parsetable[i].token;
231 	}
232 
233       i++;
234     }
235 
236   return BADTOK;
237 }
238 
tokenMacroCode(cstring s)239 static int tokenMacroCode (cstring s)
240 {
241   int i = 0;
242 
243   while (s_keytable[i].name != NULL)
244     {
245       if (cstring_equalLit (s, s_keytable[i].name))
246 	{
247 	  if (s_keytable[i].token == QLINTFALLTHROUGH)
248 	    {
249 	      voptgenerror
250 		(FLG_WARNLINTCOMMENTS,
251 		 cstring_makeLiteral
252 		 ("Traditional lint comment /*FALLTHROUGH*/ used. "
253 		  "Splint interprets this in the same way as most Unix lints, but it is "
254 		  "preferable to replace it with the /*@fallthrough@*/ "
255 		  "semantic comment"),
256 		 g_currentloc);
257 	      return QFALLTHROUGH;
258 	    }
259 	  else if (s_keytable[i].token == QLINTFALLTHRU)
260 	    {
261 	      voptgenerror
262 		(FLG_WARNLINTCOMMENTS,
263 		 cstring_makeLiteral
264 		 ("Traditional lint comment /*FALLTHRU*/ used. "
265 		  "Splint interprets this in the same way as most Unix lints, but it is "
266 		  "preferable to replace it with the /*@fallthrough@*/ "
267 		  "semantic comment"),
268 		 g_currentloc);
269 	      return QFALLTHROUGH;
270 	    }
271 	  else if (s_keytable[i].token == QLINTNOTREACHED)
272 	    {
273 	      voptgenerror
274 		(FLG_WARNLINTCOMMENTS,
275 		 cstring_makeLiteral
276 		 ("Traditional lint comment /*NOTREACHED*/ used. "
277 		  "Splint interprets this in the same way as most Unix lints, but it is "
278 		  "preferable to replace it with the /*@notreached@*/ "
279 		  "semantic comment."),
280 		 g_currentloc);
281 
282 	      return QNOTREACHED;
283 	    }
284 	  else if (s_keytable[i].token == QPRINTFLIKE)
285 	    {
286 	      setSpecialFunction (qual_createPrintfLike ());
287 	      return SKIPTOK;
288 	    }
289 	  else if (s_keytable[i].token == QLINTPRINTFLIKE)
290 	    {
291 	      voptgenerror
292 		(FLG_WARNLINTCOMMENTS,
293 		 cstring_makeLiteral
294 		 ("Traditional lint comment /*PRINTFLIKE*/ used. "
295 		  "Splint interprets this in the same way as most Unix lints, but it is "
296 		  "preferable to replace it with either /*@printflike@*/, "
297 		  "/*@scanflike@*/ or /*@messagelike@*/."),
298 		 g_currentloc);
299 
300 	      setSpecialFunction (qual_createPrintfLike ());
301 	      return SKIPTOK;
302 	    }
303 	  else if (s_keytable[i].token == QSCANFLIKE)
304 	    {
305 	      setSpecialFunction (qual_createScanfLike ());
306 	      return SKIPTOK;
307 	    }
308 	  else if (s_keytable[i].token == QMESSAGELIKE)
309 	    {
310 	      setSpecialFunction (qual_createMessageLike ());
311 	      return SKIPTOK;
312 	    }
313 	  else if (s_keytable[i].token == QARGSUSED)
314 	    {
315 	      voptgenerror
316 		(FLG_WARNLINTCOMMENTS,
317 		 cstring_makeLiteral
318 		 ("Traditional lint comment /*ARGSUSED*/ used. "
319 		  "Splint interprets this in the same way as most Unix lints, but it is "
320 		  "preferable to use /*@unused@*/ annotations on "
321 		  "the unused parameters."),
322 		 g_currentloc);
323 
324 	      setArgsUsed ();
325 	      return SKIPTOK;
326 	    }
327 	  else
328 	    {
329 	      return s_keytable[i].token;
330 	    }
331 	}
332 
333       i++;
334     }
335 
336   return BADTOK;
337 }
338 
lminput()339 static int lminput ()
340 {
341   if (s_savechar == '\0')
342     {
343       incColumn ();
344       return (cscanner_input ());
345     }
346   else
347     {
348       int save = (int) s_savechar;
349       s_savechar = '\0';
350       return save;
351     }
352 }
353 
lmsavechar(char c)354 static void lmsavechar (char c)
355 {
356   if (s_savechar == '\0')
357     {
358       s_savechar = c;
359     }
360   else
361     {
362       llbuglit ("lmsavechar: override");
363     }
364 }
365 
cscannerHelp_ninput()366 int cscannerHelp_ninput ()
367 {
368   int c = lminput ();
369 
370   if (c != EOF && ((char)c == '\n'))
371     {
372       context_incLineno ();
373     }
374 
375   return c;
376 }
377 
macro_nextChar(void)378 static char macro_nextChar (void)
379 {
380   static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
381   int ic;
382   char c;
383 
384   ic = lminput ();
385   c = char_fromInt (ic);
386 
387   if (!in_quote && !in_char && (c == '\\' || c == BEFORE_COMMENT_MARKER[0]))
388     {
389       if (c == '\\')
390 	{
391 	  while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
392 	    {
393 	      ; /* skip to newline */
394 	    }
395 
396 	  context_incLineno ();
397 
398 	  if (c != '\0')
399 	    {
400 	      return macro_nextChar ();
401 	    }
402 	  else
403 	    {
404 	      return c;
405 	    }
406 	}
407       else /* if (c == '@') */
408 	{
409 	  llassert (FALSE);
410 
411 	  if (cscannerHelp_handleLlSpecial () != BADTOK)
412 	    {
413 	      llerrorlit (FLG_SYNTAX, "Macro cannot use special syntax");
414 	    }
415 
416 	  return macro_nextChar ();
417 	}
418     }
419   else if (!in_escape && c == '\"')
420     {
421       in_quote = !in_quote;
422     }
423   else if (!in_escape && c == '\'')
424     {
425       in_char = !in_char;
426     }
427   else if ((in_quote || in_char) && c == '\\')
428     {
429       in_escape = !in_escape;
430     }
431   else if ((in_quote || in_char) && in_escape)
432     {
433       in_escape = FALSE;
434     }
435   else if (!in_quote && c == '/')
436     {
437       char c2;
438 
439       if ((c2 = char_fromInt (lminput ())) == '*')
440 	{
441 	  while (c2 != '\0')
442 	    {
443 	      while ((c2 = char_fromInt (lminput ())) != '\0'
444 		     && c2 != '\n' && c2 != '*')
445 		{
446 		  ;
447 		}
448 
449 	      if (c2 == '*')
450 		{
451 		  while ((c2 = char_fromInt (lminput ())) != '\0'
452 			 && c2 == '*')
453 		    {
454 		      ;
455 		    }
456 
457 		  if (c2 == '/')
458 		    {
459 		      goto outofcomment;
460 		    }
461 		}
462 	      else
463 		{
464 		  llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
465 		}
466 	    }
467 	outofcomment:
468 	  return macro_nextChar ();
469 	}
470       else
471 	{
472           /*** putchar does not work!  why?  puts to stdio...??! ***/
473           lmsavechar (c2);
474 	}
475     }
476   else
477     {
478       ;
479     }
480 
481   return c;
482 }
483 
484 /*
485 ** keeps semantic comments
486 */
487 
macro_nextCharC(void)488 static char macro_nextCharC (void)
489 {
490   static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
491   char c;
492 
493   c = char_fromInt (lminput ());
494 
495   if (!in_quote && !in_char && c == '\\')
496     {
497       while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
498 	{
499 	  ; /* skip to newline */
500 	}
501 
502       context_incLineno ();
503 
504       if (c != '\0')
505 	{
506 	  return macro_nextCharC ();
507 	}
508       else
509 	{
510 	  return c;
511 	}
512     }
513   else if (!in_escape && c == '\"')
514     {
515       in_quote = !in_quote;
516     }
517   else if (!in_escape && c == '\'')
518     {
519       in_char = !in_char;
520     }
521   else if ((in_quote || in_char) && c == '\\')
522     {
523       in_escape = !in_escape;
524     }
525   else if ((in_quote || in_char) && in_escape)
526     {
527       in_escape = FALSE;
528     }
529   else if (!in_quote && c == '/')
530     {
531       char c2;
532 
533       if ((c2 = char_fromInt (lminput ())) == '*')
534 	{
535 	  while (c2 != '\0')
536 	    {
537 	      while ((c2 = char_fromInt (lminput ())) != '\0'
538 		     && c2 != '\n' && c2 != '*')
539 		{
540 		  ;
541 		}
542 
543 	      if (c2 == '*')
544 		{
545 		  while ((c2 = char_fromInt (lminput ())) != '\0'
546 			 && c2 == '*')
547 		    {
548 		      ;
549 		    }
550 
551 		  if (c2 == '/')
552 		    {
553 		      goto outofcomment;
554 		    }
555 		}
556 	      else
557 		{
558 		  llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
559 		}
560 	    }
561 	outofcomment:
562 	  return macro_nextCharC ();
563 	}
564       else
565 	{
566 	  lmsavechar (c2);
567 	}
568     }
569   else /* normal character */
570     {
571       ;
572     }
573 
574   return c;
575 }
576 
577 /*
578 ** skips whitespace (handles line continuations)
579 ** returns first non-whitespace character
580 */
581 
skip_whitespace(void)582 static char skip_whitespace (void)
583 {
584   char c;
585 
586   while ((c = macro_nextChar ()) == ' ' || c == '\t')
587     {
588       ;
589     }
590 
591   return c;
592 }
593 
cscannerHelp_handleMacro()594 void cscannerHelp_handleMacro ()
595 {
596   cstring mac = cstring_undefined;
597   int macrocode;
598   char c;
599 
600   while (currentColumn () > 2)
601     {
602       mac = cstring_appendChar (mac, ' ');
603       cscannerHelp_setTokLength (-1);
604     }
605 
606   c = macro_nextCharC ();
607 
608   if (c >= '0' && c <= '9')
609     {
610       int i;
611 
612       for (i = 0; i < (((int) (c - '0')) + 1); i++)
613 	{
614 	  mac = cstring_appendChar (mac, ' ');
615 	}
616     }
617   else
618     {
619       BADBRANCH;
620     }
621 
622   while (((c = macro_nextCharC ()) != '\0') && (c != '\n'))
623     {
624       mac = cstring_appendChar (mac, c);
625     }
626 
627 
628   macrocode = tokenMacroCode (mac);
629 
630   if (macrocode == BADTOK && !isArtificial (mac))
631     {
632       context_addMacroCache (mac);
633     }
634   else
635     {
636       cstring_free (mac);
637     }
638 
639   if (c == '\n')
640     {
641       context_incLineno ();
642     }
643 }
644 
cscannerHelp_handleSpecial(char * yyt)645 bool cscannerHelp_handleSpecial (char *yyt)
646 {
647   char *l; /* !!  = mstring_create (MAX_NAME_LENGTH); */
648   int lineno = 0;
649   char c;
650   char *ol;
651   cstring olc;
652   size_t len_yyt;
653 
654   len_yyt = strlen (yyt +1) ;
655 
656   l = mstring_copy (yyt + 1);
657 
658   while ((c = char_fromInt (lminput ())) != '\n' && c != '\0')
659     {
660       l = mstring_append(l, c);
661     }
662 
663     /* Need to safe original l for deallocating. */
664   ol = l;
665 
666   l += strlen (l);
667 
668   olc = cstring_fromChars (ol);
669 
670   if (cstring_equalPrefixLit (olc, "pragma"))
671     {
672       char *pname = mstring_create (size_fromInt (MAX_PRAGMA_LEN));
673       char *opname = pname;
674       char *ptr = ol + 6; /* pragma is six characters, plus space */
675       int len = 0;
676 
677 
678       /* skip whitespace */
679       while (((c = *ptr) != '\0') && isspace (c))
680 	{
681 	  ptr++;
682 	}
683 
684 
685       while (((c = *ptr) != '\0') && !isspace (c))
686 	{
687 	  len++;
688 
689 	  if (len > MAX_PRAGMA_LEN)
690 	    {
691 	      break;
692 	    }
693 
694 	  ptr++;
695 	  *pname++ = c;
696 	}
697 
698       *pname = '\0';
699 
700       if (len == PRAGMA_LEN_EXPAND
701 	  && mstring_equal (opname, PRAGMA_EXPAND))
702 	{
703 	  cstring exname = cstring_undefined;
704 	  uentry ue;
705 
706 	  ptr++;
707 	  while (((c = *ptr) != '\0') && !isspace (c))
708 	    {
709 	      exname = cstring_appendChar (exname, c);
710 	      ptr++;
711 	    }
712 
713 
714 	  ue = usymtab_lookupExposeGlob (exname);
715 
716 	  if (uentry_isExpandedMacro (ue))
717 	    {
718 	      if (fileloc_isPreproc (uentry_whereDefined (ue)))
719 		{
720 		  fileloc_setColumn (g_currentloc, 1);
721 		  uentry_setDefined (ue, g_currentloc);
722 		}
723 	    }
724 
725 	  cstring_free (exname);
726 	}
727 
728       (void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: pragment increments line */
729     }
730   else if (cstring_equalPrefixLit (olc, "ident"))
731     {
732       /* Some pre-processors will leave these in the code.  Ignore rest of line */
733       (void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: ident increments line */
734     }
735 
736   /*
737   ** Yuk...Win32 filenames can have spaces in them...we need to read
738   ** to the matching end quote.
739   */
740   else if ((sscanf (ol, "line %d \"", &lineno) == 1)
741 	   || (sscanf (ol, " %d \"", &lineno) == 1))
742     {
743       char *tmp = ol;
744       cstring fname;
745       fileId fid;
746 
747       /*@access cstring@*/
748       while (*tmp != '\"' && *tmp != '\0')
749 	{
750 	  tmp++;
751 	}
752 
753       llassert (*tmp == '\"');
754       tmp++;
755       fname = tmp;
756 
757       while (*tmp != '\"' && *tmp != '\0')
758 	{
759 	  tmp++;
760 	}
761 
762       llassert (*tmp == '\"');
763       *tmp = '\0';
764 
765 # if defined(OS2) || defined(MSDOS) || defined(WIN32)
766 
767       /*
768       ** DOS-like path delimiters get delivered in pairs, something like
769       ** \"..\\\\file.h\", so we have to make it normal again. We do NOT
770       ** remove the pre dirs yet as we usually specify tmp paths relative
771       ** to the current directory, so tmp files would not get found in
772       ** the hash table.  If this method fails we try it again later.
773       */
774 
775       {
776 	char *stmp = fname;
777 
778 	/*
779 	** Skip past the drive marker.
780 	*/
781 
782 	if (strchr (stmp, ':') != NULL)
783 	  {
784 	    stmp = strchr (stmp, ':') + 1;
785 	  }
786 
787 	while ((stmp = strchr (stmp, CONNECTCHAR)) != NULL )
788 	  {
789 	    if (*(stmp+1) == CONNECTCHAR)
790 	      {
791 		memmove (stmp, stmp+1, strlen (stmp));
792 	      }
793 
794 	    stmp++;
795 	  }
796 
797 	fid = fileTable_lookupBase (context_fileTable (), fname);
798 	if (!(fileId_isValid (fid)))
799 	  {
800 	    fname = removePreDirs (fname);
801 	    fid = fileTable_lookupBase (context_fileTable (), fname);
802 	  }
803       }
804 # else  /* !defined(OS2) && !defined(MSDOS) */
805       fname = removePreDirs (fname);
806       fid = fileTable_lookupBase (context_fileTable (), fname);
807 # endif /* !defined(OS2) && !defined(MSDOS) */
808 
809       if (!(fileId_isValid (fid)))
810 	{
811 	  if (context_inXHFile ())
812 	    {
813 	      fid = fileTable_addXHFile (context_fileTable (), fname);
814 	    }
815 	  else if (isHeaderFile (fname))
816 	    {
817 	      fid = fileTable_addHeaderFile (context_fileTable (), fname);
818 	    }
819 	  else
820 	    {
821 	      fid = fileTable_addFile (context_fileTable (), fname);
822 	    }
823 	}
824 
825       setFileLine (fid, lineno);
826       /*@noaccess cstring@*/
827     }
828   else if ((sscanf (ol, "line %d", &lineno) == 1)
829 	   || (sscanf (ol, " %d", &lineno) == 1))
830     {
831       setLine (lineno); /* next line is <cr> */
832     }
833   else
834     {
835       if (mstring_equal (ol, "")) {
836 	DPRINTF (("Empty pp command!"));
837 	/*
838 	** evs 2000-05-16: This is a horrible kludge, to get around a bug (well, difficulty) in the pre-processor.
839 	** We handle a plain # in the input file, by echoing it, and ignoring it in the post-pp-file.
840 	*/
841 	mstring_free (ol);
842 	(void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: increments line */
843 	return FALSE;
844       } else {
845 	voptgenerror
846 	  (FLG_UNRECOGDIRECTIVE,
847 	   message ("Unrecognized pre-processor directive: #%s",
848 		    cstring_fromChars (ol)),
849 	   g_currentloc);
850 	(void) cscannerHelp_handleNewLine (); /* evans 2003-10-27: increments line */
851       }
852 
853       sfree (ol);
854       return FALSE; /* evans 2001-12-30: was: TRUE; */
855     }
856 
857   sfree (ol);
858   return FALSE;
859 }
860 
cscannerHelp_handleLlSpecial(void)861 int cscannerHelp_handleLlSpecial (void)
862 {
863   bool hasnl = FALSE;
864   int ic;
865   char c;
866   char *s = mstring_createEmpty ();
867   char *os;
868   int tok;
869   int charsread = 0;
870   fileloc loc;
871 
872   loc = fileloc_copy (g_currentloc);
873   DPRINTF (("Handle special: %s", fileloc_unparse (loc)));
874 
875   while (((ic = cscannerHelp_ninput ()) != 0) && isalpha (ic))
876     {
877       c = (char) ic;
878       s = mstring_append (s, c);
879       charsread++;
880     }
881 
882   DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));
883   os = s;
884 
885   if (charsread == 0 && ic == (int) AFTER_COMMENT_MARKER[0])
886     {
887       ic = cscannerHelp_ninput ();
888 
889       llassert (ic == (int) AFTER_COMMENT_MARKER[1]);
890 
891       if (*s == '\0')
892 	{
893 	  sfree (os);
894 	  fileloc_free (loc);
895 	  return QNOMODS; /* special token no modifications token */
896 	}
897     }
898 
899   DPRINTF (("Coment marker: %s", os));
900   tok = commentMarkerToken (cstring_fromChars (os));
901 
902   if (tok != BADTOK)
903     {
904       s_tokLength = charsread;
905       sfree (os);
906       s_inSpecPart = TRUE;
907       s_whichSpecPart = tok;
908       fileloc_free (loc);
909       return tok;
910     }
911 
912   DPRINTF (("Not a comment marker..."));
913   /* Add rest of the comment */
914 
915   if (ic != 0 && ic != EOF)
916     {
917       c = (char) ic;
918 
919       s = mstring_append (s, c);
920       charsread++;
921 
922       while (((ic = cscannerHelp_ninput ()) != 0) && (ic != EOF)
923 	     && (ic != (int) AFTER_COMMENT_MARKER[0]))
924 	{
925 	  c = (char) ic;
926 
927 	  /* evans 2001-09-01 added to prevent assertion failures for uncloses syntactic comments */
928 
929 	  if (c == '\n') {
930 	    hasnl = TRUE; /* This prevents tokLength from being set later. */
931 	    s_tokLength = 0;
932 
933 	    voptgenerror
934 	      (FLG_SYNTAX,
935 	       message ("Likely parse error: syntactic comment token spans multiple lines: %s",
936 			cstring_fromChars (s)),
937 	       loc);
938 	  }
939 
940 	  s = mstring_append (s, c);
941 	  charsread++;
942 	}
943       /*@-branchstate@*/
944     } /* spurious (?) warnings about s */
945   /*@=branchstate@*/
946 
947   DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));
948 
949   if (ic == (int) AFTER_COMMENT_MARKER[0])
950     {
951       int nc = cscannerHelp_ninput ();
952       llassert ((char) nc ==  AFTER_COMMENT_MARKER[1]);
953       charsread++;
954     }
955 
956   os = s;
957 
958   while (*s == ' ' || *s == '\t' || *s == '\n')
959     {
960       s++;
961     }
962 
963   if (*s == '-' || *s == '+' || *s == '=') /* setting flags */
964     {
965       c = *s;
966 
967       while (c == '-' || c == '+' || c == '=')
968 	{
969 	  ynm set = ynm_fromCodeChar (c);
970 	  cstring thisflag;
971 
972 	  s++;
973 
974 	  thisflag = cstring_fromChars (s);
975 
976 	  while ((c = *s) != '\0' && (c != '-') && (c != '=')
977 		 && (c != '+') && (c != ' ') && (c != '\t') && (c != '\n'))
978 	    {
979 	      s++;
980 	    }
981 
982 	  *s = '\0';
983 
984 	  if (!context_getFlag (FLG_NOCOMMENTS))
985 	    {
986 	      cstring flagname = thisflag;
987 	      flagcode fflag = flags_identifyFlag (flagname);
988 
989 	      if (flagcode_isSkip (fflag))
990 		{
991 		  ;
992 		}
993 	      else if (flagcode_isModeName (fflag))
994 		{
995 		  if (ynm_isMaybe (set))
996 		    {
997 		      llerror
998 			(FLG_BADFLAG,
999 			 message
1000 			 ("Semantic comment attempts to restore flag %s.  "
1001 			  "A mode flag cannot be restored.",
1002 			  flagname));
1003 		    }
1004 		  else
1005 		    {
1006 		      context_setMode (flagname);
1007 		    }
1008 		}
1009 	      else if (flagcode_isInvalid (fflag))
1010 		{
1011 		  voptgenerror
1012 		    (FLG_UNRECOGFLAGCOMMENTS,
1013 		     message ("Unrecognized option in semantic comment: %s",
1014 			      flagname),
1015 		     loc);
1016 		}
1017 	      else if (flagcode_isGlobalFlag (fflag))
1018 		{
1019 		  voptgenerror
1020 		    (FLG_BADFLAG,
1021 		     message
1022 		     ("Semantic comment attempts to set global flag %s.  "
1023 		      "A global flag cannot be set locally.",
1024 		      flagname),
1025 		     loc);
1026 		}
1027 	      else
1028 		{
1029 		  context_fileSetFlag (fflag, set, loc);
1030 
1031 		  if (flagcode_hasArgument (fflag))
1032 		    {
1033 		      if (ynm_isMaybe (set))
1034 			{
1035 			  voptgenerror
1036 			    (FLG_BADFLAG,
1037 			     message
1038 			     ("Semantic comment attempts to restore flag %s.  "
1039 			      "A flag for setting a value cannot be restored.",
1040 			      flagname),
1041 			     loc);
1042 			}
1043 		      else
1044 			{ /* cut-and-pastied from llmain...blecch */
1045 			  cstring extra = cstring_undefined;
1046 			  char *rest;
1047 			  char *orest;
1048 			  char rchar;
1049 
1050 			  *s = c;
1051 			  rest = mstring_copy (s);
1052 			  orest = rest;
1053 			  *s = '\0';
1054 
1055 			  while ((rchar = *rest) != '\0'
1056 				 && (isspace (rchar)))
1057 			    {
1058 			      rest++;
1059 			      s++;
1060 			    }
1061 
1062 			  while ((rchar = *rest) != '\0'
1063 				 && !isspace (rchar))
1064 			    {
1065 			      extra = cstring_appendChar (extra, rchar);
1066 			      rest++;
1067 			      s++;
1068 			    }
1069 			  s--; /* evans 2002-07-12: this was previously only in the else branch.
1070 				  Leads to an invalid read on the true branch.
1071 			       */
1072 
1073 			  sfree (orest);
1074 
1075 			  if (cstring_isUndefined (extra))
1076 			    {
1077 			      llerror
1078 				(FLG_BADFLAG,
1079 				 message
1080 				 ("Flag %s (in semantic comment) must be followed by an argument",
1081 				  flagcode_unparse (fflag)));
1082 
1083 			      cstring_free (extra);
1084 			    }
1085 			  else
1086 			    {
1087 			      if (flagcode_hasNumber (fflag))
1088 				{
1089 				  flags_setValueFlag (fflag, extra);
1090 				}
1091 			      else if (flagcode_hasChar (fflag))
1092 				{
1093 				  flags_setValueFlag (fflag, extra);
1094 				}
1095 			      else if (flagcode_hasString (fflag))
1096 				{
1097 				  flags_setStringFlag (fflag, extra);
1098 				}
1099 			      else
1100 				{
1101 				  cstring_free (extra);
1102 				  BADEXIT;
1103 				}
1104 			    }
1105 			}
1106 		    }
1107 		}
1108 	    }
1109 	  else
1110 	    {
1111 	      ;
1112 	    }
1113 
1114 	  *s = c;
1115 	  while ((c == ' ') || (c == '\t') || (c == '\n'))
1116 	    {
1117 	      c = *(++s);
1118 	    }
1119 	}
1120 
1121       if (context_inHeader () && !isArtificial (cstring_fromChars (os)))
1122 	{
1123 	  DPRINTF (("Here adding comment: %s", os));
1124 	  context_addComment (cstring_fromCharsNew (os), loc);
1125 	}
1126       else
1127 	{
1128 	  ;
1129 	}
1130     }
1131   else
1132     {
1133       char *t = s;
1134       int macrocode;
1135       char tchar = '\0';
1136       annotationInfo ainfo;
1137 
1138       while (*s != '\0' && *s != ' ' && *s != '\t' && *s != '\n')
1139 	{
1140 	  s++;
1141 	}
1142 
1143       if (*s != '\0')
1144 	{
1145 	  tchar = *s;
1146 	  *s = '\0';
1147 	  s++;
1148 	}
1149 
1150       t = cstring_toCharsSafe (cstring_downcase (cstring_fromChars (t)));
1151       macrocode = tokenMacroCode (cstring_fromChars (t));
1152 
1153       if (macrocode != BADTOK)
1154 	{
1155 	  s_tokLength = hasnl ? 0 : size_toInt (mstring_length (t));
1156 
1157 	  sfree (t);
1158 	  sfree (os);
1159 	  fileloc_free (loc);
1160 
1161 	  if (macrocode == SKIPTOK)
1162 	    {
1163 	      return BADTOK;
1164 	    }
1165 
1166 	  return macrocode;
1167 	}
1168 
1169       ainfo = context_lookupAnnotation (cstring_fromChars (os));
1170 
1171       if (annotationInfo_isDefined (ainfo)) {
1172 	DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo)));
1173 	yylval.annotation = ainfo;
1174 	s_tokLength = 0;
1175 	sfree (os);
1176 	sfree (t);
1177 	fileloc_free (loc);
1178 	return CANNOTATION;
1179       }
1180 
1181       if (context_inHeader ())
1182 	{
1183 	  if (tchar != '\0')
1184 	    {
1185 	      *(s-1) = tchar;
1186 	    }
1187 
1188 	  if ((context_inMacro () || context_inGlobalContext ())
1189 	      && macrocode != SKIPTOK
1190 	      && !isArtificial (cstring_fromChars (os)))
1191 	    {
1192 	      if (context_processingMacros ())
1193 		{
1194 		  /* evans 2002-02-24: don't add comments when procssing macros */
1195 		}
1196 	      else
1197 		{
1198 		  context_addComment (cstring_fromCharsNew (os), loc);
1199 		}
1200 	    }
1201 	  else
1202 	    {
1203 	      ;
1204 	    }
1205 
1206 	  if (tchar != '\0')
1207 	    {
1208 	      *(s-1) = '\0';
1209 	    }
1210 	}
1211 
1212       if (mstring_equal (t, "ignore"))
1213 	{
1214 	  if (!context_getFlag (FLG_NOCOMMENTS))
1215 	    {
1216 	      context_enterSuppressRegion (loc);
1217 	    }
1218 	}
1219       else if ((*t == 'i' || *t == 't')
1220 	       && (*(t + 1) == '\0'))
1221 	{
1222 	  if (!context_getFlag (FLG_NOCOMMENTS)
1223 	      && (*t == 'i' || context_getFlag (FLG_TMPCOMMENTS)))
1224 	    {
1225 	      context_enterSuppressLine (-1, loc); /* infinite suppression */
1226 	    }
1227 	}
1228       else if (((*t == 'i') || (*t == 't'))
1229 	       && ((*(t + 1) >= '0' && *(t + 1) <= '9')))
1230 	{
1231 	  bool tmpcomment = (*t == 't');
1232 	  int val = -1;
1233 	  char *tt = t; /* don't mangle t, since it is free'd */
1234 	  char lc = *(++tt);
1235 
1236 	  if (lc >= '0' && lc <= '9')
1237 	    {
1238 	      val = (int)(lc - '0');
1239 
1240 	      lc = *(++tt);
1241 	      while (lc >= '0' && lc <= '9')
1242 		{
1243 		  val *= 10;
1244 		  val += (int) (lc - '0');
1245 		  lc = *(++tt);
1246 		}
1247 	    }
1248 
1249 	  if (!context_getFlag (FLG_NOCOMMENTS)
1250 	      && (!tmpcomment || context_getFlag (FLG_TMPCOMMENTS)))
1251 	    {
1252 	      DPRINTF (("Here: enter suppress: %s", fileloc_unparse (loc)));
1253 	      context_enterSuppressLine (val, loc);
1254 	    }
1255 	}
1256       else if (mstring_equal (t, "end"))
1257 	{
1258 	  if (!context_getFlag (FLG_NOCOMMENTS))
1259 	    {
1260 	      context_exitSuppressRegion (loc);
1261 	    }
1262 	}
1263       else if (mstring_equal (t, "notfunction"))
1264 	{
1265 	 ; /* handled by pcpp */
1266 	}
1267       else if (mstring_equal (t, "access"))
1268 	{
1269 	  cstring tname;
1270 
1271 	  while (TRUE)
1272 	    {
1273 	      while (((c = *s) != '\0') && (c == ' ' || c == '\t' || c == '\n'))
1274 		{
1275 		  s++;
1276 		}
1277 
1278 	      if (c == '\0')
1279 		{
1280                    break;
1281 		}
1282 
1283 	      tname = cstring_fromChars (s);
1284 
1285 	      while ((c = *s) != '\0' && c != ' '
1286 		     && c != '\t' && c != '\n' && c != ',')
1287 		{
1288 		  s++;
1289 		}
1290 
1291 	      *s = '\0';
1292 
1293 	      DPRINTF (("Access %s", tname));
1294 
1295 	      if (!context_getFlag (FLG_NOCOMMENTS)
1296 		  && !context_getFlag (FLG_NOACCESS))
1297 		{
1298 		  if (usymtab_existsType (tname))
1299 		    {
1300 		      typeId uid = usymtab_getTypeId (tname);
1301 		      uentry ue = usymtab_getTypeEntry (uid);
1302 
1303 		      if (uentry_isAbstractDatatype (ue))
1304 			{
1305 			  context_addFileAccessType (uid);
1306 			  DPRINTF (("Adding access to: %s / %d", tname, uid));
1307 			}
1308 		      else
1309 			{
1310 			  voptgenerror
1311 			    (FLG_COMMENTERROR,
1312 			     message
1313 			     ("Non-abstract type %s used in access comment",
1314 			      tname),
1315 			     loc);
1316 			}
1317 		    }
1318 		  else
1319 		    {
1320 		      if (!(context_inSuppressRegion ()
1321 			    || context_inSuppressZone (loc)))
1322 			{
1323 			  voptgenerror
1324 			    (FLG_COMMENTERROR,
1325 			     message
1326 			     ("Unrecognized type %s used in access comment",
1327 			      tname),
1328 			     loc);
1329 			}
1330 		    }
1331 		}
1332 
1333 	      if (c != '\0')
1334 		{
1335 		  s++;
1336 		}
1337 
1338 	      if (c != ',' && c != ' ')
1339 		{
1340 		  break;
1341 		}
1342 	    }
1343 	}
1344       else if (mstring_equal (t, "noaccess"))
1345 	{
1346 	  cstring tname;
1347 	  char lc;
1348 
1349 	  while (TRUE)
1350 	    {
1351 	      while (((lc = *s) != '\0') && (lc == ' ' || lc == '\t' || lc == '\n'))
1352 		{
1353 		  s++;
1354 		}
1355 
1356 	      if (lc == '\0')
1357 		{
1358 		 break;
1359 		}
1360 
1361 	      tname = cstring_fromChars (s);
1362 
1363 	      while ((lc = *s) != '\0' && lc != ' ' && lc != '\t'
1364 		     && lc != '\n' && lc != ',')
1365 		{
1366 		  s++;
1367 		}
1368 
1369 	      *s = '\0';
1370 
1371 	      if (!context_getFlag (FLG_NOCOMMENTS)
1372 		  && !context_getFlag (FLG_NOACCESS))
1373 		{
1374 		  if (usymtab_existsType (tname))
1375 		    {
1376 		      typeId tuid = usymtab_getTypeId (tname);
1377 
1378 		      if (context_couldHaveAccess (tuid))
1379 			{
1380 			  DPRINTF (("Removing access: %s", tname));
1381 			  context_removeFileAccessType (tuid);
1382 			}
1383 		      else
1384 			{
1385 			  if (!(context_inSuppressRegion ()
1386 				|| context_inSuppressZone (loc)))
1387 			    {
1388 			      uentry ue = usymtab_getTypeEntry (tuid);
1389 
1390 			      if (uentry_isAbstractDatatype (ue))
1391 				{
1392 				  voptgenerror
1393 				    (FLG_COMMENTERROR,
1394 				     message
1395 				     ("Non-accessible abstract type %s used in noaccess comment",
1396 				      tname),
1397 				     loc);
1398 				}
1399 			      else
1400 				{
1401 				  voptgenerror
1402 				    (FLG_COMMENTERROR,
1403 				     message
1404 				     ("Non-abstract type %s used in noaccess comment",
1405 				      tname),
1406 				     loc);
1407 				}
1408 			    }
1409 			}
1410 		    }
1411 		  else
1412 		    {
1413 		      if (!(context_inSuppressRegion ()
1414 			    || context_inSuppressZone (loc)))
1415 			{
1416 			  voptgenerror
1417 			    (FLG_COMMENTERROR,
1418 			     message
1419 			     ("Unrecognized type %s used in noaccess comment",
1420 			      tname),
1421 			     loc);
1422 			}
1423 		    }
1424 		}
1425 
1426 	      if (lc != '\0')
1427 		{
1428 		  s++;
1429 		}
1430 
1431 	      if (lc != ',' && lc != ' ')
1432 		{
1433 		  break;
1434 		}
1435 	    }
1436 	}
1437       else
1438 	{
1439 	  voptgenerror (FLG_UNRECOGCOMMENTS,
1440 			message ("Semantic comment unrecognized: %s",
1441 				 cstring_fromChars (os)),
1442 			loc);
1443 	  /*@-branchstate@*/
1444 	} /* spurious (?) warning about t */
1445       /*@=branchstate@*/
1446 
1447       sfree (t);
1448     }
1449 
1450   sfree (os);
1451   fileloc_free (loc);
1452   return BADTOK;
1453 }
1454 
cscannerHelp_makeIdentifier(char * s)1455 /*@only@*/ cstring cscannerHelp_makeIdentifier (char *s)
1456 {
1457   char *c = mstring_create (strlen (s) + 1);
1458   cstring id = cstring_fromChars (c);
1459 
1460   while (isalnum (*s) || (*s == '_') || (*s == '$'))
1461     {
1462       *c++ = *s++;
1463     }
1464 
1465   *c = '\0';
1466   return (id);
1467 }
1468 
cscannerHelp_coerceId(cstring cn)1469 /*@observer@*/ /*@dependent@*/ uentry cscannerHelp_coerceId (cstring cn)
1470 {
1471   if (!(usymtab_exists (cn)))
1472     {
1473       fileloc loc = fileloc_createExternal ();
1474 
1475       /*
1476       ** We need to put this in a global scope, otherwise the sRef will be deallocated.
1477       */
1478 
1479       uentry ce = uentry_makeUnrecognized (cn, loc);
1480 
1481       if (!context_inIterEnd ())
1482 	{
1483 	  voptgenerror
1484 	    (FLG_SYSTEMUNRECOG,
1485 	     message ("Unrecognized (possibly system) identifier: %q",
1486 		      uentry_getName (ce)),
1487 	     g_currentloc);
1488 	}
1489 
1490       return ce;
1491     }
1492 
1493   return (usymtab_lookup (cn));
1494 }
1495 
1496 /*
1497 ** like, cscannerHelp_coerceId, but doesn't supercede for iters
1498 */
1499 
cscannerHelp_coerceIterId(cstring cn)1500 /*@observer@*/ uentry cscannerHelp_coerceIterId (cstring cn)
1501 {
1502   if (!(usymtab_exists (cn)))
1503     {
1504       return uentry_undefined;
1505     }
1506 
1507   return (usymtab_lookup (cn));
1508 }
1509 
1510 /*
1511 ** Need to keep this in case there is a declaration that isn't processed until
1512 ** the scope exits.  Would be good to rearrange the symbol table so this doesn't
1513 ** happen, and save all the cstring copying.
1514 */
1515 
cscannerHelp_observeLastIdentifier()1516 /*@observer@*/ cstring cscannerHelp_observeLastIdentifier ()
1517 {
1518   cstring res = s_lastidprocessed;
1519   return res;
1520 }
1521 
cscanner_setLastIdentifier(cstring id)1522 static void cscanner_setLastIdentifier (/*@keep@*/ cstring id) /*@modifies s_lastidprocessed@*/
1523 {
1524   if (cstring_isDefined (s_lastidprocessed))
1525     {
1526       cstring_free (s_lastidprocessed);
1527     }
1528 
1529   s_lastidprocessed = id;
1530 }
1531 
cscannerHelp_processIdentifier(cstring id)1532 int cscannerHelp_processIdentifier (cstring id)
1533 {
1534   uentry le;
1535 
1536   if (context_getFlag (FLG_GRAMMAR))
1537     {
1538       lldiagmsg (message ("Process identifier: %s", id));
1539     }
1540 
1541   context_clearJustPopped ();
1542   cscanner_setLastIdentifier (id);
1543 
1544   DPRINTF (("Context: %s", context_unparse ()));
1545 
1546   if (context_inFunctionHeader ())
1547     {
1548       int tok = commentMarkerToken (id);
1549       DPRINTF (("in function decl: %s", id));
1550 
1551       if (tok != BADTOK)
1552 	{
1553 	  return tok;
1554 	}
1555       else
1556 	{
1557 	  tok = tokenMacroCode (id);
1558 
1559 	  if (tok != BADTOK)
1560 	    {
1561 	      return tok;
1562 	    }
1563 	  else
1564 	    {
1565 	      annotationInfo ainfo;
1566 
1567 	      if (s_expectingMetaStateName)
1568 		{
1569 		  metaStateInfo msinfo = context_lookupMetaStateInfo (id);
1570 
1571 		  if (metaStateInfo_isDefined (msinfo))
1572 		    {
1573 		      yylval.msinfo = msinfo;
1574 		      return METASTATE_NAME;
1575 		    }
1576 		  else
1577 		    {
1578 		      DPRINTF (("Not meta state name: %s", cstring_toCharsSafe (id)));
1579 		    }
1580 		}
1581 
1582 	      ainfo = context_lookupAnnotation (id);
1583 
1584 	      if (annotationInfo_isDefined (ainfo))
1585 		{
1586 		  DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo)));
1587 		  yylval.annotation = ainfo;
1588 		  return CANNOTATION;
1589 		}
1590 	      else
1591 		{
1592 		  DPRINTF (("Not annotation: %s", id));
1593 		}
1594 	    }
1595 	}
1596     }
1597 
1598   DPRINTF (("Here!"));
1599 
1600   /* Consider handling: Defined by C99 as static const char __func__[] */
1601 
1602   if (context_getFlag (FLG_GNUEXTENSIONS))
1603     {
1604       int tok = BADTOK;
1605 
1606       if (cstring_equalLit (id, "__stdcall")
1607 	  || cstring_equalLit (id, "__cdecl")
1608 	  || cstring_equalLit (id, "__extension__"))
1609 	{
1610 	  return BADTOK;
1611 	}
1612       else if (cstring_equalLit (id, "__volatile__"))
1613 	{
1614 	  tok = QVOLATILE;
1615 	}
1616       else if (cstring_equalLit (id, "__signed"))
1617 	{
1618 	  tok = QSIGNED;
1619 	}
1620       else if (cstring_equalLit (id, "__unsigned"))
1621 	{
1622 	  tok = QUNSIGNED;
1623 	}
1624       else if (cstring_equalLit (id, "__const__"))
1625 	{
1626 	  tok = QCONST;
1627 	}
1628       else if (cstring_equalLit (id, "__alignof__"))
1629 	{
1630 	  tok = CALIGNOF; /* alignof is parsed like sizeof */
1631 	}
1632       else if (cstring_equalLit (id, "__typeof__"))
1633 	{
1634 	  tok = CTYPEOF;
1635 	}
1636       else if (cstring_equalLit (id, "typeof"))
1637 	{
1638 	  tok = CTYPEOF;
1639 	}
1640       else if (cstring_equalLit (id, "__FUNCTION__")
1641 	       || cstring_equalLit (id, "__PRETTY_FUNCTION__"))
1642 	{
1643 	  /* These tokens hold the name of the current function as strings */
1644 	  /* evans 2001-12-30: changed from exprNode_stringLiteral; bug reported by Jim Zelenka. */
1645 	  yylval.expr = exprNode_makeConstantString (id, fileloc_copy (g_currentloc));
1646 	  s_tokLength = 0;
1647 	  s_lastWasString = TRUE;
1648 	  tok = CCONSTANT;
1649 	  return tok;
1650 	}
1651       else if (cstring_equalLit (id, "__attribute__")
1652 	       || cstring_equalLit (id, "__asm__")
1653 	       || cstring_equalLit (id, "_asm")
1654 	       || cstring_equalLit (id, "__asm")
1655 	       || cstring_equalLit (id, "__declspec"))
1656 	{
1657 	  int depth = 0;
1658 	  bool useparens = FALSE;
1659 	  bool usebraces = FALSE;
1660 	  bool inquote = FALSE;
1661 	  bool inescape = FALSE;
1662 	  int ic;
1663 
1664 	  while ((ic = cscanner_input ()) != EOF)
1665 	    {
1666 	      char cc = (char) ic;
1667 
1668 	      if (inescape)
1669 		{
1670 		  inescape = FALSE;
1671 		}
1672 	      else if (cc == '\\')
1673 		{
1674 		  inescape = TRUE;
1675 		}
1676 	      else if (cc == '\"')
1677 		{
1678 		  inquote = !inquote;
1679 		}
1680 	      else if (!inquote)
1681 		{
1682 		  if (cc == '(')
1683 		    {
1684 		      if (!useparens)
1685 			{
1686 			  if (!usebraces)
1687 			    {
1688 			      useparens = TRUE;
1689 			    }
1690 			}
1691 
1692 		      if (useparens)
1693 			{
1694 			  depth++;
1695 			}
1696 		    }
1697 		  else if (cc == '{')
1698 		    {
1699 		      if (!usebraces)
1700 			{
1701 			  if (!useparens)
1702 			    {
1703 			      usebraces = TRUE;
1704 			    }
1705 			}
1706 
1707 		      if (usebraces)
1708 			{
1709 			  depth++;
1710 			}
1711 		    }
1712 		  else if (cc == ')' && useparens)
1713 		    {
1714 		      depth--;
1715 		      if (depth == 0) break;
1716 		    }
1717 		  else if (cc == '}' && usebraces)
1718 		    {
1719 		      depth--;
1720 		      if (depth == 0) break;
1721 		    }
1722 		  else if (cc == '}'
1723 			   && !usebraces && !useparens
1724 			   && cstring_equalLit (id, "__asm"))
1725 		    {
1726 		      /*
1727 		      ** We need this because some MS VC++ include files
1728 		      ** have __asm mov ... }
1729 		      ** Its a kludge, but otherwise would need to parse
1730 		      ** the asm code!
1731 		      */
1732 		      return TRBRACE;
1733 		    }
1734 		  else
1735 		    {
1736 		      ;
1737 		    }
1738 		}
1739 	      else
1740 		{
1741 		  ;
1742 		}
1743 
1744 	      if (cc == '\n')
1745 		{
1746 		  context_incLineno ();
1747 
1748 		  if (cstring_equalLit (id, "__asm")
1749 		      && !useparens && !usebraces)
1750 		    {
1751 		      break;
1752 		    }
1753 		}
1754 	    }
1755 
1756 	  llassert ((useparens && ic == (int) ')')
1757 		    || (usebraces && ic == (int) '}')
1758 		    || (!useparens && !usebraces));
1759 
1760 	  return BADTOK;
1761 	}
1762       else if (cstring_equalLit (id, "inline")
1763 	       || cstring_equalLit (id, "__inline")
1764 	       || cstring_equalLit (id, "_inline")
1765 	       || cstring_equalLit (id, "__inline__"))
1766 	{
1767 	  tok = QINLINE;
1768 	}
1769       else
1770 	{
1771 	  ;
1772 	}
1773 
1774       if (tok != BADTOK)
1775 	{
1776 	  return (cscannerHelp_returnToken (tok));
1777 	}
1778     }
1779 
1780   le = usymtab_lookupSafe (id);
1781 
1782   /*@-dependenttrans@*/
1783 
1784   if (uentry_isIter (le))
1785     {
1786       yylval.entry = le;
1787       return (ITER_NAME);
1788     }
1789   else if (uentry_isEndIter (le))
1790     {
1791       yylval.entry = le;
1792       return (ITER_ENDNAME);
1793     }
1794   else if (uentry_isUndefined (le))
1795     {
1796       yylval.cname = cstring_copy (id);
1797 
1798       /* avoid parse errors for certain system built ins */
1799 
1800       if (s_expectingTypeName && (cstring_firstChar (id) == '_')
1801 	  && (cstring_secondChar (id) == '_'))
1802 	{
1803 	  return (TYPE_NAME_OR_ID);
1804 	}
1805 
1806       return (NEW_IDENTIFIER);
1807     }
1808   else if (!uentry_isDeclared (le) && !uentry_isCodeDefined (le))
1809     {
1810       if (uentry_isDatatype (le))
1811 	{
1812 	  yylval.cname = cstring_copy (id);
1813 	  return (NEW_IDENTIFIER);
1814 	}
1815       else
1816 	{
1817 	  yylval.entry = le;
1818 	  return (IDENTIFIER);
1819 	}
1820     }
1821   else if (uentry_isDatatype (le))
1822     {
1823       if (!s_expectingTypeName)
1824 	{
1825 	  yylval.cname = cstring_copy (id);
1826 
1827 	  return (NEW_IDENTIFIER);
1828 	}
1829       else
1830 	{
1831 	  yylval.ctyp = uentry_getAbstractType (le);
1832 
1833 	  uentry_setUsed (le, g_currentloc);
1834 	  return (TYPE_NAME);
1835 	}
1836     }
1837   else
1838     {
1839       yylval.entry = le;
1840       return (IDENTIFIER);
1841     }
1842 
1843   /*@=dependenttrans@*/
1844 }
1845 
cscannerHelp_processHashIdentifier(cstring id)1846 bool cscannerHelp_processHashIdentifier (/*@only@*/ cstring id)
1847 {
1848   if (context_inMacro () || context_inIterDef () ||
1849       context_inIterEnd ())
1850     {
1851       uentry le;
1852 
1853       context_clearJustPopped ();
1854 
1855       le = usymtab_lookupSafe (id);
1856       cscanner_setLastIdentifier (id);
1857 
1858       if (uentry_isParam (le) || uentry_isRefParam (le))
1859 	{
1860 	  return TRUE;
1861 	}
1862       else
1863 	{
1864 	  return FALSE;
1865 	}
1866     }
1867   else
1868     {
1869       /*
1870       ** Will be handled by handleLlSpecial
1871       */
1872 
1873       cstring_free (id);
1874       return FALSE;
1875     }
1876 }
1877 
cscannerHelp_processString(void)1878 /*@only@*/ exprNode cscannerHelp_processString (void)
1879 {
1880   exprNode res;
1881   fileloc loc;
1882   char *nl = strchr (yytext, '\n');
1883   cstring ns = cstring_fromCharsNew (yytext);
1884 
1885   if (nl == NULL)
1886     {
1887       loc = fileloc_copy (g_currentloc);
1888       addColumn (size_toInt (cstring_length (ns)));
1889     }
1890   else
1891     {
1892       char *lastnl = nl;
1893 
1894       loc = fileloc_copy (g_currentloc);
1895 
1896       context_incLineno ();
1897 
1898       while ((nl = strchr ((nl + 1), '\n')) != NULL)
1899 	{
1900 	  context_incLineno ();
1901 	  lastnl = nl;
1902 	}
1903     }
1904 
1905 
1906   res = exprNode_stringLiteral (ns, loc);
1907   return (res);
1908 }
1909 
1910 /*
1911 ** process a wide character string L"...."
1912 */
1913 
cscannerHelp_processWideString()1914 /*@only@*/ exprNode cscannerHelp_processWideString ()
1915 {
1916   exprNode res;
1917   fileloc loc;
1918   char *nl = strchr (yytext, '\n');
1919   cstring ns;
1920 
1921   llassert (*yytext == 'L');
1922   yytext++;
1923 
1924   ns = cstring_fromCharsNew (yytext);
1925 
1926   if (nl == NULL)
1927     {
1928       loc = fileloc_copy (g_currentloc);
1929       addColumn (size_toInt (cstring_length (ns)));
1930     }
1931   else
1932     {
1933       char *lastnl = nl;
1934 
1935       loc = fileloc_copy (g_currentloc);
1936 
1937       context_incLineno ();
1938 
1939       while ((nl = strchr ((nl + 1), '\n')) != NULL)
1940 	{
1941 	  context_incLineno ();
1942 	  lastnl = nl;
1943 	}
1944     }
1945 
1946   res = exprNode_wideStringLiteral (ns, loc);
1947   return (res);
1948 }
1949 
cscannerHelp_processChar()1950 char cscannerHelp_processChar ()
1951 {
1952   char fchar;
1953   char next;
1954 
1955   llassert (*yytext != '\0');
1956   fchar = *(yytext + 1);
1957   if (fchar != '\\') return fchar;
1958 
1959   next = *(yytext + 2);
1960 
1961   switch (next)
1962     {
1963     case 'n': return '\n';
1964     case 't': return '\t';
1965     case '\"': return '\"';
1966     case '\'': return '\'';
1967     case '\\': return '\\';
1968     default: return '\0';
1969     }
1970 }
1971 
cscannerHelp_processFloat()1972 double cscannerHelp_processFloat ()
1973 {
1974   double ret = atof (yytext);
1975 
1976     return (ret);
1977 }
1978 
cscannerHelp_processHex()1979 long cscannerHelp_processHex ()
1980 {
1981   int index = 2;
1982   long val = 0;
1983 
1984   llassert (yytext[0] == '0'
1985 	    && (yytext[1] == 'X' || yytext[1] == 'x'));
1986 
1987   while (yytext[index] != '\0') {
1988     int tval;
1989     char c = yytext[index];
1990 
1991     if (c >= '0' && c <= '9') {
1992       tval = (int) c - (int) '0';
1993     } else if (c >= 'A' && c <= 'F') {
1994       tval = (int) c - (int) 'A' + 10;
1995     } else if (c >= 'a' && c <= 'f') {
1996       tval = (int) c - (int) 'a' + 10;
1997     } else if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
1998       index++;
1999       while (yytext[index] != '\0') {
2000 	if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2001 	  ;
2002 	} else {
2003 	  voptgenerror
2004 	    (FLG_SYNTAX,
2005 	     message ("Invalid character (%c) following specifier in hex constant: %s",
2006 		      c, cstring_fromChars (yytext)),
2007 	     g_currentloc);
2008 	}
2009 	index++;
2010       }
2011 
2012       break;
2013     } else {
2014       voptgenerror
2015 	(FLG_SYNTAX,
2016 	 message ("Invalid character (%c) in hex constant: %s",
2017 		  c, cstring_fromChars (yytext)),
2018 	 g_currentloc);
2019       break;
2020     }
2021 
2022     val = (val * 16) + tval;
2023     index++;
2024   }
2025 
2026   DPRINTF (("Hex constant: %s = %ld", yytext, val));
2027   return val;
2028 }
2029 
cscannerHelp_processOctal()2030 long cscannerHelp_processOctal ()
2031 {
2032   int index = 1;
2033   long val = 0;
2034 
2035   llassert (yytext[0] == '0' && yytext[1] != 'X' && yytext[1] != 'x');
2036 
2037   while (yytext[index] != '\0') {
2038     int tval;
2039     char c = yytext[index];
2040 
2041     if (c >= '0' && c <= '7') {
2042       tval = (int) c - (int) '0';
2043     } else if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2044       index++;
2045       while (yytext[index] != '\0') {
2046 	if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2047 	  ;
2048 	} else {
2049 	  voptgenerror
2050 	    (FLG_SYNTAX,
2051 	     message ("Invalid character (%c) following specifier in octal constant: %s",
2052 		      c, cstring_fromChars (yytext)),
2053 	     g_currentloc);
2054 	}
2055 	index++;
2056       }
2057 
2058       break;
2059     } else {
2060       voptgenerror
2061 	(FLG_SYNTAX,
2062 	 message ("Invalid character (%c) in octal constant: %s",
2063 		  c, cstring_fromChars (yytext)),
2064 	 g_currentloc);
2065       break;
2066     }
2067 
2068     val = (val * 8) + tval;
2069     index++;
2070   }
2071 
2072   DPRINTF (("Octal constant: %s = %ld", yytext, val));
2073   return val;
2074 }
2075 
cscannerHelp_processDec()2076 long cscannerHelp_processDec ()
2077 {
2078   return (atol (yytext));
2079 }
2080 
cscannerHelp_processSpec(int tok)2081 int cscannerHelp_processSpec (int tok)
2082 {
2083   size_t length = strlen (yytext);
2084 
2085   if (s_inSpecPart)
2086     {
2087 
2088       /*drl 12/11/2002
2089 	patched to fix assert failures in constraint code.
2090 	Added the else if test so that splint does not treat MaxSet and MaxRead
2091 	as identifies*/
2092 
2093       if (s_whichSpecPart == QMODIFIES
2094 	  || s_whichSpecPart == QDEFINES
2095 	  || s_whichSpecPart == QUSES
2096 	  || s_whichSpecPart == QALLOCATES
2097 	  || s_whichSpecPart == QSETS
2098 	  || s_whichSpecPart == QRELEASES)
2099 
2100 	{
2101 	  DPRINTF((message("Treating specifaction keyword %s as an identifiers.  (This corresponds to"
2102 			   " token %d and we're in the  specification denoted by %d see cgrammar_tokens.h"
2103 			   " for an explanation of these numbers",
2104 			   yytext, tok, s_whichSpecPart)
2105 		   ));
2106 
2107 	  ; /* Allow specificiation keywords to be used as identifiers in these contexts. */
2108 	}
2109       else if ( (s_whichSpecPart == QPRECLAUSE
2110 		 || s_whichSpecPart == QPOSTCLAUSE
2111 		 || s_whichSpecPart == QINVARIANT )
2112 		&&  (!cscannerHelp_isConstraintToken(tok) )
2113 	      )
2114 	{
2115 	  DPRINTF((message("Treating specifaction keyword %s as an identifiers.  (This corresponds to"
2116 			   " token %d and we're in the  specification denoted by %d see cgrammar_tokens.h"
2117 			   " for an explanation of these numbers",
2118 			   yytext, tok, s_whichSpecPart)
2119 		   ));
2120 
2121 	  /* Allow specificiation keywords to be used as identifiers in these contexts. */
2122 	}
2123       else
2124 	{
2125 	  cscannerHelp_setTokLengthT (length);
2126 	  return cscannerHelp_returnToken (tok);
2127 	}
2128     }
2129 
2130   context_saveLocation ();
2131   cscannerHelp_setTokLengthT (length);
2132   return (cscannerHelp_processIdentifier (cscannerHelp_makeIdentifier (yytext)));
2133 }
2134 
cscannerHelp_expectingMetaStateName()2135 void cscannerHelp_expectingMetaStateName ()
2136 {
2137   llassert (!s_expectingMetaStateName);
2138   llassert (context_inFunctionHeader ());
2139   s_expectingMetaStateName = TRUE;
2140 }
2141 
cscannerHelp_clearExpectingMetaStateName()2142 void cscannerHelp_clearExpectingMetaStateName ()
2143 {
2144   llassert (s_expectingMetaStateName);
2145   s_expectingMetaStateName = FALSE;
2146 }
2147 
cscannerHelp_isConstraintToken(int tok)2148 bool cscannerHelp_isConstraintToken (int tok)
2149    /* drl added 12/11/2002
2150       Tell whether a token has special meaning
2151       within a function constraint
2152    */
2153 {
2154   return (tok == QMAXSET || tok == QMAXREAD);
2155           /* || tok == QMINREAD || tok == QMINSET */
2156   /* uncomment the additional if statement tests when minSet and minRead are supported */
2157 }
2158 
cscannerHelp_processMacro(void)2159 bool cscannerHelp_processMacro (void)
2160 {
2161   uentry e2;
2162   ctype ct;
2163   int noparams = 0;
2164   cstring fname = cstring_undefined;
2165   bool res = TRUE;
2166   bool isspecfcn = FALSE;
2167   bool isiter = FALSE;
2168   bool skipparam = FALSE;
2169   bool isenditer = FALSE;
2170   bool unknownm = FALSE;
2171   bool hasParams = FALSE;
2172   bool emptyMacro = FALSE;
2173   char c = skip_whitespace ();
2174   fileloc loc = fileloc_noColumn (g_currentloc);
2175 
2176   /* are both of these necessary?  what do they mean? */
2177   uentryList specparams = uentryList_undefined;
2178   uentryList pn = uentryList_undefined;
2179 
2180   context_resetMacroMissingParams ();
2181 
2182   if (c == '\0' || c == '\n')
2183     {
2184       llcontbug (cstring_makeLiteral ("Bad macro"));
2185       fileloc_free (loc);
2186       return FALSE;
2187     }
2188 
2189   fname = cstring_appendChar (fname, c);
2190 
2191   while ((c = macro_nextChar ()) != '(' && c != '\0'
2192 	 && c != ' ' && c != '\t' && c != '\n')
2193     {
2194       fname = cstring_appendChar (fname, c);
2195     }
2196 
2197   if (c == ' ' || c == '\t' || c == '\n')
2198     {
2199       char oldc = c;
2200 
2201       if (c != '\n')
2202 	{
2203 	  while (c == ' ' || c == '\t')
2204 	    {
2205 	      c = macro_nextChar ();
2206 	    }
2207 	  cscanner_unput ((int) c);
2208 	}
2209 
2210       if (c == '\n')
2211 	{
2212 	  emptyMacro = TRUE;
2213 	  cscanner_unput ((int) c);
2214 	}
2215 
2216       c = oldc;
2217     }
2218 
2219   hasParams = (c == '(');
2220 
2221   if (usymtab_exists (fname))
2222     {
2223       e2 = usymtab_lookupExpose (fname);
2224       ct = uentry_getType (e2);
2225 
2226       if (uentry_isCodeDefined (e2)
2227 	  && fileloc_isUser (uentry_whereDefined (e2)))
2228 	{
2229 	  if (optgenerror
2230 	      (FLG_MACROREDEF,
2231 	       message ("Macro %s already defined", fname),
2232 	       loc))
2233 	    {
2234 	      uentry_showWhereDefined (e2);
2235 	      uentry_clearDefined (e2);
2236 	    }
2237 
2238 	  if (uentry_isFunction (e2))
2239 	    {
2240 	      uentry_setType (e2, ctype_unknown);
2241 	      ct = ctype_unknown;
2242 	      unknownm = TRUE;
2243 	      context_enterUnknownMacro (e2);
2244 	    }
2245 	  else
2246 	    {
2247 	      context_enterConstantMacro (e2);
2248 	    }
2249 	}
2250       else
2251 	{
2252 	  if (uentry_isForward (e2) && uentry_isFunction (e2))
2253 	    {
2254 	      unknownm = TRUE;
2255 
2256 	      voptgenerror
2257 		(FLG_MACROFCNDECL,
2258 		 message
2259 		 ("Parameterized macro has no prototype or specification: %s ",
2260 		  fname),
2261 		 loc);
2262 
2263 	      ct = ctype_unknown;
2264 	      uentry_setType (e2, ctype_unknown);
2265 	      uentry_setFunctionDefined (e2, loc);
2266 	      uentry_setUsed (e2, fileloc_undefined);
2267 	      context_enterUnknownMacro (e2);
2268 	    }
2269 	  else
2270 	    {
2271 	      if (uentry_isIter (e2))
2272 		{
2273 		  isiter = TRUE;
2274 		  specparams = uentry_getParams (e2);
2275 		  noparams = uentryList_size (specparams);
2276 		  uentry_setDefined (e2, loc);
2277 		  context_enterIterDef (e2);
2278 		}
2279 	      else if (uentry_isEndIter (e2))
2280 		{
2281 		  isenditer = TRUE;
2282 		  uentry_setDefined (e2, loc);
2283 		  context_enterIterEnd (e2); /* don't care about it now */
2284 		  /* but should parse like an iter! */
2285 		}
2286 	      else if (uentry_isConstant (e2))
2287 		{
2288 		  if (hasParams)
2289 		    {
2290 		      voptgenerror
2291 			(FLG_INCONDEFS,
2292 			 message ("Constant %s implemented as parameterized macro",
2293 				  fname),
2294 			 g_currentloc);
2295 
2296 		      uentry_showWhereSpecified (e2);
2297 		      uentry_setType (e2, ctype_unknown);
2298 		      uentry_makeConstantFunction (e2);
2299 		      uentry_setDefined (e2, g_currentloc);
2300 		      uentry_setFunctionDefined (e2, g_currentloc);
2301 		      context_enterUnknownMacro (e2);
2302 		    }
2303 		  else
2304 		    {
2305 		      if (!uentry_isSpecified (e2))
2306 			{
2307 			  fileloc oloc = uentry_whereDeclared (e2);
2308 
2309 			  if (fileloc_isLib (oloc))
2310 			    {
2311 			      ;
2312 			    }
2313 			  else if (fileloc_isUndefined (oloc)
2314 				   || fileloc_isPreproc (oloc))
2315 			    {
2316 			      if (!emptyMacro)
2317 				{
2318 				  voptgenerror
2319 				    (FLG_MACROCONSTDECL,
2320 				     message
2321 				     ("Macro constant %q not declared",
2322 				      uentry_getName (e2)),
2323 				     loc);
2324 				}
2325 			    }
2326 			  else if (!fileloc_withinLines (oloc, loc, 2))
2327 			    { /* bogus!  will give errors if there is too much whitespace */
2328 			      voptgenerror
2329 				(FLG_MACROCONSTDIST,
2330 				 message
2331 				 ("Macro constant name %s matches name in "
2332 				  "distant constant declaration.  This constant "
2333 				  "is declared at %q", fname,
2334 				  fileloc_unparse (oloc)),
2335 				 loc);
2336 			    }
2337 			  else
2338 			    {
2339 			      /* No warning */
2340 			    }
2341 			}
2342 
2343 		      context_enterConstantMacro (e2);
2344 		      cstring_free (fname);
2345 		      fileloc_free (loc);
2346 		      return res;
2347 		    }
2348 
2349 		}
2350 	      else if (ctype_isFunction (ct))
2351 		{
2352 		  isspecfcn = TRUE;
2353 		  specparams = ctype_argsFunction (ct);
2354 		  noparams = uentryList_size (specparams);
2355 
2356 		  uentry_setFunctionDefined (e2, loc);
2357 		  context_enterMacro (e2);
2358 		}
2359 	      else if (uentry_isVar (e2))
2360 		{
2361 		  if (hasParams)
2362 		    {
2363 		      voptgenerror
2364 			(FLG_INCONDEFS,
2365 			 message ("Variable %s implemented as parameterized macro",
2366 				  fname),
2367 			 loc);
2368 
2369 		      uentry_showWhereSpecified (e2);
2370 		      uentry_setType (e2, ctype_unknown);
2371 		      uentry_makeVarFunction (e2);
2372 		      uentry_setDefined (e2, g_currentloc);
2373 		      uentry_setFunctionDefined (e2, g_currentloc);
2374 		      context_enterUnknownMacro (e2);
2375 		    }
2376 		  else
2377 		    {
2378 		      uentry ucons = uentry_makeConstant (fname,
2379 							  ctype_unknown,
2380 							  loc);
2381 		      if (uentry_isExpandedMacro (e2))
2382 			{
2383 			  ; /* okay */
2384 			}
2385 		      else
2386 			{
2387 			  if (optgenerror
2388 			      (FLG_INCONDEFS,
2389 			       message ("Variable %s implemented by a macro",
2390 					fname),
2391 			       loc))
2392 			    {
2393 			      uentry_showWhereSpecified (e2);
2394 			    }
2395 			}
2396 
2397 		      uentry_setDefined (e2, loc);
2398 		      uentry_setUsed (ucons, loc);
2399 
2400 		      context_enterConstantMacro (ucons);
2401 		      uentry_markOwned (ucons);
2402 		      cstring_free (fname);
2403 		      return res;
2404 		    }
2405 		}
2406 	      else
2407 		{
2408 		  if (uentry_isDatatype (e2))
2409 		    {
2410 		      vgenhinterror
2411 			(FLG_SYNTAX,
2412 			 message ("Type implemented as macro: %x",
2413 				  uentry_getName (e2)),
2414 			 message ("A type is implemented using a macro definition.  A "
2415 				  "typedef should be used instead."),
2416 			 g_currentloc);
2417 
2418 		      cscannerHelp_swallowMacro ();
2419 		      /* Must exit scope (not sure why a new scope was entered?) */
2420 		      usymtab_quietExitScope (g_currentloc);
2421 		      uentry_setDefined (e2, g_currentloc);
2422 		      res = FALSE;
2423 		    }
2424 		  else
2425 		    {
2426 		      llcontbug
2427 			(message ("Unexpanded macro not function or constant: %q",
2428 				  uentry_unparse (e2)));
2429 		      uentry_setType (e2, ctype_unknown);
2430 
2431 		      if (hasParams)
2432 			{
2433 			  uentry_makeVarFunction (e2);
2434 			  uentry_setDefined (e2, g_currentloc);
2435 			  uentry_setFunctionDefined (e2, g_currentloc);
2436 			  context_enterUnknownMacro (e2);
2437 			}
2438 		    }
2439 		}
2440 	    }
2441 	}
2442     }
2443   else
2444     {
2445       uentry ce;
2446 
2447       /* evans 2001-09-09 - if it has params, assume a function */
2448       if (hasParams)
2449 	{
2450 	  voptgenerror
2451 	    (FLG_MACROMATCHNAME,
2452 	     message ("Unexpanded macro %s does not match name of a declared "
2453 		      "function. The name used in the control "
2454 		      "comment on the previous line should match.",
2455 		      fname),
2456 	     loc);
2457 
2458 	  ce = uentry_makeFunction (fname, ctype_unknown,
2459 				    typeId_invalid,
2460 				    globSet_undefined,
2461 				    sRefSet_undefined,
2462 				    warnClause_undefined,
2463 				    fileloc_undefined);
2464 	  uentry_setUsed (ce, loc); /* perhaps bogus? */
2465 	  e2 = usymtab_supEntryReturn (ce);
2466 	  context_enterUnknownMacro (e2);
2467 	}
2468       else
2469 	{
2470 	  voptgenerror
2471 	    (FLG_MACROMATCHNAME,
2472 	     message ("Unexpanded macro %s does not match name of a constant "
2473 		      "or iter declaration.  The name used in the control "
2474 		      "comment on the previous line should match.  "
2475 		      "(Assuming macro defines a constant.)",
2476 		      fname),
2477 	     loc);
2478 
2479 	  ce = uentry_makeConstant (fname, ctype_unknown, fileloc_undefined);
2480 	  uentry_setUsed (ce, loc); /* perhaps bogus? */
2481 	  e2 = usymtab_supEntryReturn (ce);
2482 
2483 	  context_enterConstantMacro (e2);
2484 	  cstring_free (fname);
2485 	  fileloc_free (loc);
2486 	  return res;
2487 	}
2488     }
2489 
2490   /* in macros, ( must follow immediatetly after name */
2491 
2492   if (hasParams)
2493     {
2494       int paramno = 0;
2495 
2496       c = skip_whitespace ();
2497 
2498       while (c != ')' && c != '\0')
2499 	{
2500 	  uentry  param;
2501 	  bool    suppress = context_inSuppressRegion ();
2502 	  cstring paramname = cstring_undefined;
2503 
2504 	  /*
2505 	  ** save the parameter location
2506 	  */
2507 
2508 	  decColumn ();
2509 	  context_saveLocation ();
2510 	  incColumn ();
2511 
2512 	  while (c != ' ' && c != '\t' && c != ',' && c != '\0' && c != ')')
2513 	    {
2514 	      paramname = cstring_appendChar (paramname, c);
2515 	      c = macro_nextChar ();
2516 	    }
2517 
2518 	  if (c == ' ' || c == '\t') c = skip_whitespace ();
2519 
2520 	  if (c == ',')
2521 	    {
2522 	      c = macro_nextChar ();
2523 	      if (c == ' ' || c == '\t') c = skip_whitespace ();
2524 	    }
2525 
2526 	  if (c == '\0')
2527 	    {
2528 	      llfatalerror (cstring_makeLiteral
2529 			    ("Bad macro syntax: uentryList"));
2530 	    }
2531 
2532 	  if ((isspecfcn || isiter) && (paramno < noparams)
2533 	      && !uentry_isElipsisMarker (uentryList_getN
2534 					  (specparams, paramno)))
2535 	    {
2536 	      fileloc sloc = context_getSaveLocation ();
2537 	      uentry decl = uentryList_getN (specparams, paramno);
2538 	      sRef sr;
2539 
2540 	      param = uentry_nameCopy (paramname, decl);
2541 
2542 	      uentry_setParam (param);
2543 	      sr = sRef_makeParam (paramno, uentry_getType (param),
2544 				   stateInfo_makeLoc (sloc, SA_DECLARED));
2545 
2546 	      if (sRef_getNullState (sr) == NS_ABSNULL)
2547 		{
2548 		  ctype pt = ctype_realType (uentry_getType (param));
2549 
2550 		  if (ctype_isUser (pt))
2551 		    {
2552 		      uentry te = usymtab_getTypeEntrySafe (ctype_typeId (pt));
2553 
2554 		      if (uentry_isValid (te))
2555 			{
2556 			  sRef_setStateFromUentry (sr, te);
2557 			}
2558 		    }
2559 		  else
2560 		    {
2561 		      sRef_setNullState (sr, NS_UNKNOWN, sloc);
2562 		    }
2563 		}
2564 
2565 	      uentry_setSref (param, sr);
2566 	      uentry_setDeclaredForceOnly (param, sloc);
2567 
2568 	      skipparam = isiter && uentry_isOut (uentryList_getN (specparams, paramno));
2569 	    }
2570 	  else
2571 	    {
2572 	      fileloc sloc = context_getSaveLocation ();
2573 
2574 	      param = uentry_makeVariableSrefParam
2575 		(paramname, ctype_unknown, fileloc_copy (sloc),
2576 		 sRef_makeParam (paramno, ctype_unknown,
2577 				 stateInfo_makeLoc (sloc, SA_DECLARED)));
2578 	      DPRINTF (("Unknown param: %s", uentry_unparseFull (param)));
2579 	      cstring_free (paramname);
2580 
2581 	      sRef_setPosNull  (uentry_getSref (param), sloc);
2582 	      uentry_setDeclaredForce (param, sloc);
2583 
2584 	      skipparam = FALSE;
2585 	      fileloc_free (sloc);
2586 	    }
2587 
2588 	  if (!skipparam)
2589 	    {
2590 	      llassert (!uentry_isElipsisMarker (param));
2591 
2592 	      if (!suppress)
2593 		{
2594 		  sRef_makeUnsafe (uentry_getSref (param));
2595 		}
2596 
2597 	      pn = uentryList_add (pn, uentry_copy (param));
2598 	      usymtab_supEntry (param);
2599 	    }
2600 	  else
2601 	    {
2602 	      /* don't add param */
2603 	      uentry_free (param);
2604 	    }
2605 
2606 	  if (c == ',')
2607 	    {
2608 	      (void) macro_nextChar ();
2609 	      c = skip_whitespace ();
2610 	    }
2611 
2612 	  paramno++;
2613 	}
2614 
2615       if (c == ')')
2616 	{
2617 	  if (isspecfcn || isiter)
2618 	    {
2619 	      if (paramno != noparams && noparams >= 0)
2620 		{
2621 		  cscannerHelp_advanceLine ();
2622 
2623 		  voptgenerror
2624 		    (FLG_INCONDEFS,
2625 		     message ("Macro %s specified with %d args, defined with %d",
2626 			      fname, noparams, paramno),
2627 		     g_currentloc);
2628 
2629 		  uentry_showWhereSpecified (e2);
2630 		  uentry_resetParams (e2, pn);
2631 		}
2632 	    }
2633 	  else
2634 	    {
2635 	      uentry_resetParams (e2, pn);
2636 	    }
2637 	}
2638     }
2639   else
2640     {
2641       /*
2642       ** the form should be:
2643       **
2644       ** # define newname oldname
2645       ** where oldname refers to a function matching the specification
2646       ** of newname.
2647       */
2648 
2649       if (unknownm)
2650 	{
2651 	  sRef_setGlobalScope ();
2652 	  usymtab_supGlobalEntry (uentry_makeVariableLoc (fname, ctype_unknown));
2653 	  sRef_clearGlobalScope ();
2654 	}
2655       else
2656 	{
2657 	  context_setMacroMissingParams ();
2658 	}
2659     }
2660 
2661 
2662   /* context_setuentryList (pn); */
2663   usymtab_enterScope ();
2664 
2665   fileloc_free (loc);
2666   cstring_free (fname);
2667 
2668   return res;
2669 }
2670 
cscannerHelp_setTokLength(int len)2671 void cscannerHelp_setTokLength (int len)
2672 {
2673   addColumn (len);
2674   s_tokLength = len;
2675   DPRINTF (("Set tok length: %d", len));
2676 }
2677 
cscannerHelp_setTokLengthT(size_t len)2678 void cscannerHelp_setTokLengthT (size_t len)
2679 {
2680   cscannerHelp_setTokLength (size_toInt (len));
2681 }
2682 
cscannerHelp_advanceLine(void)2683 void cscannerHelp_advanceLine (void)
2684 {
2685   s_tokLength = 0;
2686   beginLine ();
2687 }
2688 
cscannerHelp_returnToken(int t)2689 int cscannerHelp_returnToken (int t)
2690 {
2691   if (s_tokLength > fileloc_column (g_currentloc)) {
2692     yylval.tok = lltok_create (t, fileloc_copy (g_currentloc));
2693   } else {
2694     yylval.tok = lltok_create (t, fileloc_decColumn (g_currentloc, s_tokLength));
2695   }
2696 
2697   s_tokLength = 0;
2698   s_lastWasString = FALSE;
2699   return (t);
2700 }
2701 
cscannerHelp_returnTokenLength(int t,int length)2702 int cscannerHelp_returnTokenLength (int t, int length)
2703 {
2704   cscannerHelp_setTokLength (length);
2705   return cscannerHelp_returnToken (t);
2706 }
2707 
cscannerHelp_returnString(cstring s)2708 int cscannerHelp_returnString (cstring s)
2709 {
2710   yylval.expr = exprNode_stringLiteral (s, fileloc_decColumn (g_currentloc, s_tokLength));
2711   s_tokLength = 0;
2712   s_lastWasString = TRUE;
2713   return (CCONSTANT);
2714 }
2715 
cscannerHelp_returnInt(ctype ct,long val)2716 int cscannerHelp_returnInt (ctype ct, long val)
2717 {
2718   ctype c = ct;
2719 
2720   if (ctype_equal (ct, ctype_int))
2721     {
2722       if (val == 0)
2723 	{
2724 	  c = context_typeofZero ();
2725 	}
2726       else if (val == 1)
2727 	{
2728 	  c = context_typeofOne ();
2729 	}
2730       else
2731 	{
2732 	  ;
2733 	}
2734     }
2735 
2736   yylval.expr = exprNode_numLiteral (c, cstring_fromChars (yytext),
2737 				     fileloc_decColumn (g_currentloc, s_tokLength),
2738 				     val);
2739   s_tokLength = 0;
2740   s_lastWasString = FALSE;
2741   return (CCONSTANT);
2742 }
2743 
cscannerHelp_returnFloat(ctype ct,double f)2744 int cscannerHelp_returnFloat (ctype ct, double f)
2745 {
2746   yylval.expr = exprNode_floatLiteral (f, ct, cstring_fromChars (yytext),
2747 				       fileloc_decColumn (g_currentloc, s_tokLength));
2748   s_tokLength = 0;
2749   s_lastWasString = FALSE;
2750   return (CCONSTANT);
2751 }
2752 
cscannerHelp_returnChar(char c)2753 int cscannerHelp_returnChar (char c)
2754 {
2755   yylval.expr = exprNode_charLiteral (c, cstring_fromChars (yytext),
2756 				      fileloc_decColumn (g_currentloc, s_tokLength));
2757   s_tokLength = 0;
2758   s_lastWasString = FALSE;
2759   return (CCONSTANT);
2760 }
2761 
cscannerHelp_returnType(int tok,ctype ct)2762 int cscannerHelp_returnType (int tok, ctype ct)
2763 {
2764   yylval.ctyp = ct;
2765   s_tokLength = 0;
2766   s_lastWasString = FALSE;
2767   return tok;
2768 }
2769 
cscannerHelp_returnExpr(exprNode e)2770 int cscannerHelp_returnExpr (exprNode e)
2771 {
2772   yylval.expr = e;
2773   s_tokLength = 0;
2774   s_lastWasString = TRUE;
2775   return (CCONSTANT);
2776 }
2777 
cscannerHelp_setExpectingTypeName()2778 void cscannerHelp_setExpectingTypeName ()
2779 {
2780   s_expectingTypeName = TRUE;
2781 }
2782 
cscannerHelp_clearExpectingTypeName()2783 void cscannerHelp_clearExpectingTypeName ()
2784 {
2785   s_expectingTypeName = FALSE;
2786 }
2787 
cscannerHelp_isExpectingTypeName()2788 bool cscannerHelp_isExpectingTypeName ()
2789 {
2790   return s_expectingTypeName;
2791 }
2792 
cscannerHelp_processTextIdentifier(char * text)2793 int cscannerHelp_processTextIdentifier (char *text)
2794 {
2795   context_saveLocation ();
2796   cscannerHelp_setTokLength (size_toInt (mstring_length (text)));
2797   return cscannerHelp_processIdentifier (cscannerHelp_makeIdentifier (text));
2798 }
2799 
2800 static bool s_continueLine = FALSE;
2801 
cscannerHelp_handleNewLine()2802 int cscannerHelp_handleNewLine ()
2803 {
2804   context_incLineno ();
2805 
2806   if (s_tokLength != 0) {
2807     s_tokLength = 0;
2808     /* No error to report
2809        voptgenerror
2810        (FLG_SYNTAX,
2811        message ("Likely parse error: token spans multiple lines."),
2812        g_currentloc);
2813     */
2814   }
2815 
2816   if (s_continueLine)
2817     {
2818       s_continueLine = FALSE;
2819     }
2820   else
2821     {
2822       if (context_inMacro ())
2823 	{
2824 	  /* Don't use return cscannerHelp_returnToken */
2825 	  /* !!! evans 2002-03-13 */
2826 	  yylval.tok = lltok_create (TENDMACRO, fileloc_copy (g_currentloc));
2827 	  s_lastWasString = FALSE;
2828 	  return TENDMACRO;
2829 	}
2830     }
2831 
2832   return BADTOK;
2833 }
2834 
cscannerHelp_setContinueLine()2835 void cscannerHelp_setContinueLine ()
2836 {
2837   s_continueLine = TRUE;
2838 }
2839 
cscannerHelp_exitSpecPart()2840 void cscannerHelp_exitSpecPart ()
2841 {
2842   llassert (s_inSpecPart);
2843   s_inSpecPart = FALSE;
2844   s_whichSpecPart = BADTOK;
2845 }
2846