]> git.sur5r.net Git - cc65/blob - src/cc65/pragma.c
Merge pull request #433 from clbr/trampoline-fixes
[cc65] / src / cc65 / pragma.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 pragma.c                                  */
4 /*                                                                           */
5 /*                  Pragma handling for the cc65 C compiler                  */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2011, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdlib.h>
37 #include <string.h>
38
39 /* common */
40 #include "chartype.h"
41 #include "segnames.h"
42 #include "tgttrans.h"
43
44 /* cc65 */
45 #include "codegen.h"
46 #include "error.h"
47 #include "expr.h"
48 #include "global.h"
49 #include "litpool.h"
50 #include "scanner.h"
51 #include "scanstrbuf.h"
52 #include "symtab.h"
53 #include "pragma.h"
54 #include "wrappedcall.h"
55
56
57
58 /*****************************************************************************/
59 /*                                   data                                    */
60 /*****************************************************************************/
61
62
63
64 /* Tokens for the #pragmas */
65 typedef enum {
66     PRAGMA_ILLEGAL = -1,
67     PRAGMA_ALIGN,
68     PRAGMA_ALLOW_EAGER_INLINE,
69     PRAGMA_BSS_NAME,
70     PRAGMA_BSSSEG,                                      /* obsolete */
71     PRAGMA_CHARMAP,
72     PRAGMA_CHECK_STACK,
73     PRAGMA_CHECKSTACK,                                  /* obsolete */
74     PRAGMA_CODE_NAME,
75     PRAGMA_CODESEG,                                     /* obsolete */
76     PRAGMA_CODESIZE,
77     PRAGMA_DATA_NAME,
78     PRAGMA_DATASEG,                                     /* obsolete */
79     PRAGMA_INLINE_STDFUNCS,
80     PRAGMA_LOCAL_STRINGS,
81     PRAGMA_OPTIMIZE,
82     PRAGMA_REGVARADDR,
83     PRAGMA_REGISTER_VARS,
84     PRAGMA_REGVARS,                                     /* obsolete */
85     PRAGMA_RODATA_NAME,
86     PRAGMA_RODATASEG,                                   /* obsolete */
87     PRAGMA_SIGNED_CHARS,
88     PRAGMA_SIGNEDCHARS,                                 /* obsolete */
89     PRAGMA_STATIC_LOCALS,
90     PRAGMA_STATICLOCALS,                                /* obsolete */
91     PRAGMA_WARN,
92     PRAGMA_WRAPPED_CALL,
93     PRAGMA_WRITABLE_STRINGS,
94     PRAGMA_ZPSYM,
95     PRAGMA_COUNT
96 } pragma_t;
97
98 /* Pragma table */
99 static const struct Pragma {
100     const char* Key;            /* Keyword */
101     pragma_t    Tok;            /* Token */
102 } Pragmas[PRAGMA_COUNT] = {
103     { "align",                  PRAGMA_ALIGN              },
104     { "allow-eager-inline",     PRAGMA_ALLOW_EAGER_INLINE },
105     { "bss-name",               PRAGMA_BSS_NAME           },
106     { "bssseg",                 PRAGMA_BSSSEG             },      /* obsolete */
107     { "charmap",                PRAGMA_CHARMAP            },
108     { "check-stack",            PRAGMA_CHECK_STACK        },
109     { "checkstack",             PRAGMA_CHECKSTACK         },      /* obsolete */
110     { "code-name",              PRAGMA_CODE_NAME          },
111     { "codeseg",                PRAGMA_CODESEG            },      /* obsolete */
112     { "codesize",               PRAGMA_CODESIZE           },
113     { "data-name",              PRAGMA_DATA_NAME          },
114     { "dataseg",                PRAGMA_DATASEG            },      /* obsolete */
115     { "inline-stdfuncs",        PRAGMA_INLINE_STDFUNCS    },
116     { "local-strings",          PRAGMA_LOCAL_STRINGS      },
117     { "optimize",               PRAGMA_OPTIMIZE           },
118     { "register-vars",          PRAGMA_REGISTER_VARS      },
119     { "regvaraddr",             PRAGMA_REGVARADDR         },
120     { "regvars",                PRAGMA_REGVARS            },      /* obsolete */
121     { "rodata-name",            PRAGMA_RODATA_NAME        },
122     { "rodataseg",              PRAGMA_RODATASEG          },      /* obsolete */
123     { "signed-chars",           PRAGMA_SIGNED_CHARS       },
124     { "signedchars",            PRAGMA_SIGNEDCHARS        },      /* obsolete */
125     { "static-locals",          PRAGMA_STATIC_LOCALS      },
126     { "staticlocals",           PRAGMA_STATICLOCALS       },      /* obsolete */
127     { "warn",                   PRAGMA_WARN               },
128     { "wrapped-call",           PRAGMA_WRAPPED_CALL       },
129     { "writable-strings",       PRAGMA_WRITABLE_STRINGS   },
130     { "zpsym",                  PRAGMA_ZPSYM              },
131 };
132
133 /* Result of ParsePushPop */
134 typedef enum {
135     PP_NONE,
136     PP_POP,
137     PP_PUSH,
138     PP_ERROR,
139 } PushPopResult;
140
141
142
143 /*****************************************************************************/
144 /*                             Helper functions                              */
145 /*****************************************************************************/
146
147
148
149 static void PragmaErrorSkip (void)
150 /* Called in case of an error, skips tokens until the closing paren or a
151 ** semicolon is reached.
152 */
153 {
154     static const token_t TokenList[] = { TOK_RPAREN, TOK_SEMI };
155     SkipTokens (TokenList, sizeof(TokenList) / sizeof(TokenList[0]));
156 }
157
158
159
160 static int CmpKey (const void* Key, const void* Elem)
161 /* Compare function for bsearch */
162 {
163     return strcmp ((const char*) Key, ((const struct Pragma*) Elem)->Key);
164 }
165
166
167
168 static pragma_t FindPragma (const StrBuf* Key)
169 /* Find a pragma and return the token. Return PRAGMA_ILLEGAL if the keyword is
170 ** not a valid pragma.
171 */
172 {
173     struct Pragma* P;
174     P = bsearch (SB_GetConstBuf (Key), Pragmas, PRAGMA_COUNT, sizeof (Pragmas[0]), CmpKey);
175     return P? P->Tok : PRAGMA_ILLEGAL;
176 }
177
178
179
180 static int GetComma (StrBuf* B)
181 /* Expects and skips a comma in B. Prints an error and returns zero if no
182 ** comma is found. Return a value <> 0 otherwise.
183 */
184 {
185     SB_SkipWhite (B);
186     if (SB_Get (B) != ',') {
187         Error ("Comma expected");
188         return 0;
189     }
190     SB_SkipWhite (B);
191     return 1;
192 }
193
194
195
196 static int GetString (StrBuf* B, StrBuf* S)
197 /* Expects and skips a string in B. Prints an error and returns zero if no
198 ** string is found. Returns a value <> 0 otherwise.
199 */
200 {
201     if (!SB_GetString (B, S)) {
202         Error ("String literal expected");
203         return 0;
204     }
205     return 1;
206 }
207
208
209
210 static int GetNumber (StrBuf* B, long* Val)
211 /* Expects and skips a number in B. Prints an eror and returns zero if no
212 ** number is found. Returns a value <> 0 otherwise.
213 */
214 {
215     if (!SB_GetNumber (B, Val)) {
216         Error ("Constant integer expected");
217         return 0;
218     }
219     return 1;
220 }
221
222
223
224 static IntStack* GetWarning (StrBuf* B)
225 /* Get a warning name from the string buffer. Returns a pointer to the intstack
226 ** that holds the state of the warning, and NULL in case of errors. The
227 ** function will output error messages in case of problems.
228 */
229 {
230     IntStack* S = 0;
231     StrBuf W = AUTO_STRBUF_INITIALIZER;
232
233     /* The warning name is a symbol but the '-' char is allowed within */
234     if (SB_GetSym (B, &W, "-")) {
235
236         /* Map the warning name to an IntStack that contains its state */
237         S = FindWarning (SB_GetConstBuf (&W));
238
239         /* Handle errors */
240         if (S == 0) {
241             Error ("Pragma expects a warning name as first argument");
242         }
243     }
244
245     /* Deallocate the string */
246     SB_Done (&W);
247
248     /* Done */
249     return S;
250 }
251
252
253
254 static int HasStr (StrBuf* B, const char* E)
255 /* Checks if E follows in B. If so, skips it and returns true */
256 {
257     unsigned Len = strlen (E);
258     if (SB_GetLen (B) - SB_GetIndex (B) >= Len) {
259         if (strncmp (SB_GetConstBuf (B) + SB_GetIndex (B), E, Len) == 0) {
260             /* Found */
261             SB_SkipMultiple (B, Len);
262             return 1;
263         }
264     }
265     return 0;
266 }
267
268
269
270 static PushPopResult ParsePushPop (StrBuf* B)
271 /* Check for and parse the "push" and "pop" keywords. In case of "push", a
272 ** following comma is expected and skipped.
273 */
274 {
275     StrBuf Ident      = AUTO_STRBUF_INITIALIZER;
276     PushPopResult Res = PP_NONE;
277
278     /* Remember the current string index, so we can go back in case of errors */
279     unsigned Index = SB_GetIndex (B);
280
281     /* Try to read an identifier */
282     if (SB_GetSym (B, &Ident, 0)) {
283
284         /* Check if we have a first argument named "pop" */
285         if (SB_CompareStr (&Ident, "pop") == 0) {
286
287             Res = PP_POP;
288
289         /* Check if we have a first argument named "push" */
290         } else if (SB_CompareStr (&Ident, "push") == 0) {
291
292             Res = PP_PUSH;
293
294             /* Skip the following comma */
295             if (!GetComma (B)) {
296                 /* Error already flagged by GetComma */
297                 Res = PP_ERROR;
298             }
299
300         } else {
301
302             /* Unknown keyword, roll back */
303             SB_SetIndex (B, Index);
304         }
305     }
306
307     /* Free the string buffer and return the result */
308     SB_Done (&Ident);
309     return Res;
310 }
311
312
313
314 static void PopInt (IntStack* S)
315 /* Pops an integer from an IntStack. Prints an error if the stack is empty */
316 {
317     if (IS_GetCount (S) < 2) {
318         Error ("Cannot pop, stack is empty");
319     } else {
320         IS_Drop (S);
321     }
322 }
323
324
325
326 static void PushInt (IntStack* S, long Val)
327 /* Pushes an integer onto an IntStack. Prints an error if the stack is full */
328 {
329     if (IS_IsFull (S)) {
330         Error ("Cannot push: stack overflow");
331     } else {
332         IS_Push (S, Val);
333     }
334 }
335
336
337
338 static int BoolKeyword (StrBuf* Ident)
339 /* Check if the identifier in Ident is a keyword for a boolean value. Currently
340 ** accepted are true/false/on/off.
341 */
342 {
343     if (SB_CompareStr (Ident, "true") == 0) {
344         return 1;
345     }
346     if (SB_CompareStr (Ident, "on") == 0) {
347         return 1;
348     }
349     if (SB_CompareStr (Ident, "false") == 0) {
350         return 0;
351     }
352     if (SB_CompareStr (Ident, "off") == 0) {
353         return 0;
354     }
355
356     /* Error */
357     Error ("Pragma argument must be one of `on', `off', `true' or `false'");
358     return 0;
359 }
360
361
362
363 /*****************************************************************************/
364 /*                         Pragma handling functions                         */
365 /*****************************************************************************/
366
367
368
369 static void StringPragma (StrBuf* B, void (*Func) (const char*))
370 /* Handle a pragma that expects a string parameter */
371 {
372     StrBuf S = AUTO_STRBUF_INITIALIZER;
373
374     /* We expect a string here */
375     if (GetString (B, &S)) {
376         /* Call the given function with the string argument */
377         Func (SB_GetConstBuf (&S));
378     }
379
380     /* Call the string buf destructor */
381     SB_Done (&S);
382 }
383
384
385
386 static void SegNamePragma (StrBuf* B, segment_t Seg)
387 /* Handle a pragma that expects a segment name parameter */
388 {
389     StrBuf      S = AUTO_STRBUF_INITIALIZER;
390     const char* Name;
391
392     /* Check for the "push" or "pop" keywords */
393     int Push = 0;
394     switch (ParsePushPop (B)) {
395
396         case PP_NONE:
397             break;
398
399         case PP_PUSH:
400             Push = 1;
401             break;
402
403         case PP_POP:
404             /* Pop the old value and output it */
405             PopSegName (Seg);
406             g_segname (Seg);
407
408             /* Done */
409             goto ExitPoint;
410
411         case PP_ERROR:
412             /* Bail out */
413             goto ExitPoint;
414
415         default:
416             Internal ("Invalid result from ParsePushPop");
417
418     }
419
420     /* A string argument must follow */
421     if (!GetString (B, &S)) {
422         goto ExitPoint;
423     }
424
425     /* Get the string */
426     Name = SB_GetConstBuf (&S);
427
428     /* Check if the name is valid */
429     if (ValidSegName (Name)) {
430
431         /* Set the new name */
432         if (Push) {
433             PushSegName (Seg, Name);
434         } else {
435             SetSegName (Seg, Name);
436         }
437         g_segname (Seg);
438
439     } else {
440
441         /* Segment name is invalid */
442         Error ("Illegal segment name: `%s'", Name);
443
444     }
445
446 ExitPoint:
447     /* Call the string buf destructor */
448     SB_Done (&S);
449 }
450
451
452 static void WrappedCallPragma (StrBuf* B)
453 /* Handle the wrapped-call pragma */
454 {
455     StrBuf      S = AUTO_STRBUF_INITIALIZER;
456     const char *Name;
457     long Val;
458     SymEntry *Entry;
459
460     /* Check for the "push" or "pop" keywords */
461     switch (ParsePushPop (B)) {
462
463         case PP_NONE:
464             Error ("Push or pop required");
465             break;
466
467         case PP_PUSH:
468             break;
469
470         case PP_POP:
471             PopWrappedCall();
472
473             /* Done */
474             goto ExitPoint;
475
476         case PP_ERROR:
477             /* Bail out */
478             goto ExitPoint;
479
480         default:
481             Internal ("Invalid result from ParsePushPop");
482
483     }
484
485     /* A symbol argument must follow */
486     if (!SB_GetSym (B, &S, NULL)) {
487         goto ExitPoint;
488     }
489
490     /* Skip the following comma */
491     if (!GetComma (B)) {
492         /* Error already flagged by GetComma */
493         Error ("Value required for wrapped-call identifier");
494         goto ExitPoint;
495     }
496
497     if (!GetNumber (B, &Val)) {
498         Error ("Value required for wrapped-call identifier");
499         goto ExitPoint;
500     }
501
502     if (Val < 0 || Val > 255) {
503         Error ("Identifier must be between 0-255");
504         goto ExitPoint;
505     }
506
507     /* Get the string */
508     Name = SB_GetConstBuf (&S);
509     Entry = FindSym(Name);
510
511     /* Check if the name is valid */
512     if (Entry && Entry->Flags & SC_FUNC) {
513
514         PushWrappedCall(Entry, Val);
515         Entry->Flags |= SC_REF;
516         Entry->V.F.Func->Flags |= FD_CALL_WRAPPER;
517
518     } else {
519
520         /* Segment name is invalid */
521         Error ("Wrapped-call target does not exist or is not a function");
522
523     }
524
525 ExitPoint:
526     /* Call the string buf destructor */
527     SB_Done (&S);
528 }
529
530
531
532 static void CharMapPragma (StrBuf* B)
533 /* Change the character map */
534 {
535     long Index, C;
536
537     /* Read the character index */
538     if (!GetNumber (B, &Index)) {
539         return;
540     }
541     if (Index < 0 || Index > 255) {
542         Error ("Character index out of range");
543         return;
544     }
545
546     /* Comma follows */
547     if (!GetComma (B)) {
548         return;
549     }
550
551     /* Read the character code */
552     if (!GetNumber (B, &C)) {
553         return;
554     }
555     if (C < 0 || C > 255) {
556         Error ("Character code out of range");
557         return;
558     }
559
560     /* Warn about remapping character code 0x00
561     ** (except when remapping it back to itself).
562     */
563     if (Index + C != 0 && IS_Get (&WarnRemapZero)) {
564         if (Index == 0) {
565             Warning ("Remapping from 0 is dangerous with string functions");
566         }
567         else if (C == 0) {
568             Warning ("Remapping to 0 can make string functions stop unexpectedly");
569         }
570     }
571
572     /* Remap the character */
573     TgtTranslateSet ((unsigned) Index, (unsigned char) C);
574 }
575
576
577
578 static void WarnPragma (StrBuf* B)
579 /* Enable/disable warnings */
580 {
581     long   Val;
582     int    Push;
583
584     /* A warning name must follow */
585     IntStack* S = GetWarning (B);
586     if (S == 0) {
587         return;
588     }
589
590     /* Comma follows */
591     if (!GetComma (B)) {
592         return;
593     }
594
595     /* Check for the "push" or "pop" keywords */
596     switch (ParsePushPop (B)) {
597
598         case PP_NONE:
599             Push = 0;
600             break;
601
602         case PP_PUSH:
603             Push = 1;
604             break;
605
606         case PP_POP:
607             /* Pop the old value and bail out */
608             PopInt (S);
609             return;
610
611         case PP_ERROR:
612             /* Bail out */
613             return;
614
615         default:
616             Internal ("Invalid result from ParsePushPop");
617     }
618
619     /* Boolean argument follows */
620     if (HasStr (B, "true") || HasStr (B, "on")) {
621         Val = 1;
622     } else if (HasStr (B, "false") || HasStr (B, "off")) {
623         Val = 0;
624     } else if (!SB_GetNumber (B, &Val)) {
625         Error ("Invalid pragma argument");
626         return;
627     }
628
629     /* Set/push the new value */
630     if (Push) {
631         PushInt (S, Val);
632     } else {
633         IS_Set (S, Val);
634     }
635 }
636
637
638
639 static void FlagPragma (StrBuf* B, IntStack* Stack)
640 /* Handle a pragma that expects a boolean paramater */
641 {
642     StrBuf Ident = AUTO_STRBUF_INITIALIZER;
643     long   Val;
644     int    Push;
645
646
647     /* Try to read an identifier */
648     int IsIdent = SB_GetSym (B, &Ident, 0);
649
650     /* Check if we have a first argument named "pop" */
651     if (IsIdent && SB_CompareStr (&Ident, "pop") == 0) {
652         PopInt (Stack);
653         /* No other arguments allowed */
654         return;
655     }
656
657     /* Check if we have a first argument named "push" */
658     if (IsIdent && SB_CompareStr (&Ident, "push") == 0) {
659         Push = 1;
660         if (!GetComma (B)) {
661             goto ExitPoint;
662         }
663         IsIdent = SB_GetSym (B, &Ident, 0);
664     } else {
665         Push = 0;
666     }
667
668     /* Boolean argument follows */
669     if (IsIdent) {
670         Val = BoolKeyword (&Ident);
671     } else if (!GetNumber (B, &Val)) {
672         goto ExitPoint;
673     }
674
675     /* Set/push the new value */
676     if (Push) {
677         PushInt (Stack, Val);
678     } else {
679         IS_Set (Stack, Val);
680     }
681
682 ExitPoint:
683     /* Free the identifier */
684     SB_Done (&Ident);
685 }
686
687
688
689 static void IntPragma (StrBuf* B, IntStack* Stack, long Low, long High)
690 /* Handle a pragma that expects an int paramater */
691 {
692     long  Val;
693     int   Push;
694
695     /* Check for the "push" or "pop" keywords */
696     switch (ParsePushPop (B)) {
697
698         case PP_NONE:
699             Push = 0;
700             break;
701
702         case PP_PUSH:
703             Push = 1;
704             break;
705
706         case PP_POP:
707             /* Pop the old value and bail out */
708             PopInt (Stack);
709             return;
710
711         case PP_ERROR:
712             /* Bail out */
713             return;
714
715         default:
716             Internal ("Invalid result from ParsePushPop");
717
718     }
719
720     /* Integer argument follows */
721     if (!GetNumber (B, &Val)) {
722         return;
723     }
724
725     /* Check the argument */
726     if (Val < Low || Val > High) {
727         Error ("Pragma argument out of bounds (%ld-%ld)", Low, High);
728         return;
729     }
730
731     /* Set/push the new value */
732     if (Push) {
733         PushInt (Stack, Val);
734     } else {
735         IS_Set (Stack, Val);
736     }
737 }
738
739
740
741 static void ParsePragma (void)
742 /* Parse the contents of the _Pragma statement */
743 {
744     pragma_t Pragma;
745     StrBuf   Ident = AUTO_STRBUF_INITIALIZER;
746
747     /* Create a string buffer from the string literal */
748     StrBuf B = AUTO_STRBUF_INITIALIZER;
749     SB_Append (&B, GetLiteralStrBuf (CurTok.SVal));
750
751     /* Skip the string token */
752     NextToken ();
753
754     /* Get the pragma name from the string */
755     SB_SkipWhite (&B);
756     if (!SB_GetSym (&B, &Ident, "-")) {
757         Error ("Invalid pragma");
758         goto ExitPoint;
759     }
760
761     /* Search for the name */
762     Pragma = FindPragma (&Ident);
763
764     /* Do we know this pragma? */
765     if (Pragma == PRAGMA_ILLEGAL) {
766         /* According to the ANSI standard, we're not allowed to generate errors
767         ** for unknown pragmas, but warn about them if enabled (the default).
768         */
769         if (IS_Get (&WarnUnknownPragma)) {
770             Warning ("Unknown pragma `%s'", SB_GetConstBuf (&Ident));
771         }
772         goto ExitPoint;
773     }
774
775     /* Check for an open paren */
776     SB_SkipWhite (&B);
777     if (SB_Get (&B) != '(') {
778         Error ("'(' expected");
779         goto ExitPoint;
780     }
781
782     /* Skip white space before the argument */
783     SB_SkipWhite (&B);
784
785     /* Switch for the different pragmas */
786     switch (Pragma) {
787
788         case PRAGMA_ALIGN:
789             IntPragma (&B, &DataAlignment, 1, 4096);
790             break;
791
792         case PRAGMA_ALLOW_EAGER_INLINE:
793             FlagPragma (&B, &EagerlyInlineFuncs);
794             break;
795
796         case PRAGMA_BSSSEG:
797             Warning ("#pragma bssseg is obsolete, please use #pragma bss-name instead");
798             /* FALLTHROUGH */
799         case PRAGMA_BSS_NAME:
800             SegNamePragma (&B, SEG_BSS);
801             break;
802
803         case PRAGMA_CHARMAP:
804             CharMapPragma (&B);
805             break;
806
807         case PRAGMA_CHECKSTACK:
808             Warning ("#pragma checkstack is obsolete, please use #pragma check-stack instead");
809             /* FALLTHROUGH */
810         case PRAGMA_CHECK_STACK:
811             FlagPragma (&B, &CheckStack);
812             break;
813
814         case PRAGMA_CODESEG:
815             Warning ("#pragma codeseg is obsolete, please use #pragma code-name instead");
816             /* FALLTHROUGH */
817         case PRAGMA_CODE_NAME:
818             SegNamePragma (&B, SEG_CODE);
819             break;
820
821         case PRAGMA_CODESIZE:
822             IntPragma (&B, &CodeSizeFactor, 10, 1000);
823             break;
824
825         case PRAGMA_DATASEG:
826             Warning ("#pragma dataseg is obsolete, please use #pragma data-name instead");
827             /* FALLTHROUGH */
828         case PRAGMA_DATA_NAME:
829             SegNamePragma (&B, SEG_DATA);
830             break;
831
832         case PRAGMA_INLINE_STDFUNCS:
833             FlagPragma (&B, &InlineStdFuncs);
834             break;
835
836         case PRAGMA_LOCAL_STRINGS:
837             FlagPragma (&B, &LocalStrings);
838             break;
839
840         case PRAGMA_OPTIMIZE:
841             FlagPragma (&B, &Optimize);
842             break;
843
844         case PRAGMA_REGVARADDR:
845             FlagPragma (&B, &AllowRegVarAddr);
846             break;
847
848         case PRAGMA_REGVARS:
849             Warning ("#pragma regvars is obsolete, please use #pragma register-vars instead");
850             /* FALLTHROUGH */
851         case PRAGMA_REGISTER_VARS:
852             FlagPragma (&B, &EnableRegVars);
853             break;
854
855         case PRAGMA_RODATASEG:
856             Warning ("#pragma rodataseg is obsolete, please use #pragma rodata-name instead");
857             /* FALLTHROUGH */
858         case PRAGMA_RODATA_NAME:
859             SegNamePragma (&B, SEG_RODATA);
860             break;
861
862         case PRAGMA_SIGNEDCHARS:
863             Warning ("#pragma signedchars is obsolete, please use #pragma signed-chars instead");
864             /* FALLTHROUGH */
865         case PRAGMA_SIGNED_CHARS:
866             FlagPragma (&B, &SignedChars);
867             break;
868
869         case PRAGMA_STATICLOCALS:
870             Warning ("#pragma staticlocals is obsolete, please use #pragma static-locals instead");
871             /* FALLTHROUGH */
872         case PRAGMA_STATIC_LOCALS:
873             FlagPragma (&B, &StaticLocals);
874             break;
875
876         case PRAGMA_WRAPPED_CALL:
877             WrappedCallPragma(&B);
878             break;
879
880         case PRAGMA_WARN:
881             WarnPragma (&B);
882             break;
883
884         case PRAGMA_WRITABLE_STRINGS:
885             FlagPragma (&B, &WritableStrings);
886             break;
887
888         case PRAGMA_ZPSYM:
889             StringPragma (&B, MakeZPSym);
890             break;
891
892         default:
893             Internal ("Invalid pragma");
894     }
895
896     /* Closing paren expected */
897     SB_SkipWhite (&B);
898     if (SB_Get (&B) != ')') {
899         Error ("')' expected");
900         goto ExitPoint;
901     }
902     SB_SkipWhite (&B);
903
904     /* Allow an optional semicolon to be compatible with the old syntax */
905     if (SB_Peek (&B) == ';') {
906         SB_Skip (&B);
907         SB_SkipWhite (&B);
908     }
909
910     /* Make sure nothing follows */
911     if (SB_Peek (&B) != '\0') {
912         Error ("Unexpected input following pragma directive");
913     }
914
915 ExitPoint:
916     /* Release the string buffers */
917     SB_Done (&B);
918     SB_Done (&Ident);
919 }
920
921
922
923 void DoPragma (void)
924 /* Handle pragmas. These come always in form of the new C99 _Pragma() operator. */
925 {
926     /* Skip the token itself */
927     NextToken ();
928
929     /* We expect an opening paren */
930     if (!ConsumeLParen ()) {
931         return;
932     }
933
934     /* String literal */
935     if (CurTok.Tok != TOK_SCONST) {
936
937         /* Print a diagnostic */
938         Error ("String literal expected");
939
940         /* Try some smart error recovery: Skip tokens until we reach the
941         ** enclosing paren, or a semicolon.
942         */
943         PragmaErrorSkip ();
944
945     } else {
946
947         /* Parse the _Pragma statement */
948         ParsePragma ();
949     }
950
951     /* Closing paren needed */
952     ConsumeRParen ();
953 }