summaryrefslogtreecommitdiff
path: root/src/SDCC.lex
diff options
context:
space:
mode:
authorXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
committerXavier ASUS <xavi92psx@gmail.com>2019-10-18 00:31:54 +0200
commit268a53de823a6750d6256ee1fb1e7707b4b45740 (patch)
tree42c1799a9a82b2f7d9790ee9fe181d72a7274751 /src/SDCC.lex
downloadsdcc-gas-268a53de823a6750d6256ee1fb1e7707b4b45740.tar.gz
sdcc-3.9.0 fork implementing GNU assembler syntax
This fork aims to provide better support for stm8-binutils
Diffstat (limited to 'src/SDCC.lex')
-rw-r--r--src/SDCC.lex1187
1 files changed, 1187 insertions, 0 deletions
diff --git a/src/SDCC.lex b/src/SDCC.lex
new file mode 100644
index 0000000..6dd53c2
--- /dev/null
+++ b/src/SDCC.lex
@@ -0,0 +1,1187 @@
+/*-----------------------------------------------------------------------
+ SDCC.lex - lexical analyser for use with sdcc (free open source
+ compiler for 8/16 bit microcontrollers)
+ Written by : Sandeep Dutta . sandeep.dutta@usa.net (1997)
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ In other words, you are welcome to use, share and improve this program.
+ You are forbidden to forbid anyone else to use, share and improve
+ what you give them. Help stamp out software-hoarding!
+-------------------------------------------------------------------------*/
+
+B [0-1]
+D [0-9]
+L [a-zA-Z_$]
+H [a-fA-F0-9]
+E [Ee][+-]?{D}+
+BE [Pp][+-]?{D}+
+FS (f|F|l|L)
+IS (u|U|l|L)*
+CP (L|u|U)
+HASH (#|%:)
+
+%{
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "common.h"
+#include "newalloc.h"
+#include "dbuf_string.h"
+/* Needed by flex 2.5.4 on NetBSD 5.0.1 sparc64 */
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+/* MSVC has no unistd.h but has read() declaration in io.h */
+#if defined(_MSC_VER)
+# include <io.h>
+#endif
+
+#define TKEYWORD(token) return (isTargetKeyword(yytext) ? token :\
+ check_type())
+
+#define TKEYWORD99(token) return (options.std_c99 ? token : check_type())
+
+int column = 0; /* current column */
+
+/* global definitions */
+char *lexFilename;
+int lexLineno = 1;
+
+/* local definitions */
+static struct dbuf_s asmbuff; /* reusable _asm buffer */
+
+/* forward declarations */
+int yyerror (char *s);
+static const char *stringLiteral (char);
+static void count (void);
+static void count_char (int);
+static int process_pragma (const char *);
+static int check_type (void);
+static void checkCurrFile (const char *s);
+%}
+
+%x asm
+%%
+"__asm" {
+ count ();
+ if (asmbuff.buf == NULL)
+ dbuf_init (&asmbuff, INITIAL_INLINEASM);
+ else
+ dbuf_set_length (&asmbuff, 0);
+
+ BEGIN (asm);
+}
+<asm>"__endasm" {
+ count ();
+ yylval.yystr = dbuf_c_str (&asmbuff);
+ BEGIN (INITIAL);
+ return INLINEASM;
+}
+<asm>\n {
+ count ();
+ dbuf_append_char(&asmbuff, *yytext);
+}
+<asm>. {
+ dbuf_append_char(&asmbuff, *yytext);
+}
+"__asm__" { count (); return ASM; }
+"__at" { count (); TKEYWORD (AT); }
+"auto" { count (); return AUTO; }
+"__bit" { count (); TKEYWORD (BIT); }
+"_Bool" { count (); TKEYWORD99 (SD_BOOL); }
+"break" { count (); return BREAK; }
+"case" { count (); return CASE; }
+"char" { count (); return SD_CHAR; }
+"__code" { count (); TKEYWORD (CODE); }
+"const" { count (); return SD_CONST; }
+"continue" { count (); return CONTINUE; }
+"__critical" { count (); TKEYWORD (CRITICAL); }
+"__data" { count (); TKEYWORD (DATA); }
+"default" { count (); return DEFAULT; }
+"do" { count (); return DO; }
+"double" { count (); werror (W_DOUBLE_UNSUPPORTED); return SD_FLOAT; }
+"else" { count (); return ELSE; }
+"enum" { count (); return ENUM; }
+"extern" { count (); return EXTERN; }
+"__far" { count (); TKEYWORD (XDATA); }
+"__eeprom" { count (); TKEYWORD (EEPROM); }
+"float" { count (); return SD_FLOAT; }
+"__fixed16x16" { count (); TKEYWORD (FIXED16X16); }
+"__flash" { count (); TKEYWORD (CODE); }
+"for" { count (); return FOR; }
+"goto" { count (); return GOTO; }
+"__idata" { count (); TKEYWORD (IDATA); }
+"if" { count (); return IF; }
+"int" { count (); return SD_INT; }
+"__interrupt" { count (); TKEYWORD (INTERRUPT); }
+"__nonbanked" { count (); TKEYWORD (NONBANKED); }
+"__banked" { count (); TKEYWORD (BANKED); }
+"__trap" { count (); TKEYWORD (TRAP); }
+"long" { count (); return SD_LONG; }
+"__near" { count (); TKEYWORD (DATA); }
+"__pdata" { count (); TKEYWORD (PDATA); }
+"__reentrant" { count (); TKEYWORD (REENTRANT); }
+"__shadowregs" { count (); TKEYWORD (SHADOWREGS); }
+"__wparam" { count (); TKEYWORD (SD_WPARAM); }
+"register" { count (); return REGISTER; }
+"return" { count (); return RETURN; }
+"__sfr" { count (); TKEYWORD (SFR); }
+"__sfr16" { count (); TKEYWORD (SFR16); }
+"__sfr32" { count (); TKEYWORD (SFR32); }
+"__sbit" { count (); TKEYWORD (SBIT); }
+"short" { count (); return SD_SHORT; }
+"signed" { count (); return SIGNED; }
+"sizeof" { count (); return SIZEOF; }
+"_Alignof" { count (); return ALIGNOF; }
+"__builtin_offsetof" { count (); return OFFSETOF; }
+"__sram" { count (); TKEYWORD (XDATA); }
+"static" { count (); return STATIC; }
+"struct" { count (); return STRUCT; }
+"switch" { count (); return SWITCH; }
+"typedef" { count (); return TYPEDEF; }
+"union" { count (); return UNION; }
+"unsigned" { count (); return UNSIGNED; }
+"void" { count (); return SD_VOID; }
+"volatile" { count (); return VOLATILE; }
+"__using" { count (); TKEYWORD (USING); }
+"__naked" { count (); TKEYWORD (NAKED); }
+"while" { count (); return WHILE; }
+"__xdata" { count (); TKEYWORD (XDATA); }
+"..." { count (); return VAR_ARGS; }
+"__typeof" { count (); return TYPEOF; }
+"_JavaNative" { count (); TKEYWORD (JAVANATIVE); }
+"__overlay" { count (); TKEYWORD (OVERLAY); }
+"inline" { count (); TKEYWORD99 (INLINE); }
+"_Noreturn" { count (); return NORETURN;}
+"restrict" { count (); TKEYWORD99 (RESTRICT); }
+"__smallc" { count (); TKEYWORD (SMALLC); }
+"__preserves_regs" { count (); return PRESERVES_REGS; }
+"__z88dk_fastcall" { count (); TKEYWORD (Z88DK_FASTCALL); }
+"__z88dk_callee" { count (); TKEYWORD (Z88DK_CALLEE); }
+"__z88dk_shortcall" { count (); return Z88DK_SHORTCALL; }
+"__z88dk_params_offset" { count (); return Z88DK_PARAMS_OFFSET; }
+"__addressmod" { count (); return ADDRESSMOD; }
+"_Static_assert" { count (); return STATIC_ASSERT; }
+"_Alignas" { count (); return ALIGNAS; }
+"_Generic" { count (); return GENERIC; }
+{L}({L}|{D})* {
+ if (!options.dollars_in_ident && strchr (yytext, '$'))
+ {
+ yyerror ("stray '$' in program");
+ }
+ count ();
+ return check_type();
+}
+0[bB]{B}+{IS}? {
+ if (!options.std_sdcc)
+ {
+ yyerror ("binary (0b) constants are not allowed in ISO C");
+ }
+ count ();
+ yylval.val = constIntVal (yytext);
+ return CONSTANT;
+}
+0[xX]{H}+{IS}? { count (); yylval.val = constIntVal (yytext); return CONSTANT; }
+0[0-7]*{IS}? { count (); yylval.val = constIntVal (yytext); return CONSTANT; }
+[1-9]{D}*{IS}? { count (); yylval.val = constIntVal (yytext); return CONSTANT; }
+{CP}?'(\\.|[^\\'])+' { count (); yylval.val = charVal (yytext); return CONSTANT; /* ' make syntax highlighter happy */ }
+{D}+{E}{FS}? { count (); yylval.val = constFloatVal (yytext); return CONSTANT; }
+{D}*"."{D}+({E})?{FS}? { count (); yylval.val = constFloatVal (yytext); return CONSTANT; }
+{D}+"."{D}*({E})?{FS}? { count (); yylval.val = constFloatVal (yytext); return CONSTANT; }
+0[xX]{H}+{BE}{FS}? { count (); if (!options.std_c99) werror(E_HEXFLOAT_C99); yylval.val = constFloatVal (yytext); return CONSTANT; }
+0[xX]{H}*"."{H}+({BE})?{FS}? { count (); if (!options.std_c99) werror(E_HEXFLOAT_C99); yylval.val = constFloatVal (yytext); return CONSTANT; }
+0[xX]{H}+"."{H}*({BE})?{FS}? { count (); if (!options.std_c99) werror(E_HEXFLOAT_C99); yylval.val = constFloatVal (yytext); return CONSTANT; }
+\" { count (); yylval.yystr = stringLiteral (0); return STRING_LITERAL; }
+"L\"" { count (); if (!options.std_c95) werror(E_WCHAR_STRING_C95); yylval.yystr = stringLiteral ('L'); return STRING_LITERAL; }
+"u8\"" { count (); if (!options.std_c11) werror(E_WCHAR_STRING_C11); yylval.yystr = stringLiteral (0); return STRING_LITERAL; }
+"u\"" { count (); if (!options.std_c11) werror(E_WCHAR_STRING_C11); yylval.yystr = stringLiteral ('u'); return STRING_LITERAL; }
+"U\"" { count (); if (!options.std_c11) werror(E_WCHAR_STRING_C11); yylval.yystr = stringLiteral ('U'); return STRING_LITERAL; }
+">>=" { count (); yylval.yyint = RIGHT_ASSIGN; return RIGHT_ASSIGN; }
+"<<=" { count (); yylval.yyint = LEFT_ASSIGN; return LEFT_ASSIGN; }
+"+=" { count (); yylval.yyint = ADD_ASSIGN; return ADD_ASSIGN; }
+"-=" { count (); yylval.yyint = SUB_ASSIGN; return SUB_ASSIGN; }
+"*=" { count (); yylval.yyint = MUL_ASSIGN; return MUL_ASSIGN; }
+"/=" { count (); yylval.yyint = DIV_ASSIGN; return DIV_ASSIGN; }
+"%=" { count (); yylval.yyint = MOD_ASSIGN; return MOD_ASSIGN; }
+"&=" { count (); yylval.yyint = AND_ASSIGN; return AND_ASSIGN; }
+"^=" { count (); yylval.yyint = XOR_ASSIGN; return XOR_ASSIGN; }
+"|=" { count (); yylval.yyint = OR_ASSIGN; return OR_ASSIGN; }
+">>" { count (); return RIGHT_OP; }
+"<<" { count (); return LEFT_OP; }
+"++" { count (); return INC_OP; }
+"--" { count (); return DEC_OP; }
+"->" { count (); return PTR_OP; }
+"&&" { count (); return AND_OP; }
+"||" { count (); return OR_OP; }
+"<=" { count (); return LE_OP; }
+">=" { count (); return GE_OP; }
+"==" { count (); return EQ_OP; }
+"!=" { count (); return NE_OP; }
+";" { count (); return ';'; }
+"{"|"<%" { count (); ignoreTypedefType = 0; return '{'; }
+"}"|"%>" { count (); return '}'; }
+"," { count (); return ','; }
+":" { count (); return ':'; }
+"=" { count (); return '='; }
+"(" { count (); ignoreTypedefType = 0; return '('; }
+")" { count (); return ')'; }
+"["|"<:" { count (); return '['; }
+"]"|":>" { count (); return ']'; }
+"." { count (); return '.'; }
+"&" { count (); return '&'; }
+"!" { count (); return '!'; }
+"~" { count (); return '~'; }
+"-" { count (); return '-'; }
+"+" { count (); return '+'; }
+"*" { count (); return '*'; }
+"/" { count (); return '/'; }
+"%" { count (); return '%'; }
+"<" { count (); return '<'; }
+">" { count (); return '>'; }
+"^" { count (); return '^'; }
+"|" { count (); return '|'; }
+"?" { count (); return '?'; }
+^{HASH}pragma.* { count (); process_pragma (yytext); }
+^{HASH}.* { count (); checkCurrFile (yytext); }
+
+"\r\n" { count (); }
+"\n" { count (); }
+[ \t\v\f] { count (); }
+\\ {
+ int ch = input ();
+
+ if (ch == '\n')
+ count_char (ch);
+ else
+ {
+ /* that could have been removed by the preprocessor anyway */
+ werror (W_STRAY_BACKSLASH, column);
+ unput (ch);
+ }
+}
+. { count (); }
+%%
+
+/* flex 2.5.31 undefines yytext_ptr, so we have to define it again */
+#ifndef yytext_ptr
+#define yytext_ptr yytext
+#endif
+
+static void
+checkCurrFile (const char *s)
+{
+ int lNum;
+ char *tptr;
+
+ /* skip '#' character */
+ if (*s++ != '#')
+ return;
+
+ /* get the line number */
+ lNum = strtol (s, &tptr, 10);
+ if (tptr == s || !isspace ((unsigned char) *tptr))
+ return;
+ s = tptr;
+
+ /* adjust the line number */
+ lineno = lexLineno = lNum - 1;
+
+ /* now see if we have a file name */
+ while (*s != '"' && *s)
+ ++s;
+
+ if (*s)
+ {
+ /* there is a file name */
+ const char *sb;
+ struct dbuf_s dbuf;
+
+ dbuf_init (&dbuf, 128);
+
+ /* skip the double quote */
+ sb = ++s;
+
+ /* preprocessor emits escaped file names
+ * (e.g. double backslashes on MSDOS-ish file systems),
+ * so we have to unescape it */
+ while (*s && *s != '"')
+ {
+ if (*s == '\\')
+ {
+ /* append chars before backslash */
+ dbuf_append (&dbuf, sb, s - sb);
+ if (*++s)
+ {
+ /* append char after backslash */
+ dbuf_append (&dbuf, s, 1);
+ sb = ++s;
+ }
+ }
+ else
+ ++s;
+ }
+ dbuf_append (&dbuf, sb, s - sb);
+
+ /* DON'T free the file name referenced by lexFilename
+ * since it will be dereferenced in the future at least
+ * by function printCLine(), see struct iCode members
+ * filename in SDCCicode.c */
+
+ filename = lexFilename = dbuf_detach_c_str (&dbuf);
+ }
+}
+
+static void
+count_char (int ch)
+{
+ switch (ch)
+ {
+ case '\n':
+ column = 0;
+ lineno = ++lexLineno;
+ break;
+
+ case '\t':
+ column += 8 - (column % 8);
+ break;
+
+ default:
+ ++column;
+ break;
+ }
+}
+
+static void
+count (void)
+{
+ const char *p;
+
+ for (p = yytext; *p; ++p)
+ count_char(*p);
+}
+
+static int
+check_type (void)
+{
+ symbol *sym = findSym(SymbolTab, NULL, yytext);
+
+ strncpyz(yylval.yychar, yytext, SDCC_NAME_MAX);
+
+ /* check if it is in the table as a typedef */
+ if (!ignoreTypedefType && sym && IS_SPEC (sym->etype)
+ && SPEC_TYPEDEF (sym->etype) && findSym(TypedefTab, NULL, yytext))
+ return (TYPE_NAME);
+ /* check if it is a named address space */
+ else if (findSym (AddrspaceTab, NULL, yytext))
+ return (ADDRSPACE_NAME);
+ else
+ return(IDENTIFIER);
+}
+
+/*
+ * Change by JTV 2001-05-19 to not concatenate strings
+ * to support ANSI hex and octal escape sequences in string literals
+ */
+
+static const char *
+stringLiteral (char enc)
+{
+#define STR_BUF_CHUNCK_LEN 1024
+ int ch;
+ static struct dbuf_s dbuf; /* reusable string literal buffer */
+
+ if (dbuf.alloc == 0)
+ dbuf_init(&dbuf, STR_BUF_CHUNCK_LEN);
+ else
+ dbuf_set_length(&dbuf, 0);
+
+ switch (enc)
+ {
+ case 'u': // UTF-16
+ dbuf_append_str(&dbuf, "u\"");
+ break;
+ case 'L':
+ case 'U': // UTF-32
+ enc = 'U';
+ dbuf_append_str(&dbuf, "U\"");
+ break;
+ default: // UTF-8 or whatever else the source character set is encoded in
+ dbuf_append_char(&dbuf, '"');
+ }
+
+ /* put into the buffer till we hit the first \" */
+
+ for (; ; )
+ {
+ ch = input();
+ count_char(ch);
+ if (ch == EOF)
+ break;
+
+ switch (ch)
+ {
+ case '\\':
+ /* if it is a \ then escape char's are allowed */
+ ch = input();
+ count_char(ch);
+ if (ch == '\n')
+ {
+ /* \<newline> is a continuator */
+ }
+ else
+ {
+ char buf[2];
+
+ if (ch == EOF)
+ goto out;
+
+ buf[0] = '\\';
+ buf[1] = ch;
+ dbuf_append(&dbuf, buf, 2); /* get the escape char, no further check */
+ }
+ break; /* carry on */
+
+ case '\n':
+ /* if new line we have a new line break, which is illegal */
+ werror(W_NEWLINE_IN_STRING);
+ dbuf_append_char(&dbuf, '\n');
+ break;
+
+ case '"':
+ /* if this is a quote then we have work to do */
+ /* find the next non whitespace character */
+ /* if that is a double quote then carry on */
+ dbuf_append_char(&dbuf, '"'); /* Pass end of this string or substring to evaluator */
+ while ((ch = input()) && (isspace(ch) || ch == '\\' || ch == '#'))
+ {
+ switch (ch)
+ {
+ case '\\':
+ count_char(ch);
+ if ((ch = input()) != '\n')
+ {
+ werror(W_STRAY_BACKSLASH, column);
+ if (ch != EOF)
+ unput(ch);
+ else
+ count_char(ch);
+ }
+ else
+ count_char(ch);
+ break;
+
+ case '\n':
+ count_char(ch);
+ break;
+
+ case '#':
+ if (column == 0)
+ {
+ /* # at the beginning of the line: collect the entire line */
+ struct dbuf_s linebuf;
+ const char *line;
+
+ count_char(ch);
+
+ dbuf_init(&linebuf, STR_BUF_CHUNCK_LEN);
+ dbuf_append_char(&linebuf, '#');
+
+ while ((ch = input()) != EOF && ch != '\n')
+ dbuf_append_char(&linebuf, (char)ch);
+
+ if (ch == '\n')
+ count_char(ch);
+
+ line = dbuf_c_str(&linebuf);
+
+ /* process the line */
+ if (startsWith(line, "#pragma"))
+ process_pragma(line);
+ else
+ checkCurrFile(line);
+
+ dbuf_destroy(&linebuf);
+ }
+ else
+ {
+ unput(ch);
+ goto out;
+ }
+
+ default:
+ count_char(ch);
+ break;
+ }
+ }
+
+ if (ch == EOF)
+ goto out;
+
+ if (ch == 'u' || ch == 'U' || ch == 'L') /* Could be an utf-16 or utf-32 wide string literal prefix */
+ {
+ int ch2;
+
+ if (!(options.std_c11 || options.std_c95 && ch == 'L'))
+ {
+ werror (ch == 'L' ? E_WCHAR_STRING_C95 : E_WCHAR_STRING_C11);
+ unput(ch);
+ goto out;
+ }
+
+ ch2 = input();
+ if (ch2 != '"')
+ unput (ch2);
+ else /* It is an utf-16 or utf-32 wide string literal prefix */
+ {
+ if (!enc)
+ {
+ dbuf_prepend_char(&dbuf, ch == 'L' ? 'U' : ch);
+ enc = ch;
+ }
+ count_char(ch);
+ count_char(ch2);
+ break;
+ }
+ }
+
+ if (ch == 'u') /* Could be an utf-8 wide string literal prefix */
+ {
+ ch = input();
+ if (ch != '8')
+ {
+ unput(ch);
+ unput('u');
+ goto out;
+ }
+ ch = input();
+ if (ch != '"')
+ {
+ unput(ch);
+ unput('8');
+ unput('u');
+ goto out;
+ }
+ }
+ if (ch != '"')
+ {
+ unput(ch);
+ goto out;
+ }
+ count_char(ch);
+ break;
+
+ default:
+ dbuf_append_char(&dbuf, (char)ch); /* Put next substring introducer into output string */
+ }
+ }
+
+out:
+ return dbuf_c_str(&dbuf);
+}
+
+
+enum {
+ P_SAVE = 1,
+ P_RESTORE,
+ P_INDUCTION,
+ P_NOINDUCTION,
+ P_NOINVARIANT,
+ P_STACKAUTO,
+ P_OVERLAY_, /* I had a strange conflict with P_OVERLAY while */
+ /* cross-compiling for MINGW32 with gcc 3.2 */
+ P_NOOVERLAY,
+ P_LESSPEDANTIC,
+ P_NOGCSE,
+ P_CALLEE_SAVES,
+ P_EXCLUDE,
+ P_NOIV,
+ P_LOOPREV,
+ P_DISABLEWARN,
+ P_OPTCODESPEED,
+ P_OPTCODESIZE,
+ P_OPTCODEBALANCED,
+ P_STD_C89,
+ P_STD_C99,
+ P_STD_C11,
+ P_STD_C2X,
+ P_STD_SDCC89,
+ P_STD_SDCC99,
+ P_CODESEG,
+ P_CONSTSEG
+};
+
+
+/* SAVE/RESTORE stack */
+#define SAVE_RESTORE_SIZE 128
+
+STACK_DCL(options_stack, struct options *, SAVE_RESTORE_SIZE)
+STACK_DCL(optimize_stack, struct optimize *, SAVE_RESTORE_SIZE)
+STACK_DCL(SDCCERRG_stack, struct SDCCERRG *, SAVE_RESTORE_SIZE)
+
+/*
+ * cloneXxx functions should be updated every time a new set is
+ * added to the options or optimize structure!
+ */
+
+static struct options *
+cloneOptions (struct options *opt)
+{
+ struct options *new_opt;
+
+ new_opt = Safe_malloc(sizeof (struct options));
+
+ /* clone scalar values */
+ *new_opt = *opt;
+
+ /* clone sets */
+ new_opt->calleeSavesSet = setFromSetNonRev(opt->calleeSavesSet);
+ new_opt->excludeRegsSet = setFromSetNonRev(opt->excludeRegsSet);
+ /* not implemented yet: */
+ /* new_opt->olaysSet = setFromSetNonRev(opt->olaysSet); */
+
+ return new_opt;
+}
+
+static struct optimize *
+cloneOptimize (struct optimize *opt)
+{
+ struct optimize *new_opt;
+
+ new_opt = Safe_malloc(sizeof (struct optimize));
+
+ /* clone scalar values */
+ *new_opt = *opt;
+
+ return new_opt;
+}
+
+static struct SDCCERRG *
+cloneSDCCERRG (struct SDCCERRG *val)
+{
+ struct SDCCERRG *new_val;
+
+ new_val = Safe_malloc(sizeof (struct SDCCERRG));
+
+ /* clone scalar values */
+ *new_val = *val;
+
+ return new_val;
+}
+
+static void
+copyAndFreeOptions (struct options *dest, struct options *src)
+{
+ /* delete dest sets */
+ deleteSet(&dest->calleeSavesSet);
+ deleteSet(&dest->excludeRegsSet);
+ /* not implemented yet: */
+ /* deleteSet(&dest->olaysSet); */
+
+ /* copy src to dest */
+ *dest = *src;
+
+ Safe_free(src);
+}
+
+static void
+copyAndFreeOptimize (struct optimize *dest, struct optimize *src)
+{
+ /* copy src to dest */
+ *dest = *src;
+
+ Safe_free(src);
+}
+
+static void
+copyAndFreeSDCCERRG (struct SDCCERRG *dest, struct SDCCERRG *src)
+{
+ /* copy src to dest */
+ *dest = *src;
+
+ Safe_free(src);
+}
+
+/*
+ * returns 1 if the pragma was processed, 0 if not
+ */
+static int
+doPragma (int id, const char *name, const char *cp)
+{
+ struct pragma_token_s token;
+ int err = 0;
+ int processed = 1;
+
+ init_pragma_token(&token);
+
+ switch (id)
+ {
+ case P_SAVE:
+ {
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ STACK_PUSH(options_stack, cloneOptions(&options));
+ STACK_PUSH(optimize_stack, cloneOptimize(&optimize));
+ STACK_PUSH(SDCCERRG_stack, cloneSDCCERRG(&_SDCCERRG));
+ }
+ break;
+
+ case P_RESTORE:
+ {
+ struct options *optionsp;
+ struct optimize *optimizep;
+ struct SDCCERRG *sdccerrgp;
+
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ optionsp = STACK_POP(options_stack);
+ copyAndFreeOptions(&options, optionsp);
+
+ optimizep = STACK_POP(optimize_stack);
+ copyAndFreeOptimize(&optimize, optimizep);
+
+ sdccerrgp = STACK_POP(SDCCERRG_stack);
+ copyAndFreeSDCCERRG(&_SDCCERRG, sdccerrgp);
+ }
+ break;
+
+ case P_INDUCTION:
+ case P_NOINDUCTION:
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ optimize.loopInduction = (id == P_INDUCTION) ? 1 : 0;
+ break;
+
+ case P_NOINVARIANT:
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ optimize.loopInvariant = 0;
+ break;
+
+ case P_STACKAUTO:
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ options.stackAuto = 1;
+ break;
+
+ case P_NOGCSE:
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ optimize.global_cse = 0;
+ break;
+
+ case P_OVERLAY_:
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ break; /* notyet */
+
+ case P_NOOVERLAY:
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ options.noOverlay = 1;
+ break;
+
+ case P_LESSPEDANTIC:
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ options.lessPedantic = 1;
+ setErrorLogLevel(ERROR_LEVEL_WARNING);
+ break;
+
+ case P_CALLEE_SAVES:
+ /* append to the functions already listed
+ in callee-saves */
+ setParseWithComma(&options.calleeSavesSet, cp);
+ err = -1;
+ break;
+
+ case P_EXCLUDE:
+ {
+ deleteSet(&options.excludeRegsSet);
+ setParseWithComma(&options.excludeRegsSet, cp);
+ err = -1;
+ }
+ break;
+
+ case P_NOIV:
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ options.noiv = 1;
+ break;
+
+ case P_LOOPREV:
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ optimize.noLoopReverse = 1;
+ break;
+
+ case P_DISABLEWARN:
+ {
+ int warn;
+
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_INT != token.type)
+ {
+ err = 1;
+ break;
+ }
+ warn = token.val.int_val;
+
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ setWarningDisabled(warn);
+ }
+ break;
+
+ case P_OPTCODESPEED:
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ optimize.codeSpeed = 1;
+ optimize.codeSize = 0;
+ break;
+
+ case P_OPTCODESIZE:
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ optimize.codeSpeed = 0;
+ optimize.codeSize = 1;
+ break;
+
+ case P_OPTCODEBALANCED:
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ optimize.codeSpeed = 0;
+ optimize.codeSize = 0;
+ break;
+
+ case P_STD_C89:
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ options.std_c99 = 0;
+ options.std_c11 = 0;
+ options.std_c2x = 0;
+ options.std_sdcc = 0;
+ break;
+
+ case P_STD_C99:
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ options.std_c99 = 1;
+ options.std_c11 = 0;
+ options.std_c2x = 0;
+ options.std_sdcc = 0;
+ break;
+
+ case P_STD_C11:
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ options.std_c99 = 1;
+ options.std_c11 = 1;
+ options.std_c2x = 0;
+ options.std_sdcc = 0;
+ break;
+
+ case P_STD_C2X:
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ options.std_c99 = 1;
+ options.std_c11 = 1;
+ options.std_c2x = 1;
+ options.std_sdcc = 0;
+ break;
+
+ case P_STD_SDCC89:
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ options.std_c99 = 0;
+ options.std_c11 = 0;
+ options.std_c2x = 0;
+ options.std_sdcc = 1;
+ break;
+
+ case P_STD_SDCC99:
+ cp = get_pragma_token(cp, &token);
+ if (TOKEN_EOL != token.type)
+ {
+ err = 1;
+ break;
+ }
+
+ options.std_c99 = 1;
+ options.std_c11 = 0;
+ options.std_c2x = 0;
+ options.std_sdcc = 1;
+ break;
+
+ case P_CODESEG:
+ case P_CONSTSEG:
+ {
+ struct dbuf_s segname;
+
+ cp = get_pragma_token(cp, &token);
+ if (token.type == TOKEN_EOL)
+ {
+ err = 1;
+ break;
+ }
+
+ dbuf_init(&segname, 16);
+ dbuf_printf(&segname, "%-8s(CODE)", get_pragma_string(&token));
+
+ cp = get_pragma_token(cp, &token);
+ if (token.type != TOKEN_EOL)
+ {
+ dbuf_destroy(&segname);
+ err = 1;
+ break;
+ }
+
+ if (id == P_CODESEG)
+ options.code_seg = dbuf_detach(&segname);
+ else
+ options.const_seg = dbuf_detach(&segname);
+ }
+ break;
+
+ default:
+ processed = 0;
+ break;
+ }
+
+ get_pragma_token(cp, &token);
+
+ if (1 == err || (0 == err && token.type != TOKEN_EOL))
+ werror(W_BAD_PRAGMA_ARGUMENTS, name);
+
+ free_pragma_token(&token);
+ return processed;
+}
+
+static struct pragma_s pragma_tbl[] = {
+ { "save", P_SAVE, 0, doPragma },
+ { "restore", P_RESTORE, 0, doPragma },
+ { "induction", P_INDUCTION, 0, doPragma },
+ { "noinduction", P_NOINDUCTION, 0, doPragma },
+ { "noinvariant", P_NOINVARIANT, 0, doPragma },
+ { "noloopreverse", P_LOOPREV, 0, doPragma },
+ { "stackauto", P_STACKAUTO, 0, doPragma },
+ { "nogcse", P_NOGCSE, 0, doPragma },
+ { "overlay", P_OVERLAY_, 0, doPragma },
+ { "nooverlay", P_NOOVERLAY, 0, doPragma },
+ { "callee_saves", P_CALLEE_SAVES, 0, doPragma },
+ { "exclude", P_EXCLUDE, 0, doPragma },
+ { "noiv", P_NOIV, 0, doPragma },
+ { "less_pedantic", P_LESSPEDANTIC, 0, doPragma },
+ { "disable_warning", P_DISABLEWARN, 0, doPragma },
+ { "opt_code_speed", P_OPTCODESPEED, 0, doPragma },
+ { "opt_code_size", P_OPTCODESIZE, 0, doPragma },
+ { "opt_code_balanced", P_OPTCODEBALANCED, 0, doPragma },
+ { "std_c89", P_STD_C89, 0, doPragma },
+ { "std_c99", P_STD_C99, 0, doPragma },
+ { "std_c11", P_STD_C11, 0, doPragma },
+ { "std_c2x", P_STD_C2X, 0, doPragma },
+ { "std_sdcc89", P_STD_SDCC89, 0, doPragma },
+ { "std_sdcc99", P_STD_SDCC99, 0, doPragma },
+ { "codeseg", P_CODESEG, 0, doPragma },
+ { "constseg", P_CONSTSEG, 0, doPragma },
+ { NULL, 0, 0, NULL },
+};
+
+/*
+ * returns 1 if the pragma was processed, 0 if not
+ */
+int
+process_pragma_tbl (const struct pragma_s *pragma_tbl, const char *s)
+{
+ struct pragma_token_s token;
+ int i;
+ int ret = 0;
+
+ init_pragma_token(&token);
+
+ s = get_pragma_token(s, &token);
+
+ /* skip separating whitespace */
+ while ('\n' != *s && isspace((unsigned char)*s))
+ s++;
+
+ for (i = 0; NULL != pragma_tbl[i].name; ++i)
+ {
+ /* now compare and do what needs to be done */
+ if (strcmp(get_pragma_string(&token), pragma_tbl[i].name) == 0)
+ {
+ if (pragma_tbl[i].deprecated != 0)
+ werror(W_DEPRECATED_PRAGMA, pragma_tbl[i].name);
+
+ ret = (*pragma_tbl[i].func)(pragma_tbl[i].id, pragma_tbl[i].name, s);
+ break;
+ }
+ }
+
+ free_pragma_token(&token);
+ return ret;
+}
+
+static int
+process_pragma (const char *s)
+{
+ struct pragma_token_s token;
+
+ init_pragma_token(&token);
+
+ s = get_pragma_token(s, &token);
+ if (0 != strcmp("#pragma", get_pragma_string(&token)))
+ {
+ /* Oops, something went totally wrong - internal error */
+ wassertl(0, "pragma parser internal error");
+ }
+
+ /* skip spaces */
+ while ('\n' != *s && isspace((unsigned char)*s))
+ ++s;
+
+ /* First give the port a chance */
+ if (port->process_pragma && port->process_pragma(s))
+ return 1;
+
+ if (process_pragma_tbl(pragma_tbl, s))
+ {
+ return 1;
+ }
+ else
+ {
+ werror(W_UNKNOWN_PRAGMA, s);
+ return 0;
+ }
+}
+
+int
+yywrap (void)
+{
+ if (!STACK_EMPTY(options_stack) || !STACK_EMPTY(optimize_stack))
+ werror(W_SAVE_RESTORE);
+
+ return 1;
+}
+
+int
+yyerror (char *s)
+{
+ fflush(stdout);
+
+ werror (S_SYNTAX_ERROR, yytext, column);
+
+ return 0;
+}