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 */
65typedef 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 */
100static 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 */
136typedef 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
151static 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
162static 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
170static 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
182static 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
198static 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
212static 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
226static 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
256static 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
272static 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
316static 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
328static 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
340static 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
371static 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
388static 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
460ExitPoint:
461 /* Call the string buf destructor */
462 SB_Done (&S);
463}
464
465
466static 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
539ExitPoint:
540 /* Call the string buf destructor */
541 SB_Done (&S);
542}
543
544
545
546static 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
592static 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
653static 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
696ExitPoint:
697 /* Free the identifier */
698 SB_Done (&Ident);
699}
700
701
702
703static 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
755static 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
762static 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
940ExitPoint:
941 /* Release the string buffers */
942 SB_Done (&B);
943 SB_Done (&Ident);
944}
945
946
947
948void 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}
979