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