]> andersk Git - splint.git/blob - src/cscannerHelp.c
Fixed problem with assertion checking for negative shifts in
[splint.git] / src / cscannerHelp.c
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
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
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
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
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
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
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
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
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
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
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
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
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   
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
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
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
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
1516 /*@observer@*/ cstring cscannerHelp_observeLastIdentifier ()
1517 {
1518   cstring res = s_lastidprocessed;
1519   return res;
1520 }
1521
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
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
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
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
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
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
1972 double cscannerHelp_processFloat ()
1973 {
1974   double ret = atof (yytext);
1975
1976     return (ret);
1977 }
1978
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
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
2076 long cscannerHelp_processDec ()
2077 {
2078   return (atol (yytext));
2079 }
2080
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
2135 void cscannerHelp_expectingMetaStateName ()
2136 {
2137   llassert (!s_expectingMetaStateName);
2138   llassert (context_inFunctionHeader ());
2139   s_expectingMetaStateName = TRUE;
2140 }
2141
2142 void cscannerHelp_clearExpectingMetaStateName ()
2143 {
2144   llassert (s_expectingMetaStateName);
2145   s_expectingMetaStateName = FALSE;
2146 }
2147
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
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_SYNTAX,
2330                                  message 
2331                                  ("Macro constant name %s does not match name in "
2332                                   "previous 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
2671 void cscannerHelp_setTokLength (int len) 
2672 {
2673   addColumn (len);
2674   s_tokLength = len;
2675   DPRINTF (("Set tok length: %d", len));
2676 }
2677
2678 void cscannerHelp_setTokLengthT (size_t len)
2679 {
2680   cscannerHelp_setTokLength (size_toInt (len));
2681 }
2682
2683 void cscannerHelp_advanceLine (void)
2684 {
2685   s_tokLength = 0;
2686   beginLine ();
2687 }
2688
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
2702 int cscannerHelp_returnTokenLength (int t, int length)
2703 {
2704   cscannerHelp_setTokLength (length);
2705   return cscannerHelp_returnToken (t);
2706 }
2707
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
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
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
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
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
2770 int cscannerHelp_returnExpr (exprNode e)
2771 {
2772   yylval.expr = e; 
2773   s_tokLength = 0; 
2774   s_lastWasString = TRUE; 
2775   return (CCONSTANT); 
2776 }
2777
2778 void cscannerHelp_setExpectingTypeName ()
2779 {
2780   s_expectingTypeName = TRUE;
2781 }
2782
2783 void cscannerHelp_clearExpectingTypeName ()
2784 {
2785   s_expectingTypeName = FALSE;
2786 }
2787
2788 bool cscannerHelp_isExpectingTypeName ()
2789 {
2790   return s_expectingTypeName;
2791 }
2792
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
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
2835 void cscannerHelp_setContinueLine ()
2836 {
2837   s_continueLine = TRUE;
2838 }
2839
2840 void cscannerHelp_exitSpecPart ()
2841 {
2842   llassert (s_inSpecPart);
2843   s_inSpecPart = FALSE;
2844   s_whichSpecPart = BADTOK;
2845 }
This page took 0.287654 seconds and 5 git commands to generate.