* use dynamic memory buffers instead temporary files
[fw/sdcc] / src / SDCC.lex
index 60820b75b9c19702456f7bc31ae4ec534de81d2f..201b1c9259290914ccd7a50683131794b1edfdf8 100644 (file)
@@ -2,24 +2,24 @@
   SDCC.lex - lexical analyser for use with sdcc ( a freeware compiler for
   8/16 bit microcontrollers)
   Written by : Sandeep Dutta . sandeep.dutta@usa.net (1997)
   SDCC.lex - lexical analyser for use with sdcc ( a freeware 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 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.
    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.
    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
    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!  
+   what you give them.   Help stamp out software-hoarding!
 -------------------------------------------------------------------------*/
 
 D       [0-9]
 -------------------------------------------------------------------------*/
 
 D       [0-9]
@@ -35,11 +35,16 @@ IS      (u|U|l|L)*
 #include <ctype.h>
 #include "common.h"
 #include "newalloc.h"
 #include <ctype.h>
 #include "common.h"
 #include "newalloc.h"
-#include "dbuf.h"
+#include "dbuf_string.h"
 
 #define TKEYWORD(token) return (isTargetKeyword(yytext) ? token :\
                                 check_type())
 
 
 #define TKEYWORD(token) return (isTargetKeyword(yytext) ? token :\
                                 check_type())
 
+#define TKEYWORDSDCC(token) return (options.std_sdcc && isTargetKeyword(yytext)\
+                                    ? token : check_type())
+
+#define TKEYWORD99(token) return (options.std_c99 ? token : check_type())
+
 extern int lineno, column;
 extern char *filename;
 
 extern int lineno, column;
 extern char *filename;
 
@@ -53,77 +58,112 @@ static struct dbuf_s asmbuff;
 /* forward declarations */
 static char *stringLiteral(void);
 static void count(void);
 /* forward declarations */
 static char *stringLiteral(void);
 static void count(void);
-static int process_pragma(char *);
+static int process_pragma(const char *);
 static int check_type(void);
 static int check_type(void);
-static int isTargetKeyword(char *s);
-static int checkCurrFile(char *s);
+static int isTargetKeyword(const char *s);
+static int checkCurrFile(const char *s);
 %}
 
 %x asm
 %%
 %}
 
 %x asm
 %%
-"_asm"         {
+_?"_asm"         {
   count();
   count();
+  if (!options.std_sdcc && yytext[1] != '_')
+    return check_type();
   assert(asmbuff.alloc == 0 && asmbuff.len == 0 && asmbuff.buf == NULL);
   dbuf_init(&asmbuff, INITIAL_INLINEASM);
   BEGIN(asm);
 }
   assert(asmbuff.alloc == 0 && asmbuff.len == 0 && asmbuff.buf == NULL);
   dbuf_init(&asmbuff, INITIAL_INLINEASM);
   BEGIN(asm);
 }
-<asm>"_endasm" {
+<asm>_?"_endasm" {
   count();
   count();
-  yylval.yyinline = dbuf_c_str(&asmbuff);
-  dbuf_detach(&asmbuff);
-  BEGIN(INITIAL);
-  return (INLINEASM);
+  if (!options.std_sdcc && yytext[1] != '_')
+    {
+      dbuf_append_str(&asmbuff, yytext);
+    }
+  else
+    {
+      yylval.yyinline = dbuf_c_str(&asmbuff);
+      dbuf_detach(&asmbuff);
+      BEGIN(INITIAL);
+      return (INLINEASM);
+    }
 }
 <asm>\n        {
   count();
 }
 <asm>\n        {
   count();
-  dbuf_append(&asmbuff, yytext, 1);
+  dbuf_append_char(&asmbuff, *yytext);
 }
 <asm>.         {
 }
 <asm>.         {
-  dbuf_append(&asmbuff, yytext, 1);
+  dbuf_append_char(&asmbuff, *yytext);
 }
 }
-"at"           { count(); TKEYWORD(AT); }
+"at"           { count(); TKEYWORDSDCC(AT); }
+"__at"         { count(); TKEYWORD(AT); }
 "auto"         { count(); return(AUTO); }
 "auto"         { count(); return(AUTO); }
-"bit"          { count(); TKEYWORD(BIT); }
+"bit"          { count(); TKEYWORDSDCC(BIT); }
+"__bit"        { count(); TKEYWORD(BIT); }
 "break"        { count(); return(BREAK); }
 "case"         { count(); return(CASE); }
 "char"         { count(); return(CHAR); }
 "break"        { count(); return(BREAK); }
 "case"         { count(); return(CASE); }
 "char"         { count(); return(CHAR); }
-"code"         { count(); TKEYWORD(CODE); }
+"code"         { count(); TKEYWORDSDCC(CODE); }
+"__code"       { count(); TKEYWORD(CODE); }
 "const"        { count(); return(CONST); }
 "continue"     { count(); return(CONTINUE); }
 "const"        { count(); return(CONST); }
 "continue"     { count(); return(CONTINUE); }
-"critical"     { count(); TKEYWORD(CRITICAL); }
-"data"         { count(); TKEYWORD(DATA); }
+"critical"     { count(); TKEYWORDSDCC(CRITICAL); }
+"__critical"   { count(); TKEYWORD(CRITICAL); }
+"data"         { count(); TKEYWORDSDCC(DATA); }
+"__data"       { count(); TKEYWORD(DATA); }
 "default"      { count(); return(DEFAULT); }
 "do"           { count(); return(DO); }
 "double"       { count(); werror(W_DOUBLE_UNSUPPORTED);return(FLOAT); }
 "else"         { count(); return(ELSE); }
 "enum"         { count(); return(ENUM); }
 "extern"       { count(); return(EXTERN); }
 "default"      { count(); return(DEFAULT); }
 "do"           { count(); return(DO); }
 "double"       { count(); werror(W_DOUBLE_UNSUPPORTED);return(FLOAT); }
 "else"         { count(); return(ELSE); }
 "enum"         { count(); return(ENUM); }
 "extern"       { count(); return(EXTERN); }
-"far"          { count(); TKEYWORD(XDATA); }
-"eeprom"       { count(); TKEYWORD(EEPROM); }
+"far"          { count(); TKEYWORDSDCC(XDATA); }
+"__far"        { count(); TKEYWORD(XDATA); }
+"eeprom"       { count(); TKEYWORDSDCC(EEPROM); }
+"__eeprom"     { count(); TKEYWORD(EEPROM); }
 "float"        { count(); return(FLOAT); }
 "float"        { count(); return(FLOAT); }
-"flash"        { count(); TKEYWORD(CODE); }
+"fixed16x16"   { count(); TKEYWORDSDCC(FIXED16X16); }
+"__fixed16x16"   { count(); TKEYWORD(FIXED16X16); }
+"flash"        { count(); TKEYWORDSDCC(CODE); }
+"__flash"      { count(); TKEYWORD(CODE); }
 "for"          { count(); return(FOR); }
 "goto"         { count(); return(GOTO); }
 "for"          { count(); return(FOR); }
 "goto"         { count(); return(GOTO); }
-"idata"        { count(); TKEYWORD(IDATA); }
+"idata"        { count(); TKEYWORDSDCC(IDATA); }
+"__idata"      { count(); TKEYWORD(IDATA); }
 "if"           { count(); return(IF); }
 "int"          { count(); return(INT); }
 "if"           { count(); return(IF); }
 "int"          { count(); return(INT); }
-"interrupt"    { count(); return(INTERRUPT); }
-"nonbanked"    { count(); TKEYWORD(NONBANKED); }
-"banked"       { count(); TKEYWORD(BANKED); }
+"interrupt"    { count(); TKEYWORDSDCC(INTERRUPT); }
+"__interrupt"  { count(); TKEYWORD(INTERRUPT); }
+"nonbanked"    { count(); TKEYWORDSDCC(NONBANKED); }
+"__nonbanked"  { count(); TKEYWORD(NONBANKED); }
+"banked"       { count(); TKEYWORDSDCC(BANKED); }
+"__banked"     { count(); TKEYWORD(BANKED); }
 "long"         { count(); return(LONG); }
 "long"         { count(); return(LONG); }
-"near"         { count(); TKEYWORD(DATA); }
-"pdata"        { count(); TKEYWORD(PDATA); }
-"reentrant"    { count(); TKEYWORD(REENTRANT); }
-"shadowregs"   { count(); TKEYWORD(SHADOWREGS); }
-"wparam"       { count(); TKEYWORD(WPARAM); }
+"near"         { count(); TKEYWORDSDCC(DATA); }
+"__near"       { count(); TKEYWORD(DATA); }
+"pdata"        { count(); TKEYWORDSDCC(PDATA); }
+"__pdata"      { count(); TKEYWORD(PDATA); }
+"reentrant"    { count(); TKEYWORDSDCC(REENTRANT); }
+"__reentrant"  { count(); TKEYWORD(REENTRANT); }
+"shadowregs"   { count(); TKEYWORDSDCC(SHADOWREGS); }
+"__shadowregs" { count(); TKEYWORD(SHADOWREGS); }
+"wparam"       { count(); TKEYWORDSDCC(WPARAM); }
+"__wparam"     { count(); TKEYWORD(WPARAM); }
 "register"     { count(); return(REGISTER); }
 "return"       { count(); return(RETURN); }
 "register"     { count(); return(REGISTER); }
 "return"       { count(); return(RETURN); }
-"sfr"          { count(); TKEYWORD(SFR); }
-"sbit"         { count(); TKEYWORD(SBIT); }
+"sfr"          { count(); TKEYWORDSDCC(SFR); }
+"__sfr"        { count(); TKEYWORD(SFR); }
+"sfr16"        { count(); TKEYWORDSDCC(SFR16); }
+"__sfr16"      { count(); TKEYWORD(SFR16); }
+"sfr32"        { count(); TKEYWORDSDCC(SFR32); }
+"__sfr32"      { count(); TKEYWORD(SFR32); }
+"sbit"         { count(); TKEYWORDSDCC(SBIT); }
+"__sbit"       { count(); TKEYWORD(SBIT); }
 "short"        { count(); return(SHORT); }
 "signed"       { count(); return(SIGNED); }
 "sizeof"       { count(); return(SIZEOF); }
 "short"        { count(); return(SHORT); }
 "signed"       { count(); return(SIGNED); }
 "sizeof"       { count(); return(SIZEOF); }
-"sram"         { count(); TKEYWORD(XDATA); }
+"sram"         { count(); TKEYWORDSDCC(XDATA); }
+"__sram"       { count(); TKEYWORD(XDATA); }
 "static"       { count(); return(STATIC); }
 "struct"       { count(); return(STRUCT); }
 "switch"       { count(); return(SWITCH); }
 "static"       { count(); return(STATIC); }
 "struct"       { count(); return(STRUCT); }
 "switch"       { count(); return(SWITCH); }
@@ -132,14 +172,20 @@ static int checkCurrFile(char *s);
 "unsigned"     { count(); return(UNSIGNED); }
 "void"         { count(); return(VOID); }
 "volatile"     { count(); return(VOLATILE); }
 "unsigned"     { count(); return(UNSIGNED); }
 "void"         { count(); return(VOID); }
 "volatile"     { count(); return(VOLATILE); }
-"using"        { count(); TKEYWORD(USING); }
-"_naked"       { count(); TKEYWORD(NAKED); }
+"using"        { count(); TKEYWORDSDCC(USING); }
+"__using"      { count(); TKEYWORD(USING); }
+"_naked"       { count(); TKEYWORDSDCC(NAKED); }
+"__naked"      { count(); TKEYWORD(NAKED); }
 "while"        { count(); return(WHILE); }
 "while"        { count(); return(WHILE); }
-"xdata"        { count(); TKEYWORD(XDATA); }
+"xdata"        { count(); TKEYWORDSDCC(XDATA); }
+"__xdata"      { count(); TKEYWORD(XDATA); }
 "..."          { count(); return(VAR_ARGS); }
 "__typeof"     { count(); return TYPEOF; }
 "_JavaNative"  { count(); TKEYWORD(JAVANATIVE); }
 "..."          { count(); return(VAR_ARGS); }
 "__typeof"     { count(); return TYPEOF; }
 "_JavaNative"  { count(); TKEYWORD(JAVANATIVE); }
-"_overlay"     { count(); TKEYWORD(OVERLAY); }
+"_overlay"     { count(); TKEYWORDSDCC(OVERLAY); }
+"__overlay"    { count(); TKEYWORD(OVERLAY); }
+"inline"       { count(); TKEYWORD99(INLINE); }
+"restrict"     { count(); TKEYWORD99(RESTRICT); }
 {L}({L}|{D})*  { count(); return(check_type()); }
 0[xX]{H}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
 0[0-7]*{IS}?     { count(); yylval.val = constVal(yytext); return(CONSTANT); }
 {L}({L}|{D})*  { count(); return(check_type()); }
 0[xX]{H}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
 0[0-7]*{IS}?     { count(); yylval.val = constVal(yytext); return(CONSTANT); }
@@ -194,7 +240,7 @@ static int checkCurrFile(char *s);
 "^"            { count(); return('^'); }
 "|"            { count(); return('|'); }
 "?"            { count(); return('?'); }
 "^"            { count(); return('^'); }
 "|"            { count(); return('|'); }
 "?"            { count(); return('?'); }
-^#pragma.*"\n" { count(); process_pragma(yytext); }
+^#pragma.*$    { count(); process_pragma(yytext); }
 ^(#line.*"\n")|(#.*"\n") { count(); checkCurrFile(yytext); }
 
 ^[^(]+"("[0-9]+") : error"[^\n]+ { werror(E_PRE_PROC_FAILED, yytext); count(); }
 ^(#line.*"\n")|(#.*"\n") { count(); checkCurrFile(yytext); }
 
 ^[^(]+"("[0-9]+") : error"[^\n]+ { werror(E_PRE_PROC_FAILED, yytext); count(); }
@@ -219,7 +265,7 @@ static int checkCurrFile(char *s);
 #endif
 
 
 #endif
 
 
-static int checkCurrFile (char *s)
+static int checkCurrFile (const char *s)
 {
     int  lNum;
     char *tptr;
 {
     int  lNum;
     char *tptr;
@@ -238,13 +284,13 @@ static int checkCurrFile (char *s)
 
     /* get the line number */
     lNum = strtol(s, &tptr, 10);
 
     /* get the line number */
     lNum = strtol(s, &tptr, 10);
-    if (tptr == s || !isspace(*tptr))
+    if (tptr == s || !isspace((unsigned char)*tptr))
       return 0;
     s = tptr;
 
     /* now see if we have a file name */
       return 0;
     s = tptr;
 
     /* now see if we have a file name */
-    while (*s != '\"' && *s)
-      s++;
+    while (*s != '"' && *s)
+      ++s;
 
     /* if we don't have a filename then */
     /* set the current line number to   */
 
     /* if we don't have a filename then */
     /* set the current line number to   */
@@ -257,20 +303,24 @@ static int checkCurrFile (char *s)
     /* if we have a filename then check */
     /* if it is "standard in" if yes then */
     /* get the currentfile name info    */
     /* if we have a filename then check */
     /* if it is "standard in" if yes then */
     /* get the currentfile name info    */
-    s++ ;
+    ++s;
 
     /* in c1mode fullSrcFileName is NULL */
     if (fullSrcFileName &&
          strncmp(s, fullSrcFileName, strlen(fullSrcFileName)) == 0) {
       lineno = mylineno = lNum;
       currFname = fullSrcFileName;
 
     /* in c1mode fullSrcFileName is NULL */
     if (fullSrcFileName &&
          strncmp(s, fullSrcFileName, strlen(fullSrcFileName)) == 0) {
       lineno = mylineno = lNum;
       currFname = fullSrcFileName;
-    } else {
-        char *sb = s;
-        /* mark the end of the filename */
-        while (*s != '"') s++;
-        *s = '\0';
-        currFname = strdup (sb);
-        lineno = mylineno = lNum;
+    }
+    else {
+      const char *sb = s;
+
+      /* find the end of the filename */
+      while (*s && *s != '"')
+        ++s;
+      currFname = Safe_malloc(s - sb + 1);
+      memcpy(currFname, sb, s - sb);
+      currFname[s - sb] = '\0';
+      lineno = mylineno = lNum;
     }
     filename = currFname ;
     return 0;
     }
     filename = currFname ;
     return 0;
@@ -327,9 +377,9 @@ static char *stringLiteral(void)
   if (dbuf.alloc == 0)
     dbuf_init(&dbuf, STR_BUF_CHUNCK_LEN);
   else
   if (dbuf.alloc == 0)
     dbuf_init(&dbuf, STR_BUF_CHUNCK_LEN);
   else
-    dbuf_set_size(&dbuf, 0);
+    dbuf_set_length(&dbuf, 0);
 
 
-  dbuf_append(&dbuf, "\"", 1);
+  dbuf_append_char(&dbuf, '"');
   /* put into the buffer till we hit the first \" */
 
   while ((ch = input()) != 0) {
   /* put into the buffer till we hit the first \" */
 
   while ((ch = input()) != 0) {
@@ -352,7 +402,7 @@ static char *stringLiteral(void)
     case '\n':
       /* if new line we have a new line break, which is illegal */
       werror(W_NEWLINE_IN_STRING);
     case '\n':
       /* if new line we have a new line break, which is illegal */
       werror(W_NEWLINE_IN_STRING);
-      dbuf_append(&dbuf, "\n", 1);
+      dbuf_append_char(&dbuf, '\n');
       lineno = ++mylineno;
       column = 0;
       break;
       lineno = ++mylineno;
       column = 0;
       break;
@@ -361,8 +411,8 @@ static char *stringLiteral(void)
       /* 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    */
       /* 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(&dbuf, "\"", 1);  /* Pass end of this string or substring to evaluator */
-      while ((ch = input()) && (isspace(ch) || ch == '\\')) {
+      dbuf_append_char(&dbuf, '"');  /* Pass end of this string or substring to evaluator */
+      while ((ch = input()) && (isspace(ch) || ch == '\\' || ch == '#')) {
         switch (ch) {
         case '\\':
           if ((ch = input()) != '\n') {
         switch (ch) {
         case '\\':
           if ((ch = input()) != '\n') {
@@ -376,23 +426,52 @@ static char *stringLiteral(void)
           break;
 
         case '\n':
           break;
 
         case '\n':
-          mylineno++;
+          lineno = ++mylineno;
+          column = 0;
           break;
           break;
+
+        case '#':
+          if (0 == column) {
+            /* # at the beginning of the line: collect the entire line */
+            struct dbuf_s linebuf;
+            const char *line;
+            
+            dbuf_init(&linebuf, STR_BUF_CHUNCK_LEN);
+            dbuf_append_char(&linebuf, '#');
+
+            while ((ch = input()) && ch != '\n') {
+              dbuf_append_char(&linebuf, (char)ch);
+            }
+
+            if (ch == '\n') {
+              lineno = ++mylineno;
+              column = 0;
+            }
+
+            line = dbuf_c_str(&linebuf);
+
+            /* process the line */
+            if (startsWith(line, "#pragma"))
+              process_pragma(line);
+            else
+              checkCurrFile(line);
+
+            dbuf_destroy(&linebuf);
+          }
         }
       }
 
       if (!ch)
         goto out;
 
         }
       }
 
       if (!ch)
         goto out;
 
-      if (ch != '\"') {
+      if (ch != '"') {
         unput(ch);
         goto out;
       }
       break;
 
     default:
         unput(ch);
         goto out;
       }
       break;
 
     default:
-      buf[0] = ch;
-      dbuf_append(&dbuf, buf, 1);  /* Put next substring introducer into output string */
+      dbuf_append_char(&dbuf, (char)ch);  /* Put next substring introducer into output string */
     }
   }
 
     }
   }
 
@@ -401,7 +480,7 @@ out:
 }
 
 
 }
 
 
-enum pragma_id {
+enum {
      P_SAVE = 1,
      P_RESTORE,
      P_NOINDUCTION,
      P_SAVE = 1,
      P_RESTORE,
      P_NOINDUCTION,
@@ -421,7 +500,13 @@ enum pragma_id {
      P_DISABLEWARN,
      P_OPTCODESPEED,
      P_OPTCODESIZE,
      P_DISABLEWARN,
      P_OPTCODESPEED,
      P_OPTCODESIZE,
-     P_OPTCODEBALANCED
+     P_OPTCODEBALANCED,
+     P_STD_C89,
+     P_STD_C99,
+     P_STD_SDCC89,
+     P_STD_SDCC99,
+     P_CODESEG,
+     P_CONSTSEG
 };
 
 
 };
 
 
@@ -430,6 +515,7 @@ enum pragma_id {
 
 STACK_DCL(options_stack, struct options *, SAVE_RESTORE_SIZE)
 STACK_DCL(optimize_stack, struct optimize *, SAVE_RESTORE_SIZE)
 
 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
 
 /*
  * cloneXxx functions should be updated every time a new set is
@@ -458,7 +544,7 @@ static struct optimize *cloneOptimize(struct optimize *opt)
 {
   struct optimize *new_opt;
 
 {
   struct optimize *new_opt;
 
-  new_opt = Safe_malloc(sizeof (struct options));
+  new_opt = Safe_malloc(sizeof (struct optimize));
 
   /* clone scalar values */
   *new_opt = *opt;
 
   /* clone scalar values */
   *new_opt = *opt;
@@ -466,6 +552,18 @@ static struct optimize *cloneOptimize(struct optimize *opt)
   return new_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 */
 static void copyAndFreeOptions(struct options *dest, struct options *src)
 {
   /* delete dest sets */
@@ -474,7 +572,7 @@ static void copyAndFreeOptions(struct options *dest, struct options *src)
   /* not implemented yet: */
   /* deleteSet(&dest->olaysSet); */
 
   /* not implemented yet: */
   /* deleteSet(&dest->olaysSet); */
 
-  /* dopy src to dest */
+  /* copy src to dest */
   *dest = *src;
 
   Safe_free(src);
   *dest = *src;
 
   Safe_free(src);
@@ -482,226 +580,522 @@ static void copyAndFreeOptions(struct options *dest, struct options *src)
 
 static void copyAndFreeOptimize(struct optimize *dest, struct optimize *src)
 {
 
 static void copyAndFreeOptimize(struct optimize *dest, struct optimize *src)
 {
-  /* dopy src to dest */
+  /* copy src to dest */
   *dest = *src;
 
   Safe_free(src);
 }
 
   *dest = *src;
 
   Safe_free(src);
 }
 
-static void doPragma(int op, char *cp)
+static void copyAndFreeSDCCERRG(struct SDCCERRG *dest, struct SDCCERRG *src)
 {
 {
-  int i;
+  /* copy src to dest */
+  *dest = *src;
 
 
-  switch (op) {
-  case P_SAVE:
-    {
-      STACK_PUSH(options_stack, cloneOptions(&options));
-      STACK_PUSH(optimize_stack, cloneOptimize(&optimize));
-    }
-    break;
+  Safe_free(src);
+}
 
 
-  case P_RESTORE:
+/*
+ * 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) 
     {
     {
-      struct options *optionsp;
-      struct optimize *optimizep;
+    case P_SAVE:
+      {
+        cp = get_pragma_token(cp, &token);
+        if (TOKEN_EOL != token.type)
+          {
+            err = 1;
+            break;
+          }
 
 
-      optionsp = STACK_POP(options_stack);
-      copyAndFreeOptions(&options, optionsp);
+        STACK_PUSH(options_stack, cloneOptions(&options));
+        STACK_PUSH(optimize_stack, cloneOptimize(&optimize));
+        STACK_PUSH(SDCCERRG_stack, cloneSDCCERRG(&_SDCCERRG));
+      }
+      break;
 
 
-      optimizep = STACK_POP(optimize_stack);
-      copyAndFreeOptimize(&optimize, optimizep);
-    }
-    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;
+          }
 
 
-  case P_NOINDUCTION:
-    optimize.loopInduction = 0;
-    break;
+        optionsp = STACK_POP(options_stack);
+        copyAndFreeOptions(&options, optionsp);
 
 
-  case P_NOINVARIANT:
-    optimize.loopInvariant = 0;
-    break;
+        optimizep = STACK_POP(optimize_stack);
+        copyAndFreeOptimize(&optimize, optimizep);
 
 
-  case P_INDUCTION:
-    optimize.loopInduction = 1;
-    break;
+        sdccerrgp = STACK_POP(SDCCERRG_stack);
+        copyAndFreeSDCCERRG(&_SDCCERRG, sdccerrgp);
+      }
+      break;
 
 
-  case P_STACKAUTO:
-    options.stackAuto = 1;
-    break;
+    case P_NOINDUCTION:
+      cp = get_pragma_token(cp, &token);
+      if (TOKEN_EOL != token.type)
+        {
+          err = 1;
+          break;
+        }
 
 
-  case P_NOJTBOUND:
-    optimize.noJTabBoundary = 1;
-    break;
+      optimize.loopInduction = 0;
+      break;
 
 
-  case P_NOGCSE:
-    optimize.global_cse = 0;
-    break;
+    case P_NOINVARIANT:
+      cp = get_pragma_token(cp, &token);
+      if (TOKEN_EOL != token.type)
+        {
+          err = 1;
+          break;
+        }
 
 
-  case P_NOOVERLAY:
-    options.noOverlay = 1;
-    break;
+      optimize.loopInvariant = 0;
+      break;
 
 
-  case P_LESSPEDANTIC:
-    options.lessPedantic = 1;
-    break;
+    case P_INDUCTION:
+      cp = get_pragma_token(cp, &token);
+      if (TOKEN_EOL != token.type)
+        {
+          err = 1;
+          break;
+        }
 
 
-  case P_CALLEE_SAVES:
-    /* append to the functions already listed
-       in callee-saves */
-    setParseWithComma(&options.calleeSavesSet, cp);
-    break;
+      optimize.loopInduction = 1;
+      break;
 
 
-  case P_EXCLUDE:
-    {
-      deleteSet(&options.excludeRegsSet);
-      setParseWithComma(&options.excludeRegsSet, cp);
-    }
-    break;
+    case P_STACKAUTO:
+      cp = get_pragma_token(cp, &token);
+      if (TOKEN_EOL != token.type)
+        {
+          err = 1;
+          break;
+        }
 
 
-  case P_NOIV:
-    options.noiv = 1;
-    break;
+      options.stackAuto = 1;
+      break;
 
 
-  case P_LOOPREV:
-    optimize.noLoopReverse = 1;
-    break;
+    case P_NOJTBOUND:
+      cp = get_pragma_token(cp, &token);
+      if (TOKEN_EOL != token.type)
+        {
+          err = 1;
+          break;
+        }
 
 
-  case P_OVERLAY_:
-    break; /* notyet */
+      optimize.noJTabBoundary = 1;
+      break;
 
 
-  case P_DISABLEWARN:
-    if (sscanf(cp, "%d", &i) && (i<MAX_ERROR_WARNING))
+    case P_NOGCSE:
+      cp = get_pragma_token(cp, &token);
+      if (TOKEN_EOL != token.type)
+        {
+          err = 1;
+          break;
+        }
+
+      optimize.global_cse = 0;
+      break;
+
+    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:
       {
       {
-        setWarningDisabled(i);
+        deleteSet(&options.excludeRegsSet);
+        setParseWithComma(&options.excludeRegsSet, cp);
+        err = -1;
       }
       }
-    break;
-  
-  case P_OPTCODESPEED:
-    optimize.codeSpeed = 1;
-    optimize.codeSize = 0;
-    break;
-
-  case P_OPTCODESIZE:
-    optimize.codeSpeed = 0;
-    optimize.codeSize = 1;
-    break;
-
-  case P_OPTCODEBALANCED:
-    optimize.codeSpeed = 0;
-    optimize.codeSize = 0;
-    break;
+      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_OVERLAY_:
+      cp = get_pragma_token(cp, &token);
+      if (TOKEN_EOL != token.type)
+        {
+          err = 1;
+          break;
+        }
+
+      break; /* notyet */
+
+    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;
+          }
+
+        if (warn < MAX_ERROR_WARNING)
+          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_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_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_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_sdcc = 1;
+      break;
+
+    case P_CODESEG:
+      {
+        const char *segname;
+
+        cp = get_pragma_token(cp, &token);
+        if (token.type == TOKEN_EOL)
+          {
+            err = 1;
+            break;
+          }
+        segname = get_pragma_string(&token);
+
+        cp = get_pragma_token(cp, &token);
+        if (token.type != TOKEN_EOL)
+          {
+            err = 1;
+            break;
+          }
+
+        if (strlen(segname) > 8)
+          {
+            err = 1;
+            break;
+          }
+        else
+          {
+            dbuf_append(&token.dbuf, "(CODE)", (sizeof "(CODE)") - 1);
+            options.code_seg = Safe_strdup(get_pragma_string(&token));
+          }
+      }
+      break;
+
+    case P_CONSTSEG:
+      {
+        const char *segname;
+
+        cp = get_pragma_token(cp, &token);
+        if (token.type == TOKEN_EOL)
+          {
+            err = 1;
+            break;
+          }
+        segname = get_pragma_string(&token);
+
+        cp = get_pragma_token(cp, &token);
+        if (token.type != TOKEN_EOL)
+          {
+            err = 1;
+            break;
+          }
+
+        if (strlen(segname) > 8)
+          {
+            err = 1;
+            break;
+          }
+        else
+          {
+            dbuf_append(&token.dbuf, "(CODE)", (sizeof "(CODE)") - 1);
+            options.code_seg = Safe_strdup(get_pragma_string(&token));
+          }
+      }
+      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 int process_pragma(char *s)
-{
-#define NELEM(x)    (sizeof (x) / sizeof (x)[0])
-#define PRAGMA_STR  "#pragma"
-#define PRAGMA_LEN  ((sizeof PRAGMA_STR) - 1)
+static struct pragma_s pragma_tbl[] = {
+  { "save",           P_SAVE,         0, doPragma },
+  { "restore",        P_RESTORE,      0, doPragma },
+  { "noinduction",    P_NOINDUCTION,  0, doPragma },
+  { "noinvariant",    P_NOINVARIANT,  0, doPragma },
+  { "noloopreverse",  P_LOOPREV,      0, doPragma },
+  { "induction",      P_INDUCTION,    0, doPragma },
+  { "stackauto",      P_STACKAUTO,    0, doPragma },
+  { "nojtbound",      P_NOJTBOUND,    0, doPragma },
+  { "nogcse",         P_NOGCSE,       0, doPragma },
+  { "nooverlay",      P_NOOVERLAY,    0, doPragma },
+  { "callee_saves",   P_CALLEE_SAVES, 0, doPragma },
+  { "exclude",        P_EXCLUDE,      0, doPragma },
+  { "noiv",           P_NOIV,         0, doPragma },
+  { "overlay",        P_OVERLAY_,     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_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 },
+};
 
 
-  static struct pragma_s
-    {
-      const char *name;
-      enum pragma_id id;
-      char deprecated;
-    } pragma_tbl[] = {
-    { "save",           P_SAVE,         0 },
-    { "restore",        P_RESTORE,      0 },
-    { "noinduction",    P_NOINDUCTION,  0 },
-    { "noinvariant",    P_NOINVARIANT,  0 },
-    { "noloopreverse",  P_LOOPREV,      0 },
-    { "induction",      P_INDUCTION,    0 },
-    { "stackauto",      P_STACKAUTO,    0 },
-    { "nojtbound",      P_NOJTBOUND,    0 },
-    { "nogcse",         P_NOGCSE,       0 },
-    { "nooverlay",      P_NOOVERLAY,    0 },
-    { "callee_saves",   P_CALLEE_SAVES, 0 },
-    { "exclude",        P_EXCLUDE,      0 },
-    { "noiv",           P_NOIV,         0 },
-    { "overlay",        P_OVERLAY_,     0 },
-    { "less_pedantic",  P_LESSPEDANTIC, 0 },
-    { "disable_warning",P_DISABLEWARN,  0 },
-    { "opt_code_speed", P_OPTCODESPEED, 0 },
-    { "opt_code_size",  P_OPTCODESIZE,  0 },
-    { "opt_code_balanced",  P_OPTCODEBALANCED,  0 },
-
-    /*
-     * The following lines are deprecated pragmas,
-     * only for bacward compatibility.
-     * They should be removed in next major release after 1.4.0
-     */
-
-    { "SAVE",           P_SAVE,         1 },
-    { "RESTORE",        P_RESTORE,      1 },
-    { "NOINDUCTION",    P_NOINDUCTION,  1 },
-    { "NOINVARIANT",    P_NOINVARIANT,  1 },
-    { "NOLOOPREVERSE",  P_LOOPREV,      1 },
-    { "INDUCTION",      P_INDUCTION,    1 },
-    { "STACKAUTO",      P_STACKAUTO,    1 },
-    { "NOJTBOUND",      P_NOJTBOUND,    1 },
-    { "NOGCSE",         P_NOGCSE,       1 },
-    { "NOOVERLAY",      P_NOOVERLAY,    1 },
-    { "CALLEE-SAVES",   P_CALLEE_SAVES, 1 },
-    { "EXCLUDE",        P_EXCLUDE,      1 },
-    { "NOIV",           P_NOIV,         1 },
-    { "OVERLAY",        P_OVERLAY_,     1 },
-    { "LESS_PEDANTIC",  P_LESSPEDANTIC, 1 },
-  };
-  char *cp;
+/*
+ * 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 i;
+  int ret = 0;
 
 
-  /* find the pragma */
-  while (strncmp(s, PRAGMA_STR, PRAGMA_LEN))
-    s++;
-  s += PRAGMA_LEN;
+  init_pragma_token(&token);
 
 
-  /* look for the directive */
-  while(isspace(*s))
-    s++;
+  s = get_pragma_token(s, &token);
 
 
-  cp = s;
-  /* look for the end of the directive */
-  while ((!isspace(*s)) && (*s != '\n'))
-    s++ ;
-
-  /* First give the port a chance */
-  if (port->process_pragma && !port->process_pragma(cp))
-    return 0;
+  /* skip separating whitespace */
+  while ('\n' != *s && isspace((unsigned char)*s))
+    s++;
 
 
-  for (i = 0; i < NELEM(pragma_tbl); i++)
+  for (i = 0; NULL != pragma_tbl[i].name; ++i)
     {
       /* now compare and do what needs to be done */
     {
       /* now compare and do what needs to be done */
-      size_t len = strlen(pragma_tbl[i].name);
-
-      if (strncmp(cp, pragma_tbl[i].name, len) == 0)
+      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);
 
         {
           if (pragma_tbl[i].deprecated != 0)
             werror(W_DEPRECATED_PRAGMA, pragma_tbl[i].name);
 
-          doPragma(pragma_tbl[i].id, cp + len);
-          return 0;
+          ret = (*pragma_tbl[i].func)(pragma_tbl[i].id, pragma_tbl[i].name, s);
+          break;
         }
     }
 
         }
     }
 
-  werror(W_UNKNOWN_PRAGMA, cp);
-  return 0;
+  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, womething 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;
+    }
 }
 
 /* will return 1 if the string is a part
    of a target specific keyword */
 }
 
 /* will return 1 if the string is a part
    of a target specific keyword */
-static int isTargetKeyword(char *s)
+static int isTargetKeyword(const char *s)
 {
   int i;
 
   if (port->keywords == NULL)
     return 0;
 {
   int i;
 
   if (port->keywords == NULL)
     return 0;
-  for (i = 0 ; port->keywords[i] ; i++ ) {
-    if (strcmp(port->keywords[i],s) == 0)
-      return 1;
-  }
 
 
-    return 0;
+  if (s[0] == '_' && s[1] == '_')
+    {
+      /* Keywords in the port's array have either 0 or 1 underscore, */
+      /* so skip over the appropriate number of chars when comparing */
+      for (i = 0 ; port->keywords[i] ; i++ )
+        {
+          if (port->keywords[i][0] == '_' &&
+              strcmp(port->keywords[i],s+1) == 0)
+            return 1;
+          else if (strcmp(port->keywords[i],s+2) == 0)
+            return 1;
+        }
+    }
+  else
+    {
+      for (i = 0 ; port->keywords[i] ; i++ )
+        {
+          if (strcmp(port->keywords[i],s) == 0)
+            return 1;
+        }
+    }
+
+  return 0;
 }
 
 int yywrap(void)
 }
 
 int yywrap(void)
@@ -716,16 +1110,13 @@ int yyerror(char *s)
 {
   fflush(stdout);
 
 {
   fflush(stdout);
 
-  if (mylineno && filename) {
-    if(options.vc_err_style)
-      fprintf(stderr, "\n%s(%d) : %s: token -> '%s' ; column %d\n",
-        filename, mylineno, s, yytext, column);
-    else
-      fprintf(stderr, "\n%s:%d: %s: token -> '%s' ; column %d\n",
-        filename, mylineno, s ,yytext, column);
-    fatalError++;
-  } else {
-    /* this comes from an empy file, no problem */
-  }
+  if(options.vc_err_style)
+    fprintf(stderr, "\n%s(%d) : %s: token -> '%s' ; column %d\n",
+      filename, mylineno, s, yytext, column);
+  else
+    fprintf(stderr, "\n%s:%d: %s: token -> '%s' ; column %d\n",
+      filename, mylineno, s ,yytext, column);
+  fatalError++;
+
   return 0;
 }
   return 0;
 }