1 /*-----------------------------------------------------------------------
2 SDCC.lex - lexical analyser for use with sdcc ( a freeware compiler for
3 8/16 bit microcontrollers)
4 Written by : Sandeep Dutta . sandeep.dutta@usa.net (1997)
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 In other words, you are welcome to use, share and improve this program.
21 You are forbidden to forbid anyone else to use, share and improve
22 what you give them. Help stamp out software-hoarding!
23 -------------------------------------------------------------------------*/
40 static char *stringLiteral(void);
43 extern int lineno, column;
44 extern char *filename;
46 static void count(void);
47 static int process_pragma(char *);
48 static void my_unput(char c);
50 #define TKEYWORD(token) return (isTargetKeyword(yytext) ? token :\
55 static int check_type(void);
56 static int isTargetKeyword(char *s);
57 static int checkCurrFile (char *s);
58 struct optimize save_optimize;
59 struct options save_options;
66 asmp = asmbuff = realloc (asmbuff, INITIAL_INLINEASM);
67 asmbuffSize=INITIAL_INLINEASM;
73 yylval.yyinline = strdup (asmbuff);
78 if (asmp-asmbuff >= asmbuffSize-2) {
79 /* increase the buffersize with 50% */
80 int size=asmp-asmbuff;
81 asmbuffSize=asmbuffSize*3/2;
82 asmbuff = realloc (asmbuff, asmbuffSize);
89 if (asmp-asmbuff >= asmbuffSize-3) {
90 /* increase the buffersize with 50% */
91 int size=asmp-asmbuff;
92 asmbuffSize=asmbuffSize*3/2;
93 asmbuff = realloc (asmbuff, asmbuffSize);
98 "at" { count(); TKEYWORD(AT) ; }
99 "auto" { count(); return(AUTO); }
100 "bit" { count(); TKEYWORD(BIT) ; }
101 "break" { count(); return(BREAK); }
102 "case" { count(); return(CASE); }
103 "char" { count(); return(CHAR); }
104 "code" { count(); TKEYWORD(CODE); }
105 "const" { count(); return(CONST); }
106 "continue" { count(); return(CONTINUE); }
107 "critical" { count(); TKEYWORD(CRITICAL); }
108 "data" { count(); TKEYWORD(DATA); }
109 "default" { count(); return(DEFAULT); }
110 "do" { count(); return(DO); }
111 "double" { count(); werror(W_DOUBLE_UNSUPPORTED);return(FLOAT); }
112 "else" { count(); return(ELSE); }
113 "enum" { count(); return(ENUM); }
114 "extern" { count(); return(EXTERN); }
115 "far" { count(); TKEYWORD(XDATA); }
116 "eeprom" { count(); TKEYWORD(EEPROM); }
117 "float" { count(); return(FLOAT); }
118 "flash" { count(); TKEYWORD(CODE);}
119 "for" { count(); return(FOR); }
120 "goto" { count(); return(GOTO); }
121 "idata" { count(); TKEYWORD(IDATA);}
122 "if" { count(); return(IF); }
123 "int" { count(); return(INT); }
124 "interrupt" { count(); return(INTERRUPT);}
125 "nonbanked" { count(); TKEYWORD(NONBANKED);}
126 "banked" { count(); TKEYWORD(BANKED);}
127 "long" { count(); return(LONG); }
128 "near" { count(); TKEYWORD(DATA);}
129 "pdata" { count(); TKEYWORD(PDATA); }
130 "reentrant" { count(); TKEYWORD(REENTRANT);}
131 "register" { count(); return(REGISTER); }
132 "return" { count(); return(RETURN); }
133 "sfr" { count(); TKEYWORD(SFR) ; }
134 "sbit" { count(); TKEYWORD(SBIT) ; }
135 "short" { count(); return(SHORT); }
136 "signed" { count(); return(SIGNED); }
137 "sizeof" { count(); return(SIZEOF); }
138 "sram" { count(); TKEYWORD(XDATA);}
139 "static" { count(); return(STATIC); }
140 "struct" { count(); return(STRUCT); }
141 "switch" { count(); return(SWITCH); }
142 "typedef" { count(); return(TYPEDEF); }
143 "union" { count(); return(UNION); }
144 "unsigned" { count(); return(UNSIGNED); }
145 "void" { count(); return(VOID); }
146 "volatile" { count(); return(VOLATILE); }
147 "using" { count(); TKEYWORD(USING); }
148 "_naked" { count(); TKEYWORD(NAKED); }
149 "while" { count(); return(WHILE); }
150 "xdata" { count(); TKEYWORD(XDATA); }
151 "..." { count(); return(VAR_ARGS);}
152 "__typeof" { count(); return TYPEOF;}
153 "_JavaNative" { count(); TKEYWORD(JAVANATIVE);}
154 "_overlay" { count(); TKEYWORD(OVERLAY);}
155 {L}({L}|{D})* { count(); return(check_type()); }
156 0[xX]{H}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
157 0{D}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
158 {D}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
159 '(\\.|[^\\'])+' { count();yylval.val = charVal (yytext); return(CONSTANT); /* ' make syntax highliter happy */}
160 {D}+{E}{FS}? { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
161 {D}*"."{D}+({E})?{FS}? { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
162 {D}+"."{D}*({E})?{FS}? { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
163 \" { count(); yylval.val=strVal(stringLiteral()); return(STRING_LITERAL);}
164 ">>=" { count(); yylval.yyint = RIGHT_ASSIGN ; return(RIGHT_ASSIGN); }
165 "<<=" { count(); yylval.yyint = LEFT_ASSIGN ; return(LEFT_ASSIGN) ; }
166 "+=" { count(); yylval.yyint = ADD_ASSIGN ; return(ADD_ASSIGN) ; }
167 "-=" { count(); yylval.yyint = SUB_ASSIGN ; return(SUB_ASSIGN) ; }
168 "*=" { count(); yylval.yyint = MUL_ASSIGN ; return(MUL_ASSIGN) ; }
169 "/=" { count(); yylval.yyint = DIV_ASSIGN ; return(DIV_ASSIGN) ; }
170 "%=" { count(); yylval.yyint = MOD_ASSIGN ; return(MOD_ASSIGN) ; }
171 "&=" { count(); yylval.yyint = AND_ASSIGN ; return(AND_ASSIGN) ; }
172 "^=" { count(); yylval.yyint = XOR_ASSIGN ; return(XOR_ASSIGN) ; }
173 "|=" { count(); yylval.yyint = OR_ASSIGN ; return(OR_ASSIGN) ; }
174 ">>" { count(); return(RIGHT_OP); }
175 "<<" { count(); return(LEFT_OP); }
176 "++" { count(); return(INC_OP); }
177 "--" { count(); return(DEC_OP); }
178 "->" { count(); return(PTR_OP); }
179 "&&" { count(); return(AND_OP); }
180 "||" { count(); return(OR_OP); }
181 "<=" { count(); return(LE_OP); }
182 ">=" { count(); return(GE_OP); }
183 "==" { count(); return(EQ_OP); }
184 "!=" { count(); return(NE_OP); }
185 ";" { count(); return(';'); }
186 "{" { count(); NestLevel++ ; return('{'); }
187 "}" { count(); NestLevel--; return('}'); }
188 "," { count(); return(','); }
189 ":" { count(); return(':'); }
190 "=" { count(); return('='); }
191 "(" { count(); return('('); }
192 ")" { count(); return(')'); }
193 "[" { count(); return('['); }
194 "]" { count(); return(']'); }
195 "." { count(); return('.'); }
196 "&" { count(); return('&'); }
197 "!" { count(); return('!'); }
198 "~" { count(); return('~'); }
199 "-" { count(); return('-'); }
200 "+" { count(); return('+'); }
201 "*" { count(); return('*'); }
202 "/" { count(); return('/'); }
203 "%" { count(); return('%'); }
204 "<" { count(); return('<'); }
205 ">" { count(); return('>'); }
206 "^" { count(); return('^'); }
207 "|" { count(); return('|'); }
208 "?" { count(); return('?'); }
209 ^#line.*"\n" { count(); checkCurrFile(yytext); }
210 ^#pragma.*"\n" { count(); process_pragma(yytext); }
212 ^[^(]+"("[0-9]+") : error"[^\n]+ { werror(E_PRE_PROC_FAILED,yytext);count(); }
213 ^[^(]+"("[0-9]+") : warning"[^\n]+ { werror(W_PRE_PROC_WARNING,yytext);count(); }
216 [ \t\v\f] { count(); }
220 /* that could have been removed by the preprocessor anyway */
221 werror (W_STRAY_BACKSLASH, column);
228 static int checkCurrFile (char *s)
234 /* first check if this is a #line */
235 if ( strncmp(s,"#line",5) )
238 /* get to the line number */
245 sscanf(lineNum,"%d",&lNum);
247 /* now see if we have a file name */
248 while (*s != '\"' && *s)
251 /* if we don't have a filename then */
252 /* set the current line number to */
253 /* line number if printFlag is on */
255 lineno = mylineno = lNum ;
259 /* if we have a filename then check */
260 /* if it is "standard in" if yes then */
261 /* get the currentfile name info */
264 /* in c1mode fullSrcFileName is NULL */
265 if ( fullSrcFileName &&
266 strncmp(s,fullSrcFileName,strlen(fullSrcFileName)) == 0) {
267 lineno = mylineno = lNum;
268 currFname = fullSrcFileName ;
271 /* mark the end of the filename */
272 while (*s != '"') s++;
274 currFname = strdup (sb);
275 lineno = mylineno = lNum;
277 filename = currFname ;
284 static void count(void)
287 for (i = 0; yytext[i] != '\0'; i++) {
288 if (yytext[i] == '\n') {
290 lineno = ++mylineno ;
293 if (yytext[i] == '\t')
294 column += 8 - (column % 8);
301 static int check_type(void)
303 /* check if it is in the typedef table */
304 if (findSym(TypedefTab,NULL,yytext)) {
305 strncpyz(yylval.yychar,yytext, SDCC_NAME_MAX);
309 strncpyz (yylval.yychar,yytext, SDCC_NAME_MAX);
315 * Change by JTV 2001-05-19 to not concantenate strings
316 * to support ANSI hex and octal escape sequences in string liteals
319 static char *stringLiteral(void)
321 #define STR_BUF_CHUNCK_LEN 1024
323 static struct dbuf_s dbuf;
327 dbuf_init(&dbuf, STR_BUF_CHUNCK_LEN);
329 dbuf_set_size(&dbuf, 0);
332 dbuf_append(&dbuf, "\"", 1);
333 /* put into the buffer till we hit the first \" */
335 while ((ch = input()) != 0) {
338 /* if it is a \ then escape char's are allowed */
341 /* \<newline> is a continuator */
348 dbuf_append(&dbuf, buf, 2); /* get the escape char, no further check */
350 break; /* carry on */
353 /* if new line we have a new line break, which is illegal */
354 werror(W_NEWLINE_IN_STRING);
355 dbuf_append(&dbuf, "\n", 1);
361 /* if this is a quote then we have work to do */
362 /* find the next non whitespace character */
363 /* if that is a double quote then carry on */
364 dbuf_append(&dbuf, "\"", 1); /* Pass end of this string or substring to evaluator */
365 while ((ch = input()) && (isspace(ch) || ch=='\\')) {
368 if ((ch = input()) != '\n') {
369 werror(W_STRAY_BACKSLASH, column);
395 dbuf_append(&dbuf, buf, 1); /* Put next substring introducer into output string */
400 return (char *)dbuf_c_str(&dbuf);
419 P_OVERLAY_ /* I had a strange conflict with P_OVERLAY while */
420 /* cross-compiling for MINGW32 with gcc 3.2 */
424 /* SAVE/RESTORE stack */
425 #define SAVE_RESTORE_SIZE 128
427 STACK_DCL(options_stack, struct options *, SAVE_RESTORE_SIZE)
428 STACK_DCL(optimize_stack, struct optimize *, SAVE_RESTORE_SIZE)
431 * cloneXxx functions should be updated every time a new set is
432 * added to the options or optimize structure!
435 static struct options *cloneOptions(struct options *opt)
437 struct options *new_opt;
439 new_opt = Safe_malloc(sizeof (struct options));
441 /* clone scalar values */
445 new_opt->calleeSavesSet = setFromSetNonRev(opt->calleeSavesSet);
446 new_opt->excludeRegsSet = setFromSetNonRev(opt->excludeRegsSet);
447 /* not implemented yet: */
448 /* new_opt->olaysSet = setFromSetNonRev(opt->olaysSet); */
453 static struct optimize *cloneOptimize(struct optimize *opt)
455 struct optimize *new_opt;
457 new_opt = Safe_malloc(sizeof (struct options));
459 /* clone scalar values */
465 static void copyAndFreeOptions(struct options *dest, struct options *src)
467 /* delete dest sets */
468 deleteSet(&dest->calleeSavesSet);
469 deleteSet(&dest->excludeRegsSet);
470 /* not implemented yet: */
471 /* deleteSet(&dest->olaysSet); */
473 /* dopy src to dest */
479 static void copyAndFreeOptimize(struct optimize *dest, struct optimize *src)
481 /* dopy src to dest */
487 static void doPragma(int op, char *cp)
492 STACK_PUSH(options_stack, cloneOptions(&options));
493 STACK_PUSH(optimize_stack, cloneOptimize(&optimize));
499 struct options *optionsp;
500 struct optimize *optimizep;
502 optionsp = STACK_POP(options_stack);
503 copyAndFreeOptions(&options, optionsp);
505 optimizep = STACK_POP(optimize_stack);
506 copyAndFreeOptimize(&optimize, optimizep);
511 optimize.loopInduction = 0 ;
515 optimize.loopInvariant = 0 ;
519 optimize.loopInduction = 1 ;
523 options.stackAuto = 1;
527 optimize.noJTabBoundary = 1;
531 optimize.global_cse = 0;
535 options.noOverlay = 1;
539 options.lessPedantic = 1;
543 /* append to the functions already listed
545 setParseWithComma(&options.calleeSavesSet, cp);
550 deleteSet(&options.excludeRegsSet);
551 setParseWithComma(&options.excludeRegsSet, cp);
560 optimize.noLoopReverse = 1;
568 static int process_pragma(char *s)
570 #define NELEM(x) (sizeof (x) / sizeof (x)[0])
571 #define PRAGMA "#pragma"
573 static struct pragma_s {
578 { "RESTORE", P_RESTORE },
579 { "NOINDUCTION", P_NOINDUCTION },
580 { "NOINVARIANT", P_NOINVARIANT },
581 { "NOLOOPREVERSE", P_LOOPREV },
582 { "INDUCTION", P_INDUCTION },
583 { "STACKAUTO", P_STACKAUTO },
584 { "NOJTBOUND", P_NOJTBOUND },
585 { "NOGCSE", P_NOGCSE },
586 { "NOOVERLAY", P_NOOVERLAY },
587 { "CALLEE-SAVES", P_CALLEE_SAVES },
588 { "EXCLUDE", P_EXCLUDE },
590 { "OVERLAY", P_OVERLAY_ },
591 { "LESS_PEDANTIC", P_LESSPEDANTIC },
596 /* find the pragma */
597 while (strncmp(s, PRAGMA, (sizeof PRAGMA) - 1))
599 s += (sizeof PRAGMA) - 1;
601 /* look for the directive */
606 /* look for the end of the directive */
607 while ((!isspace(*s)) && (*s != '\n'))
610 /* First give the port a chance */
611 if (port->process_pragma && !port->process_pragma(cp))
614 for (i = 0; i < NELEM(pragma_tbl); i++) {
615 /* now compare and do what needs to be done */
616 size_t len = strlen(pragma_tbl[i].name);
618 if (strncmp(cp, pragma_tbl[i].name, len) == 0) {
619 doPragma(pragma_tbl[i].id, cp + len);
624 werror(W_UNKNOWN_PRAGMA,cp);
628 /* will return 1 if the string is a part
629 of a target specific keyword */
630 static int isTargetKeyword(char *s)
634 if (port->keywords == NULL)
636 for ( i = 0 ; port->keywords[i] ; i++ ) {
637 if (strcmp(port->keywords[i],s) == 0)
644 static void my_unput(char c)
646 yyunput(c, (yytext_ptr));
651 if (!STACK_EMPTY(options_stack) || !STACK_EMPTY(optimize_stack))
652 werror(W_SAVE_RESTORE);
661 if (mylineno && filename) {
662 if(options.vc_err_style)
663 fprintf(stderr,"\n%s(%d) : %s: token -> '%s' ; column %d\n",
667 fprintf(stderr,"\n%s:%d: %s: token -> '%s' ; column %d\n",
672 /* this comes from an empy file, no problem */