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