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