]> andersk Git - splint.git/blob - src/cscannerHelp.c
1aee6d64c1e59e1c7481e993f55e1884bc97885f
[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   else if (cstring_equalPrefixLit (olc, "ident"))
729     {
730       /* Some pre-processors will leave these in the code.  Ignore rest of line */
731     }
732   /*
733   ** Yuk...Win32 filenames can have spaces in them...we need to read
734   ** to the matching end quote.
735   */
736   else if ((sscanf (ol, "line %d \"", &lineno) == 1)
737            || (sscanf (ol, " %d \"", &lineno) == 1))
738     {
739       char *tmp = ol;
740       cstring fname;
741       fileId fid;
742
743       /*@access cstring@*/
744       while (*tmp != '\"' && *tmp != '\0')
745         {
746           tmp++;
747         }
748
749       llassert (*tmp == '\"');
750       tmp++;
751       fname = tmp;
752       
753       while (*tmp != '\"' && *tmp != '\0')
754         {
755           tmp++;
756         }
757
758       llassert (*tmp == '\"');
759       *tmp = '\0';
760
761 # if defined(OS2) || defined(MSDOS) || defined(WIN32)
762
763       /*
764       ** DOS-like path delimiters get delivered in pairs, something like 
765       ** \"..\\\\file.h\", so we have to make it normal again. We do NOT
766       ** remove the pre dirs yet as we usually specify tmp paths relative
767       ** to the current directory, so tmp files would not get found in
768       ** the hash table.  If this method fails we try it again later. 
769       */
770
771       {
772         char *stmp = fname;
773         
774         /*
775         ** Skip past the drive marker.
776         */
777         
778         if (strchr (stmp, ':') != NULL)
779           {
780             stmp = strchr (stmp, ':') + 1;
781           }
782         
783         while ((stmp = strchr (stmp, CONNECTCHAR)) != NULL )
784           {
785             if (*(stmp+1) == CONNECTCHAR)
786               {
787                 memmove (stmp, stmp+1, strlen (stmp));
788               }
789             
790             stmp++;
791           }
792         
793         fid = fileTable_lookupBase (context_fileTable (), fname);
794         if (!(fileId_isValid (fid)))
795           {
796             fname = removePreDirs (fname);
797             fid = fileTable_lookupBase (context_fileTable (), fname);
798           }
799       }
800 # else  /* !defined(OS2) && !defined(MSDOS) */
801       fname = removePreDirs (fname);
802       fid = fileTable_lookupBase (context_fileTable (), fname);      
803 # endif /* !defined(OS2) && !defined(MSDOS) */
804       
805       if (!(fileId_isValid (fid)))
806         {
807           if (context_inXHFile ())
808             {
809               fid = fileTable_addXHFile (context_fileTable (), fname);
810             }
811           else if (isHeaderFile (fname))
812             {
813               fid = fileTable_addHeaderFile (context_fileTable (), fname);
814             }
815           else
816             {
817               fid = fileTable_addFile (context_fileTable (), fname);
818             }
819         }
820       
821       setFileLine (fid, lineno);
822       /*@noaccess cstring@*/
823     }
824   else if ((sscanf (ol, "line %d", &lineno) == 1) 
825            || (sscanf (ol, " %d", &lineno) == 1))
826     {
827       setLine (lineno); /* next line is <cr> */
828     }
829   else
830     {
831       if (mstring_equal (ol, "")) {
832         DPRINTF (("Empty pp command!"));
833         /*
834         ** evs 2000-05-16: This is a horrible kludge, to get around a bug (well, difficulty) in the pre-processor.
835         ** We handle a plain # in the input file, by echoing it, and ignoring it in the post-pp-file.
836         */
837         mstring_free (ol);
838         return FALSE;
839       } else {
840         voptgenerror
841           (FLG_UNRECOGDIRECTIVE,
842            message ("Unrecognized pre-processor directive: #%s", 
843                     cstring_fromChars (ol)),
844            g_currentloc);
845       }
846       
847       sfree (ol);
848       return FALSE; /* evans 2001-12-30: was: TRUE; */
849     }
850
851   sfree (ol);
852   return FALSE;
853 }
854   
855 int cscannerHelp_handleLlSpecial (void)
856
857   bool hasnl = FALSE;
858   int ic; 
859   char c;
860   char *s = mstring_createEmpty ();
861   char *os; 
862   int tok;
863   int charsread = 0;
864   fileloc loc;
865
866   loc = fileloc_copy (g_currentloc);
867   DPRINTF (("Handle special: %s", fileloc_unparse (loc)));
868
869   while (((ic = cscannerHelp_ninput ()) != 0) && isalpha (ic))
870     {
871       c = (char) ic;
872       s = mstring_append (s, c);
873       charsread++;
874     }
875
876   DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));
877   os = s;
878
879   if (charsread == 0 && ic == (int) AFTER_COMMENT_MARKER[0])
880     {
881       ic = cscannerHelp_ninput ();
882
883       llassert (ic == (int) AFTER_COMMENT_MARKER[1]);
884             
885       if (*s == '\0')
886         {
887           sfree (os);
888           fileloc_free (loc);
889           return QNOMODS; /* special token no modifications token */
890         }
891     }
892   
893   DPRINTF (("Coment marker: %s", os));
894   tok = commentMarkerToken (cstring_fromChars (os));
895
896   if (tok != BADTOK)
897     {
898       s_tokLength = charsread;
899       sfree (os);
900       s_inSpecPart = TRUE;
901       s_whichSpecPart = tok;
902       fileloc_free (loc);
903       return tok;
904     }
905
906   DPRINTF (("Not a comment marker..."));
907   /* Add rest of the comment */
908   
909   if (ic != 0 && ic != EOF)
910     {
911       c = (char) ic;
912       
913       s = mstring_append (s, c);
914       charsread++;
915
916       while (((ic = cscannerHelp_ninput ()) != 0) && (ic != EOF)
917              && (ic != (int) AFTER_COMMENT_MARKER[0]))
918         {
919           c = (char) ic;
920
921           /* evans 2001-09-01 added to prevent assertion failures for uncloses syntactic comments */
922
923           if (c == '\n') {
924             hasnl = TRUE; /* This prevents tokLength from being set later. */
925             s_tokLength = 0; 
926
927             voptgenerror
928               (FLG_SYNTAX, 
929                message ("Likely parse error: syntactic comment token spans multiple lines: %s",
930                         cstring_fromChars (s)),
931                loc);
932           }
933
934           s = mstring_append (s, c);
935           charsread++;
936         }
937       /*@-branchstate@*/ 
938     } /* spurious (?) warnings about s */
939   /*@=branchstate@*/ 
940
941   DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));
942
943   if (ic == (int) AFTER_COMMENT_MARKER[0]) 
944     {
945       int nc = cscannerHelp_ninput ();
946       llassert ((char) nc ==  AFTER_COMMENT_MARKER[1]);
947       charsread++;
948     }
949
950   os = s;
951
952   while (*s == ' ' || *s == '\t' || *s == '\n') 
953     {
954       s++;
955     }
956
957   if (*s == '-' || *s == '+' || *s == '=') /* setting flags */
958     {
959       c = *s;
960
961       while (c == '-' || c == '+' || c == '=')
962         {
963           ynm set = ynm_fromCodeChar (c);
964           cstring thisflag;
965
966           s++;
967           
968           thisflag = cstring_fromChars (s);
969           
970           while ((c = *s) != '\0' && (c != '-') && (c != '=')
971                  && (c != '+') && (c != ' ') && (c != '\t') && (c != '\n'))
972             {
973               s++;
974             }
975
976           *s = '\0';
977
978           if (!context_getFlag (FLG_NOCOMMENTS))
979             {
980               cstring flagname = thisflag;
981               flagcode fflag = flags_identifyFlag (flagname);
982               
983               if (flagcode_isSkip (fflag))
984                 {
985                   ;
986                 }
987               else if (flagcode_isModeName (fflag))
988                 {
989                   if (ynm_isMaybe (set))
990                     {
991                       llerror
992                         (FLG_BADFLAG, 
993                          message 
994                          ("Semantic comment attempts to restore flag %s.  "
995                           "A mode flag cannot be restored.",
996                           flagname));
997                     }
998                   else
999                     {
1000                       context_setMode (flagname);
1001                     }
1002                 }
1003               else if (flagcode_isInvalid (fflag))
1004                 {
1005                   voptgenerror
1006                     (FLG_UNRECOGFLAGCOMMENTS,
1007                      message ("Unrecognized option in semantic comment: %s", 
1008                               flagname),
1009                      loc);
1010                 }
1011               else if (flagcode_isGlobalFlag (fflag))
1012                 {
1013                   voptgenerror
1014                     (FLG_BADFLAG, 
1015                      message 
1016                      ("Semantic comment attempts to set global flag %s.  "
1017                       "A global flag cannot be set locally.",
1018                       flagname),
1019                      loc);
1020                 }
1021               else
1022                 {
1023                   context_fileSetFlag (fflag, set, loc);
1024                   
1025                   if (flagcode_hasArgument (fflag))
1026                     {
1027                       if (ynm_isMaybe (set))
1028                         {
1029                           voptgenerror
1030                             (FLG_BADFLAG, 
1031                              message 
1032                              ("Semantic comment attempts to restore flag %s.  "
1033                               "A flag for setting a value cannot be restored.",
1034                               flagname),
1035                              loc);
1036                         }
1037                       else
1038                         { /* cut-and-pastied from llmain...blecch */
1039                           cstring extra = cstring_undefined;
1040                           char *rest;
1041                           char *orest;
1042                           char rchar;
1043                           
1044                           *s = c;
1045                           rest = mstring_copy (s);
1046                           orest = rest;
1047                           *s = '\0';
1048                           
1049                           while ((rchar = *rest) != '\0'
1050                                  && (isspace (rchar)))
1051                             {
1052                               rest++;
1053                               s++;
1054                             }
1055                           
1056                           while ((rchar = *rest) != '\0'
1057                                  && !isspace (rchar))
1058                             {
1059                               extra = cstring_appendChar (extra, rchar);
1060                               rest++; 
1061                               s++;
1062                             }
1063                           s--; /* evans 2002-07-12: this was previously only in the else branch.
1064                                   Leads to an invalid read on the true branch.
1065                                */
1066
1067                           sfree (orest);
1068                           
1069                           if (cstring_isUndefined (extra))
1070                             {
1071                               llerror 
1072                                 (FLG_BADFLAG,
1073                                  message
1074                                  ("Flag %s (in semantic comment) must be followed by an argument",
1075                                   flagcode_unparse (fflag)));
1076
1077                               cstring_free (extra);
1078                             }
1079                           else
1080                             {
1081                               if (flagcode_hasNumber (fflag))
1082                                 {
1083                                   flags_setValueFlag (fflag, extra);
1084                                 }
1085                               else if (flagcode_hasChar (fflag))
1086                                 {
1087                                   flags_setValueFlag (fflag, extra);
1088                                 }
1089                               else if (flagcode_hasString (fflag))
1090                                 {
1091                                   flags_setStringFlag (fflag, extra);
1092                                 }
1093                               else
1094                                 {
1095                                   cstring_free (extra);
1096                                   BADEXIT;
1097                                 }
1098                             }
1099                         }
1100                     }
1101                 }
1102             }
1103           else
1104             {
1105               ;
1106             }
1107
1108           *s = c;
1109           while ((c == ' ') || (c == '\t') || (c == '\n'))
1110             {
1111               c = *(++s);
1112             }
1113         } 
1114
1115       if (context_inHeader () && !isArtificial (cstring_fromChars (os)))
1116         {
1117           DPRINTF (("Here adding comment: %s", os));
1118           context_addComment (cstring_fromCharsNew (os), loc);
1119         }
1120       else
1121         {
1122           ;
1123         }
1124     }
1125   else
1126     {
1127       char *t = s;
1128       int macrocode;
1129       char tchar = '\0';
1130       annotationInfo ainfo;
1131
1132       while (*s != '\0' && *s != ' ' && *s != '\t' && *s != '\n') 
1133         {
1134           s++;
1135         }
1136
1137       if (*s != '\0') 
1138         {
1139           tchar = *s;
1140           *s = '\0';
1141           s++;
1142         }
1143       
1144       t = cstring_toCharsSafe (cstring_downcase (cstring_fromChars (t)));
1145       macrocode = tokenMacroCode (cstring_fromChars (t));
1146
1147       if (macrocode != BADTOK)
1148         {
1149           s_tokLength = hasnl ? 0 : size_toInt (mstring_length (t));
1150           
1151           sfree (t);
1152           sfree (os);
1153           fileloc_free (loc);
1154
1155           if (macrocode == SKIPTOK)
1156             {
1157               return BADTOK;
1158             }
1159
1160           return macrocode;
1161         }
1162       
1163       ainfo = context_lookupAnnotation (cstring_fromChars (os));
1164       
1165       if (annotationInfo_isDefined (ainfo)) {
1166         DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo)));
1167         yylval.annotation = ainfo;
1168         s_tokLength = 0;
1169         sfree (os);
1170         sfree (t);
1171         fileloc_free (loc);
1172         return CANNOTATION;
1173       } 
1174
1175       if (context_inHeader ())
1176         {
1177           if (tchar != '\0')
1178             {
1179               *(s-1) = tchar;
1180             }
1181           
1182           if ((context_inMacro () || context_inGlobalContext ())
1183               && macrocode != SKIPTOK
1184               && !isArtificial (cstring_fromChars (os))) 
1185             {
1186               if (context_processingMacros ())
1187                 {
1188                   /* evans 2002-02-24: don't add comments when procssing macros */
1189                 }
1190               else
1191                 {
1192                   context_addComment (cstring_fromCharsNew (os), loc);
1193                 }
1194             }
1195           else
1196             {
1197               ; 
1198             }
1199           
1200           if (tchar != '\0')
1201             {
1202               *(s-1) = '\0';
1203             }
1204         }
1205
1206       if (mstring_equal (t, "ignore"))
1207         {
1208           if (!context_getFlag (FLG_NOCOMMENTS))
1209             {
1210               context_enterSuppressRegion (loc);
1211             }
1212         }
1213       else if ((*t == 'i' || *t == 't')
1214                && (*(t + 1) == '\0'))
1215         {
1216           if (!context_getFlag (FLG_NOCOMMENTS)
1217               && (*t == 'i' || context_getFlag (FLG_TMPCOMMENTS)))
1218             {
1219               context_enterSuppressLine (-1, loc); /* infinite suppression */
1220             }
1221         }
1222       else if (((*t == 'i') || (*t == 't'))
1223                && ((*(t + 1) >= '0' && *(t + 1) <= '9')))
1224         {
1225           bool tmpcomment = (*t == 't');
1226           int val = -1; 
1227           char *tt = t; /* don't mangle t, since it is free'd */
1228           char lc = *(++tt);
1229
1230           if (lc >= '0' && lc <= '9')
1231             {
1232               val = (int)(lc - '0');
1233               
1234               lc = *(++tt);       
1235               while (lc >= '0' && lc <= '9')
1236                 {
1237                   val *= 10;
1238                   val += (int) (lc - '0');
1239                   lc = *(++tt);
1240                 }
1241             }
1242           
1243           if (!context_getFlag (FLG_NOCOMMENTS)
1244               && (!tmpcomment || context_getFlag (FLG_TMPCOMMENTS)))
1245             {
1246               DPRINTF (("Here: enter suppress: %s", fileloc_unparse (loc)));
1247               context_enterSuppressLine (val, loc);
1248             }
1249         }
1250       else if (mstring_equal (t, "end"))
1251         {
1252           if (!context_getFlag (FLG_NOCOMMENTS))
1253             {
1254               context_exitSuppressRegion (loc);
1255             }
1256         }
1257       else if (mstring_equal (t, "notfunction"))
1258         {
1259          ; /* handled by pcpp */
1260         }
1261       else if (mstring_equal (t, "access"))
1262         {
1263           cstring tname;
1264           
1265           while (TRUE)
1266             {
1267               while (((c = *s) != '\0') && (c == ' ' || c == '\t' || c == '\n'))
1268                 {
1269                   s++;
1270                 }
1271               
1272               if (c == '\0')
1273                 {
1274                    break;
1275                 }
1276
1277               tname = cstring_fromChars (s);
1278               
1279               while ((c = *s) != '\0' && c != ' ' 
1280                      && c != '\t' && c != '\n' && c != ',') 
1281                 {
1282                   s++;
1283                 }
1284
1285               *s = '\0';
1286
1287               DPRINTF (("Access %s", tname));
1288
1289               if (!context_getFlag (FLG_NOCOMMENTS) 
1290                   && !context_getFlag (FLG_NOACCESS))
1291                 {
1292                   if (usymtab_existsType (tname))
1293                     {
1294                       typeId uid = usymtab_getTypeId (tname);
1295                       uentry ue = usymtab_getTypeEntry (uid);
1296
1297                       if (uentry_isAbstractDatatype (ue))
1298                         {
1299                           context_addFileAccessType (uid);
1300                           DPRINTF (("Adding access to: %s / %d", tname, uid));
1301                         }
1302                       else
1303                         {
1304                           voptgenerror
1305                             (FLG_COMMENTERROR,
1306                              message
1307                              ("Non-abstract type %s used in access comment",
1308                               tname),
1309                              loc);
1310                         }
1311                     }
1312                   else
1313                     {
1314                       if (!(context_inSuppressRegion ()
1315                             || context_inSuppressZone (loc)))
1316                         {
1317                           voptgenerror
1318                             (FLG_COMMENTERROR,
1319                              message
1320                              ("Unrecognized type %s used in access comment",
1321                               tname),
1322                              loc);
1323                         }
1324                     }
1325                 }
1326               
1327               if (c != '\0') 
1328                 {
1329                   s++;
1330                 }
1331               
1332               if (c != ',' && c != ' ')
1333                 {
1334                   break;
1335                 }
1336             }
1337         }
1338       else if (mstring_equal (t, "noaccess"))
1339         {
1340           cstring tname;
1341           char lc;
1342           
1343           while (TRUE)
1344             {
1345               while (((lc = *s) != '\0') && (lc == ' ' || lc == '\t' || lc == '\n')) 
1346                 {
1347                   s++;
1348                 }
1349               
1350               if (lc == '\0')
1351                 {
1352                  break;
1353                 }
1354
1355               tname = cstring_fromChars (s);
1356               
1357               while ((lc = *s) != '\0' && lc != ' ' && lc != '\t' 
1358                      && lc != '\n' && lc != ',') 
1359                 {
1360                   s++;
1361                 }
1362
1363               *s = '\0';
1364
1365               if (!context_getFlag (FLG_NOCOMMENTS) 
1366                   && !context_getFlag (FLG_NOACCESS))
1367                 {
1368                   if (usymtab_existsType (tname))
1369                     {
1370                       typeId tuid = usymtab_getTypeId (tname);
1371                       
1372                       if (context_couldHaveAccess (tuid))
1373                         {
1374                           DPRINTF (("Removing access: %s", tname));
1375                           context_removeFileAccessType (tuid);
1376                         }
1377                       else
1378                         {
1379                           if (!(context_inSuppressRegion () 
1380                                 || context_inSuppressZone (loc)))
1381                             {
1382                               uentry ue = usymtab_getTypeEntry (tuid);
1383                               
1384                               if (uentry_isAbstractDatatype (ue))
1385                                 {
1386                                   voptgenerror
1387                                     (FLG_COMMENTERROR,
1388                                      message
1389                                      ("Non-accessible abstract type %s used in noaccess comment",
1390                                       tname),
1391                                      loc);
1392                                 }
1393                               else
1394                                 {
1395                                   voptgenerror
1396                                     (FLG_COMMENTERROR,
1397                                      message
1398                                      ("Non-abstract type %s used in noaccess comment",
1399                                       tname),
1400                                      loc);
1401                                 }
1402                             }
1403                         }
1404                     }
1405                   else
1406                     {
1407                       if (!(context_inSuppressRegion () 
1408                             || context_inSuppressZone (loc)))
1409                         {
1410                           voptgenerror
1411                             (FLG_COMMENTERROR,
1412                              message
1413                              ("Unrecognized type %s used in noaccess comment",
1414                               tname),
1415                              loc);
1416                         }
1417                     }
1418                 }
1419               
1420               if (lc != '\0') 
1421                 {
1422                   s++;
1423                 }
1424               
1425               if (lc != ',' && lc != ' ')
1426                 {
1427                   break;
1428                 }
1429             }
1430         }
1431       else
1432         {
1433           voptgenerror (FLG_UNRECOGCOMMENTS, 
1434                         message ("Semantic comment unrecognized: %s", 
1435                                  cstring_fromChars (os)),
1436                         loc);
1437           /*@-branchstate@*/
1438         } /* spurious (?) warning about t */
1439       /*@=branchstate@*/
1440       
1441       sfree (t);
1442     }
1443   
1444   sfree (os);
1445   fileloc_free (loc);
1446   return BADTOK;
1447 }
1448
1449 /*@only@*/ cstring cscannerHelp_makeIdentifier (char *s)
1450 {
1451   char *c = mstring_create (strlen (s) + 1);
1452   cstring id = cstring_fromChars (c);
1453
1454   while (isalnum (*s) || (*s == '_') || (*s == '$')) 
1455     {
1456       *c++ = *s++;
1457     }
1458
1459   *c = '\0';
1460   return (id);
1461 }
1462
1463 /*@observer@*/ /*@dependent@*/ uentry cscannerHelp_coerceId (cstring cn)
1464 {
1465   if (!(usymtab_exists (cn)))
1466     {
1467       fileloc loc = fileloc_createExternal ();
1468       
1469       /*
1470       ** We need to put this in a global scope, otherwise the sRef will be deallocated.
1471       */
1472       
1473       uentry ce = uentry_makeUnrecognized (cn, loc);
1474       
1475       if (!context_inIterEnd ())
1476         {
1477           voptgenerror 
1478             (FLG_SYSTEMUNRECOG, 
1479              message ("Unrecognized (possibly system) identifier: %q", 
1480                       uentry_getName (ce)), 
1481              g_currentloc);
1482         }
1483       
1484       return ce;
1485     }
1486   
1487   return (usymtab_lookup (cn));
1488 }
1489
1490 /*
1491 ** like, cscannerHelp_coerceId, but doesn't supercede for iters
1492 */
1493
1494 /*@observer@*/ uentry cscannerHelp_coerceIterId (cstring cn)
1495 {
1496   if (!(usymtab_exists (cn)))
1497     {
1498       return uentry_undefined;
1499     }
1500   
1501   return (usymtab_lookup (cn));
1502 }
1503
1504 /*
1505 ** Need to keep this in case there is a declaration that isn't processed until
1506 ** the scope exits.  Would be good to rearrange the symbol table so this doesn't
1507 ** happen, and save all the cstring copying.
1508 */
1509
1510 /*@observer@*/ cstring cscannerHelp_observeLastIdentifier ()
1511 {
1512   cstring res = s_lastidprocessed;
1513   return res;
1514 }
1515
1516 static void cscanner_setLastIdentifier (/*@keep@*/ cstring id) /*@modifies s_lastidprocessed@*/
1517 {
1518   if (cstring_isDefined (s_lastidprocessed))
1519     {
1520       cstring_free (s_lastidprocessed); 
1521     }
1522
1523   s_lastidprocessed = id;
1524 }
1525
1526 int cscannerHelp_processIdentifier (cstring id)
1527 {
1528   uentry le;
1529
1530   if (context_getFlag (FLG_GRAMMAR))
1531     {
1532       lldiagmsg (message ("Process identifier: %s", id));
1533     }
1534
1535   context_clearJustPopped ();
1536   cscanner_setLastIdentifier (id);
1537
1538   DPRINTF (("Context: %s", context_unparse ()));
1539
1540   if (context_inFunctionHeader ())
1541     {
1542       int tok = commentMarkerToken (id);
1543       DPRINTF (("in function decl: %s", id));
1544
1545       if (tok != BADTOK)
1546         {
1547           return tok;
1548         }
1549       else 
1550         {
1551           tok = tokenMacroCode (id);
1552           
1553           if (tok != BADTOK)
1554             {
1555               return tok;
1556             }
1557           else 
1558             {
1559               annotationInfo ainfo;
1560
1561               if (s_expectingMetaStateName) 
1562                 {
1563                   metaStateInfo msinfo = context_lookupMetaStateInfo (id);
1564
1565                   if (metaStateInfo_isDefined (msinfo))
1566                     {
1567                       yylval.msinfo = msinfo;
1568                       return METASTATE_NAME;
1569                     }
1570                   else
1571                     {
1572                       DPRINTF (("Not meta state name: %s", cstring_toCharsSafe (id)));
1573                     }
1574                 }
1575               
1576               ainfo = context_lookupAnnotation (id);
1577               
1578               if (annotationInfo_isDefined (ainfo)) 
1579                 {
1580                   DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo)));
1581                   yylval.annotation = ainfo;
1582                   return CANNOTATION;
1583                 }
1584               else
1585                 {
1586                   DPRINTF (("Not annotation: %s", id));
1587                 }
1588             }
1589         }
1590     }
1591
1592   DPRINTF (("Here!"));
1593
1594   /* Consider handling: Defined by C99 as static const char __func__[] */
1595
1596   if (context_getFlag (FLG_GNUEXTENSIONS))
1597     {
1598       int tok = BADTOK;
1599       
1600       if (cstring_equalLit (id, "__stdcall")
1601           || cstring_equalLit (id, "__cdecl")
1602           || cstring_equalLit (id, "__extension__"))
1603         {
1604           return BADTOK;
1605         }
1606       else if (cstring_equalLit (id, "__volatile__"))
1607         {
1608           tok = QVOLATILE;
1609         }
1610       else if (cstring_equalLit (id, "__signed"))
1611         {
1612           tok = QSIGNED;
1613         }
1614       else if (cstring_equalLit (id, "__unsigned"))
1615         {
1616           tok = QUNSIGNED;
1617         }
1618       else if (cstring_equalLit (id, "__const__"))
1619         {
1620           tok = QCONST;
1621         }
1622       else if (cstring_equalLit (id, "__alignof__")) 
1623         {
1624           tok = CALIGNOF; /* alignof is parsed like sizeof */
1625         }
1626       else if (cstring_equalLit (id, "__typeof__")) 
1627         {
1628           tok = CTYPEOF;
1629         }
1630       else if (cstring_equalLit (id, "typeof")) 
1631         {
1632           tok = CTYPEOF;
1633         }
1634       else if (cstring_equalLit (id, "__FUNCTION__")
1635                || cstring_equalLit (id, "__PRETTY_FUNCTION__")) 
1636         {
1637           /* These tokens hold the name of the current function as strings */
1638           /* evans 2001-12-30: changed from exprNode_stringLiteral; bug reported by Jim Zelenka. */
1639           yylval.expr = exprNode_makeConstantString (id, fileloc_copy (g_currentloc));
1640           s_tokLength = 0;
1641           s_lastWasString = TRUE;
1642           tok = CCONSTANT;
1643           return tok;
1644         }
1645       else if (cstring_equalLit (id, "__attribute__")
1646                || cstring_equalLit (id, "__asm__")
1647                || cstring_equalLit (id, "_asm")
1648                || cstring_equalLit (id, "__asm")
1649                || cstring_equalLit (id, "__declspec"))
1650         {
1651           int depth = 0;
1652           bool useparens = FALSE;
1653           bool usebraces = FALSE;
1654           bool inquote = FALSE;
1655           bool inescape = FALSE;
1656           int ic;
1657
1658           while ((ic = cscanner_input ()) != EOF)
1659             {
1660               char cc = (char) ic;
1661
1662               if (inescape)
1663                 {
1664                   inescape = FALSE;
1665                 }
1666               else if (cc == '\\')
1667                 {
1668                   inescape = TRUE;
1669                 }
1670               else if (cc == '\"')
1671                 {
1672                   inquote = !inquote;
1673                 }
1674               else if (!inquote)
1675                 {
1676                   if (cc == '(')
1677                     {
1678                       if (!useparens)
1679                         {
1680                           if (!usebraces)
1681                             {
1682                               useparens = TRUE;
1683                             }
1684                         }
1685
1686                       if (useparens)
1687                         {
1688                           depth++;
1689                         }
1690                     }
1691                   else if (cc == '{')
1692                     {
1693                       if (!usebraces)
1694                         {
1695                           if (!useparens)
1696                             {
1697                               usebraces = TRUE;
1698                             }
1699                         }
1700
1701                       if (usebraces)
1702                         {
1703                           depth++;
1704                         }
1705                     }
1706                   else if (cc == ')' && useparens)
1707                     {
1708                       depth--;
1709                       if (depth == 0) break;
1710                     }
1711                   else if (cc == '}' && usebraces)
1712                     {
1713                       depth--;
1714                       if (depth == 0) break;
1715                     }
1716                   else if (cc == '}' 
1717                            && !usebraces && !useparens
1718                            && cstring_equalLit (id, "__asm"))
1719                     {
1720                       /*
1721                       ** We need this because some MS VC++ include files
1722                       ** have __asm mov ... }
1723                       ** Its a kludge, but otherwise would need to parse
1724                       ** the asm code!
1725                       */ 
1726                       return TRBRACE;
1727                     }
1728                   else
1729                     {
1730                       ;
1731                     }
1732                 }
1733               else
1734                 {
1735                   ;
1736                 }
1737
1738               if (cc == '\n')
1739                 {
1740                   context_incLineno ();
1741
1742                   if (cstring_equalLit (id, "__asm")
1743                       && !useparens && !usebraces)
1744                     {
1745                       break;
1746                     }
1747                 }
1748             }
1749           
1750           llassert ((useparens && ic == (int) ')')
1751                     || (usebraces && ic == (int) '}')
1752                     || (!useparens && !usebraces));
1753
1754           return BADTOK;
1755         }
1756       else if (cstring_equalLit (id, "inline")
1757                || cstring_equalLit (id, "__inline")
1758                || cstring_equalLit (id, "_inline")
1759                || cstring_equalLit (id, "__inline__"))
1760         {
1761           tok = QINLINE;
1762         }
1763       else
1764         {
1765           ;
1766         }
1767       
1768       if (tok != BADTOK)
1769         {
1770           return (cscannerHelp_returnToken (tok));
1771         }
1772     }
1773
1774   le = usymtab_lookupSafe (id);
1775
1776   /*@-dependenttrans@*/
1777   
1778   if (uentry_isIter (le))
1779     {
1780       yylval.entry = le;
1781       return (ITER_NAME);
1782     }
1783   else if (uentry_isEndIter (le))
1784     {
1785       yylval.entry = le;
1786       return (ITER_ENDNAME);
1787     }
1788   else if (uentry_isUndefined (le))
1789     {
1790       yylval.cname = cstring_copy (id);
1791
1792       /* avoid parse errors for certain system built ins */
1793
1794       if (s_expectingTypeName && (cstring_firstChar (id) == '_')
1795           && (cstring_secondChar (id) == '_'))
1796         {
1797           return (TYPE_NAME_OR_ID);
1798         }
1799
1800       return (NEW_IDENTIFIER);
1801     }
1802   else if (!uentry_isDeclared (le) && !uentry_isCodeDefined (le))
1803     {
1804       if (uentry_isDatatype (le))
1805         {
1806           yylval.cname = cstring_copy (id);
1807           return (NEW_IDENTIFIER);
1808         }
1809       else
1810         {
1811           yylval.entry = le;              
1812           return (IDENTIFIER); 
1813         }
1814     }
1815   else if (uentry_isDatatype (le))
1816     {
1817       if (!s_expectingTypeName)
1818         {
1819           yylval.cname = cstring_copy (id);
1820
1821           return (NEW_IDENTIFIER);
1822         }
1823       else
1824         {
1825           yylval.ctyp = uentry_getAbstractType (le);
1826           
1827           uentry_setUsed (le, g_currentloc);
1828           return (TYPE_NAME);
1829         }
1830     }
1831   else
1832     {
1833       yylval.entry = le;            
1834       return (IDENTIFIER); 
1835     }
1836
1837   /*@=dependenttrans@*/
1838 }
1839
1840 bool cscannerHelp_processHashIdentifier (/*@only@*/ cstring id)
1841 {
1842   if (context_inMacro () || context_inIterDef () ||
1843       context_inIterEnd ())
1844     {
1845       uentry le;
1846       
1847       context_clearJustPopped ();
1848
1849       le = usymtab_lookupSafe (id);
1850       cscanner_setLastIdentifier (id);
1851
1852       if (uentry_isParam (le) || uentry_isRefParam (le))
1853         {
1854           return TRUE;
1855         }
1856       else
1857         {
1858           return FALSE;
1859         }
1860     }
1861   else
1862     {
1863       /*
1864       ** Will be handled by handleLlSpecial
1865       */
1866
1867       cstring_free (id);
1868       return FALSE;
1869     }
1870 }
1871
1872 /*@only@*/ exprNode cscannerHelp_processString (void)
1873 {
1874   exprNode res;
1875   fileloc loc;
1876   char *nl = strchr (yytext, '\n');
1877   cstring ns = cstring_fromCharsNew (yytext);
1878
1879   if (nl == NULL)
1880     {
1881       loc = fileloc_copy (g_currentloc);
1882       addColumn (size_toInt (cstring_length (ns)));
1883     }
1884   else
1885     {
1886       char *lastnl = nl;
1887
1888       loc = fileloc_copy (g_currentloc);
1889
1890       context_incLineno ();
1891       
1892       while ((nl = strchr ((nl + 1), '\n')) != NULL)
1893         {
1894           context_incLineno ();
1895           lastnl = nl;
1896         }
1897     }
1898
1899     
1900   res = exprNode_stringLiteral (ns, loc);
1901   return (res);
1902 }
1903
1904 /*
1905 ** process a wide character string L"...."
1906 */
1907
1908 /*@only@*/ exprNode cscannerHelp_processWideString ()
1909 {
1910   exprNode res;
1911   fileloc loc;
1912   char *nl = strchr (yytext, '\n');
1913   cstring ns;
1914
1915   llassert (*yytext == 'L');
1916   yytext++;
1917
1918   ns = cstring_fromCharsNew (yytext);
1919   
1920   if (nl == NULL)
1921     {
1922       loc = fileloc_copy (g_currentloc);
1923       addColumn (size_toInt (cstring_length (ns)));
1924     }
1925   else
1926     {
1927       char *lastnl = nl;
1928
1929       loc = fileloc_copy (g_currentloc);
1930
1931       context_incLineno ();
1932       
1933       while ((nl = strchr ((nl + 1), '\n')) != NULL)
1934         {
1935           context_incLineno ();
1936           lastnl = nl;
1937         }
1938     }
1939
1940   res = exprNode_wideStringLiteral (ns, loc);
1941   return (res);
1942 }
1943
1944 char cscannerHelp_processChar ()
1945 {
1946   char fchar;
1947   char next;
1948
1949   llassert (*yytext != '\0');
1950   fchar = *(yytext + 1);
1951   if (fchar != '\\') return fchar;
1952   
1953   next = *(yytext + 2);
1954   
1955   switch (next)
1956     {
1957     case 'n': return '\n';
1958     case 't': return '\t';
1959     case '\"': return '\"';
1960     case '\'': return '\'';
1961     case '\\': return '\\';
1962     default: return '\0';
1963     }
1964 }
1965
1966 double cscannerHelp_processFloat ()
1967 {
1968   double ret = atof (yytext);
1969
1970     return (ret);
1971 }
1972
1973 long cscannerHelp_processHex ()
1974 {
1975   int index = 2;
1976   long val = 0;
1977
1978   llassert (yytext[0] == '0'
1979             && (yytext[1] == 'X' || yytext[1] == 'x'));
1980
1981   while (yytext[index] != '\0') {
1982     int tval;
1983     char c = yytext[index];
1984
1985     if (c >= '0' && c <= '9') {
1986       tval = (int) c - (int) '0';
1987     } else if (c >= 'A' && c <= 'F') {
1988       tval = (int) c - (int) 'A' + 10;
1989     } else if (c >= 'a' && c <= 'f') {
1990       tval = (int) c - (int) 'a' + 10;
1991     } else if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
1992       index++;
1993       while (yytext[index] != '\0') {
1994         if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
1995           ;
1996         } else {
1997           voptgenerror
1998             (FLG_SYNTAX, 
1999              message ("Invalid character (%c) following specifier in hex constant: %s",
2000                       c, cstring_fromChars (yytext)),
2001              g_currentloc);
2002         }
2003         index++;
2004       }
2005
2006       break;
2007     } else {
2008       voptgenerror
2009         (FLG_SYNTAX, 
2010          message ("Invalid character (%c) in hex constant: %s",
2011                   c, cstring_fromChars (yytext)),
2012          g_currentloc);
2013       break;
2014     }
2015
2016     val = (val * 16) + tval;
2017     index++;
2018   }
2019
2020   DPRINTF (("Hex constant: %s = %ld", yytext, val));
2021   return val;
2022 }
2023
2024 long cscannerHelp_processOctal ()
2025 {
2026   int index = 1;
2027   long val = 0;
2028
2029   llassert (yytext[0] == '0' && yytext[1] != 'X' && yytext[1] != 'x');
2030     
2031   while (yytext[index] != '\0') {
2032     int tval;
2033     char c = yytext[index];
2034     
2035     if (c >= '0' && c <= '7') {
2036       tval = (int) c - (int) '0';
2037     } else if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2038       index++;
2039       while (yytext[index] != '\0') {
2040         if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
2041           ;
2042         } else {
2043           voptgenerror
2044             (FLG_SYNTAX, 
2045              message ("Invalid character (%c) following specifier in octal constant: %s",
2046                       c, cstring_fromChars (yytext)),
2047              g_currentloc);
2048         }
2049         index++;
2050       }
2051
2052       break;
2053     } else {
2054       voptgenerror
2055         (FLG_SYNTAX, 
2056          message ("Invalid character (%c) in octal constant: %s",
2057                   c, cstring_fromChars (yytext)),
2058          g_currentloc);
2059       break;
2060     }
2061
2062     val = (val * 8) + tval;
2063     index++;
2064   }
2065
2066   DPRINTF (("Octal constant: %s = %ld", yytext, val));
2067   return val;
2068 }
2069
2070 long cscannerHelp_processDec ()
2071 {
2072   return (atol (yytext));
2073 }
2074
2075 int cscannerHelp_processSpec (int tok)
2076 {
2077   size_t length = strlen (yytext);
2078   
2079   if (s_inSpecPart)
2080     {
2081
2082       /*drl 12/11/2002
2083         patched to fix assert failures in constraint code.
2084         Added the else if test so that splint does not treat MaxSet and MaxRead
2085         as identifies*/
2086         
2087       if (s_whichSpecPart == QMODIFIES
2088           || s_whichSpecPart == QDEFINES
2089           || s_whichSpecPart == QUSES 
2090           || s_whichSpecPart == QALLOCATES
2091           || s_whichSpecPart == QSETS
2092           || s_whichSpecPart == QRELEASES)
2093         
2094         {
2095           DPRINTF((message("Treating specifaction keyword %s as an identifiers.  (This corresponds to"
2096                            " token %d and we're in the  specification denoted by %d see cgrammar_tokens.h"
2097                            " for an explanation of these numbers",
2098                            yytext, tok, s_whichSpecPart)
2099                    ));
2100                            
2101           ; /* Allow specificiation keywords to be used as identifiers in these contexts. */
2102         }
2103       else if ( (s_whichSpecPart == QPRECLAUSE
2104                  || s_whichSpecPart == QPOSTCLAUSE
2105                  || s_whichSpecPart == QINVARIANT )
2106                 &&  (!cscannerHelp_isConstraintToken(tok) )
2107               )
2108         {
2109           DPRINTF((message("Treating specifaction keyword %s as an identifiers.  (This corresponds to"
2110                            " token %d and we're in the  specification denoted by %d see cgrammar_tokens.h"
2111                            " for an explanation of these numbers",
2112                            yytext, tok, s_whichSpecPart)
2113                    ));
2114           
2115           /* Allow specificiation keywords to be used as identifiers in these contexts. */
2116         }
2117       else
2118         {
2119           cscannerHelp_setTokLengthT (length);
2120           return cscannerHelp_returnToken (tok);
2121         }
2122     }
2123   
2124   context_saveLocation ();
2125   cscannerHelp_setTokLengthT (length);
2126   return (cscannerHelp_processIdentifier (cscannerHelp_makeIdentifier (yytext)));
2127 }
2128
2129 void cscannerHelp_expectingMetaStateName ()
2130 {
2131   llassert (!s_expectingMetaStateName);
2132   llassert (context_inFunctionHeader ());
2133   s_expectingMetaStateName = TRUE;
2134 }
2135
2136 void cscannerHelp_clearExpectingMetaStateName ()
2137 {
2138   llassert (s_expectingMetaStateName);
2139   s_expectingMetaStateName = FALSE;
2140 }
2141
2142 bool cscannerHelp_isConstraintToken (int tok)
2143    /* drl added 12/11/2002
2144       Tell whether a token has special meaning
2145       within a function constraint
2146    */
2147 {
2148   return (tok == QMAXSET || tok == QMAXREAD);
2149           /* || tok == QMINREAD || tok == QMINSET */
2150   /* uncomment the additional if statement tests when minSet and minRead are supported */
2151 }
2152
2153 bool cscannerHelp_processMacro (void)
2154 {
2155   uentry e2;
2156   ctype ct;
2157   int noparams = 0;
2158   cstring fname = cstring_undefined;
2159   bool res = TRUE;
2160   bool isspecfcn = FALSE;
2161   bool isiter = FALSE;
2162   bool skipparam = FALSE;
2163   bool isenditer = FALSE;
2164   bool unknownm = FALSE;
2165   bool hasParams = FALSE;
2166   bool emptyMacro = FALSE;
2167   char c = skip_whitespace ();
2168   fileloc loc = fileloc_noColumn (g_currentloc);
2169
2170   /* are both of these necessary?  what do they mean? */
2171   uentryList specparams = uentryList_undefined;
2172   uentryList pn = uentryList_undefined;
2173
2174   context_resetMacroMissingParams ();
2175
2176   if (c == '\0' || c == '\n')
2177     {
2178       llcontbug (cstring_makeLiteral ("Bad macro"));
2179       fileloc_free (loc);
2180       return FALSE;
2181     }
2182   
2183   fname = cstring_appendChar (fname, c);  
2184
2185   while ((c = macro_nextChar ()) != '(' && c != '\0'
2186          && c != ' ' && c != '\t' && c != '\n')
2187     {
2188       fname = cstring_appendChar (fname, c);
2189     }
2190
2191   if (c == ' ' || c == '\t' || c == '\n')
2192     {
2193       char oldc = c;
2194
2195       if (c != '\n')
2196         {
2197           while (c == ' ' || c == '\t')
2198             {
2199               c = macro_nextChar ();
2200             }
2201           cscanner_unput ((int) c);
2202         }
2203
2204       if (c == '\n')
2205         {
2206           emptyMacro = TRUE;
2207           cscanner_unput ((int) c);
2208         }
2209
2210       c = oldc;
2211     }
2212
2213   hasParams = (c == '(');
2214   
2215   if (usymtab_exists (fname))
2216     {
2217       e2 = usymtab_lookupExpose (fname);
2218       ct = uentry_getType (e2);
2219
2220       if (uentry_isCodeDefined (e2) 
2221           && fileloc_isUser (uentry_whereDefined (e2)))
2222         {
2223           if (optgenerror 
2224               (FLG_MACROREDEF,
2225                message ("Macro %s already defined", fname),
2226                loc))
2227             {
2228               uentry_showWhereDefined (e2);
2229               uentry_clearDefined (e2);
2230             }
2231
2232           if (uentry_isFunction (e2))
2233             {
2234               uentry_setType (e2, ctype_unknown);
2235               ct = ctype_unknown;
2236               unknownm = TRUE;
2237               context_enterUnknownMacro (e2); 
2238             }
2239           else
2240             {
2241               context_enterConstantMacro (e2);
2242             }
2243         }
2244       else
2245         {
2246           if (uentry_isForward (e2) && uentry_isFunction (e2))
2247             {
2248               unknownm = TRUE;
2249
2250               voptgenerror 
2251                 (FLG_MACROFCNDECL,
2252                  message
2253                  ("Parameterized macro has no prototype or specification: %s ", 
2254                   fname),
2255                  loc);
2256               
2257               ct = ctype_unknown;
2258               uentry_setType (e2, ctype_unknown);
2259               uentry_setFunctionDefined (e2, loc); 
2260               uentry_setUsed (e2, fileloc_undefined);
2261               context_enterUnknownMacro (e2); 
2262             }
2263           else
2264             {
2265               if (uentry_isIter (e2))
2266                 {
2267                   isiter = TRUE;
2268                   specparams = uentry_getParams (e2);
2269                   noparams = uentryList_size (specparams);
2270                   uentry_setDefined (e2, loc);
2271                   context_enterIterDef (e2); 
2272                 }
2273               else if (uentry_isEndIter (e2))
2274                 {
2275                   isenditer = TRUE;
2276                   uentry_setDefined (e2, loc);
2277                   context_enterIterEnd (e2); /* don't care about it now */
2278                   /* but should parse like an iter! */
2279                 }
2280               else if (uentry_isConstant (e2))
2281                 {
2282                   if (hasParams)
2283                     {
2284                       voptgenerror 
2285                         (FLG_INCONDEFS, 
2286                          message ("Constant %s implemented as parameterized macro",
2287                                   fname),
2288                          g_currentloc);
2289                       
2290                       uentry_showWhereSpecified (e2);
2291                       uentry_setType (e2, ctype_unknown);
2292                       uentry_makeConstantFunction (e2);
2293                       uentry_setDefined (e2, g_currentloc);
2294                       uentry_setFunctionDefined (e2, g_currentloc);
2295                       context_enterUnknownMacro (e2); 
2296                     }
2297                   else
2298                     {
2299                       if (!uentry_isSpecified (e2))
2300                         {
2301                           fileloc oloc = uentry_whereDeclared (e2);
2302
2303                           if (fileloc_isLib (oloc))
2304                             {
2305                               ;
2306                             }
2307                           else if (fileloc_isUndefined (oloc)
2308                                    || fileloc_isPreproc (oloc))
2309                             {
2310                               if (!emptyMacro)
2311                                 {
2312                                   voptgenerror
2313                                     (FLG_MACROCONSTDECL,
2314                                      message 
2315                                      ("Macro constant %q not declared",
2316                                       uentry_getName (e2)),
2317                                      loc);                       
2318                                 }
2319                             }
2320                           else if (!fileloc_withinLines (oloc, loc, 2))
2321                             { /* bogus!  will give errors if there is too much whitespace */
2322                               voptgenerror
2323                                 (FLG_SYNTAX,
2324                                  message 
2325                                  ("Macro constant name %s does not match name in "
2326                                   "previous constant declaration.  This constant "
2327                                   "is declared at %q", fname, 
2328                                   fileloc_unparse (oloc)),
2329                                  loc);
2330                             }
2331                           else
2332                             {
2333                               /* No warning */
2334                             }
2335                         }
2336
2337                       context_enterConstantMacro (e2);        
2338                       cstring_free (fname);
2339                       fileloc_free (loc);
2340                       return res;
2341                     }
2342
2343                 }
2344               else if (ctype_isFunction (ct))
2345                 {
2346                   isspecfcn = TRUE;
2347                   specparams = ctype_argsFunction (ct);
2348                   noparams = uentryList_size (specparams);
2349                   
2350                   uentry_setFunctionDefined (e2, loc); 
2351                   context_enterMacro (e2);
2352                 }
2353               else if (uentry_isVar (e2))
2354                 {
2355                   if (hasParams)
2356                     {
2357                       voptgenerror
2358                         (FLG_INCONDEFS,
2359                          message ("Variable %s implemented as parameterized macro", 
2360                                   fname),
2361                          loc);
2362
2363                       uentry_showWhereSpecified (e2);
2364                       uentry_setType (e2, ctype_unknown);
2365                       uentry_makeVarFunction (e2);
2366                       uentry_setDefined (e2, g_currentloc);
2367                       uentry_setFunctionDefined (e2, g_currentloc);
2368                       context_enterUnknownMacro (e2); 
2369                     }
2370                   else
2371                     {
2372                       uentry ucons = uentry_makeConstant (fname,
2373                                                           ctype_unknown,
2374                                                           loc);
2375                       if (uentry_isExpandedMacro (e2))
2376                         {
2377                           ; /* okay */
2378                         }
2379                       else
2380                         {
2381                           if (optgenerror 
2382                               (FLG_INCONDEFS,
2383                                message ("Variable %s implemented by a macro",
2384                                         fname),
2385                                loc))
2386                             {
2387                               uentry_showWhereSpecified (e2);
2388                             }
2389                         }
2390
2391                       uentry_setDefined (e2, loc);
2392                       uentry_setUsed (ucons, loc);
2393
2394                       context_enterConstantMacro (ucons);
2395                       uentry_markOwned (ucons);
2396                       cstring_free (fname);
2397                       return res;
2398                     }
2399                 }
2400               else
2401                 {
2402                   if (uentry_isDatatype (e2))
2403                     {
2404                       vgenhinterror 
2405                         (FLG_SYNTAX,
2406                          message ("Type implemented as macro: %x", 
2407                                   uentry_getName (e2)),
2408                          message ("A type is implemented using a macro definition.  A "
2409                                   "typedef should be used instead."),
2410                          g_currentloc);
2411
2412                       cscannerHelp_swallowMacro ();
2413                       /* Must exit scope (not sure why a new scope was entered?) */
2414                       usymtab_quietExitScope (g_currentloc);
2415                       uentry_setDefined (e2, g_currentloc);
2416                       res = FALSE;
2417                     }
2418                   else
2419                     {
2420                       llcontbug 
2421                         (message ("Unexpanded macro not function or constant: %q", 
2422                                   uentry_unparse (e2)));
2423                       uentry_setType (e2, ctype_unknown);
2424                       
2425                       if (hasParams)
2426                         {
2427                           uentry_makeVarFunction (e2);
2428                           uentry_setDefined (e2, g_currentloc);
2429                           uentry_setFunctionDefined (e2, g_currentloc);
2430                           context_enterUnknownMacro (e2); 
2431                         }
2432                     }
2433                 }
2434             }
2435         }
2436     }
2437   else
2438     {
2439       uentry ce;
2440
2441       /* evans 2001-09-09 - if it has params, assume a function */
2442       if (hasParams)
2443         {
2444           voptgenerror 
2445             (FLG_MACROMATCHNAME,
2446              message ("Unexpanded macro %s does not match name of a declared "
2447                       "function. The name used in the control "
2448                       "comment on the previous line should match.",
2449                       fname),
2450              loc);
2451           
2452           ce = uentry_makeFunction (fname, ctype_unknown, 
2453                                     typeId_invalid,
2454                                     globSet_undefined,
2455                                     sRefSet_undefined,
2456                                     warnClause_undefined,
2457                                     fileloc_undefined);      
2458           uentry_setUsed (ce, loc); /* perhaps bogus? */
2459           e2 = usymtab_supEntryReturn (ce);
2460           context_enterUnknownMacro (e2);             
2461         }
2462       else
2463         {
2464           voptgenerror 
2465             (FLG_MACROMATCHNAME,
2466              message ("Unexpanded macro %s does not match name of a constant "
2467                       "or iter declaration.  The name used in the control "
2468                       "comment on the previous line should match.  "
2469                       "(Assuming macro defines a constant.)", 
2470                       fname),
2471              loc);
2472           
2473           ce = uentry_makeConstant (fname, ctype_unknown, fileloc_undefined);      
2474           uentry_setUsed (ce, loc); /* perhaps bogus? */
2475           e2 = usymtab_supEntryReturn (ce);
2476           
2477           context_enterConstantMacro (e2);            
2478           cstring_free (fname);
2479           fileloc_free (loc);
2480           return res;
2481         }
2482     }
2483   
2484   /* in macros, ( must follow immediatetly after name */
2485   
2486   if (hasParams)
2487     {
2488       int paramno = 0;
2489       
2490       c = skip_whitespace ();
2491
2492       while (c != ')' && c != '\0')
2493         {
2494           uentry  param;
2495           bool    suppress = context_inSuppressRegion ();
2496           cstring paramname = cstring_undefined;
2497
2498           /*
2499           ** save the parameter location
2500           */
2501
2502           decColumn ();
2503           context_saveLocation ();
2504           incColumn ();
2505
2506           while (c != ' ' && c != '\t' && c != ',' && c != '\0' && c != ')')
2507             {
2508               paramname = cstring_appendChar (paramname, c);
2509               c = macro_nextChar ();
2510             }
2511           
2512           if (c == ' ' || c == '\t') c = skip_whitespace ();
2513
2514           if (c == ',')
2515             {
2516               c = macro_nextChar ();
2517               if (c == ' ' || c == '\t') c = skip_whitespace ();
2518             }
2519           
2520           if (c == '\0')
2521             {
2522               llfatalerror (cstring_makeLiteral
2523                             ("Bad macro syntax: uentryList"));
2524             }
2525           
2526           if ((isspecfcn || isiter) && (paramno < noparams)
2527               && !uentry_isElipsisMarker (uentryList_getN 
2528                                           (specparams, paramno)))
2529             {
2530               fileloc sloc = context_getSaveLocation ();
2531               uentry decl = uentryList_getN (specparams, paramno);
2532               sRef sr;
2533               
2534               param = uentry_nameCopy (paramname, decl);
2535                               
2536               uentry_setParam (param);
2537               sr = sRef_makeParam (paramno, uentry_getType (param), 
2538                                    stateInfo_makeLoc (sloc, SA_DECLARED));
2539
2540               if (sRef_getNullState (sr) == NS_ABSNULL)
2541                 {
2542                   ctype pt = ctype_realType (uentry_getType (param));
2543
2544                   if (ctype_isUser (pt))
2545                     {
2546                       uentry te = usymtab_getTypeEntrySafe (ctype_typeId (pt));
2547                       
2548                       if (uentry_isValid (te))
2549                         {
2550                           sRef_setStateFromUentry (sr, te);
2551                         }
2552                     }
2553                   else
2554                     {
2555                       sRef_setNullState (sr, NS_UNKNOWN, sloc);
2556                     }
2557                 }
2558
2559               uentry_setSref (param, sr);
2560               uentry_setDeclaredForceOnly (param, sloc);
2561
2562               skipparam = isiter && uentry_isOut (uentryList_getN (specparams, paramno));
2563             }
2564           else
2565             {
2566               fileloc sloc = context_getSaveLocation ();
2567
2568               param = uentry_makeVariableSrefParam 
2569                 (paramname, ctype_unknown, fileloc_copy (sloc), 
2570                  sRef_makeParam (paramno, ctype_unknown,
2571                                  stateInfo_makeLoc (sloc, SA_DECLARED)));
2572               DPRINTF (("Unknown param: %s", uentry_unparseFull (param)));
2573               cstring_free (paramname);
2574
2575               sRef_setPosNull  (uentry_getSref (param), sloc);
2576               uentry_setDeclaredForce (param, sloc);
2577
2578               skipparam = FALSE;
2579               fileloc_free (sloc);
2580             }
2581
2582           if (!skipparam)
2583             {
2584               llassert (!uentry_isElipsisMarker (param));
2585
2586               if (!suppress)
2587                 {
2588                   sRef_makeUnsafe (uentry_getSref (param));
2589                 }
2590               
2591               pn = uentryList_add (pn, uentry_copy (param));
2592               usymtab_supEntry (param);
2593             }
2594           else
2595             {
2596               /* don't add param */
2597               uentry_free (param);
2598             }
2599
2600           if (c == ',') 
2601             {
2602               (void) macro_nextChar ();
2603               c = skip_whitespace ();
2604             }
2605
2606           paramno++;
2607         }
2608       
2609       if (c == ')')
2610         {
2611           if (isspecfcn || isiter)
2612             {
2613               if (paramno != noparams && noparams >= 0)
2614                 {
2615                   cscannerHelp_advanceLine ();
2616
2617                   voptgenerror 
2618                     (FLG_INCONDEFS,
2619                      message ("Macro %s specified with %d args, defined with %d", 
2620                               fname, noparams, paramno),
2621                      g_currentloc);
2622
2623                   uentry_showWhereSpecified (e2);
2624                   uentry_resetParams (e2, pn);
2625                 }
2626             }
2627           else
2628             {
2629               uentry_resetParams (e2, pn);
2630             }
2631         }
2632     }
2633   else
2634     {
2635       /*
2636       ** the form should be:
2637       **
2638       ** # define newname oldname
2639       ** where oldname refers to a function matching the specification
2640       ** of newname.
2641       */
2642
2643       if (unknownm)
2644         {
2645           sRef_setGlobalScope ();
2646           usymtab_supGlobalEntry (uentry_makeVariableLoc (fname, ctype_unknown));
2647           sRef_clearGlobalScope ();
2648         }
2649       else
2650         {
2651           context_setMacroMissingParams ();
2652         }
2653     }
2654   
2655   
2656   /* context_setuentryList (pn); */
2657   usymtab_enterScope ();
2658
2659   fileloc_free (loc);
2660   cstring_free (fname);
2661
2662   return res;
2663 }
2664
2665 void cscannerHelp_setTokLength (int len) 
2666 {
2667   addColumn (len);
2668   s_tokLength = len;
2669   DPRINTF (("Set tok length: %d", len));
2670 }
2671
2672 void cscannerHelp_setTokLengthT (size_t len)
2673 {
2674   cscannerHelp_setTokLength (size_toInt (len));
2675 }
2676
2677 void cscannerHelp_advanceLine (void)
2678 {
2679   s_tokLength = 0;
2680   beginLine ();
2681 }
2682
2683 int cscannerHelp_returnToken (int t)
2684 {
2685   if (s_tokLength > fileloc_column (g_currentloc)) {
2686     yylval.tok = lltok_create (t, fileloc_copy (g_currentloc));
2687   } else {
2688     yylval.tok = lltok_create (t, fileloc_decColumn (g_currentloc, s_tokLength)); 
2689   }
2690
2691   s_tokLength = 0; 
2692   s_lastWasString = FALSE; 
2693   return (t); 
2694 }
2695
2696 int cscannerHelp_returnTokenLength (int t, int length)
2697 {
2698   cscannerHelp_setTokLength (length);
2699   return cscannerHelp_returnToken (t);
2700 }
2701
2702 int cscannerHelp_returnString (cstring s)
2703 {
2704   yylval.expr = exprNode_stringLiteral (s, fileloc_decColumn (g_currentloc, s_tokLength)); 
2705   s_tokLength = 0;
2706   s_lastWasString = TRUE; 
2707   return (CCONSTANT); 
2708 }
2709
2710 int cscannerHelp_returnInt (ctype ct, long val)
2711 {
2712   ctype c = ct;
2713
2714   if (ctype_equal (ct, ctype_int))
2715     {
2716       if (val == 0)
2717         {
2718           c = context_typeofZero ();
2719         }
2720       else if (val == 1)
2721         {
2722           c = context_typeofOne ();
2723         }
2724       else
2725         {
2726           ;
2727         }
2728     }
2729   
2730   yylval.expr = exprNode_numLiteral (c, cstring_fromChars (yytext), 
2731                                      fileloc_decColumn (g_currentloc, s_tokLength),
2732                                      val);   
2733   s_tokLength = 0; 
2734   s_lastWasString = FALSE;
2735   return (CCONSTANT);
2736 }
2737
2738 int cscannerHelp_returnFloat (ctype ct, double f)
2739 {
2740   yylval.expr = exprNode_floatLiteral (f, ct, cstring_fromChars (yytext), 
2741                                        fileloc_decColumn (g_currentloc, s_tokLength));
2742   s_tokLength = 0; 
2743   s_lastWasString = FALSE;
2744   return (CCONSTANT);
2745 }
2746
2747 int cscannerHelp_returnChar (char c)
2748 {
2749   yylval.expr = exprNode_charLiteral (c, cstring_fromChars (yytext), 
2750                                       fileloc_decColumn (g_currentloc, s_tokLength));
2751   s_tokLength = 0; 
2752   s_lastWasString = FALSE;
2753   return (CCONSTANT);
2754 }
2755
2756 int cscannerHelp_returnType (int tok, ctype ct) 
2757 {
2758   yylval.ctyp = ct; 
2759   s_tokLength = 0; 
2760   s_lastWasString = FALSE;
2761   return tok;
2762 }
2763
2764 int cscannerHelp_returnExpr (exprNode e)
2765 {
2766   yylval.expr = e; 
2767   s_tokLength = 0; 
2768   s_lastWasString = TRUE; 
2769   return (CCONSTANT); 
2770 }
2771
2772 void cscannerHelp_setExpectingTypeName ()
2773 {
2774   s_expectingTypeName = TRUE;
2775 }
2776
2777 void cscannerHelp_clearExpectingTypeName ()
2778 {
2779   s_expectingTypeName = FALSE;
2780 }
2781
2782 bool cscannerHelp_isExpectingTypeName ()
2783 {
2784   return s_expectingTypeName;
2785 }
2786
2787 int cscannerHelp_processTextIdentifier (char *text)
2788 {
2789   context_saveLocation (); 
2790   cscannerHelp_setTokLength (size_toInt (mstring_length (text))); 
2791   return cscannerHelp_processIdentifier (cscannerHelp_makeIdentifier (text)); 
2792 }
2793
2794 static bool s_continueLine = FALSE;
2795
2796 int cscannerHelp_handleNewLine ()
2797 {
2798   context_incLineno ();
2799
2800   if (s_tokLength != 0) { 
2801     s_tokLength = 0; 
2802     /* No error to report 
2803        voptgenerror
2804        (FLG_SYNTAX, 
2805        message ("Likely parse error: token spans multiple lines."),
2806        g_currentloc);
2807     */
2808   }
2809   
2810   if (s_continueLine)
2811     {
2812       s_continueLine = FALSE;
2813     }
2814   else 
2815     {
2816       if (context_inMacro ())
2817         {
2818           /* Don't use return cscannerHelp_returnToken */
2819           /* !!! evans 2002-03-13 */
2820           yylval.tok = lltok_create (TENDMACRO, fileloc_copy (g_currentloc)); 
2821           s_lastWasString = FALSE;
2822           return TENDMACRO;
2823         }  
2824     }
2825
2826   return BADTOK;
2827 }
2828
2829 void cscannerHelp_setContinueLine ()
2830 {
2831   s_continueLine = TRUE;
2832 }
2833
2834 void cscannerHelp_exitSpecPart ()
2835 {
2836   llassert (s_inSpecPart);
2837   s_inSpecPart = FALSE;
2838   s_whichSpecPart = BADTOK;
2839 }
This page took 0.254354 seconds and 3 git commands to generate.