/*-----------------------------------------------------------------------
- SDCC.lex - lexical analyser for use with sdcc ( a freeware compiler for
- 8/16 bit microcontrollers)
+ 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.
+ 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
- what you give them. Help stamp out software-hoarding!
+ 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!
-------------------------------------------------------------------------*/
D [0-9]
-L [a-zA-Z_]
+L [a-zA-Z_$]
H [a-fA-F0-9]
E [Ee][+-]?{D}+
FS (f|F|l|L)
#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 TKEYWORD99(token) return (options.std_c99 ? token : check_type())
-extern int lineno, column;
extern char *filename;
+extern int lineno;
+int column = 0; /* current column */
/* global definitions */
-char *currFname;
-int mylineno = 1;
+char *lexFilename;
+int lexLineno = 1;
/* local definitions */
-static struct dbuf_s asmbuff;
+static struct dbuf_s asmbuff; /* reusable _asm buffer */
/* forward declarations */
-static char *stringLiteral(void);
+int yyerror(char *s);
+static const char *stringLiteral(void);
static void count(void);
+static void count_char(int);
static int process_pragma(const char *);
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
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);
+ if (asmbuff.buf == NULL)
+ dbuf_init(&asmbuff, INITIAL_INLINEASM);
+ else
+ dbuf_set_length(&asmbuff, 0);
+
BEGIN(asm);
}
<asm>_?"_endasm" {
count();
if (!options.std_sdcc && yytext[1] != '_')
{
- dbuf_append(&asmbuff, yytext, strlen(yytext));
+ dbuf_append_str(&asmbuff, yytext);
}
else
{
yylval.yyinline = dbuf_c_str(&asmbuff);
- dbuf_detach(&asmbuff);
BEGIN(INITIAL);
return (INLINEASM);
}
}
<asm>\n {
count();
- dbuf_append(&asmbuff, yytext, 1);
+ dbuf_append_char(&asmbuff, *yytext);
}
<asm>. {
- dbuf_append(&asmbuff, yytext, 1);
+ dbuf_append_char(&asmbuff, *yytext);
}
"at" { count(); TKEYWORDSDCC(AT); }
"__at" { count(); TKEYWORD(AT); }
"__eeprom" { count(); TKEYWORD(EEPROM); }
"float" { count(); return(FLOAT); }
"fixed16x16" { count(); TKEYWORDSDCC(FIXED16X16); }
-"__fixed16x16" { count(); TKEYWORD(FIXED16X16); }
+"__fixed16x16" { count(); TKEYWORD(FIXED16X16); }
"flash" { count(); TKEYWORDSDCC(CODE); }
"__flash" { count(); TKEYWORD(CODE); }
"for" { count(); return(FOR); }
"__overlay" { count(); TKEYWORD(OVERLAY); }
"inline" { count(); TKEYWORD99(INLINE); }
"restrict" { count(); TKEYWORD99(RESTRICT); }
-{L}({L}|{D})* { count(); return(check_type()); }
+{L}({L}|{D})* {
+ if (!options.dollars_in_ident && strchr(yytext, '$'))
+ {
+ yyerror("stray '$' in program");
+ }
+ 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); }
[1-9]{D}*{IS}? { count(); yylval.val = constVal(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); }
\" { count(); yylval.val=strVal(stringLiteral()); 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(); 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); }
[ \t\v\f] { count(); }
\\ {
int ch = input();
- if (ch != '\n') {
- /* that could have been removed by the preprocessor anyway */
- werror (W_STRAY_BACKSLASH, column);
- unput(ch);
- }
+
+ if (ch == '\n')
+ count_char(ch);
+ else
+ {
+ /* that could have been removed by the preprocessor anyway */
+ werror (W_STRAY_BACKSLASH, column);
+ unput(ch);
+ }
}
. { count(); }
%%
#endif
-static int checkCurrFile (char *s)
+static int checkCurrFile (const char *s)
{
- int lNum;
- char *tptr;
+ int lNum;
+ char *tptr;
- /* skip '#' character */
- if (*s++ != '#')
- return 0;
+ /* skip '#' character */
+ if (*s++ != '#')
+ return 0;
- /* check if this is a #line
- this is not standard and can be removed in the future */
+ /* check if this is a #line
+ this is not standard and can be removed in the future */
#define LINE_STR "line"
#define LINE_LEN ((sizeof LINE_STR) - 1)
- if (strncmp(s, LINE_STR, LINE_LEN) == 0)
- s += LINE_LEN;
+ if (strncmp(s, LINE_STR, LINE_LEN) == 0)
+ s += LINE_LEN;
- /* get the line number */
- lNum = strtol(s, &tptr, 10);
- if (tptr == s || !isspace((unsigned char)*tptr))
- return 0;
- s = tptr;
+ /* get the line number */
+ lNum = strtol(s, &tptr, 10);
+ if (tptr == s || !isspace((unsigned char)*tptr))
+ return 0;
+ s = tptr;
+
+ /* adjust the line number */
+ lineno = lexLineno = lNum;
- /* now see if we have a file name */
- while (*s != '\"' && *s)
- s++;
+ /* now see if we have a file name */
+ while (*s != '"' && *s)
+ ++s;
- /* if we don't have a filename then */
- /* set the current line number to */
- /* line number if printFlag is on */
- if (!*s) {
- lineno = mylineno = lNum;
+ if (!*s)
+ {
+ /* no file name: return */
return 0;
}
- /* if we have a filename then check */
- /* if it is "standard in" if yes then */
- /* get the currentfile name info */
- s++ ;
-
- /* 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;
+ /* skip the double quote */
+ ++s;
+
+ /* get the file name and see if it is different from current one.
+ in c1mode fullSrcFileName is NULL */
+ if (fullSrcFileName &&
+ strncmp(s, fullSrcFileName, strlen(fullSrcFileName)) == 0 && fullSrcFileName[strlen(fullSrcFileName) - 1] == '"')
+ {
+ lexFilename = fullSrcFileName;
}
- filename = currFname ;
- return 0;
-}
+ else
+ {
+ const char *sb = s;
+ char *tmpFname;
-int column = 0;
-int plineIdx =0;
+ /* find the end of the file name */
+ while (*s && *s != '"')
+ ++s;
-static void count(void)
+ tmpFname = Safe_malloc(s - sb + 1);
+ memcpy(tmpFname, sb, s - sb);
+ tmpFname[s - sb] = '\0';
+
+ lexFilename = Safe_malloc(s - sb + 1);
+ copyStr(lexFilename, tmpFname);
+ }
+ filename = lexFilename;
+
+ return 0;
+}
+
+static void count_char(int ch)
{
- int i;
- for (i = 0; yytext[i] != '\0'; i++) {
- if (yytext[i] == '\n') {
+ switch (ch)
+ {
+ case '\n':
column = 0;
- lineno = ++mylineno;
+ lineno = ++lexLineno;
+ break;
+
+ case '\t':
+ column += 8 - (column % 8);
+ break;
+
+ default:
+ ++column;
+ break;
}
- else
- if (yytext[i] == '\t')
- column += 8 - (column % 8);
- else
- column++;
- }
- /* ECHO; */
+}
+
+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)) {
- strncpyz(yylval.yychar, yytext, SDCC_NAME_MAX);
+ && SPEC_TYPEDEF (sym->etype))
return (TYPE_NAME);
- }
- else {
- strncpyz (yylval.yychar, yytext, SDCC_NAME_MAX);
+ else
return(IDENTIFIER);
- }
}
/*
* to support ANSI hex and octal escape sequences in string literals
*/
-static char *stringLiteral(void)
+static const char *stringLiteral(void)
{
#define STR_BUF_CHUNCK_LEN 1024
int ch;
- static struct dbuf_s dbuf;
- char buf[2];
+ static struct dbuf_s dbuf; /* reusable string literal buffer */
if (dbuf.alloc == 0)
dbuf_init(&dbuf, STR_BUF_CHUNCK_LEN);
else
- dbuf_set_size(&dbuf, 0);
+ dbuf_set_length(&dbuf, 0);
+
+ dbuf_append_char(&dbuf, '"');
- dbuf_append(&dbuf, "\"", 1);
/* put into the buffer till we hit the first \" */
- while ((ch = input()) != 0) {
- switch (ch) {
- case '\\':
- /* if it is a \ then escape char's are allowed */
+ for (; ; )
+ {
ch = input();
- if (ch == '\n') {
- /* \<newline> is a continuator */
- lineno = ++mylineno;
- column = 0;
- }
- else {
- buf[0] = '\\';
- buf[1] = ch;
- dbuf_append(&dbuf, buf, 2); /* get the escape char, no further check */
- }
- break; /* carry on */
+ count_char(ch);
+ if (ch == EOF)
+ break;
- case '\n':
- /* if new line we have a new line break, which is illegal */
- werror(W_NEWLINE_IN_STRING);
- dbuf_append(&dbuf, "\n", 1);
- lineno = ++mylineno;
- column = 0;
- 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(&dbuf, "\"", 1); /* Pass end of this string or substring to evaluator */
- while ((ch = input()) && (isspace(ch) || ch == '\\')) {
- switch (ch) {
+ switch (ch)
+ {
case '\\':
- if ((ch = input()) != '\n') {
- werror(W_STRAY_BACKSLASH, column);
- unput(ch);
- }
- else {
- lineno = ++mylineno;
- column = 0;
- }
- break;
+ /* 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':
- mylineno++;
+ /* if new line we have a new line break, which is illegal */
+ werror(W_NEWLINE_IN_STRING);
+ dbuf_append_char(&dbuf, '\n');
break;
- }
- }
- if (!ch)
- goto out;
-
- if (ch != '\"') {
- unput(ch);
- goto out;
- }
- 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 != '"')
+ {
+ unput(ch);
+ goto out;
+ }
+ count_char(ch);
+ break;
- default:
- buf[0] = ch;
- dbuf_append(&dbuf, buf, 1); /* Put next substring introducer into output string */
+ default:
+ dbuf_append_char(&dbuf, (char)ch); /* Put next substring introducer into output string */
+ }
}
- }
out:
- return (char *)dbuf_c_str(&dbuf);
+ return dbuf_c_str(&dbuf);
}
enum {
- P_SAVE = 1,
- P_RESTORE,
- P_NOINDUCTION,
- P_NOINVARIANT,
- P_INDUCTION,
- P_STACKAUTO,
- P_NOJTBOUND,
- P_NOOVERLAY,
- P_LESSPEDANTIC,
- P_NOGCSE,
- P_CALLEE_SAVES,
- P_EXCLUDE,
- P_NOIV,
- P_LOOPREV,
- P_OVERLAY_, /* I had a strange conflict with P_OVERLAY while */
- /* cross-compiling for MINGW32 with gcc 3.2 */
- P_DISABLEWARN,
- P_OPTCODESPEED,
- P_OPTCODESIZE,
- P_OPTCODEBALANCED,
- P_STD_C89,
- P_STD_C99,
- P_STD_SDCC89,
- P_STD_SDCC99,
- P_CODESEG,
- P_CONSTSEG
+ P_SAVE = 1,
+ P_RESTORE,
+ P_NOINDUCTION,
+ P_NOINVARIANT,
+ P_INDUCTION,
+ P_STACKAUTO,
+ P_NOJTBOUND,
+ P_NOOVERLAY,
+ P_LESSPEDANTIC,
+ P_NOGCSE,
+ P_CALLEE_SAVES,
+ P_EXCLUDE,
+ P_NOIV,
+ P_LOOPREV,
+ P_OVERLAY_, /* I had a strange conflict with P_OVERLAY while */
+ /* cross-compiling for MINGW32 with gcc 3.2 */
+ P_DISABLEWARN,
+ P_OPTCODESPEED,
+ P_OPTCODESIZE,
+ P_OPTCODEBALANCED,
+ P_STD_C89,
+ P_STD_C99,
+ P_STD_SDCC89,
+ P_STD_SDCC99,
+ P_CODESEG,
+ P_CONSTSEG
};
case P_CALLEE_SAVES:
/* append to the functions already listed
in callee-saves */
- setParseWithComma(&options.calleeSavesSet, (char *)cp);
+ setParseWithComma(&options.calleeSavesSet, cp);
err = -1;
break;
case P_EXCLUDE:
{
deleteSet(&options.excludeRegsSet);
- setParseWithComma(&options.excludeRegsSet, (char *)cp);
+ setParseWithComma(&options.excludeRegsSet, cp);
err = -1;
}
break;
int warn;
cp = get_pragma_token(cp, &token);
-
- if (token.type != TOKEN_INT)
+ if (TOKEN_INT != token.type)
{
err = 1;
break;
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;
+ struct dbuf_s segname;
cp = get_pragma_token(cp, &token);
if (token.type == TOKEN_EOL)
err = 1;
break;
}
- segname = get_pragma_string(&token);
+
+ 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 (strlen(segname) > 8)
- {
- err = 1;
- break;
- }
+ if (id == P_CODESEG)
+ options.code_seg = dbuf_detach(&segname);
else
- {
- dbuf_append(&token.dbuf, "(CODE)", (sizeof "(CODE)") - 1);
- options.code_seg = Safe_strdup(get_pragma_string(&token));
- }
+ options.const_seg = dbuf_detach(&segname);
}
break;
if (0 != strcmp("#pragma", get_pragma_string(&token)))
{
/* Oops, womething went totally wrong - internal error */
+ wassertl(0, "pragma parser internal error");
}
/* skip spaces */
/* 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(options.vc_err_style)
fprintf(stderr, "\n%s(%d) : %s: token -> '%s' ; column %d\n",
- filename, mylineno, s, yytext, column);
+ lexFilename, lexLineno, s, yytext, column);
else
fprintf(stderr, "\n%s:%d: %s: token -> '%s' ; column %d\n",
- filename, mylineno, s ,yytext, column);
+ lexFilename, lexLineno, s ,yytext, column);
fatalError++;
return 0;