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 -------------------------------------------------------------------------*/
42 char *stringLiteral();
45 extern int lineno, column;
46 extern char *filename ;
49 int process_pragma(char *);
55 #define YY_PROTO(proto) proto
57 #define YY_PROTO(proto) ()
62 int yywrap YY_PROTO((void))
67 static void yyunput (int, char *);
69 static void my_unput(char c)
71 yyunput(c, (yytext_ptr));
74 #define TKEYWORD(token) return (isTargetKeyword(yytext) ? token :\
79 extern int check_type ();
80 extern int isTargetKeyword ();
81 extern int checkCurrFile (char *);
82 extern int processPragma (char *);
83 extern int printListing (int );
84 struct optimize save_optimize ;
85 struct options save_options ;
92 asmp = asmbuff = realloc (asmbuff, INITIAL_INLINEASM);
93 asmbuffSize=INITIAL_INLINEASM;
99 yylval.yyinline = strdup (asmbuff);
104 if (asmp-asmbuff >= asmbuffSize-2) {
105 // increase the buffersize with 50%
106 int size=asmp-asmbuff;
107 asmbuffSize=asmbuffSize*3/2;
108 asmbuff = realloc (asmbuff, asmbuffSize);
115 if (asmp-asmbuff >= asmbuffSize-3) {
116 // increase the buffersize with 50%
117 int size=asmp-asmbuff;
118 asmbuffSize=asmbuffSize*3/2;
119 asmbuff = realloc (asmbuff, asmbuffSize);
124 "at" { count(); TKEYWORD(AT) ; }
125 "auto" { count(); return(AUTO); }
126 "bit" { count(); TKEYWORD(BIT) ; }
127 "break" { count(); return(BREAK); }
128 "case" { count(); return(CASE); }
129 "char" { count(); return(CHAR); }
130 "code" { count(); TKEYWORD(CODE); }
131 "const" { count(); return(CONST); }
132 "continue" { count(); return(CONTINUE); }
133 "critical" { count(); TKEYWORD(CRITICAL); }
134 "data" { count(); TKEYWORD(DATA); }
135 "default" { count(); return(DEFAULT); }
136 "do" { count(); return(DO); }
137 "double" { count(); werror(W_DOUBLE_UNSUPPORTED);return(FLOAT); }
138 "else" { count(); return(ELSE); }
139 "enum" { count(); return(ENUM); }
140 "extern" { count(); return(EXTERN); }
141 "far" { count(); TKEYWORD(XDATA); }
142 "eeprom" { count(); TKEYWORD(EEPROM); }
143 "float" { count(); return(FLOAT); }
144 "flash" { count(); TKEYWORD(CODE);}
145 "for" { count(); return(FOR); }
146 "goto" { count(); return(GOTO); }
147 "idata" { count(); TKEYWORD(IDATA);}
148 "if" { count(); return(IF); }
149 "int" { count(); return(INT); }
150 "interrupt" { count(); return(INTERRUPT);}
151 "nonbanked" { count(); TKEYWORD(NONBANKED);}
152 "banked" { count(); TKEYWORD(BANKED);}
153 "long" { count(); return(LONG); }
154 "near" { count(); TKEYWORD(DATA);}
155 "pdata" { count(); TKEYWORD(PDATA); }
156 "reentrant" { count(); TKEYWORD(REENTRANT);}
157 "register" { count(); return(REGISTER); }
158 "return" { count(); return(RETURN); }
159 "sfr" { count(); TKEYWORD(SFR) ; }
160 "sbit" { count(); TKEYWORD(SBIT) ; }
161 "short" { count(); return(SHORT); }
162 "signed" { count(); return(SIGNED); }
163 "sizeof" { count(); return(SIZEOF); }
164 "sram" { count(); TKEYWORD(XDATA);}
165 "static" { count(); return(STATIC); }
166 "struct" { count(); return(STRUCT); }
167 "switch" { count(); return(SWITCH); }
168 "typedef" { count(); return(TYPEDEF); }
169 "union" { count(); return(UNION); }
170 "unsigned" { count(); return(UNSIGNED); }
171 "void" { count(); return(VOID); }
172 "volatile" { count(); return(VOLATILE); }
173 "using" { count(); TKEYWORD(USING); }
174 "_naked" { count(); TKEYWORD(NAKED); }
175 "while" { count(); return(WHILE); }
176 "xdata" { count(); TKEYWORD(XDATA); }
177 "..." { count(); return(VAR_ARGS);}
178 "__typeof" { count(); return TYPEOF;}
179 "_JavaNative" { count(); TKEYWORD(JAVANATIVE);}
180 "_overlay" { count(); TKEYWORD(OVERLAY);}
181 {L}({L}|{D})* { count(); return(check_type()); }
182 0[xX]{H}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
183 0{D}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
184 {D}+{IS}? { count(); yylval.val = constVal(yytext); return(CONSTANT); }
185 '(\\.|[^\\'])+' { count();yylval.val = charVal (yytext); return(CONSTANT); /* ' make syntax highliter happy */}
186 {D}+{E}{FS}? { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
187 {D}*"."{D}+({E})?{FS}? { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
188 {D}+"."{D}*({E})?{FS}? { count(); yylval.val = constFloatVal(yytext);return(CONSTANT); }
189 \" { count(); yylval.val=strVal(stringLiteral()); return(STRING_LITERAL);}
190 ">>=" { count(); yylval.yyint = RIGHT_ASSIGN ; return(RIGHT_ASSIGN); }
191 "<<=" { count(); yylval.yyint = LEFT_ASSIGN ; return(LEFT_ASSIGN) ; }
192 "+=" { count(); yylval.yyint = ADD_ASSIGN ; return(ADD_ASSIGN) ; }
193 "-=" { count(); yylval.yyint = SUB_ASSIGN ; return(SUB_ASSIGN) ; }
194 "*=" { count(); yylval.yyint = MUL_ASSIGN ; return(MUL_ASSIGN) ; }
195 "/=" { count(); yylval.yyint = DIV_ASSIGN ; return(DIV_ASSIGN) ; }
196 "%=" { count(); yylval.yyint = MOD_ASSIGN ; return(MOD_ASSIGN) ; }
197 "&=" { count(); yylval.yyint = AND_ASSIGN ; return(AND_ASSIGN) ; }
198 "^=" { count(); yylval.yyint = XOR_ASSIGN ; return(XOR_ASSIGN) ; }
199 "|=" { count(); yylval.yyint = OR_ASSIGN ; return(OR_ASSIGN) ; }
200 ">>" { count(); return(RIGHT_OP); }
201 "<<" { count(); return(LEFT_OP); }
202 "++" { count(); return(INC_OP); }
203 "--" { count(); return(DEC_OP); }
204 "->" { count(); return(PTR_OP); }
205 "&&" { count(); return(AND_OP); }
206 "||" { count(); return(OR_OP); }
207 "<=" { count(); return(LE_OP); }
208 ">=" { count(); return(GE_OP); }
209 "==" { count(); return(EQ_OP); }
210 "!=" { count(); return(NE_OP); }
211 ";" { count(); return(';'); }
212 "{" { count(); NestLevel++ ; return('{'); }
213 "}" { count(); NestLevel--; return('}'); }
214 "," { count(); return(','); }
215 ":" { count(); return(':'); }
216 "=" { count(); return('='); }
217 "(" { count(); return('('); }
218 ")" { count(); return(')'); }
219 "[" { count(); return('['); }
220 "]" { count(); return(']'); }
221 "." { count(); return('.'); }
222 "&" { count(); return('&'); }
223 "!" { count(); return('!'); }
224 "~" { count(); return('~'); }
225 "-" { count(); return('-'); }
226 "+" { count(); return('+'); }
227 "*" { count(); return('*'); }
228 "/" { count(); return('/'); }
229 "%" { count(); return('%'); }
230 "<" { count(); return('<'); }
231 ">" { count(); return('>'); }
232 "^" { count(); return('^'); }
233 "|" { count(); return('|'); }
234 "?" { count(); return('?'); }
235 ^#line.*"\n" { count(); checkCurrFile(yytext); }
236 ^#pragma.*"\n" { count(); process_pragma(yytext); }
238 ^[^(]+"("[0-9]+") : error"[^\n]+ { werror(E_PRE_PROC_FAILED,yytext);count(); }
239 ^[^(]+"("[0-9]+") : warning"[^\n]+ { werror(W_PRE_PROC_WARNING,yytext);count(); }
242 [ \t\v\f] { count(); }
246 // that could have been removed by the preprocessor anyway
247 werror (W_STRAY_BACKSLASH, column);
254 static int checkCurrFile (char *s)
260 /* first check if this is a #line */
261 if ( strncmp(s,"#line",5) )
264 /* get to the line number */
271 sscanf(lineNum,"%d",&lNum);
273 /* now see if we have a file name */
274 while (*s != '\"' && *s)
277 /* if we don't have a filename then */
278 /* set the current line number to */
279 /* line number if printFlag is on */
281 lineno = mylineno = lNum ;
285 /* if we have a filename then check */
286 /* if it is "standard in" if yes then */
287 /* get the currentfile name info */
290 /* in c1mode fullSrcFileName is NULL */
291 if ( fullSrcFileName &&
292 strncmp(s,fullSrcFileName,strlen(fullSrcFileName)) == 0) {
293 lineno = mylineno = lNum;
294 currFname = fullSrcFileName ;
297 /* mark the end of the filename */
298 while (*s != '"') s++;
300 currFname = strdup (sb);
301 lineno = mylineno = lNum;
303 filename = currFname ;
310 static void count(void)
313 for (i = 0; yytext[i] != '\0'; i++) {
314 if (yytext[i] == '\n') {
316 lineno = ++mylineno ;
319 if (yytext[i] == '\t')
320 column += 8 - (column % 8);
327 static int check_type(void)
329 /* check if it is in the typedef table */
330 if (findSym(TypedefTab,NULL,yytext)) {
331 strncpyz(yylval.yychar,yytext, SDCC_NAME_MAX);
335 strncpyz (yylval.yychar,yytext, SDCC_NAME_MAX);
341 * Change by JTV 2001-05-19 to not concantenate strings
342 * to support ANSI hex and octal escape sequences in string liteals
345 static char *stringLiteral(void)
347 #define STR_BUF_CHUNCK_LEN 1024
349 static struct dbuf_s dbuf;
353 dbuf_init(&dbuf, STR_BUF_CHUNCK_LEN);
355 dbuf_set_size(&dbuf, 0);
358 dbuf_append(&dbuf, "\"", 1);
359 /* put into the buffer till we hit the first \" */
361 while ((ch = input()) != 0) {
364 /* if it is a \ then escape char's are allowed */
367 /* \<newline> is a continuator */
374 dbuf_append(&dbuf, buf, 2); /* get the escape char, no further check */
376 break; /* carry on */
379 /* if new line we have a new line break, which is illegal */
380 werror(W_NEWLINE_IN_STRING);
381 dbuf_append(&dbuf, "\n", 1);
387 /* if this is a quote then we have work to do */
388 /* find the next non whitespace character */
389 /* if that is a double quote then carry on */
390 dbuf_append(&dbuf, "\"", 1); /* Pass end of this string or substring to evaluator */
391 while ((ch = input()) && (isspace(ch) || ch=='\\')) {
394 if ((ch = input()) != '\n') {
395 werror(W_STRAY_BACKSLASH, column);
421 dbuf_append(&dbuf, buf, 1); /* Put next substring introducer into output string */
426 return (char *)dbuf_c_str(&dbuf);
445 P_OVERLAY_ /* I had a strange conflict with P_OVERLAY while */
446 /* cross-compiling for MINGW32 with gcc 3.2 */
450 /* SAVE/RESTORE stack */
451 #define SAVE_RESTORE_SIZE 128
453 STACK_DCL(options_stack, struct options *, SAVE_RESTORE_SIZE)
454 STACK_DCL(optimize_stack, struct optimize *, SAVE_RESTORE_SIZE)
457 * cloneXxx functions should be updated every time a new set is
458 * added to the options or optimize structure!
461 static struct options *cloneOptions(struct options *opt)
463 struct options *new_opt;
465 new_opt = Safe_malloc(sizeof (struct options));
467 /* clone scalar values */
471 new_opt->calleeSavesSet = setFromSetNonRev(opt->calleeSavesSet);
472 new_opt->excludeRegsSet = setFromSetNonRev(opt->excludeRegsSet);
473 /* not implemented yet: */
474 /* new_opt->olaysSet = setFromSetNonRev(opt->olaysSet); */
479 static struct optimize *cloneOptimize(struct optimize *opt)
481 struct optimize *new_opt;
483 new_opt = Safe_malloc(sizeof (struct options));
485 /* clone scalar values */
491 static void copyAndFreeOptions(struct options *dest, struct options *src)
493 /* delete dest sets */
494 deleteSet(&dest->calleeSavesSet);
495 deleteSet(&dest->excludeRegsSet);
496 /* not implemented yet: */
497 /* deleteSet(&dest->olaysSet); */
499 /* dopy src to dest */
505 static void copyAndFreeOptimize(struct optimize *dest, struct optimize *src)
507 /* dopy src to dest */
513 static void doPragma(int op, char *cp)
518 STACK_PUSH(options_stack, cloneOptions(&options));
519 STACK_PUSH(optimize_stack, cloneOptimize(&optimize));
525 struct options *optionsp;
526 struct optimize *optimizep;
528 optionsp = STACK_POP(options_stack);
529 copyAndFreeOptions(&options, optionsp);
531 optimizep = STACK_POP(optimize_stack);
532 copyAndFreeOptimize(&optimize, optimizep);
537 optimize.loopInduction = 0 ;
541 optimize.loopInvariant = 0 ;
545 optimize.loopInduction = 1 ;
549 options.stackAuto = 1;
553 optimize.noJTabBoundary = 1;
557 optimize.global_cse = 0;
561 options.noOverlay = 1;
565 options.lessPedantic = 1;
569 /* append to the functions already listed
571 setParseWithComma(&options.calleeSavesSet, cp);
576 deleteSet(&options.excludeRegsSet);
577 setParseWithComma(&options.excludeRegsSet, cp);
586 optimize.noLoopReverse = 1;
594 static int process_pragma(char *s)
596 #define NELEM(x) (sizeof (x) / sizeof (x)[0])
597 #define PRAGMA "#pragma"
599 static struct pragma_s {
604 { "RESTORE", P_RESTORE },
605 { "NOINDUCTION", P_NOINDUCTION },
606 { "NOINVARIANT", P_NOINVARIANT },
607 { "NOLOOPREVERSE", P_LOOPREV },
608 { "INDUCTION", P_INDUCTION },
609 { "STACKAUTO", P_STACKAUTO },
610 { "NOJTBOUND", P_NOJTBOUND },
611 { "NOGCSE", P_NOGCSE },
612 { "NOOVERLAY", P_NOOVERLAY },
613 { "CALLEE-SAVES", P_CALLEE_SAVES },
614 { "EXCLUDE", P_EXCLUDE },
616 { "OVERLAY", P_OVERLAY_ },
617 { "LESS_PEDANTIC", P_LESSPEDANTIC },
622 /* find the pragma */
623 while (strncmp(s, PRAGMA, (sizeof PRAGMA) - 1))
625 s += (sizeof PRAGMA) - 1;
627 /* look for the directive */
632 /* look for the end of the directive */
633 while ((!isspace(*s)) && (*s != '\n'))
636 /* First give the port a chance */
637 if (port->process_pragma && !port->process_pragma(cp))
640 for (i = 0; i < NELEM(pragma_tbl); i++) {
641 /* now compare and do what needs to be done */
642 size_t len = strlen(pragma_tbl[i].name);
644 if (strncmp(cp, pragma_tbl[i].name, len) == 0) {
645 doPragma(pragma_tbl[i].id, cp + len);
650 werror(W_UNKNOWN_PRAGMA,cp);
654 /* will return 1 if the string is a part
655 of a target specific keyword */
656 static int isTargetKeyword(char *s)
660 if (port->keywords == NULL)
662 for ( i = 0 ; port->keywords[i] ; i++ ) {
663 if (strcmp(port->keywords[i],s) == 0)
674 if (mylineno && filename) {
675 if(options.vc_err_style)
676 fprintf(stdout,"\n%s(%d) : %s: token -> '%s' ; column %d\n",
680 fprintf(stdout,"\n%s:%d: %s: token -> '%s' ; column %d\n",
685 /* this comes from an empy file, no problem */