gbdk-releases/sdcc/src/SDCC.lex
2015-01-10 16:25:09 +01:00

577 lines
16 KiB
Plaintext

/*-----------------------------------------------------------------------
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 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!
-------------------------------------------------------------------------*/
D [0-9]
L [a-zA-Z_]
H [a-fA-F0-9]
E [Ee][+-]?{D}+
FS (f|F|l|L)
IS (u|U|l|L)*
%{
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "common.h"
#include "newalloc.h"
char *stringLiteral();
char *currFname;
extern int lineno, column;
extern char *filename ;
extern char *fullSrcFileName ;
int yylineno = 1 ;
void count() ;
int process_pragma(char *);
#undef yywrap
int yywrap YY_PROTO((void))
{
return(1);
}
#define TKEYWORD(token) return (isTargetKeyword(yytext) ? token :\
check_type(yytext))
char *asmbuff=NULL;
int asmbuffSize=0;
char *asmp ;
extern int check_type ();
extern int isTargetKeyword ();
extern int checkCurrFile (char *);
extern int processPragma (char *);
extern int printListing (int );
struct optimize save_optimize ;
struct options save_options ;
enum {
P_SAVE = 1,
P_RESTORE ,
P_NOINDUCTION,
P_NOINVARIANT,
P_INDUCTION ,
P_STACKAUTO ,
P_NOJTBOUND ,
P_NOOVERLAY ,
P_NOGCSE ,
P_CALLEE_SAVES,
P_EXCLUDE ,
P_LOOPREV
};
%}
%x asm
%%
"_asm" {
count();
asmp = asmbuff = realloc (asmbuff, INITIAL_INLINEASM);
asmbuffSize=INITIAL_INLINEASM;
BEGIN(asm) ;
}
<asm>"_endasm" {
count();
*asmp = '\0';
yylval.yyinline = malloc (strlen(asmbuff)+1);
strcpy(yylval.yyinline,asmbuff);
BEGIN(INITIAL);
return (INLINEASM);
}
<asm>. {
if (asmp-asmbuff >= asmbuffSize-2) {
// increase the buffersize with 50%
int size=asmp-asmbuff;
asmbuffSize=asmbuffSize*3/2;
asmbuff = realloc (asmbuff, asmbuffSize);
asmp=asmbuff+size;
}
*asmp++ = yytext[0];
}
<asm>\n {
count();
if (asmp-asmbuff >= asmbuffSize-3) {
// increase the buffersize with 50%
int size=asmp-asmbuff;
asmbuffSize=asmbuffSize*3/2;
asmbuff = realloc (asmbuff, asmbuffSize);
asmp=asmbuff+size;
}
*asmp++ = '\n' ;
}
"at" { count(); TKEYWORD(AT) ; }
"auto" { count(); return(AUTO); }
"bit" { count(); TKEYWORD(BIT) ; }
"break" { count(); return(BREAK); }
"case" { count(); return(CASE); }
"char" { count(); return(CHAR); }
"code" { count(); TKEYWORD(CODE); }
"const" { count(); return(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(FLOAT); }
"else" { count(); return(ELSE); }
"enum" { count(); return(ENUM); }
"extern" { count(); return(EXTERN); }
"far" { count(); TKEYWORD(XDATA); }
"eeprom" { count(); TKEYWORD(EEPROM); }
"float" { count(); return(FLOAT); }
"flash" { count(); TKEYWORD(CODE);}
"for" { count(); return(FOR); }
"goto" { count(); return(GOTO); }
"idata" { count(); TKEYWORD(IDATA);}
"if" { count(); return(IF); }
"int" { count(); return(INT); }
"interrupt" { count(); return(INTERRUPT);}
"nonbanked" { count(); TKEYWORD(NONBANKED);}
"banked" { count(); TKEYWORD(BANKED);}
"long" { count(); return(LONG); }
"near" { count(); TKEYWORD(DATA);}
"pdata" { count(); TKEYWORD(PDATA); }
"reentrant" { count(); TKEYWORD(REENTRANT);}
"register" { count(); return(REGISTER); }
"return" { count(); return(RETURN); }
"sfr" { count(); TKEYWORD(SFR) ; }
"sbit" { count(); TKEYWORD(SBIT) ; }
"short" { count(); return(SHORT); }
"signed" { count(); return(SIGNED); }
"sizeof" { count(); return(SIZEOF); }
"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(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);}
{L}({L}|{D})* { count(); return(check_type()); }
0[xX]{H}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
0{D}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
{D}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
'(\\.|[^\\'])+' { count();yylval.val = charVal (yytext); return(CONSTANT); /* ' make syntax highliter 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); }
\" { 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(); 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(); NestLevel++ ; return('{'); }
"}" { count(); NestLevel--; 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('<'); }
">" { count(); return('>'); }
"^" { count(); return('^'); }
"|" { count(); return('|'); }
"?" { count(); return('?'); }
^#line.*"\n" { count(); checkCurrFile(yytext); }
^#pragma.*"\n" { count(); process_pragma(yytext); }
^[^(]+"("[0-9]+") : error"[^\n]+ { werror(E_PRE_PROC_FAILED,yytext);count(); }
^[^(]+"("[0-9]+") : warning"[^\n]+ { werror(W_PRE_PROC_WARNING,yytext);count(); }
"\r\n" { count(); }
"\n" { count(); }
[ \t\v\f] { count(); }
\\ {
char ch=input();
if (ch!='\n') {
// that could have been removed by the preprocessor anyway
werror (W_STRAY_BACKSLASH, column);
unput(ch);
}
}
. { count() ; }
%%
int checkCurrFile ( char *s)
{
char lineNum[10] ;
int lNum ;
char *tptr ;
/* first check if this is a #line */
if ( strncmp(s,"#line",5) )
return 0 ;
/* get to the line number */
while (!isdigit(*s))
s++ ;
tptr = lineNum ;
while (isdigit(*s))
*tptr++ = *s++ ;
*tptr = '\0';
sscanf(lineNum,"%d",&lNum);
/* 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 = yylineno = lNum ;
return 0;
}
/* if we have a filename then check */
/* if it is "standard in" if yes then */
/* get the currentfile name info */
s++ ;
if ( strncmp(s,fullSrcFileName,strlen(fullSrcFileName)) == 0) {
lineno = yylineno = lNum;
currFname = fullSrcFileName ;
} else {
char *sb = s;
/* mark the end of the filename */
while (*s != '"') s++;
*s = '\0';
currFname = malloc (strlen(sb)+1);
strcpy(currFname,sb);
lineno = yylineno = lNum;
}
filename = currFname ;
return 0;
}
int column = 0;
int plineIdx=0;
void count()
{
int i;
for (i = 0; yytext[i] != '\0'; i++) {
if (yytext[i] == '\n') {
column = 0;
lineno = ++yylineno ;
}
else
if (yytext[i] == '\t')
column += 8 - (column % 8);
else
column++;
}
/* ECHO; */
}
int check_type()
{
/* check if it is in the typedef table */
if (findSym(TypedefTab,NULL,yytext)) {
strcpy(yylval.yychar,yytext);
return (TYPE_NAME) ;
}
else {
strcpy (yylval.yychar,yytext);
return(IDENTIFIER);
}
}
char strLitBuff[2048]; // TODO: this is asking for the next bug :)
/*
* Change by JTV 2001-05-19 to not concantenate strings
* to support ANSI hex and octal escape sequences in string liteals
*/
char *stringLiteral () {
int ch;
char *str = strLitBuff;
*str++ = '\"';
/* put into the buffer till we hit the first \" */
while (1) {
ch = input();
if (!ch)
break; /* end of input */
/* if it is a \ then escape char's are allowed */
if (ch == '\\') {
ch=input();
if (ch=='\n') {
/* \<newline> is a continuator */
lineno=++yylineno;
column=0;
continue;
}
*str++ = '\\'; /* backslash in place */
*str++ = ch; /* get the escape char, no further check */
continue; /* carry on */
}
/* if new line we have a new line break, which is illegal */
if (ch == '\n') {
werror (W_NEWLINE_IN_STRING);
*str++ = '\n';
lineno=++yylineno;
column=0;
continue;
}
/* 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 (ch == '\"') {
*str++ = ch ; /* Pass end of this string or substring to evaluator */
while ((ch = input()) && (isspace(ch) || ch=='\\')) {
switch (ch) {
case '\\':
if ((ch=input())!='\n') {
werror (W_STRAY_BACKSLASH, column);
unput(ch);
} else {
lineno=++yylineno;
column=0;
}
break;
case '\n':
yylineno++;
break;
}
}
if (!ch)
break;
if (ch != '\"') {
unput(ch) ;
break ;
}
}
*str++ = ch; /* Put next substring introducer into output string */
}
*str = '\0';
return strLitBuff;
}
void doPragma (int op, char *cp)
{
switch (op) {
case P_SAVE:
memcpy(&save_options,&options,sizeof(options));
memcpy(&save_optimize,&optimize,sizeof(optimize));
break;
case P_RESTORE:
memcpy(&options,&save_options,sizeof(options));
memcpy(&optimize,&save_optimize,sizeof(optimize));
break;
case P_NOINDUCTION:
optimize.loopInduction = 0 ;
break;
case P_NOINVARIANT:
optimize.loopInvariant = 0 ;
break;
case P_INDUCTION:
optimize.loopInduction = 1 ;
break;
case P_STACKAUTO:
options.stackAuto = 1;
break;
case P_NOJTBOUND:
optimize.noJTabBoundary = 1;
break;
case P_NOGCSE:
optimize.global_cse = 0;
break;
case P_NOOVERLAY:
options.noOverlay = 1;
break;
case P_CALLEE_SAVES:
{
int i=0;
/* append to the functions already listed
in callee-saves */
for (; options.calleeSaves[i] ;i++);
parseWithComma(&options.calleeSaves[i], Safe_strdup(cp));
}
break;
case P_EXCLUDE:
parseWithComma(options.excludeRegs, Safe_strdup(cp));
break;
case P_LOOPREV:
optimize.noLoopReverse = 1;
break;
}
}
int process_pragma(char *s)
{
char *cp ;
/* find the pragma */
while (strncmp(s,"#pragma",7))
s++;
s += 7;
/* look for the directive */
while(isspace(*s)) s++;
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;
/* now compare and do what needs to be done */
if (strncmp(cp,PRAGMA_SAVE,strlen(PRAGMA_SAVE)) == 0) {
doPragma(P_SAVE,cp+strlen(PRAGMA_SAVE));
return 0;
}
if (strncmp(cp,PRAGMA_RESTORE,strlen(PRAGMA_RESTORE)) == 0) {
doPragma (P_RESTORE,cp+strlen(PRAGMA_RESTORE));
return 0;
}
if (strncmp(cp,PRAGMA_NOINDUCTION,strlen(PRAGMA_NOINDUCTION)) == 0) {
doPragma (P_NOINDUCTION,cp+strlen(PRAGMA_NOINDUCTION)) ;
return 0;
}
if (strncmp(cp,PRAGMA_NOINVARIANT,strlen(PRAGMA_NOINVARIANT)) == 0) {
doPragma (P_NOINVARIANT,NULL) ;
return 0;
}
if (strncmp(cp,PRAGMA_INDUCTION,strlen(PRAGMA_INDUCTION)) == 0) {
doPragma (P_INDUCTION,NULL) ;
return 0;
}
if (strncmp(cp,PRAGMA_STACKAUTO,strlen(PRAGMA_STACKAUTO)) == 0) {
doPragma (P_STACKAUTO,NULL);
return 0;
}
if (strncmp(cp,PRAGMA_NOJTBOUND,strlen(PRAGMA_NOJTBOUND)) == 0) {
doPragma (P_NOJTBOUND,NULL);
return 0;
}
if (strncmp(cp,PRAGMA_NOGCSE,strlen(PRAGMA_NOGCSE)) == 0) {
doPragma (P_NOGCSE,NULL);
return 0;
}
if (strncmp(cp,PRAGMA_NOOVERLAY,strlen(PRAGMA_NOOVERLAY)) == 0) {
doPragma (P_NOOVERLAY,NULL);
return 0;
}
if (strncmp(cp,PRAGMA_CALLEESAVES,strlen(PRAGMA_CALLEESAVES)) == 0) {
doPragma(P_CALLEE_SAVES,cp+strlen(PRAGMA_CALLEESAVES));
return 0;
}
if (strncmp(cp,PRAGMA_EXCLUDE,strlen(PRAGMA_EXCLUDE)) == 0) {
doPragma(P_EXCLUDE,cp+strlen(PRAGMA_EXCLUDE));
return 0;
}
if (strncmp(cp,PRAGMA_NOLOOPREV,strlen(PRAGMA_NOLOOPREV)) == 0) {
doPragma(P_LOOPREV,NULL);
return 0;
}
werror(W_UNKNOWN_PRAGMA,cp);
return 0;
}
/* will return 1 if the string is a part
of a target specific keyword */
int isTargetKeyword(char *s)
{
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;
}
extern int fatalError;
int yyerror(char *s)
{
fflush(stdout);
if (yylineno && filename)
fprintf(stdout,"\n%s(%d) %s: token -> '%s' ; column %d\n",
filename,yylineno,
s,yytext,column);
fatalError++;
return 0;
}