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