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