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